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