Back to home page

OSCL-LXR

 
 

    


0001 #!/usr/bin/env python
0002 # SPDX-License-Identifier: GPL-2.0-only
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()