xref: /optee_os/scripts/ftrace_format.py (revision 5c2c0fb31efbeff60960336d7438e810b825d582)
1#!/usr/bin/env python3
2# SPDX-License-Identifier: BSD-2-Clause
3#
4# Copyright (c) 2023, Linaro Limited
5#
6# Converts a ftrace binary file to text. The input file has the following
7# format:
8#
9#  <ASCII text> <zero or more nul bytes> FTRACE\x00\x01 <binary data>...
10#
11# <binary data> is an array of 64-bit integers.
12# - When the topmost byte is 0, the entry indicates a function return and the
13# remaining bytes are a duration in nanoseconds.
14# - A non-zero value is a stack depth, indicating a function entry, and the
15# remaining bytes are the function's address.
16
17import sys
18
19
20line = ""
21curr_depth = 0
22
23
24def usage():
25    print(f"Usage: {sys.argv[0]} ftrace.out")
26    print("Converts a ftrace file to text. Output is written to stdout.")
27    sys.exit(0)
28
29
30def format_time(ns):
31    if ns < 1000000:
32        us = ns / 1000
33        return f"{us:7.3f} us"
34    else:
35        ms = ns / 1000000
36        return f"{ms:7.3f} ms"
37
38
39def display(depth, val):
40    global line, curr_depth
41    if depth != 0:
42        curr_depth = depth
43        if line != "":
44            line = line.replace("TIME", " " * 10) + " {"
45            print(line)
46            line = ""
47        line = f" TIME | {depth:3} | " + " " * depth + f"0x{val:016x}()"
48    else:
49        if line != "":
50            line = line.replace("TIME", format_time(val))
51            print(line)
52            line = ""
53        else:
54            if curr_depth != 0:
55                curr_depth = curr_depth - 1
56                print(" " + format_time(val) + f" | {curr_depth:3} | " +
57                      " " * curr_depth + "}")
58
59
60def main():
61    if len(sys.argv) < 2:
62        usage()
63    with open(sys.argv[1], 'rb') as f:
64        s = f.read()
65    magic = s.find(b'FTRACE\x00\x01')
66    if magic == -1:
67        print("Magic not found", file=sys.stderr)
68        sys.exit(1)
69    print(s[:magic].rstrip(b'\x00').decode())
70    s = s[magic + 8:]
71    for i in range(0, len(s), 8):
72        elem = int.from_bytes(s[i:i + 8], byteorder="little", signed=False)
73        depth = elem >> 56
74        val = elem & 0xFFFFFFFFFFFFFF
75        display(depth, val)
76
77
78if __name__ == "__main__":
79    main()
80