| #!/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) |
| 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() |