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