blob: db40fa04cd513f4a68d86af935fec02f27e507d2 [file] [log] [blame]
Frederic Weisbeckerf4a2a0d2008-10-27 02:05:25 +01001#!/usr/bin/python
2
3"""
4Copyright 2008 (c) Frederic Weisbecker <fweisbec@gmail.com>
5Licensed under the terms of the GNU GPL License version 2
6
7This script parses a trace provided by the function tracer in
8kernel/trace/trace_functions.c
9The resulted trace is processed into a tree to produce a more human
10view of the call stack by drawing textual but hierarchical tree of
11calls. Only the functions's names and the the call time are provided.
12
13Usage:
14 Be sure that you have CONFIG_FUNCTION_TRACER
GeunSik Lim156f5a72009-06-02 15:01:37 +090015 # 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
Frederic Weisbeckerf4a2a0d2008-10-27 02:05:25 +010018 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
25import sys, re
26
27class 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
89class 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
95class 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
102def 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
112def 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
128if __name__ == "__main__":
129 main()