Merge branches 'tracing/fastboot', 'tracing/ftrace' and 'tracing/urgent' into tracing...
[linux-2.6] / scripts / tracing / draw_functrace.py
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()