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