Blame view

scripts/tracing/draw_functrace.py 3.48 KB
f4a2a0d9a   Frederic Weisbecker   ftrace: add a scr...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
  #!/usr/bin/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
156f5a780   GeunSik Lim   debugfs: Fix term...
15
16
17
  	# 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
f4a2a0d9a   Frederic Weisbecker   ftrace: add a scr...
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
  	Wait some times but not too much, the script is a bit slow.
  	Break the pipe (Ctrl + Z)
  	$ scripts/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)
  " % (branch, self._func, self._time)
  		else:
  			s = "%s----%s
  " % (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("[^]]+?\\] +([0-9.]+): (\\w+) <-(\\w+)", line)
  	if m is None:
  		raise BrokenLineException
  	return (m.group(1), m.group(2), m.group(3))
  
  
  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()