Anas Nashif | 5ab117f | 2020-08-20 16:19:08 -0400 | [diff] [blame] | 1 | #!/usr/bin/env python3 |
| 2 | # |
| 3 | # Copyright (c) 2020 Intel Corporation. |
| 4 | # |
| 5 | # SPDX-License-Identifier: Apache-2.0 |
| 6 | """ |
| 7 | Script to parse CTF data and print to the screen in a custom and colorful |
| 8 | format. |
| 9 | |
| 10 | Generate trace using samples/subsys/tracing for example: |
| 11 | |
| 12 | west build -b qemu_x86 samples/subsys/tracing -t run \ |
| 13 | -- -DCONF_FILE=prj_uart_ctf.conf |
| 14 | |
| 15 | mkdir ctf |
| 16 | cp build/channel0_0 ctf/ |
| 17 | cp subsys/tracing/ctf/tsdl/metadata ctf/ |
| 18 | ./scripts/tracing/parse_ctf.py -t ctf |
| 19 | """ |
| 20 | |
| 21 | import sys |
| 22 | import datetime |
Stephanos Ioannidis | e332ddb | 2022-05-23 19:20:15 +0900 | [diff] [blame] | 23 | import colorama |
Anas Nashif | 5ab117f | 2020-08-20 16:19:08 -0400 | [diff] [blame] | 24 | from colorama import Fore |
| 25 | import argparse |
| 26 | try: |
| 27 | import bt2 |
| 28 | except ImportError: |
Gustavo Romero | 7ab955e | 2023-01-27 18:44:05 +0000 | [diff] [blame] | 29 | sys.exit("Missing dependency: You need to install python bindings of babeltrace.") |
Anas Nashif | 5ab117f | 2020-08-20 16:19:08 -0400 | [diff] [blame] | 30 | |
| 31 | def parse_args(): |
| 32 | parser = argparse.ArgumentParser( |
| 33 | description=__doc__, |
Jamie McCrae | ec70444 | 2023-01-04 16:08:36 +0000 | [diff] [blame] | 34 | formatter_class=argparse.RawDescriptionHelpFormatter, allow_abbrev=False) |
Anas Nashif | 5ab117f | 2020-08-20 16:19:08 -0400 | [diff] [blame] | 35 | parser.add_argument("-t", "--trace", |
| 36 | required=True, |
| 37 | help="tracing data (directory with metadata and trace file)") |
| 38 | args = parser.parse_args() |
| 39 | return args |
| 40 | |
| 41 | def main(): |
Stephanos Ioannidis | e332ddb | 2022-05-23 19:20:15 +0900 | [diff] [blame] | 42 | colorama.init() |
| 43 | |
Anas Nashif | 5ab117f | 2020-08-20 16:19:08 -0400 | [diff] [blame] | 44 | args = parse_args() |
| 45 | |
| 46 | msg_it = bt2.TraceCollectionMessageIterator(args.trace) |
| 47 | last_event_ns_from_origin = None |
| 48 | timeline = [] |
| 49 | |
| 50 | def get_thread(name): |
| 51 | for t in timeline: |
| 52 | if t.get('name', None) == name and t.get('in', 0 ) != 0 and not t.get('out', None): |
| 53 | return t |
| 54 | return {} |
| 55 | |
| 56 | for msg in msg_it: |
| 57 | |
| 58 | if not isinstance(msg, bt2._EventMessageConst): |
| 59 | continue |
| 60 | |
| 61 | ns_from_origin = msg.default_clock_snapshot.ns_from_origin |
| 62 | event = msg.event |
| 63 | # Compute the time difference since the last event message. |
| 64 | diff_s = 0 |
| 65 | |
| 66 | if last_event_ns_from_origin is not None: |
| 67 | diff_s = (ns_from_origin - last_event_ns_from_origin) / 1e9 |
| 68 | |
| 69 | dt = datetime.datetime.fromtimestamp(ns_from_origin / 1e9) |
| 70 | |
| 71 | if event.name in [ |
| 72 | 'thread_switched_out', |
| 73 | 'thread_switched_in', |
| 74 | 'thread_pending', |
| 75 | 'thread_ready', |
| 76 | 'thread_resume', |
| 77 | 'thread_suspend', |
| 78 | 'thread_create', |
| 79 | 'thread_abort' |
| 80 | ]: |
| 81 | |
| 82 | cpu = event.payload_field.get("cpu", None) |
| 83 | thread_id = event.payload_field.get("thread_id", None) |
| 84 | thread_name = event.payload_field.get("name", None) |
| 85 | |
| 86 | th = {} |
| 87 | if event.name in ['thread_switched_out', 'thread_switched_in'] and cpu is not None: |
| 88 | cpu_string = f"(cpu: {cpu})" |
| 89 | else: |
| 90 | cpu_string = "" |
| 91 | |
| 92 | if thread_name: |
| 93 | print(f"{dt} (+{diff_s:.6f} s): {event.name}: {thread_name} {cpu_string}") |
| 94 | elif thread_id: |
| 95 | print(f"{dt} (+{diff_s:.6f} s): {event.name}: {thread_id} {cpu_string}") |
| 96 | else: |
| 97 | print(f"{dt} (+{diff_s:.6f} s): {event.name}") |
| 98 | |
| 99 | if event.name in ['thread_switched_out', 'thread_switched_in']: |
| 100 | if thread_name: |
| 101 | th = get_thread(thread_name) |
| 102 | if not th: |
| 103 | th['name'] = thread_name |
| 104 | else: |
| 105 | th = get_thread(thread_id) |
| 106 | if not th: |
| 107 | th['name'] = thread_id |
| 108 | |
| 109 | if event.name in ['thread_switched_out']: |
| 110 | th['out'] = ns_from_origin |
| 111 | tin = th.get('in', None) |
| 112 | tout = th.get('out', None) |
| 113 | if tout is not None and tin is not None: |
Gustavo Romero | 7ab955e | 2023-01-27 18:44:05 +0000 | [diff] [blame] | 114 | diff = tout - tin |
Anas Nashif | 5ab117f | 2020-08-20 16:19:08 -0400 | [diff] [blame] | 115 | th['runtime'] = diff |
| 116 | elif event.name in ['thread_switched_in']: |
| 117 | th['in'] = ns_from_origin |
| 118 | |
| 119 | timeline.append(th) |
| 120 | |
| 121 | elif event.name in ['thread_info']: |
| 122 | stack_size = event.payload_field['stack_size'] |
| 123 | print(f"{dt} (+{diff_s:.6f} s): {event.name} (Stack size: {stack_size})") |
| 124 | elif event.name in ['start_call', 'end_call']: |
| 125 | if event.payload_field['id'] == 39: |
| 126 | c = Fore.GREEN |
| 127 | elif event.payload_field['id'] in [37, 38]: |
| 128 | c = Fore.CYAN |
| 129 | else: |
| 130 | c = Fore.YELLOW |
| 131 | print(c + f"{dt} (+{diff_s:.6f} s): {event.name} {event.payload_field['id']}" + Fore.RESET) |
| 132 | elif event.name in ['semaphore_init', 'semaphore_take', 'semaphore_give']: |
| 133 | c = Fore.CYAN |
| 134 | print(c + f"{dt} (+{diff_s:.6f} s): {event.name} ({event.payload_field['id']})" + Fore.RESET) |
| 135 | elif event.name in ['mutex_init', 'mutex_take', 'mutex_give']: |
| 136 | c = Fore.MAGENTA |
| 137 | print(c + f"{dt} (+{diff_s:.6f} s): {event.name} ({event.payload_field['id']})" + Fore.RESET) |
| 138 | |
Daniel DeGrasse | 66577a9 | 2024-06-10 19:54:36 +0000 | [diff] [blame] | 139 | elif event.name in ['named_event']: |
| 140 | name = event.payload_field['name'] |
| 141 | arg0 = event.payload_field['arg0'] |
| 142 | arg1 = event.payload_field['arg1'] |
| 143 | print(f"{dt} (+{diff_s:.6f} s): {event.name} (name: {name}, arg0: {arg0} arg1: {arg1})") |
Anas Nashif | 5ab117f | 2020-08-20 16:19:08 -0400 | [diff] [blame] | 144 | else: |
| 145 | print(f"{dt} (+{diff_s:.6f} s): {event.name}") |
| 146 | |
| 147 | last_event_ns_from_origin = ns_from_origin |
| 148 | |
| 149 | if __name__=="__main__": |
| 150 | main() |