Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
draw_functrace.py
Go to the documentation of this file.
1 #!/usr/bin/python
2 
3 """
4 Copyright 2008 (c) Frederic Weisbecker <[email protected]>
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  # 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/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 
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()