Disables allowing the python argparse library from automatically shortening command line arguments, this prevents issues whereby a new command is added and code that wrongly uses the shortened command of an existing argument which is the same as the new command being added will silently change script behaviour. Signed-off-by: Jamie McCrae <jamie.mccrae@nordicsemi.no>
145 lines
4.9 KiB
Python
145 lines
4.9 KiB
Python
#!/usr/bin/env python3
|
|
#
|
|
# Copyright (c) 2020 Intel Corporation.
|
|
#
|
|
# SPDX-License-Identifier: Apache-2.0
|
|
"""
|
|
Script to parse CTF data and print to the screen in a custom and colorful
|
|
format.
|
|
|
|
Generate trace using samples/subsys/tracing for example:
|
|
|
|
west build -b qemu_x86 samples/subsys/tracing -t run \
|
|
-- -DCONF_FILE=prj_uart_ctf.conf
|
|
|
|
mkdir ctf
|
|
cp build/channel0_0 ctf/
|
|
cp subsys/tracing/ctf/tsdl/metadata ctf/
|
|
./scripts/tracing/parse_ctf.py -t ctf
|
|
"""
|
|
|
|
import sys
|
|
import datetime
|
|
import colorama
|
|
from colorama import Fore
|
|
import argparse
|
|
try:
|
|
import bt2
|
|
except ImportError:
|
|
sys.exit("Missing dependency: You need to install python bindings of babletrace.")
|
|
|
|
def parse_args():
|
|
parser = argparse.ArgumentParser(
|
|
description=__doc__,
|
|
formatter_class=argparse.RawDescriptionHelpFormatter, allow_abbrev=False)
|
|
parser.add_argument("-t", "--trace",
|
|
required=True,
|
|
help="tracing data (directory with metadata and trace file)")
|
|
args = parser.parse_args()
|
|
return args
|
|
|
|
def main():
|
|
colorama.init()
|
|
|
|
args = parse_args()
|
|
|
|
msg_it = bt2.TraceCollectionMessageIterator(args.trace)
|
|
last_event_ns_from_origin = None
|
|
timeline = []
|
|
|
|
def get_thread(name):
|
|
for t in timeline:
|
|
if t.get('name', None) == name and t.get('in', 0 ) != 0 and not t.get('out', None):
|
|
return t
|
|
return {}
|
|
|
|
for msg in msg_it:
|
|
|
|
if not isinstance(msg, bt2._EventMessageConst):
|
|
continue
|
|
|
|
ns_from_origin = msg.default_clock_snapshot.ns_from_origin
|
|
event = msg.event
|
|
# Compute the time difference since the last event message.
|
|
diff_s = 0
|
|
|
|
if last_event_ns_from_origin is not None:
|
|
diff_s = (ns_from_origin - last_event_ns_from_origin) / 1e9
|
|
|
|
dt = datetime.datetime.fromtimestamp(ns_from_origin / 1e9)
|
|
|
|
if event.name in [
|
|
'thread_switched_out',
|
|
'thread_switched_in',
|
|
'thread_pending',
|
|
'thread_ready',
|
|
'thread_resume',
|
|
'thread_suspend',
|
|
'thread_create',
|
|
'thread_abort'
|
|
]:
|
|
|
|
cpu = event.payload_field.get("cpu", None)
|
|
thread_id = event.payload_field.get("thread_id", None)
|
|
thread_name = event.payload_field.get("name", None)
|
|
|
|
th = {}
|
|
if event.name in ['thread_switched_out', 'thread_switched_in'] and cpu is not None:
|
|
cpu_string = f"(cpu: {cpu})"
|
|
else:
|
|
cpu_string = ""
|
|
|
|
if thread_name:
|
|
print(f"{dt} (+{diff_s:.6f} s): {event.name}: {thread_name} {cpu_string}")
|
|
elif thread_id:
|
|
print(f"{dt} (+{diff_s:.6f} s): {event.name}: {thread_id} {cpu_string}")
|
|
else:
|
|
print(f"{dt} (+{diff_s:.6f} s): {event.name}")
|
|
|
|
if event.name in ['thread_switched_out', 'thread_switched_in']:
|
|
if thread_name:
|
|
th = get_thread(thread_name)
|
|
if not th:
|
|
th['name'] = thread_name
|
|
else:
|
|
th = get_thread(thread_id)
|
|
if not th:
|
|
th['name'] = thread_id
|
|
|
|
if event.name in ['thread_switched_out']:
|
|
th['out'] = ns_from_origin
|
|
tin = th.get('in', None)
|
|
tout = th.get('out', None)
|
|
if tout is not None and tin is not None:
|
|
diff = (tout - tin)
|
|
th['runtime'] = diff
|
|
elif event.name in ['thread_switched_in']:
|
|
th['in'] = ns_from_origin
|
|
|
|
timeline.append(th)
|
|
|
|
elif event.name in ['thread_info']:
|
|
stack_size = event.payload_field['stack_size']
|
|
print(f"{dt} (+{diff_s:.6f} s): {event.name} (Stack size: {stack_size})")
|
|
elif event.name in ['start_call', 'end_call']:
|
|
if event.payload_field['id'] == 39:
|
|
c = Fore.GREEN
|
|
elif event.payload_field['id'] in [37, 38]:
|
|
c = Fore.CYAN
|
|
else:
|
|
c = Fore.YELLOW
|
|
print(c + f"{dt} (+{diff_s:.6f} s): {event.name} {event.payload_field['id']}" + Fore.RESET)
|
|
elif event.name in ['semaphore_init', 'semaphore_take', 'semaphore_give']:
|
|
c = Fore.CYAN
|
|
print(c + f"{dt} (+{diff_s:.6f} s): {event.name} ({event.payload_field['id']})" + Fore.RESET)
|
|
elif event.name in ['mutex_init', 'mutex_take', 'mutex_give']:
|
|
c = Fore.MAGENTA
|
|
print(c + f"{dt} (+{diff_s:.6f} s): {event.name} ({event.payload_field['id']})" + Fore.RESET)
|
|
|
|
else:
|
|
print(f"{dt} (+{diff_s:.6f} s): {event.name}")
|
|
|
|
last_event_ns_from_origin = ns_from_origin
|
|
|
|
if __name__=="__main__":
|
|
main()
|