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