Merge tag 'mmc-v5.14-rc4' of git://git.kernel.org/pub/scm/linux/kernel/git/ulfh/mmc
[platform/kernel/linux-starfive.git] / scripts / tracing / draw_functrace.py
1 #!/usr/bin/env python
2 # SPDX-License-Identifier: GPL-2.0-only
3
4 """
5 Copyright 2008 (c) Frederic Weisbecker <fweisbec@gmail.com>
6
7 This script parses a trace provided by the function tracer in
8 kernel/trace/trace_functions.c
9 The resulted trace is processed into a tree to produce a more human
10 view of the call stack by drawing textual but hierarchical tree of
11 calls. Only the functions's names and the the call time are provided.
12
13 Usage:
14         Be sure that you have CONFIG_FUNCTION_TRACER
15         # mount -t debugfs nodev /sys/kernel/debug
16         # echo function > /sys/kernel/debug/tracing/current_tracer
17         $ cat /sys/kernel/debug/tracing/trace_pipe > ~/raw_trace_func
18         Wait some times but not too much, the script is a bit slow.
19         Break the pipe (Ctrl + Z)
20         $ scripts/tracing/draw_functrace.py < ~/raw_trace_func > draw_functrace
21         Then you have your drawn trace in draw_functrace
22 """
23
24
25 import sys, re
26
27 class CallTree:
28         """ This class provides a tree representation of the functions
29                 call stack. If a function has no parent in the kernel (interrupt,
30                 syscall, kernel thread...) then it is attached to a virtual parent
31                 called ROOT.
32         """
33         ROOT = None
34
35         def __init__(self, func, time = None, parent = None):
36                 self._func = func
37                 self._time = time
38                 if parent is None:
39                         self._parent = CallTree.ROOT
40                 else:
41                         self._parent = parent
42                 self._children = []
43
44         def calls(self, func, calltime):
45                 """ If a function calls another one, call this method to insert it
46                         into the tree at the appropriate place.
47                         @return: A reference to the newly created child node.
48                 """
49                 child = CallTree(func, calltime, self)
50                 self._children.append(child)
51                 return child
52
53         def getParent(self, func):
54                 """ Retrieve the last parent of the current node that
55                         has the name given by func. If this function is not
56                         on a parent, then create it as new child of root
57                         @return: A reference to the parent.
58                 """
59                 tree = self
60                 while tree != CallTree.ROOT and tree._func != func:
61                         tree = tree._parent
62                 if tree == CallTree.ROOT:
63                         child = CallTree.ROOT.calls(func, None)
64                         return child
65                 return tree
66
67         def __repr__(self):
68                 return self.__toString("", True)
69
70         def __toString(self, branch, lastChild):
71                 if self._time is not None:
72                         s = "%s----%s (%s)\n" % (branch, self._func, self._time)
73                 else:
74                         s = "%s----%s\n" % (branch, self._func)
75
76                 i = 0
77                 if lastChild:
78                         branch = branch[:-1] + " "
79                 while i < len(self._children):
80                         if i != len(self._children) - 1:
81                                 s += "%s" % self._children[i].__toString(branch +\
82                                                                 "    |", False)
83                         else:
84                                 s += "%s" % self._children[i].__toString(branch +\
85                                                                 "    |", True)
86                         i += 1
87                 return s
88
89 class BrokenLineException(Exception):
90         """If the last line is not complete because of the pipe breakage,
91            we want to stop the processing and ignore this line.
92         """
93         pass
94
95 class CommentLineException(Exception):
96         """ If the line is a comment (as in the beginning of the trace file),
97             just ignore it.
98         """
99         pass
100
101
102 def parseLine(line):
103         line = line.strip()
104         if line.startswith("#"):
105                 raise CommentLineException
106         m = re.match("[^]]+?\\] +([a-z.]+) +([0-9.]+): (\\w+) <-(\\w+)", line)
107         if m is None:
108                 raise BrokenLineException
109         return (m.group(2), m.group(3), m.group(4))
110
111
112 def main():
113         CallTree.ROOT = CallTree("Root (Nowhere)", None, None)
114         tree = CallTree.ROOT
115
116         for line in sys.stdin:
117                 try:
118                         calltime, callee, caller = parseLine(line)
119                 except BrokenLineException:
120                         break
121                 except CommentLineException:
122                         continue
123                 tree = tree.getParent(caller)
124                 tree = tree.calls(callee, calltime)
125
126         print(CallTree.ROOT)
127
128 if __name__ == "__main__":
129         main()