1 # stackcollapse.py - format perf samples with one line per distinct call stack
2 # SPDX-License-Identifier: GPL-2.0
4 # This script's output has two space-separated fields. The first is a semicolon
5 # separated stack including the program name (from the "comm" field) and the
6 # function names from the call stack. The second is a count:
8 # swapper;start_kernel;rest_init;cpu_idle;default_idle;native_safe_halt 2
10 # The file is sorted according to the first field.
12 # Input may be created and processed using:
14 # perf record -a -g -F 99 sleep 60
15 # perf script report stackcollapse > out.stacks-folded
17 # (perf script record stackcollapse works too).
19 # Written by Paolo Bonzini <pbonzini@redhat.com>
20 # Based on Brendan Gregg's stackcollapse-perf.pl script.
22 from __future__
import print_function
26 from collections
import defaultdict
27 from optparse
import OptionParser
, make_option
29 sys
.path
.append(os
.environ
['PERF_EXEC_PATH'] + \
30 '/scripts/python/Perf-Trace-Util/lib/Perf/Trace')
32 from perf_trace_context
import *
34 from EventClass
import *
36 # command line parsing
39 # formatting options for the bottom entry of the stack
40 make_option("--include-tid", dest
="include_tid",
41 action
="store_true", default
=False,
42 help="include thread id in stack"),
43 make_option("--include-pid", dest
="include_pid",
44 action
="store_true", default
=False,
45 help="include process id in stack"),
46 make_option("--no-comm", dest
="include_comm",
47 action
="store_false", default
=True,
48 help="do not separate stacks according to comm"),
49 make_option("--tidy-java", dest
="tidy_java",
50 action
="store_true", default
=False,
51 help="beautify Java signatures"),
52 make_option("--kernel", dest
="annotate_kernel",
53 action
="store_true", default
=False,
54 help="annotate kernel functions with _[k]")
57 parser
= OptionParser(option_list
=option_list
)
58 (opts
, args
) = parser
.parse_args()
61 parser
.error("unexpected command line argument")
62 if opts
.include_tid
and not opts
.include_comm
:
63 parser
.error("requesting tid but not comm is invalid")
64 if opts
.include_pid
and not opts
.include_comm
:
65 parser
.error("requesting pid but not comm is invalid")
69 lines
= defaultdict(lambda: 0)
71 def process_event(param_dict
):
72 def tidy_function_name(sym
, dso
):
76 sym
= sym
.replace(';', ':')
78 # the original stackcollapse-perf.pl script gives the
79 # example of converting this:
80 # Lorg/mozilla/javascript/MemberBox;.<init>(Ljava/lang/reflect/Method;)V
82 # org/mozilla/javascript/MemberBox:.init
83 sym
= sym
.replace('<', '')
84 sym
= sym
.replace('>', '')
85 if sym
[0] == 'L' and sym
.find('/'):
88 sym
= sym
[:sym
.index('(')]
92 if opts
.annotate_kernel
and dso
== '[kernel.kallsyms]':
98 if 'callchain' in param_dict
:
99 for entry
in param_dict
['callchain']:
100 entry
.setdefault('sym', dict())
101 entry
['sym'].setdefault('name', None)
102 entry
.setdefault('dso', None)
103 stack
.append(tidy_function_name(entry
['sym']['name'],
106 param_dict
.setdefault('symbol', None)
107 param_dict
.setdefault('dso', None)
108 stack
.append(tidy_function_name(param_dict
['symbol'],
111 if opts
.include_comm
:
112 comm
= param_dict
["comm"].replace(' ', '_')
115 comm
= comm
+ sep
+ str(param_dict
['sample']['pid'])
118 comm
= comm
+ sep
+ str(param_dict
['sample']['tid'])
121 stack_string
= ';'.join(reversed(stack
))
122 lines
[stack_string
] = lines
[stack_string
] + 1
127 print("%s %d" % (stack
, lines
[stack
]))