change(sysview): use esp sysview_mcore command for sysview_tracing JTAG capture

This commit is contained in:
Erhan Kurubas
2026-07-08 12:59:44 +02:00
parent 4e845e262a
commit 4a5a50e95a
3 changed files with 40 additions and 43 deletions
+4 -6
View File
@@ -111,15 +111,13 @@ NOTE: In order to run this example you need OpenOCD version `v0.10.0-esp32-20181
mon reset halt mon reset halt
b app_main b app_main
commands commands
mon esp sysview start file:///tmp/sysview_example.svdat mon esp sysview_mcore start file:///tmp/sysview_example.svdat
# For dual-core mode uncomment the line below and comment the line above
# mon esp sysview start file:///tmp/sysview_example0.svdat file:///tmp/sysview_example1.svdat
c c
end end
c c
``` ```
Using this file GDB will connect to the target, reset it, and start tracing when it hit breakpoint at `app_main`. Trace data will be saved to `/tmp/sysview_example.svdat`. Using this file GDB will connect to the target, reset it, and start tracing when it hit breakpoint at `app_main`. Trace data will be saved to `/tmp/sysview_example.svdat`. The `esp sysview_mcore` command uses the SEGGER SystemView multi-core format, so a single file holds the trace for both single- and dual-core targets.
6. Run GDB using the following command from the project root directory: 6. Run GDB using the following command from the project root directory:
@@ -132,12 +130,12 @@ NOTE: In order to run this example you need OpenOCD version `v0.10.0-esp32-20181
7. When program prints the last message, interrupt its execution (e.g. by pressing `CTRL+C`) and type the following command in GDB console to stop tracing: 7. When program prints the last message, interrupt its execution (e.g. by pressing `CTRL+C`) and type the following command in GDB console to stop tracing:
``` ```
mon esp sysview stop mon esp sysview_mcore stop
``` ```
You can also use another breakpoint to stop tracing and add respective lines to `gdbinit` at step 5. You can also use another breakpoint to stop tracing and add respective lines to `gdbinit` at step 5.
8. Open trace data file in SystemView tool. 8. Open trace data file in SystemView tool. The multi-core format produced by `esp sysview_mcore` requires SEGGER SystemView v3.60 or later.
9. Right-click on any event in `Events` view and select: 9. Right-click on any event in `Events` view and select:
+1 -3
View File
@@ -6,9 +6,7 @@ maintenance flush register-cache
b app_main b app_main
commands commands
mon esp sysview start file:///tmp/sysview_example.svdat mon esp sysview_mcore start file:///tmp/sysview_example.svdat
# For dual-core mode uncomment the line below and comment the line above
# mon esp sysview start file:///tmp/sysview_example0.svdat file:///tmp/sysview_example1.svdat
c c
end end
@@ -16,31 +16,35 @@ if typing.TYPE_CHECKING:
from conftest import OpenOCD from conftest import OpenOCD
def _validate_trace_data(trace_log: list[str], target: str, is_uart: bool = False) -> None: def _validate_trace_data(trace_log: str, target: str, dual_core: bool = False, is_uart: bool = False) -> None:
"""Validate SysView trace data in log file(s). """Validate SysView trace data in a single trace log file.
Args: Args:
trace_log: List of trace log paths trace_log: Path to the trace log file
target: Target chip name (e.g., 'esp32', 'esp32s3') target: Target chip name (e.g., 'esp32', 'esp32s3')
dual_core: If True, expect a per-core description block for both cores
(the ``esp sysview_mcore`` multi-core capture embeds one per core)
is_uart: If True, also validate STOP record at end of file is_uart: If True, also validate STOP record at end of file
""" """
STOP_EVENT_ID = 0x0B # SYSVIEW_EVTID_TRACE_STOP STOP_EVENT_ID = 0x0B # SYSVIEW_EVTID_TRACE_STOP
for idx, log in enumerate(trace_log): with open(trace_log, 'rb') as f:
with open(log, 'rb') as f: content = f.read()
content = f.read()
search_str = f'N=FreeRTOS Application,D={target},C=core{idx},O=FreeRTOS'.encode() for idx in range(2 if dual_core else 1):
assert search_str in content, f'SysView trace data not found in {log}' search_str = f'N=FreeRTOS Application,D={target},C=core{idx},O=FreeRTOS'.encode()
# The file must end with a TRACE_STOP record: the STOP event ID assert search_str in content, f'SysView core{idx} trace data not found in {trace_log}'
# followed by a variable-length timestamp delta. Walk back
# over the trailing continuation bytes (0x80 bit set) # The file must end with a TRACE_STOP record: the STOP event ID
# to find the event ID, since its offset is not fixed. # followed by a variable-length timestamp delta. Walk back
size = len(content) # over the trailing continuation bytes (0x80 bit set)
assert size >= 2, 'Trace file too small to contain STOP record' # to find the event ID, since its offset is not fixed.
i = size - 2 size = len(content)
while i >= 0 and (content[i] & 0x80): assert size >= 2, 'Trace file too small to contain STOP record'
i -= 1 i = size - 2
assert i >= 0 and content[i] == STOP_EVENT_ID, 'STOP record does not start with STOP eventID' while i >= 0 and (content[i] & 0x80):
i -= 1
assert i >= 0 and content[i] == STOP_EVENT_ID, 'STOP record does not start with STOP eventID'
def _capture_sysview_trace(ser: serial.Serial, trace_log_path: str) -> None: def _capture_sysview_trace(ser: serial.Serial, trace_log_path: str) -> None:
@@ -86,22 +90,19 @@ def _capture_sysview_trace(ser: serial.Serial, trace_log_path: str) -> None:
def _test_sysview_tracing_jtag(openocd_dut: 'OpenOCD', dut: IdfDut) -> None: def _test_sysview_tracing_jtag(openocd_dut: 'OpenOCD', dut: IdfDut) -> None:
# Construct trace log paths # Single multi-core capture file (esp sysview_mcore): one file is enough for
trace_log = [ # both single- and dual-core targets.
os.path.join(dut.logdir, 'sys_log0.svdat') # pylint: disable=protected-access trace_log = os.path.join(dut.logdir, 'sys_log.svdat') # pylint: disable=protected-access
] dual_core = not dut.app.sdkconfig.get('ESP_SYSTEM_SINGLE_CORE_MODE') or dut.target == 'esp32s3'
if not dut.app.sdkconfig.get('ESP_SYSTEM_SINGLE_CORE_MODE') or dut.target == 'esp32s3':
trace_log.append(os.path.join(dut.logdir, 'sys_log1.svdat')) # pylint: disable=protected-access
trace_files = ' '.join([f'file://{log}' for log in trace_log])
# Prepare gdbinit file # Prepare gdbinit file pointing at this run's capture file
gdb_logfile = os.path.join(dut.logdir, 'gdb.txt') gdb_logfile = os.path.join(dut.logdir, 'gdb.txt')
gdbinit_orig = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'gdbinit') gdbinit_orig = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'gdbinit')
gdbinit = os.path.join(dut.logdir, 'gdbinit') gdbinit = os.path.join(dut.logdir, 'gdbinit')
with open(gdbinit_orig) as f_r, open(gdbinit, 'w') as f_w: with open(gdbinit_orig) as f_r, open(gdbinit, 'w') as f_w:
for line in f_r: for line in f_r:
if line.startswith('mon esp sysview start'): if line.startswith('mon esp sysview_mcore start'):
f_w.write(f'mon esp sysview start {trace_files}\n') f_w.write(f'mon esp sysview_mcore start file://{trace_log}\n')
else: else:
f_w.write(line) f_w.write(line)
@@ -127,9 +128,9 @@ def _test_sysview_tracing_jtag(openocd_dut: 'OpenOCD', dut: IdfDut) -> None:
# Do a sleep while sysview samples are captured. # Do a sleep while sysview samples are captured.
time.sleep(3) time.sleep(3)
openocd.write('esp sysview stop') openocd.write('esp sysview_mcore stop')
_validate_trace_data(trace_log, dut.target) _validate_trace_data(trace_log, dut.target, dual_core=dual_core)
@pytest.mark.jtag @pytest.mark.jtag
@@ -155,8 +156,8 @@ def _test_sysview_tracing_uart(dut: IdfDut) -> None:
dut.serial.close() dut.serial.close()
time.sleep(2) # Wait for the DUT to reboot time.sleep(2) # Wait for the DUT to reboot
with serial.Serial(dut.serial.port, baudrate=dut.app.sdkconfig.get('APPTRACE_UART_BAUDRATE'), timeout=3) as ser: with serial.Serial(dut.serial.port, baudrate=dut.app.sdkconfig.get('APPTRACE_UART_BAUDRATE'), timeout=3) as ser:
trace_log = [os.path.join(dut.logdir, 'sys_log_uart.svdat')] # pylint: disable=protected-access trace_log = os.path.join(dut.logdir, 'sys_log_uart.svdat') # pylint: disable=protected-access
_capture_sysview_trace(ser, trace_log[0]) _capture_sysview_trace(ser, trace_log)
_validate_trace_data(trace_log, dut.target, is_uart=True) _validate_trace_data(trace_log, dut.target, is_uart=True)
@@ -184,6 +185,6 @@ def test_sysview_tracing_usj_serial(dut: IdfDut) -> None:
time.sleep(1) # wait for USJ port to be ready time.sleep(1) # wait for USJ port to be ready
usj_port = '/dev/serial_ports/ttyACM-esp32' usj_port = '/dev/serial_ports/ttyACM-esp32'
ser = serial.Serial(usj_port, baudrate=1000000, timeout=10) ser = serial.Serial(usj_port, baudrate=1000000, timeout=10)
trace_log = [os.path.join(dut.logdir, 'sys_log_usj.svdat')] # pylint: disable=protected-access trace_log = os.path.join(dut.logdir, 'sys_log_usj.svdat') # pylint: disable=protected-access
_capture_sysview_trace(ser, trace_log[0]) _capture_sysview_trace(ser, trace_log)
_validate_trace_data(trace_log, dut.target, is_uart=True) _validate_trace_data(trace_log, dut.target, is_uart=True)