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