Changes in 4.9.280 ALSA: seq: Fix racy deletion of subscriber scsi: sr: Return correct event when media event code is 3 media: videobuf2-core: dequeue if start_streaming fails net: natsemi: Fix missing pci_disable_device() in probe and remove mips: Fix non-POSIX regexp bnx2x: fix an error code in bnx2x_nic_load() net: pegasus: fix uninit-value in get_interrupt_interval net: fec: fix use-after-free in fec_drv_remove net: vxge: fix use-after-free in vxge_device_unregister Bluetooth: defer cleanup of resources in hci_unregister_dev() USB: usbtmc: Fix RCU stall warning USB: serial: option: add Telit FD980 composition 0x1056 USB: serial: ch341: fix character loss at high transfer rates USB: serial: ftdi_sio: add device ID for Auto-M3 OP-COM v2 usb: otg-fsm: Fix hrtimer list corruption scripts/tracing: fix the bug that can't parse raw_trace_func media: rtl28xxu: fix zero-length control request pipe: increase minimum default pipe size to 2 pages serial: 8250: Mask out floating 16/32-bit bus bits MIPS: Malta: Do not byte-swap accesses to the CBUS UART pcmcia: i82092: fix a null pointer dereference bug perf/x86/amd: Don't touch the AMD64_EVENTSEL_HOSTONLY bit inside the guest reiserfs: add check for root_inode in reiserfs_fill_super reiserfs: check directory items on read from disk alpha: Send stop IPI to send to online CPUs net/qla3xxx: fix schedule while atomic in ql_wait_for_drvr_lock and ql_adapter_reset USB:ehci:fix Kunpeng920 ehci hardware problem ppp: Fix generating ppp unit id when ifname is not specified net: xilinx_emaclite: Do not print real IOMEM pointer ovl: prevent private clone if bind mount is not allowed Linux 4.9.280 Signed-off-by: Greg Kroah-Hartman <gregkh@google.com> Change-Id: I9ec4951d64f625a7bd15aec0fae6c294e3ec0897
130 lines
3.5 KiB
Python
Executable File
130 lines
3.5 KiB
Python
Executable File
#!/usr/bin/env python
|
|
|
|
"""
|
|
Copyright 2008 (c) Frederic Weisbecker <fweisbec@gmail.com>
|
|
Licensed under the terms of the GNU GPL License version 2
|
|
|
|
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
|
|
calls. Only the functions's names and the the call time are provided.
|
|
|
|
Usage:
|
|
Be sure that you have CONFIG_FUNCTION_TRACER
|
|
# mount -t debugfs nodev /sys/kernel/debug
|
|
# echo function > /sys/kernel/debug/tracing/current_tracer
|
|
$ cat /sys/kernel/debug/tracing/trace_pipe > ~/raw_trace_func
|
|
Wait some times but not too much, the script is a bit slow.
|
|
Break the pipe (Ctrl + Z)
|
|
$ scripts/tracing/draw_functrace.py < ~/raw_trace_func > draw_functrace
|
|
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
|
|
m = re.match("[^]]+?\\] +([a-z.]+) +([0-9.]+): (\\w+) <-(\\w+)", line)
|
|
if m is None:
|
|
raise BrokenLineException
|
|
return (m.group(2), m.group(3), m.group(4))
|
|
|
|
|
|
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)
|
|
|
|
print CallTree.ROOT
|
|
|
|
if __name__ == "__main__":
|
|
main()
|