Commit | Line | Data |
---|---|---|
f4a2a0d9 FW |
1 | #!/usr/bin/python |
2 | ||
3 | """ | |
4 | Copyright 2008 (c) Frederic Weisbecker <fweisbec@gmail.com> | |
5 | Licensed under the terms of the GNU GPL License version 2 | |
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 | |
156f5a78 GL |
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 | |
f4a2a0d9 FW |
18 | Wait some times but not too much, the script is a bit slow. |
19 | Break the pipe (Ctrl + Z) | |
20 | $ scripts/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("[^]]+?\\] +([0-9.]+): (\\w+) <-(\\w+)", line) | |
107 | if m is None: | |
108 | raise BrokenLineException | |
109 | return (m.group(1), m.group(2), m.group(3)) | |
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() |