linux/scripts/tracing/draw_functrace.py
<<
>>
Prefs
   1#!/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
  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
  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()
 130