mirror of
https://git.proxmox.com/git/mirror_frr
synced 2025-04-28 15:36:25 +00:00
topotest: add --memleaks topotest option
Signed-off-by: Lou Berger <lberger@labn.net>
This commit is contained in:
parent
c6686550c3
commit
d4977708f0
@ -310,32 +310,6 @@ Test will set exit code which can be used with ``git bisect``.
|
||||
|
||||
For the simulated topology, see the description in the python file.
|
||||
|
||||
StdErr log from daemos after exit
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
To enable the reporting of any messages seen on StdErr after the daemons exit,
|
||||
the following env variable can be set::
|
||||
|
||||
export TOPOTESTS_CHECK_STDERR=Yes
|
||||
|
||||
(The value doesn't matter at this time. The check is whether the env
|
||||
variable exists or not.) There is no pass/fail on this reporting; the
|
||||
Output will be reported to the console.
|
||||
|
||||
Collect Memory Leak Information
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
FRR processes can report unfreed memory allocations upon exit. To
|
||||
enable the reporting of memory leaks, define an environment variable
|
||||
``TOPOTESTS_CHECK_MEMLEAK`` with the file prefix, i.e.::
|
||||
|
||||
export TOPOTESTS_CHECK_MEMLEAK="/home/mydir/memleak_"
|
||||
|
||||
This will enable the check and output to console and the writing of
|
||||
the information to files with the given prefix (followed by testname),
|
||||
ie :file:`/home/mydir/memcheck_test_bgp_multiview_topo1.txt` in case
|
||||
of a memory leak.
|
||||
|
||||
Running Topotests with AddressSanitizer
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
@ -561,6 +535,48 @@ Here's an example of launching ``zebra`` and ``bgpd`` inside ``gdb`` on router
|
||||
--gdb-breakpoints=nb_config_diff \
|
||||
all-protocol-startup
|
||||
|
||||
Reporting Memleaks with FRR Memory Statistics
|
||||
"""""""""""""""""""""""""""""""""""""""""""""
|
||||
|
||||
FRR reports all allocated FRR memory objects on exit to standard error.
|
||||
Topotest can be run to report such output as errors in order to check for
|
||||
memleaks in FRR memory allocations. Specifying the CLI argument
|
||||
``--memleaks`` will enable reporting FRR-based memory allocations at exit as errors.
|
||||
|
||||
.. code:: shell
|
||||
|
||||
sudo -E pytest --memleaks all-protocol-startup
|
||||
|
||||
|
||||
StdErr log from daemos after exit
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
When running with ``--memleaks``, to enable the reporting of other,
|
||||
non-memory related, messages seen on StdErr after the daemons exit,
|
||||
the following env variable can be set::
|
||||
|
||||
export TOPOTESTS_CHECK_STDERR=Yes
|
||||
|
||||
(The value doesn't matter at this time. The check is whether the env
|
||||
variable exists or not.) There is no pass/fail on this reporting; the
|
||||
Output will be reported to the console.
|
||||
|
||||
Collect Memory Leak Information
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
When running with ``--memleaks``, FRR processes report unfreed memory
|
||||
allocations upon exit. To enable also reporting of memory leaks to a specific
|
||||
location, define an environment variable ``TOPOTESTS_CHECK_MEMLEAK`` with the
|
||||
file prefix, i.e.:
|
||||
|
||||
export TOPOTESTS_CHECK_MEMLEAK="/home/mydir/memleak_"
|
||||
|
||||
For tests that support the TOPOTESTS_CHECK_MEMLEAK environment variable, this
|
||||
will enable output to the information to files with the given prefix (followed
|
||||
by testname), e.g.,:
|
||||
file:`/home/mydir/memcheck_test_bgp_multiview_topo1.txt` in case
|
||||
of a memory leak.
|
||||
|
||||
Detecting Memleaks with Valgrind
|
||||
""""""""""""""""""""""""""""""""
|
||||
|
||||
|
@ -86,6 +86,12 @@ def pytest_addoption(parser):
|
||||
),
|
||||
)
|
||||
|
||||
parser.addoption(
|
||||
"--memleaks",
|
||||
action="store_true",
|
||||
help="Report memstat results as errors",
|
||||
)
|
||||
|
||||
parser.addoption(
|
||||
"--pause",
|
||||
action="store_true",
|
||||
@ -189,7 +195,7 @@ def pytest_addoption(parser):
|
||||
)
|
||||
|
||||
|
||||
def check_for_memleaks():
|
||||
def check_for_valgrind_memleaks():
|
||||
assert topotest.g_pytest_config.option.valgrind_memleaks
|
||||
|
||||
leaks = []
|
||||
@ -232,10 +238,46 @@ def check_for_memleaks():
|
||||
pytest.fail("valgrind memleaks found for daemons: " + " ".join(daemons))
|
||||
|
||||
|
||||
def check_for_memleaks():
|
||||
leaks = []
|
||||
tgen = get_topogen() # pylint: disable=redefined-outer-name
|
||||
latest = []
|
||||
existing = []
|
||||
if tgen is not None:
|
||||
logdir = tgen.logdir
|
||||
if hasattr(tgen, "memstat_existing_files"):
|
||||
existing = tgen.memstat_existing_files
|
||||
latest = glob.glob(os.path.join(logdir, "*/*.err"))
|
||||
|
||||
daemons = []
|
||||
for vfile in latest:
|
||||
if vfile in existing:
|
||||
continue
|
||||
with open(vfile, encoding="ascii") as vf:
|
||||
vfcontent = vf.read()
|
||||
num = vfcontent.count("memstats:")
|
||||
if num:
|
||||
existing.append(vfile) # have summary don't check again
|
||||
emsg = "{} types in {}".format(num, vfile)
|
||||
leaks.append(emsg)
|
||||
daemon = re.match(r".*test[a-z_A-Z0-9\+]*/(.*)\.err", vfile).group(1)
|
||||
daemons.append("{}({})".format(daemon, num))
|
||||
|
||||
if tgen is not None:
|
||||
tgen.memstat_existing_files = existing
|
||||
|
||||
if leaks:
|
||||
logger.error("memleaks found:\n\t%s", "\n\t".join(leaks))
|
||||
pytest.fail("memleaks found for daemons: " + " ".join(daemons))
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True, scope="module")
|
||||
def module_check_memtest(request):
|
||||
yield
|
||||
if request.config.option.valgrind_memleaks:
|
||||
if get_topogen() is not None:
|
||||
check_for_valgrind_memleaks()
|
||||
if request.config.option.memleaks:
|
||||
if get_topogen() is not None:
|
||||
check_for_memleaks()
|
||||
|
||||
@ -264,6 +306,8 @@ def pytest_runtest_call(item: pytest.Item) -> None:
|
||||
|
||||
# Check for leaks if requested
|
||||
if item.config.option.valgrind_memleaks:
|
||||
check_for_valgrind_memleaks()
|
||||
if item.config.option.memleaks:
|
||||
check_for_memleaks()
|
||||
|
||||
|
||||
@ -370,10 +414,22 @@ def pytest_configure(config):
|
||||
if config.option.topology_only and is_xdist:
|
||||
pytest.exit("Cannot use --topology-only with distributed test mode")
|
||||
|
||||
pytest.exit("Cannot use --topology-only with distributed test mode")
|
||||
|
||||
# Check environment now that we have config
|
||||
if not diagnose_env(rundir):
|
||||
pytest.exit("environment has errors, please read the logs in %s" % rundir)
|
||||
|
||||
# slave TOPOTESTS_CHECK_MEMLEAK to memleaks flag
|
||||
if config.option.memleaks:
|
||||
if "TOPOTESTS_CHECK_MEMLEAK" not in os.environ:
|
||||
os.environ["TOPOTESTS_CHECK_MEMLEAK"] = "/dev/null"
|
||||
else:
|
||||
if "TOPOTESTS_CHECK_MEMLEAK" in os.environ:
|
||||
del os.environ["TOPOTESTS_CHECK_MEMLEAK"]
|
||||
if "TOPOTESTS_CHECK_STDERR" in os.environ:
|
||||
del os.environ["TOPOTESTS_CHECK_STDERR"]
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True, scope="session")
|
||||
def setup_session_auto():
|
||||
|
Loading…
Reference in New Issue
Block a user