mirror of
				git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
				synced 2025-09-04 20:19:47 +08:00 
			
		
		
		
	 4f19048fd0
			
		
	
	
		4f19048fd0
		
	
	
	
	
		
			
			Based on 1 normalized pattern(s): licensed under the terms of the gnu gpl license version 2 extracted by the scancode license scanner the SPDX license identifier GPL-2.0-only has been chosen to replace the boilerplate/reference in 62 file(s). Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Reviewed-by: Allison Randal <allison@lohutok.net> Reviewed-by: Kate Stewart <kstewart@linuxfoundation.org> Reviewed-by: Richard Fontana <rfontana@redhat.com> Cc: linux-spdx@vger.kernel.org Link: https://lkml.kernel.org/r/20190527070033.929121379@linutronix.de Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
		
			
				
	
	
		
			130 lines
		
	
	
		
			3.5 KiB
		
	
	
	
		
			Python
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			130 lines
		
	
	
		
			3.5 KiB
		
	
	
	
		
			Python
		
	
	
		
			Executable File
		
	
	
	
	
| #!/usr/bin/python
 | |
| # SPDX-License-Identifier: GPL-2.0-only
 | |
| 
 | |
| """
 | |
| Copyright 2008 (c) Frederic Weisbecker <fweisbec@gmail.com>
 | |
| 
 | |
| 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/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("[^]]+?\\] +([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()
 |