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.
24 from collections
import defaultdict
25 from optparse
import OptionParser
, make_option
27 sys
.path
.append(os
.environ
['PERF_EXEC_PATH'] + \
28 '/scripts/python/Perf-Trace-Util/lib/Perf/Trace')
30 from perf_trace_context
import *
32 from EventClass
import *
34 # command line parsing
37 # formatting options for the bottom entry of the stack
38 make_option("--include-tid", dest
="include_tid",
39 action
="store_true", default
=False,
40 help="include thread id in stack"),
41 make_option("--include-pid", dest
="include_pid",
42 action
="store_true", default
=False,
43 help="include process id in stack"),
44 make_option("--no-comm", dest
="include_comm",
45 action
="store_false", default
=True,
46 help="do not separate stacks according to comm"),
47 make_option("--tidy-java", dest
="tidy_java",
48 action
="store_true", default
=False,
49 help="beautify Java signatures"),
50 make_option("--kernel", dest
="annotate_kernel",
51 action
="store_true", default
=False,
52 help="annotate kernel functions with _[k]")
55 parser
= OptionParser(option_list
=option_list
)
56 (opts
, args
) = parser
.parse_args()
59 parser
.error("unexpected command line argument")
60 if opts
.include_tid
and not opts
.include_comm
:
61 parser
.error("requesting tid but not comm is invalid")
62 if opts
.include_pid
and not opts
.include_comm
:
63 parser
.error("requesting pid but not comm is invalid")
67 lines
= defaultdict(lambda: 0)
69 def process_event(param_dict
):
70 def tidy_function_name(sym
, dso
):
74 sym
= sym
.replace(';', ':')
76 # the original stackcollapse-perf.pl script gives the
77 # example of converting this:
78 # Lorg/mozilla/javascript/MemberBox;.<init>(Ljava/lang/reflect/Method;)V
80 # org/mozilla/javascript/MemberBox:.init
81 sym
= sym
.replace('<', '')
82 sym
= sym
.replace('>', '')
83 if sym
[0] == 'L' and sym
.find('/'):
86 sym
= sym
[:sym
.index('(')]
90 if opts
.annotate_kernel
and dso
== '[kernel.kallsyms]':
96 if 'callchain' in param_dict
:
97 for entry
in param_dict
['callchain']:
98 entry
.setdefault('sym', dict())
99 entry
['sym'].setdefault('name', None)
100 entry
.setdefault('dso', None)
101 stack
.append(tidy_function_name(entry
['sym']['name'],
104 param_dict
.setdefault('symbol', None)
105 param_dict
.setdefault('dso', None)
106 stack
.append(tidy_function_name(param_dict
['symbol'],
109 if opts
.include_comm
:
110 comm
= param_dict
["comm"].replace(' ', '_')
113 comm
= comm
+ sep
+ str(param_dict
['sample']['pid'])
116 comm
= comm
+ sep
+ str(param_dict
['sample']['tid'])
119 stack_string
= ';'.join(reversed(stack
))
120 lines
[stack_string
] = lines
[stack_string
] + 1
126 print "%s %d" % (stack
, lines
[stack
])