From: Simon Glass <sjg@chromium.org>
Add a --malloc-dump option to the pytest framework that passes
--malloc_dump to the sandbox binary. The filename may contain '%d'
which is replaced with a sequence number that increments on each U-Boot
restart, so each instance produces a separate dump.
Override close() in ConsoleSandbox to send 'poweroff' before closing
the PTY when --malloc-dump is active, so that state_uninit() runs and
writes the dump file.
Signed-off-by: Simon Glass <sjg@chromium.org>
---
doc/develop/malloc.rst | 18 ++++++++++++++++++
test/py/conftest.py | 3 +++
test/py/console_sandbox.py | 26 ++++++++++++++++++++++++++
3 files changed, 47 insertions(+)
@@ -511,6 +511,24 @@ by checking ``malloc_get_info()`` before and after::
allocations during the operation
6. Fix the leak and verify the test passes
+**Dumping heap state on exit**
+
+When running sandbox, the ``--malloc_dump`` command-line option writes a heap
+dump to a file when U-Boot exits cleanly (via ``poweroff`` or ``reset``). This
+is useful for capturing heap state at the end of a test session::
+
+ ./u-boot -Tf -c "poweroff" --malloc_dump /tmp/heap.txt
+
+The pytest framework also supports this via ``--malloc-dump``::
+
+ test/py/test.py -B sandbox --malloc-dump /tmp/heap.txt -k test_source
+
+The filename may contain ``%d`` which is replaced with a sequence number
+that increments each time U-Boot restarts during the test session, so each
+instance produces a separate dump::
+
+ test/py/test.py -B sandbox --malloc-dump /tmp/heap%d.txt -k test_vboot
+
API Reference
-------------
@@ -106,6 +106,8 @@ def pytest_addoption(parser):
help='Disable console timeout (useful for debugging)')
parser.addoption('--no-full', default=False, action='store_true',
help='Skip flat-tree tests (run live-tree only)')
+ parser.addoption('--malloc-dump', default=None,
+ help='Write malloc dump to file on exit')
def run_build(config, source_dir, build_dir, board_type, log):
@@ -362,6 +364,7 @@ def pytest_configure(config):
ubconfig.allow_exceptions = config.getoption('allow_exceptions')
ubconfig.no_timeout = config.getoption('no_timeout')
ubconfig.no_full = config.getoption('no_full')
+ ubconfig.malloc_dump = config.getoption('malloc_dump')
env_vars = (
'board_type',
@@ -25,6 +25,7 @@ class ConsoleSandbox(ConsoleBase):
super().__init__(log, config, max_fifo_fill=1024)
self.sandbox_flags = []
self.use_dtb = True
+ self.malloc_dump_seq = 0
def get_spawn(self):
"""Connect to a fresh U-Boot instance.
@@ -57,6 +58,14 @@ class ConsoleSandbox(ConsoleBase):
if self.config.no_full:
cmd.append('-F')
+ if self.config.malloc_dump:
+ try:
+ fname = self.config.malloc_dump % self.malloc_dump_seq
+ except TypeError:
+ fname = self.config.malloc_dump
+ self.malloc_dump_seq += 1
+ cmd += ['--malloc_dump', fname]
+
# Always disable the pager
cmd.append('-P')
@@ -84,6 +93,23 @@ class ConsoleSandbox(ConsoleBase):
self.sandbox_flags = []
self.use_dtb = True
+ def close(self):
+ """Terminate the sandbox, using poweroff for a clean shutdown.
+
+ When --malloc-dump is active we need state_uninit() to run, so
+ send 'poweroff' instead of just closing the PTY.
+ """
+ if self.p and self.config.malloc_dump:
+ try:
+ self.p.send('poweroff\n')
+ for _ in range(50):
+ if not self.p.isalive():
+ break
+ time.sleep(0.1)
+ except:
+ pass
+ super().close()
+
def kill(self, sig):
"""Send a specific Unix signal to the sandbox process.