0001
0002
0003
0004 """
0005 Copyright 2008 (c) Frederic Weisbecker <fweisbec@gmail.com>
0006
0007 This script parses a trace provided by the function tracer in
0008 kernel/trace/trace_functions.c
0009 The resulted trace is processed into a tree to produce a more human
0010 view of the call stack by drawing textual but hierarchical tree of
0011 calls. Only the functions's names and the call time are provided.
0012
0013 Usage:
0014 Be sure that you have CONFIG_FUNCTION_TRACER
0015 # mount -t debugfs nodev /sys/kernel/debug
0016 # echo function > /sys/kernel/debug/tracing/current_tracer
0017 $ cat /sys/kernel/debug/tracing/trace_pipe > ~/raw_trace_func
0018 Wait some times but not too much, the script is a bit slow.
0019 Break the pipe (Ctrl + Z)
0020 $ scripts/tracing/draw_functrace.py < ~/raw_trace_func > draw_functrace
0021 Then you have your drawn trace in draw_functrace
0022 """
0023
0024
0025 import sys, re
0026
0027 class CallTree:
0028 """ This class provides a tree representation of the functions
0029 call stack. If a function has no parent in the kernel (interrupt,
0030 syscall, kernel thread...) then it is attached to a virtual parent
0031 called ROOT.
0032 """
0033 ROOT = None
0034
0035 def __init__(self, func, time = None, parent = None):
0036 self._func = func
0037 self._time = time
0038 if parent is None:
0039 self._parent = CallTree.ROOT
0040 else:
0041 self._parent = parent
0042 self._children = []
0043
0044 def calls(self, func, calltime):
0045 """ If a function calls another one, call this method to insert it
0046 into the tree at the appropriate place.
0047 @return: A reference to the newly created child node.
0048 """
0049 child = CallTree(func, calltime, self)
0050 self._children.append(child)
0051 return child
0052
0053 def getParent(self, func):
0054 """ Retrieve the last parent of the current node that
0055 has the name given by func. If this function is not
0056 on a parent, then create it as new child of root
0057 @return: A reference to the parent.
0058 """
0059 tree = self
0060 while tree != CallTree.ROOT and tree._func != func:
0061 tree = tree._parent
0062 if tree == CallTree.ROOT:
0063 child = CallTree.ROOT.calls(func, None)
0064 return child
0065 return tree
0066
0067 def __repr__(self):
0068 return self.__toString("", True)
0069
0070 def __toString(self, branch, lastChild):
0071 if self._time is not None:
0072 s = "%s----%s (%s)\n" % (branch, self._func, self._time)
0073 else:
0074 s = "%s----%s\n" % (branch, self._func)
0075
0076 i = 0
0077 if lastChild:
0078 branch = branch[:-1] + " "
0079 while i < len(self._children):
0080 if i != len(self._children) - 1:
0081 s += "%s" % self._children[i].__toString(branch +\
0082 " |", False)
0083 else:
0084 s += "%s" % self._children[i].__toString(branch +\
0085 " |", True)
0086 i += 1
0087 return s
0088
0089 class BrokenLineException(Exception):
0090 """If the last line is not complete because of the pipe breakage,
0091 we want to stop the processing and ignore this line.
0092 """
0093 pass
0094
0095 class CommentLineException(Exception):
0096 """ If the line is a comment (as in the beginning of the trace file),
0097 just ignore it.
0098 """
0099 pass
0100
0101
0102 def parseLine(line):
0103 line = line.strip()
0104 if line.startswith("#"):
0105 raise CommentLineException
0106 m = re.match("[^]]+?\\] +([a-z.]+) +([0-9.]+): (\\w+) <-(\\w+)", line)
0107 if m is None:
0108 raise BrokenLineException
0109 return (m.group(2), m.group(3), m.group(4))
0110
0111
0112 def main():
0113 CallTree.ROOT = CallTree("Root (Nowhere)", None, None)
0114 tree = CallTree.ROOT
0115
0116 for line in sys.stdin:
0117 try:
0118 calltime, callee, caller = parseLine(line)
0119 except BrokenLineException:
0120 break
0121 except CommentLineException:
0122 continue
0123 tree = tree.getParent(caller)
0124 tree = tree.calls(callee, calltime)
0125
0126 print(CallTree.ROOT)
0127
0128 if __name__ == "__main__":
0129 main()