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