From 53f8ca764e0fc0afc59aa68b51d55d364e77e1cf Mon Sep 17 00:00:00 2001 From: Dominik Pataky Date: Fri, 3 Apr 2020 15:36:09 +0200 Subject: [PATCH] Tests: add memory performance tests A new test file is added which contains memory and CPU tests. For now, only the memory usage tests work (threading!). They print out tables of memory usage based on file path and on function. Additionally, they check some basic measurements: if all packets were processed and if a collection of version 9/10 called any functions in 10/9. Refs #24 --- tests/test_performance.py | 157 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 157 insertions(+) create mode 100644 tests/test_performance.py diff --git a/tests/test_performance.py b/tests/test_performance.py new file mode 100644 index 0000000..ffeba7a --- /dev/null +++ b/tests/test_performance.py @@ -0,0 +1,157 @@ +#!/usr/bin/env python3 + +""" +This file belongs to https://github.com/bitkeks/python-netflow-v9-softflowd. + +Copyright 2016-2020 Dominik Pataky +Licensed under MIT License. See LICENSE. +""" +import io +import linecache +import cProfile +import pstats +import tracemalloc +import unittest +from pstats import SortKey + +from tests.lib import send_recv_packets, generate_packets + +NUM_PACKETS_PERFORMANCE = 5000 + + +class TestNetflowIPFIXPerformance(unittest.TestCase): + def setUp(self) -> None: + """ + Before each test run, start tracemalloc profiling. + :return: + """ + tracemalloc.start() + print("\n\n") + + def tearDown(self) -> None: + """ + After each test run, stop tracemalloc. + :return: + """ + tracemalloc.stop() + + def _memory_of_version(self, version) -> tracemalloc.Snapshot: + """ + Create memory snapshot of collector run with packets of version :version: + :param version: + :return: + """ + if not tracemalloc.is_tracing(): + raise RuntimeError + pkts, t1, t2 = send_recv_packets(generate_packets(NUM_PACKETS_PERFORMANCE, version)) + self.assertEqual(len(pkts), NUM_PACKETS_PERFORMANCE) + snapshot = tracemalloc.take_snapshot() + del pkts + return snapshot + + @staticmethod + def _print_memory_statistics(snapshot: tracemalloc.Snapshot, key: str, topx: int = 10): + """ + Print memory statistics from a tracemalloc.Snapshot in certain formats. + :param snapshot: + :param key: + :param topx: + :return: + """ + if key not in ["filename", "lineno", "traceback"]: + raise KeyError + + stats = snapshot.statistics(key) + if key == "lineno": + print("\n## Detailed memory of traceback, based on lines ##") + for idx, stat in enumerate(stats[:topx]): + frame = stat.traceback[0] + print("\n{idx:02d}: {filename}:{lineno} {size:.1f} KiB, count {count}".format( + idx=idx+1, filename=frame.filename, lineno=frame.lineno, size=stat.size / 1024, count=stat.count + )) + + lines = [] + lines_whitespaces = [] + for lineshift in range(-3, 2): + stat = linecache.getline(frame.filename, frame.lineno + lineshift) + lines_whitespaces.append(len(stat) - len(stat.lstrip(" "))) # count + lines.append(stat.strip()) + lines_whitespaces = [x - min([y for y in lines_whitespaces if y > 0]) for x in lines_whitespaces] + for lidx, stat in enumerate(lines): + print(" {}{}".format("> " if lidx == 3 else "| ", " " * lines_whitespaces.pop(0) + stat)) + elif key == "filename": + print("\n## Detailed memory by file ##") + for idx, stat in enumerate(stats[:topx]): + frame = stat.traceback[0] + print("{idx:02d}: {filename:80s} {size:6.1f} KiB, count {count:5