2020-11-23 17:15:33 +03:00
#!/usr/bin/env python
2019-05-27 09:55:14 +03:00
# SPDX-License-Identifier: GPL-2.0-only
2008-10-27 04:05:25 +03:00
"""
Copyright 2008 ( c ) Frederic Weisbecker < fweisbec @gmail.com >
This script parses a trace provided by the function tracer in
kernel / trace / trace_functions . c
The resulted trace is processed into a tree to produce a more human
view of the call stack by drawing textual but hierarchical tree of
2022-07-22 13:29:07 +03:00
calls . Only the functions ' s names and the call time are provided.
2008-10-27 04:05:25 +03:00
Usage :
Be sure that you have CONFIG_FUNCTION_TRACER
2023-02-16 01:33:45 +03:00
# mount -t tracefs nodev /sys/kernel/tracing
# echo function > /sys/kernel/tracing/current_tracer
$ cat / sys / kernel / tracing / trace_pipe > ~ / raw_trace_func
2008-10-27 04:05:25 +03:00
Wait some times but not too much , the script is a bit slow .
Break the pipe ( Ctrl + Z )
2021-06-11 05:21:07 +03:00
$ scripts / tracing / draw_functrace . py < ~ / raw_trace_func > draw_functrace
2008-10-27 04:05:25 +03:00
Then you have your drawn trace in draw_functrace
"""
import sys , re
class CallTree :
""" This class provides a tree representation of the functions
call stack . If a function has no parent in the kernel ( interrupt ,
syscall , kernel thread . . . ) then it is attached to a virtual parent
called ROOT .
"""
ROOT = None
def __init__ ( self , func , time = None , parent = None ) :
self . _func = func
self . _time = time
if parent is None :
self . _parent = CallTree . ROOT
else :
self . _parent = parent
self . _children = [ ]
def calls ( self , func , calltime ) :
""" If a function calls another one, call this method to insert it
into the tree at the appropriate place .
@return : A reference to the newly created child node .
"""
child = CallTree ( func , calltime , self )
self . _children . append ( child )
return child
def getParent ( self , func ) :
""" Retrieve the last parent of the current node that
has the name given by func . If this function is not
on a parent , then create it as new child of root
@return : A reference to the parent .
"""
tree = self
while tree != CallTree . ROOT and tree . _func != func :
tree = tree . _parent
if tree == CallTree . ROOT :
child = CallTree . ROOT . calls ( func , None )
return child
return tree
def __repr__ ( self ) :
return self . __toString ( " " , True )
def __toString ( self , branch , lastChild ) :
if self . _time is not None :
s = " %s ---- %s ( %s ) \n " % ( branch , self . _func , self . _time )
else :
s = " %s ---- %s \n " % ( branch , self . _func )
i = 0
if lastChild :
branch = branch [ : - 1 ] + " "
while i < len ( self . _children ) :
if i != len ( self . _children ) - 1 :
s + = " %s " % self . _children [ i ] . __toString ( branch + \
" | " , False )
else :
s + = " %s " % self . _children [ i ] . __toString ( branch + \
" | " , True )
i + = 1
return s
class BrokenLineException ( Exception ) :
""" If the last line is not complete because of the pipe breakage,
we want to stop the processing and ignore this line .
"""
pass
class CommentLineException ( Exception ) :
""" If the line is a comment (as in the beginning of the trace file),
just ignore it .
"""
pass
def parseLine ( line ) :
line = line . strip ( )
if line . startswith ( " # " ) :
raise CommentLineException
2021-06-11 05:21:07 +03:00
m = re . match ( " [^]]+? \\ ] +([a-z.]+) +([0-9.]+): ( \\ w+) <-( \\ w+) " , line )
2008-10-27 04:05:25 +03:00
if m is None :
raise BrokenLineException
2021-06-11 05:21:07 +03:00
return ( m . group ( 2 ) , m . group ( 3 ) , m . group ( 4 ) )
2008-10-27 04:05:25 +03:00
def main ( ) :
CallTree . ROOT = CallTree ( " Root (Nowhere) " , None , None )
tree = CallTree . ROOT
for line in sys . stdin :
try :
calltime , callee , caller = parseLine ( line )
except BrokenLineException :
break
except CommentLineException :
continue
tree = tree . getParent ( caller )
tree = tree . calls ( callee , calltime )
2018-07-28 17:48:33 +03:00
print ( CallTree . ROOT )
2008-10-27 04:05:25 +03:00
if __name__ == " __main__ " :
main ( )