aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf
diff options
context:
space:
mode:
Diffstat (limited to 'tools/perf')
-rw-r--r--tools/perf/Documentation/Makefile2
-rw-r--r--tools/perf/Documentation/perf-config.txt357
-rw-r--r--tools/perf/Documentation/perf-inject.txt7
-rw-r--r--tools/perf/Documentation/perf-list.txt6
-rw-r--r--tools/perf/Documentation/perf-record.txt6
-rw-r--r--tools/perf/Documentation/perf-report.txt40
-rw-r--r--tools/perf/Documentation/perf-stat.txt35
-rw-r--r--tools/perf/Documentation/perf-top.txt3
-rw-r--r--tools/perf/Documentation/perfconfig.example2
-rw-r--r--tools/perf/Documentation/tips.txt1
-rw-r--r--tools/perf/MANIFEST1
-rw-r--r--tools/perf/Makefile25
-rw-r--r--tools/perf/Makefile.perf18
-rw-r--r--tools/perf/arch/arm/Makefile1
-rw-r--r--tools/perf/arch/arm64/Makefile1
-rw-r--r--tools/perf/arch/powerpc/Makefile3
-rw-r--r--tools/perf/arch/powerpc/util/Build1
-rw-r--r--tools/perf/arch/powerpc/util/book3s_hcalls.h123
-rw-r--r--tools/perf/arch/powerpc/util/book3s_hv_exits.h33
-rw-r--r--tools/perf/arch/powerpc/util/header.c6
-rw-r--r--tools/perf/arch/powerpc/util/kvm-stat.c170
-rw-r--r--tools/perf/arch/s390/util/kvm-stat.c10
-rw-r--r--tools/perf/arch/x86/Makefile1
-rw-r--r--tools/perf/arch/x86/tests/rdpmc.c3
-rw-r--r--tools/perf/arch/x86/util/intel-bts.c4
-rw-r--r--tools/perf/arch/x86/util/intel-pt.c6
-rw-r--r--tools/perf/arch/x86/util/kvm-stat.c16
-rw-r--r--tools/perf/bench/bench.h22
-rw-r--r--tools/perf/bench/mem-memcpy-arch.h2
-rw-r--r--tools/perf/bench/mem-memcpy-x86-64-asm.S5
-rw-r--r--tools/perf/bench/mem-memset-arch.h2
-rw-r--r--tools/perf/bench/numa.c2
-rw-r--r--tools/perf/builtin-annotate.c4
-rw-r--r--tools/perf/builtin-buildid-cache.c14
-rw-r--r--tools/perf/builtin-config.c27
-rw-r--r--tools/perf/builtin-diff.c4
-rw-r--r--tools/perf/builtin-help.c74
-rw-r--r--tools/perf/builtin-inject.c113
-rw-r--r--tools/perf/builtin-kmem.c53
-rw-r--r--tools/perf/builtin-kvm.c38
-rw-r--r--tools/perf/builtin-mem.c86
-rw-r--r--tools/perf/builtin-record.c197
-rw-r--r--tools/perf/builtin-report.c61
-rw-r--r--tools/perf/builtin-script.c201
-rw-r--r--tools/perf/builtin-stat.c567
-rw-r--r--tools/perf/builtin-timechart.c2
-rw-r--r--tools/perf/builtin-top.c51
-rw-r--r--tools/perf/builtin-trace.c63
-rw-r--r--tools/perf/builtin.h64
-rw-r--r--tools/perf/config/Makefile121
-rw-r--r--tools/perf/config/utilities.mak179
-rw-r--r--tools/perf/jvmti/Makefile89
-rw-r--r--tools/perf/jvmti/jvmti_agent.c465
-rw-r--r--tools/perf/jvmti/jvmti_agent.h36
-rw-r--r--tools/perf/jvmti/libjvmti.c304
-rw-r--r--tools/perf/perf.c18
-rw-r--r--tools/perf/perf.h2
-rw-r--r--tools/perf/scripts/python/Perf-Trace-Util/lib/Perf/Trace/Util.py5
-rw-r--r--tools/perf/tests/.gitignore1
-rw-r--r--tools/perf/tests/Build9
-rw-r--r--tools/perf/tests/bp_signal.c140
-rw-r--r--tools/perf/tests/bpf-script-test-relocation.c50
-rw-r--r--tools/perf/tests/bpf.c65
-rw-r--r--tools/perf/tests/code-reading.c15
-rw-r--r--tools/perf/tests/dwarf-unwind.c4
-rw-r--r--tools/perf/tests/hists_common.c6
-rw-r--r--tools/perf/tests/hists_cumulate.c11
-rw-r--r--tools/perf/tests/hists_filter.c11
-rw-r--r--tools/perf/tests/hists_link.c20
-rw-r--r--tools/perf/tests/hists_output.c19
-rw-r--r--tools/perf/tests/llvm.c25
-rw-r--r--tools/perf/tests/llvm.h5
-rw-r--r--tools/perf/tests/make50
-rw-r--r--tools/perf/tests/parse-events.c54
-rwxr-xr-xtools/perf/tests/perf-targz-src-pkg2
-rw-r--r--tools/perf/tests/vmlinux-kallsyms.c24
-rw-r--r--tools/perf/ui/browser.c4
-rw-r--r--tools/perf/ui/browser.h2
-rw-r--r--tools/perf/ui/browsers/annotate.c2
-rw-r--r--tools/perf/ui/browsers/hists.c887
-rw-r--r--tools/perf/ui/gtk/hists.c201
-rw-r--r--tools/perf/ui/hist.c262
-rw-r--r--tools/perf/ui/stdio/hist.c302
-rw-r--r--tools/perf/util/Build11
-rw-r--r--tools/perf/util/abspath.c37
-rw-r--r--tools/perf/util/annotate.h2
-rw-r--r--tools/perf/util/auxtrace.c7
-rw-r--r--tools/perf/util/auxtrace.h8
-rw-r--r--tools/perf/util/bpf-loader.c724
-rw-r--r--tools/perf/util/bpf-loader.h59
-rw-r--r--tools/perf/util/build-id.c53
-rw-r--r--tools/perf/util/build-id.h1
-rw-r--r--tools/perf/util/cache.h25
-rw-r--r--tools/perf/util/callchain.c102
-rw-r--r--tools/perf/util/callchain.h4
-rw-r--r--tools/perf/util/cgroup.h4
-rw-r--r--tools/perf/util/cloexec.h2
-rw-r--r--tools/perf/util/color.c5
-rw-r--r--tools/perf/util/config.c4
-rw-r--r--tools/perf/util/cpumap.c30
-rw-r--r--tools/perf/util/cpumap.h32
-rw-r--r--tools/perf/util/ctype.c9
-rw-r--r--tools/perf/util/data-convert-bt.c140
-rw-r--r--tools/perf/util/db-export.c2
-rw-r--r--tools/perf/util/debug.c111
-rw-r--r--tools/perf/util/debug.h1
-rw-r--r--tools/perf/util/demangle-java.c199
-rw-r--r--tools/perf/util/demangle-java.h10
-rw-r--r--tools/perf/util/dso.c5
-rw-r--r--tools/perf/util/dso.h3
-rw-r--r--tools/perf/util/dwarf-aux.c10
-rw-r--r--tools/perf/util/dwarf-aux.h72
-rw-r--r--tools/perf/util/env.c13
-rw-r--r--tools/perf/util/env.h15
-rw-r--r--tools/perf/util/event.c48
-rw-r--r--tools/perf/util/event.h13
-rw-r--r--tools/perf/util/evlist.c43
-rw-r--r--tools/perf/util/evlist.h3
-rw-r--r--tools/perf/util/evsel.c31
-rw-r--r--tools/perf/util/evsel.h14
-rw-r--r--tools/perf/util/genelf.c449
-rw-r--r--tools/perf/util/genelf.h61
-rw-r--r--tools/perf/util/genelf_debug.c610
-rw-r--r--tools/perf/util/header.c275
-rw-r--r--tools/perf/util/header.h3
-rw-r--r--tools/perf/util/help-unknown-cmd.c5
-rw-r--r--tools/perf/util/hist.c843
-rw-r--r--tools/perf/util/hist.h123
-rw-r--r--tools/perf/util/intel-bts.c3
-rw-r--r--tools/perf/util/intel-pt-decoder/insn.c6
-rw-r--r--tools/perf/util/intel-pt.c3
-rw-r--r--tools/perf/util/jit.h11
-rw-r--r--tools/perf/util/jitdump.c699
-rw-r--r--tools/perf/util/jitdump.h124
-rw-r--r--tools/perf/util/kvm-stat.h8
-rw-r--r--tools/perf/util/llvm-utils.c24
-rw-r--r--tools/perf/util/llvm-utils.h7
-rw-r--r--tools/perf/util/machine.c14
-rw-r--r--tools/perf/util/machine.h12
-rw-r--r--tools/perf/util/mem-events.c255
-rw-r--r--tools/perf/util/mem-events.h35
-rw-r--r--tools/perf/util/parse-events.c314
-rw-r--r--tools/perf/util/parse-events.h49
-rw-r--r--tools/perf/util/parse-events.l19
-rw-r--r--tools/perf/util/parse-events.y184
-rw-r--r--tools/perf/util/path.c30
-rw-r--r--tools/perf/util/pmu.c34
-rw-r--r--tools/perf/util/probe-event.c2
-rw-r--r--tools/perf/util/probe-event.h57
-rw-r--r--tools/perf/util/probe-finder.c8
-rw-r--r--tools/perf/util/probe-finder.h24
-rw-r--r--tools/perf/util/quote.h2
-rw-r--r--tools/perf/util/scripting-engines/trace-event-perl.c3
-rw-r--r--tools/perf/util/scripting-engines/trace-event-python.c7
-rw-r--r--tools/perf/util/session.c45
-rw-r--r--tools/perf/util/setup.py4
-rw-r--r--tools/perf/util/sort.c761
-rw-r--r--tools/perf/util/sort.h29
-rw-r--r--tools/perf/util/stat-shadow.c239
-rw-r--r--tools/perf/util/stat.c14
-rw-r--r--tools/perf/util/stat.h24
-rw-r--r--tools/perf/util/strbuf.c27
-rw-r--r--tools/perf/util/strbuf.h23
-rw-r--r--tools/perf/util/svghelper.h51
-rw-r--r--tools/perf/util/symbol-elf.c15
-rw-r--r--tools/perf/util/symbol.c10
-rw-r--r--tools/perf/util/symbol.h7
-rw-r--r--tools/perf/util/trace-event.c1
-rw-r--r--tools/perf/util/tsc.c2
-rw-r--r--tools/perf/util/usage.c8
-rw-r--r--tools/perf/util/util.c112
-rw-r--r--tools/perf/util/util.h52
-rw-r--r--tools/perf/util/wrapper.c12
173 files changed, 11206 insertions, 2308 deletions
diff --git a/tools/perf/Documentation/Makefile b/tools/perf/Documentation/Makefile
index 3ba1c0b09908..098cfb9ca8f0 100644
--- a/tools/perf/Documentation/Makefile
+++ b/tools/perf/Documentation/Makefile
@@ -1,5 +1,5 @@
1include ../../scripts/Makefile.include 1include ../../scripts/Makefile.include
2include ../config/utilities.mak 2include ../../scripts/utilities.mak
3 3
4MAN1_TXT= \ 4MAN1_TXT= \
5 $(filter-out $(addsuffix .txt, $(ARTICLES) $(SP_ARTICLES)), \ 5 $(filter-out $(addsuffix .txt, $(ARTICLES) $(SP_ARTICLES)), \
diff --git a/tools/perf/Documentation/perf-config.txt b/tools/perf/Documentation/perf-config.txt
index b9ca1e304158..15949e2a7805 100644
--- a/tools/perf/Documentation/perf-config.txt
+++ b/tools/perf/Documentation/perf-config.txt
@@ -8,7 +8,7 @@ perf-config - Get and set variables in a configuration file.
8SYNOPSIS 8SYNOPSIS
9-------- 9--------
10[verse] 10[verse]
11'perf config' -l | --list 11'perf config' [<file-option>] -l | --list
12 12
13DESCRIPTION 13DESCRIPTION
14----------- 14-----------
@@ -21,6 +21,14 @@ OPTIONS
21--list:: 21--list::
22 Show current config variables, name and value, for all sections. 22 Show current config variables, name and value, for all sections.
23 23
24--user::
25 For writing and reading options: write to user
26 '$HOME/.perfconfig' file or read it.
27
28--system::
29 For writing and reading options: write to system-wide
30 '$(sysconfdir)/perfconfig' or read it.
31
24CONFIGURATION FILE 32CONFIGURATION FILE
25------------------ 33------------------
26 34
@@ -30,6 +38,10 @@ The '$HOME/.perfconfig' file is used to store a per-user configuration.
30The file '$(sysconfdir)/perfconfig' can be used to 38The file '$(sysconfdir)/perfconfig' can be used to
31store a system-wide default configuration. 39store a system-wide default configuration.
32 40
41When reading or writing, the values are read from the system and user
42configuration files by default, and options '--system' and '--user'
43can be used to tell the command to read from or write to only that location.
44
33Syntax 45Syntax
34~~~~~~ 46~~~~~~
35 47
@@ -62,7 +74,7 @@ Given a $HOME/.perfconfig like this:
62 medium = green, default 74 medium = green, default
63 normal = lightgray, default 75 normal = lightgray, default
64 selected = white, lightgray 76 selected = white, lightgray
65 code = blue, default 77 jump_arrows = blue, default
66 addr = magenta, default 78 addr = magenta, default
67 root = white, blue 79 root = white, blue
68 80
@@ -98,6 +110,347 @@ Given a $HOME/.perfconfig like this:
98 order = caller 110 order = caller
99 sort-key = function 111 sort-key = function
100 112
113Variables
114~~~~~~~~~
115
116colors.*::
117 The variables for customizing the colors used in the output for the
118 'report', 'top' and 'annotate' in the TUI. They should specify the
119 foreground and background colors, separated by a comma, for example:
120
121 medium = green, lightgray
122
123 If you want to use the color configured for you terminal, just leave it
124 as 'default', for example:
125
126 medium = default, lightgray
127
128 Available colors:
129 red, yellow, green, cyan, gray, black, blue,
130 white, default, magenta, lightgray
131
132 colors.top::
133 'top' means a overhead percentage which is more than 5%.
134 And values of this variable specify percentage colors.
135 Basic key values are foreground-color 'red' and
136 background-color 'default'.
137 colors.medium::
138 'medium' means a overhead percentage which has more than 0.5%.
139 Default values are 'green' and 'default'.
140 colors.normal::
141 'normal' means the rest of overhead percentages
142 except 'top', 'medium', 'selected'.
143 Default values are 'lightgray' and 'default'.
144 colors.selected::
145 This selects the colors for the current entry in a list of entries
146 from sub-commands (top, report, annotate).
147 Default values are 'black' and 'lightgray'.
148 colors.jump_arrows::
149 Colors for jump arrows on assembly code listings
150 such as 'jns', 'jmp', 'jane', etc.
151 Default values are 'blue', 'default'.
152 colors.addr::
153 This selects colors for addresses from 'annotate'.
154 Default values are 'magenta', 'default'.
155 colors.root::
156 Colors for headers in the output of a sub-commands (top, report).
157 Default values are 'white', 'blue'.
158
159tui.*, gtk.*::
160 Subcommands that can be configured here are 'top', 'report' and 'annotate'.
161 These values are booleans, for example:
162
163 [tui]
164 top = true
165
166 will make the TUI be the default for the 'top' subcommand. Those will be
167 available if the required libs were detected at tool build time.
168
169buildid.*::
170 buildid.dir::
171 Each executable and shared library in modern distributions comes with a
172 content based identifier that, if available, will be inserted in a
173 'perf.data' file header to, at analysis time find what is needed to do
174 symbol resolution, code annotation, etc.
175
176 The recording tools also stores a hard link or copy in a per-user
177 directory, $HOME/.debug/, of binaries, shared libraries, /proc/kallsyms
178 and /proc/kcore files to be used at analysis time.
179
180 The buildid.dir variable can be used to either change this directory
181 cache location, or to disable it altogether. If you want to disable it,
182 set buildid.dir to /dev/null. The default is $HOME/.debug
183
184annotate.*::
185 These options work only for TUI.
186 These are in control of addresses, jump function, source code
187 in lines of assembly code from a specific program.
188
189 annotate.hide_src_code::
190 If a program which is analyzed has source code,
191 this option lets 'annotate' print a list of assembly code with the source code.
192 For example, let's see a part of a program. There're four lines.
193 If this option is 'true', they can be printed
194 without source code from a program as below.
195
196 │ push %rbp
197 │ mov %rsp,%rbp
198 │ sub $0x10,%rsp
199 │ mov (%rdi),%rdx
200
201 But if this option is 'false', source code of the part
202 can be also printed as below. Default is 'false'.
203
204 │ struct rb_node *rb_next(const struct rb_node *node)
205 │ {
206 │ push %rbp
207 │ mov %rsp,%rbp
208 │ sub $0x10,%rsp
209 │ struct rb_node *parent;
210 │
211 │ if (RB_EMPTY_NODE(node))
212 │ mov (%rdi),%rdx
213 │ return n;
214
215 annotate.use_offset::
216 Basing on a first address of a loaded function, offset can be used.
217 Instead of using original addresses of assembly code,
218 addresses subtracted from a base address can be printed.
219 Let's illustrate an example.
220 If a base address is 0XFFFFFFFF81624d50 as below,
221
222 ffffffff81624d50 <load0>
223
224 an address on assembly code has a specific absolute address as below
225
226 ffffffff816250b8:│ mov 0x8(%r14),%rdi
227
228 but if use_offset is 'true', an address subtracted from a base address is printed.
229 Default is true. This option is only applied to TUI.
230
231 368:│ mov 0x8(%r14),%rdi
232
233 annotate.jump_arrows::
234 There can be jump instruction among assembly code.
235 Depending on a boolean value of jump_arrows,
236 arrows can be printed or not which represent
237 where do the instruction jump into as below.
238
239 │ ┌──jmp 1333
240 │ │ xchg %ax,%ax
241 │1330:│ mov %r15,%r10
242 │1333:└─→cmp %r15,%r14
243
244 If jump_arrow is 'false', the arrows isn't printed as below.
245 Default is 'false'.
246
247 │ ↓ jmp 1333
248 │ xchg %ax,%ax
249 │1330: mov %r15,%r10
250 │1333: cmp %r15,%r14
251
252 annotate.show_linenr::
253 When showing source code if this option is 'true',
254 line numbers are printed as below.
255
256 │1628 if (type & PERF_SAMPLE_IDENTIFIER) {
257 │ ↓ jne 508
258 │1628 data->id = *array;
259 │1629 array++;
260 │1630 }
261
262 However if this option is 'false', they aren't printed as below.
263 Default is 'false'.
264
265 │ if (type & PERF_SAMPLE_IDENTIFIER) {
266 │ ↓ jne 508
267 │ data->id = *array;
268 │ array++;
269 │ }
270
271 annotate.show_nr_jumps::
272 Let's see a part of assembly code.
273
274 │1382: movb $0x1,-0x270(%rbp)
275
276 If use this, the number of branches jumping to that address can be printed as below.
277 Default is 'false'.
278
279 │1 1382: movb $0x1,-0x270(%rbp)
280
281 annotate.show_total_period::
282 To compare two records on an instruction base, with this option
283 provided, display total number of samples that belong to a line
284 in assembly code. If this option is 'true', total periods are printed
285 instead of percent values as below.
286
287 302 │ mov %eax,%eax
288
289 But if this option is 'false', percent values for overhead are printed i.e.
290 Default is 'false'.
291
292 99.93 │ mov %eax,%eax
293
294hist.*::
295 hist.percentage::
296 This option control the way to calculate overhead of filtered entries -
297 that means the value of this option is effective only if there's a
298 filter (by comm, dso or symbol name). Suppose a following example:
299
300 Overhead Symbols
301 ........ .......
302 33.33% foo
303 33.33% bar
304 33.33% baz
305
306 This is an original overhead and we'll filter out the first 'foo'
307 entry. The value of 'relative' would increase the overhead of 'bar'
308 and 'baz' to 50.00% for each, while 'absolute' would show their
309 current overhead (33.33%).
310
311ui.*::
312 ui.show-headers::
313 This option controls display of column headers (like 'Overhead' and 'Symbol')
314 in 'report' and 'top'. If this option is false, they are hidden.
315 This option is only applied to TUI.
316
317call-graph.*::
318 When sub-commands 'top' and 'report' work with -g/—-children
319 there're options in control of call-graph.
320
321 call-graph.record-mode::
322 The record-mode can be 'fp' (frame pointer), 'dwarf' and 'lbr'.
323 The value of 'dwarf' is effective only if perf detect needed library
324 (libunwind or a recent version of libdw).
325 'lbr' only work for cpus that support it.
326
327 call-graph.dump-size::
328 The size of stack to dump in order to do post-unwinding. Default is 8192 (byte).
329 When using dwarf into record-mode, the default size will be used if omitted.
330
331 call-graph.print-type::
332 The print-types can be graph (graph absolute), fractal (graph relative),
333 flat and folded. This option controls a way to show overhead for each callchain
334 entry. Suppose a following example.
335
336 Overhead Symbols
337 ........ .......
338 40.00% foo
339 |
340 ---foo
341 |
342 |--50.00%--bar
343 | main
344 |
345 --50.00%--baz
346 main
347
348 This output is a 'fractal' format. The 'foo' came from 'bar' and 'baz' exactly
349 half and half so 'fractal' shows 50.00% for each
350 (meaning that it assumes 100% total overhead of 'foo').
351
352 The 'graph' uses absolute overhead value of 'foo' as total so each of
353 'bar' and 'baz' callchain will have 20.00% of overhead.
354 If 'flat' is used, single column and linear exposure of call chains.
355 'folded' mean call chains are displayed in a line, separated by semicolons.
356
357 call-graph.order::
358 This option controls print order of callchains. The default is
359 'callee' which means callee is printed at top and then followed by its
360 caller and so on. The 'caller' prints it in reverse order.
361
362 If this option is not set and report.children or top.children is
363 set to true (or the equivalent command line option is given),
364 the default value of this option is changed to 'caller' for the
365 execution of 'perf report' or 'perf top'. Other commands will
366 still default to 'callee'.
367
368 call-graph.sort-key::
369 The callchains are merged if they contain same information.
370 The sort-key option determines a way to compare the callchains.
371 A value of 'sort-key' can be 'function' or 'address'.
372 The default is 'function'.
373
374 call-graph.threshold::
375 When there're many callchains it'd print tons of lines. So perf omits
376 small callchains under a certain overhead (threshold) and this option
377 control the threshold. Default is 0.5 (%). The overhead is calculated
378 by value depends on call-graph.print-type.
379
380 call-graph.print-limit::
381 This is a maximum number of lines of callchain printed for a single
382 histogram entry. Default is 0 which means no limitation.
383
384report.*::
385 report.percent-limit::
386 This one is mostly the same as call-graph.threshold but works for
387 histogram entries. Entries having an overhead lower than this
388 percentage will not be printed. Default is '0'. If percent-limit
389 is '10', only entries which have more than 10% of overhead will be
390 printed.
391
392 report.queue-size::
393 This option sets up the maximum allocation size of the internal
394 event queue for ordering events. Default is 0, meaning no limit.
395
396 report.children::
397 'Children' means functions called from another function.
398 If this option is true, 'perf report' cumulates callchains of children
399 and show (accumulated) total overhead as well as 'Self' overhead.
400 Please refer to the 'perf report' manual. The default is 'true'.
401
402 report.group::
403 This option is to show event group information together.
404 Example output with this turned on, notice that there is one column
405 per event in the group, ref-cycles and cycles:
406
407 # group: {ref-cycles,cycles}
408 # ========
409 #
410 # Samples: 7K of event 'anon group { ref-cycles, cycles }'
411 # Event count (approx.): 6876107743
412 #
413 # Overhead Command Shared Object Symbol
414 # ................ ....... ................. ...................
415 #
416 99.84% 99.76% noploop noploop [.] main
417 0.07% 0.00% noploop ld-2.15.so [.] strcmp
418 0.03% 0.00% noploop [kernel.kallsyms] [k] timerqueue_del
419
420top.*::
421 top.children::
422 Same as 'report.children'. So if it is enabled, the output of 'top'
423 command will have 'Children' overhead column as well as 'Self' overhead
424 column by default.
425 The default is 'true'.
426
427man.*::
428 man.viewer::
429 This option can assign a tool to view manual pages when 'help'
430 subcommand was invoked. Supported tools are 'man', 'woman'
431 (with emacs client) and 'konqueror'. Default is 'man'.
432
433 New man viewer tool can be also added using 'man.<tool>.cmd'
434 or use different path using 'man.<tool>.path' config option.
435
436pager.*::
437 pager.<subcommand>::
438 When the subcommand is run on stdio, determine whether it uses
439 pager or not based on this value. Default is 'unspecified'.
440
441kmem.*::
442 kmem.default::
443 This option decides which allocator is to be analyzed if neither
444 '--slab' nor '--page' option is used. Default is 'slab'.
445
446record.*::
447 record.build-id::
448 This option can be 'cache', 'no-cache' or 'skip'.
449 'cache' is to post-process data and save/update the binaries into
450 the build-id cache (in ~/.debug). This is the default.
451 But if this option is 'no-cache', it will not update the build-id cache.
452 'skip' skips post-processing and does not update the cache.
453
101SEE ALSO 454SEE ALSO
102-------- 455--------
103linkperf:perf[1] 456linkperf:perf[1]
diff --git a/tools/perf/Documentation/perf-inject.txt b/tools/perf/Documentation/perf-inject.txt
index 0b1cedeef895..87b2588d1cbd 100644
--- a/tools/perf/Documentation/perf-inject.txt
+++ b/tools/perf/Documentation/perf-inject.txt
@@ -53,6 +53,13 @@ include::itrace.txt[]
53--strip:: 53--strip::
54 Use with --itrace to strip out non-synthesized events. 54 Use with --itrace to strip out non-synthesized events.
55 55
56-j::
57--jit::
58 Process jitdump files by injecting the mmap records corresponding to jitted
59 functions. This option also generates the ELF images for each jitted function
60 found in the jitdumps files captured in the input perf.data file. Use this option
61 if you are monitoring environment using JIT runtimes, such as Java, DART or V8.
62
56SEE ALSO 63SEE ALSO
57-------- 64--------
58linkperf:perf-record[1], linkperf:perf-report[1], linkperf:perf-archive[1] 65linkperf:perf-record[1], linkperf:perf-report[1], linkperf:perf-archive[1]
diff --git a/tools/perf/Documentation/perf-list.txt b/tools/perf/Documentation/perf-list.txt
index 79483f40e991..ec723d0a5bb3 100644
--- a/tools/perf/Documentation/perf-list.txt
+++ b/tools/perf/Documentation/perf-list.txt
@@ -40,10 +40,12 @@ address should be. The 'p' modifier can be specified multiple times:
40 0 - SAMPLE_IP can have arbitrary skid 40 0 - SAMPLE_IP can have arbitrary skid
41 1 - SAMPLE_IP must have constant skid 41 1 - SAMPLE_IP must have constant skid
42 2 - SAMPLE_IP requested to have 0 skid 42 2 - SAMPLE_IP requested to have 0 skid
43 3 - SAMPLE_IP must have 0 skid 43 3 - SAMPLE_IP must have 0 skid, or uses randomization to avoid
44 sample shadowing effects.
44 45
45For Intel systems precise event sampling is implemented with PEBS 46For Intel systems precise event sampling is implemented with PEBS
46which supports up to precise-level 2. 47which supports up to precise-level 2, and precise level 3 for
48some special cases
47 49
48On AMD systems it is implemented using IBS (up to precise-level 2). 50On AMD systems it is implemented using IBS (up to precise-level 2).
49The precise modifier works with event types 0x76 (cpu-cycles, CPU 51The precise modifier works with event types 0x76 (cpu-cycles, CPU
diff --git a/tools/perf/Documentation/perf-record.txt b/tools/perf/Documentation/perf-record.txt
index fbceb631387c..19aa17532a16 100644
--- a/tools/perf/Documentation/perf-record.txt
+++ b/tools/perf/Documentation/perf-record.txt
@@ -341,6 +341,12 @@ Specify vmlinux path which has debuginfo.
341--buildid-all:: 341--buildid-all::
342Record build-id of all DSOs regardless whether it's actually hit or not. 342Record build-id of all DSOs regardless whether it's actually hit or not.
343 343
344--all-kernel::
345Configure all used events to run in kernel space.
346
347--all-user::
348Configure all used events to run in user space.
349
344SEE ALSO 350SEE ALSO
345-------- 351--------
346linkperf:perf-stat[1], linkperf:perf-list[1] 352linkperf:perf-stat[1], linkperf:perf-list[1]
diff --git a/tools/perf/Documentation/perf-report.txt b/tools/perf/Documentation/perf-report.txt
index 8a301f6afb37..12113992ac9d 100644
--- a/tools/perf/Documentation/perf-report.txt
+++ b/tools/perf/Documentation/perf-report.txt
@@ -117,6 +117,22 @@ OPTIONS
117 And default sort keys are changed to comm, dso_from, symbol_from, dso_to 117 And default sort keys are changed to comm, dso_from, symbol_from, dso_to
118 and symbol_to, see '--branch-stack'. 118 and symbol_to, see '--branch-stack'.
119 119
120 If the --mem-mode option is used, the following sort keys are also available
121 (incompatible with --branch-stack):
122 symbol_daddr, dso_daddr, locked, tlb, mem, snoop, dcacheline.
123
124 - symbol_daddr: name of data symbol being executed on at the time of sample
125 - dso_daddr: name of library or module containing the data being executed
126 on at the time of the sample
127 - locked: whether the bus was locked at the time of the sample
128 - tlb: type of tlb access for the data at the time of the sample
129 - mem: type of memory access for the data at the time of the sample
130 - snoop: type of snoop (if any) for the data at the time of the sample
131 - dcacheline: the cacheline the data address is on at the time of the sample
132
133 And the default sort keys are changed to local_weight, mem, sym, dso,
134 symbol_daddr, dso_daddr, snoop, tlb, locked, see '--mem-mode'.
135
120 If the data file has tracepoint event(s), following (dynamic) sort keys 136 If the data file has tracepoint event(s), following (dynamic) sort keys
121 are also available: 137 are also available:
122 trace, trace_fields, [<event>.]<field>[/raw] 138 trace, trace_fields, [<event>.]<field>[/raw]
@@ -151,22 +167,6 @@ OPTIONS
151 By default, every sort keys not specified in -F will be appended 167 By default, every sort keys not specified in -F will be appended
152 automatically. 168 automatically.
153 169
154 If --mem-mode option is used, following sort keys are also available
155 (incompatible with --branch-stack):
156 symbol_daddr, dso_daddr, locked, tlb, mem, snoop, dcacheline.
157
158 - symbol_daddr: name of data symbol being executed on at the time of sample
159 - dso_daddr: name of library or module containing the data being executed
160 on at the time of sample
161 - locked: whether the bus was locked at the time of sample
162 - tlb: type of tlb access for the data at the time of sample
163 - mem: type of memory access for the data at the time of sample
164 - snoop: type of snoop (if any) for the data at the time of sample
165 - dcacheline: the cacheline the data address is on at the time of sample
166
167 And default sort keys are changed to local_weight, mem, sym, dso,
168 symbol_daddr, dso_daddr, snoop, tlb, locked, see '--mem-mode'.
169
170-p:: 170-p::
171--parent=<regex>:: 171--parent=<regex>::
172 A regex filter to identify parent. The parent is a caller of this 172 A regex filter to identify parent. The parent is a caller of this
@@ -351,7 +351,10 @@ OPTIONS
351 351
352--percent-limit:: 352--percent-limit::
353 Do not show entries which have an overhead under that percent. 353 Do not show entries which have an overhead under that percent.
354 (Default: 0). 354 (Default: 0). Note that this option also sets the percent limit (threshold)
355 of callchains. However the default value of callchain threshold is
356 different than the default value of hist entries. Please see the
357 --call-graph option for details.
355 358
356--percentage:: 359--percentage::
357 Determine how to display the overhead percentage of filtered entries. 360 Determine how to display the overhead percentage of filtered entries.
@@ -398,6 +401,9 @@ include::itrace.txt[]
398--raw-trace:: 401--raw-trace::
399 When displaying traceevent output, do not use print fmt or plugins. 402 When displaying traceevent output, do not use print fmt or plugins.
400 403
404--hierarchy::
405 Enable hierarchical output.
406
401include::callchain-overhead-calculation.txt[] 407include::callchain-overhead-calculation.txt[]
402 408
403SEE ALSO 409SEE ALSO
diff --git a/tools/perf/Documentation/perf-stat.txt b/tools/perf/Documentation/perf-stat.txt
index 52ef7a9d50aa..04f23b404bbc 100644
--- a/tools/perf/Documentation/perf-stat.txt
+++ b/tools/perf/Documentation/perf-stat.txt
@@ -69,6 +69,14 @@ report::
69--scale:: 69--scale::
70 scale/normalize counter values 70 scale/normalize counter values
71 71
72-d::
73--detailed::
74 print more detailed statistics, can be specified up to 3 times
75
76 -d: detailed events, L1 and LLC data cache
77 -d -d: more detailed events, dTLB and iTLB events
78 -d -d -d: very detailed events, adding prefetch events
79
72-r:: 80-r::
73--repeat=<n>:: 81--repeat=<n>::
74 repeat command and print average + stddev (max: 100). 0 means forever. 82 repeat command and print average + stddev (max: 100). 0 means forever.
@@ -139,6 +147,10 @@ Print count deltas every N milliseconds (minimum: 10ms)
139The overhead percentage could be high in some cases, for instance with small, sub 100ms intervals. Use with caution. 147The overhead percentage could be high in some cases, for instance with small, sub 100ms intervals. Use with caution.
140 example: 'perf stat -I 1000 -e cycles -a sleep 5' 148 example: 'perf stat -I 1000 -e cycles -a sleep 5'
141 149
150--metric-only::
151Only print computed metrics. Print them in a single line.
152Don't show any raw values. Not supported with --per-thread.
153
142--per-socket:: 154--per-socket::
143Aggregate counts per processor socket for system-wide mode measurements. This 155Aggregate counts per processor socket for system-wide mode measurements. This
144is a useful mode to detect imbalance between sockets. To enable this mode, 156is a useful mode to detect imbalance between sockets. To enable this mode,
@@ -211,6 +223,29 @@ $ perf stat -- make -j
211 223
212 Wall-clock time elapsed: 719.554352 msecs 224 Wall-clock time elapsed: 719.554352 msecs
213 225
226CSV FORMAT
227----------
228
229With -x, perf stat is able to output a not-quite-CSV format output
230Commas in the output are not put into "". To make it easy to parse
231it is recommended to use a different character like -x \;
232
233The fields are in this order:
234
235 - optional usec time stamp in fractions of second (with -I xxx)
236 - optional CPU, core, or socket identifier
237 - optional number of logical CPUs aggregated
238 - counter value
239 - unit of the counter value or empty
240 - event name
241 - run time of counter
242 - percentage of measurement time the counter was running
243 - optional variance if multiple values are collected with -r
244 - optional metric value
245 - optional unit of metric
246
247Additional metrics may be printed with all earlier fields being empty.
248
214SEE ALSO 249SEE ALSO
215-------- 250--------
216linkperf:perf-top[1], linkperf:perf-list[1] 251linkperf:perf-top[1], linkperf:perf-list[1]
diff --git a/tools/perf/Documentation/perf-top.txt b/tools/perf/Documentation/perf-top.txt
index b0e60e17db38..19f046f027cd 100644
--- a/tools/perf/Documentation/perf-top.txt
+++ b/tools/perf/Documentation/perf-top.txt
@@ -233,6 +233,9 @@ Default is to monitor all CPUS.
233--raw-trace:: 233--raw-trace::
234 When displaying traceevent output, do not use print fmt or plugins. 234 When displaying traceevent output, do not use print fmt or plugins.
235 235
236--hierarchy::
237 Enable hierarchy output.
238
236INTERACTIVE PROMPTING KEYS 239INTERACTIVE PROMPTING KEYS
237-------------------------- 240--------------------------
238 241
diff --git a/tools/perf/Documentation/perfconfig.example b/tools/perf/Documentation/perfconfig.example
index 767ea2436e1c..1d8d5bc4cd2d 100644
--- a/tools/perf/Documentation/perfconfig.example
+++ b/tools/perf/Documentation/perfconfig.example
@@ -5,7 +5,7 @@
5 medium = green, lightgray 5 medium = green, lightgray
6 normal = black, lightgray 6 normal = black, lightgray
7 selected = lightgray, magenta 7 selected = lightgray, magenta
8 code = blue, lightgray 8 jump_arrows = blue, lightgray
9 addr = magenta, lightgray 9 addr = magenta, lightgray
10 10
11[tui] 11[tui]
diff --git a/tools/perf/Documentation/tips.txt b/tools/perf/Documentation/tips.txt
index e0ce9573b79b..5950b5a24efd 100644
--- a/tools/perf/Documentation/tips.txt
+++ b/tools/perf/Documentation/tips.txt
@@ -27,3 +27,4 @@ Skip collecing build-id when recording: perf record -B
27To change sampling frequency to 100 Hz: perf record -F 100 27To change sampling frequency to 100 Hz: perf record -F 100
28See assembly instructions with percentage: perf annotate <symbol> 28See assembly instructions with percentage: perf annotate <symbol>
29If you prefer Intel style assembly, try: perf annotate -M intel 29If you prefer Intel style assembly, try: perf annotate -M intel
30For hierarchical output, try: perf report --hierarchy
diff --git a/tools/perf/MANIFEST b/tools/perf/MANIFEST
index 2e1fa2357528..8c8c6b9ce915 100644
--- a/tools/perf/MANIFEST
+++ b/tools/perf/MANIFEST
@@ -74,6 +74,7 @@ arch/*/include/uapi/asm/unistd*.h
74arch/*/include/uapi/asm/perf_regs.h 74arch/*/include/uapi/asm/perf_regs.h
75arch/*/lib/memcpy*.S 75arch/*/lib/memcpy*.S
76arch/*/lib/memset*.S 76arch/*/lib/memset*.S
77arch/*/include/asm/*features.h
77include/linux/poison.h 78include/linux/poison.h
78include/linux/hw_breakpoint.h 79include/linux/hw_breakpoint.h
79include/uapi/linux/perf_event.h 80include/uapi/linux/perf_event.h
diff --git a/tools/perf/Makefile b/tools/perf/Makefile
index dcd9a70c7193..32a64e619028 100644
--- a/tools/perf/Makefile
+++ b/tools/perf/Makefile
@@ -68,6 +68,20 @@ all tags TAGS:
68 $(print_msg) 68 $(print_msg)
69 $(make) 69 $(make)
70 70
71ifdef MAKECMDGOALS
72has_clean := 0
73ifneq ($(filter clean,$(MAKECMDGOALS)),)
74 has_clean := 1
75endif # clean
76
77ifeq ($(has_clean),1)
78 rest := $(filter-out clean,$(MAKECMDGOALS))
79 ifneq ($(rest),)
80$(rest): clean
81 endif # rest
82endif # has_clean
83endif # MAKECMDGOALS
84
71# 85#
72# The clean target is not really parallel, don't print the jobs info: 86# The clean target is not really parallel, don't print the jobs info:
73# 87#
@@ -75,10 +89,17 @@ clean:
75 $(make) 89 $(make)
76 90
77# 91#
78# The build-test target is not really parallel, don't print the jobs info: 92# The build-test target is not really parallel, don't print the jobs info,
93# it also uses only the tests/make targets that don't pollute the source
94# repository, i.e. that uses O= or builds the tarpkg outside the source
95# repo directories.
96#
97# For a full test, use:
98#
99# make -C tools/perf -f tests/make
79# 100#
80build-test: 101build-test:
81 @$(MAKE) SHUF=1 -f tests/make --no-print-directory 102 @$(MAKE) SHUF=1 -f tests/make REUSE_FEATURES_DUMP=1 MK=Makefile SET_PARALLEL=1 --no-print-directory tarpkg out
82 103
83# 104#
84# All other targets get passed through: 105# All other targets get passed through:
diff --git a/tools/perf/Makefile.perf b/tools/perf/Makefile.perf
index 5d34815c7ccb..000ea210389d 100644
--- a/tools/perf/Makefile.perf
+++ b/tools/perf/Makefile.perf
@@ -3,7 +3,7 @@ include ../scripts/Makefile.include
3# The default target of this Makefile is... 3# The default target of this Makefile is...
4all: 4all:
5 5
6include config/utilities.mak 6include ../scripts/utilities.mak
7 7
8# Define V to have a more verbose compile. 8# Define V to have a more verbose compile.
9# 9#
@@ -58,6 +58,9 @@ include config/utilities.mak
58# 58#
59# Define NO_LIBBIONIC if you do not want bionic support 59# Define NO_LIBBIONIC if you do not want bionic support
60# 60#
61# Define NO_LIBCRYPTO if you do not want libcrypto (openssl) support
62# used for generating build-ids for ELFs generated by jitdump.
63#
61# Define NO_LIBDW_DWARF_UNWIND if you do not want libdw support 64# Define NO_LIBDW_DWARF_UNWIND if you do not want libdw support
62# for dwarf backtrace post unwind. 65# for dwarf backtrace post unwind.
63# 66#
@@ -136,6 +139,8 @@ $(call allow-override,CC,$(CROSS_COMPILE)gcc)
136$(call allow-override,AR,$(CROSS_COMPILE)ar) 139$(call allow-override,AR,$(CROSS_COMPILE)ar)
137$(call allow-override,LD,$(CROSS_COMPILE)ld) 140$(call allow-override,LD,$(CROSS_COMPILE)ld)
138 141
142LD += $(EXTRA_LDFLAGS)
143
139PKG_CONFIG = $(CROSS_COMPILE)pkg-config 144PKG_CONFIG = $(CROSS_COMPILE)pkg-config
140 145
141RM = rm -f 146RM = rm -f
@@ -165,7 +170,16 @@ ifeq ($(filter-out $(NON_CONFIG_TARGETS),$(MAKECMDGOALS)),)
165endif 170endif
166endif 171endif
167 172
173# Set FEATURE_TESTS to 'all' so all possible feature checkers are executed.
174# Without this setting the output feature dump file misses some features, for
175# example, liberty. Select all checkers so we won't get an incomplete feature
176# dump file.
168ifeq ($(config),1) 177ifeq ($(config),1)
178ifdef MAKECMDGOALS
179ifeq ($(filter feature-dump,$(MAKECMDGOALS)),feature-dump)
180FEATURE_TESTS := all
181endif
182endif
169include config/Makefile 183include config/Makefile
170endif 184endif
171 185
@@ -618,7 +632,7 @@ clean: $(LIBTRACEEVENT)-clean $(LIBAPI)-clean $(LIBBPF)-clean $(LIBSUBCMD)-clean
618 $(call QUIET_CLEAN, core-progs) $(RM) $(ALL_PROGRAMS) perf perf-read-vdso32 perf-read-vdsox32 632 $(call QUIET_CLEAN, core-progs) $(RM) $(ALL_PROGRAMS) perf perf-read-vdso32 perf-read-vdsox32
619 $(call QUIET_CLEAN, core-gen) $(RM) *.spec *.pyc *.pyo */*.pyc */*.pyo $(OUTPUT)common-cmds.h TAGS tags cscope* $(OUTPUT)PERF-VERSION-FILE $(OUTPUT)FEATURE-DUMP $(OUTPUT)util/*-bison* $(OUTPUT)util/*-flex* \ 633 $(call QUIET_CLEAN, core-gen) $(RM) *.spec *.pyc *.pyo */*.pyc */*.pyo $(OUTPUT)common-cmds.h TAGS tags cscope* $(OUTPUT)PERF-VERSION-FILE $(OUTPUT)FEATURE-DUMP $(OUTPUT)util/*-bison* $(OUTPUT)util/*-flex* \
620 $(OUTPUT)util/intel-pt-decoder/inat-tables.c $(OUTPUT)fixdep \ 634 $(OUTPUT)util/intel-pt-decoder/inat-tables.c $(OUTPUT)fixdep \
621 $(OUTPUT)tests/llvm-src-{base,kbuild,prologue}.c 635 $(OUTPUT)tests/llvm-src-{base,kbuild,prologue,relocation}.c
622 $(QUIET_SUBDIR0)Documentation $(QUIET_SUBDIR1) clean 636 $(QUIET_SUBDIR0)Documentation $(QUIET_SUBDIR1) clean
623 $(python-clean) 637 $(python-clean)
624 638
diff --git a/tools/perf/arch/arm/Makefile b/tools/perf/arch/arm/Makefile
index 7fbca175099e..18b13518d8d8 100644
--- a/tools/perf/arch/arm/Makefile
+++ b/tools/perf/arch/arm/Makefile
@@ -1,3 +1,4 @@
1ifndef NO_DWARF 1ifndef NO_DWARF
2PERF_HAVE_DWARF_REGS := 1 2PERF_HAVE_DWARF_REGS := 1
3endif 3endif
4PERF_HAVE_JITDUMP := 1
diff --git a/tools/perf/arch/arm64/Makefile b/tools/perf/arch/arm64/Makefile
index 7fbca175099e..18b13518d8d8 100644
--- a/tools/perf/arch/arm64/Makefile
+++ b/tools/perf/arch/arm64/Makefile
@@ -1,3 +1,4 @@
1ifndef NO_DWARF 1ifndef NO_DWARF
2PERF_HAVE_DWARF_REGS := 1 2PERF_HAVE_DWARF_REGS := 1
3endif 3endif
4PERF_HAVE_JITDUMP := 1
diff --git a/tools/perf/arch/powerpc/Makefile b/tools/perf/arch/powerpc/Makefile
index 7fbca175099e..56e05f126ad8 100644
--- a/tools/perf/arch/powerpc/Makefile
+++ b/tools/perf/arch/powerpc/Makefile
@@ -1,3 +1,6 @@
1ifndef NO_DWARF 1ifndef NO_DWARF
2PERF_HAVE_DWARF_REGS := 1 2PERF_HAVE_DWARF_REGS := 1
3endif 3endif
4
5HAVE_KVM_STAT_SUPPORT := 1
6PERF_HAVE_JITDUMP := 1
diff --git a/tools/perf/arch/powerpc/util/Build b/tools/perf/arch/powerpc/util/Build
index 7b8b0d1a1b62..c8fe2074d217 100644
--- a/tools/perf/arch/powerpc/util/Build
+++ b/tools/perf/arch/powerpc/util/Build
@@ -1,5 +1,6 @@
1libperf-y += header.o 1libperf-y += header.o
2libperf-y += sym-handling.o 2libperf-y += sym-handling.o
3libperf-y += kvm-stat.o
3 4
4libperf-$(CONFIG_DWARF) += dwarf-regs.o 5libperf-$(CONFIG_DWARF) += dwarf-regs.o
5libperf-$(CONFIG_DWARF) += skip-callchain-idx.o 6libperf-$(CONFIG_DWARF) += skip-callchain-idx.o
diff --git a/tools/perf/arch/powerpc/util/book3s_hcalls.h b/tools/perf/arch/powerpc/util/book3s_hcalls.h
new file mode 100644
index 000000000000..0dd6b7f2d44f
--- /dev/null
+++ b/tools/perf/arch/powerpc/util/book3s_hcalls.h
@@ -0,0 +1,123 @@
1#ifndef ARCH_PERF_BOOK3S_HV_HCALLS_H
2#define ARCH_PERF_BOOK3S_HV_HCALLS_H
3
4/*
5 * PowerPC HCALL codes : hcall code to name mapping
6 */
7#define kvm_trace_symbol_hcall \
8 {0x4, "H_REMOVE"}, \
9 {0x8, "H_ENTER"}, \
10 {0xc, "H_READ"}, \
11 {0x10, "H_CLEAR_MOD"}, \
12 {0x14, "H_CLEAR_REF"}, \
13 {0x18, "H_PROTECT"}, \
14 {0x1c, "H_GET_TCE"}, \
15 {0x20, "H_PUT_TCE"}, \
16 {0x24, "H_SET_SPRG0"}, \
17 {0x28, "H_SET_DABR"}, \
18 {0x2c, "H_PAGE_INIT"}, \
19 {0x30, "H_SET_ASR"}, \
20 {0x34, "H_ASR_ON"}, \
21 {0x38, "H_ASR_OFF"}, \
22 {0x3c, "H_LOGICAL_CI_LOAD"}, \
23 {0x40, "H_LOGICAL_CI_STORE"}, \
24 {0x44, "H_LOGICAL_CACHE_LOAD"}, \
25 {0x48, "H_LOGICAL_CACHE_STORE"}, \
26 {0x4c, "H_LOGICAL_ICBI"}, \
27 {0x50, "H_LOGICAL_DCBF"}, \
28 {0x54, "H_GET_TERM_CHAR"}, \
29 {0x58, "H_PUT_TERM_CHAR"}, \
30 {0x5c, "H_REAL_TO_LOGICAL"}, \
31 {0x60, "H_HYPERVISOR_DATA"}, \
32 {0x64, "H_EOI"}, \
33 {0x68, "H_CPPR"}, \
34 {0x6c, "H_IPI"}, \
35 {0x70, "H_IPOLL"}, \
36 {0x74, "H_XIRR"}, \
37 {0x78, "H_MIGRATE_DMA"}, \
38 {0x7c, "H_PERFMON"}, \
39 {0xdc, "H_REGISTER_VPA"}, \
40 {0xe0, "H_CEDE"}, \
41 {0xe4, "H_CONFER"}, \
42 {0xe8, "H_PROD"}, \
43 {0xec, "H_GET_PPP"}, \
44 {0xf0, "H_SET_PPP"}, \
45 {0xf4, "H_PURR"}, \
46 {0xf8, "H_PIC"}, \
47 {0xfc, "H_REG_CRQ"}, \
48 {0x100, "H_FREE_CRQ"}, \
49 {0x104, "H_VIO_SIGNAL"}, \
50 {0x108, "H_SEND_CRQ"}, \
51 {0x110, "H_COPY_RDMA"}, \
52 {0x114, "H_REGISTER_LOGICAL_LAN"}, \
53 {0x118, "H_FREE_LOGICAL_LAN"}, \
54 {0x11c, "H_ADD_LOGICAL_LAN_BUFFER"}, \
55 {0x120, "H_SEND_LOGICAL_LAN"}, \
56 {0x124, "H_BULK_REMOVE"}, \
57 {0x130, "H_MULTICAST_CTRL"}, \
58 {0x134, "H_SET_XDABR"}, \
59 {0x138, "H_STUFF_TCE"}, \
60 {0x13c, "H_PUT_TCE_INDIRECT"}, \
61 {0x14c, "H_CHANGE_LOGICAL_LAN_MAC"}, \
62 {0x150, "H_VTERM_PARTNER_INFO"}, \
63 {0x154, "H_REGISTER_VTERM"}, \
64 {0x158, "H_FREE_VTERM"}, \
65 {0x15c, "H_RESET_EVENTS"}, \
66 {0x160, "H_ALLOC_RESOURCE"}, \
67 {0x164, "H_FREE_RESOURCE"}, \
68 {0x168, "H_MODIFY_QP"}, \
69 {0x16c, "H_QUERY_QP"}, \
70 {0x170, "H_REREGISTER_PMR"}, \
71 {0x174, "H_REGISTER_SMR"}, \
72 {0x178, "H_QUERY_MR"}, \
73 {0x17c, "H_QUERY_MW"}, \
74 {0x180, "H_QUERY_HCA"}, \
75 {0x184, "H_QUERY_PORT"}, \
76 {0x188, "H_MODIFY_PORT"}, \
77 {0x18c, "H_DEFINE_AQP1"}, \
78 {0x190, "H_GET_TRACE_BUFFER"}, \
79 {0x194, "H_DEFINE_AQP0"}, \
80 {0x198, "H_RESIZE_MR"}, \
81 {0x19c, "H_ATTACH_MCQP"}, \
82 {0x1a0, "H_DETACH_MCQP"}, \
83 {0x1a4, "H_CREATE_RPT"}, \
84 {0x1a8, "H_REMOVE_RPT"}, \
85 {0x1ac, "H_REGISTER_RPAGES"}, \
86 {0x1b0, "H_DISABLE_AND_GETC"}, \
87 {0x1b4, "H_ERROR_DATA"}, \
88 {0x1b8, "H_GET_HCA_INFO"}, \
89 {0x1bc, "H_GET_PERF_COUNT"}, \
90 {0x1c0, "H_MANAGE_TRACE"}, \
91 {0x1d4, "H_FREE_LOGICAL_LAN_BUFFER"}, \
92 {0x1d8, "H_POLL_PENDING"}, \
93 {0x1e4, "H_QUERY_INT_STATE"}, \
94 {0x244, "H_ILLAN_ATTRIBUTES"}, \
95 {0x250, "H_MODIFY_HEA_QP"}, \
96 {0x254, "H_QUERY_HEA_QP"}, \
97 {0x258, "H_QUERY_HEA"}, \
98 {0x25c, "H_QUERY_HEA_PORT"}, \
99 {0x260, "H_MODIFY_HEA_PORT"}, \
100 {0x264, "H_REG_BCMC"}, \
101 {0x268, "H_DEREG_BCMC"}, \
102 {0x26c, "H_REGISTER_HEA_RPAGES"}, \
103 {0x270, "H_DISABLE_AND_GET_HEA"}, \
104 {0x274, "H_GET_HEA_INFO"}, \
105 {0x278, "H_ALLOC_HEA_RESOURCE"}, \
106 {0x284, "H_ADD_CONN"}, \
107 {0x288, "H_DEL_CONN"}, \
108 {0x298, "H_JOIN"}, \
109 {0x2a4, "H_VASI_STATE"}, \
110 {0x2b0, "H_ENABLE_CRQ"}, \
111 {0x2b8, "H_GET_EM_PARMS"}, \
112 {0x2d0, "H_SET_MPP"}, \
113 {0x2d4, "H_GET_MPP"}, \
114 {0x2ec, "H_HOME_NODE_ASSOCIATIVITY"}, \
115 {0x2f4, "H_BEST_ENERGY"}, \
116 {0x2fc, "H_XIRR_X"}, \
117 {0x300, "H_RANDOM"}, \
118 {0x304, "H_COP"}, \
119 {0x314, "H_GET_MPP_X"}, \
120 {0x31c, "H_SET_MODE"}, \
121 {0xf000, "H_RTAS"} \
122
123#endif
diff --git a/tools/perf/arch/powerpc/util/book3s_hv_exits.h b/tools/perf/arch/powerpc/util/book3s_hv_exits.h
new file mode 100644
index 000000000000..e68ba2da8970
--- /dev/null
+++ b/tools/perf/arch/powerpc/util/book3s_hv_exits.h
@@ -0,0 +1,33 @@
1#ifndef ARCH_PERF_BOOK3S_HV_EXITS_H
2#define ARCH_PERF_BOOK3S_HV_EXITS_H
3
4/*
5 * PowerPC Interrupt vectors : exit code to name mapping
6 */
7
8#define kvm_trace_symbol_exit \
9 {0x0, "RETURN_TO_HOST"}, \
10 {0x100, "SYSTEM_RESET"}, \
11 {0x200, "MACHINE_CHECK"}, \
12 {0x300, "DATA_STORAGE"}, \
13 {0x380, "DATA_SEGMENT"}, \
14 {0x400, "INST_STORAGE"}, \
15 {0x480, "INST_SEGMENT"}, \
16 {0x500, "EXTERNAL"}, \
17 {0x501, "EXTERNAL_LEVEL"}, \
18 {0x502, "EXTERNAL_HV"}, \
19 {0x600, "ALIGNMENT"}, \
20 {0x700, "PROGRAM"}, \
21 {0x800, "FP_UNAVAIL"}, \
22 {0x900, "DECREMENTER"}, \
23 {0x980, "HV_DECREMENTER"}, \
24 {0xc00, "SYSCALL"}, \
25 {0xd00, "TRACE"}, \
26 {0xe00, "H_DATA_STORAGE"}, \
27 {0xe20, "H_INST_STORAGE"}, \
28 {0xe40, "H_EMUL_ASSIST"}, \
29 {0xf00, "PERFMON"}, \
30 {0xf20, "ALTIVEC"}, \
31 {0xf40, "VSX"}
32
33#endif
diff --git a/tools/perf/arch/powerpc/util/header.c b/tools/perf/arch/powerpc/util/header.c
index 6c1b8a75db09..f8ccee132867 100644
--- a/tools/perf/arch/powerpc/util/header.c
+++ b/tools/perf/arch/powerpc/util/header.c
@@ -3,9 +3,9 @@
3#include <stdio.h> 3#include <stdio.h>
4#include <stdlib.h> 4#include <stdlib.h>
5#include <string.h> 5#include <string.h>
6 6#include <linux/stringify.h>
7#include "../../util/header.h" 7#include "header.h"
8#include "../../util/util.h" 8#include "util.h"
9 9
10#define mfspr(rn) ({unsigned long rval; \ 10#define mfspr(rn) ({unsigned long rval; \
11 asm volatile("mfspr %0," __stringify(rn) \ 11 asm volatile("mfspr %0," __stringify(rn) \
diff --git a/tools/perf/arch/powerpc/util/kvm-stat.c b/tools/perf/arch/powerpc/util/kvm-stat.c
new file mode 100644
index 000000000000..74eee30398f8
--- /dev/null
+++ b/tools/perf/arch/powerpc/util/kvm-stat.c
@@ -0,0 +1,170 @@
1#include "util/kvm-stat.h"
2#include "util/parse-events.h"
3#include "util/debug.h"
4
5#include "book3s_hv_exits.h"
6#include "book3s_hcalls.h"
7
8#define NR_TPS 4
9
10const char *vcpu_id_str = "vcpu_id";
11const int decode_str_len = 40;
12const char *kvm_entry_trace = "kvm_hv:kvm_guest_enter";
13const char *kvm_exit_trace = "kvm_hv:kvm_guest_exit";
14
15define_exit_reasons_table(hv_exit_reasons, kvm_trace_symbol_exit);
16define_exit_reasons_table(hcall_reasons, kvm_trace_symbol_hcall);
17
18/* Tracepoints specific to ppc_book3s_hv */
19const char *ppc_book3s_hv_kvm_tp[] = {
20 "kvm_hv:kvm_guest_enter",
21 "kvm_hv:kvm_guest_exit",
22 "kvm_hv:kvm_hcall_enter",
23 "kvm_hv:kvm_hcall_exit",
24 NULL,
25};
26
27/* 1 extra placeholder for NULL */
28const char *kvm_events_tp[NR_TPS + 1];
29const char *kvm_exit_reason;
30
31static void hcall_event_get_key(struct perf_evsel *evsel,
32 struct perf_sample *sample,
33 struct event_key *key)
34{
35 key->info = 0;
36 key->key = perf_evsel__intval(evsel, sample, "req");
37}
38
39static const char *get_hcall_exit_reason(u64 exit_code)
40{
41 struct exit_reasons_table *tbl = hcall_reasons;
42
43 while (tbl->reason != NULL) {
44 if (tbl->exit_code == exit_code)
45 return tbl->reason;
46 tbl++;
47 }
48
49 pr_debug("Unknown hcall code: %lld\n",
50 (unsigned long long)exit_code);
51 return "UNKNOWN";
52}
53
54static bool hcall_event_end(struct perf_evsel *evsel,
55 struct perf_sample *sample __maybe_unused,
56 struct event_key *key __maybe_unused)
57{
58 return (!strcmp(evsel->name, kvm_events_tp[3]));
59}
60
61static bool hcall_event_begin(struct perf_evsel *evsel,
62 struct perf_sample *sample, struct event_key *key)
63{
64 if (!strcmp(evsel->name, kvm_events_tp[2])) {
65 hcall_event_get_key(evsel, sample, key);
66 return true;
67 }
68
69 return false;
70}
71static void hcall_event_decode_key(struct perf_kvm_stat *kvm __maybe_unused,
72 struct event_key *key,
73 char *decode)
74{
75 const char *hcall_reason = get_hcall_exit_reason(key->key);
76
77 scnprintf(decode, decode_str_len, "%s", hcall_reason);
78}
79
80static struct kvm_events_ops hcall_events = {
81 .is_begin_event = hcall_event_begin,
82 .is_end_event = hcall_event_end,
83 .decode_key = hcall_event_decode_key,
84 .name = "HCALL-EVENT",
85};
86
87static struct kvm_events_ops exit_events = {
88 .is_begin_event = exit_event_begin,
89 .is_end_event = exit_event_end,
90 .decode_key = exit_event_decode_key,
91 .name = "VM-EXIT"
92};
93
94struct kvm_reg_events_ops kvm_reg_events_ops[] = {
95 { .name = "vmexit", .ops = &exit_events },
96 { .name = "hcall", .ops = &hcall_events },
97 { NULL, NULL },
98};
99
100const char * const kvm_skip_events[] = {
101 NULL,
102};
103
104
105static int is_tracepoint_available(const char *str, struct perf_evlist *evlist)
106{
107 struct parse_events_error err;
108 int ret;
109
110 err.str = NULL;
111 ret = parse_events(evlist, str, &err);
112 if (err.str)
113 pr_err("%s : %s\n", str, err.str);
114 return ret;
115}
116
117static int ppc__setup_book3s_hv(struct perf_kvm_stat *kvm,
118 struct perf_evlist *evlist)
119{
120 const char **events_ptr;
121 int i, nr_tp = 0, err = -1;
122
123 /* Check for book3s_hv tracepoints */
124 for (events_ptr = ppc_book3s_hv_kvm_tp; *events_ptr; events_ptr++) {
125 err = is_tracepoint_available(*events_ptr, evlist);
126 if (err)
127 return -1;
128 nr_tp++;
129 }
130
131 for (i = 0; i < nr_tp; i++)
132 kvm_events_tp[i] = ppc_book3s_hv_kvm_tp[i];
133
134 kvm_events_tp[i] = NULL;
135 kvm_exit_reason = "trap";
136 kvm->exit_reasons = hv_exit_reasons;
137 kvm->exit_reasons_isa = "HV";
138
139 return 0;
140}
141
142/* Wrapper to setup kvm tracepoints */
143static int ppc__setup_kvm_tp(struct perf_kvm_stat *kvm)
144{
145 struct perf_evlist *evlist = perf_evlist__new();
146
147 if (evlist == NULL)
148 return -ENOMEM;
149
150 /* Right now, only supported on book3s_hv */
151 return ppc__setup_book3s_hv(kvm, evlist);
152}
153
154int setup_kvm_events_tp(struct perf_kvm_stat *kvm)
155{
156 return ppc__setup_kvm_tp(kvm);
157}
158
159int cpu_isa_init(struct perf_kvm_stat *kvm, const char *cpuid __maybe_unused)
160{
161 int ret;
162
163 ret = ppc__setup_kvm_tp(kvm);
164 if (ret) {
165 kvm->exit_reasons = NULL;
166 kvm->exit_reasons_isa = NULL;
167 }
168
169 return ret;
170}
diff --git a/tools/perf/arch/s390/util/kvm-stat.c b/tools/perf/arch/s390/util/kvm-stat.c
index a5dbc07ec9dc..ed57df2e6d68 100644
--- a/tools/perf/arch/s390/util/kvm-stat.c
+++ b/tools/perf/arch/s390/util/kvm-stat.c
@@ -10,7 +10,7 @@
10 */ 10 */
11 11
12#include "../../util/kvm-stat.h" 12#include "../../util/kvm-stat.h"
13#include <asm/kvm_perf.h> 13#include <asm/sie.h>
14 14
15define_exit_reasons_table(sie_exit_reasons, sie_intercept_code); 15define_exit_reasons_table(sie_exit_reasons, sie_intercept_code);
16define_exit_reasons_table(sie_icpt_insn_codes, icpt_insn_codes); 16define_exit_reasons_table(sie_icpt_insn_codes, icpt_insn_codes);
@@ -18,6 +18,12 @@ define_exit_reasons_table(sie_sigp_order_codes, sigp_order_codes);
18define_exit_reasons_table(sie_diagnose_codes, diagnose_codes); 18define_exit_reasons_table(sie_diagnose_codes, diagnose_codes);
19define_exit_reasons_table(sie_icpt_prog_codes, icpt_prog_codes); 19define_exit_reasons_table(sie_icpt_prog_codes, icpt_prog_codes);
20 20
21const char *vcpu_id_str = "id";
22const int decode_str_len = 40;
23const char *kvm_exit_reason = "icptcode";
24const char *kvm_entry_trace = "kvm:kvm_s390_sie_enter";
25const char *kvm_exit_trace = "kvm:kvm_s390_sie_exit";
26
21static void event_icpt_insn_get_key(struct perf_evsel *evsel, 27static void event_icpt_insn_get_key(struct perf_evsel *evsel,
22 struct perf_sample *sample, 28 struct perf_sample *sample,
23 struct event_key *key) 29 struct event_key *key)
@@ -73,7 +79,7 @@ static struct kvm_events_ops exit_events = {
73 .name = "VM-EXIT" 79 .name = "VM-EXIT"
74}; 80};
75 81
76const char * const kvm_events_tp[] = { 82const char *kvm_events_tp[] = {
77 "kvm:kvm_s390_sie_enter", 83 "kvm:kvm_s390_sie_enter",
78 "kvm:kvm_s390_sie_exit", 84 "kvm:kvm_s390_sie_exit",
79 "kvm:kvm_s390_intercept_instruction", 85 "kvm:kvm_s390_intercept_instruction",
diff --git a/tools/perf/arch/x86/Makefile b/tools/perf/arch/x86/Makefile
index 09ba923debe8..269af2143735 100644
--- a/tools/perf/arch/x86/Makefile
+++ b/tools/perf/arch/x86/Makefile
@@ -3,3 +3,4 @@ PERF_HAVE_DWARF_REGS := 1
3endif 3endif
4HAVE_KVM_STAT_SUPPORT := 1 4HAVE_KVM_STAT_SUPPORT := 1
5PERF_HAVE_ARCH_REGS_QUERY_REGISTER_OFFSET := 1 5PERF_HAVE_ARCH_REGS_QUERY_REGISTER_OFFSET := 1
6PERF_HAVE_JITDUMP := 1
diff --git a/tools/perf/arch/x86/tests/rdpmc.c b/tools/perf/arch/x86/tests/rdpmc.c
index 7bb0d13c235f..72193f19d6d7 100644
--- a/tools/perf/arch/x86/tests/rdpmc.c
+++ b/tools/perf/arch/x86/tests/rdpmc.c
@@ -59,7 +59,7 @@ static u64 mmap_read_self(void *addr)
59 u64 quot, rem; 59 u64 quot, rem;
60 60
61 quot = (cyc >> time_shift); 61 quot = (cyc >> time_shift);
62 rem = cyc & ((1 << time_shift) - 1); 62 rem = cyc & (((u64)1 << time_shift) - 1);
63 delta = time_offset + quot * time_mult + 63 delta = time_offset + quot * time_mult +
64 ((rem * time_mult) >> time_shift); 64 ((rem * time_mult) >> time_shift);
65 65
@@ -103,6 +103,7 @@ static int __test__rdpmc(void)
103 103
104 sigfillset(&sa.sa_mask); 104 sigfillset(&sa.sa_mask);
105 sa.sa_sigaction = segfault_handler; 105 sa.sa_sigaction = segfault_handler;
106 sa.sa_flags = 0;
106 sigaction(SIGSEGV, &sa, NULL); 107 sigaction(SIGSEGV, &sa, NULL);
107 108
108 fd = sys_perf_event_open(&attr, 0, -1, -1, 109 fd = sys_perf_event_open(&attr, 0, -1, -1,
diff --git a/tools/perf/arch/x86/util/intel-bts.c b/tools/perf/arch/x86/util/intel-bts.c
index 8d8150f1cf9b..d66f9ad4df2e 100644
--- a/tools/perf/arch/x86/util/intel-bts.c
+++ b/tools/perf/arch/x86/util/intel-bts.c
@@ -60,7 +60,9 @@ struct branch {
60 u64 misc; 60 u64 misc;
61}; 61};
62 62
63static size_t intel_bts_info_priv_size(struct auxtrace_record *itr __maybe_unused) 63static size_t
64intel_bts_info_priv_size(struct auxtrace_record *itr __maybe_unused,
65 struct perf_evlist *evlist __maybe_unused)
64{ 66{
65 return INTEL_BTS_AUXTRACE_PRIV_SIZE; 67 return INTEL_BTS_AUXTRACE_PRIV_SIZE;
66} 68}
diff --git a/tools/perf/arch/x86/util/intel-pt.c b/tools/perf/arch/x86/util/intel-pt.c
index f05daacc9e78..a3395179c9ee 100644
--- a/tools/perf/arch/x86/util/intel-pt.c
+++ b/tools/perf/arch/x86/util/intel-pt.c
@@ -89,7 +89,7 @@ static int intel_pt_parse_terms_with_default(struct list_head *formats,
89 89
90 *config = attr.config; 90 *config = attr.config;
91out_free: 91out_free:
92 parse_events__free_terms(terms); 92 parse_events_terms__delete(terms);
93 return err; 93 return err;
94} 94}
95 95
@@ -273,7 +273,9 @@ intel_pt_pmu_default_config(struct perf_pmu *intel_pt_pmu)
273 return attr; 273 return attr;
274} 274}
275 275
276static size_t intel_pt_info_priv_size(struct auxtrace_record *itr __maybe_unused) 276static size_t
277intel_pt_info_priv_size(struct auxtrace_record *itr __maybe_unused,
278 struct perf_evlist *evlist __maybe_unused)
277{ 279{
278 return INTEL_PT_AUXTRACE_PRIV_SIZE; 280 return INTEL_PT_AUXTRACE_PRIV_SIZE;
279} 281}
diff --git a/tools/perf/arch/x86/util/kvm-stat.c b/tools/perf/arch/x86/util/kvm-stat.c
index 14e4e668fad7..b63d4be655a2 100644
--- a/tools/perf/arch/x86/util/kvm-stat.c
+++ b/tools/perf/arch/x86/util/kvm-stat.c
@@ -1,5 +1,7 @@
1#include "../../util/kvm-stat.h" 1#include "../../util/kvm-stat.h"
2#include <asm/kvm_perf.h> 2#include <asm/svm.h>
3#include <asm/vmx.h>
4#include <asm/kvm.h>
3 5
4define_exit_reasons_table(vmx_exit_reasons, VMX_EXIT_REASONS); 6define_exit_reasons_table(vmx_exit_reasons, VMX_EXIT_REASONS);
5define_exit_reasons_table(svm_exit_reasons, SVM_EXIT_REASONS); 7define_exit_reasons_table(svm_exit_reasons, SVM_EXIT_REASONS);
@@ -11,6 +13,12 @@ static struct kvm_events_ops exit_events = {
11 .name = "VM-EXIT" 13 .name = "VM-EXIT"
12}; 14};
13 15
16const char *vcpu_id_str = "vcpu_id";
17const int decode_str_len = 20;
18const char *kvm_exit_reason = "exit_reason";
19const char *kvm_entry_trace = "kvm:kvm_entry";
20const char *kvm_exit_trace = "kvm:kvm_exit";
21
14/* 22/*
15 * For the mmio events, we treat: 23 * For the mmio events, we treat:
16 * the time of MMIO write: kvm_mmio(KVM_TRACE_MMIO_WRITE...) -> kvm_entry 24 * the time of MMIO write: kvm_mmio(KVM_TRACE_MMIO_WRITE...) -> kvm_entry
@@ -65,7 +73,7 @@ static void mmio_event_decode_key(struct perf_kvm_stat *kvm __maybe_unused,
65 struct event_key *key, 73 struct event_key *key,
66 char *decode) 74 char *decode)
67{ 75{
68 scnprintf(decode, DECODE_STR_LEN, "%#lx:%s", 76 scnprintf(decode, decode_str_len, "%#lx:%s",
69 (unsigned long)key->key, 77 (unsigned long)key->key,
70 key->info == KVM_TRACE_MMIO_WRITE ? "W" : "R"); 78 key->info == KVM_TRACE_MMIO_WRITE ? "W" : "R");
71} 79}
@@ -109,7 +117,7 @@ static void ioport_event_decode_key(struct perf_kvm_stat *kvm __maybe_unused,
109 struct event_key *key, 117 struct event_key *key,
110 char *decode) 118 char *decode)
111{ 119{
112 scnprintf(decode, DECODE_STR_LEN, "%#llx:%s", 120 scnprintf(decode, decode_str_len, "%#llx:%s",
113 (unsigned long long)key->key, 121 (unsigned long long)key->key,
114 key->info ? "POUT" : "PIN"); 122 key->info ? "POUT" : "PIN");
115} 123}
@@ -121,7 +129,7 @@ static struct kvm_events_ops ioport_events = {
121 .name = "IO Port Access" 129 .name = "IO Port Access"
122}; 130};
123 131
124const char * const kvm_events_tp[] = { 132const char *kvm_events_tp[] = {
125 "kvm:kvm_entry", 133 "kvm:kvm_entry",
126 "kvm:kvm_exit", 134 "kvm:kvm_exit",
127 "kvm:kvm_mmio", 135 "kvm:kvm_mmio",
diff --git a/tools/perf/bench/bench.h b/tools/perf/bench/bench.h
index a50df86f2b9b..579a592990dd 100644
--- a/tools/perf/bench/bench.h
+++ b/tools/perf/bench/bench.h
@@ -25,19 +25,17 @@
25# endif 25# endif
26#endif 26#endif
27 27
28extern int bench_numa(int argc, const char **argv, const char *prefix); 28int bench_numa(int argc, const char **argv, const char *prefix);
29extern int bench_sched_messaging(int argc, const char **argv, const char *prefix); 29int bench_sched_messaging(int argc, const char **argv, const char *prefix);
30extern int bench_sched_pipe(int argc, const char **argv, const char *prefix); 30int bench_sched_pipe(int argc, const char **argv, const char *prefix);
31extern int bench_mem_memcpy(int argc, const char **argv, 31int bench_mem_memcpy(int argc, const char **argv, const char *prefix);
32 const char *prefix __maybe_unused); 32int bench_mem_memset(int argc, const char **argv, const char *prefix);
33extern int bench_mem_memset(int argc, const char **argv, const char *prefix); 33int bench_futex_hash(int argc, const char **argv, const char *prefix);
34extern int bench_futex_hash(int argc, const char **argv, const char *prefix); 34int bench_futex_wake(int argc, const char **argv, const char *prefix);
35extern int bench_futex_wake(int argc, const char **argv, const char *prefix); 35int bench_futex_wake_parallel(int argc, const char **argv, const char *prefix);
36extern int bench_futex_wake_parallel(int argc, const char **argv, 36int bench_futex_requeue(int argc, const char **argv, const char *prefix);
37 const char *prefix);
38extern int bench_futex_requeue(int argc, const char **argv, const char *prefix);
39/* pi futexes */ 37/* pi futexes */
40extern int bench_futex_lock_pi(int argc, const char **argv, const char *prefix); 38int bench_futex_lock_pi(int argc, const char **argv, const char *prefix);
41 39
42#define BENCH_FORMAT_DEFAULT_STR "default" 40#define BENCH_FORMAT_DEFAULT_STR "default"
43#define BENCH_FORMAT_DEFAULT 0 41#define BENCH_FORMAT_DEFAULT 0
diff --git a/tools/perf/bench/mem-memcpy-arch.h b/tools/perf/bench/mem-memcpy-arch.h
index 57b4ed871459..5aad2a9408b0 100644
--- a/tools/perf/bench/mem-memcpy-arch.h
+++ b/tools/perf/bench/mem-memcpy-arch.h
@@ -2,7 +2,7 @@
2#ifdef HAVE_ARCH_X86_64_SUPPORT 2#ifdef HAVE_ARCH_X86_64_SUPPORT
3 3
4#define MEMCPY_FN(fn, name, desc) \ 4#define MEMCPY_FN(fn, name, desc) \
5 extern void *fn(void *, const void *, size_t); 5 void *fn(void *, const void *, size_t);
6 6
7#include "mem-memcpy-x86-64-asm-def.h" 7#include "mem-memcpy-x86-64-asm-def.h"
8 8
diff --git a/tools/perf/bench/mem-memcpy-x86-64-asm.S b/tools/perf/bench/mem-memcpy-x86-64-asm.S
index e4c2c30143b9..5c3cce082cb8 100644
--- a/tools/perf/bench/mem-memcpy-x86-64-asm.S
+++ b/tools/perf/bench/mem-memcpy-x86-64-asm.S
@@ -1,6 +1,11 @@
1
2/* Various wrappers to make the kernel .S file build in user-space: */
3
1#define memcpy MEMCPY /* don't hide glibc's memcpy() */ 4#define memcpy MEMCPY /* don't hide glibc's memcpy() */
2#define altinstr_replacement text 5#define altinstr_replacement text
3#define globl p2align 4; .globl 6#define globl p2align 4; .globl
7#define _ASM_EXTABLE_FAULT(x, y)
8
4#include "../../../arch/x86/lib/memcpy_64.S" 9#include "../../../arch/x86/lib/memcpy_64.S"
5/* 10/*
6 * We need to provide note.GNU-stack section, saying that we want 11 * We need to provide note.GNU-stack section, saying that we want
diff --git a/tools/perf/bench/mem-memset-arch.h b/tools/perf/bench/mem-memset-arch.h
index 633800cb0dcb..0d15786d9ae3 100644
--- a/tools/perf/bench/mem-memset-arch.h
+++ b/tools/perf/bench/mem-memset-arch.h
@@ -2,7 +2,7 @@
2#ifdef HAVE_ARCH_X86_64_SUPPORT 2#ifdef HAVE_ARCH_X86_64_SUPPORT
3 3
4#define MEMSET_FN(fn, name, desc) \ 4#define MEMSET_FN(fn, name, desc) \
5 extern void *fn(void *, int, size_t); 5 void *fn(void *, int, size_t);
6 6
7#include "mem-memset-x86-64-asm-def.h" 7#include "mem-memset-x86-64-asm-def.h"
8 8
diff --git a/tools/perf/bench/numa.c b/tools/perf/bench/numa.c
index 5049d6357a46..7500d959d7eb 100644
--- a/tools/perf/bench/numa.c
+++ b/tools/perf/bench/numa.c
@@ -293,7 +293,7 @@ static void bind_to_memnode(int node)
293 if (node == -1) 293 if (node == -1)
294 return; 294 return;
295 295
296 BUG_ON(g->p.nr_nodes > (int)sizeof(nodemask)); 296 BUG_ON(g->p.nr_nodes > (int)sizeof(nodemask)*8);
297 nodemask = 1L << node; 297 nodemask = 1L << node;
298 298
299 ret = set_mempolicy(MPOL_BIND, &nodemask, sizeof(nodemask)*8); 299 ret = set_mempolicy(MPOL_BIND, &nodemask, sizeof(nodemask)*8);
diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c
index cc5c1267c738..814158393656 100644
--- a/tools/perf/builtin-annotate.c
+++ b/tools/perf/builtin-annotate.c
@@ -94,7 +94,7 @@ static int process_sample_event(struct perf_tool *tool,
94 struct addr_location al; 94 struct addr_location al;
95 int ret = 0; 95 int ret = 0;
96 96
97 if (perf_event__preprocess_sample(event, machine, &al, sample) < 0) { 97 if (machine__resolve(machine, &al, sample) < 0) {
98 pr_warning("problem processing %d event, skipping it.\n", 98 pr_warning("problem processing %d event, skipping it.\n",
99 event->header.type); 99 event->header.type);
100 return -1; 100 return -1;
@@ -245,7 +245,7 @@ static int __cmd_annotate(struct perf_annotate *ann)
245 hists__collapse_resort(hists, NULL); 245 hists__collapse_resort(hists, NULL);
246 /* Don't sort callchain */ 246 /* Don't sort callchain */
247 perf_evsel__reset_sample_bit(pos, CALLCHAIN); 247 perf_evsel__reset_sample_bit(pos, CALLCHAIN);
248 hists__output_resort(hists, NULL); 248 perf_evsel__output_resort(pos, NULL);
249 249
250 if (symbol_conf.event_group && 250 if (symbol_conf.event_group &&
251 !perf_evsel__is_group_leader(pos)) 251 !perf_evsel__is_group_leader(pos))
diff --git a/tools/perf/builtin-buildid-cache.c b/tools/perf/builtin-buildid-cache.c
index d93bff7fc0e4..632efc6b79a0 100644
--- a/tools/perf/builtin-buildid-cache.c
+++ b/tools/perf/builtin-buildid-cache.c
@@ -38,19 +38,7 @@ static int build_id_cache__kcore_buildid(const char *proc_dir, char *sbuildid)
38 38
39static int build_id_cache__kcore_dir(char *dir, size_t sz) 39static int build_id_cache__kcore_dir(char *dir, size_t sz)
40{ 40{
41 struct timeval tv; 41 return fetch_current_timestamp(dir, sz);
42 struct tm tm;
43 char dt[32];
44
45 if (gettimeofday(&tv, NULL) || !localtime_r(&tv.tv_sec, &tm))
46 return -1;
47
48 if (!strftime(dt, sizeof(dt), "%Y%m%d%H%M%S", &tm))
49 return -1;
50
51 scnprintf(dir, sz, "%s%02u", dt, (unsigned)tv.tv_usec / 10000);
52
53 return 0;
54} 42}
55 43
56static bool same_kallsyms_reloc(const char *from_dir, char *to_dir) 44static bool same_kallsyms_reloc(const char *from_dir, char *to_dir)
diff --git a/tools/perf/builtin-config.c b/tools/perf/builtin-config.c
index f04e804a9fad..c42448ed5dfe 100644
--- a/tools/perf/builtin-config.c
+++ b/tools/perf/builtin-config.c
@@ -13,8 +13,10 @@
13#include "util/util.h" 13#include "util/util.h"
14#include "util/debug.h" 14#include "util/debug.h"
15 15
16static bool use_system_config, use_user_config;
17
16static const char * const config_usage[] = { 18static const char * const config_usage[] = {
17 "perf config [options]", 19 "perf config [<file-option>] [options]",
18 NULL 20 NULL
19}; 21};
20 22
@@ -25,6 +27,8 @@ enum actions {
25static struct option config_options[] = { 27static struct option config_options[] = {
26 OPT_SET_UINT('l', "list", &actions, 28 OPT_SET_UINT('l', "list", &actions,
27 "show current config variables", ACTION_LIST), 29 "show current config variables", ACTION_LIST),
30 OPT_BOOLEAN(0, "system", &use_system_config, "use system config file"),
31 OPT_BOOLEAN(0, "user", &use_user_config, "use user config file"),
28 OPT_END() 32 OPT_END()
29}; 33};
30 34
@@ -42,10 +46,23 @@ static int show_config(const char *key, const char *value,
42int cmd_config(int argc, const char **argv, const char *prefix __maybe_unused) 46int cmd_config(int argc, const char **argv, const char *prefix __maybe_unused)
43{ 47{
44 int ret = 0; 48 int ret = 0;
49 char *user_config = mkpath("%s/.perfconfig", getenv("HOME"));
45 50
46 argc = parse_options(argc, argv, config_options, config_usage, 51 argc = parse_options(argc, argv, config_options, config_usage,
47 PARSE_OPT_STOP_AT_NON_OPTION); 52 PARSE_OPT_STOP_AT_NON_OPTION);
48 53
54 if (use_system_config && use_user_config) {
55 pr_err("Error: only one config file at a time\n");
56 parse_options_usage(config_usage, config_options, "user", 0);
57 parse_options_usage(NULL, config_options, "system", 0);
58 return -1;
59 }
60
61 if (use_system_config)
62 config_exclusive_filename = perf_etc_perfconfig();
63 else if (use_user_config)
64 config_exclusive_filename = user_config;
65
49 switch (actions) { 66 switch (actions) {
50 case ACTION_LIST: 67 case ACTION_LIST:
51 if (argc) { 68 if (argc) {
@@ -53,9 +70,13 @@ int cmd_config(int argc, const char **argv, const char *prefix __maybe_unused)
53 parse_options_usage(config_usage, config_options, "l", 1); 70 parse_options_usage(config_usage, config_options, "l", 1);
54 } else { 71 } else {
55 ret = perf_config(show_config, NULL); 72 ret = perf_config(show_config, NULL);
56 if (ret < 0) 73 if (ret < 0) {
74 const char * config_filename = config_exclusive_filename;
75 if (!config_exclusive_filename)
76 config_filename = user_config;
57 pr_err("Nothing configured, " 77 pr_err("Nothing configured, "
58 "please check your ~/.perfconfig file\n"); 78 "please check your %s \n", config_filename);
79 }
59 } 80 }
60 break; 81 break;
61 default: 82 default:
diff --git a/tools/perf/builtin-diff.c b/tools/perf/builtin-diff.c
index 36ccc2b8827f..8053a8ceefda 100644
--- a/tools/perf/builtin-diff.c
+++ b/tools/perf/builtin-diff.c
@@ -330,7 +330,7 @@ static int diff__process_sample_event(struct perf_tool *tool __maybe_unused,
330 struct hists *hists = evsel__hists(evsel); 330 struct hists *hists = evsel__hists(evsel);
331 int ret = -1; 331 int ret = -1;
332 332
333 if (perf_event__preprocess_sample(event, machine, &al, sample) < 0) { 333 if (machine__resolve(machine, &al, sample) < 0) {
334 pr_warning("problem processing %d event, skipping it.\n", 334 pr_warning("problem processing %d event, skipping it.\n",
335 event->header.type); 335 event->header.type);
336 return -1; 336 return -1;
@@ -1264,8 +1264,6 @@ int cmd_diff(int argc, const char **argv, const char *prefix __maybe_unused)
1264 if (ret < 0) 1264 if (ret < 0)
1265 return ret; 1265 return ret;
1266 1266
1267 perf_config(perf_default_config, NULL);
1268
1269 argc = parse_options(argc, argv, options, diff_usage, 0); 1267 argc = parse_options(argc, argv, options, diff_usage, 0);
1270 1268
1271 if (symbol__init(NULL) < 0) 1269 if (symbol__init(NULL) < 0)
diff --git a/tools/perf/builtin-help.c b/tools/perf/builtin-help.c
index 96c1a4cfbbbf..bc1de9b8fd67 100644
--- a/tools/perf/builtin-help.c
+++ b/tools/perf/builtin-help.c
@@ -86,8 +86,7 @@ static int check_emacsclient_version(void)
86 return -1; 86 return -1;
87 } 87 }
88 88
89 strbuf_remove(&buffer, 0, strlen("emacsclient")); 89 version = atoi(buffer.buf + strlen("emacsclient"));
90 version = atoi(buffer.buf);
91 90
92 if (version < 22) { 91 if (version < 22) {
93 fprintf(stderr, 92 fprintf(stderr,
@@ -107,12 +106,14 @@ static void exec_woman_emacs(const char *path, const char *page)
107 106
108 if (!check_emacsclient_version()) { 107 if (!check_emacsclient_version()) {
109 /* This works only with emacsclient version >= 22. */ 108 /* This works only with emacsclient version >= 22. */
110 struct strbuf man_page = STRBUF_INIT; 109 char *man_page;
111 110
112 if (!path) 111 if (!path)
113 path = "emacsclient"; 112 path = "emacsclient";
114 strbuf_addf(&man_page, "(woman \"%s\")", page); 113 if (asprintf(&man_page, "(woman \"%s\")", page) > 0) {
115 execlp(path, "emacsclient", "-e", man_page.buf, NULL); 114 execlp(path, "emacsclient", "-e", man_page, NULL);
115 free(man_page);
116 }
116 warning("failed to exec '%s': %s", path, 117 warning("failed to exec '%s': %s", path,
117 strerror_r(errno, sbuf, sizeof(sbuf))); 118 strerror_r(errno, sbuf, sizeof(sbuf)));
118 } 119 }
@@ -123,7 +124,7 @@ static void exec_man_konqueror(const char *path, const char *page)
123 const char *display = getenv("DISPLAY"); 124 const char *display = getenv("DISPLAY");
124 125
125 if (display && *display) { 126 if (display && *display) {
126 struct strbuf man_page = STRBUF_INIT; 127 char *man_page;
127 const char *filename = "kfmclient"; 128 const char *filename = "kfmclient";
128 char sbuf[STRERR_BUFSIZE]; 129 char sbuf[STRERR_BUFSIZE];
129 130
@@ -142,8 +143,10 @@ static void exec_man_konqueror(const char *path, const char *page)
142 filename = file; 143 filename = file;
143 } else 144 } else
144 path = "kfmclient"; 145 path = "kfmclient";
145 strbuf_addf(&man_page, "man:%s(1)", page); 146 if (asprintf(&man_page, "man:%s(1)", page) > 0) {
146 execlp(path, filename, "newTab", man_page.buf, NULL); 147 execlp(path, filename, "newTab", man_page, NULL);
148 free(man_page);
149 }
147 warning("failed to exec '%s': %s", path, 150 warning("failed to exec '%s': %s", path,
148 strerror_r(errno, sbuf, sizeof(sbuf))); 151 strerror_r(errno, sbuf, sizeof(sbuf)));
149 } 152 }
@@ -162,11 +165,13 @@ static void exec_man_man(const char *path, const char *page)
162 165
163static void exec_man_cmd(const char *cmd, const char *page) 166static void exec_man_cmd(const char *cmd, const char *page)
164{ 167{
165 struct strbuf shell_cmd = STRBUF_INIT;
166 char sbuf[STRERR_BUFSIZE]; 168 char sbuf[STRERR_BUFSIZE];
169 char *shell_cmd;
167 170
168 strbuf_addf(&shell_cmd, "%s %s", cmd, page); 171 if (asprintf(&shell_cmd, "%s %s", cmd, page) > 0) {
169 execl("/bin/sh", "sh", "-c", shell_cmd.buf, NULL); 172 execl("/bin/sh", "sh", "-c", shell_cmd, NULL);
173 free(shell_cmd);
174 }
170 warning("failed to exec '%s': %s", cmd, 175 warning("failed to exec '%s': %s", cmd,
171 strerror_r(errno, sbuf, sizeof(sbuf))); 176 strerror_r(errno, sbuf, sizeof(sbuf)));
172} 177}
@@ -273,7 +278,7 @@ static int perf_help_config(const char *var, const char *value, void *cb)
273 if (!prefixcmp(var, "man.")) 278 if (!prefixcmp(var, "man."))
274 return add_man_viewer_info(var, value); 279 return add_man_viewer_info(var, value);
275 280
276 return perf_default_config(var, value, cb); 281 return 0;
277} 282}
278 283
279static struct cmdnames main_cmds, other_cmds; 284static struct cmdnames main_cmds, other_cmds;
@@ -300,43 +305,33 @@ static int is_perf_command(const char *s)
300 is_in_cmdlist(&other_cmds, s); 305 is_in_cmdlist(&other_cmds, s);
301} 306}
302 307
303static const char *prepend(const char *prefix, const char *cmd)
304{
305 size_t pre_len = strlen(prefix);
306 size_t cmd_len = strlen(cmd);
307 char *p = malloc(pre_len + cmd_len + 1);
308 memcpy(p, prefix, pre_len);
309 strcpy(p + pre_len, cmd);
310 return p;
311}
312
313static const char *cmd_to_page(const char *perf_cmd) 308static const char *cmd_to_page(const char *perf_cmd)
314{ 309{
310 char *s;
311
315 if (!perf_cmd) 312 if (!perf_cmd)
316 return "perf"; 313 return "perf";
317 else if (!prefixcmp(perf_cmd, "perf")) 314 else if (!prefixcmp(perf_cmd, "perf"))
318 return perf_cmd; 315 return perf_cmd;
319 else 316
320 return prepend("perf-", perf_cmd); 317 return asprintf(&s, "perf-%s", perf_cmd) < 0 ? NULL : s;
321} 318}
322 319
323static void setup_man_path(void) 320static void setup_man_path(void)
324{ 321{
325 struct strbuf new_path = STRBUF_INIT; 322 char *new_path;
326 const char *old_path = getenv("MANPATH"); 323 const char *old_path = getenv("MANPATH");
327 324
328 /* We should always put ':' after our path. If there is no 325 /* We should always put ':' after our path. If there is no
329 * old_path, the ':' at the end will let 'man' to try 326 * old_path, the ':' at the end will let 'man' to try
330 * system-wide paths after ours to find the manual page. If 327 * system-wide paths after ours to find the manual page. If
331 * there is old_path, we need ':' as delimiter. */ 328 * there is old_path, we need ':' as delimiter. */
332 strbuf_addstr(&new_path, system_path(PERF_MAN_PATH)); 329 if (asprintf(&new_path, "%s:%s", system_path(PERF_MAN_PATH), old_path ?: "") > 0) {
333 strbuf_addch(&new_path, ':'); 330 setenv("MANPATH", new_path, 1);
334 if (old_path) 331 free(new_path);
335 strbuf_addstr(&new_path, old_path); 332 } else {
336 333 error("Unable to setup man path");
337 setenv("MANPATH", new_path.buf, 1); 334 }
338
339 strbuf_release(&new_path);
340} 335}
341 336
342static void exec_viewer(const char *name, const char *page) 337static void exec_viewer(const char *name, const char *page)
@@ -381,7 +376,7 @@ static int show_info_page(const char *perf_cmd)
381 return -1; 376 return -1;
382} 377}
383 378
384static int get_html_page_path(struct strbuf *page_path, const char *page) 379static int get_html_page_path(char **page_path, const char *page)
385{ 380{
386 struct stat st; 381 struct stat st;
387 const char *html_path = system_path(PERF_HTML_PATH); 382 const char *html_path = system_path(PERF_HTML_PATH);
@@ -393,10 +388,7 @@ static int get_html_page_path(struct strbuf *page_path, const char *page)
393 return -1; 388 return -1;
394 } 389 }
395 390
396 strbuf_init(page_path, 0); 391 return asprintf(page_path, "%s/%s.html", html_path, page);
397 strbuf_addf(page_path, "%s/%s.html", html_path, page);
398
399 return 0;
400} 392}
401 393
402/* 394/*
@@ -414,12 +406,12 @@ static void open_html(const char *path)
414static int show_html_page(const char *perf_cmd) 406static int show_html_page(const char *perf_cmd)
415{ 407{
416 const char *page = cmd_to_page(perf_cmd); 408 const char *page = cmd_to_page(perf_cmd);
417 struct strbuf page_path; /* it leaks but we exec bellow */ 409 char *page_path; /* it leaks but we exec bellow */
418 410
419 if (get_html_page_path(&page_path, page) != 0) 411 if (get_html_page_path(&page_path, page) < 0)
420 return -1; 412 return -1;
421 413
422 open_html(page_path.buf); 414 open_html(page_path);
423 415
424 return 0; 416 return 0;
425} 417}
diff --git a/tools/perf/builtin-inject.c b/tools/perf/builtin-inject.c
index 0022e02ed31a..d1a2d104f2bc 100644
--- a/tools/perf/builtin-inject.c
+++ b/tools/perf/builtin-inject.c
@@ -17,6 +17,7 @@
17#include "util/build-id.h" 17#include "util/build-id.h"
18#include "util/data.h" 18#include "util/data.h"
19#include "util/auxtrace.h" 19#include "util/auxtrace.h"
20#include "util/jit.h"
20 21
21#include <subcmd/parse-options.h> 22#include <subcmd/parse-options.h>
22 23
@@ -29,6 +30,7 @@ struct perf_inject {
29 bool sched_stat; 30 bool sched_stat;
30 bool have_auxtrace; 31 bool have_auxtrace;
31 bool strip; 32 bool strip;
33 bool jit_mode;
32 const char *input_name; 34 const char *input_name;
33 struct perf_data_file output; 35 struct perf_data_file output;
34 u64 bytes_written; 36 u64 bytes_written;
@@ -71,6 +73,15 @@ static int perf_event__repipe_oe_synth(struct perf_tool *tool,
71 return perf_event__repipe_synth(tool, event); 73 return perf_event__repipe_synth(tool, event);
72} 74}
73 75
76#ifdef HAVE_JITDUMP
77static int perf_event__drop_oe(struct perf_tool *tool __maybe_unused,
78 union perf_event *event __maybe_unused,
79 struct ordered_events *oe __maybe_unused)
80{
81 return 0;
82}
83#endif
84
74static int perf_event__repipe_op2_synth(struct perf_tool *tool, 85static int perf_event__repipe_op2_synth(struct perf_tool *tool,
75 union perf_event *event, 86 union perf_event *event,
76 struct perf_session *session 87 struct perf_session *session
@@ -120,8 +131,7 @@ static int copy_bytes(struct perf_inject *inject, int fd, off_t size)
120 131
121static s64 perf_event__repipe_auxtrace(struct perf_tool *tool, 132static s64 perf_event__repipe_auxtrace(struct perf_tool *tool,
122 union perf_event *event, 133 union perf_event *event,
123 struct perf_session *session 134 struct perf_session *session)
124 __maybe_unused)
125{ 135{
126 struct perf_inject *inject = container_of(tool, struct perf_inject, 136 struct perf_inject *inject = container_of(tool, struct perf_inject,
127 tool); 137 tool);
@@ -234,6 +244,31 @@ static int perf_event__repipe_mmap(struct perf_tool *tool,
234 return err; 244 return err;
235} 245}
236 246
247#ifdef HAVE_JITDUMP
248static int perf_event__jit_repipe_mmap(struct perf_tool *tool,
249 union perf_event *event,
250 struct perf_sample *sample,
251 struct machine *machine)
252{
253 struct perf_inject *inject = container_of(tool, struct perf_inject, tool);
254 u64 n = 0;
255 int ret;
256
257 /*
258 * if jit marker, then inject jit mmaps and generate ELF images
259 */
260 ret = jit_process(inject->session, &inject->output, machine,
261 event->mmap.filename, sample->pid, &n);
262 if (ret < 0)
263 return ret;
264 if (ret) {
265 inject->bytes_written += n;
266 return 0;
267 }
268 return perf_event__repipe_mmap(tool, event, sample, machine);
269}
270#endif
271
237static int perf_event__repipe_mmap2(struct perf_tool *tool, 272static int perf_event__repipe_mmap2(struct perf_tool *tool,
238 union perf_event *event, 273 union perf_event *event,
239 struct perf_sample *sample, 274 struct perf_sample *sample,
@@ -247,6 +282,31 @@ static int perf_event__repipe_mmap2(struct perf_tool *tool,
247 return err; 282 return err;
248} 283}
249 284
285#ifdef HAVE_JITDUMP
286static int perf_event__jit_repipe_mmap2(struct perf_tool *tool,
287 union perf_event *event,
288 struct perf_sample *sample,
289 struct machine *machine)
290{
291 struct perf_inject *inject = container_of(tool, struct perf_inject, tool);
292 u64 n = 0;
293 int ret;
294
295 /*
296 * if jit marker, then inject jit mmaps and generate ELF images
297 */
298 ret = jit_process(inject->session, &inject->output, machine,
299 event->mmap2.filename, sample->pid, &n);
300 if (ret < 0)
301 return ret;
302 if (ret) {
303 inject->bytes_written += n;
304 return 0;
305 }
306 return perf_event__repipe_mmap2(tool, event, sample, machine);
307}
308#endif
309
250static int perf_event__repipe_fork(struct perf_tool *tool, 310static int perf_event__repipe_fork(struct perf_tool *tool,
251 union perf_event *event, 311 union perf_event *event,
252 struct perf_sample *sample, 312 struct perf_sample *sample,
@@ -356,9 +416,6 @@ static int perf_event__inject_buildid(struct perf_tool *tool,
356{ 416{
357 struct addr_location al; 417 struct addr_location al;
358 struct thread *thread; 418 struct thread *thread;
359 u8 cpumode;
360
361 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
362 419
363 thread = machine__findnew_thread(machine, sample->pid, sample->tid); 420 thread = machine__findnew_thread(machine, sample->pid, sample->tid);
364 if (thread == NULL) { 421 if (thread == NULL) {
@@ -367,7 +424,7 @@ static int perf_event__inject_buildid(struct perf_tool *tool,
367 goto repipe; 424 goto repipe;
368 } 425 }
369 426
370 thread__find_addr_map(thread, cpumode, MAP__FUNCTION, sample->ip, &al); 427 thread__find_addr_map(thread, sample->cpumode, MAP__FUNCTION, sample->ip, &al);
371 428
372 if (al.map != NULL) { 429 if (al.map != NULL) {
373 if (!al.map->dso->hit) { 430 if (!al.map->dso->hit) {
@@ -626,12 +683,16 @@ static int __cmd_inject(struct perf_inject *inject)
626 ret = perf_session__process_events(session); 683 ret = perf_session__process_events(session);
627 684
628 if (!file_out->is_pipe) { 685 if (!file_out->is_pipe) {
629 if (inject->build_ids) { 686 if (inject->build_ids)
630 perf_header__set_feat(&session->header, 687 perf_header__set_feat(&session->header,
631 HEADER_BUILD_ID); 688 HEADER_BUILD_ID);
632 if (inject->have_auxtrace) 689 /*
633 dsos__hit_all(session); 690 * Keep all buildids when there is unprocessed AUX data because
634 } 691 * it is not known which ones the AUX trace hits.
692 */
693 if (perf_header__has_feat(&session->header, HEADER_BUILD_ID) &&
694 inject->have_auxtrace && !inject->itrace_synth_opts.set)
695 dsos__hit_all(session);
635 /* 696 /*
636 * The AUX areas have been removed and replaced with 697 * The AUX areas have been removed and replaced with
637 * synthesized hardware events, so clear the feature flag and 698 * synthesized hardware events, so clear the feature flag and
@@ -703,7 +764,7 @@ int cmd_inject(int argc, const char **argv, const char *prefix __maybe_unused)
703 }; 764 };
704 int ret; 765 int ret;
705 766
706 const struct option options[] = { 767 struct option options[] = {
707 OPT_BOOLEAN('b', "build-ids", &inject.build_ids, 768 OPT_BOOLEAN('b', "build-ids", &inject.build_ids,
708 "Inject build-ids into the output stream"), 769 "Inject build-ids into the output stream"),
709 OPT_STRING('i', "input", &inject.input_name, "file", 770 OPT_STRING('i', "input", &inject.input_name, "file",
@@ -713,6 +774,9 @@ int cmd_inject(int argc, const char **argv, const char *prefix __maybe_unused)
713 OPT_BOOLEAN('s', "sched-stat", &inject.sched_stat, 774 OPT_BOOLEAN('s', "sched-stat", &inject.sched_stat,
714 "Merge sched-stat and sched-switch for getting events " 775 "Merge sched-stat and sched-switch for getting events "
715 "where and how long tasks slept"), 776 "where and how long tasks slept"),
777#ifdef HAVE_JITDUMP
778 OPT_BOOLEAN('j', "jit", &inject.jit_mode, "merge jitdump files into perf.data file"),
779#endif
716 OPT_INCR('v', "verbose", &verbose, 780 OPT_INCR('v', "verbose", &verbose,
717 "be more verbose (show build ids, etc)"), 781 "be more verbose (show build ids, etc)"),
718 OPT_STRING(0, "kallsyms", &symbol_conf.kallsyms_name, "file", 782 OPT_STRING(0, "kallsyms", &symbol_conf.kallsyms_name, "file",
@@ -729,7 +793,9 @@ int cmd_inject(int argc, const char **argv, const char *prefix __maybe_unused)
729 "perf inject [<options>]", 793 "perf inject [<options>]",
730 NULL 794 NULL
731 }; 795 };
732 796#ifndef HAVE_JITDUMP
797 set_option_nobuild(options, 'j', "jit", "NO_LIBELF=1", true);
798#endif
733 argc = parse_options(argc, argv, options, inject_usage, 0); 799 argc = parse_options(argc, argv, options, inject_usage, 0);
734 800
735 /* 801 /*
@@ -755,6 +821,29 @@ int cmd_inject(int argc, const char **argv, const char *prefix __maybe_unused)
755 if (inject.session == NULL) 821 if (inject.session == NULL)
756 return -1; 822 return -1;
757 823
824 if (inject.build_ids) {
825 /*
826 * to make sure the mmap records are ordered correctly
827 * and so that the correct especially due to jitted code
828 * mmaps. We cannot generate the buildid hit list and
829 * inject the jit mmaps at the same time for now.
830 */
831 inject.tool.ordered_events = true;
832 inject.tool.ordering_requires_timestamps = true;
833 }
834#ifdef HAVE_JITDUMP
835 if (inject.jit_mode) {
836 inject.tool.mmap2 = perf_event__jit_repipe_mmap2;
837 inject.tool.mmap = perf_event__jit_repipe_mmap;
838 inject.tool.ordered_events = true;
839 inject.tool.ordering_requires_timestamps = true;
840 /*
841 * JIT MMAP injection injects all MMAP events in one go, so it
842 * does not obey finished_round semantics.
843 */
844 inject.tool.finished_round = perf_event__drop_oe;
845 }
846#endif
758 ret = symbol__init(&inject.session->header.env); 847 ret = symbol__init(&inject.session->header.env);
759 if (ret < 0) 848 if (ret < 0)
760 goto out_delete; 849 goto out_delete;
diff --git a/tools/perf/builtin-kmem.c b/tools/perf/builtin-kmem.c
index 118010553d0c..c9cb3be47cff 100644
--- a/tools/perf/builtin-kmem.c
+++ b/tools/perf/builtin-kmem.c
@@ -602,7 +602,7 @@ static int gfpcmp(const void *a, const void *b)
602 return fa->flags - fb->flags; 602 return fa->flags - fb->flags;
603} 603}
604 604
605/* see include/trace/events/gfpflags.h */ 605/* see include/trace/events/mmflags.h */
606static const struct { 606static const struct {
607 const char *original; 607 const char *original;
608 const char *compact; 608 const char *compact;
@@ -612,30 +612,39 @@ static const struct {
612 { "GFP_HIGHUSER", "HU" }, 612 { "GFP_HIGHUSER", "HU" },
613 { "GFP_USER", "U" }, 613 { "GFP_USER", "U" },
614 { "GFP_TEMPORARY", "TMP" }, 614 { "GFP_TEMPORARY", "TMP" },
615 { "GFP_KERNEL_ACCOUNT", "KAC" },
615 { "GFP_KERNEL", "K" }, 616 { "GFP_KERNEL", "K" },
616 { "GFP_NOFS", "NF" }, 617 { "GFP_NOFS", "NF" },
617 { "GFP_ATOMIC", "A" }, 618 { "GFP_ATOMIC", "A" },
618 { "GFP_NOIO", "NI" }, 619 { "GFP_NOIO", "NI" },
619 { "GFP_HIGH", "H" },
620 { "GFP_WAIT", "W" },
621 { "GFP_IO", "I" },
622 { "GFP_COLD", "CO" },
623 { "GFP_NOWARN", "NWR" },
624 { "GFP_REPEAT", "R" },
625 { "GFP_NOFAIL", "NF" },
626 { "GFP_NORETRY", "NR" },
627 { "GFP_COMP", "C" },
628 { "GFP_ZERO", "Z" },
629 { "GFP_NOMEMALLOC", "NMA" },
630 { "GFP_MEMALLOC", "MA" },
631 { "GFP_HARDWALL", "HW" },
632 { "GFP_THISNODE", "TN" },
633 { "GFP_RECLAIMABLE", "RC" },
634 { "GFP_MOVABLE", "M" },
635 { "GFP_NOTRACK", "NT" },
636 { "GFP_NO_KSWAPD", "NK" },
637 { "GFP_OTHER_NODE", "ON" },
638 { "GFP_NOWAIT", "NW" }, 620 { "GFP_NOWAIT", "NW" },
621 { "GFP_DMA", "D" },
622 { "__GFP_HIGHMEM", "HM" },
623 { "GFP_DMA32", "D32" },
624 { "__GFP_HIGH", "H" },
625 { "__GFP_ATOMIC", "_A" },
626 { "__GFP_IO", "I" },
627 { "__GFP_FS", "F" },
628 { "__GFP_COLD", "CO" },
629 { "__GFP_NOWARN", "NWR" },
630 { "__GFP_REPEAT", "R" },
631 { "__GFP_NOFAIL", "NF" },
632 { "__GFP_NORETRY", "NR" },
633 { "__GFP_COMP", "C" },
634 { "__GFP_ZERO", "Z" },
635 { "__GFP_NOMEMALLOC", "NMA" },
636 { "__GFP_MEMALLOC", "MA" },
637 { "__GFP_HARDWALL", "HW" },
638 { "__GFP_THISNODE", "TN" },
639 { "__GFP_RECLAIMABLE", "RC" },
640 { "__GFP_MOVABLE", "M" },
641 { "__GFP_ACCOUNT", "AC" },
642 { "__GFP_NOTRACK", "NT" },
643 { "__GFP_WRITE", "WR" },
644 { "__GFP_RECLAIM", "R" },
645 { "__GFP_DIRECT_RECLAIM", "DR" },
646 { "__GFP_KSWAPD_RECLAIM", "KR" },
647 { "__GFP_OTHER_NODE", "ON" },
639}; 648};
640 649
641static size_t max_gfp_len; 650static size_t max_gfp_len;
@@ -1834,7 +1843,7 @@ static int __cmd_record(int argc, const char **argv)
1834 return cmd_record(i, rec_argv, NULL); 1843 return cmd_record(i, rec_argv, NULL);
1835} 1844}
1836 1845
1837static int kmem_config(const char *var, const char *value, void *cb) 1846static int kmem_config(const char *var, const char *value, void *cb __maybe_unused)
1838{ 1847{
1839 if (!strcmp(var, "kmem.default")) { 1848 if (!strcmp(var, "kmem.default")) {
1840 if (!strcmp(value, "slab")) 1849 if (!strcmp(value, "slab"))
@@ -1847,7 +1856,7 @@ static int kmem_config(const char *var, const char *value, void *cb)
1847 return 0; 1856 return 0;
1848 } 1857 }
1849 1858
1850 return perf_default_config(var, value, cb); 1859 return 0;
1851} 1860}
1852 1861
1853int cmd_kmem(int argc, const char **argv, const char *prefix __maybe_unused) 1862int cmd_kmem(int argc, const char **argv, const char *prefix __maybe_unused)
diff --git a/tools/perf/builtin-kvm.c b/tools/perf/builtin-kvm.c
index 4418d9214872..bff666458b28 100644
--- a/tools/perf/builtin-kvm.c
+++ b/tools/perf/builtin-kvm.c
@@ -30,7 +30,6 @@
30#include <math.h> 30#include <math.h>
31 31
32#ifdef HAVE_KVM_STAT_SUPPORT 32#ifdef HAVE_KVM_STAT_SUPPORT
33#include <asm/kvm_perf.h>
34#include "util/kvm-stat.h" 33#include "util/kvm-stat.h"
35 34
36void exit_event_get_key(struct perf_evsel *evsel, 35void exit_event_get_key(struct perf_evsel *evsel,
@@ -38,12 +37,12 @@ void exit_event_get_key(struct perf_evsel *evsel,
38 struct event_key *key) 37 struct event_key *key)
39{ 38{
40 key->info = 0; 39 key->info = 0;
41 key->key = perf_evsel__intval(evsel, sample, KVM_EXIT_REASON); 40 key->key = perf_evsel__intval(evsel, sample, kvm_exit_reason);
42} 41}
43 42
44bool kvm_exit_event(struct perf_evsel *evsel) 43bool kvm_exit_event(struct perf_evsel *evsel)
45{ 44{
46 return !strcmp(evsel->name, KVM_EXIT_TRACE); 45 return !strcmp(evsel->name, kvm_exit_trace);
47} 46}
48 47
49bool exit_event_begin(struct perf_evsel *evsel, 48bool exit_event_begin(struct perf_evsel *evsel,
@@ -59,7 +58,7 @@ bool exit_event_begin(struct perf_evsel *evsel,
59 58
60bool kvm_entry_event(struct perf_evsel *evsel) 59bool kvm_entry_event(struct perf_evsel *evsel)
61{ 60{
62 return !strcmp(evsel->name, KVM_ENTRY_TRACE); 61 return !strcmp(evsel->name, kvm_entry_trace);
63} 62}
64 63
65bool exit_event_end(struct perf_evsel *evsel, 64bool exit_event_end(struct perf_evsel *evsel,
@@ -91,7 +90,7 @@ void exit_event_decode_key(struct perf_kvm_stat *kvm,
91 const char *exit_reason = get_exit_reason(kvm, key->exit_reasons, 90 const char *exit_reason = get_exit_reason(kvm, key->exit_reasons,
92 key->key); 91 key->key);
93 92
94 scnprintf(decode, DECODE_STR_LEN, "%s", exit_reason); 93 scnprintf(decode, decode_str_len, "%s", exit_reason);
95} 94}
96 95
97static bool register_kvm_events_ops(struct perf_kvm_stat *kvm) 96static bool register_kvm_events_ops(struct perf_kvm_stat *kvm)
@@ -357,7 +356,7 @@ static bool handle_end_event(struct perf_kvm_stat *kvm,
357 time_diff = sample->time - time_begin; 356 time_diff = sample->time - time_begin;
358 357
359 if (kvm->duration && time_diff > kvm->duration) { 358 if (kvm->duration && time_diff > kvm->duration) {
360 char decode[DECODE_STR_LEN]; 359 char decode[decode_str_len];
361 360
362 kvm->events_ops->decode_key(kvm, &event->key, decode); 361 kvm->events_ops->decode_key(kvm, &event->key, decode);
363 if (!skip_event(decode)) { 362 if (!skip_event(decode)) {
@@ -385,7 +384,8 @@ struct vcpu_event_record *per_vcpu_record(struct thread *thread,
385 return NULL; 384 return NULL;
386 } 385 }
387 386
388 vcpu_record->vcpu_id = perf_evsel__intval(evsel, sample, VCPU_ID); 387 vcpu_record->vcpu_id = perf_evsel__intval(evsel, sample,
388 vcpu_id_str);
389 thread__set_priv(thread, vcpu_record); 389 thread__set_priv(thread, vcpu_record);
390 } 390 }
391 391
@@ -574,7 +574,7 @@ static void show_timeofday(void)
574 574
575static void print_result(struct perf_kvm_stat *kvm) 575static void print_result(struct perf_kvm_stat *kvm)
576{ 576{
577 char decode[DECODE_STR_LEN]; 577 char decode[decode_str_len];
578 struct kvm_event *event; 578 struct kvm_event *event;
579 int vcpu = kvm->trace_vcpu; 579 int vcpu = kvm->trace_vcpu;
580 580
@@ -585,7 +585,7 @@ static void print_result(struct perf_kvm_stat *kvm)
585 585
586 pr_info("\n\n"); 586 pr_info("\n\n");
587 print_vcpu_info(kvm); 587 print_vcpu_info(kvm);
588 pr_info("%*s ", DECODE_STR_LEN, kvm->events_ops->name); 588 pr_info("%*s ", decode_str_len, kvm->events_ops->name);
589 pr_info("%10s ", "Samples"); 589 pr_info("%10s ", "Samples");
590 pr_info("%9s ", "Samples%"); 590 pr_info("%9s ", "Samples%");
591 591
@@ -604,7 +604,7 @@ static void print_result(struct perf_kvm_stat *kvm)
604 min = get_event_min(event, vcpu); 604 min = get_event_min(event, vcpu);
605 605
606 kvm->events_ops->decode_key(kvm, &event->key, decode); 606 kvm->events_ops->decode_key(kvm, &event->key, decode);
607 pr_info("%*s ", DECODE_STR_LEN, decode); 607 pr_info("%*s ", decode_str_len, decode);
608 pr_info("%10llu ", (unsigned long long)ecount); 608 pr_info("%10llu ", (unsigned long long)ecount);
609 pr_info("%8.2f%% ", (double)ecount / kvm->total_count * 100); 609 pr_info("%8.2f%% ", (double)ecount / kvm->total_count * 100);
610 pr_info("%8.2f%% ", (double)etime / kvm->total_time * 100); 610 pr_info("%8.2f%% ", (double)etime / kvm->total_time * 100);
@@ -1132,6 +1132,11 @@ exit:
1132 _p; \ 1132 _p; \
1133 }) 1133 })
1134 1134
1135int __weak setup_kvm_events_tp(struct perf_kvm_stat *kvm __maybe_unused)
1136{
1137 return 0;
1138}
1139
1135static int 1140static int
1136kvm_events_record(struct perf_kvm_stat *kvm, int argc, const char **argv) 1141kvm_events_record(struct perf_kvm_stat *kvm, int argc, const char **argv)
1137{ 1142{
@@ -1148,7 +1153,14 @@ kvm_events_record(struct perf_kvm_stat *kvm, int argc, const char **argv)
1148 NULL 1153 NULL
1149 }; 1154 };
1150 const char * const *events_tp; 1155 const char * const *events_tp;
1156 int ret;
1157
1151 events_tp_size = 0; 1158 events_tp_size = 0;
1159 ret = setup_kvm_events_tp(kvm);
1160 if (ret < 0) {
1161 pr_err("Unable to setup the kvm tracepoints\n");
1162 return ret;
1163 }
1152 1164
1153 for (events_tp = kvm_events_tp; *events_tp; events_tp++) 1165 for (events_tp = kvm_events_tp; *events_tp; events_tp++)
1154 events_tp_size++; 1166 events_tp_size++;
@@ -1377,6 +1389,12 @@ static int kvm_events_live(struct perf_kvm_stat *kvm,
1377 /* 1389 /*
1378 * generate the event list 1390 * generate the event list
1379 */ 1391 */
1392 err = setup_kvm_events_tp(kvm);
1393 if (err < 0) {
1394 pr_err("Unable to setup the kvm tracepoints\n");
1395 return err;
1396 }
1397
1380 kvm->evlist = kvm_live_event_list(); 1398 kvm->evlist = kvm_live_event_list();
1381 if (kvm->evlist == NULL) { 1399 if (kvm->evlist == NULL) {
1382 err = -1; 1400 err = -1;
diff --git a/tools/perf/builtin-mem.c b/tools/perf/builtin-mem.c
index 390170041696..85db3be4b3cb 100644
--- a/tools/perf/builtin-mem.c
+++ b/tools/perf/builtin-mem.c
@@ -6,6 +6,8 @@
6#include "util/tool.h" 6#include "util/tool.h"
7#include "util/session.h" 7#include "util/session.h"
8#include "util/data.h" 8#include "util/data.h"
9#include "util/mem-events.h"
10#include "util/debug.h"
9 11
10#define MEM_OPERATION_LOAD 0x1 12#define MEM_OPERATION_LOAD 0x1
11#define MEM_OPERATION_STORE 0x2 13#define MEM_OPERATION_STORE 0x2
@@ -21,11 +23,56 @@ struct perf_mem {
21 DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS); 23 DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS);
22}; 24};
23 25
26static int parse_record_events(const struct option *opt,
27 const char *str, int unset __maybe_unused)
28{
29 struct perf_mem *mem = *(struct perf_mem **)opt->value;
30 int j;
31
32 if (strcmp(str, "list")) {
33 if (!perf_mem_events__parse(str)) {
34 mem->operation = 0;
35 return 0;
36 }
37 exit(-1);
38 }
39
40 for (j = 0; j < PERF_MEM_EVENTS__MAX; j++) {
41 struct perf_mem_event *e = &perf_mem_events[j];
42
43 fprintf(stderr, "%-13s%-*s%s\n",
44 e->tag,
45 verbose ? 25 : 0,
46 verbose ? perf_mem_events__name(j) : "",
47 e->supported ? ": available" : "");
48 }
49 exit(0);
50}
51
52static const char * const __usage[] = {
53 "perf mem record [<options>] [<command>]",
54 "perf mem record [<options>] -- <command> [<options>]",
55 NULL
56};
57
58static const char * const *record_mem_usage = __usage;
59
24static int __cmd_record(int argc, const char **argv, struct perf_mem *mem) 60static int __cmd_record(int argc, const char **argv, struct perf_mem *mem)
25{ 61{
26 int rec_argc, i = 0, j; 62 int rec_argc, i = 0, j;
27 const char **rec_argv; 63 const char **rec_argv;
28 int ret; 64 int ret;
65 struct option options[] = {
66 OPT_CALLBACK('e', "event", &mem, "event",
67 "event selector. use 'perf mem record -e list' to list available events",
68 parse_record_events),
69 OPT_INCR('v', "verbose", &verbose,
70 "be more verbose (show counter open errors, etc)"),
71 OPT_END()
72 };
73
74 argc = parse_options(argc, argv, options, record_mem_usage,
75 PARSE_OPT_STOP_AT_NON_OPTION);
29 76
30 rec_argc = argc + 7; /* max number of arguments */ 77 rec_argc = argc + 7; /* max number of arguments */
31 rec_argv = calloc(rec_argc + 1, sizeof(char *)); 78 rec_argv = calloc(rec_argc + 1, sizeof(char *));
@@ -35,23 +82,40 @@ static int __cmd_record(int argc, const char **argv, struct perf_mem *mem)
35 rec_argv[i++] = "record"; 82 rec_argv[i++] = "record";
36 83
37 if (mem->operation & MEM_OPERATION_LOAD) 84 if (mem->operation & MEM_OPERATION_LOAD)
85 perf_mem_events[PERF_MEM_EVENTS__LOAD].record = true;
86
87 if (perf_mem_events[PERF_MEM_EVENTS__LOAD].record)
38 rec_argv[i++] = "-W"; 88 rec_argv[i++] = "-W";
39 89
40 rec_argv[i++] = "-d"; 90 rec_argv[i++] = "-d";
41 91
42 if (mem->operation & MEM_OPERATION_LOAD) { 92 for (j = 0; j < PERF_MEM_EVENTS__MAX; j++) {
43 rec_argv[i++] = "-e"; 93 if (!perf_mem_events[j].record)
44 rec_argv[i++] = "cpu/mem-loads/pp"; 94 continue;
45 } 95
96 if (!perf_mem_events[j].supported) {
97 pr_err("failed: event '%s' not supported\n",
98 perf_mem_events__name(j));
99 return -1;
100 }
46 101
47 if (mem->operation & MEM_OPERATION_STORE) {
48 rec_argv[i++] = "-e"; 102 rec_argv[i++] = "-e";
49 rec_argv[i++] = "cpu/mem-stores/pp"; 103 rec_argv[i++] = perf_mem_events__name(j);
50 } 104 };
51 105
52 for (j = 1; j < argc; j++, i++) 106 for (j = 0; j < argc; j++, i++)
53 rec_argv[i] = argv[j]; 107 rec_argv[i] = argv[j];
54 108
109 if (verbose > 0) {
110 pr_debug("calling: record ");
111
112 while (rec_argv[j]) {
113 pr_debug("%s ", rec_argv[j]);
114 j++;
115 }
116 pr_debug("\n");
117 }
118
55 ret = cmd_record(i, rec_argv, NULL); 119 ret = cmd_record(i, rec_argv, NULL);
56 free(rec_argv); 120 free(rec_argv);
57 return ret; 121 return ret;
@@ -67,7 +131,7 @@ dump_raw_samples(struct perf_tool *tool,
67 struct addr_location al; 131 struct addr_location al;
68 const char *fmt; 132 const char *fmt;
69 133
70 if (perf_event__preprocess_sample(event, machine, &al, sample) < 0) { 134 if (machine__resolve(machine, &al, sample) < 0) {
71 fprintf(stderr, "problem processing %d event, skipping it.\n", 135 fprintf(stderr, "problem processing %d event, skipping it.\n",
72 event->header.type); 136 event->header.type);
73 return -1; 137 return -1;
@@ -298,6 +362,10 @@ int cmd_mem(int argc, const char **argv, const char *prefix __maybe_unused)
298 NULL 362 NULL
299 }; 363 };
300 364
365 if (perf_mem_events__init()) {
366 pr_err("failed: memory events not supported\n");
367 return -1;
368 }
301 369
302 argc = parse_options_subcommand(argc, argv, mem_options, mem_subcommands, 370 argc = parse_options_subcommand(argc, argv, mem_options, mem_subcommands,
303 mem_usage, PARSE_OPT_STOP_AT_NON_OPTION); 371 mem_usage, PARSE_OPT_STOP_AT_NON_OPTION);
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index 319712a4e02b..515510ecc76a 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -32,6 +32,8 @@
32#include "util/parse-branch-options.h" 32#include "util/parse-branch-options.h"
33#include "util/parse-regs-options.h" 33#include "util/parse-regs-options.h"
34#include "util/llvm-utils.h" 34#include "util/llvm-utils.h"
35#include "util/bpf-loader.h"
36#include "asm/bug.h"
35 37
36#include <unistd.h> 38#include <unistd.h>
37#include <sched.h> 39#include <sched.h>
@@ -49,7 +51,9 @@ struct record {
49 const char *progname; 51 const char *progname;
50 int realtime_prio; 52 int realtime_prio;
51 bool no_buildid; 53 bool no_buildid;
54 bool no_buildid_set;
52 bool no_buildid_cache; 55 bool no_buildid_cache;
56 bool no_buildid_cache_set;
53 bool buildid_all; 57 bool buildid_all;
54 unsigned long long samples; 58 unsigned long long samples;
55}; 59};
@@ -320,7 +324,10 @@ try_again:
320 } else { 324 } else {
321 pr_err("failed to mmap with %d (%s)\n", errno, 325 pr_err("failed to mmap with %d (%s)\n", errno,
322 strerror_r(errno, msg, sizeof(msg))); 326 strerror_r(errno, msg, sizeof(msg)));
323 rc = -errno; 327 if (errno)
328 rc = -errno;
329 else
330 rc = -EINVAL;
324 } 331 }
325 goto out; 332 goto out;
326 } 333 }
@@ -464,6 +471,29 @@ static void record__init_features(struct record *rec)
464 perf_header__clear_feat(&session->header, HEADER_STAT); 471 perf_header__clear_feat(&session->header, HEADER_STAT);
465} 472}
466 473
474static void
475record__finish_output(struct record *rec)
476{
477 struct perf_data_file *file = &rec->file;
478 int fd = perf_data_file__fd(file);
479
480 if (file->is_pipe)
481 return;
482
483 rec->session->header.data_size += rec->bytes_written;
484 file->size = lseek(perf_data_file__fd(file), 0, SEEK_CUR);
485
486 if (!rec->no_buildid) {
487 process_buildids(rec);
488
489 if (rec->buildid_all)
490 dsos__hit_all(rec->session);
491 }
492 perf_session__write_header(rec->session, rec->evlist, fd, true);
493
494 return;
495}
496
467static volatile int workload_exec_errno; 497static volatile int workload_exec_errno;
468 498
469/* 499/*
@@ -482,6 +512,74 @@ static void workload_exec_failed_signal(int signo __maybe_unused,
482 512
483static void snapshot_sig_handler(int sig); 513static void snapshot_sig_handler(int sig);
484 514
515static int record__synthesize(struct record *rec)
516{
517 struct perf_session *session = rec->session;
518 struct machine *machine = &session->machines.host;
519 struct perf_data_file *file = &rec->file;
520 struct record_opts *opts = &rec->opts;
521 struct perf_tool *tool = &rec->tool;
522 int fd = perf_data_file__fd(file);
523 int err = 0;
524
525 if (file->is_pipe) {
526 err = perf_event__synthesize_attrs(tool, session,
527 process_synthesized_event);
528 if (err < 0) {
529 pr_err("Couldn't synthesize attrs.\n");
530 goto out;
531 }
532
533 if (have_tracepoints(&rec->evlist->entries)) {
534 /*
535 * FIXME err <= 0 here actually means that
536 * there were no tracepoints so its not really
537 * an error, just that we don't need to
538 * synthesize anything. We really have to
539 * return this more properly and also
540 * propagate errors that now are calling die()
541 */
542 err = perf_event__synthesize_tracing_data(tool, fd, rec->evlist,
543 process_synthesized_event);
544 if (err <= 0) {
545 pr_err("Couldn't record tracing data.\n");
546 goto out;
547 }
548 rec->bytes_written += err;
549 }
550 }
551
552 if (rec->opts.full_auxtrace) {
553 err = perf_event__synthesize_auxtrace_info(rec->itr, tool,
554 session, process_synthesized_event);
555 if (err)
556 goto out;
557 }
558
559 err = perf_event__synthesize_kernel_mmap(tool, process_synthesized_event,
560 machine);
561 WARN_ONCE(err < 0, "Couldn't record kernel reference relocation symbol\n"
562 "Symbol resolution may be skewed if relocation was used (e.g. kexec).\n"
563 "Check /proc/kallsyms permission or run as root.\n");
564
565 err = perf_event__synthesize_modules(tool, process_synthesized_event,
566 machine);
567 WARN_ONCE(err < 0, "Couldn't record kernel module information.\n"
568 "Symbol resolution may be skewed if relocation was used (e.g. kexec).\n"
569 "Check /proc/modules permission or run as root.\n");
570
571 if (perf_guest) {
572 machines__process_guests(&session->machines,
573 perf_event__synthesize_guest_os, tool);
574 }
575
576 err = __machine__synthesize_threads(machine, tool, &opts->target, rec->evlist->threads,
577 process_synthesized_event, opts->sample_address,
578 opts->proc_map_timeout);
579out:
580 return err;
581}
582
485static int __cmd_record(struct record *rec, int argc, const char **argv) 583static int __cmd_record(struct record *rec, int argc, const char **argv)
486{ 584{
487 int err; 585 int err;
@@ -534,6 +632,16 @@ static int __cmd_record(struct record *rec, int argc, const char **argv)
534 goto out_child; 632 goto out_child;
535 } 633 }
536 634
635 err = bpf__apply_obj_config();
636 if (err) {
637 char errbuf[BUFSIZ];
638
639 bpf__strerror_apply_obj_config(err, errbuf, sizeof(errbuf));
640 pr_err("ERROR: Apply config to BPF failed: %s\n",
641 errbuf);
642 goto out_child;
643 }
644
537 /* 645 /*
538 * Normally perf_session__new would do this, but it doesn't have the 646 * Normally perf_session__new would do this, but it doesn't have the
539 * evlist. 647 * evlist.
@@ -566,63 +674,8 @@ static int __cmd_record(struct record *rec, int argc, const char **argv)
566 674
567 machine = &session->machines.host; 675 machine = &session->machines.host;
568 676
569 if (file->is_pipe) { 677 err = record__synthesize(rec);
570 err = perf_event__synthesize_attrs(tool, session,
571 process_synthesized_event);
572 if (err < 0) {
573 pr_err("Couldn't synthesize attrs.\n");
574 goto out_child;
575 }
576
577 if (have_tracepoints(&rec->evlist->entries)) {
578 /*
579 * FIXME err <= 0 here actually means that
580 * there were no tracepoints so its not really
581 * an error, just that we don't need to
582 * synthesize anything. We really have to
583 * return this more properly and also
584 * propagate errors that now are calling die()
585 */
586 err = perf_event__synthesize_tracing_data(tool, fd, rec->evlist,
587 process_synthesized_event);
588 if (err <= 0) {
589 pr_err("Couldn't record tracing data.\n");
590 goto out_child;
591 }
592 rec->bytes_written += err;
593 }
594 }
595
596 if (rec->opts.full_auxtrace) {
597 err = perf_event__synthesize_auxtrace_info(rec->itr, tool,
598 session, process_synthesized_event);
599 if (err)
600 goto out_delete_session;
601 }
602
603 err = perf_event__synthesize_kernel_mmap(tool, process_synthesized_event,
604 machine);
605 if (err < 0)
606 pr_err("Couldn't record kernel reference relocation symbol\n"
607 "Symbol resolution may be skewed if relocation was used (e.g. kexec).\n"
608 "Check /proc/kallsyms permission or run as root.\n");
609
610 err = perf_event__synthesize_modules(tool, process_synthesized_event,
611 machine);
612 if (err < 0) 678 if (err < 0)
613 pr_err("Couldn't record kernel module information.\n"
614 "Symbol resolution may be skewed if relocation was used (e.g. kexec).\n"
615 "Check /proc/modules permission or run as root.\n");
616
617 if (perf_guest) {
618 machines__process_guests(&session->machines,
619 perf_event__synthesize_guest_os, tool);
620 }
621
622 err = __machine__synthesize_threads(machine, tool, &opts->target, rec->evlist->threads,
623 process_synthesized_event, opts->sample_address,
624 opts->proc_map_timeout);
625 if (err != 0)
626 goto out_child; 679 goto out_child;
627 680
628 if (rec->realtime_prio) { 681 if (rec->realtime_prio) {
@@ -758,18 +811,8 @@ out_child:
758 /* this will be recalculated during process_buildids() */ 811 /* this will be recalculated during process_buildids() */
759 rec->samples = 0; 812 rec->samples = 0;
760 813
761 if (!err && !file->is_pipe) { 814 if (!err)
762 rec->session->header.data_size += rec->bytes_written; 815 record__finish_output(rec);
763 file->size = lseek(perf_data_file__fd(file), 0, SEEK_CUR);
764
765 if (!rec->no_buildid) {
766 process_buildids(rec);
767
768 if (rec->buildid_all)
769 dsos__hit_all(rec->session);
770 }
771 perf_session__write_header(rec->session, rec->evlist, fd, true);
772 }
773 816
774 if (!err && !quiet) { 817 if (!err && !quiet) {
775 char samples[128]; 818 char samples[128];
@@ -1097,10 +1140,12 @@ struct option __record_options[] = {
1097 OPT_BOOLEAN('P', "period", &record.opts.period, "Record the sample period"), 1140 OPT_BOOLEAN('P', "period", &record.opts.period, "Record the sample period"),
1098 OPT_BOOLEAN('n', "no-samples", &record.opts.no_samples, 1141 OPT_BOOLEAN('n', "no-samples", &record.opts.no_samples,
1099 "don't sample"), 1142 "don't sample"),
1100 OPT_BOOLEAN('N', "no-buildid-cache", &record.no_buildid_cache, 1143 OPT_BOOLEAN_SET('N', "no-buildid-cache", &record.no_buildid_cache,
1101 "do not update the buildid cache"), 1144 &record.no_buildid_cache_set,
1102 OPT_BOOLEAN('B', "no-buildid", &record.no_buildid, 1145 "do not update the buildid cache"),
1103 "do not collect buildids in perf.data"), 1146 OPT_BOOLEAN_SET('B', "no-buildid", &record.no_buildid,
1147 &record.no_buildid_set,
1148 "do not collect buildids in perf.data"),
1104 OPT_CALLBACK('G', "cgroup", &record.evlist, "name", 1149 OPT_CALLBACK('G', "cgroup", &record.evlist, "name",
1105 "monitor event in cgroup name only", 1150 "monitor event in cgroup name only",
1106 parse_cgroups), 1151 parse_cgroups),
@@ -1136,6 +1181,12 @@ struct option __record_options[] = {
1136 "per thread proc mmap processing timeout in ms"), 1181 "per thread proc mmap processing timeout in ms"),
1137 OPT_BOOLEAN(0, "switch-events", &record.opts.record_switch_events, 1182 OPT_BOOLEAN(0, "switch-events", &record.opts.record_switch_events,
1138 "Record context switch events"), 1183 "Record context switch events"),
1184 OPT_BOOLEAN_FLAG(0, "all-kernel", &record.opts.all_kernel,
1185 "Configure all used events to run in kernel space.",
1186 PARSE_OPT_EXCLUSIVE),
1187 OPT_BOOLEAN_FLAG(0, "all-user", &record.opts.all_user,
1188 "Configure all used events to run in user space.",
1189 PARSE_OPT_EXCLUSIVE),
1139 OPT_STRING(0, "clang-path", &llvm_param.clang_path, "clang path", 1190 OPT_STRING(0, "clang-path", &llvm_param.clang_path, "clang path",
1140 "clang binary to use for compiling BPF scriptlets"), 1191 "clang binary to use for compiling BPF scriptlets"),
1141 OPT_STRING(0, "clang-opt", &llvm_param.clang_opt, "clang options", 1192 OPT_STRING(0, "clang-opt", &llvm_param.clang_opt, "clang options",
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
index 2bf537f190a0..160ea23b45aa 100644
--- a/tools/perf/builtin-report.c
+++ b/tools/perf/builtin-report.c
@@ -41,6 +41,7 @@
41 41
42#include <dlfcn.h> 42#include <dlfcn.h>
43#include <linux/bitmap.h> 43#include <linux/bitmap.h>
44#include <linux/stringify.h>
44 45
45struct report { 46struct report {
46 struct perf_tool tool; 47 struct perf_tool tool;
@@ -75,7 +76,10 @@ static int report__config(const char *var, const char *value, void *cb)
75 return 0; 76 return 0;
76 } 77 }
77 if (!strcmp(var, "report.percent-limit")) { 78 if (!strcmp(var, "report.percent-limit")) {
78 rep->min_percent = strtof(value, NULL); 79 double pcnt = strtof(value, NULL);
80
81 rep->min_percent = pcnt;
82 callchain_param.min_percent = pcnt;
79 return 0; 83 return 0;
80 } 84 }
81 if (!strcmp(var, "report.children")) { 85 if (!strcmp(var, "report.children")) {
@@ -87,7 +91,7 @@ static int report__config(const char *var, const char *value, void *cb)
87 return 0; 91 return 0;
88 } 92 }
89 93
90 return perf_default_config(var, value, cb); 94 return 0;
91} 95}
92 96
93static int hist_iter__report_callback(struct hist_entry_iter *iter, 97static int hist_iter__report_callback(struct hist_entry_iter *iter,
@@ -151,7 +155,7 @@ static int process_sample_event(struct perf_tool *tool,
151 }; 155 };
152 int ret = 0; 156 int ret = 0;
153 157
154 if (perf_event__preprocess_sample(event, machine, &al, sample) < 0) { 158 if (machine__resolve(machine, &al, sample) < 0) {
155 pr_debug("problem processing %d event, skipping it.\n", 159 pr_debug("problem processing %d event, skipping it.\n",
156 event->header.type); 160 event->header.type);
157 return -1; 161 return -1;
@@ -466,10 +470,11 @@ static int report__browse_hists(struct report *rep)
466 return ret; 470 return ret;
467} 471}
468 472
469static void report__collapse_hists(struct report *rep) 473static int report__collapse_hists(struct report *rep)
470{ 474{
471 struct ui_progress prog; 475 struct ui_progress prog;
472 struct perf_evsel *pos; 476 struct perf_evsel *pos;
477 int ret = 0;
473 478
474 ui_progress__init(&prog, rep->nr_entries, "Merging related events..."); 479 ui_progress__init(&prog, rep->nr_entries, "Merging related events...");
475 480
@@ -481,7 +486,9 @@ static void report__collapse_hists(struct report *rep)
481 486
482 hists->socket_filter = rep->socket_filter; 487 hists->socket_filter = rep->socket_filter;
483 488
484 hists__collapse_resort(hists, &prog); 489 ret = hists__collapse_resort(hists, &prog);
490 if (ret < 0)
491 break;
485 492
486 /* Non-group events are considered as leader */ 493 /* Non-group events are considered as leader */
487 if (symbol_conf.event_group && 494 if (symbol_conf.event_group &&
@@ -494,6 +501,7 @@ static void report__collapse_hists(struct report *rep)
494 } 501 }
495 502
496 ui_progress__finish(); 503 ui_progress__finish();
504 return ret;
497} 505}
498 506
499static void report__output_resort(struct report *rep) 507static void report__output_resort(struct report *rep)
@@ -504,7 +512,7 @@ static void report__output_resort(struct report *rep)
504 ui_progress__init(&prog, rep->nr_entries, "Sorting events for output..."); 512 ui_progress__init(&prog, rep->nr_entries, "Sorting events for output...");
505 513
506 evlist__for_each(rep->session->evlist, pos) 514 evlist__for_each(rep->session->evlist, pos)
507 hists__output_resort(evsel__hists(pos), &prog); 515 perf_evsel__output_resort(pos, &prog);
508 516
509 ui_progress__finish(); 517 ui_progress__finish();
510} 518}
@@ -561,7 +569,11 @@ static int __cmd_report(struct report *rep)
561 } 569 }
562 } 570 }
563 571
564 report__collapse_hists(rep); 572 ret = report__collapse_hists(rep);
573 if (ret) {
574 ui__error("failed to process hist entry\n");
575 return ret;
576 }
565 577
566 if (session_done()) 578 if (session_done())
567 return 0; 579 return 0;
@@ -633,8 +645,10 @@ parse_percent_limit(const struct option *opt, const char *str,
633 int unset __maybe_unused) 645 int unset __maybe_unused)
634{ 646{
635 struct report *rep = opt->value; 647 struct report *rep = opt->value;
648 double pcnt = strtof(str, NULL);
636 649
637 rep->min_percent = strtof(str, NULL); 650 rep->min_percent = pcnt;
651 callchain_param.min_percent = pcnt;
638 return 0; 652 return 0;
639} 653}
640 654
@@ -798,6 +812,8 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
798 "only show processor socket that match with this filter"), 812 "only show processor socket that match with this filter"),
799 OPT_BOOLEAN(0, "raw-trace", &symbol_conf.raw_trace, 813 OPT_BOOLEAN(0, "raw-trace", &symbol_conf.raw_trace,
800 "Show raw trace event output (do not use print fmt or plugins)"), 814 "Show raw trace event output (do not use print fmt or plugins)"),
815 OPT_BOOLEAN(0, "hierarchy", &symbol_conf.report_hierarchy,
816 "Show entries in a hierarchy"),
801 OPT_END() 817 OPT_END()
802 }; 818 };
803 struct perf_data_file file = { 819 struct perf_data_file file = {
@@ -907,13 +923,19 @@ repeat:
907 symbol_conf.cumulate_callchain = false; 923 symbol_conf.cumulate_callchain = false;
908 } 924 }
909 925
910 if (setup_sorting(session->evlist) < 0) { 926 if (symbol_conf.report_hierarchy) {
911 if (sort_order) 927 /* disable incompatible options */
912 parse_options_usage(report_usage, options, "s", 1); 928 symbol_conf.event_group = false;
913 if (field_order) 929 symbol_conf.cumulate_callchain = false;
914 parse_options_usage(sort_order ? NULL : report_usage, 930
915 options, "F", 1); 931 if (field_order) {
916 goto error; 932 pr_err("Error: --hierarchy and --fields options cannot be used together\n");
933 parse_options_usage(report_usage, options, "F", 1);
934 parse_options_usage(NULL, options, "hierarchy", 0);
935 goto error;
936 }
937
938 sort__need_collapse = true;
917 } 939 }
918 940
919 /* Force tty output for header output and per-thread stat. */ 941 /* Force tty output for header output and per-thread stat. */
@@ -925,6 +947,15 @@ repeat:
925 else 947 else
926 use_browser = 0; 948 use_browser = 0;
927 949
950 if (setup_sorting(session->evlist) < 0) {
951 if (sort_order)
952 parse_options_usage(report_usage, options, "s", 1);
953 if (field_order)
954 parse_options_usage(sort_order ? NULL : report_usage,
955 options, "F", 1);
956 goto error;
957 }
958
928 if (report.header || report.header_only) { 959 if (report.header || report.header_only) {
929 perf_session__fprintf_info(session, stdout, 960 perf_session__fprintf_info(session, stdout,
930 report.show_full_info); 961 report.show_full_info);
diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c
index c691214d820f..3770c3dffe5e 100644
--- a/tools/perf/builtin-script.c
+++ b/tools/perf/builtin-script.c
@@ -23,6 +23,7 @@
23#include "util/stat.h" 23#include "util/stat.h"
24#include <linux/bitmap.h> 24#include <linux/bitmap.h>
25#include "asm/bug.h" 25#include "asm/bug.h"
26#include "util/mem-events.h"
26 27
27static char const *script_name; 28static char const *script_name;
28static char const *generate_script_lang; 29static char const *generate_script_lang;
@@ -58,6 +59,9 @@ enum perf_output_field {
58 PERF_OUTPUT_IREGS = 1U << 14, 59 PERF_OUTPUT_IREGS = 1U << 14,
59 PERF_OUTPUT_BRSTACK = 1U << 15, 60 PERF_OUTPUT_BRSTACK = 1U << 15,
60 PERF_OUTPUT_BRSTACKSYM = 1U << 16, 61 PERF_OUTPUT_BRSTACKSYM = 1U << 16,
62 PERF_OUTPUT_DATA_SRC = 1U << 17,
63 PERF_OUTPUT_WEIGHT = 1U << 18,
64 PERF_OUTPUT_BPF_OUTPUT = 1U << 19,
61}; 65};
62 66
63struct output_option { 67struct output_option {
@@ -81,6 +85,9 @@ struct output_option {
81 {.str = "iregs", .field = PERF_OUTPUT_IREGS}, 85 {.str = "iregs", .field = PERF_OUTPUT_IREGS},
82 {.str = "brstack", .field = PERF_OUTPUT_BRSTACK}, 86 {.str = "brstack", .field = PERF_OUTPUT_BRSTACK},
83 {.str = "brstacksym", .field = PERF_OUTPUT_BRSTACKSYM}, 87 {.str = "brstacksym", .field = PERF_OUTPUT_BRSTACKSYM},
88 {.str = "data_src", .field = PERF_OUTPUT_DATA_SRC},
89 {.str = "weight", .field = PERF_OUTPUT_WEIGHT},
90 {.str = "bpf-output", .field = PERF_OUTPUT_BPF_OUTPUT},
84}; 91};
85 92
86/* default set to maintain compatibility with current format */ 93/* default set to maintain compatibility with current format */
@@ -101,7 +108,7 @@ static struct {
101 PERF_OUTPUT_SYM | PERF_OUTPUT_DSO | 108 PERF_OUTPUT_SYM | PERF_OUTPUT_DSO |
102 PERF_OUTPUT_PERIOD, 109 PERF_OUTPUT_PERIOD,
103 110
104 .invalid_fields = PERF_OUTPUT_TRACE, 111 .invalid_fields = PERF_OUTPUT_TRACE | PERF_OUTPUT_BPF_OUTPUT,
105 }, 112 },
106 113
107 [PERF_TYPE_SOFTWARE] = { 114 [PERF_TYPE_SOFTWARE] = {
@@ -111,7 +118,7 @@ static struct {
111 PERF_OUTPUT_CPU | PERF_OUTPUT_TIME | 118 PERF_OUTPUT_CPU | PERF_OUTPUT_TIME |
112 PERF_OUTPUT_EVNAME | PERF_OUTPUT_IP | 119 PERF_OUTPUT_EVNAME | PERF_OUTPUT_IP |
113 PERF_OUTPUT_SYM | PERF_OUTPUT_DSO | 120 PERF_OUTPUT_SYM | PERF_OUTPUT_DSO |
114 PERF_OUTPUT_PERIOD, 121 PERF_OUTPUT_PERIOD | PERF_OUTPUT_BPF_OUTPUT,
115 122
116 .invalid_fields = PERF_OUTPUT_TRACE, 123 .invalid_fields = PERF_OUTPUT_TRACE,
117 }, 124 },
@@ -121,7 +128,7 @@ static struct {
121 128
122 .fields = PERF_OUTPUT_COMM | PERF_OUTPUT_TID | 129 .fields = PERF_OUTPUT_COMM | PERF_OUTPUT_TID |
123 PERF_OUTPUT_CPU | PERF_OUTPUT_TIME | 130 PERF_OUTPUT_CPU | PERF_OUTPUT_TIME |
124 PERF_OUTPUT_EVNAME | PERF_OUTPUT_TRACE, 131 PERF_OUTPUT_EVNAME | PERF_OUTPUT_TRACE
125 }, 132 },
126 133
127 [PERF_TYPE_RAW] = { 134 [PERF_TYPE_RAW] = {
@@ -131,9 +138,10 @@ static struct {
131 PERF_OUTPUT_CPU | PERF_OUTPUT_TIME | 138 PERF_OUTPUT_CPU | PERF_OUTPUT_TIME |
132 PERF_OUTPUT_EVNAME | PERF_OUTPUT_IP | 139 PERF_OUTPUT_EVNAME | PERF_OUTPUT_IP |
133 PERF_OUTPUT_SYM | PERF_OUTPUT_DSO | 140 PERF_OUTPUT_SYM | PERF_OUTPUT_DSO |
134 PERF_OUTPUT_PERIOD, 141 PERF_OUTPUT_PERIOD | PERF_OUTPUT_ADDR |
142 PERF_OUTPUT_DATA_SRC | PERF_OUTPUT_WEIGHT,
135 143
136 .invalid_fields = PERF_OUTPUT_TRACE, 144 .invalid_fields = PERF_OUTPUT_TRACE | PERF_OUTPUT_BPF_OUTPUT,
137 }, 145 },
138 146
139 [PERF_TYPE_BREAKPOINT] = { 147 [PERF_TYPE_BREAKPOINT] = {
@@ -145,7 +153,7 @@ static struct {
145 PERF_OUTPUT_SYM | PERF_OUTPUT_DSO | 153 PERF_OUTPUT_SYM | PERF_OUTPUT_DSO |
146 PERF_OUTPUT_PERIOD, 154 PERF_OUTPUT_PERIOD,
147 155
148 .invalid_fields = PERF_OUTPUT_TRACE, 156 .invalid_fields = PERF_OUTPUT_TRACE | PERF_OUTPUT_BPF_OUTPUT,
149 }, 157 },
150}; 158};
151 159
@@ -242,6 +250,16 @@ static int perf_evsel__check_attr(struct perf_evsel *evsel,
242 PERF_OUTPUT_ADDR, allow_user_set)) 250 PERF_OUTPUT_ADDR, allow_user_set))
243 return -EINVAL; 251 return -EINVAL;
244 252
253 if (PRINT_FIELD(DATA_SRC) &&
254 perf_evsel__check_stype(evsel, PERF_SAMPLE_DATA_SRC, "DATA_SRC",
255 PERF_OUTPUT_DATA_SRC))
256 return -EINVAL;
257
258 if (PRINT_FIELD(WEIGHT) &&
259 perf_evsel__check_stype(evsel, PERF_SAMPLE_WEIGHT, "WEIGHT",
260 PERF_OUTPUT_WEIGHT))
261 return -EINVAL;
262
245 if (PRINT_FIELD(SYM) && !PRINT_FIELD(IP) && !PRINT_FIELD(ADDR)) { 263 if (PRINT_FIELD(SYM) && !PRINT_FIELD(IP) && !PRINT_FIELD(ADDR)) {
246 pr_err("Display of symbols requested but neither sample IP nor " 264 pr_err("Display of symbols requested but neither sample IP nor "
247 "sample address\nis selected. Hence, no addresses to convert " 265 "sample address\nis selected. Hence, no addresses to convert "
@@ -387,9 +405,7 @@ out:
387 return 0; 405 return 0;
388} 406}
389 407
390static void print_sample_iregs(union perf_event *event __maybe_unused, 408static void print_sample_iregs(struct perf_sample *sample,
391 struct perf_sample *sample,
392 struct thread *thread __maybe_unused,
393 struct perf_event_attr *attr) 409 struct perf_event_attr *attr)
394{ 410{
395 struct regs_dump *regs = &sample->intr_regs; 411 struct regs_dump *regs = &sample->intr_regs;
@@ -458,10 +474,7 @@ mispred_str(struct branch_entry *br)
458 return br->flags.predicted ? 'P' : 'M'; 474 return br->flags.predicted ? 'P' : 'M';
459} 475}
460 476
461static void print_sample_brstack(union perf_event *event __maybe_unused, 477static void print_sample_brstack(struct perf_sample *sample)
462 struct perf_sample *sample,
463 struct thread *thread __maybe_unused,
464 struct perf_event_attr *attr __maybe_unused)
465{ 478{
466 struct branch_stack *br = sample->branch_stack; 479 struct branch_stack *br = sample->branch_stack;
467 u64 i; 480 u64 i;
@@ -480,14 +493,11 @@ static void print_sample_brstack(union perf_event *event __maybe_unused,
480 } 493 }
481} 494}
482 495
483static void print_sample_brstacksym(union perf_event *event __maybe_unused, 496static void print_sample_brstacksym(struct perf_sample *sample,
484 struct perf_sample *sample, 497 struct thread *thread)
485 struct thread *thread __maybe_unused,
486 struct perf_event_attr *attr __maybe_unused)
487{ 498{
488 struct branch_stack *br = sample->branch_stack; 499 struct branch_stack *br = sample->branch_stack;
489 struct addr_location alf, alt; 500 struct addr_location alf, alt;
490 u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
491 u64 i, from, to; 501 u64 i, from, to;
492 502
493 if (!(br && br->nr)) 503 if (!(br && br->nr))
@@ -500,11 +510,11 @@ static void print_sample_brstacksym(union perf_event *event __maybe_unused,
500 from = br->entries[i].from; 510 from = br->entries[i].from;
501 to = br->entries[i].to; 511 to = br->entries[i].to;
502 512
503 thread__find_addr_map(thread, cpumode, MAP__FUNCTION, from, &alf); 513 thread__find_addr_map(thread, sample->cpumode, MAP__FUNCTION, from, &alf);
504 if (alf.map) 514 if (alf.map)
505 alf.sym = map__find_symbol(alf.map, alf.addr, NULL); 515 alf.sym = map__find_symbol(alf.map, alf.addr, NULL);
506 516
507 thread__find_addr_map(thread, cpumode, MAP__FUNCTION, to, &alt); 517 thread__find_addr_map(thread, sample->cpumode, MAP__FUNCTION, to, &alt);
508 if (alt.map) 518 if (alt.map)
509 alt.sym = map__find_symbol(alt.map, alt.addr, NULL); 519 alt.sym = map__find_symbol(alt.map, alt.addr, NULL);
510 520
@@ -520,8 +530,7 @@ static void print_sample_brstacksym(union perf_event *event __maybe_unused,
520} 530}
521 531
522 532
523static void print_sample_addr(union perf_event *event, 533static void print_sample_addr(struct perf_sample *sample,
524 struct perf_sample *sample,
525 struct thread *thread, 534 struct thread *thread,
526 struct perf_event_attr *attr) 535 struct perf_event_attr *attr)
527{ 536{
@@ -532,7 +541,7 @@ static void print_sample_addr(union perf_event *event,
532 if (!sample_addr_correlates_sym(attr)) 541 if (!sample_addr_correlates_sym(attr))
533 return; 542 return;
534 543
535 perf_event__preprocess_sample_addr(event, sample, thread, &al); 544 thread__resolve(thread, &al, sample);
536 545
537 if (PRINT_FIELD(SYM)) { 546 if (PRINT_FIELD(SYM)) {
538 printf(" "); 547 printf(" ");
@@ -549,8 +558,7 @@ static void print_sample_addr(union perf_event *event,
549 } 558 }
550} 559}
551 560
552static void print_sample_bts(union perf_event *event, 561static void print_sample_bts(struct perf_sample *sample,
553 struct perf_sample *sample,
554 struct perf_evsel *evsel, 562 struct perf_evsel *evsel,
555 struct thread *thread, 563 struct thread *thread,
556 struct addr_location *al) 564 struct addr_location *al)
@@ -580,7 +588,7 @@ static void print_sample_bts(union perf_event *event,
580 ((evsel->attr.sample_type & PERF_SAMPLE_ADDR) && 588 ((evsel->attr.sample_type & PERF_SAMPLE_ADDR) &&
581 !output[attr->type].user_set)) { 589 !output[attr->type].user_set)) {
582 printf(" => "); 590 printf(" => ");
583 print_sample_addr(event, sample, thread, attr); 591 print_sample_addr(sample, thread, attr);
584 } 592 }
585 593
586 if (print_srcline_last) 594 if (print_srcline_last)
@@ -608,6 +616,84 @@ static void print_sample_flags(u32 flags)
608 printf(" %-4s ", str); 616 printf(" %-4s ", str);
609} 617}
610 618
619struct printer_data {
620 int line_no;
621 bool hit_nul;
622 bool is_printable;
623};
624
625static void
626print_sample_bpf_output_printer(enum binary_printer_ops op,
627 unsigned int val,
628 void *extra)
629{
630 unsigned char ch = (unsigned char)val;
631 struct printer_data *printer_data = extra;
632
633 switch (op) {
634 case BINARY_PRINT_DATA_BEGIN:
635 printf("\n");
636 break;
637 case BINARY_PRINT_LINE_BEGIN:
638 printf("%17s", !printer_data->line_no ? "BPF output:" :
639 " ");
640 break;
641 case BINARY_PRINT_ADDR:
642 printf(" %04x:", val);
643 break;
644 case BINARY_PRINT_NUM_DATA:
645 printf(" %02x", val);
646 break;
647 case BINARY_PRINT_NUM_PAD:
648 printf(" ");
649 break;
650 case BINARY_PRINT_SEP:
651 printf(" ");
652 break;
653 case BINARY_PRINT_CHAR_DATA:
654 if (printer_data->hit_nul && ch)
655 printer_data->is_printable = false;
656
657 if (!isprint(ch)) {
658 printf("%c", '.');
659
660 if (!printer_data->is_printable)
661 break;
662
663 if (ch == '\0')
664 printer_data->hit_nul = true;
665 else
666 printer_data->is_printable = false;
667 } else {
668 printf("%c", ch);
669 }
670 break;
671 case BINARY_PRINT_CHAR_PAD:
672 printf(" ");
673 break;
674 case BINARY_PRINT_LINE_END:
675 printf("\n");
676 printer_data->line_no++;
677 break;
678 case BINARY_PRINT_DATA_END:
679 default:
680 break;
681 }
682}
683
684static void print_sample_bpf_output(struct perf_sample *sample)
685{
686 unsigned int nr_bytes = sample->raw_size;
687 struct printer_data printer_data = {0, false, true};
688
689 print_binary(sample->raw_data, nr_bytes, 8,
690 print_sample_bpf_output_printer, &printer_data);
691
692 if (printer_data.is_printable && printer_data.hit_nul)
693 printf("%17s \"%s\"\n", "BPF string:",
694 (char *)(sample->raw_data));
695}
696
611struct perf_script { 697struct perf_script {
612 struct perf_tool tool; 698 struct perf_tool tool;
613 struct perf_session *session; 699 struct perf_session *session;
@@ -634,7 +720,24 @@ static int perf_evlist__max_name_len(struct perf_evlist *evlist)
634 return max; 720 return max;
635} 721}
636 722
637static void process_event(struct perf_script *script, union perf_event *event, 723static size_t data_src__printf(u64 data_src)
724{
725 struct mem_info mi = { .data_src.val = data_src };
726 char decode[100];
727 char out[100];
728 static int maxlen;
729 int len;
730
731 perf_script__meminfo_scnprintf(decode, 100, &mi);
732
733 len = scnprintf(out, 100, "%16" PRIx64 " %s", data_src, decode);
734 if (maxlen < len)
735 maxlen = len;
736
737 return printf("%-*s", maxlen, out);
738}
739
740static void process_event(struct perf_script *script,
638 struct perf_sample *sample, struct perf_evsel *evsel, 741 struct perf_sample *sample, struct perf_evsel *evsel,
639 struct addr_location *al) 742 struct addr_location *al)
640{ 743{
@@ -663,7 +766,7 @@ static void process_event(struct perf_script *script, union perf_event *event,
663 print_sample_flags(sample->flags); 766 print_sample_flags(sample->flags);
664 767
665 if (is_bts_event(attr)) { 768 if (is_bts_event(attr)) {
666 print_sample_bts(event, sample, evsel, thread, al); 769 print_sample_bts(sample, evsel, thread, al);
667 return; 770 return;
668 } 771 }
669 772
@@ -671,7 +774,13 @@ static void process_event(struct perf_script *script, union perf_event *event,
671 event_format__print(evsel->tp_format, sample->cpu, 774 event_format__print(evsel->tp_format, sample->cpu,
672 sample->raw_data, sample->raw_size); 775 sample->raw_data, sample->raw_size);
673 if (PRINT_FIELD(ADDR)) 776 if (PRINT_FIELD(ADDR))
674 print_sample_addr(event, sample, thread, attr); 777 print_sample_addr(sample, thread, attr);
778
779 if (PRINT_FIELD(DATA_SRC))
780 data_src__printf(sample->data_src);
781
782 if (PRINT_FIELD(WEIGHT))
783 printf("%16" PRIu64, sample->weight);
675 784
676 if (PRINT_FIELD(IP)) { 785 if (PRINT_FIELD(IP)) {
677 if (!symbol_conf.use_callchain) 786 if (!symbol_conf.use_callchain)
@@ -685,12 +794,15 @@ static void process_event(struct perf_script *script, union perf_event *event,
685 } 794 }
686 795
687 if (PRINT_FIELD(IREGS)) 796 if (PRINT_FIELD(IREGS))
688 print_sample_iregs(event, sample, thread, attr); 797 print_sample_iregs(sample, attr);
689 798
690 if (PRINT_FIELD(BRSTACK)) 799 if (PRINT_FIELD(BRSTACK))
691 print_sample_brstack(event, sample, thread, attr); 800 print_sample_brstack(sample);
692 else if (PRINT_FIELD(BRSTACKSYM)) 801 else if (PRINT_FIELD(BRSTACKSYM))
693 print_sample_brstacksym(event, sample, thread, attr); 802 print_sample_brstacksym(sample, thread);
803
804 if (perf_evsel__is_bpf_output(evsel) && PRINT_FIELD(BPF_OUTPUT))
805 print_sample_bpf_output(sample);
694 806
695 printf("\n"); 807 printf("\n");
696} 808}
@@ -783,7 +895,7 @@ static int process_sample_event(struct perf_tool *tool,
783 return 0; 895 return 0;
784 } 896 }
785 897
786 if (perf_event__preprocess_sample(event, machine, &al, sample) < 0) { 898 if (machine__resolve(machine, &al, sample) < 0) {
787 pr_err("problem processing %d event, skipping it.\n", 899 pr_err("problem processing %d event, skipping it.\n",
788 event->header.type); 900 event->header.type);
789 return -1; 901 return -1;
@@ -798,7 +910,7 @@ static int process_sample_event(struct perf_tool *tool,
798 if (scripting_ops) 910 if (scripting_ops)
799 scripting_ops->process_event(event, sample, evsel, &al); 911 scripting_ops->process_event(event, sample, evsel, &al);
800 else 912 else
801 process_event(scr, event, sample, evsel, &al); 913 process_event(scr, sample, evsel, &al);
802 914
803out_put: 915out_put:
804 addr_location__put(&al); 916 addr_location__put(&al);
@@ -1090,23 +1202,6 @@ static struct script_spec *script_spec__find(const char *spec)
1090 return NULL; 1202 return NULL;
1091} 1203}
1092 1204
1093static struct script_spec *script_spec__findnew(const char *spec,
1094 struct scripting_ops *ops)
1095{
1096 struct script_spec *s = script_spec__find(spec);
1097
1098 if (s)
1099 return s;
1100
1101 s = script_spec__new(spec, ops);
1102 if (!s)
1103 return NULL;
1104
1105 script_spec__add(s);
1106
1107 return s;
1108}
1109
1110int script_spec_register(const char *spec, struct scripting_ops *ops) 1205int script_spec_register(const char *spec, struct scripting_ops *ops)
1111{ 1206{
1112 struct script_spec *s; 1207 struct script_spec *s;
@@ -1115,9 +1210,11 @@ int script_spec_register(const char *spec, struct scripting_ops *ops)
1115 if (s) 1210 if (s)
1116 return -1; 1211 return -1;
1117 1212
1118 s = script_spec__findnew(spec, ops); 1213 s = script_spec__new(spec, ops);
1119 if (!s) 1214 if (!s)
1120 return -1; 1215 return -1;
1216 else
1217 script_spec__add(s);
1121 1218
1122 return 0; 1219 return 0;
1123} 1220}
diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c
index 038e877081b6..1f19f2f999c8 100644
--- a/tools/perf/builtin-stat.c
+++ b/tools/perf/builtin-stat.c
@@ -122,6 +122,7 @@ static bool sync_run = false;
122static unsigned int initial_delay = 0; 122static unsigned int initial_delay = 0;
123static unsigned int unit_width = 4; /* strlen("unit") */ 123static unsigned int unit_width = 4; /* strlen("unit") */
124static bool forever = false; 124static bool forever = false;
125static bool metric_only = false;
125static struct timespec ref_time; 126static struct timespec ref_time;
126static struct cpu_map *aggr_map; 127static struct cpu_map *aggr_map;
127static aggr_get_id_t aggr_get_id; 128static aggr_get_id_t aggr_get_id;
@@ -735,6 +736,191 @@ static void aggr_printout(struct perf_evsel *evsel, int id, int nr)
735 } 736 }
736} 737}
737 738
739struct outstate {
740 FILE *fh;
741 bool newline;
742 const char *prefix;
743 int nfields;
744 int id, nr;
745 struct perf_evsel *evsel;
746};
747
748#define METRIC_LEN 35
749
750static void new_line_std(void *ctx)
751{
752 struct outstate *os = ctx;
753
754 os->newline = true;
755}
756
757static void do_new_line_std(struct outstate *os)
758{
759 fputc('\n', os->fh);
760 fputs(os->prefix, os->fh);
761 aggr_printout(os->evsel, os->id, os->nr);
762 if (stat_config.aggr_mode == AGGR_NONE)
763 fprintf(os->fh, " ");
764 fprintf(os->fh, " ");
765}
766
767static void print_metric_std(void *ctx, const char *color, const char *fmt,
768 const char *unit, double val)
769{
770 struct outstate *os = ctx;
771 FILE *out = os->fh;
772 int n;
773 bool newline = os->newline;
774
775 os->newline = false;
776
777 if (unit == NULL || fmt == NULL) {
778 fprintf(out, "%-*s", METRIC_LEN, "");
779 return;
780 }
781
782 if (newline)
783 do_new_line_std(os);
784
785 n = fprintf(out, " # ");
786 if (color)
787 n += color_fprintf(out, color, fmt, val);
788 else
789 n += fprintf(out, fmt, val);
790 fprintf(out, " %-*s", METRIC_LEN - n - 1, unit);
791}
792
793static void new_line_csv(void *ctx)
794{
795 struct outstate *os = ctx;
796 int i;
797
798 fputc('\n', os->fh);
799 if (os->prefix)
800 fprintf(os->fh, "%s%s", os->prefix, csv_sep);
801 aggr_printout(os->evsel, os->id, os->nr);
802 for (i = 0; i < os->nfields; i++)
803 fputs(csv_sep, os->fh);
804}
805
806static void print_metric_csv(void *ctx,
807 const char *color __maybe_unused,
808 const char *fmt, const char *unit, double val)
809{
810 struct outstate *os = ctx;
811 FILE *out = os->fh;
812 char buf[64], *vals, *ends;
813
814 if (unit == NULL || fmt == NULL) {
815 fprintf(out, "%s%s%s%s", csv_sep, csv_sep, csv_sep, csv_sep);
816 return;
817 }
818 snprintf(buf, sizeof(buf), fmt, val);
819 vals = buf;
820 while (isspace(*vals))
821 vals++;
822 ends = vals;
823 while (isdigit(*ends) || *ends == '.')
824 ends++;
825 *ends = 0;
826 while (isspace(*unit))
827 unit++;
828 fprintf(out, "%s%s%s%s", csv_sep, vals, csv_sep, unit);
829}
830
831#define METRIC_ONLY_LEN 20
832
833/* Filter out some columns that don't work well in metrics only mode */
834
835static bool valid_only_metric(const char *unit)
836{
837 if (!unit)
838 return false;
839 if (strstr(unit, "/sec") ||
840 strstr(unit, "hz") ||
841 strstr(unit, "Hz") ||
842 strstr(unit, "CPUs utilized"))
843 return false;
844 return true;
845}
846
847static const char *fixunit(char *buf, struct perf_evsel *evsel,
848 const char *unit)
849{
850 if (!strncmp(unit, "of all", 6)) {
851 snprintf(buf, 1024, "%s %s", perf_evsel__name(evsel),
852 unit);
853 return buf;
854 }
855 return unit;
856}
857
858static void print_metric_only(void *ctx, const char *color, const char *fmt,
859 const char *unit, double val)
860{
861 struct outstate *os = ctx;
862 FILE *out = os->fh;
863 int n;
864 char buf[1024];
865 unsigned mlen = METRIC_ONLY_LEN;
866
867 if (!valid_only_metric(unit))
868 return;
869 unit = fixunit(buf, os->evsel, unit);
870 if (color)
871 n = color_fprintf(out, color, fmt, val);
872 else
873 n = fprintf(out, fmt, val);
874 if (n > METRIC_ONLY_LEN)
875 n = METRIC_ONLY_LEN;
876 if (mlen < strlen(unit))
877 mlen = strlen(unit) + 1;
878 fprintf(out, "%*s", mlen - n, "");
879}
880
881static void print_metric_only_csv(void *ctx, const char *color __maybe_unused,
882 const char *fmt,
883 const char *unit, double val)
884{
885 struct outstate *os = ctx;
886 FILE *out = os->fh;
887 char buf[64], *vals, *ends;
888 char tbuf[1024];
889
890 if (!valid_only_metric(unit))
891 return;
892 unit = fixunit(tbuf, os->evsel, unit);
893 snprintf(buf, sizeof buf, fmt, val);
894 vals = buf;
895 while (isspace(*vals))
896 vals++;
897 ends = vals;
898 while (isdigit(*ends) || *ends == '.')
899 ends++;
900 *ends = 0;
901 fprintf(out, "%s%s", vals, csv_sep);
902}
903
904static void new_line_metric(void *ctx __maybe_unused)
905{
906}
907
908static void print_metric_header(void *ctx, const char *color __maybe_unused,
909 const char *fmt __maybe_unused,
910 const char *unit, double val __maybe_unused)
911{
912 struct outstate *os = ctx;
913 char tbuf[1024];
914
915 if (!valid_only_metric(unit))
916 return;
917 unit = fixunit(tbuf, os->evsel, unit);
918 if (csv_output)
919 fprintf(os->fh, "%s%s", unit, csv_sep);
920 else
921 fprintf(os->fh, "%-*s ", METRIC_ONLY_LEN, unit);
922}
923
738static void nsec_printout(int id, int nr, struct perf_evsel *evsel, double avg) 924static void nsec_printout(int id, int nr, struct perf_evsel *evsel, double avg)
739{ 925{
740 FILE *output = stat_config.output; 926 FILE *output = stat_config.output;
@@ -763,6 +949,28 @@ static void nsec_printout(int id, int nr, struct perf_evsel *evsel, double avg)
763 fprintf(output, "%s%s", csv_sep, evsel->cgrp->name); 949 fprintf(output, "%s%s", csv_sep, evsel->cgrp->name);
764} 950}
765 951
952static int first_shadow_cpu(struct perf_evsel *evsel, int id)
953{
954 int i;
955
956 if (!aggr_get_id)
957 return 0;
958
959 if (stat_config.aggr_mode == AGGR_NONE)
960 return id;
961
962 if (stat_config.aggr_mode == AGGR_GLOBAL)
963 return 0;
964
965 for (i = 0; i < perf_evsel__nr_cpus(evsel); i++) {
966 int cpu2 = perf_evsel__cpus(evsel)->map[i];
967
968 if (aggr_get_id(evsel_list->cpus, cpu2) == id)
969 return cpu2;
970 }
971 return 0;
972}
973
766static void abs_printout(int id, int nr, struct perf_evsel *evsel, double avg) 974static void abs_printout(int id, int nr, struct perf_evsel *evsel, double avg)
767{ 975{
768 FILE *output = stat_config.output; 976 FILE *output = stat_config.output;
@@ -793,22 +1001,124 @@ static void abs_printout(int id, int nr, struct perf_evsel *evsel, double avg)
793 fprintf(output, "%s%s", csv_sep, evsel->cgrp->name); 1001 fprintf(output, "%s%s", csv_sep, evsel->cgrp->name);
794} 1002}
795 1003
796static void printout(int id, int nr, struct perf_evsel *counter, double uval) 1004static void printout(int id, int nr, struct perf_evsel *counter, double uval,
1005 char *prefix, u64 run, u64 ena, double noise)
797{ 1006{
798 int cpu = cpu_map__id_to_cpu(id); 1007 struct perf_stat_output_ctx out;
1008 struct outstate os = {
1009 .fh = stat_config.output,
1010 .prefix = prefix ? prefix : "",
1011 .id = id,
1012 .nr = nr,
1013 .evsel = counter,
1014 };
1015 print_metric_t pm = print_metric_std;
1016 void (*nl)(void *);
799 1017
800 if (stat_config.aggr_mode == AGGR_GLOBAL) 1018 if (metric_only) {
801 cpu = 0; 1019 nl = new_line_metric;
1020 if (csv_output)
1021 pm = print_metric_only_csv;
1022 else
1023 pm = print_metric_only;
1024 } else
1025 nl = new_line_std;
1026
1027 if (csv_output && !metric_only) {
1028 static int aggr_fields[] = {
1029 [AGGR_GLOBAL] = 0,
1030 [AGGR_THREAD] = 1,
1031 [AGGR_NONE] = 1,
1032 [AGGR_SOCKET] = 2,
1033 [AGGR_CORE] = 2,
1034 };
1035
1036 pm = print_metric_csv;
1037 nl = new_line_csv;
1038 os.nfields = 3;
1039 os.nfields += aggr_fields[stat_config.aggr_mode];
1040 if (counter->cgrp)
1041 os.nfields++;
1042 }
1043 if (run == 0 || ena == 0 || counter->counts->scaled == -1) {
1044 if (metric_only) {
1045 pm(&os, NULL, "", "", 0);
1046 return;
1047 }
1048 aggr_printout(counter, id, nr);
1049
1050 fprintf(stat_config.output, "%*s%s",
1051 csv_output ? 0 : 18,
1052 counter->supported ? CNTR_NOT_COUNTED : CNTR_NOT_SUPPORTED,
1053 csv_sep);
1054
1055 fprintf(stat_config.output, "%-*s%s",
1056 csv_output ? 0 : unit_width,
1057 counter->unit, csv_sep);
1058
1059 fprintf(stat_config.output, "%*s",
1060 csv_output ? 0 : -25,
1061 perf_evsel__name(counter));
1062
1063 if (counter->cgrp)
1064 fprintf(stat_config.output, "%s%s",
1065 csv_sep, counter->cgrp->name);
802 1066
803 if (nsec_counter(counter)) 1067 if (!csv_output)
1068 pm(&os, NULL, NULL, "", 0);
1069 print_noise(counter, noise);
1070 print_running(run, ena);
1071 if (csv_output)
1072 pm(&os, NULL, NULL, "", 0);
1073 return;
1074 }
1075
1076 if (metric_only)
1077 /* nothing */;
1078 else if (nsec_counter(counter))
804 nsec_printout(id, nr, counter, uval); 1079 nsec_printout(id, nr, counter, uval);
805 else 1080 else
806 abs_printout(id, nr, counter, uval); 1081 abs_printout(id, nr, counter, uval);
807 1082
808 if (!csv_output && !stat_config.interval) 1083 out.print_metric = pm;
809 perf_stat__print_shadow_stats(stat_config.output, counter, 1084 out.new_line = nl;
810 uval, cpu, 1085 out.ctx = &os;
811 stat_config.aggr_mode); 1086
1087 if (csv_output && !metric_only) {
1088 print_noise(counter, noise);
1089 print_running(run, ena);
1090 }
1091
1092 perf_stat__print_shadow_stats(counter, uval,
1093 first_shadow_cpu(counter, id),
1094 &out);
1095 if (!csv_output && !metric_only) {
1096 print_noise(counter, noise);
1097 print_running(run, ena);
1098 }
1099}
1100
1101static void aggr_update_shadow(void)
1102{
1103 int cpu, s2, id, s;
1104 u64 val;
1105 struct perf_evsel *counter;
1106
1107 for (s = 0; s < aggr_map->nr; s++) {
1108 id = aggr_map->map[s];
1109 evlist__for_each(evsel_list, counter) {
1110 val = 0;
1111 for (cpu = 0; cpu < perf_evsel__nr_cpus(counter); cpu++) {
1112 s2 = aggr_get_id(evsel_list->cpus, cpu);
1113 if (s2 != id)
1114 continue;
1115 val += perf_counts(counter->counts, cpu, 0)->val;
1116 }
1117 val = val * counter->scale;
1118 perf_stat__update_shadow_stats(counter, &val,
1119 first_shadow_cpu(counter, id));
1120 }
1121 }
812} 1122}
813 1123
814static void print_aggr(char *prefix) 1124static void print_aggr(char *prefix)
@@ -818,12 +1128,23 @@ static void print_aggr(char *prefix)
818 int cpu, s, s2, id, nr; 1128 int cpu, s, s2, id, nr;
819 double uval; 1129 double uval;
820 u64 ena, run, val; 1130 u64 ena, run, val;
1131 bool first;
821 1132
822 if (!(aggr_map || aggr_get_id)) 1133 if (!(aggr_map || aggr_get_id))
823 return; 1134 return;
824 1135
1136 aggr_update_shadow();
1137
1138 /*
1139 * With metric_only everything is on a single line.
1140 * Without each counter has its own line.
1141 */
825 for (s = 0; s < aggr_map->nr; s++) { 1142 for (s = 0; s < aggr_map->nr; s++) {
1143 if (prefix && metric_only)
1144 fprintf(output, "%s", prefix);
1145
826 id = aggr_map->map[s]; 1146 id = aggr_map->map[s];
1147 first = true;
827 evlist__for_each(evsel_list, counter) { 1148 evlist__for_each(evsel_list, counter) {
828 val = ena = run = 0; 1149 val = ena = run = 0;
829 nr = 0; 1150 nr = 0;
@@ -836,41 +1157,20 @@ static void print_aggr(char *prefix)
836 run += perf_counts(counter->counts, cpu, 0)->run; 1157 run += perf_counts(counter->counts, cpu, 0)->run;
837 nr++; 1158 nr++;
838 } 1159 }
839 if (prefix) 1160 if (first && metric_only) {
840 fprintf(output, "%s", prefix); 1161 first = false;
841
842 if (run == 0 || ena == 0) {
843 aggr_printout(counter, id, nr); 1162 aggr_printout(counter, id, nr);
844
845 fprintf(output, "%*s%s",
846 csv_output ? 0 : 18,
847 counter->supported ? CNTR_NOT_COUNTED : CNTR_NOT_SUPPORTED,
848 csv_sep);
849
850 fprintf(output, "%-*s%s",
851 csv_output ? 0 : unit_width,
852 counter->unit, csv_sep);
853
854 fprintf(output, "%*s",
855 csv_output ? 0 : -25,
856 perf_evsel__name(counter));
857
858 if (counter->cgrp)
859 fprintf(output, "%s%s",
860 csv_sep, counter->cgrp->name);
861
862 print_running(run, ena);
863 fputc('\n', output);
864 continue;
865 } 1163 }
866 uval = val * counter->scale; 1164 if (prefix && !metric_only)
867 printout(id, nr, counter, uval); 1165 fprintf(output, "%s", prefix);
868 if (!csv_output)
869 print_noise(counter, 1.0);
870 1166
871 print_running(run, ena); 1167 uval = val * counter->scale;
872 fputc('\n', output); 1168 printout(id, nr, counter, uval, prefix, run, ena, 1.0);
1169 if (!metric_only)
1170 fputc('\n', output);
873 } 1171 }
1172 if (metric_only)
1173 fputc('\n', output);
874 } 1174 }
875} 1175}
876 1176
@@ -895,12 +1195,7 @@ static void print_aggr_thread(struct perf_evsel *counter, char *prefix)
895 fprintf(output, "%s", prefix); 1195 fprintf(output, "%s", prefix);
896 1196
897 uval = val * counter->scale; 1197 uval = val * counter->scale;
898 printout(thread, 0, counter, uval); 1198 printout(thread, 0, counter, uval, prefix, run, ena, 1.0);
899
900 if (!csv_output)
901 print_noise(counter, 1.0);
902
903 print_running(run, ena);
904 fputc('\n', output); 1199 fputc('\n', output);
905 } 1200 }
906} 1201}
@@ -914,43 +1209,19 @@ static void print_counter_aggr(struct perf_evsel *counter, char *prefix)
914 FILE *output = stat_config.output; 1209 FILE *output = stat_config.output;
915 struct perf_stat_evsel *ps = counter->priv; 1210 struct perf_stat_evsel *ps = counter->priv;
916 double avg = avg_stats(&ps->res_stats[0]); 1211 double avg = avg_stats(&ps->res_stats[0]);
917 int scaled = counter->counts->scaled;
918 double uval; 1212 double uval;
919 double avg_enabled, avg_running; 1213 double avg_enabled, avg_running;
920 1214
921 avg_enabled = avg_stats(&ps->res_stats[1]); 1215 avg_enabled = avg_stats(&ps->res_stats[1]);
922 avg_running = avg_stats(&ps->res_stats[2]); 1216 avg_running = avg_stats(&ps->res_stats[2]);
923 1217
924 if (prefix) 1218 if (prefix && !metric_only)
925 fprintf(output, "%s", prefix); 1219 fprintf(output, "%s", prefix);
926 1220
927 if (scaled == -1 || !counter->supported) {
928 fprintf(output, "%*s%s",
929 csv_output ? 0 : 18,
930 counter->supported ? CNTR_NOT_COUNTED : CNTR_NOT_SUPPORTED,
931 csv_sep);
932 fprintf(output, "%-*s%s",
933 csv_output ? 0 : unit_width,
934 counter->unit, csv_sep);
935 fprintf(output, "%*s",
936 csv_output ? 0 : -25,
937 perf_evsel__name(counter));
938
939 if (counter->cgrp)
940 fprintf(output, "%s%s", csv_sep, counter->cgrp->name);
941
942 print_running(avg_running, avg_enabled);
943 fputc('\n', output);
944 return;
945 }
946
947 uval = avg * counter->scale; 1221 uval = avg * counter->scale;
948 printout(-1, 0, counter, uval); 1222 printout(-1, 0, counter, uval, prefix, avg_running, avg_enabled, avg);
949 1223 if (!metric_only)
950 print_noise(counter, avg); 1224 fprintf(output, "\n");
951
952 print_running(avg_running, avg_enabled);
953 fprintf(output, "\n");
954} 1225}
955 1226
956/* 1227/*
@@ -972,39 +1243,78 @@ static void print_counter(struct perf_evsel *counter, char *prefix)
972 if (prefix) 1243 if (prefix)
973 fprintf(output, "%s", prefix); 1244 fprintf(output, "%s", prefix);
974 1245
975 if (run == 0 || ena == 0) { 1246 uval = val * counter->scale;
976 fprintf(output, "CPU%*d%s%*s%s", 1247 printout(cpu, 0, counter, uval, prefix, run, ena, 1.0);
977 csv_output ? 0 : -4,
978 perf_evsel__cpus(counter)->map[cpu], csv_sep,
979 csv_output ? 0 : 18,
980 counter->supported ? CNTR_NOT_COUNTED : CNTR_NOT_SUPPORTED,
981 csv_sep);
982 1248
983 fprintf(output, "%-*s%s", 1249 fputc('\n', output);
984 csv_output ? 0 : unit_width, 1250 }
985 counter->unit, csv_sep); 1251}
986 1252
987 fprintf(output, "%*s", 1253static void print_no_aggr_metric(char *prefix)
988 csv_output ? 0 : -25, 1254{
989 perf_evsel__name(counter)); 1255 int cpu;
1256 int nrcpus = 0;
1257 struct perf_evsel *counter;
1258 u64 ena, run, val;
1259 double uval;
990 1260
991 if (counter->cgrp) 1261 nrcpus = evsel_list->cpus->nr;
992 fprintf(output, "%s%s", 1262 for (cpu = 0; cpu < nrcpus; cpu++) {
993 csv_sep, counter->cgrp->name); 1263 bool first = true;
994 1264
995 print_running(run, ena); 1265 if (prefix)
996 fputc('\n', output); 1266 fputs(prefix, stat_config.output);
997 continue; 1267 evlist__for_each(evsel_list, counter) {
1268 if (first) {
1269 aggr_printout(counter, cpu, 0);
1270 first = false;
1271 }
1272 val = perf_counts(counter->counts, cpu, 0)->val;
1273 ena = perf_counts(counter->counts, cpu, 0)->ena;
1274 run = perf_counts(counter->counts, cpu, 0)->run;
1275
1276 uval = val * counter->scale;
1277 printout(cpu, 0, counter, uval, prefix, run, ena, 1.0);
998 } 1278 }
1279 fputc('\n', stat_config.output);
1280 }
1281}
999 1282
1000 uval = val * counter->scale; 1283static int aggr_header_lens[] = {
1001 printout(cpu, 0, counter, uval); 1284 [AGGR_CORE] = 18,
1002 if (!csv_output) 1285 [AGGR_SOCKET] = 12,
1003 print_noise(counter, 1.0); 1286 [AGGR_NONE] = 6,
1004 print_running(run, ena); 1287 [AGGR_THREAD] = 24,
1288 [AGGR_GLOBAL] = 0,
1289};
1005 1290
1006 fputc('\n', output); 1291static void print_metric_headers(char *prefix)
1292{
1293 struct perf_stat_output_ctx out;
1294 struct perf_evsel *counter;
1295 struct outstate os = {
1296 .fh = stat_config.output
1297 };
1298
1299 if (prefix)
1300 fprintf(stat_config.output, "%s", prefix);
1301
1302 if (!csv_output)
1303 fprintf(stat_config.output, "%*s",
1304 aggr_header_lens[stat_config.aggr_mode], "");
1305
1306 /* Print metrics headers only */
1307 evlist__for_each(evsel_list, counter) {
1308 os.evsel = counter;
1309 out.ctx = &os;
1310 out.print_metric = print_metric_header;
1311 out.new_line = new_line_metric;
1312 os.evsel = counter;
1313 perf_stat__print_shadow_stats(counter, 0,
1314 0,
1315 &out);
1007 } 1316 }
1317 fputc('\n', stat_config.output);
1008} 1318}
1009 1319
1010static void print_interval(char *prefix, struct timespec *ts) 1320static void print_interval(char *prefix, struct timespec *ts)
@@ -1014,7 +1324,7 @@ static void print_interval(char *prefix, struct timespec *ts)
1014 1324
1015 sprintf(prefix, "%6lu.%09lu%s", ts->tv_sec, ts->tv_nsec, csv_sep); 1325 sprintf(prefix, "%6lu.%09lu%s", ts->tv_sec, ts->tv_nsec, csv_sep);
1016 1326
1017 if (num_print_interval == 0 && !csv_output) { 1327 if (num_print_interval == 0 && !csv_output && !metric_only) {
1018 switch (stat_config.aggr_mode) { 1328 switch (stat_config.aggr_mode) {
1019 case AGGR_SOCKET: 1329 case AGGR_SOCKET:
1020 fprintf(output, "# time socket cpus counts %*s events\n", unit_width, "unit"); 1330 fprintf(output, "# time socket cpus counts %*s events\n", unit_width, "unit");
@@ -1101,6 +1411,17 @@ static void print_counters(struct timespec *ts, int argc, const char **argv)
1101 else 1411 else
1102 print_header(argc, argv); 1412 print_header(argc, argv);
1103 1413
1414 if (metric_only) {
1415 static int num_print_iv;
1416
1417 if (num_print_iv == 0)
1418 print_metric_headers(prefix);
1419 if (num_print_iv++ == 25)
1420 num_print_iv = 0;
1421 if (stat_config.aggr_mode == AGGR_GLOBAL && prefix)
1422 fprintf(stat_config.output, "%s", prefix);
1423 }
1424
1104 switch (stat_config.aggr_mode) { 1425 switch (stat_config.aggr_mode) {
1105 case AGGR_CORE: 1426 case AGGR_CORE:
1106 case AGGR_SOCKET: 1427 case AGGR_SOCKET:
@@ -1113,10 +1434,16 @@ static void print_counters(struct timespec *ts, int argc, const char **argv)
1113 case AGGR_GLOBAL: 1434 case AGGR_GLOBAL:
1114 evlist__for_each(evsel_list, counter) 1435 evlist__for_each(evsel_list, counter)
1115 print_counter_aggr(counter, prefix); 1436 print_counter_aggr(counter, prefix);
1437 if (metric_only)
1438 fputc('\n', stat_config.output);
1116 break; 1439 break;
1117 case AGGR_NONE: 1440 case AGGR_NONE:
1118 evlist__for_each(evsel_list, counter) 1441 if (metric_only)
1119 print_counter(counter, prefix); 1442 print_no_aggr_metric(prefix);
1443 else {
1444 evlist__for_each(evsel_list, counter)
1445 print_counter(counter, prefix);
1446 }
1120 break; 1447 break;
1121 case AGGR_UNSET: 1448 case AGGR_UNSET:
1122 default: 1449 default:
@@ -1237,6 +1564,8 @@ static const struct option stat_options[] = {
1237 "aggregate counts per thread", AGGR_THREAD), 1564 "aggregate counts per thread", AGGR_THREAD),
1238 OPT_UINTEGER('D', "delay", &initial_delay, 1565 OPT_UINTEGER('D', "delay", &initial_delay,
1239 "ms to wait before starting measurement after program start"), 1566 "ms to wait before starting measurement after program start"),
1567 OPT_BOOLEAN(0, "metric-only", &metric_only,
1568 "Only print computed metrics. No raw values"),
1240 OPT_END() 1569 OPT_END()
1241}; 1570};
1242 1571
@@ -1435,7 +1764,7 @@ static int perf_stat_init_aggr_mode_file(struct perf_stat *st)
1435 */ 1764 */
1436static int add_default_attributes(void) 1765static int add_default_attributes(void)
1437{ 1766{
1438 struct perf_event_attr default_attrs[] = { 1767 struct perf_event_attr default_attrs0[] = {
1439 1768
1440 { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_TASK_CLOCK }, 1769 { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_TASK_CLOCK },
1441 { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_CONTEXT_SWITCHES }, 1770 { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_CONTEXT_SWITCHES },
@@ -1443,8 +1772,14 @@ static int add_default_attributes(void)
1443 { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_PAGE_FAULTS }, 1772 { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_PAGE_FAULTS },
1444 1773
1445 { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_CPU_CYCLES }, 1774 { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_CPU_CYCLES },
1775};
1776 struct perf_event_attr frontend_attrs[] = {
1446 { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_STALLED_CYCLES_FRONTEND }, 1777 { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_STALLED_CYCLES_FRONTEND },
1778};
1779 struct perf_event_attr backend_attrs[] = {
1447 { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_STALLED_CYCLES_BACKEND }, 1780 { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_STALLED_CYCLES_BACKEND },
1781};
1782 struct perf_event_attr default_attrs1[] = {
1448 { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_INSTRUCTIONS }, 1783 { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_INSTRUCTIONS },
1449 { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_BRANCH_INSTRUCTIONS }, 1784 { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_BRANCH_INSTRUCTIONS },
1450 { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_BRANCH_MISSES }, 1785 { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_BRANCH_MISSES },
@@ -1561,7 +1896,19 @@ static int add_default_attributes(void)
1561 } 1896 }
1562 1897
1563 if (!evsel_list->nr_entries) { 1898 if (!evsel_list->nr_entries) {
1564 if (perf_evlist__add_default_attrs(evsel_list, default_attrs) < 0) 1899 if (perf_evlist__add_default_attrs(evsel_list, default_attrs0) < 0)
1900 return -1;
1901 if (pmu_have_event("cpu", "stalled-cycles-frontend")) {
1902 if (perf_evlist__add_default_attrs(evsel_list,
1903 frontend_attrs) < 0)
1904 return -1;
1905 }
1906 if (pmu_have_event("cpu", "stalled-cycles-backend")) {
1907 if (perf_evlist__add_default_attrs(evsel_list,
1908 backend_attrs) < 0)
1909 return -1;
1910 }
1911 if (perf_evlist__add_default_attrs(evsel_list, default_attrs1) < 0)
1565 return -1; 1912 return -1;
1566 } 1913 }
1567 1914
@@ -1825,9 +2172,11 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
1825 if (evsel_list == NULL) 2172 if (evsel_list == NULL)
1826 return -ENOMEM; 2173 return -ENOMEM;
1827 2174
2175 parse_events__shrink_config_terms();
1828 argc = parse_options_subcommand(argc, argv, stat_options, stat_subcommands, 2176 argc = parse_options_subcommand(argc, argv, stat_options, stat_subcommands,
1829 (const char **) stat_usage, 2177 (const char **) stat_usage,
1830 PARSE_OPT_STOP_AT_NON_OPTION); 2178 PARSE_OPT_STOP_AT_NON_OPTION);
2179 perf_stat__init_shadow_stats();
1831 2180
1832 if (csv_sep) { 2181 if (csv_sep) {
1833 csv_output = true; 2182 csv_output = true;
@@ -1858,6 +2207,16 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
1858 goto out; 2207 goto out;
1859 } 2208 }
1860 2209
2210 if (metric_only && stat_config.aggr_mode == AGGR_THREAD) {
2211 fprintf(stderr, "--metric-only is not supported with --per-thread\n");
2212 goto out;
2213 }
2214
2215 if (metric_only && run_count > 1) {
2216 fprintf(stderr, "--metric-only is not supported with -r\n");
2217 goto out;
2218 }
2219
1861 if (output_fd < 0) { 2220 if (output_fd < 0) {
1862 fprintf(stderr, "argument to --log-fd must be a > 0\n"); 2221 fprintf(stderr, "argument to --log-fd must be a > 0\n");
1863 parse_options_usage(stat_usage, stat_options, "log-fd", 0); 2222 parse_options_usage(stat_usage, stat_options, "log-fd", 0);
diff --git a/tools/perf/builtin-timechart.c b/tools/perf/builtin-timechart.c
index bd7a7757176f..40cc9bb3506c 100644
--- a/tools/perf/builtin-timechart.c
+++ b/tools/perf/builtin-timechart.c
@@ -489,7 +489,7 @@ static const char *cat_backtrace(union perf_event *event,
489 if (!chain) 489 if (!chain)
490 goto exit; 490 goto exit;
491 491
492 if (perf_event__preprocess_sample(event, machine, &al, sample) < 0) { 492 if (machine__resolve(machine, &al, sample) < 0) {
493 fprintf(stderr, "problem processing %d event, skipping it.\n", 493 fprintf(stderr, "problem processing %d event, skipping it.\n",
494 event->header.type); 494 event->header.type);
495 goto exit; 495 goto exit;
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c
index bf01cbb0ef23..833214979c4f 100644
--- a/tools/perf/builtin-top.c
+++ b/tools/perf/builtin-top.c
@@ -67,6 +67,7 @@
67#include <sys/utsname.h> 67#include <sys/utsname.h>
68#include <sys/mman.h> 68#include <sys/mman.h>
69 69
70#include <linux/stringify.h>
70#include <linux/types.h> 71#include <linux/types.h>
71 72
72static volatile int done; 73static volatile int done;
@@ -252,7 +253,8 @@ static void perf_top__print_sym_table(struct perf_top *top)
252 char bf[160]; 253 char bf[160];
253 int printed = 0; 254 int printed = 0;
254 const int win_width = top->winsize.ws_col - 1; 255 const int win_width = top->winsize.ws_col - 1;
255 struct hists *hists = evsel__hists(top->sym_evsel); 256 struct perf_evsel *evsel = top->sym_evsel;
257 struct hists *hists = evsel__hists(evsel);
256 258
257 puts(CONSOLE_CLEAR); 259 puts(CONSOLE_CLEAR);
258 260
@@ -288,7 +290,7 @@ static void perf_top__print_sym_table(struct perf_top *top)
288 } 290 }
289 291
290 hists__collapse_resort(hists, NULL); 292 hists__collapse_resort(hists, NULL);
291 hists__output_resort(hists, NULL); 293 perf_evsel__output_resort(evsel, NULL);
292 294
293 hists__output_recalc_col_len(hists, top->print_entries - printed); 295 hists__output_recalc_col_len(hists, top->print_entries - printed);
294 putchar('\n'); 296 putchar('\n');
@@ -540,6 +542,7 @@ static bool perf_top__handle_keypress(struct perf_top *top, int c)
540static void perf_top__sort_new_samples(void *arg) 542static void perf_top__sort_new_samples(void *arg)
541{ 543{
542 struct perf_top *t = arg; 544 struct perf_top *t = arg;
545 struct perf_evsel *evsel = t->sym_evsel;
543 struct hists *hists; 546 struct hists *hists;
544 547
545 perf_top__reset_sample_counters(t); 548 perf_top__reset_sample_counters(t);
@@ -547,7 +550,7 @@ static void perf_top__sort_new_samples(void *arg)
547 if (t->evlist->selected != NULL) 550 if (t->evlist->selected != NULL)
548 t->sym_evsel = t->evlist->selected; 551 t->sym_evsel = t->evlist->selected;
549 552
550 hists = evsel__hists(t->sym_evsel); 553 hists = evsel__hists(evsel);
551 554
552 if (t->evlist->enabled) { 555 if (t->evlist->enabled) {
553 if (t->zero) { 556 if (t->zero) {
@@ -559,7 +562,7 @@ static void perf_top__sort_new_samples(void *arg)
559 } 562 }
560 563
561 hists__collapse_resort(hists, NULL); 564 hists__collapse_resort(hists, NULL);
562 hists__output_resort(hists, NULL); 565 perf_evsel__output_resort(evsel, NULL);
563} 566}
564 567
565static void *display_thread_tui(void *arg) 568static void *display_thread_tui(void *arg)
@@ -726,7 +729,7 @@ static void perf_event__process_sample(struct perf_tool *tool,
726 if (event->header.misc & PERF_RECORD_MISC_EXACT_IP) 729 if (event->header.misc & PERF_RECORD_MISC_EXACT_IP)
727 top->exact_samples++; 730 top->exact_samples++;
728 731
729 if (perf_event__preprocess_sample(event, machine, &al, sample) < 0) 732 if (machine__resolve(machine, &al, sample) < 0)
730 return; 733 return;
731 734
732 if (!top->kptr_restrict_warned && 735 if (!top->kptr_restrict_warned &&
@@ -807,7 +810,6 @@ static void perf_top__mmap_read_idx(struct perf_top *top, int idx)
807 struct perf_session *session = top->session; 810 struct perf_session *session = top->session;
808 union perf_event *event; 811 union perf_event *event;
809 struct machine *machine; 812 struct machine *machine;
810 u8 origin;
811 int ret; 813 int ret;
812 814
813 while ((event = perf_evlist__mmap_read(top->evlist, idx)) != NULL) { 815 while ((event = perf_evlist__mmap_read(top->evlist, idx)) != NULL) {
@@ -820,12 +822,10 @@ static void perf_top__mmap_read_idx(struct perf_top *top, int idx)
820 evsel = perf_evlist__id2evsel(session->evlist, sample.id); 822 evsel = perf_evlist__id2evsel(session->evlist, sample.id);
821 assert(evsel != NULL); 823 assert(evsel != NULL);
822 824
823 origin = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
824
825 if (event->header.type == PERF_RECORD_SAMPLE) 825 if (event->header.type == PERF_RECORD_SAMPLE)
826 ++top->samples; 826 ++top->samples;
827 827
828 switch (origin) { 828 switch (sample.cpumode) {
829 case PERF_RECORD_MISC_USER: 829 case PERF_RECORD_MISC_USER:
830 ++top->us_samples; 830 ++top->us_samples;
831 if (top->hide_user_symbols) 831 if (top->hide_user_symbols)
@@ -1063,7 +1063,7 @@ parse_callchain_opt(const struct option *opt, const char *arg, int unset)
1063 return parse_callchain_top_opt(arg); 1063 return parse_callchain_top_opt(arg);
1064} 1064}
1065 1065
1066static int perf_top_config(const char *var, const char *value, void *cb) 1066static int perf_top_config(const char *var, const char *value, void *cb __maybe_unused)
1067{ 1067{
1068 if (!strcmp(var, "top.call-graph")) 1068 if (!strcmp(var, "top.call-graph"))
1069 var = "call-graph.record-mode"; /* fall-through */ 1069 var = "call-graph.record-mode"; /* fall-through */
@@ -1072,7 +1072,7 @@ static int perf_top_config(const char *var, const char *value, void *cb)
1072 return 0; 1072 return 0;
1073 } 1073 }
1074 1074
1075 return perf_default_config(var, value, cb); 1075 return 0;
1076} 1076}
1077 1077
1078static int 1078static int
@@ -1212,6 +1212,8 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused)
1212 parse_branch_stack), 1212 parse_branch_stack),
1213 OPT_BOOLEAN(0, "raw-trace", &symbol_conf.raw_trace, 1213 OPT_BOOLEAN(0, "raw-trace", &symbol_conf.raw_trace,
1214 "Show raw trace event output (do not use print fmt or plugins)"), 1214 "Show raw trace event output (do not use print fmt or plugins)"),
1215 OPT_BOOLEAN(0, "hierarchy", &symbol_conf.report_hierarchy,
1216 "Show entries in a hierarchy"),
1215 OPT_END() 1217 OPT_END()
1216 }; 1218 };
1217 const char * const top_usage[] = { 1219 const char * const top_usage[] = {
@@ -1239,10 +1241,30 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused)
1239 goto out_delete_evlist; 1241 goto out_delete_evlist;
1240 } 1242 }
1241 1243
1244 if (symbol_conf.report_hierarchy) {
1245 /* disable incompatible options */
1246 symbol_conf.event_group = false;
1247 symbol_conf.cumulate_callchain = false;
1248
1249 if (field_order) {
1250 pr_err("Error: --hierarchy and --fields options cannot be used together\n");
1251 parse_options_usage(top_usage, options, "fields", 0);
1252 parse_options_usage(NULL, options, "hierarchy", 0);
1253 goto out_delete_evlist;
1254 }
1255 }
1256
1242 sort__mode = SORT_MODE__TOP; 1257 sort__mode = SORT_MODE__TOP;
1243 /* display thread wants entries to be collapsed in a different tree */ 1258 /* display thread wants entries to be collapsed in a different tree */
1244 sort__need_collapse = 1; 1259 sort__need_collapse = 1;
1245 1260
1261 if (top.use_stdio)
1262 use_browser = 0;
1263 else if (top.use_tui)
1264 use_browser = 1;
1265
1266 setup_browser(false);
1267
1246 if (setup_sorting(top.evlist) < 0) { 1268 if (setup_sorting(top.evlist) < 0) {
1247 if (sort_order) 1269 if (sort_order)
1248 parse_options_usage(top_usage, options, "s", 1); 1270 parse_options_usage(top_usage, options, "s", 1);
@@ -1252,13 +1274,6 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused)
1252 goto out_delete_evlist; 1274 goto out_delete_evlist;
1253 } 1275 }
1254 1276
1255 if (top.use_stdio)
1256 use_browser = 0;
1257 else if (top.use_tui)
1258 use_browser = 1;
1259
1260 setup_browser(false);
1261
1262 status = target__validate(target); 1277 status = target__validate(target);
1263 if (status) { 1278 if (status) {
1264 target__strerror(target, status, errbuf, BUFSIZ); 1279 target__strerror(target, status, errbuf, BUFSIZ);
diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c
index 20916dd77aac..93ac724fb635 100644
--- a/tools/perf/builtin-trace.c
+++ b/tools/perf/builtin-trace.c
@@ -33,6 +33,7 @@
33#include "util/stat.h" 33#include "util/stat.h"
34#include "trace-event.h" 34#include "trace-event.h"
35#include "util/parse-events.h" 35#include "util/parse-events.h"
36#include "util/bpf-loader.h"
36 37
37#include <libaudit.h> 38#include <libaudit.h>
38#include <stdlib.h> 39#include <stdlib.h>
@@ -1724,8 +1725,12 @@ static int trace__read_syscall_info(struct trace *trace, int id)
1724 1725
1725 sc->args = sc->tp_format->format.fields; 1726 sc->args = sc->tp_format->format.fields;
1726 sc->nr_args = sc->tp_format->format.nr_fields; 1727 sc->nr_args = sc->tp_format->format.nr_fields;
1727 /* drop nr field - not relevant here; does not exist on older kernels */ 1728 /*
1728 if (sc->args && strcmp(sc->args->name, "nr") == 0) { 1729 * We need to check and discard the first variable '__syscall_nr'
1730 * or 'nr' that mean the syscall number. It is needless here.
1731 * So drop '__syscall_nr' or 'nr' field but does not exist on older kernels.
1732 */
1733 if (sc->args && (!strcmp(sc->args->name, "__syscall_nr") || !strcmp(sc->args->name, "nr"))) {
1729 sc->args = sc->args->next; 1734 sc->args = sc->args->next;
1730 --sc->nr_args; 1735 --sc->nr_args;
1731 } 1736 }
@@ -2177,6 +2182,37 @@ out_dump:
2177 return 0; 2182 return 0;
2178} 2183}
2179 2184
2185static void bpf_output__printer(enum binary_printer_ops op,
2186 unsigned int val, void *extra)
2187{
2188 FILE *output = extra;
2189 unsigned char ch = (unsigned char)val;
2190
2191 switch (op) {
2192 case BINARY_PRINT_CHAR_DATA:
2193 fprintf(output, "%c", isprint(ch) ? ch : '.');
2194 break;
2195 case BINARY_PRINT_DATA_BEGIN:
2196 case BINARY_PRINT_LINE_BEGIN:
2197 case BINARY_PRINT_ADDR:
2198 case BINARY_PRINT_NUM_DATA:
2199 case BINARY_PRINT_NUM_PAD:
2200 case BINARY_PRINT_SEP:
2201 case BINARY_PRINT_CHAR_PAD:
2202 case BINARY_PRINT_LINE_END:
2203 case BINARY_PRINT_DATA_END:
2204 default:
2205 break;
2206 }
2207}
2208
2209static void bpf_output__fprintf(struct trace *trace,
2210 struct perf_sample *sample)
2211{
2212 print_binary(sample->raw_data, sample->raw_size, 8,
2213 bpf_output__printer, trace->output);
2214}
2215
2180static int trace__event_handler(struct trace *trace, struct perf_evsel *evsel, 2216static int trace__event_handler(struct trace *trace, struct perf_evsel *evsel,
2181 union perf_event *event __maybe_unused, 2217 union perf_event *event __maybe_unused,
2182 struct perf_sample *sample) 2218 struct perf_sample *sample)
@@ -2189,7 +2225,9 @@ static int trace__event_handler(struct trace *trace, struct perf_evsel *evsel,
2189 2225
2190 fprintf(trace->output, "%s:", evsel->name); 2226 fprintf(trace->output, "%s:", evsel->name);
2191 2227
2192 if (evsel->tp_format) { 2228 if (perf_evsel__is_bpf_output(evsel)) {
2229 bpf_output__fprintf(trace, sample);
2230 } else if (evsel->tp_format) {
2193 event_format__fprintf(evsel->tp_format, sample->cpu, 2231 event_format__fprintf(evsel->tp_format, sample->cpu,
2194 sample->raw_data, sample->raw_size, 2232 sample->raw_data, sample->raw_size,
2195 trace->output); 2233 trace->output);
@@ -2218,11 +2256,10 @@ static void print_location(FILE *f, struct perf_sample *sample,
2218 2256
2219static int trace__pgfault(struct trace *trace, 2257static int trace__pgfault(struct trace *trace,
2220 struct perf_evsel *evsel, 2258 struct perf_evsel *evsel,
2221 union perf_event *event, 2259 union perf_event *event __maybe_unused,
2222 struct perf_sample *sample) 2260 struct perf_sample *sample)
2223{ 2261{
2224 struct thread *thread; 2262 struct thread *thread;
2225 u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
2226 struct addr_location al; 2263 struct addr_location al;
2227 char map_type = 'd'; 2264 char map_type = 'd';
2228 struct thread_trace *ttrace; 2265 struct thread_trace *ttrace;
@@ -2241,7 +2278,7 @@ static int trace__pgfault(struct trace *trace,
2241 if (trace->summary_only) 2278 if (trace->summary_only)
2242 goto out; 2279 goto out;
2243 2280
2244 thread__find_addr_location(thread, cpumode, MAP__FUNCTION, 2281 thread__find_addr_location(thread, sample->cpumode, MAP__FUNCTION,
2245 sample->ip, &al); 2282 sample->ip, &al);
2246 2283
2247 trace__fprintf_entry_head(trace, thread, 0, sample->time, trace->output); 2284 trace__fprintf_entry_head(trace, thread, 0, sample->time, trace->output);
@@ -2254,11 +2291,11 @@ static int trace__pgfault(struct trace *trace,
2254 2291
2255 fprintf(trace->output, "] => "); 2292 fprintf(trace->output, "] => ");
2256 2293
2257 thread__find_addr_location(thread, cpumode, MAP__VARIABLE, 2294 thread__find_addr_location(thread, sample->cpumode, MAP__VARIABLE,
2258 sample->addr, &al); 2295 sample->addr, &al);
2259 2296
2260 if (!al.map) { 2297 if (!al.map) {
2261 thread__find_addr_location(thread, cpumode, 2298 thread__find_addr_location(thread, sample->cpumode,
2262 MAP__FUNCTION, sample->addr, &al); 2299 MAP__FUNCTION, sample->addr, &al);
2263 2300
2264 if (al.map) 2301 if (al.map)
@@ -2586,6 +2623,16 @@ static int trace__run(struct trace *trace, int argc, const char **argv)
2586 if (err < 0) 2623 if (err < 0)
2587 goto out_error_open; 2624 goto out_error_open;
2588 2625
2626 err = bpf__apply_obj_config();
2627 if (err) {
2628 char errbuf[BUFSIZ];
2629
2630 bpf__strerror_apply_obj_config(err, errbuf, sizeof(errbuf));
2631 pr_err("ERROR: Apply config to BPF failed: %s\n",
2632 errbuf);
2633 goto out_error_open;
2634 }
2635
2589 /* 2636 /*
2590 * Better not use !target__has_task() here because we need to cover the 2637 * Better not use !target__has_task() here because we need to cover the
2591 * case where no threads were specified in the command line, but a 2638 * case where no threads were specified in the command line, but a
diff --git a/tools/perf/builtin.h b/tools/perf/builtin.h
index 3f871b54e261..41c24010ab43 100644
--- a/tools/perf/builtin.h
+++ b/tools/perf/builtin.h
@@ -7,38 +7,38 @@
7extern const char perf_usage_string[]; 7extern const char perf_usage_string[];
8extern const char perf_more_info_string[]; 8extern const char perf_more_info_string[];
9 9
10extern void list_common_cmds_help(void); 10void list_common_cmds_help(void);
11extern const char *help_unknown_cmd(const char *cmd); 11const char *help_unknown_cmd(const char *cmd);
12extern void prune_packed_objects(int); 12void prune_packed_objects(int);
13extern int read_line_with_nul(char *buf, int size, FILE *file); 13int read_line_with_nul(char *buf, int size, FILE *file);
14extern int check_pager_config(const char *cmd); 14int check_pager_config(const char *cmd);
15 15
16extern int cmd_annotate(int argc, const char **argv, const char *prefix); 16int cmd_annotate(int argc, const char **argv, const char *prefix);
17extern int cmd_bench(int argc, const char **argv, const char *prefix); 17int cmd_bench(int argc, const char **argv, const char *prefix);
18extern int cmd_buildid_cache(int argc, const char **argv, const char *prefix); 18int cmd_buildid_cache(int argc, const char **argv, const char *prefix);
19extern int cmd_buildid_list(int argc, const char **argv, const char *prefix); 19int cmd_buildid_list(int argc, const char **argv, const char *prefix);
20extern int cmd_config(int argc, const char **argv, const char *prefix); 20int cmd_config(int argc, const char **argv, const char *prefix);
21extern int cmd_diff(int argc, const char **argv, const char *prefix); 21int cmd_diff(int argc, const char **argv, const char *prefix);
22extern int cmd_evlist(int argc, const char **argv, const char *prefix); 22int cmd_evlist(int argc, const char **argv, const char *prefix);
23extern int cmd_help(int argc, const char **argv, const char *prefix); 23int cmd_help(int argc, const char **argv, const char *prefix);
24extern int cmd_sched(int argc, const char **argv, const char *prefix); 24int cmd_sched(int argc, const char **argv, const char *prefix);
25extern int cmd_list(int argc, const char **argv, const char *prefix); 25int cmd_list(int argc, const char **argv, const char *prefix);
26extern int cmd_record(int argc, const char **argv, const char *prefix); 26int cmd_record(int argc, const char **argv, const char *prefix);
27extern int cmd_report(int argc, const char **argv, const char *prefix); 27int cmd_report(int argc, const char **argv, const char *prefix);
28extern int cmd_stat(int argc, const char **argv, const char *prefix); 28int cmd_stat(int argc, const char **argv, const char *prefix);
29extern int cmd_timechart(int argc, const char **argv, const char *prefix); 29int cmd_timechart(int argc, const char **argv, const char *prefix);
30extern int cmd_top(int argc, const char **argv, const char *prefix); 30int cmd_top(int argc, const char **argv, const char *prefix);
31extern int cmd_script(int argc, const char **argv, const char *prefix); 31int cmd_script(int argc, const char **argv, const char *prefix);
32extern int cmd_version(int argc, const char **argv, const char *prefix); 32int cmd_version(int argc, const char **argv, const char *prefix);
33extern int cmd_probe(int argc, const char **argv, const char *prefix); 33int cmd_probe(int argc, const char **argv, const char *prefix);
34extern int cmd_kmem(int argc, const char **argv, const char *prefix); 34int cmd_kmem(int argc, const char **argv, const char *prefix);
35extern int cmd_lock(int argc, const char **argv, const char *prefix); 35int cmd_lock(int argc, const char **argv, const char *prefix);
36extern int cmd_kvm(int argc, const char **argv, const char *prefix); 36int cmd_kvm(int argc, const char **argv, const char *prefix);
37extern int cmd_test(int argc, const char **argv, const char *prefix); 37int cmd_test(int argc, const char **argv, const char *prefix);
38extern int cmd_trace(int argc, const char **argv, const char *prefix); 38int cmd_trace(int argc, const char **argv, const char *prefix);
39extern int cmd_inject(int argc, const char **argv, const char *prefix); 39int cmd_inject(int argc, const char **argv, const char *prefix);
40extern int cmd_mem(int argc, const char **argv, const char *prefix); 40int cmd_mem(int argc, const char **argv, const char *prefix);
41extern int cmd_data(int argc, const char **argv, const char *prefix); 41int cmd_data(int argc, const char **argv, const char *prefix);
42 42
43extern int find_scripts(char **scripts_array, char **scripts_path_array); 43int find_scripts(char **scripts_array, char **scripts_path_array);
44#endif 44#endif
diff --git a/tools/perf/config/Makefile b/tools/perf/config/Makefile
index 511141b102e8..f7d7f5a1cad5 100644
--- a/tools/perf/config/Makefile
+++ b/tools/perf/config/Makefile
@@ -61,50 +61,45 @@ endif
61 61
62ifeq ($(LIBUNWIND_LIBS),) 62ifeq ($(LIBUNWIND_LIBS),)
63 NO_LIBUNWIND := 1 63 NO_LIBUNWIND := 1
64else
65 #
66 # For linking with debug library, run like:
67 #
68 # make DEBUG=1 LIBUNWIND_DIR=/opt/libunwind/
69 #
70 ifdef LIBUNWIND_DIR
71 LIBUNWIND_CFLAGS = -I$(LIBUNWIND_DIR)/include
72 LIBUNWIND_LDFLAGS = -L$(LIBUNWIND_DIR)/lib
73 endif
74 LIBUNWIND_LDFLAGS += $(LIBUNWIND_LIBS)
75
76 # Set per-feature check compilation flags
77 FEATURE_CHECK_CFLAGS-libunwind = $(LIBUNWIND_CFLAGS)
78 FEATURE_CHECK_LDFLAGS-libunwind = $(LIBUNWIND_LDFLAGS)
79 FEATURE_CHECK_CFLAGS-libunwind-debug-frame = $(LIBUNWIND_CFLAGS)
80 FEATURE_CHECK_LDFLAGS-libunwind-debug-frame = $(LIBUNWIND_LDFLAGS)
81endif 64endif
65#
66# For linking with debug library, run like:
67#
68# make DEBUG=1 LIBUNWIND_DIR=/opt/libunwind/
69#
70ifdef LIBUNWIND_DIR
71 LIBUNWIND_CFLAGS = -I$(LIBUNWIND_DIR)/include
72 LIBUNWIND_LDFLAGS = -L$(LIBUNWIND_DIR)/lib
73endif
74LIBUNWIND_LDFLAGS += $(LIBUNWIND_LIBS)
75
76# Set per-feature check compilation flags
77FEATURE_CHECK_CFLAGS-libunwind = $(LIBUNWIND_CFLAGS)
78FEATURE_CHECK_LDFLAGS-libunwind = $(LIBUNWIND_LDFLAGS)
79FEATURE_CHECK_CFLAGS-libunwind-debug-frame = $(LIBUNWIND_CFLAGS)
80FEATURE_CHECK_LDFLAGS-libunwind-debug-frame = $(LIBUNWIND_LDFLAGS)
82 81
83ifeq ($(NO_PERF_REGS),0) 82ifeq ($(NO_PERF_REGS),0)
84 CFLAGS += -DHAVE_PERF_REGS_SUPPORT 83 CFLAGS += -DHAVE_PERF_REGS_SUPPORT
85endif 84endif
86 85
87ifndef NO_LIBELF 86# for linking with debug library, run like:
88 # for linking with debug library, run like: 87# make DEBUG=1 LIBDW_DIR=/opt/libdw/
89 # make DEBUG=1 LIBDW_DIR=/opt/libdw/ 88ifdef LIBDW_DIR
90 ifdef LIBDW_DIR 89 LIBDW_CFLAGS := -I$(LIBDW_DIR)/include
91 LIBDW_CFLAGS := -I$(LIBDW_DIR)/include 90 LIBDW_LDFLAGS := -L$(LIBDW_DIR)/lib
92 LIBDW_LDFLAGS := -L$(LIBDW_DIR)/lib
93 endif
94 FEATURE_CHECK_CFLAGS-libdw-dwarf-unwind := $(LIBDW_CFLAGS)
95 FEATURE_CHECK_LDFLAGS-libdw-dwarf-unwind := $(LIBDW_LDFLAGS) -ldw
96endif 91endif
92FEATURE_CHECK_CFLAGS-libdw-dwarf-unwind := $(LIBDW_CFLAGS)
93FEATURE_CHECK_LDFLAGS-libdw-dwarf-unwind := $(LIBDW_LDFLAGS) -ldw
97 94
98ifdef LIBBABELTRACE 95# for linking with debug library, run like:
99 # for linking with debug library, run like: 96# make DEBUG=1 LIBBABELTRACE_DIR=/opt/libbabeltrace/
100 # make DEBUG=1 LIBBABELTRACE_DIR=/opt/libbabeltrace/ 97ifdef LIBBABELTRACE_DIR
101 ifdef LIBBABELTRACE_DIR 98 LIBBABELTRACE_CFLAGS := -I$(LIBBABELTRACE_DIR)/include
102 LIBBABELTRACE_CFLAGS := -I$(LIBBABELTRACE_DIR)/include 99 LIBBABELTRACE_LDFLAGS := -L$(LIBBABELTRACE_DIR)/lib
103 LIBBABELTRACE_LDFLAGS := -L$(LIBBABELTRACE_DIR)/lib
104 endif
105 FEATURE_CHECK_CFLAGS-libbabeltrace := $(LIBBABELTRACE_CFLAGS)
106 FEATURE_CHECK_LDFLAGS-libbabeltrace := $(LIBBABELTRACE_LDFLAGS) -lbabeltrace-ctf
107endif 100endif
101FEATURE_CHECK_CFLAGS-libbabeltrace := $(LIBBABELTRACE_CFLAGS)
102FEATURE_CHECK_LDFLAGS-libbabeltrace := $(LIBBABELTRACE_LDFLAGS) -lbabeltrace-ctf
108 103
109FEATURE_CHECK_CFLAGS-bpf = -I. -I$(srctree)/tools/include -I$(srctree)/arch/$(ARCH)/include/uapi -I$(srctree)/include/uapi 104FEATURE_CHECK_CFLAGS-bpf = -I. -I$(srctree)/tools/include -I$(srctree)/arch/$(ARCH)/include/uapi -I$(srctree)/include/uapi
110# include ARCH specific config 105# include ARCH specific config
@@ -114,7 +109,7 @@ ifdef PERF_HAVE_ARCH_REGS_QUERY_REGISTER_OFFSET
114 CFLAGS += -DHAVE_ARCH_REGS_QUERY_REGISTER_OFFSET 109 CFLAGS += -DHAVE_ARCH_REGS_QUERY_REGISTER_OFFSET
115endif 110endif
116 111
117include $(src-perf)/config/utilities.mak 112include $(srctree)/tools/scripts/utilities.mak
118 113
119ifeq ($(call get-executable,$(FLEX)),) 114ifeq ($(call get-executable,$(FLEX)),)
120 dummy := $(error Error: $(FLEX) is missing on this system, please install it) 115 dummy := $(error Error: $(FLEX) is missing on this system, please install it)
@@ -145,28 +140,26 @@ ifdef PARSER_DEBUG
145 $(call detected_var,PARSER_DEBUG_FLEX) 140 $(call detected_var,PARSER_DEBUG_FLEX)
146endif 141endif
147 142
148ifndef NO_LIBPYTHON 143# Try different combinations to accommodate systems that only have
149 # Try different combinations to accommodate systems that only have 144# python[2][-config] in weird combinations but always preferring
150 # python[2][-config] in weird combinations but always preferring 145# python2 and python2-config as per pep-0394. If we catch a
151 # python2 and python2-config as per pep-0394. If we catch a 146# python[-config] in version 3, the version check will kill it.
152 # python[-config] in version 3, the version check will kill it. 147PYTHON2 := $(if $(call get-executable,python2),python2,python)
153 PYTHON2 := $(if $(call get-executable,python2),python2,python) 148override PYTHON := $(call get-executable-or-default,PYTHON,$(PYTHON2))
154 override PYTHON := $(call get-executable-or-default,PYTHON,$(PYTHON2)) 149PYTHON2_CONFIG := \
155 PYTHON2_CONFIG := \ 150 $(if $(call get-executable,$(PYTHON)-config),$(PYTHON)-config,python-config)
156 $(if $(call get-executable,$(PYTHON)-config),$(PYTHON)-config,python-config) 151override PYTHON_CONFIG := \
157 override PYTHON_CONFIG := \ 152 $(call get-executable-or-default,PYTHON_CONFIG,$(PYTHON2_CONFIG))
158 $(call get-executable-or-default,PYTHON_CONFIG,$(PYTHON2_CONFIG))
159 153
160 PYTHON_CONFIG_SQ := $(call shell-sq,$(PYTHON_CONFIG)) 154PYTHON_CONFIG_SQ := $(call shell-sq,$(PYTHON_CONFIG))
161 155
162 PYTHON_EMBED_LDOPTS := $(shell $(PYTHON_CONFIG_SQ) --ldflags 2>/dev/null) 156PYTHON_EMBED_LDOPTS := $(shell $(PYTHON_CONFIG_SQ) --ldflags 2>/dev/null)
163 PYTHON_EMBED_CCOPTS := $(shell $(PYTHON_CONFIG_SQ) --cflags 2>/dev/null) 157PYTHON_EMBED_CCOPTS := $(shell $(PYTHON_CONFIG_SQ) --cflags 2>/dev/null)
164 158
165 FEATURE_CHECK_CFLAGS-libpython := $(PYTHON_EMBED_CCOPTS) 159FEATURE_CHECK_CFLAGS-libpython := $(PYTHON_EMBED_CCOPTS)
166 FEATURE_CHECK_LDFLAGS-libpython := $(PYTHON_EMBED_LDOPTS) 160FEATURE_CHECK_LDFLAGS-libpython := $(PYTHON_EMBED_LDOPTS)
167 FEATURE_CHECK_CFLAGS-libpython-version := $(PYTHON_EMBED_CCOPTS) 161FEATURE_CHECK_CFLAGS-libpython-version := $(PYTHON_EMBED_CCOPTS)
168 FEATURE_CHECK_LDFLAGS-libpython-version := $(PYTHON_EMBED_LDOPTS) 162FEATURE_CHECK_LDFLAGS-libpython-version := $(PYTHON_EMBED_LDOPTS)
169endif
170 163
171CFLAGS += -fno-omit-frame-pointer 164CFLAGS += -fno-omit-frame-pointer
172CFLAGS += -ggdb3 165CFLAGS += -ggdb3
@@ -335,6 +328,13 @@ ifndef NO_LIBELF
335 endif # NO_LIBBPF 328 endif # NO_LIBBPF
336endif # NO_LIBELF 329endif # NO_LIBELF
337 330
331ifdef PERF_HAVE_JITDUMP
332 ifndef NO_DWARF
333 $(call detected,CONFIG_JITDUMP)
334 CFLAGS += -DHAVE_JITDUMP
335 endif
336endif
337
338ifeq ($(ARCH),powerpc) 338ifeq ($(ARCH),powerpc)
339 ifndef NO_DWARF 339 ifndef NO_DWARF
340 CFLAGS += -DHAVE_SKIP_CALLCHAIN_IDX 340 CFLAGS += -DHAVE_SKIP_CALLCHAIN_IDX
@@ -411,6 +411,17 @@ ifndef NO_LIBAUDIT
411 endif 411 endif
412endif 412endif
413 413
414ifndef NO_LIBCRYPTO
415 ifneq ($(feature-libcrypto), 1)
416 msg := $(warning No libcrypto.h found, disables jitted code injection, please install libssl-devel or libssl-dev);
417 NO_LIBCRYPTO := 1
418 else
419 CFLAGS += -DHAVE_LIBCRYPTO_SUPPORT
420 EXTLIBS += -lcrypto
421 $(call detected,CONFIG_CRYPTO)
422 endif
423endif
424
414ifdef NO_NEWT 425ifdef NO_NEWT
415 NO_SLANG=1 426 NO_SLANG=1
416endif 427endif
diff --git a/tools/perf/config/utilities.mak b/tools/perf/config/utilities.mak
deleted file mode 100644
index c16ce833079c..000000000000
--- a/tools/perf/config/utilities.mak
+++ /dev/null
@@ -1,179 +0,0 @@
1# This allows us to work with the newline character:
2define newline
3
4
5endef
6newline := $(newline)
7
8# nl-escape
9#
10# Usage: escape = $(call nl-escape[,escape])
11#
12# This is used as the common way to specify
13# what should replace a newline when escaping
14# newlines; the default is a bizarre string.
15#
16nl-escape = $(if $(1),$(1),m822df3020w6a44id34bt574ctac44eb9f4n)
17
18# escape-nl
19#
20# Usage: escaped-text = $(call escape-nl,text[,escape])
21#
22# GNU make's $(shell ...) function converts to a
23# single space each newline character in the output
24# produced during the expansion; this may not be
25# desirable.
26#
27# The only solution is to change each newline into
28# something that won't be converted, so that the
29# information can be recovered later with
30# $(call unescape-nl...)
31#
32escape-nl = $(subst $(newline),$(call nl-escape,$(2)),$(1))
33
34# unescape-nl
35#
36# Usage: text = $(call unescape-nl,escaped-text[,escape])
37#
38# See escape-nl.
39#
40unescape-nl = $(subst $(call nl-escape,$(2)),$(newline),$(1))
41
42# shell-escape-nl
43#
44# Usage: $(shell some-command | $(call shell-escape-nl[,escape]))
45#
46# Use this to escape newlines from within a shell call;
47# the default escape is a bizarre string.
48#
49# NOTE: The escape is used directly as a string constant
50# in an `awk' program that is delimited by shell
51# single-quotes, so be wary of the characters
52# that are chosen.
53#
54define shell-escape-nl
55awk 'NR==1 {t=$$0} NR>1 {t=t "$(nl-escape)" $$0} END {printf t}'
56endef
57
58# shell-unescape-nl
59#
60# Usage: $(shell some-command | $(call shell-unescape-nl[,escape]))
61#
62# Use this to unescape newlines from within a shell call;
63# the default escape is a bizarre string.
64#
65# NOTE: The escape is used directly as an extended regular
66# expression constant in an `awk' program that is
67# delimited by shell single-quotes, so be wary
68# of the characters that are chosen.
69#
70# (The bash shell has a bug where `{gsub(...),...}' is
71# misinterpreted as a brace expansion; this can be
72# overcome by putting a space between `{' and `gsub').
73#
74define shell-unescape-nl
75awk 'NR==1 {t=$$0} NR>1 {t=t "\n" $$0} END { gsub(/$(nl-escape)/,"\n",t); printf t }'
76endef
77
78# escape-for-shell-sq
79#
80# Usage: embeddable-text = $(call escape-for-shell-sq,text)
81#
82# This function produces text that is suitable for
83# embedding in a shell string that is delimited by
84# single-quotes.
85#
86escape-for-shell-sq = $(subst ','\'',$(1))
87
88# shell-sq
89#
90# Usage: single-quoted-and-escaped-text = $(call shell-sq,text)
91#
92shell-sq = '$(escape-for-shell-sq)'
93
94# shell-wordify
95#
96# Usage: wordified-text = $(call shell-wordify,text)
97#
98# For instance:
99#
100# |define text
101# |hello
102# |world
103# |endef
104# |
105# |target:
106# | echo $(call shell-wordify,$(text))
107#
108# At least GNU make gets confused by expanding a newline
109# within the context of a command line of a makefile rule
110# (this is in constrast to a `$(shell ...)' function call,
111# which can handle it just fine).
112#
113# This function avoids the problem by producing a string
114# that works as a shell word, regardless of whether or
115# not it contains a newline.
116#
117# If the text to be wordified contains a newline, then
118# an intrictate shell command substitution is constructed
119# to render the text as a single line; when the shell
120# processes the resulting escaped text, it transforms
121# it into the original unescaped text.
122#
123# If the text does not contain a newline, then this function
124# produces the same results as the `$(shell-sq)' function.
125#
126shell-wordify = $(if $(findstring $(newline),$(1)),$(_sw-esc-nl),$(shell-sq))
127define _sw-esc-nl
128"$$(echo $(call escape-nl,$(shell-sq),$(2)) | $(call shell-unescape-nl,$(2)))"
129endef
130
131# is-absolute
132#
133# Usage: bool-value = $(call is-absolute,path)
134#
135is-absolute = $(shell echo $(shell-sq) | grep -q ^/ && echo y)
136
137# lookup
138#
139# Usage: absolute-executable-path-or-empty = $(call lookup,path)
140#
141# (It's necessary to use `sh -c' because GNU make messes up by
142# trying too hard and getting things wrong).
143#
144lookup = $(call unescape-nl,$(shell sh -c $(_l-sh)))
145_l-sh = $(call shell-sq,command -v $(shell-sq) | $(call shell-escape-nl,))
146
147# is-executable
148#
149# Usage: bool-value = $(call is-executable,path)
150#
151# (It's necessary to use `sh -c' because GNU make messes up by
152# trying too hard and getting things wrong).
153#
154is-executable = $(call _is-executable-helper,$(shell-sq))
155_is-executable-helper = $(shell sh -c $(_is-executable-sh))
156_is-executable-sh = $(call shell-sq,test -f $(1) -a -x $(1) && echo y)
157
158# get-executable
159#
160# Usage: absolute-executable-path-or-empty = $(call get-executable,path)
161#
162# The goal is to get an absolute path for an executable;
163# the `command -v' is defined by POSIX, but it's not
164# necessarily very portable, so it's only used if
165# relative path resolution is requested, as determined
166# by the presence of a leading `/'.
167#
168get-executable = $(if $(1),$(if $(is-absolute),$(_ge-abspath),$(lookup)))
169_ge-abspath = $(if $(is-executable),$(1))
170
171# get-supplied-or-default-executable
172#
173# Usage: absolute-executable-path-or-empty = $(call get-executable-or-default,variable,default)
174#
175define get-executable-or-default
176$(if $($(1)),$(call _ge_attempt,$($(1)),$(1)),$(call _ge_attempt,$(2)))
177endef
178_ge_attempt = $(if $(get-executable),$(get-executable),$(call _gea_err,$(2)))
179_gea_err = $(if $(1),$(error Please set '$(1)' appropriately))
diff --git a/tools/perf/jvmti/Makefile b/tools/perf/jvmti/Makefile
new file mode 100644
index 000000000000..5ce61a1bda9c
--- /dev/null
+++ b/tools/perf/jvmti/Makefile
@@ -0,0 +1,89 @@
1ARCH=$(shell uname -m)
2
3ifeq ($(ARCH), x86_64)
4JARCH=amd64
5endif
6ifeq ($(ARCH), armv7l)
7JARCH=armhf
8endif
9ifeq ($(ARCH), armv6l)
10JARCH=armhf
11endif
12ifeq ($(ARCH), aarch64)
13JARCH=aarch64
14endif
15ifeq ($(ARCH), ppc64)
16JARCH=powerpc
17endif
18ifeq ($(ARCH), ppc64le)
19JARCH=powerpc
20endif
21
22DESTDIR=/usr/local
23
24VERSION=1
25REVISION=0
26AGE=0
27
28LN=ln -sf
29RM=rm
30
31SLIBJVMTI=libjvmti.so.$(VERSION).$(REVISION).$(AGE)
32VLIBJVMTI=libjvmti.so.$(VERSION)
33SLDFLAGS=-shared -Wl,-soname -Wl,$(VLIBJVMTI)
34SOLIBEXT=so
35
36# The following works at least on fedora 23, you may need the next
37# line for other distros.
38ifneq (,$(wildcard /usr/sbin/update-java-alternatives))
39JDIR=$(shell /usr/sbin/update-java-alternatives -l | head -1 | cut -d ' ' -f 3)
40else
41 ifneq (,$(wildcard /usr/sbin/alternatives))
42 JDIR=$(shell alternatives --display java | tail -1 | cut -d' ' -f 5 | sed 's%/jre/bin/java.%%g')
43 endif
44endif
45ifndef JDIR
46$(error Could not find alternatives command, you need to set JDIR= to point to the root of your Java directory)
47else
48 ifeq (,$(wildcard $(JDIR)/include/jvmti.h))
49 $(error the openjdk development package appears to me missing, install and try again)
50 endif
51endif
52$(info Using Java from $(JDIR))
53# -lrt required in 32-bit mode for clock_gettime()
54LIBS=-lelf -lrt
55INCDIR=-I $(JDIR)/include -I $(JDIR)/include/linux
56
57TARGETS=$(SLIBJVMTI)
58
59SRCS=libjvmti.c jvmti_agent.c
60OBJS=$(SRCS:.c=.o)
61SOBJS=$(OBJS:.o=.lo)
62OPT=-O2 -g -Werror -Wall
63
64CFLAGS=$(INCDIR) $(OPT)
65
66all: $(TARGETS)
67
68.c.o:
69 $(CC) $(CFLAGS) -c $*.c
70.c.lo:
71 $(CC) -fPIC -DPIC $(CFLAGS) -c $*.c -o $*.lo
72
73$(OBJS) $(SOBJS): Makefile jvmti_agent.h ../util/jitdump.h
74
75$(SLIBJVMTI): $(SOBJS)
76 $(CC) $(CFLAGS) $(SLDFLAGS) -o $@ $(SOBJS) $(LIBS)
77 $(LN) $@ libjvmti.$(SOLIBEXT)
78
79clean:
80 $(RM) -f *.o *.so.* *.so *.lo
81
82install:
83 -mkdir -p $(DESTDIR)/lib
84 install -m 755 $(SLIBJVMTI) $(DESTDIR)/lib/
85 (cd $(DESTDIR)/lib; $(LN) $(SLIBJVMTI) $(VLIBJVMTI))
86 (cd $(DESTDIR)/lib; $(LN) $(SLIBJVMTI) libjvmti.$(SOLIBEXT))
87 ldconfig
88
89.SUFFIXES: .c .S .o .lo
diff --git a/tools/perf/jvmti/jvmti_agent.c b/tools/perf/jvmti/jvmti_agent.c
new file mode 100644
index 000000000000..6461e02ab940
--- /dev/null
+++ b/tools/perf/jvmti/jvmti_agent.c
@@ -0,0 +1,465 @@
1/*
2 * jvmti_agent.c: JVMTI agent interface
3 *
4 * Adapted from the Oprofile code in opagent.c:
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 *
19 * Copyright 2007 OProfile authors
20 * Jens Wilke
21 * Daniel Hansel
22 * Copyright IBM Corporation 2007
23 */
24#include <sys/types.h>
25#include <sys/stat.h> /* for mkdir() */
26#include <stdio.h>
27#include <errno.h>
28#include <string.h>
29#include <stdlib.h>
30#include <stdint.h>
31#include <limits.h>
32#include <fcntl.h>
33#include <unistd.h>
34#include <time.h>
35#include <sys/mman.h>
36#include <syscall.h> /* for gettid() */
37#include <err.h>
38
39#include "jvmti_agent.h"
40#include "../util/jitdump.h"
41
42#define JIT_LANG "java"
43
44static char jit_path[PATH_MAX];
45static void *marker_addr;
46
47/*
48 * padding buffer
49 */
50static const char pad_bytes[7];
51
52static inline pid_t gettid(void)
53{
54 return (pid_t)syscall(__NR_gettid);
55}
56
57static int get_e_machine(struct jitheader *hdr)
58{
59 ssize_t sret;
60 char id[16];
61 int fd, ret = -1;
62 int m = -1;
63 struct {
64 uint16_t e_type;
65 uint16_t e_machine;
66 } info;
67
68 fd = open("/proc/self/exe", O_RDONLY);
69 if (fd == -1)
70 return -1;
71
72 sret = read(fd, id, sizeof(id));
73 if (sret != sizeof(id))
74 goto error;
75
76 /* check ELF signature */
77 if (id[0] != 0x7f || id[1] != 'E' || id[2] != 'L' || id[3] != 'F')
78 goto error;
79
80 sret = read(fd, &info, sizeof(info));
81 if (sret != sizeof(info))
82 goto error;
83
84 m = info.e_machine;
85 if (m < 0)
86 m = 0; /* ELF EM_NONE */
87
88 hdr->elf_mach = m;
89 ret = 0;
90error:
91 close(fd);
92 return ret;
93}
94
95#define NSEC_PER_SEC 1000000000
96static int perf_clk_id = CLOCK_MONOTONIC;
97
98static inline uint64_t
99timespec_to_ns(const struct timespec *ts)
100{
101 return ((uint64_t) ts->tv_sec * NSEC_PER_SEC) + ts->tv_nsec;
102}
103
104static inline uint64_t
105perf_get_timestamp(void)
106{
107 struct timespec ts;
108 int ret;
109
110 ret = clock_gettime(perf_clk_id, &ts);
111 if (ret)
112 return 0;
113
114 return timespec_to_ns(&ts);
115}
116
117static int
118debug_cache_init(void)
119{
120 char str[32];
121 char *base, *p;
122 struct tm tm;
123 time_t t;
124 int ret;
125
126 time(&t);
127 localtime_r(&t, &tm);
128
129 base = getenv("JITDUMPDIR");
130 if (!base)
131 base = getenv("HOME");
132 if (!base)
133 base = ".";
134
135 strftime(str, sizeof(str), JIT_LANG"-jit-%Y%m%d", &tm);
136
137 snprintf(jit_path, PATH_MAX - 1, "%s/.debug/", base);
138
139 ret = mkdir(jit_path, 0755);
140 if (ret == -1) {
141 if (errno != EEXIST) {
142 warn("jvmti: cannot create jit cache dir %s", jit_path);
143 return -1;
144 }
145 }
146
147 snprintf(jit_path, PATH_MAX - 1, "%s/.debug/jit", base);
148 ret = mkdir(jit_path, 0755);
149 if (ret == -1) {
150 if (errno != EEXIST) {
151 warn("cannot create jit cache dir %s", jit_path);
152 return -1;
153 }
154 }
155
156 snprintf(jit_path, PATH_MAX - 1, "%s/.debug/jit/%s.XXXXXXXX", base, str);
157
158 p = mkdtemp(jit_path);
159 if (p != jit_path) {
160 warn("cannot create jit cache dir %s", jit_path);
161 return -1;
162 }
163
164 return 0;
165}
166
167static int
168perf_open_marker_file(int fd)
169{
170 long pgsz;
171
172 pgsz = sysconf(_SC_PAGESIZE);
173 if (pgsz == -1)
174 return -1;
175
176 /*
177 * we mmap the jitdump to create an MMAP RECORD in perf.data file.
178 * The mmap is captured either live (perf record running when we mmap)
179 * or in deferred mode, via /proc/PID/maps
180 * the MMAP record is used as a marker of a jitdump file for more meta
181 * data info about the jitted code. Perf report/annotate detect this
182 * special filename and process the jitdump file.
183 *
184 * mapping must be PROT_EXEC to ensure it is captured by perf record
185 * even when not using -d option
186 */
187 marker_addr = mmap(NULL, pgsz, PROT_READ|PROT_EXEC, MAP_PRIVATE, fd, 0);
188 return (marker_addr == MAP_FAILED) ? -1 : 0;
189}
190
191static void
192perf_close_marker_file(void)
193{
194 long pgsz;
195
196 if (!marker_addr)
197 return;
198
199 pgsz = sysconf(_SC_PAGESIZE);
200 if (pgsz == -1)
201 return;
202
203 munmap(marker_addr, pgsz);
204}
205
206void *jvmti_open(void)
207{
208 int pad_cnt;
209 char dump_path[PATH_MAX];
210 struct jitheader header;
211 int fd;
212 FILE *fp;
213
214 /*
215 * check if clockid is supported
216 */
217 if (!perf_get_timestamp())
218 warnx("jvmti: kernel does not support %d clock id", perf_clk_id);
219
220 memset(&header, 0, sizeof(header));
221
222 debug_cache_init();
223
224 /*
225 * jitdump file name
226 */
227 snprintf(dump_path, PATH_MAX, "%s/jit-%i.dump", jit_path, getpid());
228
229 fd = open(dump_path, O_CREAT|O_TRUNC|O_RDWR, 0666);
230 if (fd == -1)
231 return NULL;
232
233 /*
234 * create perf.data maker for the jitdump file
235 */
236 if (perf_open_marker_file(fd)) {
237 warnx("jvmti: failed to create marker file");
238 return NULL;
239 }
240
241 fp = fdopen(fd, "w+");
242 if (!fp) {
243 warn("jvmti: cannot create %s", dump_path);
244 close(fd);
245 goto error;
246 }
247
248 warnx("jvmti: jitdump in %s", dump_path);
249
250 if (get_e_machine(&header)) {
251 warn("get_e_machine failed\n");
252 goto error;
253 }
254
255 header.magic = JITHEADER_MAGIC;
256 header.version = JITHEADER_VERSION;
257 header.total_size = sizeof(header);
258 header.pid = getpid();
259
260 /* calculate amount of padding '\0' */
261 pad_cnt = PADDING_8ALIGNED(header.total_size);
262 header.total_size += pad_cnt;
263
264 header.timestamp = perf_get_timestamp();
265
266 if (!fwrite(&header, sizeof(header), 1, fp)) {
267 warn("jvmti: cannot write dumpfile header");
268 goto error;
269 }
270
271 /* write padding '\0' if necessary */
272 if (pad_cnt && !fwrite(pad_bytes, pad_cnt, 1, fp)) {
273 warn("jvmti: cannot write dumpfile header padding");
274 goto error;
275 }
276
277 return fp;
278error:
279 fclose(fp);
280 return NULL;
281}
282
283int
284jvmti_close(void *agent)
285{
286 struct jr_code_close rec;
287 FILE *fp = agent;
288
289 if (!fp) {
290 warnx("jvmti: incalid fd in close_agent");
291 return -1;
292 }
293
294 rec.p.id = JIT_CODE_CLOSE;
295 rec.p.total_size = sizeof(rec);
296
297 rec.p.timestamp = perf_get_timestamp();
298
299 if (!fwrite(&rec, sizeof(rec), 1, fp))
300 return -1;
301
302 fclose(fp);
303
304 fp = NULL;
305
306 perf_close_marker_file();
307
308 return 0;
309}
310
311int
312jvmti_write_code(void *agent, char const *sym,
313 uint64_t vma, void const *code, unsigned int const size)
314{
315 static int code_generation = 1;
316 struct jr_code_load rec;
317 size_t sym_len;
318 size_t padding_count;
319 FILE *fp = agent;
320 int ret = -1;
321
322 /* don't care about 0 length function, no samples */
323 if (size == 0)
324 return 0;
325
326 if (!fp) {
327 warnx("jvmti: invalid fd in write_native_code");
328 return -1;
329 }
330
331 sym_len = strlen(sym) + 1;
332
333 rec.p.id = JIT_CODE_LOAD;
334 rec.p.total_size = sizeof(rec) + sym_len;
335 padding_count = PADDING_8ALIGNED(rec.p.total_size);
336 rec.p. total_size += padding_count;
337 rec.p.timestamp = perf_get_timestamp();
338
339 rec.code_size = size;
340 rec.vma = vma;
341 rec.code_addr = vma;
342 rec.pid = getpid();
343 rec.tid = gettid();
344
345 if (code)
346 rec.p.total_size += size;
347
348 /*
349 * If JVM is multi-threaded, nultiple concurrent calls to agent
350 * may be possible, so protect file writes
351 */
352 flockfile(fp);
353
354 /*
355 * get code index inside lock to avoid race condition
356 */
357 rec.code_index = code_generation++;
358
359 ret = fwrite_unlocked(&rec, sizeof(rec), 1, fp);
360 fwrite_unlocked(sym, sym_len, 1, fp);
361
362 if (padding_count)
363 fwrite_unlocked(pad_bytes, padding_count, 1, fp);
364
365 if (code)
366 fwrite_unlocked(code, size, 1, fp);
367
368 funlockfile(fp);
369
370 ret = 0;
371
372 return ret;
373}
374
375int
376jvmti_write_debug_info(void *agent, uint64_t code, const char *file,
377 jvmti_line_info_t *li, int nr_lines)
378{
379 struct jr_code_debug_info rec;
380 size_t sret, len, size, flen;
381 size_t padding_count;
382 uint64_t addr;
383 const char *fn = file;
384 FILE *fp = agent;
385 int i;
386
387 /*
388 * no entry to write
389 */
390 if (!nr_lines)
391 return 0;
392
393 if (!fp) {
394 warnx("jvmti: invalid fd in write_debug_info");
395 return -1;
396 }
397
398 flen = strlen(file) + 1;
399
400 rec.p.id = JIT_CODE_DEBUG_INFO;
401 size = sizeof(rec);
402 rec.p.timestamp = perf_get_timestamp();
403 rec.code_addr = (uint64_t)(uintptr_t)code;
404 rec.nr_entry = nr_lines;
405
406 /*
407 * on disk source line info layout:
408 * uint64_t : addr
409 * int : line number
410 * int : column discriminator
411 * file[] : source file name
412 * padding : pad to multiple of 8 bytes
413 */
414 size += nr_lines * sizeof(struct debug_entry);
415 size += flen * nr_lines;
416 /*
417 * pad to 8 bytes
418 */
419 padding_count = PADDING_8ALIGNED(size);
420
421 rec.p.total_size = size + padding_count;
422
423 /*
424 * If JVM is multi-threaded, nultiple concurrent calls to agent
425 * may be possible, so protect file writes
426 */
427 flockfile(fp);
428
429 sret = fwrite_unlocked(&rec, sizeof(rec), 1, fp);
430 if (sret != 1)
431 goto error;
432
433 for (i = 0; i < nr_lines; i++) {
434
435 addr = (uint64_t)li[i].pc;
436 len = sizeof(addr);
437 sret = fwrite_unlocked(&addr, len, 1, fp);
438 if (sret != 1)
439 goto error;
440
441 len = sizeof(li[0].line_number);
442 sret = fwrite_unlocked(&li[i].line_number, len, 1, fp);
443 if (sret != 1)
444 goto error;
445
446 len = sizeof(li[0].discrim);
447 sret = fwrite_unlocked(&li[i].discrim, len, 1, fp);
448 if (sret != 1)
449 goto error;
450
451 sret = fwrite_unlocked(fn, flen, 1, fp);
452 if (sret != 1)
453 goto error;
454 }
455 if (padding_count)
456 sret = fwrite_unlocked(pad_bytes, padding_count, 1, fp);
457 if (sret != 1)
458 goto error;
459
460 funlockfile(fp);
461 return 0;
462error:
463 funlockfile(fp);
464 return -1;
465}
diff --git a/tools/perf/jvmti/jvmti_agent.h b/tools/perf/jvmti/jvmti_agent.h
new file mode 100644
index 000000000000..bedf5d0ba9ff
--- /dev/null
+++ b/tools/perf/jvmti/jvmti_agent.h
@@ -0,0 +1,36 @@
1#ifndef __JVMTI_AGENT_H__
2#define __JVMTI_AGENT_H__
3
4#include <sys/types.h>
5#include <stdint.h>
6#include <jvmti.h>
7
8#define __unused __attribute__((unused))
9
10#if defined(__cplusplus)
11extern "C" {
12#endif
13
14typedef struct {
15 unsigned long pc;
16 int line_number;
17 int discrim; /* discriminator -- 0 for now */
18} jvmti_line_info_t;
19
20void *jvmti_open(void);
21int jvmti_close(void *agent);
22int jvmti_write_code(void *agent, char const *symbol_name,
23 uint64_t vma, void const *code,
24 const unsigned int code_size);
25
26int jvmti_write_debug_info(void *agent,
27 uint64_t code,
28 const char *file,
29 jvmti_line_info_t *li,
30 int nr_lines);
31
32#if defined(__cplusplus)
33}
34
35#endif
36#endif /* __JVMTI_H__ */
diff --git a/tools/perf/jvmti/libjvmti.c b/tools/perf/jvmti/libjvmti.c
new file mode 100644
index 000000000000..ac12e4b91a92
--- /dev/null
+++ b/tools/perf/jvmti/libjvmti.c
@@ -0,0 +1,304 @@
1#include <sys/types.h>
2#include <stdio.h>
3#include <string.h>
4#include <stdlib.h>
5#include <err.h>
6#include <jvmti.h>
7#include <jvmticmlr.h>
8#include <limits.h>
9
10#include "jvmti_agent.h"
11
12static int has_line_numbers;
13void *jvmti_agent;
14
15static jvmtiError
16do_get_line_numbers(jvmtiEnv *jvmti, void *pc, jmethodID m, jint bci,
17 jvmti_line_info_t *tab, jint *nr)
18{
19 jint i, lines = 0;
20 jint nr_lines = 0;
21 jvmtiLineNumberEntry *loc_tab = NULL;
22 jvmtiError ret;
23
24 ret = (*jvmti)->GetLineNumberTable(jvmti, m, &nr_lines, &loc_tab);
25 if (ret != JVMTI_ERROR_NONE)
26 return ret;
27
28 for (i = 0; i < nr_lines; i++) {
29 if (loc_tab[i].start_location < bci) {
30 tab[lines].pc = (unsigned long)pc;
31 tab[lines].line_number = loc_tab[i].line_number;
32 tab[lines].discrim = 0; /* not yet used */
33 lines++;
34 } else {
35 break;
36 }
37 }
38 (*jvmti)->Deallocate(jvmti, (unsigned char *)loc_tab);
39 *nr = lines;
40 return JVMTI_ERROR_NONE;
41}
42
43static jvmtiError
44get_line_numbers(jvmtiEnv *jvmti, const void *compile_info, jvmti_line_info_t **tab, int *nr_lines)
45{
46 const jvmtiCompiledMethodLoadRecordHeader *hdr;
47 jvmtiCompiledMethodLoadInlineRecord *rec;
48 jvmtiLineNumberEntry *lne = NULL;
49 PCStackInfo *c;
50 jint nr, ret;
51 int nr_total = 0;
52 int i, lines_total = 0;
53
54 if (!(tab && nr_lines))
55 return JVMTI_ERROR_NULL_POINTER;
56
57 /*
58 * Phase 1 -- get the number of lines necessary
59 */
60 for (hdr = compile_info; hdr != NULL; hdr = hdr->next) {
61 if (hdr->kind == JVMTI_CMLR_INLINE_INFO) {
62 rec = (jvmtiCompiledMethodLoadInlineRecord *)hdr;
63 for (i = 0; i < rec->numpcs; i++) {
64 c = rec->pcinfo + i;
65 nr = 0;
66 /*
67 * unfortunately, need a tab to get the number of lines!
68 */
69 ret = (*jvmti)->GetLineNumberTable(jvmti, c->methods[0], &nr, &lne);
70 if (ret == JVMTI_ERROR_NONE) {
71 /* free what was allocated for nothing */
72 (*jvmti)->Deallocate(jvmti, (unsigned char *)lne);
73 nr_total += (int)nr;
74 }
75 }
76 }
77 }
78
79 if (nr_total == 0)
80 return JVMTI_ERROR_NOT_FOUND;
81
82 /*
83 * Phase 2 -- allocate big enough line table
84 */
85 *tab = malloc(nr_total * sizeof(**tab));
86 if (!*tab)
87 return JVMTI_ERROR_OUT_OF_MEMORY;
88
89 for (hdr = compile_info; hdr != NULL; hdr = hdr->next) {
90 if (hdr->kind == JVMTI_CMLR_INLINE_INFO) {
91 rec = (jvmtiCompiledMethodLoadInlineRecord *)hdr;
92 for (i = 0; i < rec->numpcs; i++) {
93 c = rec->pcinfo + i;
94 nr = 0;
95 ret = do_get_line_numbers(jvmti, c->pc,
96 c->methods[0],
97 c->bcis[0],
98 *tab + lines_total,
99 &nr);
100 if (ret == JVMTI_ERROR_NONE)
101 lines_total += nr;
102 }
103 }
104 }
105 *nr_lines = lines_total;
106 return JVMTI_ERROR_NONE;
107}
108
109static void JNICALL
110compiled_method_load_cb(jvmtiEnv *jvmti,
111 jmethodID method,
112 jint code_size,
113 void const *code_addr,
114 jint map_length,
115 jvmtiAddrLocationMap const *map,
116 const void *compile_info)
117{
118 jvmti_line_info_t *line_tab = NULL;
119 jclass decl_class;
120 char *class_sign = NULL;
121 char *func_name = NULL;
122 char *func_sign = NULL;
123 char *file_name= NULL;
124 char fn[PATH_MAX];
125 uint64_t addr = (uint64_t)(uintptr_t)code_addr;
126 jvmtiError ret;
127 int nr_lines = 0; /* in line_tab[] */
128 size_t len;
129
130 ret = (*jvmti)->GetMethodDeclaringClass(jvmti, method,
131 &decl_class);
132 if (ret != JVMTI_ERROR_NONE) {
133 warnx("jvmti: cannot get declaring class");
134 return;
135 }
136
137 if (has_line_numbers && map && map_length) {
138 ret = get_line_numbers(jvmti, compile_info, &line_tab, &nr_lines);
139 if (ret != JVMTI_ERROR_NONE) {
140 warnx("jvmti: cannot get line table for method");
141 nr_lines = 0;
142 }
143 }
144
145 ret = (*jvmti)->GetSourceFileName(jvmti, decl_class, &file_name);
146 if (ret != JVMTI_ERROR_NONE) {
147 warnx("jvmti: cannot get source filename ret=%d", ret);
148 goto error;
149 }
150
151 ret = (*jvmti)->GetClassSignature(jvmti, decl_class,
152 &class_sign, NULL);
153 if (ret != JVMTI_ERROR_NONE) {
154 warnx("jvmti: getclassignature failed");
155 goto error;
156 }
157
158 ret = (*jvmti)->GetMethodName(jvmti, method, &func_name,
159 &func_sign, NULL);
160 if (ret != JVMTI_ERROR_NONE) {
161 warnx("jvmti: failed getmethodname");
162 goto error;
163 }
164
165 /*
166 * Assume path name is class hierarchy, this is a common practice with Java programs
167 */
168 if (*class_sign == 'L') {
169 int j, i = 0;
170 char *p = strrchr(class_sign, '/');
171 if (p) {
172 /* drop the 'L' prefix and copy up to the final '/' */
173 for (i = 0; i < (p - class_sign); i++)
174 fn[i] = class_sign[i+1];
175 }
176 /*
177 * append file name, we use loops and not string ops to avoid modifying
178 * class_sign which is used later for the symbol name
179 */
180 for (j = 0; i < (PATH_MAX - 1) && file_name && j < strlen(file_name); j++, i++)
181 fn[i] = file_name[j];
182 fn[i] = '\0';
183 } else {
184 /* fallback case */
185 strcpy(fn, file_name);
186 }
187 /*
188 * write source line info record if we have it
189 */
190 if (jvmti_write_debug_info(jvmti_agent, addr, fn, line_tab, nr_lines))
191 warnx("jvmti: write_debug_info() failed");
192
193 len = strlen(func_name) + strlen(class_sign) + strlen(func_sign) + 2;
194 {
195 char str[len];
196 snprintf(str, len, "%s%s%s", class_sign, func_name, func_sign);
197
198 if (jvmti_write_code(jvmti_agent, str, addr, code_addr, code_size))
199 warnx("jvmti: write_code() failed");
200 }
201error:
202 (*jvmti)->Deallocate(jvmti, (unsigned char *)func_name);
203 (*jvmti)->Deallocate(jvmti, (unsigned char *)func_sign);
204 (*jvmti)->Deallocate(jvmti, (unsigned char *)class_sign);
205 (*jvmti)->Deallocate(jvmti, (unsigned char *)file_name);
206 free(line_tab);
207}
208
209static void JNICALL
210code_generated_cb(jvmtiEnv *jvmti,
211 char const *name,
212 void const *code_addr,
213 jint code_size)
214{
215 uint64_t addr = (uint64_t)(unsigned long)code_addr;
216 int ret;
217
218 ret = jvmti_write_code(jvmti_agent, name, addr, code_addr, code_size);
219 if (ret)
220 warnx("jvmti: write_code() failed for code_generated");
221}
222
223JNIEXPORT jint JNICALL
224Agent_OnLoad(JavaVM *jvm, char *options, void *reserved __unused)
225{
226 jvmtiEventCallbacks cb;
227 jvmtiCapabilities caps1;
228 jvmtiJlocationFormat format;
229 jvmtiEnv *jvmti = NULL;
230 jint ret;
231
232 jvmti_agent = jvmti_open();
233 if (!jvmti_agent) {
234 warnx("jvmti: open_agent failed");
235 return -1;
236 }
237
238 /*
239 * Request a JVMTI interface version 1 environment
240 */
241 ret = (*jvm)->GetEnv(jvm, (void *)&jvmti, JVMTI_VERSION_1);
242 if (ret != JNI_OK) {
243 warnx("jvmti: jvmti version 1 not supported");
244 return -1;
245 }
246
247 /*
248 * acquire method_load capability, we require it
249 * request line numbers (optional)
250 */
251 memset(&caps1, 0, sizeof(caps1));
252 caps1.can_generate_compiled_method_load_events = 1;
253
254 ret = (*jvmti)->AddCapabilities(jvmti, &caps1);
255 if (ret != JVMTI_ERROR_NONE) {
256 warnx("jvmti: acquire compiled_method capability failed");
257 return -1;
258 }
259 ret = (*jvmti)->GetJLocationFormat(jvmti, &format);
260 if (ret == JVMTI_ERROR_NONE && format == JVMTI_JLOCATION_JVMBCI) {
261 memset(&caps1, 0, sizeof(caps1));
262 caps1.can_get_line_numbers = 1;
263 caps1.can_get_source_file_name = 1;
264 ret = (*jvmti)->AddCapabilities(jvmti, &caps1);
265 if (ret == JVMTI_ERROR_NONE)
266 has_line_numbers = 1;
267 }
268
269 memset(&cb, 0, sizeof(cb));
270
271 cb.CompiledMethodLoad = compiled_method_load_cb;
272 cb.DynamicCodeGenerated = code_generated_cb;
273
274 ret = (*jvmti)->SetEventCallbacks(jvmti, &cb, sizeof(cb));
275 if (ret != JVMTI_ERROR_NONE) {
276 warnx("jvmti: cannot set event callbacks");
277 return -1;
278 }
279
280 ret = (*jvmti)->SetEventNotificationMode(jvmti, JVMTI_ENABLE,
281 JVMTI_EVENT_COMPILED_METHOD_LOAD, NULL);
282 if (ret != JVMTI_ERROR_NONE) {
283 warnx("jvmti: setnotification failed for method_load");
284 return -1;
285 }
286
287 ret = (*jvmti)->SetEventNotificationMode(jvmti, JVMTI_ENABLE,
288 JVMTI_EVENT_DYNAMIC_CODE_GENERATED, NULL);
289 if (ret != JVMTI_ERROR_NONE) {
290 warnx("jvmti: setnotification failed on code_generated");
291 return -1;
292 }
293 return 0;
294}
295
296JNIEXPORT void JNICALL
297Agent_OnUnload(JavaVM *jvm __unused)
298{
299 int ret;
300
301 ret = jvmti_close(jvmti_agent);
302 if (ret)
303 errx(1, "Error: op_close_agent()");
304}
diff --git a/tools/perf/perf.c b/tools/perf/perf.c
index a929618b8eb6..aaee0a782747 100644
--- a/tools/perf/perf.c
+++ b/tools/perf/perf.c
@@ -454,11 +454,12 @@ static void handle_internal_command(int argc, const char **argv)
454 454
455static void execv_dashed_external(const char **argv) 455static void execv_dashed_external(const char **argv)
456{ 456{
457 struct strbuf cmd = STRBUF_INIT; 457 char *cmd;
458 const char *tmp; 458 const char *tmp;
459 int status; 459 int status;
460 460
461 strbuf_addf(&cmd, "perf-%s", argv[0]); 461 if (asprintf(&cmd, "perf-%s", argv[0]) < 0)
462 goto do_die;
462 463
463 /* 464 /*
464 * argv[0] must be the perf command, but the argv array 465 * argv[0] must be the perf command, but the argv array
@@ -467,7 +468,7 @@ static void execv_dashed_external(const char **argv)
467 * restore it on error. 468 * restore it on error.
468 */ 469 */
469 tmp = argv[0]; 470 tmp = argv[0];
470 argv[0] = cmd.buf; 471 argv[0] = cmd;
471 472
472 /* 473 /*
473 * if we fail because the command is not found, it is 474 * if we fail because the command is not found, it is
@@ -475,15 +476,16 @@ static void execv_dashed_external(const char **argv)
475 */ 476 */
476 status = run_command_v_opt(argv, 0); 477 status = run_command_v_opt(argv, 0);
477 if (status != -ERR_RUN_COMMAND_EXEC) { 478 if (status != -ERR_RUN_COMMAND_EXEC) {
478 if (IS_RUN_COMMAND_ERR(status)) 479 if (IS_RUN_COMMAND_ERR(status)) {
480do_die:
479 die("unable to run '%s'", argv[0]); 481 die("unable to run '%s'", argv[0]);
482 }
480 exit(-status); 483 exit(-status);
481 } 484 }
482 errno = ENOENT; /* as if we called execvp */ 485 errno = ENOENT; /* as if we called execvp */
483 486
484 argv[0] = tmp; 487 argv[0] = tmp;
485 488 zfree(&cmd);
486 strbuf_release(&cmd);
487} 489}
488 490
489static int run_argv(int *argcp, const char ***argv) 491static int run_argv(int *argcp, const char ***argv)
@@ -546,6 +548,8 @@ int main(int argc, const char **argv)
546 548
547 srandom(time(NULL)); 549 srandom(time(NULL));
548 550
551 perf_config(perf_default_config, NULL);
552
549 /* get debugfs/tracefs mount point from /proc/mounts */ 553 /* get debugfs/tracefs mount point from /proc/mounts */
550 tracing_path_mount(); 554 tracing_path_mount();
551 555
@@ -613,6 +617,8 @@ int main(int argc, const char **argv)
613 */ 617 */
614 pthread__block_sigwinch(); 618 pthread__block_sigwinch();
615 619
620 perf_debug_setup();
621
616 while (1) { 622 while (1) {
617 static int done_help; 623 static int done_help;
618 int was_alias = run_argv(&argc, &argv); 624 int was_alias = run_argv(&argc, &argv);
diff --git a/tools/perf/perf.h b/tools/perf/perf.h
index 90129accffbe..5381a01c0610 100644
--- a/tools/perf/perf.h
+++ b/tools/perf/perf.h
@@ -58,6 +58,8 @@ struct record_opts {
58 bool full_auxtrace; 58 bool full_auxtrace;
59 bool auxtrace_snapshot_mode; 59 bool auxtrace_snapshot_mode;
60 bool record_switch_events; 60 bool record_switch_events;
61 bool all_kernel;
62 bool all_user;
61 unsigned int freq; 63 unsigned int freq;
62 unsigned int mmap_pages; 64 unsigned int mmap_pages;
63 unsigned int auxtrace_mmap_pages; 65 unsigned int auxtrace_mmap_pages;
diff --git a/tools/perf/scripts/python/Perf-Trace-Util/lib/Perf/Trace/Util.py b/tools/perf/scripts/python/Perf-Trace-Util/lib/Perf/Trace/Util.py
index 15c8400240fd..1d95009592eb 100644
--- a/tools/perf/scripts/python/Perf-Trace-Util/lib/Perf/Trace/Util.py
+++ b/tools/perf/scripts/python/Perf-Trace-Util/lib/Perf/Trace/Util.py
@@ -71,7 +71,10 @@ try:
71except: 71except:
72 if not audit_package_warned: 72 if not audit_package_warned:
73 audit_package_warned = True 73 audit_package_warned = True
74 print "Install the audit-libs-python package to get syscall names" 74 print "Install the audit-libs-python package to get syscall names.\n" \
75 "For example:\n # apt-get install python-audit (Ubuntu)" \
76 "\n # yum install audit-libs-python (Fedora)" \
77 "\n etc.\n"
75 78
76def syscall_name(id): 79def syscall_name(id):
77 try: 80 try:
diff --git a/tools/perf/tests/.gitignore b/tools/perf/tests/.gitignore
index bf016c439fbd..8cc30e731c73 100644
--- a/tools/perf/tests/.gitignore
+++ b/tools/perf/tests/.gitignore
@@ -1,3 +1,4 @@
1llvm-src-base.c 1llvm-src-base.c
2llvm-src-kbuild.c 2llvm-src-kbuild.c
3llvm-src-prologue.c 3llvm-src-prologue.c
4llvm-src-relocation.c
diff --git a/tools/perf/tests/Build b/tools/perf/tests/Build
index 614899b88b37..1ba628ed049a 100644
--- a/tools/perf/tests/Build
+++ b/tools/perf/tests/Build
@@ -31,7 +31,7 @@ perf-y += sample-parsing.o
31perf-y += parse-no-sample-id-all.o 31perf-y += parse-no-sample-id-all.o
32perf-y += kmod-path.o 32perf-y += kmod-path.o
33perf-y += thread-map.o 33perf-y += thread-map.o
34perf-y += llvm.o llvm-src-base.o llvm-src-kbuild.o llvm-src-prologue.o 34perf-y += llvm.o llvm-src-base.o llvm-src-kbuild.o llvm-src-prologue.o llvm-src-relocation.o
35perf-y += bpf.o 35perf-y += bpf.o
36perf-y += topology.o 36perf-y += topology.o
37perf-y += cpumap.o 37perf-y += cpumap.o
@@ -59,6 +59,13 @@ $(OUTPUT)tests/llvm-src-prologue.c: tests/bpf-script-test-prologue.c tests/Build
59 $(Q)sed -e 's/"/\\"/g' -e 's/\(.*\)/"\1\\n"/g' $< >> $@ 59 $(Q)sed -e 's/"/\\"/g' -e 's/\(.*\)/"\1\\n"/g' $< >> $@
60 $(Q)echo ';' >> $@ 60 $(Q)echo ';' >> $@
61 61
62$(OUTPUT)tests/llvm-src-relocation.c: tests/bpf-script-test-relocation.c tests/Build
63 $(call rule_mkdir)
64 $(Q)echo '#include <tests/llvm.h>' > $@
65 $(Q)echo 'const char test_llvm__bpf_test_relocation[] =' >> $@
66 $(Q)sed -e 's/"/\\"/g' -e 's/\(.*\)/"\1\\n"/g' $< >> $@
67 $(Q)echo ';' >> $@
68
62ifeq ($(ARCH),$(filter $(ARCH),x86 arm arm64)) 69ifeq ($(ARCH),$(filter $(ARCH),x86 arm arm64))
63perf-$(CONFIG_DWARF_UNWIND) += dwarf-unwind.o 70perf-$(CONFIG_DWARF_UNWIND) += dwarf-unwind.o
64endif 71endif
diff --git a/tools/perf/tests/bp_signal.c b/tools/perf/tests/bp_signal.c
index fb80c9eb6a95..e7664fe3bd33 100644
--- a/tools/perf/tests/bp_signal.c
+++ b/tools/perf/tests/bp_signal.c
@@ -29,14 +29,59 @@
29 29
30static int fd1; 30static int fd1;
31static int fd2; 31static int fd2;
32static int fd3;
32static int overflows; 33static int overflows;
34static int overflows_2;
35
36volatile long the_var;
37
38
39/*
40 * Use ASM to ensure watchpoint and breakpoint can be triggered
41 * at one instruction.
42 */
43#if defined (__x86_64__)
44extern void __test_function(volatile long *ptr);
45asm (
46 ".globl __test_function\n"
47 "__test_function:\n"
48 "incq (%rdi)\n"
49 "ret\n");
50#elif defined (__aarch64__)
51extern void __test_function(volatile long *ptr);
52asm (
53 ".globl __test_function\n"
54 "__test_function:\n"
55 "str x30, [x0]\n"
56 "ret\n");
57
58#else
59static void __test_function(volatile long *ptr)
60{
61 *ptr = 0x1234;
62}
63#endif
33 64
34__attribute__ ((noinline)) 65__attribute__ ((noinline))
35static int test_function(void) 66static int test_function(void)
36{ 67{
68 __test_function(&the_var);
69 the_var++;
37 return time(NULL); 70 return time(NULL);
38} 71}
39 72
73static void sig_handler_2(int signum __maybe_unused,
74 siginfo_t *oh __maybe_unused,
75 void *uc __maybe_unused)
76{
77 overflows_2++;
78 if (overflows_2 > 10) {
79 ioctl(fd1, PERF_EVENT_IOC_DISABLE, 0);
80 ioctl(fd2, PERF_EVENT_IOC_DISABLE, 0);
81 ioctl(fd3, PERF_EVENT_IOC_DISABLE, 0);
82 }
83}
84
40static void sig_handler(int signum __maybe_unused, 85static void sig_handler(int signum __maybe_unused,
41 siginfo_t *oh __maybe_unused, 86 siginfo_t *oh __maybe_unused,
42 void *uc __maybe_unused) 87 void *uc __maybe_unused)
@@ -54,10 +99,11 @@ static void sig_handler(int signum __maybe_unused,
54 */ 99 */
55 ioctl(fd1, PERF_EVENT_IOC_DISABLE, 0); 100 ioctl(fd1, PERF_EVENT_IOC_DISABLE, 0);
56 ioctl(fd2, PERF_EVENT_IOC_DISABLE, 0); 101 ioctl(fd2, PERF_EVENT_IOC_DISABLE, 0);
102 ioctl(fd3, PERF_EVENT_IOC_DISABLE, 0);
57 } 103 }
58} 104}
59 105
60static int bp_event(void *fn, int setup_signal) 106static int __event(bool is_x, void *addr, int sig)
61{ 107{
62 struct perf_event_attr pe; 108 struct perf_event_attr pe;
63 int fd; 109 int fd;
@@ -67,8 +113,8 @@ static int bp_event(void *fn, int setup_signal)
67 pe.size = sizeof(struct perf_event_attr); 113 pe.size = sizeof(struct perf_event_attr);
68 114
69 pe.config = 0; 115 pe.config = 0;
70 pe.bp_type = HW_BREAKPOINT_X; 116 pe.bp_type = is_x ? HW_BREAKPOINT_X : HW_BREAKPOINT_W;
71 pe.bp_addr = (unsigned long) fn; 117 pe.bp_addr = (unsigned long) addr;
72 pe.bp_len = sizeof(long); 118 pe.bp_len = sizeof(long);
73 119
74 pe.sample_period = 1; 120 pe.sample_period = 1;
@@ -86,17 +132,25 @@ static int bp_event(void *fn, int setup_signal)
86 return TEST_FAIL; 132 return TEST_FAIL;
87 } 133 }
88 134
89 if (setup_signal) { 135 fcntl(fd, F_SETFL, O_RDWR|O_NONBLOCK|O_ASYNC);
90 fcntl(fd, F_SETFL, O_RDWR|O_NONBLOCK|O_ASYNC); 136 fcntl(fd, F_SETSIG, sig);
91 fcntl(fd, F_SETSIG, SIGIO); 137 fcntl(fd, F_SETOWN, getpid());
92 fcntl(fd, F_SETOWN, getpid());
93 }
94 138
95 ioctl(fd, PERF_EVENT_IOC_RESET, 0); 139 ioctl(fd, PERF_EVENT_IOC_RESET, 0);
96 140
97 return fd; 141 return fd;
98} 142}
99 143
144static int bp_event(void *addr, int sig)
145{
146 return __event(true, addr, sig);
147}
148
149static int wp_event(void *addr, int sig)
150{
151 return __event(false, addr, sig);
152}
153
100static long long bp_count(int fd) 154static long long bp_count(int fd)
101{ 155{
102 long long count; 156 long long count;
@@ -114,7 +168,7 @@ static long long bp_count(int fd)
114int test__bp_signal(int subtest __maybe_unused) 168int test__bp_signal(int subtest __maybe_unused)
115{ 169{
116 struct sigaction sa; 170 struct sigaction sa;
117 long long count1, count2; 171 long long count1, count2, count3;
118 172
119 /* setup SIGIO signal handler */ 173 /* setup SIGIO signal handler */
120 memset(&sa, 0, sizeof(struct sigaction)); 174 memset(&sa, 0, sizeof(struct sigaction));
@@ -126,21 +180,52 @@ int test__bp_signal(int subtest __maybe_unused)
126 return TEST_FAIL; 180 return TEST_FAIL;
127 } 181 }
128 182
183 sa.sa_sigaction = (void *) sig_handler_2;
184 if (sigaction(SIGUSR1, &sa, NULL) < 0) {
185 pr_debug("failed setting up signal handler 2\n");
186 return TEST_FAIL;
187 }
188
129 /* 189 /*
130 * We create following events: 190 * We create following events:
131 * 191 *
132 * fd1 - breakpoint event on test_function with SIGIO 192 * fd1 - breakpoint event on __test_function with SIGIO
133 * signal configured. We should get signal 193 * signal configured. We should get signal
134 * notification each time the breakpoint is hit 194 * notification each time the breakpoint is hit
135 * 195 *
136 * fd2 - breakpoint event on sig_handler without SIGIO 196 * fd2 - breakpoint event on sig_handler with SIGUSR1
197 * configured. We should get SIGUSR1 each time when
198 * breakpoint is hit
199 *
200 * fd3 - watchpoint event on __test_function with SIGIO
137 * configured. 201 * configured.
138 * 202 *
139 * Following processing should happen: 203 * Following processing should happen:
140 * - execute test_function 204 * Exec: Action: Result:
141 * - fd1 event breakpoint hit -> count1 == 1 205 * incq (%rdi) - fd1 event breakpoint hit -> count1 == 1
142 * - SIGIO is delivered -> overflows == 1 206 * - SIGIO is delivered
143 * - fd2 event breakpoint hit -> count2 == 1 207 * sig_handler - fd2 event breakpoint hit -> count2 == 1
208 * - SIGUSR1 is delivered
209 * sig_handler_2 -> overflows_2 == 1 (nested signal)
210 * sys_rt_sigreturn - return from sig_handler_2
211 * overflows++ -> overflows = 1
212 * sys_rt_sigreturn - return from sig_handler
213 * incq (%rdi) - fd3 event watchpoint hit -> count3 == 1 (wp and bp in one insn)
214 * - SIGIO is delivered
215 * sig_handler - fd2 event breakpoint hit -> count2 == 2
216 * - SIGUSR1 is delivered
217 * sig_handler_2 -> overflows_2 == 2 (nested signal)
218 * sys_rt_sigreturn - return from sig_handler_2
219 * overflows++ -> overflows = 2
220 * sys_rt_sigreturn - return from sig_handler
221 * the_var++ - fd3 event watchpoint hit -> count3 == 2 (standalone watchpoint)
222 * - SIGIO is delivered
223 * sig_handler - fd2 event breakpoint hit -> count2 == 3
224 * - SIGUSR1 is delivered
225 * sig_handler_2 -> overflows_2 == 3 (nested signal)
226 * sys_rt_sigreturn - return from sig_handler_2
227 * overflows++ -> overflows == 3
228 * sys_rt_sigreturn - return from sig_handler
144 * 229 *
145 * The test case check following error conditions: 230 * The test case check following error conditions:
146 * - we get stuck in signal handler because of debug 231 * - we get stuck in signal handler because of debug
@@ -152,11 +237,13 @@ int test__bp_signal(int subtest __maybe_unused)
152 * 237 *
153 */ 238 */
154 239
155 fd1 = bp_event(test_function, 1); 240 fd1 = bp_event(__test_function, SIGIO);
156 fd2 = bp_event(sig_handler, 0); 241 fd2 = bp_event(sig_handler, SIGUSR1);
242 fd3 = wp_event((void *)&the_var, SIGIO);
157 243
158 ioctl(fd1, PERF_EVENT_IOC_ENABLE, 0); 244 ioctl(fd1, PERF_EVENT_IOC_ENABLE, 0);
159 ioctl(fd2, PERF_EVENT_IOC_ENABLE, 0); 245 ioctl(fd2, PERF_EVENT_IOC_ENABLE, 0);
246 ioctl(fd3, PERF_EVENT_IOC_ENABLE, 0);
160 247
161 /* 248 /*
162 * Kick off the test by trigering 'fd1' 249 * Kick off the test by trigering 'fd1'
@@ -166,15 +253,18 @@ int test__bp_signal(int subtest __maybe_unused)
166 253
167 ioctl(fd1, PERF_EVENT_IOC_DISABLE, 0); 254 ioctl(fd1, PERF_EVENT_IOC_DISABLE, 0);
168 ioctl(fd2, PERF_EVENT_IOC_DISABLE, 0); 255 ioctl(fd2, PERF_EVENT_IOC_DISABLE, 0);
256 ioctl(fd3, PERF_EVENT_IOC_DISABLE, 0);
169 257
170 count1 = bp_count(fd1); 258 count1 = bp_count(fd1);
171 count2 = bp_count(fd2); 259 count2 = bp_count(fd2);
260 count3 = bp_count(fd3);
172 261
173 close(fd1); 262 close(fd1);
174 close(fd2); 263 close(fd2);
264 close(fd3);
175 265
176 pr_debug("count1 %lld, count2 %lld, overflow %d\n", 266 pr_debug("count1 %lld, count2 %lld, count3 %lld, overflow %d, overflows_2 %d\n",
177 count1, count2, overflows); 267 count1, count2, count3, overflows, overflows_2);
178 268
179 if (count1 != 1) { 269 if (count1 != 1) {
180 if (count1 == 11) 270 if (count1 == 11)
@@ -183,12 +273,18 @@ int test__bp_signal(int subtest __maybe_unused)
183 pr_debug("failed: wrong count for bp1%lld\n", count1); 273 pr_debug("failed: wrong count for bp1%lld\n", count1);
184 } 274 }
185 275
186 if (overflows != 1) 276 if (overflows != 3)
187 pr_debug("failed: wrong overflow hit\n"); 277 pr_debug("failed: wrong overflow hit\n");
188 278
189 if (count2 != 1) 279 if (overflows_2 != 3)
280 pr_debug("failed: wrong overflow_2 hit\n");
281
282 if (count2 != 3)
190 pr_debug("failed: wrong count for bp2\n"); 283 pr_debug("failed: wrong count for bp2\n");
191 284
192 return count1 == 1 && overflows == 1 && count2 == 1 ? 285 if (count3 != 2)
286 pr_debug("failed: wrong count for bp3\n");
287
288 return count1 == 1 && overflows == 3 && count2 == 3 && overflows_2 == 3 && count3 == 2 ?
193 TEST_OK : TEST_FAIL; 289 TEST_OK : TEST_FAIL;
194} 290}
diff --git a/tools/perf/tests/bpf-script-test-relocation.c b/tools/perf/tests/bpf-script-test-relocation.c
new file mode 100644
index 000000000000..93af77421816
--- /dev/null
+++ b/tools/perf/tests/bpf-script-test-relocation.c
@@ -0,0 +1,50 @@
1/*
2 * bpf-script-test-relocation.c
3 * Test BPF loader checking relocation
4 */
5#ifndef LINUX_VERSION_CODE
6# error Need LINUX_VERSION_CODE
7# error Example: for 4.2 kernel, put 'clang-opt="-DLINUX_VERSION_CODE=0x40200" into llvm section of ~/.perfconfig'
8#endif
9#define BPF_ANY 0
10#define BPF_MAP_TYPE_ARRAY 2
11#define BPF_FUNC_map_lookup_elem 1
12#define BPF_FUNC_map_update_elem 2
13
14static void *(*bpf_map_lookup_elem)(void *map, void *key) =
15 (void *) BPF_FUNC_map_lookup_elem;
16static void *(*bpf_map_update_elem)(void *map, void *key, void *value, int flags) =
17 (void *) BPF_FUNC_map_update_elem;
18
19struct bpf_map_def {
20 unsigned int type;
21 unsigned int key_size;
22 unsigned int value_size;
23 unsigned int max_entries;
24};
25
26#define SEC(NAME) __attribute__((section(NAME), used))
27struct bpf_map_def SEC("maps") my_table = {
28 .type = BPF_MAP_TYPE_ARRAY,
29 .key_size = sizeof(int),
30 .value_size = sizeof(int),
31 .max_entries = 1,
32};
33
34int this_is_a_global_val;
35
36SEC("func=sys_write")
37int bpf_func__sys_write(void *ctx)
38{
39 int key = 0;
40 int value = 0;
41
42 /*
43 * Incorrect relocation. Should not allow this program be
44 * loaded into kernel.
45 */
46 bpf_map_update_elem(&this_is_a_global_val, &key, &value, 0);
47 return 0;
48}
49char _license[] SEC("license") = "GPL";
50int _version SEC("version") = LINUX_VERSION_CODE;
diff --git a/tools/perf/tests/bpf.c b/tools/perf/tests/bpf.c
index 33689a0cf821..199501c71e27 100644
--- a/tools/perf/tests/bpf.c
+++ b/tools/perf/tests/bpf.c
@@ -1,7 +1,11 @@
1#include <stdio.h> 1#include <stdio.h>
2#include <sys/epoll.h> 2#include <sys/epoll.h>
3#include <util/util.h>
3#include <util/bpf-loader.h> 4#include <util/bpf-loader.h>
4#include <util/evlist.h> 5#include <util/evlist.h>
6#include <linux/bpf.h>
7#include <linux/filter.h>
8#include <bpf/bpf.h>
5#include "tests.h" 9#include "tests.h"
6#include "llvm.h" 10#include "llvm.h"
7#include "debug.h" 11#include "debug.h"
@@ -71,6 +75,15 @@ static struct {
71 (NR_ITERS + 1) / 4, 75 (NR_ITERS + 1) / 4,
72 }, 76 },
73#endif 77#endif
78 {
79 LLVM_TESTCASE_BPF_RELOCATION,
80 "Test BPF relocation checker",
81 "[bpf_relocation_test]",
82 "fix 'perf test LLVM' first",
83 "libbpf error when dealing with relocation",
84 NULL,
85 0,
86 },
74}; 87};
75 88
76static int do_test(struct bpf_object *obj, int (*func)(void), 89static int do_test(struct bpf_object *obj, int (*func)(void),
@@ -99,7 +112,7 @@ static int do_test(struct bpf_object *obj, int (*func)(void),
99 parse_evlist.error = &parse_error; 112 parse_evlist.error = &parse_error;
100 INIT_LIST_HEAD(&parse_evlist.list); 113 INIT_LIST_HEAD(&parse_evlist.list);
101 114
102 err = parse_events_load_bpf_obj(&parse_evlist, &parse_evlist.list, obj); 115 err = parse_events_load_bpf_obj(&parse_evlist, &parse_evlist.list, obj, NULL);
103 if (err || list_empty(&parse_evlist.list)) { 116 if (err || list_empty(&parse_evlist.list)) {
104 pr_debug("Failed to add events selected by BPF\n"); 117 pr_debug("Failed to add events selected by BPF\n");
105 return TEST_FAIL; 118 return TEST_FAIL;
@@ -190,7 +203,7 @@ static int __test__bpf(int idx)
190 203
191 ret = test_llvm__fetch_bpf_obj(&obj_buf, &obj_buf_sz, 204 ret = test_llvm__fetch_bpf_obj(&obj_buf, &obj_buf_sz,
192 bpf_testcase_table[idx].prog_id, 205 bpf_testcase_table[idx].prog_id,
193 true); 206 true, NULL);
194 if (ret != TEST_OK || !obj_buf || !obj_buf_sz) { 207 if (ret != TEST_OK || !obj_buf || !obj_buf_sz) {
195 pr_debug("Unable to get BPF object, %s\n", 208 pr_debug("Unable to get BPF object, %s\n",
196 bpf_testcase_table[idx].msg_compile_fail); 209 bpf_testcase_table[idx].msg_compile_fail);
@@ -202,14 +215,21 @@ static int __test__bpf(int idx)
202 215
203 obj = prepare_bpf(obj_buf, obj_buf_sz, 216 obj = prepare_bpf(obj_buf, obj_buf_sz,
204 bpf_testcase_table[idx].name); 217 bpf_testcase_table[idx].name);
205 if (!obj) { 218 if ((!!bpf_testcase_table[idx].target_func) != (!!obj)) {
219 if (!obj)
220 pr_debug("Fail to load BPF object: %s\n",
221 bpf_testcase_table[idx].msg_load_fail);
222 else
223 pr_debug("Success unexpectedly: %s\n",
224 bpf_testcase_table[idx].msg_load_fail);
206 ret = TEST_FAIL; 225 ret = TEST_FAIL;
207 goto out; 226 goto out;
208 } 227 }
209 228
210 ret = do_test(obj, 229 if (obj)
211 bpf_testcase_table[idx].target_func, 230 ret = do_test(obj,
212 bpf_testcase_table[idx].expect_result); 231 bpf_testcase_table[idx].target_func,
232 bpf_testcase_table[idx].expect_result);
213out: 233out:
214 bpf__clear(); 234 bpf__clear();
215 return ret; 235 return ret;
@@ -227,6 +247,36 @@ const char *test__bpf_subtest_get_desc(int i)
227 return bpf_testcase_table[i].desc; 247 return bpf_testcase_table[i].desc;
228} 248}
229 249
250static int check_env(void)
251{
252 int err;
253 unsigned int kver_int;
254 char license[] = "GPL";
255
256 struct bpf_insn insns[] = {
257 BPF_MOV64_IMM(BPF_REG_0, 1),
258 BPF_EXIT_INSN(),
259 };
260
261 err = fetch_kernel_version(&kver_int, NULL, 0);
262 if (err) {
263 pr_debug("Unable to get kernel version\n");
264 return err;
265 }
266
267 err = bpf_load_program(BPF_PROG_TYPE_KPROBE, insns,
268 sizeof(insns) / sizeof(insns[0]),
269 license, kver_int, NULL, 0);
270 if (err < 0) {
271 pr_err("Missing basic BPF support, skip this test: %s\n",
272 strerror(errno));
273 return err;
274 }
275 close(err);
276
277 return 0;
278}
279
230int test__bpf(int i) 280int test__bpf(int i)
231{ 281{
232 int err; 282 int err;
@@ -239,6 +289,9 @@ int test__bpf(int i)
239 return TEST_SKIP; 289 return TEST_SKIP;
240 } 290 }
241 291
292 if (check_env())
293 return TEST_SKIP;
294
242 err = __test__bpf(i); 295 err = __test__bpf(i);
243 return err; 296 return err;
244} 297}
diff --git a/tools/perf/tests/code-reading.c b/tools/perf/tests/code-reading.c
index 313a48c6b2bc..abd3f0ec0c0b 100644
--- a/tools/perf/tests/code-reading.c
+++ b/tools/perf/tests/code-reading.c
@@ -293,7 +293,6 @@ static int process_sample_event(struct machine *machine,
293{ 293{
294 struct perf_sample sample; 294 struct perf_sample sample;
295 struct thread *thread; 295 struct thread *thread;
296 u8 cpumode;
297 int ret; 296 int ret;
298 297
299 if (perf_evlist__parse_sample(evlist, event, &sample)) { 298 if (perf_evlist__parse_sample(evlist, event, &sample)) {
@@ -307,9 +306,7 @@ static int process_sample_event(struct machine *machine,
307 return -1; 306 return -1;
308 } 307 }
309 308
310 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; 309 ret = read_object_code(sample.ip, READLEN, sample.cpumode, thread, state);
311
312 ret = read_object_code(sample.ip, READLEN, cpumode, thread, state);
313 thread__put(thread); 310 thread__put(thread);
314 return ret; 311 return ret;
315} 312}
@@ -439,7 +436,7 @@ static int do_test_code_reading(bool try_kcore)
439 .mmap_pages = UINT_MAX, 436 .mmap_pages = UINT_MAX,
440 .user_freq = UINT_MAX, 437 .user_freq = UINT_MAX,
441 .user_interval = ULLONG_MAX, 438 .user_interval = ULLONG_MAX,
442 .freq = 4000, 439 .freq = 500,
443 .target = { 440 .target = {
444 .uses_mmap = true, 441 .uses_mmap = true,
445 }, 442 },
@@ -559,7 +556,13 @@ static int do_test_code_reading(bool try_kcore)
559 evlist = NULL; 556 evlist = NULL;
560 continue; 557 continue;
561 } 558 }
562 pr_debug("perf_evlist__open failed\n"); 559
560 if (verbose) {
561 char errbuf[512];
562 perf_evlist__strerror_open(evlist, errno, errbuf, sizeof(errbuf));
563 pr_debug("perf_evlist__open() failed!\n%s\n", errbuf);
564 }
565
563 goto out_put; 566 goto out_put;
564 } 567 }
565 break; 568 break;
diff --git a/tools/perf/tests/dwarf-unwind.c b/tools/perf/tests/dwarf-unwind.c
index 1c5c0221cea2..8f6eb853aaf7 100644
--- a/tools/perf/tests/dwarf-unwind.c
+++ b/tools/perf/tests/dwarf-unwind.c
@@ -20,10 +20,10 @@
20 20
21static int mmap_handler(struct perf_tool *tool __maybe_unused, 21static int mmap_handler(struct perf_tool *tool __maybe_unused,
22 union perf_event *event, 22 union perf_event *event,
23 struct perf_sample *sample __maybe_unused, 23 struct perf_sample *sample,
24 struct machine *machine) 24 struct machine *machine)
25{ 25{
26 return machine__process_mmap2_event(machine, event, NULL); 26 return machine__process_mmap2_event(machine, event, sample);
27} 27}
28 28
29static int init_live_machine(struct machine *machine) 29static int init_live_machine(struct machine *machine)
diff --git a/tools/perf/tests/hists_common.c b/tools/perf/tests/hists_common.c
index 071a8b5f5232..f55f4bd47932 100644
--- a/tools/perf/tests/hists_common.c
+++ b/tools/perf/tests/hists_common.c
@@ -100,9 +100,11 @@ struct machine *setup_fake_machine(struct machines *machines)
100 } 100 }
101 101
102 for (i = 0; i < ARRAY_SIZE(fake_mmap_info); i++) { 102 for (i = 0; i < ARRAY_SIZE(fake_mmap_info); i++) {
103 struct perf_sample sample = {
104 .cpumode = PERF_RECORD_MISC_USER,
105 };
103 union perf_event fake_mmap_event = { 106 union perf_event fake_mmap_event = {
104 .mmap = { 107 .mmap = {
105 .header = { .misc = PERF_RECORD_MISC_USER, },
106 .pid = fake_mmap_info[i].pid, 108 .pid = fake_mmap_info[i].pid,
107 .tid = fake_mmap_info[i].pid, 109 .tid = fake_mmap_info[i].pid,
108 .start = fake_mmap_info[i].start, 110 .start = fake_mmap_info[i].start,
@@ -114,7 +116,7 @@ struct machine *setup_fake_machine(struct machines *machines)
114 strcpy(fake_mmap_event.mmap.filename, 116 strcpy(fake_mmap_event.mmap.filename,
115 fake_mmap_info[i].filename); 117 fake_mmap_info[i].filename);
116 118
117 machine__process_mmap_event(machine, &fake_mmap_event, NULL); 119 machine__process_mmap_event(machine, &fake_mmap_event, &sample);
118 } 120 }
119 121
120 for (i = 0; i < ARRAY_SIZE(fake_symbols); i++) { 122 for (i = 0; i < ARRAY_SIZE(fake_symbols); i++) {
diff --git a/tools/perf/tests/hists_cumulate.c b/tools/perf/tests/hists_cumulate.c
index 5e6a86e50fb9..ed5aa9eaeb6c 100644
--- a/tools/perf/tests/hists_cumulate.c
+++ b/tools/perf/tests/hists_cumulate.c
@@ -81,11 +81,6 @@ static int add_hist_entries(struct hists *hists, struct machine *machine)
81 size_t i; 81 size_t i;
82 82
83 for (i = 0; i < ARRAY_SIZE(fake_samples); i++) { 83 for (i = 0; i < ARRAY_SIZE(fake_samples); i++) {
84 const union perf_event event = {
85 .header = {
86 .misc = PERF_RECORD_MISC_USER,
87 },
88 };
89 struct hist_entry_iter iter = { 84 struct hist_entry_iter iter = {
90 .evsel = evsel, 85 .evsel = evsel,
91 .sample = &sample, 86 .sample = &sample,
@@ -97,13 +92,13 @@ static int add_hist_entries(struct hists *hists, struct machine *machine)
97 else 92 else
98 iter.ops = &hist_iter_normal; 93 iter.ops = &hist_iter_normal;
99 94
95 sample.cpumode = PERF_RECORD_MISC_USER;
100 sample.pid = fake_samples[i].pid; 96 sample.pid = fake_samples[i].pid;
101 sample.tid = fake_samples[i].pid; 97 sample.tid = fake_samples[i].pid;
102 sample.ip = fake_samples[i].ip; 98 sample.ip = fake_samples[i].ip;
103 sample.callchain = (struct ip_callchain *)fake_callchains[i]; 99 sample.callchain = (struct ip_callchain *)fake_callchains[i];
104 100
105 if (perf_event__preprocess_sample(&event, machine, &al, 101 if (machine__resolve(machine, &al, &sample) < 0)
106 &sample) < 0)
107 goto out; 102 goto out;
108 103
109 if (hist_entry_iter__add(&iter, &al, PERF_MAX_STACK_DEPTH, 104 if (hist_entry_iter__add(&iter, &al, PERF_MAX_STACK_DEPTH,
@@ -191,7 +186,7 @@ static int do_test(struct hists *hists, struct result *expected, size_t nr_expec
191 * function since TEST_ASSERT_VAL() returns in case of failure. 186 * function since TEST_ASSERT_VAL() returns in case of failure.
192 */ 187 */
193 hists__collapse_resort(hists, NULL); 188 hists__collapse_resort(hists, NULL);
194 hists__output_resort(hists, NULL); 189 perf_evsel__output_resort(hists_to_evsel(hists), NULL);
195 190
196 if (verbose > 2) { 191 if (verbose > 2) {
197 pr_info("use callchain: %d, cumulate callchain: %d\n", 192 pr_info("use callchain: %d, cumulate callchain: %d\n",
diff --git a/tools/perf/tests/hists_filter.c b/tools/perf/tests/hists_filter.c
index 351a42463444..b825d24f8186 100644
--- a/tools/perf/tests/hists_filter.c
+++ b/tools/perf/tests/hists_filter.c
@@ -58,11 +58,6 @@ static int add_hist_entries(struct perf_evlist *evlist,
58 */ 58 */
59 evlist__for_each(evlist, evsel) { 59 evlist__for_each(evlist, evsel) {
60 for (i = 0; i < ARRAY_SIZE(fake_samples); i++) { 60 for (i = 0; i < ARRAY_SIZE(fake_samples); i++) {
61 const union perf_event event = {
62 .header = {
63 .misc = PERF_RECORD_MISC_USER,
64 },
65 };
66 struct hist_entry_iter iter = { 61 struct hist_entry_iter iter = {
67 .evsel = evsel, 62 .evsel = evsel,
68 .sample = &sample, 63 .sample = &sample,
@@ -76,12 +71,12 @@ static int add_hist_entries(struct perf_evlist *evlist,
76 hists->dso_filter = NULL; 71 hists->dso_filter = NULL;
77 hists->symbol_filter_str = NULL; 72 hists->symbol_filter_str = NULL;
78 73
74 sample.cpumode = PERF_RECORD_MISC_USER;
79 sample.pid = fake_samples[i].pid; 75 sample.pid = fake_samples[i].pid;
80 sample.tid = fake_samples[i].pid; 76 sample.tid = fake_samples[i].pid;
81 sample.ip = fake_samples[i].ip; 77 sample.ip = fake_samples[i].ip;
82 78
83 if (perf_event__preprocess_sample(&event, machine, &al, 79 if (machine__resolve(machine, &al, &sample) < 0)
84 &sample) < 0)
85 goto out; 80 goto out;
86 81
87 al.socket = fake_samples[i].socket; 82 al.socket = fake_samples[i].socket;
@@ -145,7 +140,7 @@ int test__hists_filter(int subtest __maybe_unused)
145 struct hists *hists = evsel__hists(evsel); 140 struct hists *hists = evsel__hists(evsel);
146 141
147 hists__collapse_resort(hists, NULL); 142 hists__collapse_resort(hists, NULL);
148 hists__output_resort(hists, NULL); 143 perf_evsel__output_resort(evsel, NULL);
149 144
150 if (verbose > 2) { 145 if (verbose > 2) {
151 pr_info("Normal histogram\n"); 146 pr_info("Normal histogram\n");
diff --git a/tools/perf/tests/hists_link.c b/tools/perf/tests/hists_link.c
index 64b257d8d557..358324e47805 100644
--- a/tools/perf/tests/hists_link.c
+++ b/tools/perf/tests/hists_link.c
@@ -76,17 +76,12 @@ static int add_hist_entries(struct perf_evlist *evlist, struct machine *machine)
76 struct hists *hists = evsel__hists(evsel); 76 struct hists *hists = evsel__hists(evsel);
77 77
78 for (k = 0; k < ARRAY_SIZE(fake_common_samples); k++) { 78 for (k = 0; k < ARRAY_SIZE(fake_common_samples); k++) {
79 const union perf_event event = { 79 sample.cpumode = PERF_RECORD_MISC_USER;
80 .header = {
81 .misc = PERF_RECORD_MISC_USER,
82 },
83 };
84
85 sample.pid = fake_common_samples[k].pid; 80 sample.pid = fake_common_samples[k].pid;
86 sample.tid = fake_common_samples[k].pid; 81 sample.tid = fake_common_samples[k].pid;
87 sample.ip = fake_common_samples[k].ip; 82 sample.ip = fake_common_samples[k].ip;
88 if (perf_event__preprocess_sample(&event, machine, &al, 83
89 &sample) < 0) 84 if (machine__resolve(machine, &al, &sample) < 0)
90 goto out; 85 goto out;
91 86
92 he = __hists__add_entry(hists, &al, NULL, 87 he = __hists__add_entry(hists, &al, NULL,
@@ -102,17 +97,10 @@ static int add_hist_entries(struct perf_evlist *evlist, struct machine *machine)
102 } 97 }
103 98
104 for (k = 0; k < ARRAY_SIZE(fake_samples[i]); k++) { 99 for (k = 0; k < ARRAY_SIZE(fake_samples[i]); k++) {
105 const union perf_event event = {
106 .header = {
107 .misc = PERF_RECORD_MISC_USER,
108 },
109 };
110
111 sample.pid = fake_samples[i][k].pid; 100 sample.pid = fake_samples[i][k].pid;
112 sample.tid = fake_samples[i][k].pid; 101 sample.tid = fake_samples[i][k].pid;
113 sample.ip = fake_samples[i][k].ip; 102 sample.ip = fake_samples[i][k].ip;
114 if (perf_event__preprocess_sample(&event, machine, &al, 103 if (machine__resolve(machine, &al, &sample) < 0)
115 &sample) < 0)
116 goto out; 104 goto out;
117 105
118 he = __hists__add_entry(hists, &al, NULL, 106 he = __hists__add_entry(hists, &al, NULL,
diff --git a/tools/perf/tests/hists_output.c b/tools/perf/tests/hists_output.c
index b231265148d8..d3556fbe8c5c 100644
--- a/tools/perf/tests/hists_output.c
+++ b/tools/perf/tests/hists_output.c
@@ -51,11 +51,6 @@ static int add_hist_entries(struct hists *hists, struct machine *machine)
51 size_t i; 51 size_t i;
52 52
53 for (i = 0; i < ARRAY_SIZE(fake_samples); i++) { 53 for (i = 0; i < ARRAY_SIZE(fake_samples); i++) {
54 const union perf_event event = {
55 .header = {
56 .misc = PERF_RECORD_MISC_USER,
57 },
58 };
59 struct hist_entry_iter iter = { 54 struct hist_entry_iter iter = {
60 .evsel = evsel, 55 .evsel = evsel,
61 .sample = &sample, 56 .sample = &sample,
@@ -63,13 +58,13 @@ static int add_hist_entries(struct hists *hists, struct machine *machine)
63 .hide_unresolved = false, 58 .hide_unresolved = false,
64 }; 59 };
65 60
61 sample.cpumode = PERF_RECORD_MISC_USER;
66 sample.cpu = fake_samples[i].cpu; 62 sample.cpu = fake_samples[i].cpu;
67 sample.pid = fake_samples[i].pid; 63 sample.pid = fake_samples[i].pid;
68 sample.tid = fake_samples[i].pid; 64 sample.tid = fake_samples[i].pid;
69 sample.ip = fake_samples[i].ip; 65 sample.ip = fake_samples[i].ip;
70 66
71 if (perf_event__preprocess_sample(&event, machine, &al, 67 if (machine__resolve(machine, &al, &sample) < 0)
72 &sample) < 0)
73 goto out; 68 goto out;
74 69
75 if (hist_entry_iter__add(&iter, &al, PERF_MAX_STACK_DEPTH, 70 if (hist_entry_iter__add(&iter, &al, PERF_MAX_STACK_DEPTH,
@@ -156,7 +151,7 @@ static int test1(struct perf_evsel *evsel, struct machine *machine)
156 goto out; 151 goto out;
157 152
158 hists__collapse_resort(hists, NULL); 153 hists__collapse_resort(hists, NULL);
159 hists__output_resort(hists, NULL); 154 perf_evsel__output_resort(evsel, NULL);
160 155
161 if (verbose > 2) { 156 if (verbose > 2) {
162 pr_info("[fields = %s, sort = %s]\n", field_order, sort_order); 157 pr_info("[fields = %s, sort = %s]\n", field_order, sort_order);
@@ -256,7 +251,7 @@ static int test2(struct perf_evsel *evsel, struct machine *machine)
256 goto out; 251 goto out;
257 252
258 hists__collapse_resort(hists, NULL); 253 hists__collapse_resort(hists, NULL);
259 hists__output_resort(hists, NULL); 254 perf_evsel__output_resort(evsel, NULL);
260 255
261 if (verbose > 2) { 256 if (verbose > 2) {
262 pr_info("[fields = %s, sort = %s]\n", field_order, sort_order); 257 pr_info("[fields = %s, sort = %s]\n", field_order, sort_order);
@@ -310,7 +305,7 @@ static int test3(struct perf_evsel *evsel, struct machine *machine)
310 goto out; 305 goto out;
311 306
312 hists__collapse_resort(hists, NULL); 307 hists__collapse_resort(hists, NULL);
313 hists__output_resort(hists, NULL); 308 perf_evsel__output_resort(evsel, NULL);
314 309
315 if (verbose > 2) { 310 if (verbose > 2) {
316 pr_info("[fields = %s, sort = %s]\n", field_order, sort_order); 311 pr_info("[fields = %s, sort = %s]\n", field_order, sort_order);
@@ -388,7 +383,7 @@ static int test4(struct perf_evsel *evsel, struct machine *machine)
388 goto out; 383 goto out;
389 384
390 hists__collapse_resort(hists, NULL); 385 hists__collapse_resort(hists, NULL);
391 hists__output_resort(hists, NULL); 386 perf_evsel__output_resort(evsel, NULL);
392 387
393 if (verbose > 2) { 388 if (verbose > 2) {
394 pr_info("[fields = %s, sort = %s]\n", field_order, sort_order); 389 pr_info("[fields = %s, sort = %s]\n", field_order, sort_order);
@@ -491,7 +486,7 @@ static int test5(struct perf_evsel *evsel, struct machine *machine)
491 goto out; 486 goto out;
492 487
493 hists__collapse_resort(hists, NULL); 488 hists__collapse_resort(hists, NULL);
494 hists__output_resort(hists, NULL); 489 perf_evsel__output_resort(evsel, NULL);
495 490
496 if (verbose > 2) { 491 if (verbose > 2) {
497 pr_info("[fields = %s, sort = %s]\n", field_order, sort_order); 492 pr_info("[fields = %s, sort = %s]\n", field_order, sort_order);
diff --git a/tools/perf/tests/llvm.c b/tools/perf/tests/llvm.c
index 06f45c1d4256..cff564fb4b66 100644
--- a/tools/perf/tests/llvm.c
+++ b/tools/perf/tests/llvm.c
@@ -6,12 +6,6 @@
6#include "tests.h" 6#include "tests.h"
7#include "debug.h" 7#include "debug.h"
8 8
9static int perf_config_cb(const char *var, const char *val,
10 void *arg __maybe_unused)
11{
12 return perf_default_config(var, val, arg);
13}
14
15#ifdef HAVE_LIBBPF_SUPPORT 9#ifdef HAVE_LIBBPF_SUPPORT
16static int test__bpf_parsing(void *obj_buf, size_t obj_buf_sz) 10static int test__bpf_parsing(void *obj_buf, size_t obj_buf_sz)
17{ 11{
@@ -35,6 +29,7 @@ static int test__bpf_parsing(void *obj_buf __maybe_unused,
35static struct { 29static struct {
36 const char *source; 30 const char *source;
37 const char *desc; 31 const char *desc;
32 bool should_load_fail;
38} bpf_source_table[__LLVM_TESTCASE_MAX] = { 33} bpf_source_table[__LLVM_TESTCASE_MAX] = {
39 [LLVM_TESTCASE_BASE] = { 34 [LLVM_TESTCASE_BASE] = {
40 .source = test_llvm__bpf_base_prog, 35 .source = test_llvm__bpf_base_prog,
@@ -48,14 +43,19 @@ static struct {
48 .source = test_llvm__bpf_test_prologue_prog, 43 .source = test_llvm__bpf_test_prologue_prog,
49 .desc = "Compile source for BPF prologue generation test", 44 .desc = "Compile source for BPF prologue generation test",
50 }, 45 },
46 [LLVM_TESTCASE_BPF_RELOCATION] = {
47 .source = test_llvm__bpf_test_relocation,
48 .desc = "Compile source for BPF relocation test",
49 .should_load_fail = true,
50 },
51}; 51};
52 52
53
54int 53int
55test_llvm__fetch_bpf_obj(void **p_obj_buf, 54test_llvm__fetch_bpf_obj(void **p_obj_buf,
56 size_t *p_obj_buf_sz, 55 size_t *p_obj_buf_sz,
57 enum test_llvm__testcase idx, 56 enum test_llvm__testcase idx,
58 bool force) 57 bool force,
58 bool *should_load_fail)
59{ 59{
60 const char *source; 60 const char *source;
61 const char *desc; 61 const char *desc;
@@ -68,8 +68,8 @@ test_llvm__fetch_bpf_obj(void **p_obj_buf,
68 68
69 source = bpf_source_table[idx].source; 69 source = bpf_source_table[idx].source;
70 desc = bpf_source_table[idx].desc; 70 desc = bpf_source_table[idx].desc;
71 71 if (should_load_fail)
72 perf_config(perf_config_cb, NULL); 72 *should_load_fail = bpf_source_table[idx].should_load_fail;
73 73
74 /* 74 /*
75 * Skip this test if user's .perfconfig doesn't set [llvm] section 75 * Skip this test if user's .perfconfig doesn't set [llvm] section
@@ -136,14 +136,15 @@ int test__llvm(int subtest)
136 int ret; 136 int ret;
137 void *obj_buf = NULL; 137 void *obj_buf = NULL;
138 size_t obj_buf_sz = 0; 138 size_t obj_buf_sz = 0;
139 bool should_load_fail = false;
139 140
140 if ((subtest < 0) || (subtest >= __LLVM_TESTCASE_MAX)) 141 if ((subtest < 0) || (subtest >= __LLVM_TESTCASE_MAX))
141 return TEST_FAIL; 142 return TEST_FAIL;
142 143
143 ret = test_llvm__fetch_bpf_obj(&obj_buf, &obj_buf_sz, 144 ret = test_llvm__fetch_bpf_obj(&obj_buf, &obj_buf_sz,
144 subtest, false); 145 subtest, false, &should_load_fail);
145 146
146 if (ret == TEST_OK) { 147 if (ret == TEST_OK && !should_load_fail) {
147 ret = test__bpf_parsing(obj_buf, obj_buf_sz); 148 ret = test__bpf_parsing(obj_buf, obj_buf_sz);
148 if (ret != TEST_OK) { 149 if (ret != TEST_OK) {
149 pr_debug("Failed to parse test case '%s'\n", 150 pr_debug("Failed to parse test case '%s'\n",
diff --git a/tools/perf/tests/llvm.h b/tools/perf/tests/llvm.h
index 5150b4d6ef50..0eaa604be99d 100644
--- a/tools/perf/tests/llvm.h
+++ b/tools/perf/tests/llvm.h
@@ -7,14 +7,17 @@
7extern const char test_llvm__bpf_base_prog[]; 7extern const char test_llvm__bpf_base_prog[];
8extern const char test_llvm__bpf_test_kbuild_prog[]; 8extern const char test_llvm__bpf_test_kbuild_prog[];
9extern const char test_llvm__bpf_test_prologue_prog[]; 9extern const char test_llvm__bpf_test_prologue_prog[];
10extern const char test_llvm__bpf_test_relocation[];
10 11
11enum test_llvm__testcase { 12enum test_llvm__testcase {
12 LLVM_TESTCASE_BASE, 13 LLVM_TESTCASE_BASE,
13 LLVM_TESTCASE_KBUILD, 14 LLVM_TESTCASE_KBUILD,
14 LLVM_TESTCASE_BPF_PROLOGUE, 15 LLVM_TESTCASE_BPF_PROLOGUE,
16 LLVM_TESTCASE_BPF_RELOCATION,
15 __LLVM_TESTCASE_MAX, 17 __LLVM_TESTCASE_MAX,
16}; 18};
17 19
18int test_llvm__fetch_bpf_obj(void **p_obj_buf, size_t *p_obj_buf_sz, 20int test_llvm__fetch_bpf_obj(void **p_obj_buf, size_t *p_obj_buf_sz,
19 enum test_llvm__testcase index, bool force); 21 enum test_llvm__testcase index, bool force,
22 bool *should_load_fail);
20#endif 23#endif
diff --git a/tools/perf/tests/make b/tools/perf/tests/make
index f918015512af..cac15d93aea6 100644
--- a/tools/perf/tests/make
+++ b/tools/perf/tests/make
@@ -15,6 +15,7 @@ else
15PERF := . 15PERF := .
16PERF_O := $(PERF) 16PERF_O := $(PERF)
17O_OPT := 17O_OPT :=
18FULL_O := $(shell readlink -f $(PERF_O) || echo $(PERF_O))
18 19
19ifneq ($(O),) 20ifneq ($(O),)
20 FULL_O := $(shell readlink -f $(O) || echo $(O)) 21 FULL_O := $(shell readlink -f $(O) || echo $(O))
@@ -79,6 +80,7 @@ make_no_libaudit := NO_LIBAUDIT=1
79make_no_libbionic := NO_LIBBIONIC=1 80make_no_libbionic := NO_LIBBIONIC=1
80make_no_auxtrace := NO_AUXTRACE=1 81make_no_auxtrace := NO_AUXTRACE=1
81make_no_libbpf := NO_LIBBPF=1 82make_no_libbpf := NO_LIBBPF=1
83make_no_libcrypto := NO_LIBCRYPTO=1
82make_tags := tags 84make_tags := tags
83make_cscope := cscope 85make_cscope := cscope
84make_help := help 86make_help := help
@@ -102,6 +104,7 @@ make_minimal := NO_LIBPERL=1 NO_LIBPYTHON=1 NO_NEWT=1 NO_GTK2=1
102make_minimal += NO_DEMANGLE=1 NO_LIBELF=1 NO_LIBUNWIND=1 NO_BACKTRACE=1 104make_minimal += NO_DEMANGLE=1 NO_LIBELF=1 NO_LIBUNWIND=1 NO_BACKTRACE=1
103make_minimal += NO_LIBNUMA=1 NO_LIBAUDIT=1 NO_LIBBIONIC=1 105make_minimal += NO_LIBNUMA=1 NO_LIBAUDIT=1 NO_LIBBIONIC=1
104make_minimal += NO_LIBDW_DWARF_UNWIND=1 NO_AUXTRACE=1 NO_LIBBPF=1 106make_minimal += NO_LIBDW_DWARF_UNWIND=1 NO_AUXTRACE=1 NO_LIBBPF=1
107make_minimal += NO_LIBCRYPTO=1
105 108
106# $(run) contains all available tests 109# $(run) contains all available tests
107run := make_pure 110run := make_pure
@@ -110,6 +113,9 @@ run := make_pure
110# disable features detection 113# disable features detection
111ifeq ($(MK),Makefile) 114ifeq ($(MK),Makefile)
112run += make_clean_all 115run += make_clean_all
116MAKE_F := $(MAKE)
117else
118MAKE_F := $(MAKE) -f $(MK)
113endif 119endif
114run += make_python_perf_so 120run += make_python_perf_so
115run += make_debug 121run += make_debug
@@ -260,6 +266,8 @@ run := $(shell shuf -e $(run))
260run_O := $(shell shuf -e $(run_O)) 266run_O := $(shell shuf -e $(run_O))
261endif 267endif
262 268
269max_width := $(shell echo $(run_O) | sed 's/ /\n/g' | wc -L)
270
263ifdef DEBUG 271ifdef DEBUG
264d := $(info run $(run)) 272d := $(info run $(run))
265d := $(info run_O $(run_O)) 273d := $(info run_O $(run_O))
@@ -267,13 +275,13 @@ endif
267 275
268MAKEFLAGS := --no-print-directory 276MAKEFLAGS := --no-print-directory
269 277
270clean := @(cd $(PERF); make -s -f $(MK) $(O_OPT) clean >/dev/null) 278clean := @(cd $(PERF); $(MAKE_F) -s $(O_OPT) clean >/dev/null)
271 279
272$(run): 280$(run):
273 $(call clean) 281 $(call clean)
274 @TMP_DEST=$$(mktemp -d); \ 282 @TMP_DEST=$$(mktemp -d); \
275 cmd="cd $(PERF) && make -f $(MK) $(PARALLEL_OPT) $(O_OPT) DESTDIR=$$TMP_DEST $($@)"; \ 283 cmd="cd $(PERF) && $(MAKE_F) $($@) $(PARALLEL_OPT) $(O_OPT) DESTDIR=$$TMP_DEST"; \
276 echo "- $@: $$cmd" && echo $$cmd > $@ && \ 284 printf "%*.*s: %s\n" $(max_width) $(max_width) "$@" "$$cmd" && echo $$cmd > $@ && \
277 ( eval $$cmd ) >> $@ 2>&1; \ 285 ( eval $$cmd ) >> $@ 2>&1; \
278 echo " test: $(call test,$@)" >> $@ 2>&1; \ 286 echo " test: $(call test,$@)" >> $@ 2>&1; \
279 $(call test,$@) && \ 287 $(call test,$@) && \
@@ -283,8 +291,8 @@ $(run_O):
283 $(call clean) 291 $(call clean)
284 @TMP_O=$$(mktemp -d); \ 292 @TMP_O=$$(mktemp -d); \
285 TMP_DEST=$$(mktemp -d); \ 293 TMP_DEST=$$(mktemp -d); \
286 cmd="cd $(PERF) && make -f $(MK) $(PARALLEL_OPT) O=$$TMP_O DESTDIR=$$TMP_DEST $($(patsubst %_O,%,$@))"; \ 294 cmd="cd $(PERF) && $(MAKE_F) $($(patsubst %_O,%,$@)) $(PARALLEL_OPT) O=$$TMP_O DESTDIR=$$TMP_DEST"; \
287 echo "- $@: $$cmd" && echo $$cmd > $@ && \ 295 printf "%*.*s: %s\n" $(max_width) $(max_width) "$@" "$$cmd" && echo $$cmd > $@ && \
288 ( eval $$cmd ) >> $@ 2>&1 && \ 296 ( eval $$cmd ) >> $@ 2>&1 && \
289 echo " test: $(call test_O,$@)" >> $@ 2>&1; \ 297 echo " test: $(call test_O,$@)" >> $@ 2>&1; \
290 $(call test_O,$@) && \ 298 $(call test_O,$@) && \
@@ -313,11 +321,43 @@ make_kernelsrc_tools:
313 (make -C ../../tools $(PARALLEL_OPT) $(K_O_OPT) perf) > $@ 2>&1 && \ 321 (make -C ../../tools $(PARALLEL_OPT) $(K_O_OPT) perf) > $@ 2>&1 && \
314 test -x $(KERNEL_O)/tools/perf/perf && rm -f $@ || (cat $@ ; false) 322 test -x $(KERNEL_O)/tools/perf/perf && rm -f $@ || (cat $@ ; false)
315 323
324FEATURES_DUMP_FILE := $(FULL_O)/BUILD_TEST_FEATURE_DUMP
325FEATURES_DUMP_FILE_STATIC := $(FULL_O)/BUILD_TEST_FEATURE_DUMP_STATIC
326
316all: $(run) $(run_O) tarpkg make_kernelsrc make_kernelsrc_tools 327all: $(run) $(run_O) tarpkg make_kernelsrc make_kernelsrc_tools
317 @echo OK 328 @echo OK
329 @rm -f $(FEATURES_DUMP_FILE) $(FEATURES_DUMP_FILE_STATIC)
318 330
319out: $(run_O) 331out: $(run_O)
320 @echo OK 332 @echo OK
333 @rm -f $(FEATURES_DUMP_FILE) $(FEATURES_DUMP_FILE_STATIC)
334
335ifeq ($(REUSE_FEATURES_DUMP),1)
336$(FEATURES_DUMP_FILE):
337 $(call clean)
338 @cmd="cd $(PERF) && make FEATURE_DUMP_COPY=$@ $(O_OPT) feature-dump"; \
339 echo "- $@: $$cmd" && echo $$cmd && \
340 ( eval $$cmd ) > /dev/null 2>&1
341
342$(FEATURES_DUMP_FILE_STATIC):
343 $(call clean)
344 @cmd="cd $(PERF) && make FEATURE_DUMP_COPY=$@ $(O_OPT) LDFLAGS='-static' feature-dump"; \
345 echo "- $@: $$cmd" && echo $$cmd && \
346 ( eval $$cmd ) > /dev/null 2>&1
347
348# Add feature dump dependency for run/run_O targets
349$(foreach t,$(run) $(run_O),$(eval \
350 $(t): $(if $(findstring make_static,$(t)),\
351 $(FEATURES_DUMP_FILE_STATIC),\
352 $(FEATURES_DUMP_FILE))))
353
354# Append 'FEATURES_DUMP=' option to all test cases. For example:
355# make_no_libbpf: NO_LIBBPF=1 --> NO_LIBBPF=1 FEATURES_DUMP=/a/b/BUILD_TEST_FEATURE_DUMP
356# make_static: LDFLAGS=-static --> LDFLAGS=-static FEATURES_DUMP=/a/b/BUILD_TEST_FEATURE_DUMP_STATIC
357$(foreach t,$(run),$(if $(findstring make_static,$(t)),\
358 $(eval $(t) := $($(t)) FEATURES_DUMP=$(FEATURES_DUMP_FILE_STATIC)),\
359 $(eval $(t) := $($(t)) FEATURES_DUMP=$(FEATURES_DUMP_FILE))))
360endif
321 361
322.PHONY: all $(run) $(run_O) tarpkg clean make_kernelsrc make_kernelsrc_tools 362.PHONY: all $(run) $(run_O) tarpkg clean make_kernelsrc make_kernelsrc_tools
323endif # ifndef MK 363endif # ifndef MK
diff --git a/tools/perf/tests/parse-events.c b/tools/perf/tests/parse-events.c
index abe8849d1d70..7865f68dc0d8 100644
--- a/tools/perf/tests/parse-events.c
+++ b/tools/perf/tests/parse-events.c
@@ -1271,6 +1271,38 @@ static int test__checkevent_precise_max_modifier(struct perf_evlist *evlist)
1271 return 0; 1271 return 0;
1272} 1272}
1273 1273
1274static int test__checkevent_config_symbol(struct perf_evlist *evlist)
1275{
1276 struct perf_evsel *evsel = perf_evlist__first(evlist);
1277
1278 TEST_ASSERT_VAL("wrong name setting", strcmp(evsel->name, "insn") == 0);
1279 return 0;
1280}
1281
1282static int test__checkevent_config_raw(struct perf_evlist *evlist)
1283{
1284 struct perf_evsel *evsel = perf_evlist__first(evlist);
1285
1286 TEST_ASSERT_VAL("wrong name setting", strcmp(evsel->name, "rawpmu") == 0);
1287 return 0;
1288}
1289
1290static int test__checkevent_config_num(struct perf_evlist *evlist)
1291{
1292 struct perf_evsel *evsel = perf_evlist__first(evlist);
1293
1294 TEST_ASSERT_VAL("wrong name setting", strcmp(evsel->name, "numpmu") == 0);
1295 return 0;
1296}
1297
1298static int test__checkevent_config_cache(struct perf_evlist *evlist)
1299{
1300 struct perf_evsel *evsel = perf_evlist__first(evlist);
1301
1302 TEST_ASSERT_VAL("wrong name setting", strcmp(evsel->name, "cachepmu") == 0);
1303 return 0;
1304}
1305
1274static int count_tracepoints(void) 1306static int count_tracepoints(void)
1275{ 1307{
1276 struct dirent *events_ent; 1308 struct dirent *events_ent;
@@ -1579,6 +1611,26 @@ static struct evlist_test test__events[] = {
1579 .check = test__checkevent_precise_max_modifier, 1611 .check = test__checkevent_precise_max_modifier,
1580 .id = 47, 1612 .id = 47,
1581 }, 1613 },
1614 {
1615 .name = "instructions/name=insn/",
1616 .check = test__checkevent_config_symbol,
1617 .id = 48,
1618 },
1619 {
1620 .name = "r1234/name=rawpmu/",
1621 .check = test__checkevent_config_raw,
1622 .id = 49,
1623 },
1624 {
1625 .name = "4:0x6530160/name=numpmu/",
1626 .check = test__checkevent_config_num,
1627 .id = 50,
1628 },
1629 {
1630 .name = "L1-dcache-misses/name=cachepmu/",
1631 .check = test__checkevent_config_cache,
1632 .id = 51,
1633 },
1582}; 1634};
1583 1635
1584static struct evlist_test test__events_pmu[] = { 1636static struct evlist_test test__events_pmu[] = {
@@ -1666,7 +1718,7 @@ static int test_term(struct terms_test *t)
1666 } 1718 }
1667 1719
1668 ret = t->check(&terms); 1720 ret = t->check(&terms);
1669 parse_events__free_terms(&terms); 1721 parse_events_terms__purge(&terms);
1670 1722
1671 return ret; 1723 return ret;
1672} 1724}
diff --git a/tools/perf/tests/perf-targz-src-pkg b/tools/perf/tests/perf-targz-src-pkg
index 238aa3927c71..f2d9c5fe58e0 100755
--- a/tools/perf/tests/perf-targz-src-pkg
+++ b/tools/perf/tests/perf-targz-src-pkg
@@ -15,7 +15,7 @@ TMP_DEST=$(mktemp -d)
15tar xf ${TARBALL} -C $TMP_DEST 15tar xf ${TARBALL} -C $TMP_DEST
16rm -f ${TARBALL} 16rm -f ${TARBALL}
17cd - > /dev/null 17cd - > /dev/null
18make -C $TMP_DEST/perf*/tools/perf > /dev/null 2>&1 18make -C $TMP_DEST/perf*/tools/perf > /dev/null
19RC=$? 19RC=$?
20rm -rf ${TMP_DEST} 20rm -rf ${TMP_DEST}
21exit $RC 21exit $RC
diff --git a/tools/perf/tests/vmlinux-kallsyms.c b/tools/perf/tests/vmlinux-kallsyms.c
index f0bfc9e8fd9f..630b0b409b97 100644
--- a/tools/perf/tests/vmlinux-kallsyms.c
+++ b/tools/perf/tests/vmlinux-kallsyms.c
@@ -110,7 +110,6 @@ int test__vmlinux_matches_kallsyms(int subtest __maybe_unused)
110 */ 110 */
111 for (nd = rb_first(&vmlinux_map->dso->symbols[type]); nd; nd = rb_next(nd)) { 111 for (nd = rb_first(&vmlinux_map->dso->symbols[type]); nd; nd = rb_next(nd)) {
112 struct symbol *pair, *first_pair; 112 struct symbol *pair, *first_pair;
113 bool backwards = true;
114 113
115 sym = rb_entry(nd, struct symbol, rb_node); 114 sym = rb_entry(nd, struct symbol, rb_node);
116 115
@@ -151,27 +150,14 @@ next_pair:
151 continue; 150 continue;
152 151
153 } else { 152 } else {
154 struct rb_node *nnd; 153 pair = machine__find_kernel_symbol_by_name(&kallsyms, type, sym->name, NULL, NULL);
155detour: 154 if (pair) {
156 nnd = backwards ? rb_prev(&pair->rb_node) : 155 if (UM(pair->start) == mem_start)
157 rb_next(&pair->rb_node);
158 if (nnd) {
159 struct symbol *next = rb_entry(nnd, struct symbol, rb_node);
160
161 if (UM(next->start) == mem_start) {
162 pair = next;
163 goto next_pair; 156 goto next_pair;
164 }
165 }
166 157
167 if (backwards) { 158 pr_debug("%#" PRIx64 ": diff name v: %s k: %s\n",
168 backwards = false; 159 mem_start, sym->name, pair->name);
169 pair = first_pair;
170 goto detour;
171 } 160 }
172
173 pr_debug("%#" PRIx64 ": diff name v: %s k: %s\n",
174 mem_start, sym->name, pair->name);
175 } 161 }
176 } else 162 } else
177 pr_debug("%#" PRIx64 ": %s not on kallsyms\n", 163 pr_debug("%#" PRIx64 ": %s not on kallsyms\n",
diff --git a/tools/perf/ui/browser.c b/tools/perf/ui/browser.c
index d37202121689..af68a9d488bf 100644
--- a/tools/perf/ui/browser.c
+++ b/tools/perf/ui/browser.c
@@ -531,8 +531,8 @@ static struct ui_browser_colorset {
531 .bg = "yellow", 531 .bg = "yellow",
532 }, 532 },
533 { 533 {
534 .colorset = HE_COLORSET_CODE, 534 .colorset = HE_COLORSET_JUMP_ARROWS,
535 .name = "code", 535 .name = "jump_arrows",
536 .fg = "blue", 536 .fg = "blue",
537 .bg = "default", 537 .bg = "default",
538 }, 538 },
diff --git a/tools/perf/ui/browser.h b/tools/perf/ui/browser.h
index 01781de59532..be3b70eb5fca 100644
--- a/tools/perf/ui/browser.h
+++ b/tools/perf/ui/browser.h
@@ -7,7 +7,7 @@
7#define HE_COLORSET_MEDIUM 51 7#define HE_COLORSET_MEDIUM 51
8#define HE_COLORSET_NORMAL 52 8#define HE_COLORSET_NORMAL 52
9#define HE_COLORSET_SELECTED 53 9#define HE_COLORSET_SELECTED 53
10#define HE_COLORSET_CODE 54 10#define HE_COLORSET_JUMP_ARROWS 54
11#define HE_COLORSET_ADDR 55 11#define HE_COLORSET_ADDR 55
12#define HE_COLORSET_ROOT 56 12#define HE_COLORSET_ROOT 56
13 13
diff --git a/tools/perf/ui/browsers/annotate.c b/tools/perf/ui/browsers/annotate.c
index 718bd46d47fa..4fc208e82c6f 100644
--- a/tools/perf/ui/browsers/annotate.c
+++ b/tools/perf/ui/browsers/annotate.c
@@ -284,7 +284,7 @@ static void annotate_browser__draw_current_jump(struct ui_browser *browser)
284 to = (u64)btarget->idx; 284 to = (u64)btarget->idx;
285 } 285 }
286 286
287 ui_browser__set_color(browser, HE_COLORSET_CODE); 287 ui_browser__set_color(browser, HE_COLORSET_JUMP_ARROWS);
288 __ui_browser__line_arrow(browser, pcnt_width + 2 + ab->addr_width, 288 __ui_browser__line_arrow(browser, pcnt_width + 2 + ab->addr_width,
289 from, to); 289 from, to);
290} 290}
diff --git a/tools/perf/ui/browsers/hists.c b/tools/perf/ui/browsers/hists.c
index 08c09ad755d2..2a83414159a6 100644
--- a/tools/perf/ui/browsers/hists.c
+++ b/tools/perf/ui/browsers/hists.c
@@ -32,6 +32,7 @@ struct hist_browser {
32 bool show_headers; 32 bool show_headers;
33 float min_pcnt; 33 float min_pcnt;
34 u64 nr_non_filtered_entries; 34 u64 nr_non_filtered_entries;
35 u64 nr_hierarchy_entries;
35 u64 nr_callchain_rows; 36 u64 nr_callchain_rows;
36}; 37};
37 38
@@ -58,11 +59,11 @@ static int hist_browser__get_folding(struct hist_browser *browser)
58 59
59 for (nd = rb_first(&hists->entries); 60 for (nd = rb_first(&hists->entries);
60 (nd = hists__filter_entries(nd, browser->min_pcnt)) != NULL; 61 (nd = hists__filter_entries(nd, browser->min_pcnt)) != NULL;
61 nd = rb_next(nd)) { 62 nd = rb_hierarchy_next(nd)) {
62 struct hist_entry *he = 63 struct hist_entry *he =
63 rb_entry(nd, struct hist_entry, rb_node); 64 rb_entry(nd, struct hist_entry, rb_node);
64 65
65 if (he->unfolded) 66 if (he->leaf && he->unfolded)
66 unfolded_rows += he->nr_rows; 67 unfolded_rows += he->nr_rows;
67 } 68 }
68 return unfolded_rows; 69 return unfolded_rows;
@@ -72,7 +73,9 @@ static u32 hist_browser__nr_entries(struct hist_browser *hb)
72{ 73{
73 u32 nr_entries; 74 u32 nr_entries;
74 75
75 if (hist_browser__has_filter(hb)) 76 if (symbol_conf.report_hierarchy)
77 nr_entries = hb->nr_hierarchy_entries;
78 else if (hist_browser__has_filter(hb))
76 nr_entries = hb->nr_non_filtered_entries; 79 nr_entries = hb->nr_non_filtered_entries;
77 else 80 else
78 nr_entries = hb->hists->nr_entries; 81 nr_entries = hb->hists->nr_entries;
@@ -247,6 +250,38 @@ static int callchain__count_rows(struct rb_root *chain)
247 return n; 250 return n;
248} 251}
249 252
253static int hierarchy_count_rows(struct hist_browser *hb, struct hist_entry *he,
254 bool include_children)
255{
256 int count = 0;
257 struct rb_node *node;
258 struct hist_entry *child;
259
260 if (he->leaf)
261 return callchain__count_rows(&he->sorted_chain);
262
263 if (he->has_no_entry)
264 return 1;
265
266 node = rb_first(&he->hroot_out);
267 while (node) {
268 float percent;
269
270 child = rb_entry(node, struct hist_entry, rb_node);
271 percent = hist_entry__get_percent_limit(child);
272
273 if (!child->filtered && percent >= hb->min_pcnt) {
274 count++;
275
276 if (include_children && child->unfolded)
277 count += hierarchy_count_rows(hb, child, true);
278 }
279
280 node = rb_next(node);
281 }
282 return count;
283}
284
250static bool hist_entry__toggle_fold(struct hist_entry *he) 285static bool hist_entry__toggle_fold(struct hist_entry *he)
251{ 286{
252 if (!he) 287 if (!he)
@@ -302,7 +337,7 @@ static void callchain_node__init_have_children(struct callchain_node *node,
302 chain = list_entry(node->val.next, struct callchain_list, list); 337 chain = list_entry(node->val.next, struct callchain_list, list);
303 chain->has_children = has_sibling; 338 chain->has_children = has_sibling;
304 339
305 if (node->val.next != node->val.prev) { 340 if (!list_empty(&node->val)) {
306 chain = list_entry(node->val.prev, struct callchain_list, list); 341 chain = list_entry(node->val.prev, struct callchain_list, list);
307 chain->has_children = !RB_EMPTY_ROOT(&node->rb_root); 342 chain->has_children = !RB_EMPTY_ROOT(&node->rb_root);
308 } 343 }
@@ -326,11 +361,17 @@ static void callchain__init_have_children(struct rb_root *root)
326 361
327static void hist_entry__init_have_children(struct hist_entry *he) 362static void hist_entry__init_have_children(struct hist_entry *he)
328{ 363{
329 if (!he->init_have_children) { 364 if (he->init_have_children)
365 return;
366
367 if (he->leaf) {
330 he->has_children = !RB_EMPTY_ROOT(&he->sorted_chain); 368 he->has_children = !RB_EMPTY_ROOT(&he->sorted_chain);
331 callchain__init_have_children(&he->sorted_chain); 369 callchain__init_have_children(&he->sorted_chain);
332 he->init_have_children = true; 370 } else {
371 he->has_children = !RB_EMPTY_ROOT(&he->hroot_out);
333 } 372 }
373
374 he->init_have_children = true;
334} 375}
335 376
336static bool hist_browser__toggle_fold(struct hist_browser *browser) 377static bool hist_browser__toggle_fold(struct hist_browser *browser)
@@ -349,17 +390,49 @@ static bool hist_browser__toggle_fold(struct hist_browser *browser)
349 has_children = callchain_list__toggle_fold(cl); 390 has_children = callchain_list__toggle_fold(cl);
350 391
351 if (has_children) { 392 if (has_children) {
393 int child_rows = 0;
394
352 hist_entry__init_have_children(he); 395 hist_entry__init_have_children(he);
353 browser->b.nr_entries -= he->nr_rows; 396 browser->b.nr_entries -= he->nr_rows;
354 browser->nr_callchain_rows -= he->nr_rows;
355 397
356 if (he->unfolded) 398 if (he->leaf)
357 he->nr_rows = callchain__count_rows(&he->sorted_chain); 399 browser->nr_callchain_rows -= he->nr_rows;
358 else 400 else
401 browser->nr_hierarchy_entries -= he->nr_rows;
402
403 if (symbol_conf.report_hierarchy)
404 child_rows = hierarchy_count_rows(browser, he, true);
405
406 if (he->unfolded) {
407 if (he->leaf)
408 he->nr_rows = callchain__count_rows(&he->sorted_chain);
409 else
410 he->nr_rows = hierarchy_count_rows(browser, he, false);
411
412 /* account grand children */
413 if (symbol_conf.report_hierarchy)
414 browser->b.nr_entries += child_rows - he->nr_rows;
415
416 if (!he->leaf && he->nr_rows == 0) {
417 he->has_no_entry = true;
418 he->nr_rows = 1;
419 }
420 } else {
421 if (symbol_conf.report_hierarchy)
422 browser->b.nr_entries -= child_rows - he->nr_rows;
423
424 if (he->has_no_entry)
425 he->has_no_entry = false;
426
359 he->nr_rows = 0; 427 he->nr_rows = 0;
428 }
360 429
361 browser->b.nr_entries += he->nr_rows; 430 browser->b.nr_entries += he->nr_rows;
362 browser->nr_callchain_rows += he->nr_rows; 431
432 if (he->leaf)
433 browser->nr_callchain_rows += he->nr_rows;
434 else
435 browser->nr_hierarchy_entries += he->nr_rows;
363 436
364 return true; 437 return true;
365 } 438 }
@@ -422,13 +495,38 @@ static int callchain__set_folding(struct rb_root *chain, bool unfold)
422 return n; 495 return n;
423} 496}
424 497
425static void hist_entry__set_folding(struct hist_entry *he, bool unfold) 498static int hierarchy_set_folding(struct hist_browser *hb, struct hist_entry *he,
499 bool unfold __maybe_unused)
500{
501 float percent;
502 struct rb_node *nd;
503 struct hist_entry *child;
504 int n = 0;
505
506 for (nd = rb_first(&he->hroot_out); nd; nd = rb_next(nd)) {
507 child = rb_entry(nd, struct hist_entry, rb_node);
508 percent = hist_entry__get_percent_limit(child);
509 if (!child->filtered && percent >= hb->min_pcnt)
510 n++;
511 }
512
513 return n;
514}
515
516static void hist_entry__set_folding(struct hist_entry *he,
517 struct hist_browser *hb, bool unfold)
426{ 518{
427 hist_entry__init_have_children(he); 519 hist_entry__init_have_children(he);
428 he->unfolded = unfold ? he->has_children : false; 520 he->unfolded = unfold ? he->has_children : false;
429 521
430 if (he->has_children) { 522 if (he->has_children) {
431 int n = callchain__set_folding(&he->sorted_chain, unfold); 523 int n;
524
525 if (he->leaf)
526 n = callchain__set_folding(&he->sorted_chain, unfold);
527 else
528 n = hierarchy_set_folding(hb, he, unfold);
529
432 he->nr_rows = unfold ? n : 0; 530 he->nr_rows = unfold ? n : 0;
433 } else 531 } else
434 he->nr_rows = 0; 532 he->nr_rows = 0;
@@ -438,19 +536,38 @@ static void
438__hist_browser__set_folding(struct hist_browser *browser, bool unfold) 536__hist_browser__set_folding(struct hist_browser *browser, bool unfold)
439{ 537{
440 struct rb_node *nd; 538 struct rb_node *nd;
441 struct hists *hists = browser->hists; 539 struct hist_entry *he;
540 double percent;
442 541
443 for (nd = rb_first(&hists->entries); 542 nd = rb_first(&browser->hists->entries);
444 (nd = hists__filter_entries(nd, browser->min_pcnt)) != NULL; 543 while (nd) {
445 nd = rb_next(nd)) { 544 he = rb_entry(nd, struct hist_entry, rb_node);
446 struct hist_entry *he = rb_entry(nd, struct hist_entry, rb_node); 545
447 hist_entry__set_folding(he, unfold); 546 /* set folding state even if it's currently folded */
448 browser->nr_callchain_rows += he->nr_rows; 547 nd = __rb_hierarchy_next(nd, HMD_FORCE_CHILD);
548
549 hist_entry__set_folding(he, browser, unfold);
550
551 percent = hist_entry__get_percent_limit(he);
552 if (he->filtered || percent < browser->min_pcnt)
553 continue;
554
555 if (!he->depth || unfold)
556 browser->nr_hierarchy_entries++;
557 if (he->leaf)
558 browser->nr_callchain_rows += he->nr_rows;
559 else if (unfold && !hist_entry__has_hierarchy_children(he, browser->min_pcnt)) {
560 browser->nr_hierarchy_entries++;
561 he->has_no_entry = true;
562 he->nr_rows = 1;
563 } else
564 he->has_no_entry = false;
449 } 565 }
450} 566}
451 567
452static void hist_browser__set_folding(struct hist_browser *browser, bool unfold) 568static void hist_browser__set_folding(struct hist_browser *browser, bool unfold)
453{ 569{
570 browser->nr_hierarchy_entries = 0;
454 browser->nr_callchain_rows = 0; 571 browser->nr_callchain_rows = 0;
455 __hist_browser__set_folding(browser, unfold); 572 __hist_browser__set_folding(browser, unfold);
456 573
@@ -657,9 +774,24 @@ static int hist_browser__show_callchain_list(struct hist_browser *browser,
657 return 1; 774 return 1;
658} 775}
659 776
777static bool check_percent_display(struct rb_node *node, u64 parent_total)
778{
779 struct callchain_node *child;
780
781 if (node == NULL)
782 return false;
783
784 if (rb_next(node))
785 return true;
786
787 child = rb_entry(node, struct callchain_node, rb_node);
788 return callchain_cumul_hits(child) != parent_total;
789}
790
660static int hist_browser__show_callchain_flat(struct hist_browser *browser, 791static int hist_browser__show_callchain_flat(struct hist_browser *browser,
661 struct rb_root *root, 792 struct rb_root *root,
662 unsigned short row, u64 total, 793 unsigned short row, u64 total,
794 u64 parent_total,
663 print_callchain_entry_fn print, 795 print_callchain_entry_fn print,
664 struct callchain_print_arg *arg, 796 struct callchain_print_arg *arg,
665 check_output_full_fn is_output_full) 797 check_output_full_fn is_output_full)
@@ -669,7 +801,7 @@ static int hist_browser__show_callchain_flat(struct hist_browser *browser,
669 bool need_percent; 801 bool need_percent;
670 802
671 node = rb_first(root); 803 node = rb_first(root);
672 need_percent = node && rb_next(node); 804 need_percent = check_percent_display(node, parent_total);
673 805
674 while (node) { 806 while (node) {
675 struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node); 807 struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node);
@@ -763,6 +895,7 @@ static char *hist_browser__folded_callchain_str(struct hist_browser *browser,
763static int hist_browser__show_callchain_folded(struct hist_browser *browser, 895static int hist_browser__show_callchain_folded(struct hist_browser *browser,
764 struct rb_root *root, 896 struct rb_root *root,
765 unsigned short row, u64 total, 897 unsigned short row, u64 total,
898 u64 parent_total,
766 print_callchain_entry_fn print, 899 print_callchain_entry_fn print,
767 struct callchain_print_arg *arg, 900 struct callchain_print_arg *arg,
768 check_output_full_fn is_output_full) 901 check_output_full_fn is_output_full)
@@ -772,7 +905,7 @@ static int hist_browser__show_callchain_folded(struct hist_browser *browser,
772 bool need_percent; 905 bool need_percent;
773 906
774 node = rb_first(root); 907 node = rb_first(root);
775 need_percent = node && rb_next(node); 908 need_percent = check_percent_display(node, parent_total);
776 909
777 while (node) { 910 while (node) {
778 struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node); 911 struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node);
@@ -844,20 +977,24 @@ next:
844 return row - first_row; 977 return row - first_row;
845} 978}
846 979
847static int hist_browser__show_callchain(struct hist_browser *browser, 980static int hist_browser__show_callchain_graph(struct hist_browser *browser,
848 struct rb_root *root, int level, 981 struct rb_root *root, int level,
849 unsigned short row, u64 total, 982 unsigned short row, u64 total,
983 u64 parent_total,
850 print_callchain_entry_fn print, 984 print_callchain_entry_fn print,
851 struct callchain_print_arg *arg, 985 struct callchain_print_arg *arg,
852 check_output_full_fn is_output_full) 986 check_output_full_fn is_output_full)
853{ 987{
854 struct rb_node *node; 988 struct rb_node *node;
855 int first_row = row, offset = level * LEVEL_OFFSET_STEP; 989 int first_row = row, offset = level * LEVEL_OFFSET_STEP;
856 u64 new_total;
857 bool need_percent; 990 bool need_percent;
991 u64 percent_total = total;
992
993 if (callchain_param.mode == CHAIN_GRAPH_REL)
994 percent_total = parent_total;
858 995
859 node = rb_first(root); 996 node = rb_first(root);
860 need_percent = node && rb_next(node); 997 need_percent = check_percent_display(node, parent_total);
861 998
862 while (node) { 999 while (node) {
863 struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node); 1000 struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node);
@@ -878,7 +1015,7 @@ static int hist_browser__show_callchain(struct hist_browser *browser,
878 folded_sign = callchain_list__folded(chain); 1015 folded_sign = callchain_list__folded(chain);
879 1016
880 row += hist_browser__show_callchain_list(browser, child, 1017 row += hist_browser__show_callchain_list(browser, child,
881 chain, row, total, 1018 chain, row, percent_total,
882 was_first && need_percent, 1019 was_first && need_percent,
883 offset + extra_offset, 1020 offset + extra_offset,
884 print, arg); 1021 print, arg);
@@ -893,13 +1030,9 @@ static int hist_browser__show_callchain(struct hist_browser *browser,
893 if (folded_sign == '-') { 1030 if (folded_sign == '-') {
894 const int new_level = level + (extra_offset ? 2 : 1); 1031 const int new_level = level + (extra_offset ? 2 : 1);
895 1032
896 if (callchain_param.mode == CHAIN_GRAPH_REL) 1033 row += hist_browser__show_callchain_graph(browser, &child->rb_root,
897 new_total = child->children_hit; 1034 new_level, row, total,
898 else 1035 child->children_hit,
899 new_total = total;
900
901 row += hist_browser__show_callchain(browser, &child->rb_root,
902 new_level, row, new_total,
903 print, arg, is_output_full); 1036 print, arg, is_output_full);
904 } 1037 }
905 if (is_output_full(browser, row)) 1038 if (is_output_full(browser, row))
@@ -910,6 +1043,45 @@ out:
910 return row - first_row; 1043 return row - first_row;
911} 1044}
912 1045
1046static int hist_browser__show_callchain(struct hist_browser *browser,
1047 struct hist_entry *entry, int level,
1048 unsigned short row,
1049 print_callchain_entry_fn print,
1050 struct callchain_print_arg *arg,
1051 check_output_full_fn is_output_full)
1052{
1053 u64 total = hists__total_period(entry->hists);
1054 u64 parent_total;
1055 int printed;
1056
1057 if (symbol_conf.cumulate_callchain)
1058 parent_total = entry->stat_acc->period;
1059 else
1060 parent_total = entry->stat.period;
1061
1062 if (callchain_param.mode == CHAIN_FLAT) {
1063 printed = hist_browser__show_callchain_flat(browser,
1064 &entry->sorted_chain, row,
1065 total, parent_total, print, arg,
1066 is_output_full);
1067 } else if (callchain_param.mode == CHAIN_FOLDED) {
1068 printed = hist_browser__show_callchain_folded(browser,
1069 &entry->sorted_chain, row,
1070 total, parent_total, print, arg,
1071 is_output_full);
1072 } else {
1073 printed = hist_browser__show_callchain_graph(browser,
1074 &entry->sorted_chain, level, row,
1075 total, parent_total, print, arg,
1076 is_output_full);
1077 }
1078
1079 if (arg->is_current_entry)
1080 browser->he_selection = entry;
1081
1082 return printed;
1083}
1084
913struct hpp_arg { 1085struct hpp_arg {
914 struct ui_browser *b; 1086 struct ui_browser *b;
915 char folded_sign; 1087 char folded_sign;
@@ -1006,7 +1178,6 @@ static int hist_browser__show_entry(struct hist_browser *browser,
1006 struct hist_entry *entry, 1178 struct hist_entry *entry,
1007 unsigned short row) 1179 unsigned short row)
1008{ 1180{
1009 char s[256];
1010 int printed = 0; 1181 int printed = 0;
1011 int width = browser->b.width; 1182 int width = browser->b.width;
1012 char folded_sign = ' '; 1183 char folded_sign = ' ';
@@ -1031,16 +1202,18 @@ static int hist_browser__show_entry(struct hist_browser *browser,
1031 .folded_sign = folded_sign, 1202 .folded_sign = folded_sign,
1032 .current_entry = current_entry, 1203 .current_entry = current_entry,
1033 }; 1204 };
1034 struct perf_hpp hpp = {
1035 .buf = s,
1036 .size = sizeof(s),
1037 .ptr = &arg,
1038 };
1039 int column = 0; 1205 int column = 0;
1040 1206
1041 hist_browser__gotorc(browser, row, 0); 1207 hist_browser__gotorc(browser, row, 0);
1042 1208
1043 perf_hpp__for_each_format(fmt) { 1209 hists__for_each_format(browser->hists, fmt) {
1210 char s[2048];
1211 struct perf_hpp hpp = {
1212 .buf = s,
1213 .size = sizeof(s),
1214 .ptr = &arg,
1215 };
1216
1044 if (perf_hpp__should_skip(fmt, entry->hists) || 1217 if (perf_hpp__should_skip(fmt, entry->hists) ||
1045 column++ < browser->b.horiz_scroll) 1218 column++ < browser->b.horiz_scroll)
1046 continue; 1219 continue;
@@ -1065,11 +1238,18 @@ static int hist_browser__show_entry(struct hist_browser *browser,
1065 } 1238 }
1066 1239
1067 if (fmt->color) { 1240 if (fmt->color) {
1068 width -= fmt->color(fmt, &hpp, entry); 1241 int ret = fmt->color(fmt, &hpp, entry);
1242 hist_entry__snprintf_alignment(entry, &hpp, fmt, ret);
1243 /*
1244 * fmt->color() already used ui_browser to
1245 * print the non alignment bits, skip it (+ret):
1246 */
1247 ui_browser__printf(&browser->b, "%s", s + ret);
1069 } else { 1248 } else {
1070 width -= fmt->entry(fmt, &hpp, entry); 1249 hist_entry__snprintf_alignment(entry, &hpp, fmt, fmt->entry(fmt, &hpp, entry));
1071 ui_browser__printf(&browser->b, "%s", s); 1250 ui_browser__printf(&browser->b, "%s", s);
1072 } 1251 }
1252 width -= hpp.buf - s;
1073 } 1253 }
1074 1254
1075 /* The scroll bar isn't being used */ 1255 /* The scroll bar isn't being used */
@@ -1084,43 +1264,246 @@ static int hist_browser__show_entry(struct hist_browser *browser,
1084 --row_offset; 1264 --row_offset;
1085 1265
1086 if (folded_sign == '-' && row != browser->b.rows) { 1266 if (folded_sign == '-' && row != browser->b.rows) {
1087 u64 total = hists__total_period(entry->hists);
1088 struct callchain_print_arg arg = { 1267 struct callchain_print_arg arg = {
1089 .row_offset = row_offset, 1268 .row_offset = row_offset,
1090 .is_current_entry = current_entry, 1269 .is_current_entry = current_entry,
1091 }; 1270 };
1092 1271
1093 if (callchain_param.mode == CHAIN_GRAPH_REL) { 1272 printed += hist_browser__show_callchain(browser, entry, 1, row,
1094 if (symbol_conf.cumulate_callchain)
1095 total = entry->stat_acc->period;
1096 else
1097 total = entry->stat.period;
1098 }
1099
1100 if (callchain_param.mode == CHAIN_FLAT) {
1101 printed += hist_browser__show_callchain_flat(browser,
1102 &entry->sorted_chain, row, total,
1103 hist_browser__show_callchain_entry, &arg,
1104 hist_browser__check_output_full);
1105 } else if (callchain_param.mode == CHAIN_FOLDED) {
1106 printed += hist_browser__show_callchain_folded(browser,
1107 &entry->sorted_chain, row, total,
1108 hist_browser__show_callchain_entry, &arg, 1273 hist_browser__show_callchain_entry, &arg,
1109 hist_browser__check_output_full); 1274 hist_browser__check_output_full);
1275 }
1276
1277 return printed;
1278}
1279
1280static int hist_browser__show_hierarchy_entry(struct hist_browser *browser,
1281 struct hist_entry *entry,
1282 unsigned short row,
1283 int level)
1284{
1285 int printed = 0;
1286 int width = browser->b.width;
1287 char folded_sign = ' ';
1288 bool current_entry = ui_browser__is_current_entry(&browser->b, row);
1289 off_t row_offset = entry->row_offset;
1290 bool first = true;
1291 struct perf_hpp_fmt *fmt;
1292 struct perf_hpp_list_node *fmt_node;
1293 struct hpp_arg arg = {
1294 .b = &browser->b,
1295 .current_entry = current_entry,
1296 };
1297 int column = 0;
1298 int hierarchy_indent = (entry->hists->nr_hpp_node - 2) * HIERARCHY_INDENT;
1299
1300 if (current_entry) {
1301 browser->he_selection = entry;
1302 browser->selection = &entry->ms;
1303 }
1304
1305 hist_entry__init_have_children(entry);
1306 folded_sign = hist_entry__folded(entry);
1307 arg.folded_sign = folded_sign;
1308
1309 if (entry->leaf && row_offset) {
1310 row_offset--;
1311 goto show_callchain;
1312 }
1313
1314 hist_browser__gotorc(browser, row, 0);
1315
1316 if (current_entry && browser->b.navkeypressed)
1317 ui_browser__set_color(&browser->b, HE_COLORSET_SELECTED);
1318 else
1319 ui_browser__set_color(&browser->b, HE_COLORSET_NORMAL);
1320
1321 ui_browser__write_nstring(&browser->b, "", level * HIERARCHY_INDENT);
1322 width -= level * HIERARCHY_INDENT;
1323
1324 /* the first hpp_list_node is for overhead columns */
1325 fmt_node = list_first_entry(&entry->hists->hpp_formats,
1326 struct perf_hpp_list_node, list);
1327 perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) {
1328 char s[2048];
1329 struct perf_hpp hpp = {
1330 .buf = s,
1331 .size = sizeof(s),
1332 .ptr = &arg,
1333 };
1334
1335 if (perf_hpp__should_skip(fmt, entry->hists) ||
1336 column++ < browser->b.horiz_scroll)
1337 continue;
1338
1339 if (current_entry && browser->b.navkeypressed) {
1340 ui_browser__set_color(&browser->b,
1341 HE_COLORSET_SELECTED);
1110 } else { 1342 } else {
1111 printed += hist_browser__show_callchain(browser, 1343 ui_browser__set_color(&browser->b,
1112 &entry->sorted_chain, 1, row, total, 1344 HE_COLORSET_NORMAL);
1113 hist_browser__show_callchain_entry, &arg, 1345 }
1114 hist_browser__check_output_full); 1346
1347 if (first) {
1348 ui_browser__printf(&browser->b, "%c", folded_sign);
1349 width--;
1350 first = false;
1351 } else {
1352 ui_browser__printf(&browser->b, " ");
1353 width -= 2;
1354 }
1355
1356 if (fmt->color) {
1357 int ret = fmt->color(fmt, &hpp, entry);
1358 hist_entry__snprintf_alignment(entry, &hpp, fmt, ret);
1359 /*
1360 * fmt->color() already used ui_browser to
1361 * print the non alignment bits, skip it (+ret):
1362 */
1363 ui_browser__printf(&browser->b, "%s", s + ret);
1364 } else {
1365 int ret = fmt->entry(fmt, &hpp, entry);
1366 hist_entry__snprintf_alignment(entry, &hpp, fmt, ret);
1367 ui_browser__printf(&browser->b, "%s", s);
1368 }
1369 width -= hpp.buf - s;
1370 }
1371
1372 ui_browser__write_nstring(&browser->b, "", hierarchy_indent);
1373 width -= hierarchy_indent;
1374
1375 if (column >= browser->b.horiz_scroll) {
1376 char s[2048];
1377 struct perf_hpp hpp = {
1378 .buf = s,
1379 .size = sizeof(s),
1380 .ptr = &arg,
1381 };
1382
1383 if (current_entry && browser->b.navkeypressed) {
1384 ui_browser__set_color(&browser->b,
1385 HE_COLORSET_SELECTED);
1386 } else {
1387 ui_browser__set_color(&browser->b,
1388 HE_COLORSET_NORMAL);
1115 } 1389 }
1116 1390
1117 if (arg.is_current_entry) 1391 perf_hpp_list__for_each_format(entry->hpp_list, fmt) {
1118 browser->he_selection = entry; 1392 ui_browser__write_nstring(&browser->b, "", 2);
1393 width -= 2;
1394
1395 /*
1396 * No need to call hist_entry__snprintf_alignment()
1397 * since this fmt is always the last column in the
1398 * hierarchy mode.
1399 */
1400 if (fmt->color) {
1401 width -= fmt->color(fmt, &hpp, entry);
1402 } else {
1403 int i = 0;
1404
1405 width -= fmt->entry(fmt, &hpp, entry);
1406 ui_browser__printf(&browser->b, "%s", ltrim(s));
1407
1408 while (isspace(s[i++]))
1409 width++;
1410 }
1411 }
1412 }
1413
1414 /* The scroll bar isn't being used */
1415 if (!browser->b.navkeypressed)
1416 width += 1;
1417
1418 ui_browser__write_nstring(&browser->b, "", width);
1419
1420 ++row;
1421 ++printed;
1422
1423show_callchain:
1424 if (entry->leaf && folded_sign == '-' && row != browser->b.rows) {
1425 struct callchain_print_arg carg = {
1426 .row_offset = row_offset,
1427 };
1428
1429 printed += hist_browser__show_callchain(browser, entry,
1430 level + 1, row,
1431 hist_browser__show_callchain_entry, &carg,
1432 hist_browser__check_output_full);
1119 } 1433 }
1120 1434
1121 return printed; 1435 return printed;
1122} 1436}
1123 1437
1438static int hist_browser__show_no_entry(struct hist_browser *browser,
1439 unsigned short row, int level)
1440{
1441 int width = browser->b.width;
1442 bool current_entry = ui_browser__is_current_entry(&browser->b, row);
1443 bool first = true;
1444 int column = 0;
1445 int ret;
1446 struct perf_hpp_fmt *fmt;
1447 struct perf_hpp_list_node *fmt_node;
1448 int indent = browser->hists->nr_hpp_node - 2;
1449
1450 if (current_entry) {
1451 browser->he_selection = NULL;
1452 browser->selection = NULL;
1453 }
1454
1455 hist_browser__gotorc(browser, row, 0);
1456
1457 if (current_entry && browser->b.navkeypressed)
1458 ui_browser__set_color(&browser->b, HE_COLORSET_SELECTED);
1459 else
1460 ui_browser__set_color(&browser->b, HE_COLORSET_NORMAL);
1461
1462 ui_browser__write_nstring(&browser->b, "", level * HIERARCHY_INDENT);
1463 width -= level * HIERARCHY_INDENT;
1464
1465 /* the first hpp_list_node is for overhead columns */
1466 fmt_node = list_first_entry(&browser->hists->hpp_formats,
1467 struct perf_hpp_list_node, list);
1468 perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) {
1469 if (perf_hpp__should_skip(fmt, browser->hists) ||
1470 column++ < browser->b.horiz_scroll)
1471 continue;
1472
1473 ret = fmt->width(fmt, NULL, hists_to_evsel(browser->hists));
1474
1475 if (first) {
1476 /* for folded sign */
1477 first = false;
1478 ret++;
1479 } else {
1480 /* space between columns */
1481 ret += 2;
1482 }
1483
1484 ui_browser__write_nstring(&browser->b, "", ret);
1485 width -= ret;
1486 }
1487
1488 ui_browser__write_nstring(&browser->b, "", indent * HIERARCHY_INDENT);
1489 width -= indent * HIERARCHY_INDENT;
1490
1491 if (column >= browser->b.horiz_scroll) {
1492 char buf[32];
1493
1494 ret = snprintf(buf, sizeof(buf), "no entry >= %.2f%%", browser->min_pcnt);
1495 ui_browser__printf(&browser->b, " %s", buf);
1496 width -= ret + 2;
1497 }
1498
1499 /* The scroll bar isn't being used */
1500 if (!browser->b.navkeypressed)
1501 width += 1;
1502
1503 ui_browser__write_nstring(&browser->b, "", width);
1504 return 1;
1505}
1506
1124static int advance_hpp_check(struct perf_hpp *hpp, int inc) 1507static int advance_hpp_check(struct perf_hpp *hpp, int inc)
1125{ 1508{
1126 advance_hpp(hpp, inc); 1509 advance_hpp(hpp, inc);
@@ -1144,7 +1527,7 @@ static int hists_browser__scnprintf_headers(struct hist_browser *browser, char *
1144 return ret; 1527 return ret;
1145 } 1528 }
1146 1529
1147 perf_hpp__for_each_format(fmt) { 1530 hists__for_each_format(browser->hists, fmt) {
1148 if (perf_hpp__should_skip(fmt, hists) || column++ < browser->b.horiz_scroll) 1531 if (perf_hpp__should_skip(fmt, hists) || column++ < browser->b.horiz_scroll)
1149 continue; 1532 continue;
1150 1533
@@ -1160,11 +1543,96 @@ static int hists_browser__scnprintf_headers(struct hist_browser *browser, char *
1160 return ret; 1543 return ret;
1161} 1544}
1162 1545
1546static int hists_browser__scnprintf_hierarchy_headers(struct hist_browser *browser, char *buf, size_t size)
1547{
1548 struct hists *hists = browser->hists;
1549 struct perf_hpp dummy_hpp = {
1550 .buf = buf,
1551 .size = size,
1552 };
1553 struct perf_hpp_fmt *fmt;
1554 struct perf_hpp_list_node *fmt_node;
1555 size_t ret = 0;
1556 int column = 0;
1557 int indent = hists->nr_hpp_node - 2;
1558 bool first_node, first_col;
1559
1560 ret = scnprintf(buf, size, " ");
1561 if (advance_hpp_check(&dummy_hpp, ret))
1562 return ret;
1563
1564 /* the first hpp_list_node is for overhead columns */
1565 fmt_node = list_first_entry(&hists->hpp_formats,
1566 struct perf_hpp_list_node, list);
1567 perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) {
1568 if (column++ < browser->b.horiz_scroll)
1569 continue;
1570
1571 ret = fmt->header(fmt, &dummy_hpp, hists_to_evsel(hists));
1572 if (advance_hpp_check(&dummy_hpp, ret))
1573 break;
1574
1575 ret = scnprintf(dummy_hpp.buf, dummy_hpp.size, " ");
1576 if (advance_hpp_check(&dummy_hpp, ret))
1577 break;
1578 }
1579
1580 ret = scnprintf(dummy_hpp.buf, dummy_hpp.size, "%*s",
1581 indent * HIERARCHY_INDENT, "");
1582 if (advance_hpp_check(&dummy_hpp, ret))
1583 return ret;
1584
1585 first_node = true;
1586 list_for_each_entry_continue(fmt_node, &hists->hpp_formats, list) {
1587 if (!first_node) {
1588 ret = scnprintf(dummy_hpp.buf, dummy_hpp.size, " / ");
1589 if (advance_hpp_check(&dummy_hpp, ret))
1590 break;
1591 }
1592 first_node = false;
1593
1594 first_col = true;
1595 perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) {
1596 char *start;
1597
1598 if (perf_hpp__should_skip(fmt, hists))
1599 continue;
1600
1601 if (!first_col) {
1602 ret = scnprintf(dummy_hpp.buf, dummy_hpp.size, "+");
1603 if (advance_hpp_check(&dummy_hpp, ret))
1604 break;
1605 }
1606 first_col = false;
1607
1608 ret = fmt->header(fmt, &dummy_hpp, hists_to_evsel(hists));
1609 dummy_hpp.buf[ret] = '\0';
1610 rtrim(dummy_hpp.buf);
1611
1612 start = ltrim(dummy_hpp.buf);
1613 ret = strlen(start);
1614
1615 if (start != dummy_hpp.buf)
1616 memmove(dummy_hpp.buf, start, ret + 1);
1617
1618 if (advance_hpp_check(&dummy_hpp, ret))
1619 break;
1620 }
1621 }
1622
1623 return ret;
1624}
1625
1163static void hist_browser__show_headers(struct hist_browser *browser) 1626static void hist_browser__show_headers(struct hist_browser *browser)
1164{ 1627{
1165 char headers[1024]; 1628 char headers[1024];
1166 1629
1167 hists_browser__scnprintf_headers(browser, headers, sizeof(headers)); 1630 if (symbol_conf.report_hierarchy)
1631 hists_browser__scnprintf_hierarchy_headers(browser, headers,
1632 sizeof(headers));
1633 else
1634 hists_browser__scnprintf_headers(browser, headers,
1635 sizeof(headers));
1168 ui_browser__gotorc(&browser->b, 0, 0); 1636 ui_browser__gotorc(&browser->b, 0, 0);
1169 ui_browser__set_color(&browser->b, HE_COLORSET_ROOT); 1637 ui_browser__set_color(&browser->b, HE_COLORSET_ROOT);
1170 ui_browser__write_nstring(&browser->b, headers, browser->b.width + 1); 1638 ui_browser__write_nstring(&browser->b, headers, browser->b.width + 1);
@@ -1196,18 +1664,34 @@ static unsigned int hist_browser__refresh(struct ui_browser *browser)
1196 hb->he_selection = NULL; 1664 hb->he_selection = NULL;
1197 hb->selection = NULL; 1665 hb->selection = NULL;
1198 1666
1199 for (nd = browser->top; nd; nd = rb_next(nd)) { 1667 for (nd = browser->top; nd; nd = rb_hierarchy_next(nd)) {
1200 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); 1668 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
1201 float percent; 1669 float percent;
1202 1670
1203 if (h->filtered) 1671 if (h->filtered) {
1672 /* let it move to sibling */
1673 h->unfolded = false;
1204 continue; 1674 continue;
1675 }
1205 1676
1206 percent = hist_entry__get_percent_limit(h); 1677 percent = hist_entry__get_percent_limit(h);
1207 if (percent < hb->min_pcnt) 1678 if (percent < hb->min_pcnt)
1208 continue; 1679 continue;
1209 1680
1210 row += hist_browser__show_entry(hb, h, row); 1681 if (symbol_conf.report_hierarchy) {
1682 row += hist_browser__show_hierarchy_entry(hb, h, row,
1683 h->depth);
1684 if (row == browser->rows)
1685 break;
1686
1687 if (h->has_no_entry) {
1688 hist_browser__show_no_entry(hb, row, h->depth + 1);
1689 row++;
1690 }
1691 } else {
1692 row += hist_browser__show_entry(hb, h, row);
1693 }
1694
1211 if (row == browser->rows) 1695 if (row == browser->rows)
1212 break; 1696 break;
1213 } 1697 }
@@ -1225,7 +1709,14 @@ static struct rb_node *hists__filter_entries(struct rb_node *nd,
1225 if (!h->filtered && percent >= min_pcnt) 1709 if (!h->filtered && percent >= min_pcnt)
1226 return nd; 1710 return nd;
1227 1711
1228 nd = rb_next(nd); 1712 /*
1713 * If it's filtered, its all children also were filtered.
1714 * So move to sibling node.
1715 */
1716 if (rb_next(nd))
1717 nd = rb_next(nd);
1718 else
1719 nd = rb_hierarchy_next(nd);
1229 } 1720 }
1230 1721
1231 return NULL; 1722 return NULL;
@@ -1241,7 +1732,7 @@ static struct rb_node *hists__filter_prev_entries(struct rb_node *nd,
1241 if (!h->filtered && percent >= min_pcnt) 1732 if (!h->filtered && percent >= min_pcnt)
1242 return nd; 1733 return nd;
1243 1734
1244 nd = rb_prev(nd); 1735 nd = rb_hierarchy_prev(nd);
1245 } 1736 }
1246 1737
1247 return NULL; 1738 return NULL;
@@ -1271,8 +1762,8 @@ static void ui_browser__hists_seek(struct ui_browser *browser,
1271 nd = browser->top; 1762 nd = browser->top;
1272 goto do_offset; 1763 goto do_offset;
1273 case SEEK_END: 1764 case SEEK_END:
1274 nd = hists__filter_prev_entries(rb_last(browser->entries), 1765 nd = rb_hierarchy_last(rb_last(browser->entries));
1275 hb->min_pcnt); 1766 nd = hists__filter_prev_entries(nd, hb->min_pcnt);
1276 first = false; 1767 first = false;
1277 break; 1768 break;
1278 default: 1769 default:
@@ -1306,7 +1797,7 @@ do_offset:
1306 if (offset > 0) { 1797 if (offset > 0) {
1307 do { 1798 do {
1308 h = rb_entry(nd, struct hist_entry, rb_node); 1799 h = rb_entry(nd, struct hist_entry, rb_node);
1309 if (h->unfolded) { 1800 if (h->unfolded && h->leaf) {
1310 u16 remaining = h->nr_rows - h->row_offset; 1801 u16 remaining = h->nr_rows - h->row_offset;
1311 if (offset > remaining) { 1802 if (offset > remaining) {
1312 offset -= remaining; 1803 offset -= remaining;
@@ -1318,7 +1809,8 @@ do_offset:
1318 break; 1809 break;
1319 } 1810 }
1320 } 1811 }
1321 nd = hists__filter_entries(rb_next(nd), hb->min_pcnt); 1812 nd = hists__filter_entries(rb_hierarchy_next(nd),
1813 hb->min_pcnt);
1322 if (nd == NULL) 1814 if (nd == NULL)
1323 break; 1815 break;
1324 --offset; 1816 --offset;
@@ -1327,7 +1819,7 @@ do_offset:
1327 } else if (offset < 0) { 1819 } else if (offset < 0) {
1328 while (1) { 1820 while (1) {
1329 h = rb_entry(nd, struct hist_entry, rb_node); 1821 h = rb_entry(nd, struct hist_entry, rb_node);
1330 if (h->unfolded) { 1822 if (h->unfolded && h->leaf) {
1331 if (first) { 1823 if (first) {
1332 if (-offset > h->row_offset) { 1824 if (-offset > h->row_offset) {
1333 offset += h->row_offset; 1825 offset += h->row_offset;
@@ -1351,7 +1843,7 @@ do_offset:
1351 } 1843 }
1352 } 1844 }
1353 1845
1354 nd = hists__filter_prev_entries(rb_prev(nd), 1846 nd = hists__filter_prev_entries(rb_hierarchy_prev(nd),
1355 hb->min_pcnt); 1847 hb->min_pcnt);
1356 if (nd == NULL) 1848 if (nd == NULL)
1357 break; 1849 break;
@@ -1364,7 +1856,7 @@ do_offset:
1364 * row_offset at its last entry. 1856 * row_offset at its last entry.
1365 */ 1857 */
1366 h = rb_entry(nd, struct hist_entry, rb_node); 1858 h = rb_entry(nd, struct hist_entry, rb_node);
1367 if (h->unfolded) 1859 if (h->unfolded && h->leaf)
1368 h->row_offset = h->nr_rows; 1860 h->row_offset = h->nr_rows;
1369 break; 1861 break;
1370 } 1862 }
@@ -1378,17 +1870,14 @@ do_offset:
1378} 1870}
1379 1871
1380static int hist_browser__fprintf_callchain(struct hist_browser *browser, 1872static int hist_browser__fprintf_callchain(struct hist_browser *browser,
1381 struct hist_entry *he, FILE *fp) 1873 struct hist_entry *he, FILE *fp,
1874 int level)
1382{ 1875{
1383 u64 total = hists__total_period(he->hists);
1384 struct callchain_print_arg arg = { 1876 struct callchain_print_arg arg = {
1385 .fp = fp, 1877 .fp = fp,
1386 }; 1878 };
1387 1879
1388 if (symbol_conf.cumulate_callchain) 1880 hist_browser__show_callchain(browser, he, level, 0,
1389 total = he->stat_acc->period;
1390
1391 hist_browser__show_callchain(browser, &he->sorted_chain, 1, 0, total,
1392 hist_browser__fprintf_callchain_entry, &arg, 1881 hist_browser__fprintf_callchain_entry, &arg,
1393 hist_browser__check_dump_full); 1882 hist_browser__check_dump_full);
1394 return arg.printed; 1883 return arg.printed;
@@ -1414,7 +1903,7 @@ static int hist_browser__fprintf_entry(struct hist_browser *browser,
1414 if (symbol_conf.use_callchain) 1903 if (symbol_conf.use_callchain)
1415 printed += fprintf(fp, "%c ", folded_sign); 1904 printed += fprintf(fp, "%c ", folded_sign);
1416 1905
1417 perf_hpp__for_each_format(fmt) { 1906 hists__for_each_format(browser->hists, fmt) {
1418 if (perf_hpp__should_skip(fmt, he->hists)) 1907 if (perf_hpp__should_skip(fmt, he->hists))
1419 continue; 1908 continue;
1420 1909
@@ -1425,12 +1914,71 @@ static int hist_browser__fprintf_entry(struct hist_browser *browser,
1425 first = false; 1914 first = false;
1426 1915
1427 ret = fmt->entry(fmt, &hpp, he); 1916 ret = fmt->entry(fmt, &hpp, he);
1917 ret = hist_entry__snprintf_alignment(he, &hpp, fmt, ret);
1428 advance_hpp(&hpp, ret); 1918 advance_hpp(&hpp, ret);
1429 } 1919 }
1430 printed += fprintf(fp, "%s\n", rtrim(s)); 1920 printed += fprintf(fp, "%s\n", s);
1431 1921
1432 if (folded_sign == '-') 1922 if (folded_sign == '-')
1433 printed += hist_browser__fprintf_callchain(browser, he, fp); 1923 printed += hist_browser__fprintf_callchain(browser, he, fp, 1);
1924
1925 return printed;
1926}
1927
1928
1929static int hist_browser__fprintf_hierarchy_entry(struct hist_browser *browser,
1930 struct hist_entry *he,
1931 FILE *fp, int level)
1932{
1933 char s[8192];
1934 int printed = 0;
1935 char folded_sign = ' ';
1936 struct perf_hpp hpp = {
1937 .buf = s,
1938 .size = sizeof(s),
1939 };
1940 struct perf_hpp_fmt *fmt;
1941 struct perf_hpp_list_node *fmt_node;
1942 bool first = true;
1943 int ret;
1944 int hierarchy_indent = (he->hists->nr_hpp_node - 2) * HIERARCHY_INDENT;
1945
1946 printed = fprintf(fp, "%*s", level * HIERARCHY_INDENT, "");
1947
1948 folded_sign = hist_entry__folded(he);
1949 printed += fprintf(fp, "%c", folded_sign);
1950
1951 /* the first hpp_list_node is for overhead columns */
1952 fmt_node = list_first_entry(&he->hists->hpp_formats,
1953 struct perf_hpp_list_node, list);
1954 perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) {
1955 if (!first) {
1956 ret = scnprintf(hpp.buf, hpp.size, " ");
1957 advance_hpp(&hpp, ret);
1958 } else
1959 first = false;
1960
1961 ret = fmt->entry(fmt, &hpp, he);
1962 advance_hpp(&hpp, ret);
1963 }
1964
1965 ret = scnprintf(hpp.buf, hpp.size, "%*s", hierarchy_indent, "");
1966 advance_hpp(&hpp, ret);
1967
1968 perf_hpp_list__for_each_format(he->hpp_list, fmt) {
1969 ret = scnprintf(hpp.buf, hpp.size, " ");
1970 advance_hpp(&hpp, ret);
1971
1972 ret = fmt->entry(fmt, &hpp, he);
1973 advance_hpp(&hpp, ret);
1974 }
1975
1976 printed += fprintf(fp, "%s\n", rtrim(s));
1977
1978 if (he->leaf && folded_sign == '-') {
1979 printed += hist_browser__fprintf_callchain(browser, he, fp,
1980 he->depth + 1);
1981 }
1434 1982
1435 return printed; 1983 return printed;
1436} 1984}
@@ -1444,8 +1992,16 @@ static int hist_browser__fprintf(struct hist_browser *browser, FILE *fp)
1444 while (nd) { 1992 while (nd) {
1445 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); 1993 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
1446 1994
1447 printed += hist_browser__fprintf_entry(browser, h, fp); 1995 if (symbol_conf.report_hierarchy) {
1448 nd = hists__filter_entries(rb_next(nd), browser->min_pcnt); 1996 printed += hist_browser__fprintf_hierarchy_entry(browser,
1997 h, fp,
1998 h->depth);
1999 } else {
2000 printed += hist_browser__fprintf_entry(browser, h, fp);
2001 }
2002
2003 nd = hists__filter_entries(rb_hierarchy_next(nd),
2004 browser->min_pcnt);
1449 } 2005 }
1450 2006
1451 return printed; 2007 return printed;
@@ -1580,11 +2136,18 @@ static int hists__browser_title(struct hists *hists,
1580 if (hists->uid_filter_str) 2136 if (hists->uid_filter_str)
1581 printed += snprintf(bf + printed, size - printed, 2137 printed += snprintf(bf + printed, size - printed,
1582 ", UID: %s", hists->uid_filter_str); 2138 ", UID: %s", hists->uid_filter_str);
1583 if (thread) 2139 if (thread) {
1584 printed += scnprintf(bf + printed, size - printed, 2140 if (sort__has_thread) {
2141 printed += scnprintf(bf + printed, size - printed,
1585 ", Thread: %s(%d)", 2142 ", Thread: %s(%d)",
1586 (thread->comm_set ? thread__comm_str(thread) : ""), 2143 (thread->comm_set ? thread__comm_str(thread) : ""),
1587 thread->tid); 2144 thread->tid);
2145 } else {
2146 printed += scnprintf(bf + printed, size - printed,
2147 ", Thread: %s",
2148 (thread->comm_set ? thread__comm_str(thread) : ""));
2149 }
2150 }
1588 if (dso) 2151 if (dso)
1589 printed += scnprintf(bf + printed, size - printed, 2152 printed += scnprintf(bf + printed, size - printed,
1590 ", DSO: %s", dso->short_name); 2153 ", DSO: %s", dso->short_name);
@@ -1759,15 +2322,24 @@ do_zoom_thread(struct hist_browser *browser, struct popup_action *act)
1759{ 2322{
1760 struct thread *thread = act->thread; 2323 struct thread *thread = act->thread;
1761 2324
2325 if ((!sort__has_thread && !sort__has_comm) || thread == NULL)
2326 return 0;
2327
1762 if (browser->hists->thread_filter) { 2328 if (browser->hists->thread_filter) {
1763 pstack__remove(browser->pstack, &browser->hists->thread_filter); 2329 pstack__remove(browser->pstack, &browser->hists->thread_filter);
1764 perf_hpp__set_elide(HISTC_THREAD, false); 2330 perf_hpp__set_elide(HISTC_THREAD, false);
1765 thread__zput(browser->hists->thread_filter); 2331 thread__zput(browser->hists->thread_filter);
1766 ui_helpline__pop(); 2332 ui_helpline__pop();
1767 } else { 2333 } else {
1768 ui_helpline__fpush("To zoom out press ESC or ENTER + \"Zoom out of %s(%d) thread\"", 2334 if (sort__has_thread) {
1769 thread->comm_set ? thread__comm_str(thread) : "", 2335 ui_helpline__fpush("To zoom out press ESC or ENTER + \"Zoom out of %s(%d) thread\"",
1770 thread->tid); 2336 thread->comm_set ? thread__comm_str(thread) : "",
2337 thread->tid);
2338 } else {
2339 ui_helpline__fpush("To zoom out press ESC or ENTER + \"Zoom out of %s thread\"",
2340 thread->comm_set ? thread__comm_str(thread) : "");
2341 }
2342
1771 browser->hists->thread_filter = thread__get(thread); 2343 browser->hists->thread_filter = thread__get(thread);
1772 perf_hpp__set_elide(HISTC_THREAD, false); 2344 perf_hpp__set_elide(HISTC_THREAD, false);
1773 pstack__push(browser->pstack, &browser->hists->thread_filter); 2345 pstack__push(browser->pstack, &browser->hists->thread_filter);
@@ -1782,13 +2354,22 @@ static int
1782add_thread_opt(struct hist_browser *browser, struct popup_action *act, 2354add_thread_opt(struct hist_browser *browser, struct popup_action *act,
1783 char **optstr, struct thread *thread) 2355 char **optstr, struct thread *thread)
1784{ 2356{
1785 if (thread == NULL) 2357 int ret;
2358
2359 if ((!sort__has_thread && !sort__has_comm) || thread == NULL)
1786 return 0; 2360 return 0;
1787 2361
1788 if (asprintf(optstr, "Zoom %s %s(%d) thread", 2362 if (sort__has_thread) {
1789 browser->hists->thread_filter ? "out of" : "into", 2363 ret = asprintf(optstr, "Zoom %s %s(%d) thread",
1790 thread->comm_set ? thread__comm_str(thread) : "", 2364 browser->hists->thread_filter ? "out of" : "into",
1791 thread->tid) < 0) 2365 thread->comm_set ? thread__comm_str(thread) : "",
2366 thread->tid);
2367 } else {
2368 ret = asprintf(optstr, "Zoom %s %s thread",
2369 browser->hists->thread_filter ? "out of" : "into",
2370 thread->comm_set ? thread__comm_str(thread) : "");
2371 }
2372 if (ret < 0)
1792 return 0; 2373 return 0;
1793 2374
1794 act->thread = thread; 2375 act->thread = thread;
@@ -1801,6 +2382,9 @@ do_zoom_dso(struct hist_browser *browser, struct popup_action *act)
1801{ 2382{
1802 struct map *map = act->ms.map; 2383 struct map *map = act->ms.map;
1803 2384
2385 if (!sort__has_dso || map == NULL)
2386 return 0;
2387
1804 if (browser->hists->dso_filter) { 2388 if (browser->hists->dso_filter) {
1805 pstack__remove(browser->pstack, &browser->hists->dso_filter); 2389 pstack__remove(browser->pstack, &browser->hists->dso_filter);
1806 perf_hpp__set_elide(HISTC_DSO, false); 2390 perf_hpp__set_elide(HISTC_DSO, false);
@@ -1825,7 +2409,7 @@ static int
1825add_dso_opt(struct hist_browser *browser, struct popup_action *act, 2409add_dso_opt(struct hist_browser *browser, struct popup_action *act,
1826 char **optstr, struct map *map) 2410 char **optstr, struct map *map)
1827{ 2411{
1828 if (map == NULL) 2412 if (!sort__has_dso || map == NULL)
1829 return 0; 2413 return 0;
1830 2414
1831 if (asprintf(optstr, "Zoom %s %s DSO", 2415 if (asprintf(optstr, "Zoom %s %s DSO",
@@ -1850,7 +2434,7 @@ static int
1850add_map_opt(struct hist_browser *browser __maybe_unused, 2434add_map_opt(struct hist_browser *browser __maybe_unused,
1851 struct popup_action *act, char **optstr, struct map *map) 2435 struct popup_action *act, char **optstr, struct map *map)
1852{ 2436{
1853 if (map == NULL) 2437 if (!sort__has_dso || map == NULL)
1854 return 0; 2438 return 0;
1855 2439
1856 if (asprintf(optstr, "Browse map details") < 0) 2440 if (asprintf(optstr, "Browse map details") < 0)
@@ -1952,6 +2536,9 @@ add_exit_opt(struct hist_browser *browser __maybe_unused,
1952static int 2536static int
1953do_zoom_socket(struct hist_browser *browser, struct popup_action *act) 2537do_zoom_socket(struct hist_browser *browser, struct popup_action *act)
1954{ 2538{
2539 if (!sort__has_socket || act->socket < 0)
2540 return 0;
2541
1955 if (browser->hists->socket_filter > -1) { 2542 if (browser->hists->socket_filter > -1) {
1956 pstack__remove(browser->pstack, &browser->hists->socket_filter); 2543 pstack__remove(browser->pstack, &browser->hists->socket_filter);
1957 browser->hists->socket_filter = -1; 2544 browser->hists->socket_filter = -1;
@@ -1971,7 +2558,7 @@ static int
1971add_socket_opt(struct hist_browser *browser, struct popup_action *act, 2558add_socket_opt(struct hist_browser *browser, struct popup_action *act,
1972 char **optstr, int socket_id) 2559 char **optstr, int socket_id)
1973{ 2560{
1974 if (socket_id < 0) 2561 if (!sort__has_socket || socket_id < 0)
1975 return 0; 2562 return 0;
1976 2563
1977 if (asprintf(optstr, "Zoom %s Processor Socket %d", 2564 if (asprintf(optstr, "Zoom %s Processor Socket %d",
@@ -1989,17 +2576,60 @@ static void hist_browser__update_nr_entries(struct hist_browser *hb)
1989 u64 nr_entries = 0; 2576 u64 nr_entries = 0;
1990 struct rb_node *nd = rb_first(&hb->hists->entries); 2577 struct rb_node *nd = rb_first(&hb->hists->entries);
1991 2578
1992 if (hb->min_pcnt == 0) { 2579 if (hb->min_pcnt == 0 && !symbol_conf.report_hierarchy) {
1993 hb->nr_non_filtered_entries = hb->hists->nr_non_filtered_entries; 2580 hb->nr_non_filtered_entries = hb->hists->nr_non_filtered_entries;
1994 return; 2581 return;
1995 } 2582 }
1996 2583
1997 while ((nd = hists__filter_entries(nd, hb->min_pcnt)) != NULL) { 2584 while ((nd = hists__filter_entries(nd, hb->min_pcnt)) != NULL) {
1998 nr_entries++; 2585 nr_entries++;
1999 nd = rb_next(nd); 2586 nd = rb_hierarchy_next(nd);
2000 } 2587 }
2001 2588
2002 hb->nr_non_filtered_entries = nr_entries; 2589 hb->nr_non_filtered_entries = nr_entries;
2590 hb->nr_hierarchy_entries = nr_entries;
2591}
2592
2593static void hist_browser__update_percent_limit(struct hist_browser *hb,
2594 double percent)
2595{
2596 struct hist_entry *he;
2597 struct rb_node *nd = rb_first(&hb->hists->entries);
2598 u64 total = hists__total_period(hb->hists);
2599 u64 min_callchain_hits = total * (percent / 100);
2600
2601 hb->min_pcnt = callchain_param.min_percent = percent;
2602
2603 while ((nd = hists__filter_entries(nd, hb->min_pcnt)) != NULL) {
2604 he = rb_entry(nd, struct hist_entry, rb_node);
2605
2606 if (he->has_no_entry) {
2607 he->has_no_entry = false;
2608 he->nr_rows = 0;
2609 }
2610
2611 if (!he->leaf || !symbol_conf.use_callchain)
2612 goto next;
2613
2614 if (callchain_param.mode == CHAIN_GRAPH_REL) {
2615 total = he->stat.period;
2616
2617 if (symbol_conf.cumulate_callchain)
2618 total = he->stat_acc->period;
2619
2620 min_callchain_hits = total * (percent / 100);
2621 }
2622
2623 callchain_param.sort(&he->sorted_chain, he->callchain,
2624 min_callchain_hits, &callchain_param);
2625
2626next:
2627 nd = __rb_hierarchy_next(nd, HMD_FORCE_CHILD);
2628
2629 /* force to re-evaluate folding state of callchains */
2630 he->init_have_children = false;
2631 hist_entry__set_folding(he, hb, false);
2632 }
2003} 2633}
2004 2634
2005static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events, 2635static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
@@ -2037,6 +2667,7 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
2037 "E Expand all callchains\n" \ 2667 "E Expand all callchains\n" \
2038 "F Toggle percentage of filtered entries\n" \ 2668 "F Toggle percentage of filtered entries\n" \
2039 "H Display column headers\n" \ 2669 "H Display column headers\n" \
2670 "L Change percent limit\n" \
2040 "m Display context menu\n" \ 2671 "m Display context menu\n" \
2041 "S Zoom into current Processor Socket\n" \ 2672 "S Zoom into current Processor Socket\n" \
2042 2673
@@ -2077,7 +2708,7 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
2077 memset(options, 0, sizeof(options)); 2708 memset(options, 0, sizeof(options));
2078 memset(actions, 0, sizeof(actions)); 2709 memset(actions, 0, sizeof(actions));
2079 2710
2080 perf_hpp__for_each_format(fmt) { 2711 hists__for_each_format(browser->hists, fmt) {
2081 perf_hpp__reset_width(fmt, hists); 2712 perf_hpp__reset_width(fmt, hists);
2082 /* 2713 /*
2083 * This is done just once, and activates the horizontal scrolling 2714 * This is done just once, and activates the horizontal scrolling
@@ -2192,6 +2823,24 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
2192 top->zero = !top->zero; 2823 top->zero = !top->zero;
2193 } 2824 }
2194 continue; 2825 continue;
2826 case 'L':
2827 if (ui_browser__input_window("Percent Limit",
2828 "Please enter the value you want to hide entries under that percent.",
2829 buf, "ENTER: OK, ESC: Cancel",
2830 delay_secs * 2) == K_ENTER) {
2831 char *end;
2832 double new_percent = strtod(buf, &end);
2833
2834 if (new_percent < 0 || new_percent > 100) {
2835 ui_browser__warning(&browser->b, delay_secs * 2,
2836 "Invalid percent: %.2f", new_percent);
2837 continue;
2838 }
2839
2840 hist_browser__update_percent_limit(browser, new_percent);
2841 hist_browser__reset(browser);
2842 }
2843 continue;
2195 case K_F1: 2844 case K_F1:
2196 case 'h': 2845 case 'h':
2197 case '?': 2846 case '?':
@@ -2263,10 +2912,7 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
2263 continue; 2912 continue;
2264 } 2913 }
2265 2914
2266 if (!sort__has_sym) 2915 if (!sort__has_sym || browser->selection == NULL)
2267 goto add_exit_option;
2268
2269 if (browser->selection == NULL)
2270 goto skip_annotation; 2916 goto skip_annotation;
2271 2917
2272 if (sort__mode == SORT_MODE__BRANCH) { 2918 if (sort__mode == SORT_MODE__BRANCH) {
@@ -2306,11 +2952,16 @@ skip_annotation:
2306 &options[nr_options], 2952 &options[nr_options],
2307 socked_id); 2953 socked_id);
2308 /* perf script support */ 2954 /* perf script support */
2955 if (!is_report_browser(hbt))
2956 goto skip_scripting;
2957
2309 if (browser->he_selection) { 2958 if (browser->he_selection) {
2310 nr_options += add_script_opt(browser, 2959 if (sort__has_thread && thread) {
2311 &actions[nr_options], 2960 nr_options += add_script_opt(browser,
2312 &options[nr_options], 2961 &actions[nr_options],
2313 thread, NULL); 2962 &options[nr_options],
2963 thread, NULL);
2964 }
2314 /* 2965 /*
2315 * Note that browser->selection != NULL 2966 * Note that browser->selection != NULL
2316 * when browser->he_selection is not NULL, 2967 * when browser->he_selection is not NULL,
@@ -2320,16 +2971,18 @@ skip_annotation:
2320 * 2971 *
2321 * See hist_browser__show_entry. 2972 * See hist_browser__show_entry.
2322 */ 2973 */
2323 nr_options += add_script_opt(browser, 2974 if (sort__has_sym && browser->selection->sym) {
2324 &actions[nr_options], 2975 nr_options += add_script_opt(browser,
2325 &options[nr_options], 2976 &actions[nr_options],
2326 NULL, browser->selection->sym); 2977 &options[nr_options],
2978 NULL, browser->selection->sym);
2979 }
2327 } 2980 }
2328 nr_options += add_script_opt(browser, &actions[nr_options], 2981 nr_options += add_script_opt(browser, &actions[nr_options],
2329 &options[nr_options], NULL, NULL); 2982 &options[nr_options], NULL, NULL);
2330 nr_options += add_switch_opt(browser, &actions[nr_options], 2983 nr_options += add_switch_opt(browser, &actions[nr_options],
2331 &options[nr_options]); 2984 &options[nr_options]);
2332add_exit_option: 2985skip_scripting:
2333 nr_options += add_exit_opt(browser, &actions[nr_options], 2986 nr_options += add_exit_opt(browser, &actions[nr_options],
2334 &options[nr_options]); 2987 &options[nr_options]);
2335 2988
diff --git a/tools/perf/ui/gtk/hists.c b/tools/perf/ui/gtk/hists.c
index 0f8dcfdfb10f..2aa45b606fa4 100644
--- a/tools/perf/ui/gtk/hists.c
+++ b/tools/perf/ui/gtk/hists.c
@@ -55,7 +55,7 @@ static u64 he_get_acc_##_field(struct hist_entry *he) \
55 return he->stat_acc->_field; \ 55 return he->stat_acc->_field; \
56} \ 56} \
57 \ 57 \
58static int perf_gtk__hpp_color_##_type(struct perf_hpp_fmt *fmt __maybe_unused, \ 58static int perf_gtk__hpp_color_##_type(struct perf_hpp_fmt *fmt, \
59 struct perf_hpp *hpp, \ 59 struct perf_hpp *hpp, \
60 struct hist_entry *he) \ 60 struct hist_entry *he) \
61{ \ 61{ \
@@ -306,7 +306,7 @@ static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists,
306 306
307 nr_cols = 0; 307 nr_cols = 0;
308 308
309 perf_hpp__for_each_format(fmt) 309 hists__for_each_format(hists, fmt)
310 col_types[nr_cols++] = G_TYPE_STRING; 310 col_types[nr_cols++] = G_TYPE_STRING;
311 311
312 store = gtk_tree_store_newv(nr_cols, col_types); 312 store = gtk_tree_store_newv(nr_cols, col_types);
@@ -317,7 +317,7 @@ static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists,
317 317
318 col_idx = 0; 318 col_idx = 0;
319 319
320 perf_hpp__for_each_format(fmt) { 320 hists__for_each_format(hists, fmt) {
321 if (perf_hpp__should_skip(fmt, hists)) 321 if (perf_hpp__should_skip(fmt, hists))
322 continue; 322 continue;
323 323
@@ -367,7 +367,7 @@ static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists,
367 367
368 col_idx = 0; 368 col_idx = 0;
369 369
370 perf_hpp__for_each_format(fmt) { 370 hists__for_each_format(hists, fmt) {
371 if (perf_hpp__should_skip(fmt, h->hists)) 371 if (perf_hpp__should_skip(fmt, h->hists))
372 continue; 372 continue;
373 373
@@ -396,6 +396,194 @@ static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists,
396 gtk_container_add(GTK_CONTAINER(window), view); 396 gtk_container_add(GTK_CONTAINER(window), view);
397} 397}
398 398
399static void perf_gtk__add_hierarchy_entries(struct hists *hists,
400 struct rb_root *root,
401 GtkTreeStore *store,
402 GtkTreeIter *parent,
403 struct perf_hpp *hpp,
404 float min_pcnt)
405{
406 int col_idx = 0;
407 struct rb_node *node;
408 struct hist_entry *he;
409 struct perf_hpp_fmt *fmt;
410 struct perf_hpp_list_node *fmt_node;
411 u64 total = hists__total_period(hists);
412 int size;
413
414 for (node = rb_first(root); node; node = rb_next(node)) {
415 GtkTreeIter iter;
416 float percent;
417 char *bf;
418
419 he = rb_entry(node, struct hist_entry, rb_node);
420 if (he->filtered)
421 continue;
422
423 percent = hist_entry__get_percent_limit(he);
424 if (percent < min_pcnt)
425 continue;
426
427 gtk_tree_store_append(store, &iter, parent);
428
429 col_idx = 0;
430
431 /* the first hpp_list_node is for overhead columns */
432 fmt_node = list_first_entry(&hists->hpp_formats,
433 struct perf_hpp_list_node, list);
434 perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) {
435 if (fmt->color)
436 fmt->color(fmt, hpp, he);
437 else
438 fmt->entry(fmt, hpp, he);
439
440 gtk_tree_store_set(store, &iter, col_idx++, hpp->buf, -1);
441 }
442
443 bf = hpp->buf;
444 size = hpp->size;
445 perf_hpp_list__for_each_format(he->hpp_list, fmt) {
446 int ret;
447
448 if (fmt->color)
449 ret = fmt->color(fmt, hpp, he);
450 else
451 ret = fmt->entry(fmt, hpp, he);
452
453 snprintf(hpp->buf + ret, hpp->size - ret, " ");
454 advance_hpp(hpp, ret + 2);
455 }
456
457 gtk_tree_store_set(store, &iter, col_idx, ltrim(rtrim(bf)), -1);
458
459 if (!he->leaf) {
460 hpp->buf = bf;
461 hpp->size = size;
462
463 perf_gtk__add_hierarchy_entries(hists, &he->hroot_out,
464 store, &iter, hpp,
465 min_pcnt);
466
467 if (!hist_entry__has_hierarchy_children(he, min_pcnt)) {
468 char buf[32];
469 GtkTreeIter child;
470
471 snprintf(buf, sizeof(buf), "no entry >= %.2f%%",
472 min_pcnt);
473
474 gtk_tree_store_append(store, &child, &iter);
475 gtk_tree_store_set(store, &child, col_idx, buf, -1);
476 }
477 }
478
479 if (symbol_conf.use_callchain && he->leaf) {
480 if (callchain_param.mode == CHAIN_GRAPH_REL)
481 total = symbol_conf.cumulate_callchain ?
482 he->stat_acc->period : he->stat.period;
483
484 perf_gtk__add_callchain(&he->sorted_chain, store, &iter,
485 col_idx, total);
486 }
487 }
488
489}
490
491static void perf_gtk__show_hierarchy(GtkWidget *window, struct hists *hists,
492 float min_pcnt)
493{
494 struct perf_hpp_fmt *fmt;
495 struct perf_hpp_list_node *fmt_node;
496 GType col_types[MAX_COLUMNS];
497 GtkCellRenderer *renderer;
498 GtkTreeStore *store;
499 GtkWidget *view;
500 int col_idx;
501 int nr_cols = 0;
502 char s[512];
503 char buf[512];
504 bool first_node, first_col;
505 struct perf_hpp hpp = {
506 .buf = s,
507 .size = sizeof(s),
508 };
509
510 hists__for_each_format(hists, fmt) {
511 if (perf_hpp__is_sort_entry(fmt) ||
512 perf_hpp__is_dynamic_entry(fmt))
513 break;
514
515 col_types[nr_cols++] = G_TYPE_STRING;
516 }
517 col_types[nr_cols++] = G_TYPE_STRING;
518
519 store = gtk_tree_store_newv(nr_cols, col_types);
520 view = gtk_tree_view_new();
521 renderer = gtk_cell_renderer_text_new();
522
523 col_idx = 0;
524
525 /* the first hpp_list_node is for overhead columns */
526 fmt_node = list_first_entry(&hists->hpp_formats,
527 struct perf_hpp_list_node, list);
528 perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) {
529 gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view),
530 -1, fmt->name,
531 renderer, "markup",
532 col_idx++, NULL);
533 }
534
535 /* construct merged column header since sort keys share single column */
536 buf[0] = '\0';
537 first_node = true;
538 list_for_each_entry_continue(fmt_node, &hists->hpp_formats, list) {
539 if (!first_node)
540 strcat(buf, " / ");
541 first_node = false;
542
543 first_col = true;
544 perf_hpp_list__for_each_format(&fmt_node->hpp ,fmt) {
545 if (perf_hpp__should_skip(fmt, hists))
546 continue;
547
548 if (!first_col)
549 strcat(buf, "+");
550 first_col = false;
551
552 fmt->header(fmt, &hpp, hists_to_evsel(hists));
553 strcat(buf, ltrim(rtrim(hpp.buf)));
554 }
555 }
556
557 gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view),
558 -1, buf,
559 renderer, "markup",
560 col_idx++, NULL);
561
562 for (col_idx = 0; col_idx < nr_cols; col_idx++) {
563 GtkTreeViewColumn *column;
564
565 column = gtk_tree_view_get_column(GTK_TREE_VIEW(view), col_idx);
566 gtk_tree_view_column_set_resizable(column, TRUE);
567
568 if (col_idx == 0) {
569 gtk_tree_view_set_expander_column(GTK_TREE_VIEW(view),
570 column);
571 }
572 }
573
574 gtk_tree_view_set_model(GTK_TREE_VIEW(view), GTK_TREE_MODEL(store));
575 g_object_unref(GTK_TREE_MODEL(store));
576
577 perf_gtk__add_hierarchy_entries(hists, &hists->entries, store,
578 NULL, &hpp, min_pcnt);
579
580 gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(view), TRUE);
581
582 g_signal_connect(view, "row-activated",
583 G_CALLBACK(on_row_activated), NULL);
584 gtk_container_add(GTK_CONTAINER(window), view);
585}
586
399int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist, 587int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist,
400 const char *help, 588 const char *help,
401 struct hist_browser_timer *hbt __maybe_unused, 589 struct hist_browser_timer *hbt __maybe_unused,
@@ -463,7 +651,10 @@ int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist,
463 GTK_POLICY_AUTOMATIC, 651 GTK_POLICY_AUTOMATIC,
464 GTK_POLICY_AUTOMATIC); 652 GTK_POLICY_AUTOMATIC);
465 653
466 perf_gtk__show_hists(scrolled_window, hists, min_pcnt); 654 if (symbol_conf.report_hierarchy)
655 perf_gtk__show_hierarchy(scrolled_window, hists, min_pcnt);
656 else
657 perf_gtk__show_hists(scrolled_window, hists, min_pcnt);
467 658
468 tab_label = gtk_label_new(evname); 659 tab_label = gtk_label_new(evname);
469 660
diff --git a/tools/perf/ui/hist.c b/tools/perf/ui/hist.c
index bf2a66e254ea..3baeaa6e71b5 100644
--- a/tools/perf/ui/hist.c
+++ b/tools/perf/ui/hist.c
@@ -5,6 +5,7 @@
5#include "../util/util.h" 5#include "../util/util.h"
6#include "../util/sort.h" 6#include "../util/sort.h"
7#include "../util/evsel.h" 7#include "../util/evsel.h"
8#include "../util/evlist.h"
8 9
9/* hist period print (hpp) functions */ 10/* hist period print (hpp) functions */
10 11
@@ -371,7 +372,20 @@ static int64_t hpp__nop_cmp(struct perf_hpp_fmt *fmt __maybe_unused,
371 return 0; 372 return 0;
372} 373}
373 374
374#define HPP__COLOR_PRINT_FNS(_name, _fn) \ 375static bool perf_hpp__is_hpp_entry(struct perf_hpp_fmt *a)
376{
377 return a->header == hpp__header_fn;
378}
379
380static bool hpp__equal(struct perf_hpp_fmt *a, struct perf_hpp_fmt *b)
381{
382 if (!perf_hpp__is_hpp_entry(a) || !perf_hpp__is_hpp_entry(b))
383 return false;
384
385 return a->idx == b->idx;
386}
387
388#define HPP__COLOR_PRINT_FNS(_name, _fn, _idx) \
375 { \ 389 { \
376 .name = _name, \ 390 .name = _name, \
377 .header = hpp__header_fn, \ 391 .header = hpp__header_fn, \
@@ -381,9 +395,11 @@ static int64_t hpp__nop_cmp(struct perf_hpp_fmt *fmt __maybe_unused,
381 .cmp = hpp__nop_cmp, \ 395 .cmp = hpp__nop_cmp, \
382 .collapse = hpp__nop_cmp, \ 396 .collapse = hpp__nop_cmp, \
383 .sort = hpp__sort_ ## _fn, \ 397 .sort = hpp__sort_ ## _fn, \
398 .idx = PERF_HPP__ ## _idx, \
399 .equal = hpp__equal, \
384 } 400 }
385 401
386#define HPP__COLOR_ACC_PRINT_FNS(_name, _fn) \ 402#define HPP__COLOR_ACC_PRINT_FNS(_name, _fn, _idx) \
387 { \ 403 { \
388 .name = _name, \ 404 .name = _name, \
389 .header = hpp__header_fn, \ 405 .header = hpp__header_fn, \
@@ -393,9 +409,11 @@ static int64_t hpp__nop_cmp(struct perf_hpp_fmt *fmt __maybe_unused,
393 .cmp = hpp__nop_cmp, \ 409 .cmp = hpp__nop_cmp, \
394 .collapse = hpp__nop_cmp, \ 410 .collapse = hpp__nop_cmp, \
395 .sort = hpp__sort_ ## _fn, \ 411 .sort = hpp__sort_ ## _fn, \
412 .idx = PERF_HPP__ ## _idx, \
413 .equal = hpp__equal, \
396 } 414 }
397 415
398#define HPP__PRINT_FNS(_name, _fn) \ 416#define HPP__PRINT_FNS(_name, _fn, _idx) \
399 { \ 417 { \
400 .name = _name, \ 418 .name = _name, \
401 .header = hpp__header_fn, \ 419 .header = hpp__header_fn, \
@@ -404,22 +422,25 @@ static int64_t hpp__nop_cmp(struct perf_hpp_fmt *fmt __maybe_unused,
404 .cmp = hpp__nop_cmp, \ 422 .cmp = hpp__nop_cmp, \
405 .collapse = hpp__nop_cmp, \ 423 .collapse = hpp__nop_cmp, \
406 .sort = hpp__sort_ ## _fn, \ 424 .sort = hpp__sort_ ## _fn, \
425 .idx = PERF_HPP__ ## _idx, \
426 .equal = hpp__equal, \
407 } 427 }
408 428
409struct perf_hpp_fmt perf_hpp__format[] = { 429struct perf_hpp_fmt perf_hpp__format[] = {
410 HPP__COLOR_PRINT_FNS("Overhead", overhead), 430 HPP__COLOR_PRINT_FNS("Overhead", overhead, OVERHEAD),
411 HPP__COLOR_PRINT_FNS("sys", overhead_sys), 431 HPP__COLOR_PRINT_FNS("sys", overhead_sys, OVERHEAD_SYS),
412 HPP__COLOR_PRINT_FNS("usr", overhead_us), 432 HPP__COLOR_PRINT_FNS("usr", overhead_us, OVERHEAD_US),
413 HPP__COLOR_PRINT_FNS("guest sys", overhead_guest_sys), 433 HPP__COLOR_PRINT_FNS("guest sys", overhead_guest_sys, OVERHEAD_GUEST_SYS),
414 HPP__COLOR_PRINT_FNS("guest usr", overhead_guest_us), 434 HPP__COLOR_PRINT_FNS("guest usr", overhead_guest_us, OVERHEAD_GUEST_US),
415 HPP__COLOR_ACC_PRINT_FNS("Children", overhead_acc), 435 HPP__COLOR_ACC_PRINT_FNS("Children", overhead_acc, OVERHEAD_ACC),
416 HPP__PRINT_FNS("Samples", samples), 436 HPP__PRINT_FNS("Samples", samples, SAMPLES),
417 HPP__PRINT_FNS("Period", period) 437 HPP__PRINT_FNS("Period", period, PERIOD)
418}; 438};
419 439
420LIST_HEAD(perf_hpp__list); 440struct perf_hpp_list perf_hpp_list = {
421LIST_HEAD(perf_hpp__sort_list); 441 .fields = LIST_HEAD_INIT(perf_hpp_list.fields),
422 442 .sorts = LIST_HEAD_INIT(perf_hpp_list.sorts),
443};
423 444
424#undef HPP__COLOR_PRINT_FNS 445#undef HPP__COLOR_PRINT_FNS
425#undef HPP__COLOR_ACC_PRINT_FNS 446#undef HPP__COLOR_ACC_PRINT_FNS
@@ -485,63 +506,60 @@ void perf_hpp__init(void)
485 hpp_dimension__add_output(PERF_HPP__PERIOD); 506 hpp_dimension__add_output(PERF_HPP__PERIOD);
486} 507}
487 508
488void perf_hpp__column_register(struct perf_hpp_fmt *format) 509void perf_hpp_list__column_register(struct perf_hpp_list *list,
510 struct perf_hpp_fmt *format)
489{ 511{
490 list_add_tail(&format->list, &perf_hpp__list); 512 list_add_tail(&format->list, &list->fields);
491} 513}
492 514
493void perf_hpp__column_unregister(struct perf_hpp_fmt *format) 515void perf_hpp_list__register_sort_field(struct perf_hpp_list *list,
516 struct perf_hpp_fmt *format)
494{ 517{
495 list_del(&format->list); 518 list_add_tail(&format->sort_list, &list->sorts);
496} 519}
497 520
498void perf_hpp__register_sort_field(struct perf_hpp_fmt *format) 521void perf_hpp__column_unregister(struct perf_hpp_fmt *format)
499{
500 list_add_tail(&format->sort_list, &perf_hpp__sort_list);
501}
502
503void perf_hpp__column_enable(unsigned col)
504{
505 BUG_ON(col >= PERF_HPP__MAX_INDEX);
506 perf_hpp__column_register(&perf_hpp__format[col]);
507}
508
509void perf_hpp__column_disable(unsigned col)
510{ 522{
511 BUG_ON(col >= PERF_HPP__MAX_INDEX); 523 list_del(&format->list);
512 perf_hpp__column_unregister(&perf_hpp__format[col]);
513} 524}
514 525
515void perf_hpp__cancel_cumulate(void) 526void perf_hpp__cancel_cumulate(void)
516{ 527{
528 struct perf_hpp_fmt *fmt, *acc, *ovh, *tmp;
529
517 if (is_strict_order(field_order)) 530 if (is_strict_order(field_order))
518 return; 531 return;
519 532
520 perf_hpp__column_disable(PERF_HPP__OVERHEAD_ACC); 533 ovh = &perf_hpp__format[PERF_HPP__OVERHEAD];
521 perf_hpp__format[PERF_HPP__OVERHEAD].name = "Overhead"; 534 acc = &perf_hpp__format[PERF_HPP__OVERHEAD_ACC];
535
536 perf_hpp_list__for_each_format_safe(&perf_hpp_list, fmt, tmp) {
537 if (acc->equal(acc, fmt)) {
538 perf_hpp__column_unregister(fmt);
539 continue;
540 }
541
542 if (ovh->equal(ovh, fmt))
543 fmt->name = "Overhead";
544 }
522} 545}
523 546
524void perf_hpp__setup_output_field(void) 547static bool fmt_equal(struct perf_hpp_fmt *a, struct perf_hpp_fmt *b)
548{
549 return a->equal && a->equal(a, b);
550}
551
552void perf_hpp__setup_output_field(struct perf_hpp_list *list)
525{ 553{
526 struct perf_hpp_fmt *fmt; 554 struct perf_hpp_fmt *fmt;
527 555
528 /* append sort keys to output field */ 556 /* append sort keys to output field */
529 perf_hpp__for_each_sort_list(fmt) { 557 perf_hpp_list__for_each_sort_list(list, fmt) {
530 if (!list_empty(&fmt->list)) 558 struct perf_hpp_fmt *pos;
531 continue;
532
533 /*
534 * sort entry fields are dynamically created,
535 * so they can share a same sort key even though
536 * the list is empty.
537 */
538 if (perf_hpp__is_sort_entry(fmt)) {
539 struct perf_hpp_fmt *pos;
540 559
541 perf_hpp__for_each_format(pos) { 560 perf_hpp_list__for_each_format(list, pos) {
542 if (perf_hpp__same_sort_entry(pos, fmt)) 561 if (fmt_equal(fmt, pos))
543 goto next; 562 goto next;
544 }
545 } 563 }
546 564
547 perf_hpp__column_register(fmt); 565 perf_hpp__column_register(fmt);
@@ -550,27 +568,17 @@ next:
550 } 568 }
551} 569}
552 570
553void perf_hpp__append_sort_keys(void) 571void perf_hpp__append_sort_keys(struct perf_hpp_list *list)
554{ 572{
555 struct perf_hpp_fmt *fmt; 573 struct perf_hpp_fmt *fmt;
556 574
557 /* append output fields to sort keys */ 575 /* append output fields to sort keys */
558 perf_hpp__for_each_format(fmt) { 576 perf_hpp_list__for_each_format(list, fmt) {
559 if (!list_empty(&fmt->sort_list)) 577 struct perf_hpp_fmt *pos;
560 continue;
561
562 /*
563 * sort entry fields are dynamically created,
564 * so they can share a same sort key even though
565 * the list is empty.
566 */
567 if (perf_hpp__is_sort_entry(fmt)) {
568 struct perf_hpp_fmt *pos;
569 578
570 perf_hpp__for_each_sort_list(pos) { 579 perf_hpp_list__for_each_sort_list(list, pos) {
571 if (perf_hpp__same_sort_entry(pos, fmt)) 580 if (fmt_equal(fmt, pos))
572 goto next; 581 goto next;
573 }
574 } 582 }
575 583
576 perf_hpp__register_sort_field(fmt); 584 perf_hpp__register_sort_field(fmt);
@@ -579,20 +587,29 @@ next:
579 } 587 }
580} 588}
581 589
582void perf_hpp__reset_output_field(void) 590
591static void fmt_free(struct perf_hpp_fmt *fmt)
592{
593 if (fmt->free)
594 fmt->free(fmt);
595}
596
597void perf_hpp__reset_output_field(struct perf_hpp_list *list)
583{ 598{
584 struct perf_hpp_fmt *fmt, *tmp; 599 struct perf_hpp_fmt *fmt, *tmp;
585 600
586 /* reset output fields */ 601 /* reset output fields */
587 perf_hpp__for_each_format_safe(fmt, tmp) { 602 perf_hpp_list__for_each_format_safe(list, fmt, tmp) {
588 list_del_init(&fmt->list); 603 list_del_init(&fmt->list);
589 list_del_init(&fmt->sort_list); 604 list_del_init(&fmt->sort_list);
605 fmt_free(fmt);
590 } 606 }
591 607
592 /* reset sort keys */ 608 /* reset sort keys */
593 perf_hpp__for_each_sort_list_safe(fmt, tmp) { 609 perf_hpp_list__for_each_sort_list_safe(list, fmt, tmp) {
594 list_del_init(&fmt->list); 610 list_del_init(&fmt->list);
595 list_del_init(&fmt->sort_list); 611 list_del_init(&fmt->sort_list);
612 fmt_free(fmt);
596 } 613 }
597} 614}
598 615
@@ -606,7 +623,7 @@ unsigned int hists__sort_list_width(struct hists *hists)
606 bool first = true; 623 bool first = true;
607 struct perf_hpp dummy_hpp; 624 struct perf_hpp dummy_hpp;
608 625
609 perf_hpp__for_each_format(fmt) { 626 hists__for_each_format(hists, fmt) {
610 if (perf_hpp__should_skip(fmt, hists)) 627 if (perf_hpp__should_skip(fmt, hists))
611 continue; 628 continue;
612 629
@@ -624,22 +641,39 @@ unsigned int hists__sort_list_width(struct hists *hists)
624 return ret; 641 return ret;
625} 642}
626 643
627void perf_hpp__reset_width(struct perf_hpp_fmt *fmt, struct hists *hists) 644unsigned int hists__overhead_width(struct hists *hists)
628{ 645{
629 int idx; 646 struct perf_hpp_fmt *fmt;
630 647 int ret = 0;
631 if (perf_hpp__is_sort_entry(fmt)) 648 bool first = true;
632 return perf_hpp__reset_sort_width(fmt, hists); 649 struct perf_hpp dummy_hpp;
633 650
634 for (idx = 0; idx < PERF_HPP__MAX_INDEX; idx++) { 651 hists__for_each_format(hists, fmt) {
635 if (fmt == &perf_hpp__format[idx]) 652 if (perf_hpp__is_sort_entry(fmt) || perf_hpp__is_dynamic_entry(fmt))
636 break; 653 break;
654
655 if (first)
656 first = false;
657 else
658 ret += 2;
659
660 ret += fmt->width(fmt, &dummy_hpp, hists_to_evsel(hists));
637 } 661 }
638 662
639 if (idx == PERF_HPP__MAX_INDEX) 663 return ret;
664}
665
666void perf_hpp__reset_width(struct perf_hpp_fmt *fmt, struct hists *hists)
667{
668 if (perf_hpp__is_sort_entry(fmt))
669 return perf_hpp__reset_sort_width(fmt, hists);
670
671 if (perf_hpp__is_dynamic_entry(fmt))
640 return; 672 return;
641 673
642 switch (idx) { 674 BUG_ON(fmt->idx >= PERF_HPP__MAX_INDEX);
675
676 switch (fmt->idx) {
643 case PERF_HPP__OVERHEAD: 677 case PERF_HPP__OVERHEAD:
644 case PERF_HPP__OVERHEAD_SYS: 678 case PERF_HPP__OVERHEAD_SYS:
645 case PERF_HPP__OVERHEAD_US: 679 case PERF_HPP__OVERHEAD_US:
@@ -667,7 +701,7 @@ void perf_hpp__set_user_width(const char *width_list_str)
667 struct perf_hpp_fmt *fmt; 701 struct perf_hpp_fmt *fmt;
668 const char *ptr = width_list_str; 702 const char *ptr = width_list_str;
669 703
670 perf_hpp__for_each_format(fmt) { 704 perf_hpp_list__for_each_format(&perf_hpp_list, fmt) {
671 char *p; 705 char *p;
672 706
673 int len = strtol(ptr, &p, 10); 707 int len = strtol(ptr, &p, 10);
@@ -679,3 +713,71 @@ void perf_hpp__set_user_width(const char *width_list_str)
679 break; 713 break;
680 } 714 }
681} 715}
716
717static int add_hierarchy_fmt(struct hists *hists, struct perf_hpp_fmt *fmt)
718{
719 struct perf_hpp_list_node *node = NULL;
720 struct perf_hpp_fmt *fmt_copy;
721 bool found = false;
722 bool skip = perf_hpp__should_skip(fmt, hists);
723
724 list_for_each_entry(node, &hists->hpp_formats, list) {
725 if (node->level == fmt->level) {
726 found = true;
727 break;
728 }
729 }
730
731 if (!found) {
732 node = malloc(sizeof(*node));
733 if (node == NULL)
734 return -1;
735
736 node->skip = skip;
737 node->level = fmt->level;
738 perf_hpp_list__init(&node->hpp);
739
740 hists->nr_hpp_node++;
741 list_add_tail(&node->list, &hists->hpp_formats);
742 }
743
744 fmt_copy = perf_hpp_fmt__dup(fmt);
745 if (fmt_copy == NULL)
746 return -1;
747
748 if (!skip)
749 node->skip = false;
750
751 list_add_tail(&fmt_copy->list, &node->hpp.fields);
752 list_add_tail(&fmt_copy->sort_list, &node->hpp.sorts);
753
754 return 0;
755}
756
757int perf_hpp__setup_hists_formats(struct perf_hpp_list *list,
758 struct perf_evlist *evlist)
759{
760 struct perf_evsel *evsel;
761 struct perf_hpp_fmt *fmt;
762 struct hists *hists;
763 int ret;
764
765 if (!symbol_conf.report_hierarchy)
766 return 0;
767
768 evlist__for_each(evlist, evsel) {
769 hists = evsel__hists(evsel);
770
771 perf_hpp_list__for_each_sort_list(list, fmt) {
772 if (perf_hpp__is_dynamic_entry(fmt) &&
773 !perf_hpp__defined_dynamic_entry(fmt, hists))
774 continue;
775
776 ret = add_hierarchy_fmt(hists, fmt);
777 if (ret < 0)
778 return ret;
779 }
780 }
781
782 return 0;
783}
diff --git a/tools/perf/ui/stdio/hist.c b/tools/perf/ui/stdio/hist.c
index 387110d50b00..7aff5acf3265 100644
--- a/tools/perf/ui/stdio/hist.c
+++ b/tools/perf/ui/stdio/hist.c
@@ -165,8 +165,28 @@ static size_t __callchain__fprintf_graph(FILE *fp, struct rb_root *root,
165 return ret; 165 return ret;
166} 166}
167 167
168/*
169 * If have one single callchain root, don't bother printing
170 * its percentage (100 % in fractal mode and the same percentage
171 * than the hist in graph mode). This also avoid one level of column.
172 *
173 * However when percent-limit applied, it's possible that single callchain
174 * node have different (non-100% in fractal mode) percentage.
175 */
176static bool need_percent_display(struct rb_node *node, u64 parent_samples)
177{
178 struct callchain_node *cnode;
179
180 if (rb_next(node))
181 return true;
182
183 cnode = rb_entry(node, struct callchain_node, rb_node);
184 return callchain_cumul_hits(cnode) != parent_samples;
185}
186
168static size_t callchain__fprintf_graph(FILE *fp, struct rb_root *root, 187static size_t callchain__fprintf_graph(FILE *fp, struct rb_root *root,
169 u64 total_samples, int left_margin) 188 u64 total_samples, u64 parent_samples,
189 int left_margin)
170{ 190{
171 struct callchain_node *cnode; 191 struct callchain_node *cnode;
172 struct callchain_list *chain; 192 struct callchain_list *chain;
@@ -177,13 +197,8 @@ static size_t callchain__fprintf_graph(FILE *fp, struct rb_root *root,
177 int ret = 0; 197 int ret = 0;
178 char bf[1024]; 198 char bf[1024];
179 199
180 /*
181 * If have one single callchain root, don't bother printing
182 * its percentage (100 % in fractal mode and the same percentage
183 * than the hist in graph mode). This also avoid one level of column.
184 */
185 node = rb_first(root); 200 node = rb_first(root);
186 if (node && !rb_next(node)) { 201 if (node && !need_percent_display(node, parent_samples)) {
187 cnode = rb_entry(node, struct callchain_node, rb_node); 202 cnode = rb_entry(node, struct callchain_node, rb_node);
188 list_for_each_entry(chain, &cnode->val, list) { 203 list_for_each_entry(chain, &cnode->val, list) {
189 /* 204 /*
@@ -213,9 +228,15 @@ static size_t callchain__fprintf_graph(FILE *fp, struct rb_root *root,
213 root = &cnode->rb_root; 228 root = &cnode->rb_root;
214 } 229 }
215 230
231 if (callchain_param.mode == CHAIN_GRAPH_REL)
232 total_samples = parent_samples;
233
216 ret += __callchain__fprintf_graph(fp, root, total_samples, 234 ret += __callchain__fprintf_graph(fp, root, total_samples,
217 1, 1, left_margin); 235 1, 1, left_margin);
218 ret += fprintf(fp, "\n"); 236 if (ret) {
237 /* do not add a blank line if it printed nothing */
238 ret += fprintf(fp, "\n");
239 }
219 240
220 return ret; 241 return ret;
221} 242}
@@ -323,16 +344,19 @@ static size_t hist_entry_callchain__fprintf(struct hist_entry *he,
323 u64 total_samples, int left_margin, 344 u64 total_samples, int left_margin,
324 FILE *fp) 345 FILE *fp)
325{ 346{
347 u64 parent_samples = he->stat.period;
348
349 if (symbol_conf.cumulate_callchain)
350 parent_samples = he->stat_acc->period;
351
326 switch (callchain_param.mode) { 352 switch (callchain_param.mode) {
327 case CHAIN_GRAPH_REL: 353 case CHAIN_GRAPH_REL:
328 return callchain__fprintf_graph(fp, &he->sorted_chain, 354 return callchain__fprintf_graph(fp, &he->sorted_chain, total_samples,
329 symbol_conf.cumulate_callchain ? 355 parent_samples, left_margin);
330 he->stat_acc->period : he->stat.period,
331 left_margin);
332 break; 356 break;
333 case CHAIN_GRAPH_ABS: 357 case CHAIN_GRAPH_ABS:
334 return callchain__fprintf_graph(fp, &he->sorted_chain, total_samples, 358 return callchain__fprintf_graph(fp, &he->sorted_chain, total_samples,
335 left_margin); 359 parent_samples, left_margin);
336 break; 360 break;
337 case CHAIN_FLAT: 361 case CHAIN_FLAT:
338 return callchain__fprintf_flat(fp, &he->sorted_chain, total_samples); 362 return callchain__fprintf_flat(fp, &he->sorted_chain, total_samples);
@@ -349,45 +373,66 @@ static size_t hist_entry_callchain__fprintf(struct hist_entry *he,
349 return 0; 373 return 0;
350} 374}
351 375
352static size_t hist_entry__callchain_fprintf(struct hist_entry *he, 376static int hist_entry__snprintf(struct hist_entry *he, struct perf_hpp *hpp)
353 struct hists *hists,
354 FILE *fp)
355{ 377{
356 int left_margin = 0; 378 const char *sep = symbol_conf.field_sep;
357 u64 total_period = hists->stats.total_period; 379 struct perf_hpp_fmt *fmt;
380 char *start = hpp->buf;
381 int ret;
382 bool first = true;
358 383
359 if (field_order == NULL && (sort_order == NULL || 384 if (symbol_conf.exclude_other && !he->parent)
360 !prefixcmp(sort_order, "comm"))) { 385 return 0;
361 struct perf_hpp_fmt *fmt;
362 386
363 perf_hpp__for_each_format(fmt) { 387 hists__for_each_format(he->hists, fmt) {
364 if (!perf_hpp__is_sort_entry(fmt)) 388 if (perf_hpp__should_skip(fmt, he->hists))
365 continue; 389 continue;
366 390
367 /* must be 'comm' sort entry */ 391 /*
368 left_margin = fmt->width(fmt, NULL, hists_to_evsel(hists)); 392 * If there's no field_sep, we still need
369 left_margin -= thread__comm_len(he->thread); 393 * to display initial ' '.
370 break; 394 */
371 } 395 if (!sep || !first) {
396 ret = scnprintf(hpp->buf, hpp->size, "%s", sep ?: " ");
397 advance_hpp(hpp, ret);
398 } else
399 first = false;
400
401 if (perf_hpp__use_color() && fmt->color)
402 ret = fmt->color(fmt, hpp, he);
403 else
404 ret = fmt->entry(fmt, hpp, he);
405
406 ret = hist_entry__snprintf_alignment(he, hpp, fmt, ret);
407 advance_hpp(hpp, ret);
372 } 408 }
373 return hist_entry_callchain__fprintf(he, total_period, left_margin, fp); 409
410 return hpp->buf - start;
374} 411}
375 412
376static int hist_entry__snprintf(struct hist_entry *he, struct perf_hpp *hpp) 413static int hist_entry__hierarchy_fprintf(struct hist_entry *he,
414 struct perf_hpp *hpp,
415 struct hists *hists,
416 FILE *fp)
377{ 417{
378 const char *sep = symbol_conf.field_sep; 418 const char *sep = symbol_conf.field_sep;
379 struct perf_hpp_fmt *fmt; 419 struct perf_hpp_fmt *fmt;
380 char *start = hpp->buf; 420 struct perf_hpp_list_node *fmt_node;
381 int ret; 421 char *buf = hpp->buf;
422 size_t size = hpp->size;
423 int ret, printed = 0;
382 bool first = true; 424 bool first = true;
383 425
384 if (symbol_conf.exclude_other && !he->parent) 426 if (symbol_conf.exclude_other && !he->parent)
385 return 0; 427 return 0;
386 428
387 perf_hpp__for_each_format(fmt) { 429 ret = scnprintf(hpp->buf, hpp->size, "%*s", he->depth * HIERARCHY_INDENT, "");
388 if (perf_hpp__should_skip(fmt, he->hists)) 430 advance_hpp(hpp, ret);
389 continue;
390 431
432 /* the first hpp_list_node is for overhead columns */
433 fmt_node = list_first_entry(&hists->hpp_formats,
434 struct perf_hpp_list_node, list);
435 perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) {
391 /* 436 /*
392 * If there's no field_sep, we still need 437 * If there's no field_sep, we still need
393 * to display initial ' '. 438 * to display initial ' '.
@@ -403,10 +448,47 @@ static int hist_entry__snprintf(struct hist_entry *he, struct perf_hpp *hpp)
403 else 448 else
404 ret = fmt->entry(fmt, hpp, he); 449 ret = fmt->entry(fmt, hpp, he);
405 450
451 ret = hist_entry__snprintf_alignment(he, hpp, fmt, ret);
406 advance_hpp(hpp, ret); 452 advance_hpp(hpp, ret);
407 } 453 }
408 454
409 return hpp->buf - start; 455 if (!sep)
456 ret = scnprintf(hpp->buf, hpp->size, "%*s",
457 (hists->nr_hpp_node - 2) * HIERARCHY_INDENT, "");
458 advance_hpp(hpp, ret);
459
460 printed += fprintf(fp, "%s", buf);
461
462 perf_hpp_list__for_each_format(he->hpp_list, fmt) {
463 hpp->buf = buf;
464 hpp->size = size;
465
466 /*
467 * No need to call hist_entry__snprintf_alignment() since this
468 * fmt is always the last column in the hierarchy mode.
469 */
470 if (perf_hpp__use_color() && fmt->color)
471 fmt->color(fmt, hpp, he);
472 else
473 fmt->entry(fmt, hpp, he);
474
475 /*
476 * dynamic entries are right-aligned but we want left-aligned
477 * in the hierarchy mode
478 */
479 printed += fprintf(fp, "%s%s", sep ?: " ", ltrim(buf));
480 }
481 printed += putc('\n', fp);
482
483 if (symbol_conf.use_callchain && he->leaf) {
484 u64 total = hists__total_period(hists);
485
486 printed += hist_entry_callchain__fprintf(he, total, 0, fp);
487 goto out;
488 }
489
490out:
491 return printed;
410} 492}
411 493
412static int hist_entry__fprintf(struct hist_entry *he, size_t size, 494static int hist_entry__fprintf(struct hist_entry *he, size_t size,
@@ -418,24 +500,134 @@ static int hist_entry__fprintf(struct hist_entry *he, size_t size,
418 .buf = bf, 500 .buf = bf,
419 .size = size, 501 .size = size,
420 }; 502 };
503 u64 total_period = hists->stats.total_period;
421 504
422 if (size == 0 || size > bfsz) 505 if (size == 0 || size > bfsz)
423 size = hpp.size = bfsz; 506 size = hpp.size = bfsz;
424 507
508 if (symbol_conf.report_hierarchy)
509 return hist_entry__hierarchy_fprintf(he, &hpp, hists, fp);
510
425 hist_entry__snprintf(he, &hpp); 511 hist_entry__snprintf(he, &hpp);
426 512
427 ret = fprintf(fp, "%s\n", bf); 513 ret = fprintf(fp, "%s\n", bf);
428 514
429 if (symbol_conf.use_callchain) 515 if (symbol_conf.use_callchain)
430 ret += hist_entry__callchain_fprintf(he, hists, fp); 516 ret += hist_entry_callchain__fprintf(he, total_period, 0, fp);
431 517
432 return ret; 518 return ret;
433} 519}
434 520
521static int print_hierarchy_indent(const char *sep, int indent,
522 const char *line, FILE *fp)
523{
524 if (sep != NULL || indent < 2)
525 return 0;
526
527 return fprintf(fp, "%-.*s", (indent - 2) * HIERARCHY_INDENT, line);
528}
529
530static int print_hierarchy_header(struct hists *hists, struct perf_hpp *hpp,
531 const char *sep, FILE *fp)
532{
533 bool first_node, first_col;
534 int indent;
535 int depth;
536 unsigned width = 0;
537 unsigned header_width = 0;
538 struct perf_hpp_fmt *fmt;
539 struct perf_hpp_list_node *fmt_node;
540
541 indent = hists->nr_hpp_node;
542
543 /* preserve max indent depth for column headers */
544 print_hierarchy_indent(sep, indent, spaces, fp);
545
546 /* the first hpp_list_node is for overhead columns */
547 fmt_node = list_first_entry(&hists->hpp_formats,
548 struct perf_hpp_list_node, list);
549
550 perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) {
551 fmt->header(fmt, hpp, hists_to_evsel(hists));
552 fprintf(fp, "%s%s", hpp->buf, sep ?: " ");
553 }
554
555 /* combine sort headers with ' / ' */
556 first_node = true;
557 list_for_each_entry_continue(fmt_node, &hists->hpp_formats, list) {
558 if (!first_node)
559 header_width += fprintf(fp, " / ");
560 first_node = false;
561
562 first_col = true;
563 perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) {
564 if (perf_hpp__should_skip(fmt, hists))
565 continue;
566
567 if (!first_col)
568 header_width += fprintf(fp, "+");
569 first_col = false;
570
571 fmt->header(fmt, hpp, hists_to_evsel(hists));
572 rtrim(hpp->buf);
573
574 header_width += fprintf(fp, "%s", ltrim(hpp->buf));
575 }
576 }
577
578 fprintf(fp, "\n# ");
579
580 /* preserve max indent depth for initial dots */
581 print_hierarchy_indent(sep, indent, dots, fp);
582
583 /* the first hpp_list_node is for overhead columns */
584 fmt_node = list_first_entry(&hists->hpp_formats,
585 struct perf_hpp_list_node, list);
586
587 first_col = true;
588 perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) {
589 if (!first_col)
590 fprintf(fp, "%s", sep ?: "..");
591 first_col = false;
592
593 width = fmt->width(fmt, hpp, hists_to_evsel(hists));
594 fprintf(fp, "%.*s", width, dots);
595 }
596
597 depth = 0;
598 list_for_each_entry_continue(fmt_node, &hists->hpp_formats, list) {
599 first_col = true;
600 width = depth * HIERARCHY_INDENT;
601
602 perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) {
603 if (perf_hpp__should_skip(fmt, hists))
604 continue;
605
606 if (!first_col)
607 width++; /* for '+' sign between column header */
608 first_col = false;
609
610 width += fmt->width(fmt, hpp, hists_to_evsel(hists));
611 }
612
613 if (width > header_width)
614 header_width = width;
615
616 depth++;
617 }
618
619 fprintf(fp, "%s%-.*s", sep ?: " ", header_width, dots);
620
621 fprintf(fp, "\n#\n");
622
623 return 2;
624}
625
435size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows, 626size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows,
436 int max_cols, float min_pcnt, FILE *fp) 627 int max_cols, float min_pcnt, FILE *fp)
437{ 628{
438 struct perf_hpp_fmt *fmt; 629 struct perf_hpp_fmt *fmt;
630 struct perf_hpp_list_node *fmt_node;
439 struct rb_node *nd; 631 struct rb_node *nd;
440 size_t ret = 0; 632 size_t ret = 0;
441 unsigned int width; 633 unsigned int width;
@@ -449,10 +641,11 @@ size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows,
449 bool first = true; 641 bool first = true;
450 size_t linesz; 642 size_t linesz;
451 char *line = NULL; 643 char *line = NULL;
644 unsigned indent;
452 645
453 init_rem_hits(); 646 init_rem_hits();
454 647
455 perf_hpp__for_each_format(fmt) 648 hists__for_each_format(hists, fmt)
456 perf_hpp__reset_width(fmt, hists); 649 perf_hpp__reset_width(fmt, hists);
457 650
458 if (symbol_conf.col_width_list_str) 651 if (symbol_conf.col_width_list_str)
@@ -463,7 +656,16 @@ size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows,
463 656
464 fprintf(fp, "# "); 657 fprintf(fp, "# ");
465 658
466 perf_hpp__for_each_format(fmt) { 659 if (symbol_conf.report_hierarchy) {
660 list_for_each_entry(fmt_node, &hists->hpp_formats, list) {
661 perf_hpp_list__for_each_format(&fmt_node->hpp, fmt)
662 perf_hpp__reset_width(fmt, hists);
663 }
664 nr_rows += print_hierarchy_header(hists, &dummy_hpp, sep, fp);
665 goto print_entries;
666 }
667
668 hists__for_each_format(hists, fmt) {
467 if (perf_hpp__should_skip(fmt, hists)) 669 if (perf_hpp__should_skip(fmt, hists))
468 continue; 670 continue;
469 671
@@ -487,7 +689,7 @@ size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows,
487 689
488 fprintf(fp, "# "); 690 fprintf(fp, "# ");
489 691
490 perf_hpp__for_each_format(fmt) { 692 hists__for_each_format(hists, fmt) {
491 unsigned int i; 693 unsigned int i;
492 694
493 if (perf_hpp__should_skip(fmt, hists)) 695 if (perf_hpp__should_skip(fmt, hists))
@@ -520,7 +722,9 @@ print_entries:
520 goto out; 722 goto out;
521 } 723 }
522 724
523 for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) { 725 indent = hists__overhead_width(hists) + 4;
726
727 for (nd = rb_first(&hists->entries); nd; nd = __rb_hierarchy_next(nd, HMD_FORCE_CHILD)) {
524 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); 728 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
525 float percent; 729 float percent;
526 730
@@ -536,6 +740,20 @@ print_entries:
536 if (max_rows && ++nr_rows >= max_rows) 740 if (max_rows && ++nr_rows >= max_rows)
537 break; 741 break;
538 742
743 /*
744 * If all children are filtered out or percent-limited,
745 * display "no entry >= x.xx%" message.
746 */
747 if (!h->leaf && !hist_entry__has_hierarchy_children(h, min_pcnt)) {
748 int depth = hists->nr_hpp_node + h->depth + 1;
749
750 print_hierarchy_indent(sep, depth, spaces, fp);
751 fprintf(fp, "%*sno entry >= %.2f%%\n", indent, "", min_pcnt);
752
753 if (max_rows && ++nr_rows >= max_rows)
754 break;
755 }
756
539 if (h->ms.map == NULL && verbose > 1) { 757 if (h->ms.map == NULL && verbose > 1) {
540 __map_groups__fprintf_maps(h->thread->mg, 758 __map_groups__fprintf_maps(h->thread->mg,
541 MAP__FUNCTION, fp); 759 MAP__FUNCTION, fp);
diff --git a/tools/perf/util/Build b/tools/perf/util/Build
index 5eec53a3f4ac..da48fd843438 100644
--- a/tools/perf/util/Build
+++ b/tools/perf/util/Build
@@ -1,4 +1,3 @@
1libperf-y += abspath.o
2libperf-y += alias.o 1libperf-y += alias.o
3libperf-y += annotate.o 2libperf-y += annotate.o
4libperf-y += build-id.o 3libperf-y += build-id.o
@@ -82,6 +81,7 @@ libperf-y += parse-branch-options.o
82libperf-y += parse-regs-options.o 81libperf-y += parse-regs-options.o
83libperf-y += term.o 82libperf-y += term.o
84libperf-y += help-unknown-cmd.o 83libperf-y += help-unknown-cmd.o
84libperf-y += mem-events.o
85 85
86libperf-$(CONFIG_LIBBPF) += bpf-loader.o 86libperf-$(CONFIG_LIBBPF) += bpf-loader.o
87libperf-$(CONFIG_BPF_PROLOGUE) += bpf-prologue.o 87libperf-$(CONFIG_BPF_PROLOGUE) += bpf-prologue.o
@@ -105,8 +105,17 @@ libperf-y += scripting-engines/
105 105
106libperf-$(CONFIG_ZLIB) += zlib.o 106libperf-$(CONFIG_ZLIB) += zlib.o
107libperf-$(CONFIG_LZMA) += lzma.o 107libperf-$(CONFIG_LZMA) += lzma.o
108libperf-y += demangle-java.o
109
110ifdef CONFIG_JITDUMP
111libperf-$(CONFIG_LIBELF) += jitdump.o
112libperf-$(CONFIG_LIBELF) += genelf.o
113libperf-$(CONFIG_LIBELF) += genelf_debug.o
114endif
108 115
109CFLAGS_config.o += -DETC_PERFCONFIG="BUILD_STR($(ETC_PERFCONFIG_SQ))" 116CFLAGS_config.o += -DETC_PERFCONFIG="BUILD_STR($(ETC_PERFCONFIG_SQ))"
117# avoid compiler warnings in 32-bit mode
118CFLAGS_genelf_debug.o += -Wno-packed
110 119
111$(OUTPUT)util/parse-events-flex.c: util/parse-events.l $(OUTPUT)util/parse-events-bison.c 120$(OUTPUT)util/parse-events-flex.c: util/parse-events.l $(OUTPUT)util/parse-events-bison.c
112 $(call rule_mkdir) 121 $(call rule_mkdir)
diff --git a/tools/perf/util/abspath.c b/tools/perf/util/abspath.c
deleted file mode 100644
index 0e76affe9c36..000000000000
--- a/tools/perf/util/abspath.c
+++ /dev/null
@@ -1,37 +0,0 @@
1#include "cache.h"
2
3static const char *get_pwd_cwd(void)
4{
5 static char cwd[PATH_MAX + 1];
6 char *pwd;
7 struct stat cwd_stat, pwd_stat;
8 if (getcwd(cwd, PATH_MAX) == NULL)
9 return NULL;
10 pwd = getenv("PWD");
11 if (pwd && strcmp(pwd, cwd)) {
12 stat(cwd, &cwd_stat);
13 if (!stat(pwd, &pwd_stat) &&
14 pwd_stat.st_dev == cwd_stat.st_dev &&
15 pwd_stat.st_ino == cwd_stat.st_ino) {
16 strlcpy(cwd, pwd, PATH_MAX);
17 }
18 }
19 return cwd;
20}
21
22const char *make_nonrelative_path(const char *path)
23{
24 static char buf[PATH_MAX + 1];
25
26 if (is_absolute_path(path)) {
27 if (strlcpy(buf, path, PATH_MAX) >= PATH_MAX)
28 die("Too long path: %.*s", 60, path);
29 } else {
30 const char *cwd = get_pwd_cwd();
31 if (!cwd)
32 die("Cannot determine the current working directory");
33 if (snprintf(buf, PATH_MAX, "%s/%s", cwd, path) >= PATH_MAX)
34 die("Too long path: %.*s", 60, path);
35 }
36 return buf;
37}
diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h
index cea323d9ee7e..9241f8c2b7e1 100644
--- a/tools/perf/util/annotate.h
+++ b/tools/perf/util/annotate.h
@@ -158,7 +158,7 @@ int symbol__annotate(struct symbol *sym, struct map *map, size_t privsize);
158 158
159int hist_entry__annotate(struct hist_entry *he, size_t privsize); 159int hist_entry__annotate(struct hist_entry *he, size_t privsize);
160 160
161int symbol__annotate_init(struct map *map __maybe_unused, struct symbol *sym); 161int symbol__annotate_init(struct map *map, struct symbol *sym);
162int symbol__annotate_printf(struct symbol *sym, struct map *map, 162int symbol__annotate_printf(struct symbol *sym, struct map *map,
163 struct perf_evsel *evsel, bool full_paths, 163 struct perf_evsel *evsel, bool full_paths,
164 int min_pcnt, int max_lines, int context); 164 int min_pcnt, int max_lines, int context);
diff --git a/tools/perf/util/auxtrace.c b/tools/perf/util/auxtrace.c
index 360fda01f3b0..ec164fe70718 100644
--- a/tools/perf/util/auxtrace.c
+++ b/tools/perf/util/auxtrace.c
@@ -478,10 +478,11 @@ void auxtrace_heap__pop(struct auxtrace_heap *heap)
478 heap_array[last].ordinal); 478 heap_array[last].ordinal);
479} 479}
480 480
481size_t auxtrace_record__info_priv_size(struct auxtrace_record *itr) 481size_t auxtrace_record__info_priv_size(struct auxtrace_record *itr,
482 struct perf_evlist *evlist)
482{ 483{
483 if (itr) 484 if (itr)
484 return itr->info_priv_size(itr); 485 return itr->info_priv_size(itr, evlist);
485 return 0; 486 return 0;
486} 487}
487 488
@@ -852,7 +853,7 @@ int perf_event__synthesize_auxtrace_info(struct auxtrace_record *itr,
852 int err; 853 int err;
853 854
854 pr_debug2("Synthesizing auxtrace information\n"); 855 pr_debug2("Synthesizing auxtrace information\n");
855 priv_size = auxtrace_record__info_priv_size(itr); 856 priv_size = auxtrace_record__info_priv_size(itr, session->evlist);
856 ev = zalloc(sizeof(struct auxtrace_info_event) + priv_size); 857 ev = zalloc(sizeof(struct auxtrace_info_event) + priv_size);
857 if (!ev) 858 if (!ev)
858 return -ENOMEM; 859 return -ENOMEM;
diff --git a/tools/perf/util/auxtrace.h b/tools/perf/util/auxtrace.h
index b86f90db1352..57ff31ecb8e4 100644
--- a/tools/perf/util/auxtrace.h
+++ b/tools/perf/util/auxtrace.h
@@ -293,7 +293,8 @@ struct auxtrace_record {
293 int (*recording_options)(struct auxtrace_record *itr, 293 int (*recording_options)(struct auxtrace_record *itr,
294 struct perf_evlist *evlist, 294 struct perf_evlist *evlist,
295 struct record_opts *opts); 295 struct record_opts *opts);
296 size_t (*info_priv_size)(struct auxtrace_record *itr); 296 size_t (*info_priv_size)(struct auxtrace_record *itr,
297 struct perf_evlist *evlist);
297 int (*info_fill)(struct auxtrace_record *itr, 298 int (*info_fill)(struct auxtrace_record *itr,
298 struct perf_session *session, 299 struct perf_session *session,
299 struct auxtrace_info_event *auxtrace_info, 300 struct auxtrace_info_event *auxtrace_info,
@@ -429,7 +430,8 @@ int auxtrace_parse_snapshot_options(struct auxtrace_record *itr,
429int auxtrace_record__options(struct auxtrace_record *itr, 430int auxtrace_record__options(struct auxtrace_record *itr,
430 struct perf_evlist *evlist, 431 struct perf_evlist *evlist,
431 struct record_opts *opts); 432 struct record_opts *opts);
432size_t auxtrace_record__info_priv_size(struct auxtrace_record *itr); 433size_t auxtrace_record__info_priv_size(struct auxtrace_record *itr,
434 struct perf_evlist *evlist);
433int auxtrace_record__info_fill(struct auxtrace_record *itr, 435int auxtrace_record__info_fill(struct auxtrace_record *itr,
434 struct perf_session *session, 436 struct perf_session *session,
435 struct auxtrace_info_event *auxtrace_info, 437 struct auxtrace_info_event *auxtrace_info,
@@ -515,7 +517,7 @@ static inline void auxtrace__free(struct perf_session *session)
515 517
516static inline struct auxtrace_record * 518static inline struct auxtrace_record *
517auxtrace_record__init(struct perf_evlist *evlist __maybe_unused, 519auxtrace_record__init(struct perf_evlist *evlist __maybe_unused,
518 int *err __maybe_unused) 520 int *err)
519{ 521{
520 *err = 0; 522 *err = 0;
521 return NULL; 523 return NULL;
diff --git a/tools/perf/util/bpf-loader.c b/tools/perf/util/bpf-loader.c
index 540a7efa657e..0967ce601931 100644
--- a/tools/perf/util/bpf-loader.c
+++ b/tools/perf/util/bpf-loader.c
@@ -7,6 +7,7 @@
7 7
8#include <linux/bpf.h> 8#include <linux/bpf.h>
9#include <bpf/libbpf.h> 9#include <bpf/libbpf.h>
10#include <bpf/bpf.h>
10#include <linux/err.h> 11#include <linux/err.h>
11#include <linux/string.h> 12#include <linux/string.h>
12#include "perf.h" 13#include "perf.h"
@@ -16,6 +17,7 @@
16#include "llvm-utils.h" 17#include "llvm-utils.h"
17#include "probe-event.h" 18#include "probe-event.h"
18#include "probe-finder.h" // for MAX_PROBES 19#include "probe-finder.h" // for MAX_PROBES
20#include "parse-events.h"
19#include "llvm-utils.h" 21#include "llvm-utils.h"
20 22
21#define DEFINE_PRINT_FN(name, level) \ 23#define DEFINE_PRINT_FN(name, level) \
@@ -108,8 +110,8 @@ void bpf__clear(void)
108} 110}
109 111
110static void 112static void
111bpf_prog_priv__clear(struct bpf_program *prog __maybe_unused, 113clear_prog_priv(struct bpf_program *prog __maybe_unused,
112 void *_priv) 114 void *_priv)
113{ 115{
114 struct bpf_prog_priv *priv = _priv; 116 struct bpf_prog_priv *priv = _priv;
115 117
@@ -337,7 +339,7 @@ config_bpf_program(struct bpf_program *prog)
337 } 339 }
338 pr_debug("bpf: config '%s' is ok\n", config_str); 340 pr_debug("bpf: config '%s' is ok\n", config_str);
339 341
340 err = bpf_program__set_private(prog, priv, bpf_prog_priv__clear); 342 err = bpf_program__set_private(prog, priv, clear_prog_priv);
341 if (err) { 343 if (err) {
342 pr_debug("Failed to set priv for program '%s'\n", config_str); 344 pr_debug("Failed to set priv for program '%s'\n", config_str);
343 goto errout; 345 goto errout;
@@ -739,6 +741,682 @@ int bpf__foreach_tev(struct bpf_object *obj,
739 return 0; 741 return 0;
740} 742}
741 743
744enum bpf_map_op_type {
745 BPF_MAP_OP_SET_VALUE,
746 BPF_MAP_OP_SET_EVSEL,
747};
748
749enum bpf_map_key_type {
750 BPF_MAP_KEY_ALL,
751 BPF_MAP_KEY_RANGES,
752};
753
754struct bpf_map_op {
755 struct list_head list;
756 enum bpf_map_op_type op_type;
757 enum bpf_map_key_type key_type;
758 union {
759 struct parse_events_array array;
760 } k;
761 union {
762 u64 value;
763 struct perf_evsel *evsel;
764 } v;
765};
766
767struct bpf_map_priv {
768 struct list_head ops_list;
769};
770
771static void
772bpf_map_op__delete(struct bpf_map_op *op)
773{
774 if (!list_empty(&op->list))
775 list_del(&op->list);
776 if (op->key_type == BPF_MAP_KEY_RANGES)
777 parse_events__clear_array(&op->k.array);
778 free(op);
779}
780
781static void
782bpf_map_priv__purge(struct bpf_map_priv *priv)
783{
784 struct bpf_map_op *pos, *n;
785
786 list_for_each_entry_safe(pos, n, &priv->ops_list, list) {
787 list_del_init(&pos->list);
788 bpf_map_op__delete(pos);
789 }
790}
791
792static void
793bpf_map_priv__clear(struct bpf_map *map __maybe_unused,
794 void *_priv)
795{
796 struct bpf_map_priv *priv = _priv;
797
798 bpf_map_priv__purge(priv);
799 free(priv);
800}
801
802static int
803bpf_map_op_setkey(struct bpf_map_op *op, struct parse_events_term *term)
804{
805 op->key_type = BPF_MAP_KEY_ALL;
806 if (!term)
807 return 0;
808
809 if (term->array.nr_ranges) {
810 size_t memsz = term->array.nr_ranges *
811 sizeof(op->k.array.ranges[0]);
812
813 op->k.array.ranges = memdup(term->array.ranges, memsz);
814 if (!op->k.array.ranges) {
815 pr_debug("No enough memory to alloc indices for map\n");
816 return -ENOMEM;
817 }
818 op->key_type = BPF_MAP_KEY_RANGES;
819 op->k.array.nr_ranges = term->array.nr_ranges;
820 }
821 return 0;
822}
823
824static struct bpf_map_op *
825bpf_map_op__new(struct parse_events_term *term)
826{
827 struct bpf_map_op *op;
828 int err;
829
830 op = zalloc(sizeof(*op));
831 if (!op) {
832 pr_debug("Failed to alloc bpf_map_op\n");
833 return ERR_PTR(-ENOMEM);
834 }
835 INIT_LIST_HEAD(&op->list);
836
837 err = bpf_map_op_setkey(op, term);
838 if (err) {
839 free(op);
840 return ERR_PTR(err);
841 }
842 return op;
843}
844
845static int
846bpf_map__add_op(struct bpf_map *map, struct bpf_map_op *op)
847{
848 struct bpf_map_priv *priv;
849 const char *map_name;
850 int err;
851
852 map_name = bpf_map__get_name(map);
853 err = bpf_map__get_private(map, (void **)&priv);
854 if (err) {
855 pr_debug("Failed to get private from map %s\n", map_name);
856 return err;
857 }
858
859 if (!priv) {
860 priv = zalloc(sizeof(*priv));
861 if (!priv) {
862 pr_debug("No enough memory to alloc map private\n");
863 return -ENOMEM;
864 }
865 INIT_LIST_HEAD(&priv->ops_list);
866
867 if (bpf_map__set_private(map, priv, bpf_map_priv__clear)) {
868 free(priv);
869 return -BPF_LOADER_ERRNO__INTERNAL;
870 }
871 }
872
873 list_add_tail(&op->list, &priv->ops_list);
874 return 0;
875}
876
877static struct bpf_map_op *
878bpf_map__add_newop(struct bpf_map *map, struct parse_events_term *term)
879{
880 struct bpf_map_op *op;
881 int err;
882
883 op = bpf_map_op__new(term);
884 if (IS_ERR(op))
885 return op;
886
887 err = bpf_map__add_op(map, op);
888 if (err) {
889 bpf_map_op__delete(op);
890 return ERR_PTR(err);
891 }
892 return op;
893}
894
895static int
896__bpf_map__config_value(struct bpf_map *map,
897 struct parse_events_term *term)
898{
899 struct bpf_map_def def;
900 struct bpf_map_op *op;
901 const char *map_name;
902 int err;
903
904 map_name = bpf_map__get_name(map);
905
906 err = bpf_map__get_def(map, &def);
907 if (err) {
908 pr_debug("Unable to get map definition from '%s'\n",
909 map_name);
910 return -BPF_LOADER_ERRNO__INTERNAL;
911 }
912
913 if (def.type != BPF_MAP_TYPE_ARRAY) {
914 pr_debug("Map %s type is not BPF_MAP_TYPE_ARRAY\n",
915 map_name);
916 return -BPF_LOADER_ERRNO__OBJCONF_MAP_TYPE;
917 }
918 if (def.key_size < sizeof(unsigned int)) {
919 pr_debug("Map %s has incorrect key size\n", map_name);
920 return -BPF_LOADER_ERRNO__OBJCONF_MAP_KEYSIZE;
921 }
922 switch (def.value_size) {
923 case 1:
924 case 2:
925 case 4:
926 case 8:
927 break;
928 default:
929 pr_debug("Map %s has incorrect value size\n", map_name);
930 return -BPF_LOADER_ERRNO__OBJCONF_MAP_VALUESIZE;
931 }
932
933 op = bpf_map__add_newop(map, term);
934 if (IS_ERR(op))
935 return PTR_ERR(op);
936 op->op_type = BPF_MAP_OP_SET_VALUE;
937 op->v.value = term->val.num;
938 return 0;
939}
940
941static int
942bpf_map__config_value(struct bpf_map *map,
943 struct parse_events_term *term,
944 struct perf_evlist *evlist __maybe_unused)
945{
946 if (!term->err_val) {
947 pr_debug("Config value not set\n");
948 return -BPF_LOADER_ERRNO__OBJCONF_CONF;
949 }
950
951 if (term->type_val != PARSE_EVENTS__TERM_TYPE_NUM) {
952 pr_debug("ERROR: wrong value type for 'value'\n");
953 return -BPF_LOADER_ERRNO__OBJCONF_MAP_VALUE;
954 }
955
956 return __bpf_map__config_value(map, term);
957}
958
959static int
960__bpf_map__config_event(struct bpf_map *map,
961 struct parse_events_term *term,
962 struct perf_evlist *evlist)
963{
964 struct perf_evsel *evsel;
965 struct bpf_map_def def;
966 struct bpf_map_op *op;
967 const char *map_name;
968 int err;
969
970 map_name = bpf_map__get_name(map);
971 evsel = perf_evlist__find_evsel_by_str(evlist, term->val.str);
972 if (!evsel) {
973 pr_debug("Event (for '%s') '%s' doesn't exist\n",
974 map_name, term->val.str);
975 return -BPF_LOADER_ERRNO__OBJCONF_MAP_NOEVT;
976 }
977
978 err = bpf_map__get_def(map, &def);
979 if (err) {
980 pr_debug("Unable to get map definition from '%s'\n",
981 map_name);
982 return err;
983 }
984
985 /*
986 * No need to check key_size and value_size:
987 * kernel has already checked them.
988 */
989 if (def.type != BPF_MAP_TYPE_PERF_EVENT_ARRAY) {
990 pr_debug("Map %s type is not BPF_MAP_TYPE_PERF_EVENT_ARRAY\n",
991 map_name);
992 return -BPF_LOADER_ERRNO__OBJCONF_MAP_TYPE;
993 }
994
995 op = bpf_map__add_newop(map, term);
996 if (IS_ERR(op))
997 return PTR_ERR(op);
998 op->op_type = BPF_MAP_OP_SET_EVSEL;
999 op->v.evsel = evsel;
1000 return 0;
1001}
1002
1003static int
1004bpf_map__config_event(struct bpf_map *map,
1005 struct parse_events_term *term,
1006 struct perf_evlist *evlist)
1007{
1008 if (!term->err_val) {
1009 pr_debug("Config value not set\n");
1010 return -BPF_LOADER_ERRNO__OBJCONF_CONF;
1011 }
1012
1013 if (term->type_val != PARSE_EVENTS__TERM_TYPE_STR) {
1014 pr_debug("ERROR: wrong value type for 'event'\n");
1015 return -BPF_LOADER_ERRNO__OBJCONF_MAP_VALUE;
1016 }
1017
1018 return __bpf_map__config_event(map, term, evlist);
1019}
1020
1021struct bpf_obj_config__map_func {
1022 const char *config_opt;
1023 int (*config_func)(struct bpf_map *, struct parse_events_term *,
1024 struct perf_evlist *);
1025};
1026
1027struct bpf_obj_config__map_func bpf_obj_config__map_funcs[] = {
1028 {"value", bpf_map__config_value},
1029 {"event", bpf_map__config_event},
1030};
1031
1032static int
1033config_map_indices_range_check(struct parse_events_term *term,
1034 struct bpf_map *map,
1035 const char *map_name)
1036{
1037 struct parse_events_array *array = &term->array;
1038 struct bpf_map_def def;
1039 unsigned int i;
1040 int err;
1041
1042 if (!array->nr_ranges)
1043 return 0;
1044 if (!array->ranges) {
1045 pr_debug("ERROR: map %s: array->nr_ranges is %d but range array is NULL\n",
1046 map_name, (int)array->nr_ranges);
1047 return -BPF_LOADER_ERRNO__INTERNAL;
1048 }
1049
1050 err = bpf_map__get_def(map, &def);
1051 if (err) {
1052 pr_debug("ERROR: Unable to get map definition from '%s'\n",
1053 map_name);
1054 return -BPF_LOADER_ERRNO__INTERNAL;
1055 }
1056
1057 for (i = 0; i < array->nr_ranges; i++) {
1058 unsigned int start = array->ranges[i].start;
1059 size_t length = array->ranges[i].length;
1060 unsigned int idx = start + length - 1;
1061
1062 if (idx >= def.max_entries) {
1063 pr_debug("ERROR: index %d too large\n", idx);
1064 return -BPF_LOADER_ERRNO__OBJCONF_MAP_IDX2BIG;
1065 }
1066 }
1067 return 0;
1068}
1069
1070static int
1071bpf__obj_config_map(struct bpf_object *obj,
1072 struct parse_events_term *term,
1073 struct perf_evlist *evlist,
1074 int *key_scan_pos)
1075{
1076 /* key is "map:<mapname>.<config opt>" */
1077 char *map_name = strdup(term->config + sizeof("map:") - 1);
1078 struct bpf_map *map;
1079 int err = -BPF_LOADER_ERRNO__OBJCONF_OPT;
1080 char *map_opt;
1081 size_t i;
1082
1083 if (!map_name)
1084 return -ENOMEM;
1085
1086 map_opt = strchr(map_name, '.');
1087 if (!map_opt) {
1088 pr_debug("ERROR: Invalid map config: %s\n", map_name);
1089 goto out;
1090 }
1091
1092 *map_opt++ = '\0';
1093 if (*map_opt == '\0') {
1094 pr_debug("ERROR: Invalid map option: %s\n", term->config);
1095 goto out;
1096 }
1097
1098 map = bpf_object__get_map_by_name(obj, map_name);
1099 if (!map) {
1100 pr_debug("ERROR: Map %s doesn't exist\n", map_name);
1101 err = -BPF_LOADER_ERRNO__OBJCONF_MAP_NOTEXIST;
1102 goto out;
1103 }
1104
1105 *key_scan_pos += strlen(map_opt);
1106 err = config_map_indices_range_check(term, map, map_name);
1107 if (err)
1108 goto out;
1109 *key_scan_pos -= strlen(map_opt);
1110
1111 for (i = 0; i < ARRAY_SIZE(bpf_obj_config__map_funcs); i++) {
1112 struct bpf_obj_config__map_func *func =
1113 &bpf_obj_config__map_funcs[i];
1114
1115 if (strcmp(map_opt, func->config_opt) == 0) {
1116 err = func->config_func(map, term, evlist);
1117 goto out;
1118 }
1119 }
1120
1121 pr_debug("ERROR: Invalid map config option '%s'\n", map_opt);
1122 err = -BPF_LOADER_ERRNO__OBJCONF_MAP_OPT;
1123out:
1124 free(map_name);
1125 if (!err)
1126 key_scan_pos += strlen(map_opt);
1127 return err;
1128}
1129
1130int bpf__config_obj(struct bpf_object *obj,
1131 struct parse_events_term *term,
1132 struct perf_evlist *evlist,
1133 int *error_pos)
1134{
1135 int key_scan_pos = 0;
1136 int err;
1137
1138 if (!obj || !term || !term->config)
1139 return -EINVAL;
1140
1141 if (!prefixcmp(term->config, "map:")) {
1142 key_scan_pos = sizeof("map:") - 1;
1143 err = bpf__obj_config_map(obj, term, evlist, &key_scan_pos);
1144 goto out;
1145 }
1146 err = -BPF_LOADER_ERRNO__OBJCONF_OPT;
1147out:
1148 if (error_pos)
1149 *error_pos = key_scan_pos;
1150 return err;
1151
1152}
1153
1154typedef int (*map_config_func_t)(const char *name, int map_fd,
1155 struct bpf_map_def *pdef,
1156 struct bpf_map_op *op,
1157 void *pkey, void *arg);
1158
1159static int
1160foreach_key_array_all(map_config_func_t func,
1161 void *arg, const char *name,
1162 int map_fd, struct bpf_map_def *pdef,
1163 struct bpf_map_op *op)
1164{
1165 unsigned int i;
1166 int err;
1167
1168 for (i = 0; i < pdef->max_entries; i++) {
1169 err = func(name, map_fd, pdef, op, &i, arg);
1170 if (err) {
1171 pr_debug("ERROR: failed to insert value to %s[%u]\n",
1172 name, i);
1173 return err;
1174 }
1175 }
1176 return 0;
1177}
1178
1179static int
1180foreach_key_array_ranges(map_config_func_t func, void *arg,
1181 const char *name, int map_fd,
1182 struct bpf_map_def *pdef,
1183 struct bpf_map_op *op)
1184{
1185 unsigned int i, j;
1186 int err;
1187
1188 for (i = 0; i < op->k.array.nr_ranges; i++) {
1189 unsigned int start = op->k.array.ranges[i].start;
1190 size_t length = op->k.array.ranges[i].length;
1191
1192 for (j = 0; j < length; j++) {
1193 unsigned int idx = start + j;
1194
1195 err = func(name, map_fd, pdef, op, &idx, arg);
1196 if (err) {
1197 pr_debug("ERROR: failed to insert value to %s[%u]\n",
1198 name, idx);
1199 return err;
1200 }
1201 }
1202 }
1203 return 0;
1204}
1205
1206static int
1207bpf_map_config_foreach_key(struct bpf_map *map,
1208 map_config_func_t func,
1209 void *arg)
1210{
1211 int err, map_fd;
1212 const char *name;
1213 struct bpf_map_op *op;
1214 struct bpf_map_def def;
1215 struct bpf_map_priv *priv;
1216
1217 name = bpf_map__get_name(map);
1218
1219 err = bpf_map__get_private(map, (void **)&priv);
1220 if (err) {
1221 pr_debug("ERROR: failed to get private from map %s\n", name);
1222 return -BPF_LOADER_ERRNO__INTERNAL;
1223 }
1224 if (!priv || list_empty(&priv->ops_list)) {
1225 pr_debug("INFO: nothing to config for map %s\n", name);
1226 return 0;
1227 }
1228
1229 err = bpf_map__get_def(map, &def);
1230 if (err) {
1231 pr_debug("ERROR: failed to get definition from map %s\n", name);
1232 return -BPF_LOADER_ERRNO__INTERNAL;
1233 }
1234 map_fd = bpf_map__get_fd(map);
1235 if (map_fd < 0) {
1236 pr_debug("ERROR: failed to get fd from map %s\n", name);
1237 return map_fd;
1238 }
1239
1240 list_for_each_entry(op, &priv->ops_list, list) {
1241 switch (def.type) {
1242 case BPF_MAP_TYPE_ARRAY:
1243 case BPF_MAP_TYPE_PERF_EVENT_ARRAY:
1244 switch (op->key_type) {
1245 case BPF_MAP_KEY_ALL:
1246 err = foreach_key_array_all(func, arg, name,
1247 map_fd, &def, op);
1248 break;
1249 case BPF_MAP_KEY_RANGES:
1250 err = foreach_key_array_ranges(func, arg, name,
1251 map_fd, &def,
1252 op);
1253 break;
1254 default:
1255 pr_debug("ERROR: keytype for map '%s' invalid\n",
1256 name);
1257 return -BPF_LOADER_ERRNO__INTERNAL;
1258 }
1259 if (err)
1260 return err;
1261 break;
1262 default:
1263 pr_debug("ERROR: type of '%s' incorrect\n", name);
1264 return -BPF_LOADER_ERRNO__OBJCONF_MAP_TYPE;
1265 }
1266 }
1267
1268 return 0;
1269}
1270
1271static int
1272apply_config_value_for_key(int map_fd, void *pkey,
1273 size_t val_size, u64 val)
1274{
1275 int err = 0;
1276
1277 switch (val_size) {
1278 case 1: {
1279 u8 _val = (u8)(val);
1280 err = bpf_map_update_elem(map_fd, pkey, &_val, BPF_ANY);
1281 break;
1282 }
1283 case 2: {
1284 u16 _val = (u16)(val);
1285 err = bpf_map_update_elem(map_fd, pkey, &_val, BPF_ANY);
1286 break;
1287 }
1288 case 4: {
1289 u32 _val = (u32)(val);
1290 err = bpf_map_update_elem(map_fd, pkey, &_val, BPF_ANY);
1291 break;
1292 }
1293 case 8: {
1294 err = bpf_map_update_elem(map_fd, pkey, &val, BPF_ANY);
1295 break;
1296 }
1297 default:
1298 pr_debug("ERROR: invalid value size\n");
1299 return -BPF_LOADER_ERRNO__OBJCONF_MAP_VALUESIZE;
1300 }
1301 if (err && errno)
1302 err = -errno;
1303 return err;
1304}
1305
1306static int
1307apply_config_evsel_for_key(const char *name, int map_fd, void *pkey,
1308 struct perf_evsel *evsel)
1309{
1310 struct xyarray *xy = evsel->fd;
1311 struct perf_event_attr *attr;
1312 unsigned int key, events;
1313 bool check_pass = false;
1314 int *evt_fd;
1315 int err;
1316
1317 if (!xy) {
1318 pr_debug("ERROR: evsel not ready for map %s\n", name);
1319 return -BPF_LOADER_ERRNO__INTERNAL;
1320 }
1321
1322 if (xy->row_size / xy->entry_size != 1) {
1323 pr_debug("ERROR: Dimension of target event is incorrect for map %s\n",
1324 name);
1325 return -BPF_LOADER_ERRNO__OBJCONF_MAP_EVTDIM;
1326 }
1327
1328 attr = &evsel->attr;
1329 if (attr->inherit) {
1330 pr_debug("ERROR: Can't put inherit event into map %s\n", name);
1331 return -BPF_LOADER_ERRNO__OBJCONF_MAP_EVTINH;
1332 }
1333
1334 if (perf_evsel__is_bpf_output(evsel))
1335 check_pass = true;
1336 if (attr->type == PERF_TYPE_RAW)
1337 check_pass = true;
1338 if (attr->type == PERF_TYPE_HARDWARE)
1339 check_pass = true;
1340 if (!check_pass) {
1341 pr_debug("ERROR: Event type is wrong for map %s\n", name);
1342 return -BPF_LOADER_ERRNO__OBJCONF_MAP_EVTTYPE;
1343 }
1344
1345 events = xy->entries / (xy->row_size / xy->entry_size);
1346 key = *((unsigned int *)pkey);
1347 if (key >= events) {
1348 pr_debug("ERROR: there is no event %d for map %s\n",
1349 key, name);
1350 return -BPF_LOADER_ERRNO__OBJCONF_MAP_MAPSIZE;
1351 }
1352 evt_fd = xyarray__entry(xy, key, 0);
1353 err = bpf_map_update_elem(map_fd, pkey, evt_fd, BPF_ANY);
1354 if (err && errno)
1355 err = -errno;
1356 return err;
1357}
1358
1359static int
1360apply_obj_config_map_for_key(const char *name, int map_fd,
1361 struct bpf_map_def *pdef __maybe_unused,
1362 struct bpf_map_op *op,
1363 void *pkey, void *arg __maybe_unused)
1364{
1365 int err;
1366
1367 switch (op->op_type) {
1368 case BPF_MAP_OP_SET_VALUE:
1369 err = apply_config_value_for_key(map_fd, pkey,
1370 pdef->value_size,
1371 op->v.value);
1372 break;
1373 case BPF_MAP_OP_SET_EVSEL:
1374 err = apply_config_evsel_for_key(name, map_fd, pkey,
1375 op->v.evsel);
1376 break;
1377 default:
1378 pr_debug("ERROR: unknown value type for '%s'\n", name);
1379 err = -BPF_LOADER_ERRNO__INTERNAL;
1380 }
1381 return err;
1382}
1383
1384static int
1385apply_obj_config_map(struct bpf_map *map)
1386{
1387 return bpf_map_config_foreach_key(map,
1388 apply_obj_config_map_for_key,
1389 NULL);
1390}
1391
1392static int
1393apply_obj_config_object(struct bpf_object *obj)
1394{
1395 struct bpf_map *map;
1396 int err;
1397
1398 bpf_map__for_each(map, obj) {
1399 err = apply_obj_config_map(map);
1400 if (err)
1401 return err;
1402 }
1403 return 0;
1404}
1405
1406int bpf__apply_obj_config(void)
1407{
1408 struct bpf_object *obj, *tmp;
1409 int err;
1410
1411 bpf_object__for_each_safe(obj, tmp) {
1412 err = apply_obj_config_object(obj);
1413 if (err)
1414 return err;
1415 }
1416
1417 return 0;
1418}
1419
742#define ERRNO_OFFSET(e) ((e) - __BPF_LOADER_ERRNO__START) 1420#define ERRNO_OFFSET(e) ((e) - __BPF_LOADER_ERRNO__START)
743#define ERRCODE_OFFSET(c) ERRNO_OFFSET(BPF_LOADER_ERRNO__##c) 1421#define ERRCODE_OFFSET(c) ERRNO_OFFSET(BPF_LOADER_ERRNO__##c)
744#define NR_ERRNO (__BPF_LOADER_ERRNO__END - __BPF_LOADER_ERRNO__START) 1422#define NR_ERRNO (__BPF_LOADER_ERRNO__END - __BPF_LOADER_ERRNO__START)
@@ -753,6 +1431,20 @@ static const char *bpf_loader_strerror_table[NR_ERRNO] = {
753 [ERRCODE_OFFSET(PROLOGUE)] = "Failed to generate prologue", 1431 [ERRCODE_OFFSET(PROLOGUE)] = "Failed to generate prologue",
754 [ERRCODE_OFFSET(PROLOGUE2BIG)] = "Prologue too big for program", 1432 [ERRCODE_OFFSET(PROLOGUE2BIG)] = "Prologue too big for program",
755 [ERRCODE_OFFSET(PROLOGUEOOB)] = "Offset out of bound for prologue", 1433 [ERRCODE_OFFSET(PROLOGUEOOB)] = "Offset out of bound for prologue",
1434 [ERRCODE_OFFSET(OBJCONF_OPT)] = "Invalid object config option",
1435 [ERRCODE_OFFSET(OBJCONF_CONF)] = "Config value not set (missing '=')",
1436 [ERRCODE_OFFSET(OBJCONF_MAP_OPT)] = "Invalid object map config option",
1437 [ERRCODE_OFFSET(OBJCONF_MAP_NOTEXIST)] = "Target map doesn't exist",
1438 [ERRCODE_OFFSET(OBJCONF_MAP_VALUE)] = "Incorrect value type for map",
1439 [ERRCODE_OFFSET(OBJCONF_MAP_TYPE)] = "Incorrect map type",
1440 [ERRCODE_OFFSET(OBJCONF_MAP_KEYSIZE)] = "Incorrect map key size",
1441 [ERRCODE_OFFSET(OBJCONF_MAP_VALUESIZE)] = "Incorrect map value size",
1442 [ERRCODE_OFFSET(OBJCONF_MAP_NOEVT)] = "Event not found for map setting",
1443 [ERRCODE_OFFSET(OBJCONF_MAP_MAPSIZE)] = "Invalid map size for event setting",
1444 [ERRCODE_OFFSET(OBJCONF_MAP_EVTDIM)] = "Event dimension too large",
1445 [ERRCODE_OFFSET(OBJCONF_MAP_EVTINH)] = "Doesn't support inherit event",
1446 [ERRCODE_OFFSET(OBJCONF_MAP_EVTTYPE)] = "Wrong event type for map",
1447 [ERRCODE_OFFSET(OBJCONF_MAP_IDX2BIG)] = "Index too large",
756}; 1448};
757 1449
758static int 1450static int
@@ -872,3 +1564,29 @@ int bpf__strerror_load(struct bpf_object *obj,
872 bpf__strerror_end(buf, size); 1564 bpf__strerror_end(buf, size);
873 return 0; 1565 return 0;
874} 1566}
1567
1568int bpf__strerror_config_obj(struct bpf_object *obj __maybe_unused,
1569 struct parse_events_term *term __maybe_unused,
1570 struct perf_evlist *evlist __maybe_unused,
1571 int *error_pos __maybe_unused, int err,
1572 char *buf, size_t size)
1573{
1574 bpf__strerror_head(err, buf, size);
1575 bpf__strerror_entry(BPF_LOADER_ERRNO__OBJCONF_MAP_TYPE,
1576 "Can't use this config term with this map type");
1577 bpf__strerror_end(buf, size);
1578 return 0;
1579}
1580
1581int bpf__strerror_apply_obj_config(int err, char *buf, size_t size)
1582{
1583 bpf__strerror_head(err, buf, size);
1584 bpf__strerror_entry(BPF_LOADER_ERRNO__OBJCONF_MAP_EVTDIM,
1585 "Cannot set event to BPF map in multi-thread tracing");
1586 bpf__strerror_entry(BPF_LOADER_ERRNO__OBJCONF_MAP_EVTINH,
1587 "%s (Hint: use -i to turn off inherit)", emsg);
1588 bpf__strerror_entry(BPF_LOADER_ERRNO__OBJCONF_MAP_EVTTYPE,
1589 "Can only put raw, hardware and BPF output event into a BPF map");
1590 bpf__strerror_end(buf, size);
1591 return 0;
1592}
diff --git a/tools/perf/util/bpf-loader.h b/tools/perf/util/bpf-loader.h
index 6fdc0457e2b6..be4311944e3d 100644
--- a/tools/perf/util/bpf-loader.h
+++ b/tools/perf/util/bpf-loader.h
@@ -10,6 +10,7 @@
10#include <string.h> 10#include <string.h>
11#include <bpf/libbpf.h> 11#include <bpf/libbpf.h>
12#include "probe-event.h" 12#include "probe-event.h"
13#include "evlist.h"
13#include "debug.h" 14#include "debug.h"
14 15
15enum bpf_loader_errno { 16enum bpf_loader_errno {
@@ -24,10 +25,25 @@ enum bpf_loader_errno {
24 BPF_LOADER_ERRNO__PROLOGUE, /* Failed to generate prologue */ 25 BPF_LOADER_ERRNO__PROLOGUE, /* Failed to generate prologue */
25 BPF_LOADER_ERRNO__PROLOGUE2BIG, /* Prologue too big for program */ 26 BPF_LOADER_ERRNO__PROLOGUE2BIG, /* Prologue too big for program */
26 BPF_LOADER_ERRNO__PROLOGUEOOB, /* Offset out of bound for prologue */ 27 BPF_LOADER_ERRNO__PROLOGUEOOB, /* Offset out of bound for prologue */
28 BPF_LOADER_ERRNO__OBJCONF_OPT, /* Invalid object config option */
29 BPF_LOADER_ERRNO__OBJCONF_CONF, /* Config value not set (lost '=')) */
30 BPF_LOADER_ERRNO__OBJCONF_MAP_OPT, /* Invalid object map config option */
31 BPF_LOADER_ERRNO__OBJCONF_MAP_NOTEXIST, /* Target map not exist */
32 BPF_LOADER_ERRNO__OBJCONF_MAP_VALUE, /* Incorrect value type for map */
33 BPF_LOADER_ERRNO__OBJCONF_MAP_TYPE, /* Incorrect map type */
34 BPF_LOADER_ERRNO__OBJCONF_MAP_KEYSIZE, /* Incorrect map key size */
35 BPF_LOADER_ERRNO__OBJCONF_MAP_VALUESIZE,/* Incorrect map value size */
36 BPF_LOADER_ERRNO__OBJCONF_MAP_NOEVT, /* Event not found for map setting */
37 BPF_LOADER_ERRNO__OBJCONF_MAP_MAPSIZE, /* Invalid map size for event setting */
38 BPF_LOADER_ERRNO__OBJCONF_MAP_EVTDIM, /* Event dimension too large */
39 BPF_LOADER_ERRNO__OBJCONF_MAP_EVTINH, /* Doesn't support inherit event */
40 BPF_LOADER_ERRNO__OBJCONF_MAP_EVTTYPE, /* Wrong event type for map */
41 BPF_LOADER_ERRNO__OBJCONF_MAP_IDX2BIG, /* Index too large */
27 __BPF_LOADER_ERRNO__END, 42 __BPF_LOADER_ERRNO__END,
28}; 43};
29 44
30struct bpf_object; 45struct bpf_object;
46struct parse_events_term;
31#define PERF_BPF_PROBE_GROUP "perf_bpf_probe" 47#define PERF_BPF_PROBE_GROUP "perf_bpf_probe"
32 48
33typedef int (*bpf_prog_iter_callback_t)(struct probe_trace_event *tev, 49typedef int (*bpf_prog_iter_callback_t)(struct probe_trace_event *tev,
@@ -53,6 +69,16 @@ int bpf__strerror_load(struct bpf_object *obj, int err,
53 char *buf, size_t size); 69 char *buf, size_t size);
54int bpf__foreach_tev(struct bpf_object *obj, 70int bpf__foreach_tev(struct bpf_object *obj,
55 bpf_prog_iter_callback_t func, void *arg); 71 bpf_prog_iter_callback_t func, void *arg);
72
73int bpf__config_obj(struct bpf_object *obj, struct parse_events_term *term,
74 struct perf_evlist *evlist, int *error_pos);
75int bpf__strerror_config_obj(struct bpf_object *obj,
76 struct parse_events_term *term,
77 struct perf_evlist *evlist,
78 int *error_pos, int err, char *buf,
79 size_t size);
80int bpf__apply_obj_config(void);
81int bpf__strerror_apply_obj_config(int err, char *buf, size_t size);
56#else 82#else
57static inline struct bpf_object * 83static inline struct bpf_object *
58bpf__prepare_load(const char *filename __maybe_unused, 84bpf__prepare_load(const char *filename __maybe_unused,
@@ -84,6 +110,21 @@ bpf__foreach_tev(struct bpf_object *obj __maybe_unused,
84} 110}
85 111
86static inline int 112static inline int
113bpf__config_obj(struct bpf_object *obj __maybe_unused,
114 struct parse_events_term *term __maybe_unused,
115 struct perf_evlist *evlist __maybe_unused,
116 int *error_pos __maybe_unused)
117{
118 return 0;
119}
120
121static inline int
122bpf__apply_obj_config(void)
123{
124 return 0;
125}
126
127static inline int
87__bpf_strerror(char *buf, size_t size) 128__bpf_strerror(char *buf, size_t size)
88{ 129{
89 if (!size) 130 if (!size)
@@ -118,5 +159,23 @@ static inline int bpf__strerror_load(struct bpf_object *obj __maybe_unused,
118{ 159{
119 return __bpf_strerror(buf, size); 160 return __bpf_strerror(buf, size);
120} 161}
162
163static inline int
164bpf__strerror_config_obj(struct bpf_object *obj __maybe_unused,
165 struct parse_events_term *term __maybe_unused,
166 struct perf_evlist *evlist __maybe_unused,
167 int *error_pos __maybe_unused,
168 int err __maybe_unused,
169 char *buf, size_t size)
170{
171 return __bpf_strerror(buf, size);
172}
173
174static inline int
175bpf__strerror_apply_obj_config(int err __maybe_unused,
176 char *buf, size_t size)
177{
178 return __bpf_strerror(buf, size);
179}
121#endif 180#endif
122#endif 181#endif
diff --git a/tools/perf/util/build-id.c b/tools/perf/util/build-id.c
index 6a7e273a514a..0573c2ec861d 100644
--- a/tools/perf/util/build-id.c
+++ b/tools/perf/util/build-id.c
@@ -28,7 +28,6 @@ int build_id__mark_dso_hit(struct perf_tool *tool __maybe_unused,
28 struct machine *machine) 28 struct machine *machine)
29{ 29{
30 struct addr_location al; 30 struct addr_location al;
31 u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
32 struct thread *thread = machine__findnew_thread(machine, sample->pid, 31 struct thread *thread = machine__findnew_thread(machine, sample->pid,
33 sample->tid); 32 sample->tid);
34 33
@@ -38,7 +37,7 @@ int build_id__mark_dso_hit(struct perf_tool *tool __maybe_unused,
38 return -1; 37 return -1;
39 } 38 }
40 39
41 thread__find_addr_map(thread, cpumode, MAP__FUNCTION, sample->ip, &al); 40 thread__find_addr_map(thread, sample->cpumode, MAP__FUNCTION, sample->ip, &al);
42 41
43 if (al.map != NULL) 42 if (al.map != NULL)
44 al.map->dso->hit = 1; 43 al.map->dso->hit = 1;
@@ -166,6 +165,50 @@ char *dso__build_id_filename(const struct dso *dso, char *bf, size_t size)
166 return build_id__filename(build_id_hex, bf, size); 165 return build_id__filename(build_id_hex, bf, size);
167} 166}
168 167
168bool dso__build_id_is_kmod(const struct dso *dso, char *bf, size_t size)
169{
170 char *id_name, *ch;
171 struct stat sb;
172
173 id_name = dso__build_id_filename(dso, bf, size);
174 if (!id_name)
175 goto err;
176 if (access(id_name, F_OK))
177 goto err;
178 if (lstat(id_name, &sb) == -1)
179 goto err;
180 if ((size_t)sb.st_size > size - 1)
181 goto err;
182 if (readlink(id_name, bf, size - 1) < 0)
183 goto err;
184
185 bf[sb.st_size] = '\0';
186
187 /*
188 * link should be:
189 * ../../lib/modules/4.4.0-rc4/kernel/net/ipv4/netfilter/nf_nat_ipv4.ko/a09fe3eb3147dafa4e3b31dbd6257e4d696bdc92
190 */
191 ch = strrchr(bf, '/');
192 if (!ch)
193 goto err;
194 if (ch - 3 < bf)
195 goto err;
196
197 return strncmp(".ko", ch - 3, 3) == 0;
198err:
199 /*
200 * If dso__build_id_filename work, get id_name again,
201 * because id_name points to bf and is broken.
202 */
203 if (id_name)
204 id_name = dso__build_id_filename(dso, bf, size);
205 pr_err("Invalid build id: %s\n", id_name ? :
206 dso->long_name ? :
207 dso->short_name ? :
208 "[unknown]");
209 return false;
210}
211
169#define dsos__for_each_with_build_id(pos, head) \ 212#define dsos__for_each_with_build_id(pos, head) \
170 list_for_each_entry(pos, head, node) \ 213 list_for_each_entry(pos, head, node) \
171 if (!pos->has_build_id) \ 214 if (!pos->has_build_id) \
@@ -211,6 +254,7 @@ static int machine__write_buildid_table(struct machine *machine, int fd)
211 dsos__for_each_with_build_id(pos, &machine->dsos.head) { 254 dsos__for_each_with_build_id(pos, &machine->dsos.head) {
212 const char *name; 255 const char *name;
213 size_t name_len; 256 size_t name_len;
257 bool in_kernel = false;
214 258
215 if (!pos->hit) 259 if (!pos->hit)
216 continue; 260 continue;
@@ -227,8 +271,11 @@ static int machine__write_buildid_table(struct machine *machine, int fd)
227 name_len = pos->long_name_len + 1; 271 name_len = pos->long_name_len + 1;
228 } 272 }
229 273
274 in_kernel = pos->kernel ||
275 is_kernel_module(name,
276 PERF_RECORD_MISC_CPUMODE_UNKNOWN);
230 err = write_buildid(name, name_len, pos->build_id, machine->pid, 277 err = write_buildid(name, name_len, pos->build_id, machine->pid,
231 pos->kernel ? kmisc : umisc, fd); 278 in_kernel ? kmisc : umisc, fd);
232 if (err) 279 if (err)
233 break; 280 break;
234 } 281 }
diff --git a/tools/perf/util/build-id.h b/tools/perf/util/build-id.h
index 27a14a8a945b..64af3e20610d 100644
--- a/tools/perf/util/build-id.h
+++ b/tools/perf/util/build-id.h
@@ -16,6 +16,7 @@ int sysfs__sprintf_build_id(const char *root_dir, char *sbuild_id);
16int filename__sprintf_build_id(const char *pathname, char *sbuild_id); 16int filename__sprintf_build_id(const char *pathname, char *sbuild_id);
17 17
18char *dso__build_id_filename(const struct dso *dso, char *bf, size_t size); 18char *dso__build_id_filename(const struct dso *dso, char *bf, size_t size);
19bool dso__build_id_is_kmod(const struct dso *dso, char *bf, size_t size);
19 20
20int build_id__mark_dso_hit(struct perf_tool *tool, union perf_event *event, 21int build_id__mark_dso_hit(struct perf_tool *tool, union perf_event *event,
21 struct perf_sample *sample, struct perf_evsel *evsel, 22 struct perf_sample *sample, struct perf_evsel *evsel,
diff --git a/tools/perf/util/cache.h b/tools/perf/util/cache.h
index 07b5d63947b1..1f5a93c2c9a2 100644
--- a/tools/perf/util/cache.h
+++ b/tools/perf/util/cache.h
@@ -23,14 +23,17 @@
23#define PERF_TRACEFS_ENVIRONMENT "PERF_TRACEFS_DIR" 23#define PERF_TRACEFS_ENVIRONMENT "PERF_TRACEFS_DIR"
24#define PERF_PAGER_ENVIRONMENT "PERF_PAGER" 24#define PERF_PAGER_ENVIRONMENT "PERF_PAGER"
25 25
26extern const char *config_exclusive_filename;
27
26typedef int (*config_fn_t)(const char *, const char *, void *); 28typedef int (*config_fn_t)(const char *, const char *, void *);
27extern int perf_default_config(const char *, const char *, void *); 29int perf_default_config(const char *, const char *, void *);
28extern int perf_config(config_fn_t fn, void *); 30int perf_config(config_fn_t fn, void *);
29extern int perf_config_int(const char *, const char *); 31int perf_config_int(const char *, const char *);
30extern u64 perf_config_u64(const char *, const char *); 32u64 perf_config_u64(const char *, const char *);
31extern int perf_config_bool(const char *, const char *); 33int perf_config_bool(const char *, const char *);
32extern int config_error_nonbool(const char *); 34int config_error_nonbool(const char *);
33extern const char *perf_config_dirname(const char *, const char *); 35const char *perf_config_dirname(const char *, const char *);
36const char *perf_etc_perfconfig(void);
34 37
35char *alias_lookup(const char *alias); 38char *alias_lookup(const char *alias);
36int split_cmdline(char *cmdline, const char ***argv); 39int split_cmdline(char *cmdline, const char ***argv);
@@ -61,13 +64,9 @@ static inline int is_absolute_path(const char *path)
61 return path[0] == '/'; 64 return path[0] == '/';
62} 65}
63 66
64const char *make_nonrelative_path(const char *path);
65char *strip_path_suffix(const char *path, const char *suffix); 67char *strip_path_suffix(const char *path, const char *suffix);
66 68
67extern char *mkpath(const char *fmt, ...) __attribute__((format (printf, 1, 2))); 69char *mkpath(const char *fmt, ...) __attribute__((format (printf, 1, 2)));
68extern char *perf_path(const char *fmt, ...) __attribute__((format (printf, 1, 2))); 70char *perf_path(const char *fmt, ...) __attribute__((format (printf, 1, 2)));
69
70extern char *perf_pathdup(const char *fmt, ...)
71 __attribute__((format (printf, 1, 2)));
72 71
73#endif /* __PERF_CACHE_H */ 72#endif /* __PERF_CACHE_H */
diff --git a/tools/perf/util/callchain.c b/tools/perf/util/callchain.c
index 53c43eb9489e..24b4bd0d7754 100644
--- a/tools/perf/util/callchain.c
+++ b/tools/perf/util/callchain.c
@@ -416,7 +416,7 @@ create_child(struct callchain_node *parent, bool inherit_children)
416/* 416/*
417 * Fill the node with callchain values 417 * Fill the node with callchain values
418 */ 418 */
419static void 419static int
420fill_node(struct callchain_node *node, struct callchain_cursor *cursor) 420fill_node(struct callchain_node *node, struct callchain_cursor *cursor)
421{ 421{
422 struct callchain_cursor_node *cursor_node; 422 struct callchain_cursor_node *cursor_node;
@@ -433,7 +433,7 @@ fill_node(struct callchain_node *node, struct callchain_cursor *cursor)
433 call = zalloc(sizeof(*call)); 433 call = zalloc(sizeof(*call));
434 if (!call) { 434 if (!call) {
435 perror("not enough memory for the code path tree"); 435 perror("not enough memory for the code path tree");
436 return; 436 return -1;
437 } 437 }
438 call->ip = cursor_node->ip; 438 call->ip = cursor_node->ip;
439 call->ms.sym = cursor_node->sym; 439 call->ms.sym = cursor_node->sym;
@@ -443,6 +443,7 @@ fill_node(struct callchain_node *node, struct callchain_cursor *cursor)
443 callchain_cursor_advance(cursor); 443 callchain_cursor_advance(cursor);
444 cursor_node = callchain_cursor_current(cursor); 444 cursor_node = callchain_cursor_current(cursor);
445 } 445 }
446 return 0;
446} 447}
447 448
448static struct callchain_node * 449static struct callchain_node *
@@ -453,7 +454,19 @@ add_child(struct callchain_node *parent,
453 struct callchain_node *new; 454 struct callchain_node *new;
454 455
455 new = create_child(parent, false); 456 new = create_child(parent, false);
456 fill_node(new, cursor); 457 if (new == NULL)
458 return NULL;
459
460 if (fill_node(new, cursor) < 0) {
461 struct callchain_list *call, *tmp;
462
463 list_for_each_entry_safe(call, tmp, &new->val, list) {
464 list_del(&call->list);
465 free(call);
466 }
467 free(new);
468 return NULL;
469 }
457 470
458 new->children_hit = 0; 471 new->children_hit = 0;
459 new->hit = period; 472 new->hit = period;
@@ -462,16 +475,32 @@ add_child(struct callchain_node *parent,
462 return new; 475 return new;
463} 476}
464 477
465static s64 match_chain(struct callchain_cursor_node *node, 478enum match_result {
466 struct callchain_list *cnode) 479 MATCH_ERROR = -1,
480 MATCH_EQ,
481 MATCH_LT,
482 MATCH_GT,
483};
484
485static enum match_result match_chain(struct callchain_cursor_node *node,
486 struct callchain_list *cnode)
467{ 487{
468 struct symbol *sym = node->sym; 488 struct symbol *sym = node->sym;
489 u64 left, right;
469 490
470 if (cnode->ms.sym && sym && 491 if (cnode->ms.sym && sym &&
471 callchain_param.key == CCKEY_FUNCTION) 492 callchain_param.key == CCKEY_FUNCTION) {
472 return cnode->ms.sym->start - sym->start; 493 left = cnode->ms.sym->start;
473 else 494 right = sym->start;
474 return cnode->ip - node->ip; 495 } else {
496 left = cnode->ip;
497 right = node->ip;
498 }
499
500 if (left == right)
501 return MATCH_EQ;
502
503 return left > right ? MATCH_GT : MATCH_LT;
475} 504}
476 505
477/* 506/*
@@ -479,7 +508,7 @@ static s64 match_chain(struct callchain_cursor_node *node,
479 * give a part of its callchain to the created child. 508 * give a part of its callchain to the created child.
480 * Then create another child to host the given callchain of new branch 509 * Then create another child to host the given callchain of new branch
481 */ 510 */
482static void 511static int
483split_add_child(struct callchain_node *parent, 512split_add_child(struct callchain_node *parent,
484 struct callchain_cursor *cursor, 513 struct callchain_cursor *cursor,
485 struct callchain_list *to_split, 514 struct callchain_list *to_split,
@@ -491,6 +520,8 @@ split_add_child(struct callchain_node *parent,
491 520
492 /* split */ 521 /* split */
493 new = create_child(parent, true); 522 new = create_child(parent, true);
523 if (new == NULL)
524 return -1;
494 525
495 /* split the callchain and move a part to the new child */ 526 /* split the callchain and move a part to the new child */
496 old_tail = parent->val.prev; 527 old_tail = parent->val.prev;
@@ -524,6 +555,8 @@ split_add_child(struct callchain_node *parent,
524 555
525 node = callchain_cursor_current(cursor); 556 node = callchain_cursor_current(cursor);
526 new = add_child(parent, cursor, period); 557 new = add_child(parent, cursor, period);
558 if (new == NULL)
559 return -1;
527 560
528 /* 561 /*
529 * This is second child since we moved parent's children 562 * This is second child since we moved parent's children
@@ -534,7 +567,7 @@ split_add_child(struct callchain_node *parent,
534 cnode = list_first_entry(&first->val, struct callchain_list, 567 cnode = list_first_entry(&first->val, struct callchain_list,
535 list); 568 list);
536 569
537 if (match_chain(node, cnode) < 0) 570 if (match_chain(node, cnode) == MATCH_LT)
538 pp = &p->rb_left; 571 pp = &p->rb_left;
539 else 572 else
540 pp = &p->rb_right; 573 pp = &p->rb_right;
@@ -545,14 +578,15 @@ split_add_child(struct callchain_node *parent,
545 parent->hit = period; 578 parent->hit = period;
546 parent->count = 1; 579 parent->count = 1;
547 } 580 }
581 return 0;
548} 582}
549 583
550static int 584static enum match_result
551append_chain(struct callchain_node *root, 585append_chain(struct callchain_node *root,
552 struct callchain_cursor *cursor, 586 struct callchain_cursor *cursor,
553 u64 period); 587 u64 period);
554 588
555static void 589static int
556append_chain_children(struct callchain_node *root, 590append_chain_children(struct callchain_node *root,
557 struct callchain_cursor *cursor, 591 struct callchain_cursor *cursor,
558 u64 period) 592 u64 period)
@@ -564,36 +598,42 @@ append_chain_children(struct callchain_node *root,
564 598
565 node = callchain_cursor_current(cursor); 599 node = callchain_cursor_current(cursor);
566 if (!node) 600 if (!node)
567 return; 601 return -1;
568 602
569 /* lookup in childrens */ 603 /* lookup in childrens */
570 while (*p) { 604 while (*p) {
571 s64 ret; 605 enum match_result ret;
572 606
573 parent = *p; 607 parent = *p;
574 rnode = rb_entry(parent, struct callchain_node, rb_node_in); 608 rnode = rb_entry(parent, struct callchain_node, rb_node_in);
575 609
576 /* If at least first entry matches, rely to children */ 610 /* If at least first entry matches, rely to children */
577 ret = append_chain(rnode, cursor, period); 611 ret = append_chain(rnode, cursor, period);
578 if (ret == 0) 612 if (ret == MATCH_EQ)
579 goto inc_children_hit; 613 goto inc_children_hit;
614 if (ret == MATCH_ERROR)
615 return -1;
580 616
581 if (ret < 0) 617 if (ret == MATCH_LT)
582 p = &parent->rb_left; 618 p = &parent->rb_left;
583 else 619 else
584 p = &parent->rb_right; 620 p = &parent->rb_right;
585 } 621 }
586 /* nothing in children, add to the current node */ 622 /* nothing in children, add to the current node */
587 rnode = add_child(root, cursor, period); 623 rnode = add_child(root, cursor, period);
624 if (rnode == NULL)
625 return -1;
626
588 rb_link_node(&rnode->rb_node_in, parent, p); 627 rb_link_node(&rnode->rb_node_in, parent, p);
589 rb_insert_color(&rnode->rb_node_in, &root->rb_root_in); 628 rb_insert_color(&rnode->rb_node_in, &root->rb_root_in);
590 629
591inc_children_hit: 630inc_children_hit:
592 root->children_hit += period; 631 root->children_hit += period;
593 root->children_count++; 632 root->children_count++;
633 return 0;
594} 634}
595 635
596static int 636static enum match_result
597append_chain(struct callchain_node *root, 637append_chain(struct callchain_node *root,
598 struct callchain_cursor *cursor, 638 struct callchain_cursor *cursor,
599 u64 period) 639 u64 period)
@@ -602,7 +642,7 @@ append_chain(struct callchain_node *root,
602 u64 start = cursor->pos; 642 u64 start = cursor->pos;
603 bool found = false; 643 bool found = false;
604 u64 matches; 644 u64 matches;
605 int cmp = 0; 645 enum match_result cmp = MATCH_ERROR;
606 646
607 /* 647 /*
608 * Lookup in the current node 648 * Lookup in the current node
@@ -618,7 +658,7 @@ append_chain(struct callchain_node *root,
618 break; 658 break;
619 659
620 cmp = match_chain(node, cnode); 660 cmp = match_chain(node, cnode);
621 if (cmp) 661 if (cmp != MATCH_EQ)
622 break; 662 break;
623 663
624 found = true; 664 found = true;
@@ -628,7 +668,7 @@ append_chain(struct callchain_node *root,
628 668
629 /* matches not, relay no the parent */ 669 /* matches not, relay no the parent */
630 if (!found) { 670 if (!found) {
631 WARN_ONCE(!cmp, "Chain comparison error\n"); 671 WARN_ONCE(cmp == MATCH_ERROR, "Chain comparison error\n");
632 return cmp; 672 return cmp;
633 } 673 }
634 674
@@ -636,21 +676,25 @@ append_chain(struct callchain_node *root,
636 676
637 /* we match only a part of the node. Split it and add the new chain */ 677 /* we match only a part of the node. Split it and add the new chain */
638 if (matches < root->val_nr) { 678 if (matches < root->val_nr) {
639 split_add_child(root, cursor, cnode, start, matches, period); 679 if (split_add_child(root, cursor, cnode, start, matches,
640 return 0; 680 period) < 0)
681 return MATCH_ERROR;
682
683 return MATCH_EQ;
641 } 684 }
642 685
643 /* we match 100% of the path, increment the hit */ 686 /* we match 100% of the path, increment the hit */
644 if (matches == root->val_nr && cursor->pos == cursor->nr) { 687 if (matches == root->val_nr && cursor->pos == cursor->nr) {
645 root->hit += period; 688 root->hit += period;
646 root->count++; 689 root->count++;
647 return 0; 690 return MATCH_EQ;
648 } 691 }
649 692
650 /* We match the node and still have a part remaining */ 693 /* We match the node and still have a part remaining */
651 append_chain_children(root, cursor, period); 694 if (append_chain_children(root, cursor, period) < 0)
695 return MATCH_ERROR;
652 696
653 return 0; 697 return MATCH_EQ;
654} 698}
655 699
656int callchain_append(struct callchain_root *root, 700int callchain_append(struct callchain_root *root,
@@ -662,7 +706,8 @@ int callchain_append(struct callchain_root *root,
662 706
663 callchain_cursor_commit(cursor); 707 callchain_cursor_commit(cursor);
664 708
665 append_chain_children(&root->node, cursor, period); 709 if (append_chain_children(&root->node, cursor, period) < 0)
710 return -1;
666 711
667 if (cursor->nr > root->max_depth) 712 if (cursor->nr > root->max_depth)
668 root->max_depth = cursor->nr; 713 root->max_depth = cursor->nr;
@@ -690,7 +735,8 @@ merge_chain_branch(struct callchain_cursor *cursor,
690 735
691 if (src->hit) { 736 if (src->hit) {
692 callchain_cursor_commit(cursor); 737 callchain_cursor_commit(cursor);
693 append_chain_children(dst, cursor, src->hit); 738 if (append_chain_children(dst, cursor, src->hit) < 0)
739 return -1;
694 } 740 }
695 741
696 n = rb_first(&src->rb_root_in); 742 n = rb_first(&src->rb_root_in);
diff --git a/tools/perf/util/callchain.h b/tools/perf/util/callchain.h
index 18dd22269764..d2a9e694810c 100644
--- a/tools/perf/util/callchain.h
+++ b/tools/perf/util/callchain.h
@@ -220,7 +220,7 @@ int fill_callchain_info(struct addr_location *al, struct callchain_cursor_node *
220 bool hide_unresolved); 220 bool hide_unresolved);
221 221
222extern const char record_callchain_help[]; 222extern const char record_callchain_help[];
223extern int parse_callchain_record(const char *arg, struct callchain_param *param); 223int parse_callchain_record(const char *arg, struct callchain_param *param);
224int parse_callchain_record_opt(const char *arg, struct callchain_param *param); 224int parse_callchain_record_opt(const char *arg, struct callchain_param *param);
225int parse_callchain_report_opt(const char *arg); 225int parse_callchain_report_opt(const char *arg);
226int parse_callchain_top_opt(const char *arg); 226int parse_callchain_top_opt(const char *arg);
@@ -236,7 +236,7 @@ static inline void callchain_cursor_snapshot(struct callchain_cursor *dest,
236} 236}
237 237
238#ifdef HAVE_SKIP_CALLCHAIN_IDX 238#ifdef HAVE_SKIP_CALLCHAIN_IDX
239extern int arch_skip_callchain_idx(struct thread *thread, struct ip_callchain *chain); 239int arch_skip_callchain_idx(struct thread *thread, struct ip_callchain *chain);
240#else 240#else
241static inline int arch_skip_callchain_idx(struct thread *thread __maybe_unused, 241static inline int arch_skip_callchain_idx(struct thread *thread __maybe_unused,
242 struct ip_callchain *chain __maybe_unused) 242 struct ip_callchain *chain __maybe_unused)
diff --git a/tools/perf/util/cgroup.h b/tools/perf/util/cgroup.h
index b4b8cb42fe5e..31f8dcdbd7ef 100644
--- a/tools/perf/util/cgroup.h
+++ b/tools/perf/util/cgroup.h
@@ -13,7 +13,7 @@ struct cgroup_sel {
13 13
14 14
15extern int nr_cgroups; /* number of explicit cgroups defined */ 15extern int nr_cgroups; /* number of explicit cgroups defined */
16extern void close_cgroup(struct cgroup_sel *cgrp); 16void close_cgroup(struct cgroup_sel *cgrp);
17extern int parse_cgroups(const struct option *opt, const char *str, int unset); 17int parse_cgroups(const struct option *opt, const char *str, int unset);
18 18
19#endif /* __CGROUP_H__ */ 19#endif /* __CGROUP_H__ */
diff --git a/tools/perf/util/cloexec.h b/tools/perf/util/cloexec.h
index 3bee6773ddb0..d0d465953d36 100644
--- a/tools/perf/util/cloexec.h
+++ b/tools/perf/util/cloexec.h
@@ -5,7 +5,7 @@ unsigned long perf_event_open_cloexec_flag(void);
5 5
6#ifdef __GLIBC_PREREQ 6#ifdef __GLIBC_PREREQ
7#if !__GLIBC_PREREQ(2, 6) && !defined(__UCLIBC__) 7#if !__GLIBC_PREREQ(2, 6) && !defined(__UCLIBC__)
8extern int sched_getcpu(void) __THROW; 8int sched_getcpu(void) __THROW;
9#endif 9#endif
10#endif 10#endif
11 11
diff --git a/tools/perf/util/color.c b/tools/perf/util/color.c
index e5fb88bab9e1..43e84aa27e4a 100644
--- a/tools/perf/util/color.c
+++ b/tools/perf/util/color.c
@@ -32,14 +32,15 @@ int perf_config_colorbool(const char *var, const char *value, int stdout_is_tty)
32 return 0; 32 return 0;
33} 33}
34 34
35int perf_color_default_config(const char *var, const char *value, void *cb) 35int perf_color_default_config(const char *var, const char *value,
36 void *cb __maybe_unused)
36{ 37{
37 if (!strcmp(var, "color.ui")) { 38 if (!strcmp(var, "color.ui")) {
38 perf_use_color_default = perf_config_colorbool(var, value, -1); 39 perf_use_color_default = perf_config_colorbool(var, value, -1);
39 return 0; 40 return 0;
40 } 41 }
41 42
42 return perf_default_config(var, value, cb); 43 return 0;
43} 44}
44 45
45static int __color_vsnprintf(char *bf, size_t size, const char *color, 46static int __color_vsnprintf(char *bf, size_t size, const char *color,
diff --git a/tools/perf/util/config.c b/tools/perf/util/config.c
index d3e12e30e1d5..4e727635476e 100644
--- a/tools/perf/util/config.c
+++ b/tools/perf/util/config.c
@@ -26,7 +26,7 @@ static const char *config_file_name;
26static int config_linenr; 26static int config_linenr;
27static int config_file_eof; 27static int config_file_eof;
28 28
29static const char *config_exclusive_filename; 29const char *config_exclusive_filename;
30 30
31static int get_next_char(void) 31static int get_next_char(void)
32{ 32{
@@ -434,7 +434,7 @@ static int perf_config_from_file(config_fn_t fn, const char *filename, void *dat
434 return ret; 434 return ret;
435} 435}
436 436
437static const char *perf_etc_perfconfig(void) 437const char *perf_etc_perfconfig(void)
438{ 438{
439 static const char *system_wide; 439 static const char *system_wide;
440 if (!system_wide) 440 if (!system_wide)
diff --git a/tools/perf/util/cpumap.c b/tools/perf/util/cpumap.c
index fa935093a599..9bcf2bed3a6d 100644
--- a/tools/perf/util/cpumap.c
+++ b/tools/perf/util/cpumap.c
@@ -8,6 +8,10 @@
8#include <linux/bitmap.h> 8#include <linux/bitmap.h>
9#include "asm/bug.h" 9#include "asm/bug.h"
10 10
11static int max_cpu_num;
12static int max_node_num;
13static int *cpunode_map;
14
11static struct cpu_map *cpu_map__default_new(void) 15static struct cpu_map *cpu_map__default_new(void)
12{ 16{
13 struct cpu_map *cpus; 17 struct cpu_map *cpus;
@@ -486,6 +490,32 @@ out:
486 pr_err("Failed to read max nodes, using default of %d\n", max_node_num); 490 pr_err("Failed to read max nodes, using default of %d\n", max_node_num);
487} 491}
488 492
493int cpu__max_node(void)
494{
495 if (unlikely(!max_node_num))
496 set_max_node_num();
497
498 return max_node_num;
499}
500
501int cpu__max_cpu(void)
502{
503 if (unlikely(!max_cpu_num))
504 set_max_cpu_num();
505
506 return max_cpu_num;
507}
508
509int cpu__get_node(int cpu)
510{
511 if (unlikely(cpunode_map == NULL)) {
512 pr_debug("cpu_map not initialized\n");
513 return -1;
514 }
515
516 return cpunode_map[cpu];
517}
518
489static int init_cpunode_map(void) 519static int init_cpunode_map(void)
490{ 520{
491 int i; 521 int i;
diff --git a/tools/perf/util/cpumap.h b/tools/perf/util/cpumap.h
index 71c41b9efabb..81a2562aaa2b 100644
--- a/tools/perf/util/cpumap.h
+++ b/tools/perf/util/cpumap.h
@@ -57,37 +57,11 @@ static inline bool cpu_map__empty(const struct cpu_map *map)
57 return map ? map->map[0] == -1 : true; 57 return map ? map->map[0] == -1 : true;
58} 58}
59 59
60int max_cpu_num;
61int max_node_num;
62int *cpunode_map;
63
64int cpu__setup_cpunode_map(void); 60int cpu__setup_cpunode_map(void);
65 61
66static inline int cpu__max_node(void) 62int cpu__max_node(void);
67{ 63int cpu__max_cpu(void);
68 if (unlikely(!max_node_num)) 64int cpu__get_node(int cpu);
69 pr_debug("cpu_map not initialized\n");
70
71 return max_node_num;
72}
73
74static inline int cpu__max_cpu(void)
75{
76 if (unlikely(!max_cpu_num))
77 pr_debug("cpu_map not initialized\n");
78
79 return max_cpu_num;
80}
81
82static inline int cpu__get_node(int cpu)
83{
84 if (unlikely(cpunode_map == NULL)) {
85 pr_debug("cpu_map not initialized\n");
86 return -1;
87 }
88
89 return cpunode_map[cpu];
90}
91 65
92int cpu_map__build_map(struct cpu_map *cpus, struct cpu_map **res, 66int cpu_map__build_map(struct cpu_map *cpus, struct cpu_map **res,
93 int (*f)(struct cpu_map *map, int cpu, void *data), 67 int (*f)(struct cpu_map *map, int cpu, void *data),
diff --git a/tools/perf/util/ctype.c b/tools/perf/util/ctype.c
index aada3ac5e891..d4a5a21c2a7e 100644
--- a/tools/perf/util/ctype.c
+++ b/tools/perf/util/ctype.c
@@ -32,8 +32,17 @@ unsigned char sane_ctype[256] = {
32 32
33const char *graph_line = 33const char *graph_line =
34 "_____________________________________________________________________" 34 "_____________________________________________________________________"
35 "_____________________________________________________________________"
35 "_____________________________________________________________________"; 36 "_____________________________________________________________________";
36const char *graph_dotted_line = 37const char *graph_dotted_line =
37 "---------------------------------------------------------------------" 38 "---------------------------------------------------------------------"
38 "---------------------------------------------------------------------" 39 "---------------------------------------------------------------------"
39 "---------------------------------------------------------------------"; 40 "---------------------------------------------------------------------";
41const char *spaces =
42 " "
43 " "
44 " ";
45const char *dots =
46 "....................................................................."
47 "....................................................................."
48 ".....................................................................";
diff --git a/tools/perf/util/data-convert-bt.c b/tools/perf/util/data-convert-bt.c
index 34cd1e4039d3..bbf69d248ec5 100644
--- a/tools/perf/util/data-convert-bt.c
+++ b/tools/perf/util/data-convert-bt.c
@@ -352,6 +352,84 @@ static int add_tracepoint_values(struct ctf_writer *cw,
352 return ret; 352 return ret;
353} 353}
354 354
355static int
356add_bpf_output_values(struct bt_ctf_event_class *event_class,
357 struct bt_ctf_event *event,
358 struct perf_sample *sample)
359{
360 struct bt_ctf_field_type *len_type, *seq_type;
361 struct bt_ctf_field *len_field, *seq_field;
362 unsigned int raw_size = sample->raw_size;
363 unsigned int nr_elements = raw_size / sizeof(u32);
364 unsigned int i;
365 int ret;
366
367 if (nr_elements * sizeof(u32) != raw_size)
368 pr_warning("Incorrect raw_size (%u) in bpf output event, skip %lu bytes\n",
369 raw_size, nr_elements * sizeof(u32) - raw_size);
370
371 len_type = bt_ctf_event_class_get_field_by_name(event_class, "raw_len");
372 len_field = bt_ctf_field_create(len_type);
373 if (!len_field) {
374 pr_err("failed to create 'raw_len' for bpf output event\n");
375 ret = -1;
376 goto put_len_type;
377 }
378
379 ret = bt_ctf_field_unsigned_integer_set_value(len_field, nr_elements);
380 if (ret) {
381 pr_err("failed to set field value for raw_len\n");
382 goto put_len_field;
383 }
384 ret = bt_ctf_event_set_payload(event, "raw_len", len_field);
385 if (ret) {
386 pr_err("failed to set payload to raw_len\n");
387 goto put_len_field;
388 }
389
390 seq_type = bt_ctf_event_class_get_field_by_name(event_class, "raw_data");
391 seq_field = bt_ctf_field_create(seq_type);
392 if (!seq_field) {
393 pr_err("failed to create 'raw_data' for bpf output event\n");
394 ret = -1;
395 goto put_seq_type;
396 }
397
398 ret = bt_ctf_field_sequence_set_length(seq_field, len_field);
399 if (ret) {
400 pr_err("failed to set length of 'raw_data'\n");
401 goto put_seq_field;
402 }
403
404 for (i = 0; i < nr_elements; i++) {
405 struct bt_ctf_field *elem_field =
406 bt_ctf_field_sequence_get_field(seq_field, i);
407
408 ret = bt_ctf_field_unsigned_integer_set_value(elem_field,
409 ((u32 *)(sample->raw_data))[i]);
410
411 bt_ctf_field_put(elem_field);
412 if (ret) {
413 pr_err("failed to set raw_data[%d]\n", i);
414 goto put_seq_field;
415 }
416 }
417
418 ret = bt_ctf_event_set_payload(event, "raw_data", seq_field);
419 if (ret)
420 pr_err("failed to set payload for raw_data\n");
421
422put_seq_field:
423 bt_ctf_field_put(seq_field);
424put_seq_type:
425 bt_ctf_field_type_put(seq_type);
426put_len_field:
427 bt_ctf_field_put(len_field);
428put_len_type:
429 bt_ctf_field_type_put(len_type);
430 return ret;
431}
432
355static int add_generic_values(struct ctf_writer *cw, 433static int add_generic_values(struct ctf_writer *cw,
356 struct bt_ctf_event *event, 434 struct bt_ctf_event *event,
357 struct perf_evsel *evsel, 435 struct perf_evsel *evsel,
@@ -554,7 +632,7 @@ static bool is_flush_needed(struct ctf_stream *cs)
554} 632}
555 633
556static int process_sample_event(struct perf_tool *tool, 634static int process_sample_event(struct perf_tool *tool,
557 union perf_event *_event __maybe_unused, 635 union perf_event *_event,
558 struct perf_sample *sample, 636 struct perf_sample *sample,
559 struct perf_evsel *evsel, 637 struct perf_evsel *evsel,
560 struct machine *machine __maybe_unused) 638 struct machine *machine __maybe_unused)
@@ -597,6 +675,12 @@ static int process_sample_event(struct perf_tool *tool,
597 return -1; 675 return -1;
598 } 676 }
599 677
678 if (perf_evsel__is_bpf_output(evsel)) {
679 ret = add_bpf_output_values(event_class, event, sample);
680 if (ret)
681 return -1;
682 }
683
600 cs = ctf_stream(cw, get_sample_cpu(cw, sample, evsel)); 684 cs = ctf_stream(cw, get_sample_cpu(cw, sample, evsel));
601 if (cs) { 685 if (cs) {
602 if (is_flush_needed(cs)) 686 if (is_flush_needed(cs))
@@ -744,6 +828,25 @@ static int add_tracepoint_types(struct ctf_writer *cw,
744 return ret; 828 return ret;
745} 829}
746 830
831static int add_bpf_output_types(struct ctf_writer *cw,
832 struct bt_ctf_event_class *class)
833{
834 struct bt_ctf_field_type *len_type = cw->data.u32;
835 struct bt_ctf_field_type *seq_base_type = cw->data.u32_hex;
836 struct bt_ctf_field_type *seq_type;
837 int ret;
838
839 ret = bt_ctf_event_class_add_field(class, len_type, "raw_len");
840 if (ret)
841 return ret;
842
843 seq_type = bt_ctf_field_type_sequence_create(seq_base_type, "raw_len");
844 if (!seq_type)
845 return -1;
846
847 return bt_ctf_event_class_add_field(class, seq_type, "raw_data");
848}
849
747static int add_generic_types(struct ctf_writer *cw, struct perf_evsel *evsel, 850static int add_generic_types(struct ctf_writer *cw, struct perf_evsel *evsel,
748 struct bt_ctf_event_class *event_class) 851 struct bt_ctf_event_class *event_class)
749{ 852{
@@ -755,7 +858,8 @@ static int add_generic_types(struct ctf_writer *cw, struct perf_evsel *evsel,
755 * ctf event header 858 * ctf event header
756 * PERF_SAMPLE_READ - TODO 859 * PERF_SAMPLE_READ - TODO
757 * PERF_SAMPLE_CALLCHAIN - TODO 860 * PERF_SAMPLE_CALLCHAIN - TODO
758 * PERF_SAMPLE_RAW - tracepoint fields are handled separately 861 * PERF_SAMPLE_RAW - tracepoint fields and BPF output
862 * are handled separately
759 * PERF_SAMPLE_BRANCH_STACK - TODO 863 * PERF_SAMPLE_BRANCH_STACK - TODO
760 * PERF_SAMPLE_REGS_USER - TODO 864 * PERF_SAMPLE_REGS_USER - TODO
761 * PERF_SAMPLE_STACK_USER - TODO 865 * PERF_SAMPLE_STACK_USER - TODO
@@ -824,6 +928,12 @@ static int add_event(struct ctf_writer *cw, struct perf_evsel *evsel)
824 goto err; 928 goto err;
825 } 929 }
826 930
931 if (perf_evsel__is_bpf_output(evsel)) {
932 ret = add_bpf_output_types(cw, event_class);
933 if (ret)
934 goto err;
935 }
936
827 ret = bt_ctf_stream_class_add_event_class(cw->stream_class, event_class); 937 ret = bt_ctf_stream_class_add_event_class(cw->stream_class, event_class);
828 if (ret) { 938 if (ret) {
829 pr("Failed to add event class into stream.\n"); 939 pr("Failed to add event class into stream.\n");
@@ -858,6 +968,23 @@ static int setup_events(struct ctf_writer *cw, struct perf_session *session)
858 return 0; 968 return 0;
859} 969}
860 970
971static void cleanup_events(struct perf_session *session)
972{
973 struct perf_evlist *evlist = session->evlist;
974 struct perf_evsel *evsel;
975
976 evlist__for_each(evlist, evsel) {
977 struct evsel_priv *priv;
978
979 priv = evsel->priv;
980 bt_ctf_event_class_put(priv->event_class);
981 zfree(&evsel->priv);
982 }
983
984 perf_evlist__delete(evlist);
985 session->evlist = NULL;
986}
987
861static int setup_streams(struct ctf_writer *cw, struct perf_session *session) 988static int setup_streams(struct ctf_writer *cw, struct perf_session *session)
862{ 989{
863 struct ctf_stream **stream; 990 struct ctf_stream **stream;
@@ -953,6 +1080,12 @@ static struct bt_ctf_field_type *create_int_type(int size, bool sign, bool hex)
953 bt_ctf_field_type_integer_set_base(type, BT_CTF_INTEGER_BASE_HEXADECIMAL)) 1080 bt_ctf_field_type_integer_set_base(type, BT_CTF_INTEGER_BASE_HEXADECIMAL))
954 goto err; 1081 goto err;
955 1082
1083#if __BYTE_ORDER == __BIG_ENDIAN
1084 bt_ctf_field_type_set_byte_order(type, BT_CTF_BYTE_ORDER_BIG_ENDIAN);
1085#else
1086 bt_ctf_field_type_set_byte_order(type, BT_CTF_BYTE_ORDER_LITTLE_ENDIAN);
1087#endif
1088
956 pr2("Created type: INTEGER %d-bit %ssigned %s\n", 1089 pr2("Created type: INTEGER %d-bit %ssigned %s\n",
957 size, sign ? "un" : "", hex ? "hex" : ""); 1090 size, sign ? "un" : "", hex ? "hex" : "");
958 return type; 1091 return type;
@@ -1100,7 +1233,7 @@ static int convert__config(const char *var, const char *value, void *cb)
1100 return 0; 1233 return 0;
1101 } 1234 }
1102 1235
1103 return perf_default_config(var, value, cb); 1236 return 0;
1104} 1237}
1105 1238
1106int bt_convert__perf2ctf(const char *input, const char *path, bool force) 1239int bt_convert__perf2ctf(const char *input, const char *path, bool force)
@@ -1171,6 +1304,7 @@ int bt_convert__perf2ctf(const char *input, const char *path, bool force)
1171 (double) c.events_size / 1024.0 / 1024.0, 1304 (double) c.events_size / 1024.0 / 1024.0,
1172 c.events_count); 1305 c.events_count);
1173 1306
1307 cleanup_events(session);
1174 perf_session__delete(session); 1308 perf_session__delete(session);
1175 ctf_writer__cleanup(cw); 1309 ctf_writer__cleanup(cw);
1176 1310
diff --git a/tools/perf/util/db-export.c b/tools/perf/util/db-export.c
index 1c9689e4cc17..049438d51b9a 100644
--- a/tools/perf/util/db-export.c
+++ b/tools/perf/util/db-export.c
@@ -333,7 +333,7 @@ int db_export__sample(struct db_export *dbe, union perf_event *event,
333 sample_addr_correlates_sym(&evsel->attr)) { 333 sample_addr_correlates_sym(&evsel->attr)) {
334 struct addr_location addr_al; 334 struct addr_location addr_al;
335 335
336 perf_event__preprocess_sample_addr(event, sample, thread, &addr_al); 336 thread__resolve(thread, &addr_al, sample);
337 err = db_ids_from_al(dbe, &addr_al, &es.addr_dso_db_id, 337 err = db_ids_from_al(dbe, &addr_al, &es.addr_dso_db_id,
338 &es.addr_sym_db_id, &es.addr_offset); 338 &es.addr_sym_db_id, &es.addr_offset);
339 if (err) 339 if (err)
diff --git a/tools/perf/util/debug.c b/tools/perf/util/debug.c
index 86d9c7302598..8c4212abd19b 100644
--- a/tools/perf/util/debug.c
+++ b/tools/perf/util/debug.c
@@ -5,6 +5,7 @@
5#include <string.h> 5#include <string.h>
6#include <stdarg.h> 6#include <stdarg.h>
7#include <stdio.h> 7#include <stdio.h>
8#include <api/debug.h>
8 9
9#include "cache.h" 10#include "cache.h"
10#include "color.h" 11#include "color.h"
@@ -22,7 +23,7 @@ int debug_ordered_events;
22static int redirect_to_stderr; 23static int redirect_to_stderr;
23int debug_data_convert; 24int debug_data_convert;
24 25
25static int _eprintf(int level, int var, const char *fmt, va_list args) 26int veprintf(int level, int var, const char *fmt, va_list args)
26{ 27{
27 int ret = 0; 28 int ret = 0;
28 29
@@ -36,24 +37,19 @@ static int _eprintf(int level, int var, const char *fmt, va_list args)
36 return ret; 37 return ret;
37} 38}
38 39
39int veprintf(int level, int var, const char *fmt, va_list args)
40{
41 return _eprintf(level, var, fmt, args);
42}
43
44int eprintf(int level, int var, const char *fmt, ...) 40int eprintf(int level, int var, const char *fmt, ...)
45{ 41{
46 va_list args; 42 va_list args;
47 int ret; 43 int ret;
48 44
49 va_start(args, fmt); 45 va_start(args, fmt);
50 ret = _eprintf(level, var, fmt, args); 46 ret = veprintf(level, var, fmt, args);
51 va_end(args); 47 va_end(args);
52 48
53 return ret; 49 return ret;
54} 50}
55 51
56static int __eprintf_time(u64 t, const char *fmt, va_list args) 52static int veprintf_time(u64 t, const char *fmt, va_list args)
57{ 53{
58 int ret = 0; 54 int ret = 0;
59 u64 secs, usecs, nsecs = t; 55 u64 secs, usecs, nsecs = t;
@@ -75,7 +71,7 @@ int eprintf_time(int level, int var, u64 t, const char *fmt, ...)
75 71
76 if (var >= level) { 72 if (var >= level) {
77 va_start(args, fmt); 73 va_start(args, fmt);
78 ret = __eprintf_time(t, fmt, args); 74 ret = veprintf_time(t, fmt, args);
79 va_end(args); 75 va_end(args);
80 } 76 }
81 77
@@ -91,7 +87,7 @@ void pr_stat(const char *fmt, ...)
91 va_list args; 87 va_list args;
92 88
93 va_start(args, fmt); 89 va_start(args, fmt);
94 _eprintf(1, verbose, fmt, args); 90 veprintf(1, verbose, fmt, args);
95 va_end(args); 91 va_end(args);
96 eprintf(1, verbose, "\n"); 92 eprintf(1, verbose, "\n");
97} 93}
@@ -110,40 +106,61 @@ int dump_printf(const char *fmt, ...)
110 return ret; 106 return ret;
111} 107}
112 108
109static void trace_event_printer(enum binary_printer_ops op,
110 unsigned int val, void *extra)
111{
112 const char *color = PERF_COLOR_BLUE;
113 union perf_event *event = (union perf_event *)extra;
114 unsigned char ch = (unsigned char)val;
115
116 switch (op) {
117 case BINARY_PRINT_DATA_BEGIN:
118 printf(".");
119 color_fprintf(stdout, color, "\n. ... raw event: size %d bytes\n",
120 event->header.size);
121 break;
122 case BINARY_PRINT_LINE_BEGIN:
123 printf(".");
124 break;
125 case BINARY_PRINT_ADDR:
126 color_fprintf(stdout, color, " %04x: ", val);
127 break;
128 case BINARY_PRINT_NUM_DATA:
129 color_fprintf(stdout, color, " %02x", val);
130 break;
131 case BINARY_PRINT_NUM_PAD:
132 color_fprintf(stdout, color, " ");
133 break;
134 case BINARY_PRINT_SEP:
135 color_fprintf(stdout, color, " ");
136 break;
137 case BINARY_PRINT_CHAR_DATA:
138 color_fprintf(stdout, color, "%c",
139 isprint(ch) ? ch : '.');
140 break;
141 case BINARY_PRINT_CHAR_PAD:
142 color_fprintf(stdout, color, " ");
143 break;
144 case BINARY_PRINT_LINE_END:
145 color_fprintf(stdout, color, "\n");
146 break;
147 case BINARY_PRINT_DATA_END:
148 printf("\n");
149 break;
150 default:
151 break;
152 }
153}
154
113void trace_event(union perf_event *event) 155void trace_event(union perf_event *event)
114{ 156{
115 unsigned char *raw_event = (void *)event; 157 unsigned char *raw_event = (void *)event;
116 const char *color = PERF_COLOR_BLUE;
117 int i, j;
118 158
119 if (!dump_trace) 159 if (!dump_trace)
120 return; 160 return;
121 161
122 printf("."); 162 print_binary(raw_event, event->header.size, 16,
123 color_fprintf(stdout, color, "\n. ... raw event: size %d bytes\n", 163 trace_event_printer, event);
124 event->header.size);
125
126 for (i = 0; i < event->header.size; i++) {
127 if ((i & 15) == 0) {
128 printf(".");
129 color_fprintf(stdout, color, " %04x: ", i);
130 }
131
132 color_fprintf(stdout, color, " %02x", raw_event[i]);
133
134 if (((i & 15) == 15) || i == event->header.size-1) {
135 color_fprintf(stdout, color, " ");
136 for (j = 0; j < 15-(i & 15); j++)
137 color_fprintf(stdout, color, " ");
138 for (j = i & ~15; j <= i; j++) {
139 color_fprintf(stdout, color, "%c",
140 isprint(raw_event[j]) ?
141 raw_event[j] : '.');
142 }
143 color_fprintf(stdout, color, "\n");
144 }
145 }
146 printf(".\n");
147} 164}
148 165
149static struct debug_variable { 166static struct debug_variable {
@@ -192,3 +209,23 @@ int perf_debug_option(const char *str)
192 free(s); 209 free(s);
193 return 0; 210 return 0;
194} 211}
212
213#define DEBUG_WRAPPER(__n, __l) \
214static int pr_ ## __n ## _wrapper(const char *fmt, ...) \
215{ \
216 va_list args; \
217 int ret; \
218 \
219 va_start(args, fmt); \
220 ret = veprintf(__l, verbose, fmt, args); \
221 va_end(args); \
222 return ret; \
223}
224
225DEBUG_WRAPPER(warning, 0);
226DEBUG_WRAPPER(debug, 1);
227
228void perf_debug_setup(void)
229{
230 libapi_set_print(pr_warning_wrapper, pr_warning_wrapper, pr_debug_wrapper);
231}
diff --git a/tools/perf/util/debug.h b/tools/perf/util/debug.h
index 8b9a088c32ab..14bafda79eda 100644
--- a/tools/perf/util/debug.h
+++ b/tools/perf/util/debug.h
@@ -53,5 +53,6 @@ int eprintf_time(int level, int var, u64 t, const char *fmt, ...) __attribute__(
53int veprintf(int level, int var, const char *fmt, va_list args); 53int veprintf(int level, int var, const char *fmt, va_list args);
54 54
55int perf_debug_option(const char *str); 55int perf_debug_option(const char *str);
56void perf_debug_setup(void);
56 57
57#endif /* __PERF_DEBUG_H */ 58#endif /* __PERF_DEBUG_H */
diff --git a/tools/perf/util/demangle-java.c b/tools/perf/util/demangle-java.c
new file mode 100644
index 000000000000..3e6062ab2cdd
--- /dev/null
+++ b/tools/perf/util/demangle-java.c
@@ -0,0 +1,199 @@
1#include <sys/types.h>
2#include <stdio.h>
3#include <string.h>
4#include "util.h"
5#include "debug.h"
6#include "symbol.h"
7
8#include "demangle-java.h"
9
10enum {
11 MODE_PREFIX = 0,
12 MODE_CLASS = 1,
13 MODE_FUNC = 2,
14 MODE_TYPE = 3,
15 MODE_CTYPE = 3, /* class arg */
16};
17
18#define BASE_ENT(c, n) [c - 'A']=n
19static const char *base_types['Z' - 'A' + 1] = {
20 BASE_ENT('B', "byte" ),
21 BASE_ENT('C', "char" ),
22 BASE_ENT('D', "double" ),
23 BASE_ENT('F', "float" ),
24 BASE_ENT('I', "int" ),
25 BASE_ENT('J', "long" ),
26 BASE_ENT('S', "short" ),
27 BASE_ENT('Z', "bool" ),
28};
29
30/*
31 * demangle Java symbol between str and end positions and stores
32 * up to maxlen characters into buf. The parser starts in mode.
33 *
34 * Use MODE_PREFIX to process entire prototype till end position
35 * Use MODE_TYPE to process return type if str starts on return type char
36 *
37 * Return:
38 * success: buf
39 * error : NULL
40 */
41static char *
42__demangle_java_sym(const char *str, const char *end, char *buf, int maxlen, int mode)
43{
44 int rlen = 0;
45 int array = 0;
46 int narg = 0;
47 const char *q;
48
49 if (!end)
50 end = str + strlen(str);
51
52 for (q = str; q != end; q++) {
53
54 if (rlen == (maxlen - 1))
55 break;
56
57 switch (*q) {
58 case 'L':
59 if (mode == MODE_PREFIX || mode == MODE_CTYPE) {
60 if (mode == MODE_CTYPE) {
61 if (narg)
62 rlen += scnprintf(buf + rlen, maxlen - rlen, ", ");
63 narg++;
64 }
65 rlen += scnprintf(buf + rlen, maxlen - rlen, "class ");
66 if (mode == MODE_PREFIX)
67 mode = MODE_CLASS;
68 } else
69 buf[rlen++] = *q;
70 break;
71 case 'B':
72 case 'C':
73 case 'D':
74 case 'F':
75 case 'I':
76 case 'J':
77 case 'S':
78 case 'Z':
79 if (mode == MODE_TYPE) {
80 if (narg)
81 rlen += scnprintf(buf + rlen, maxlen - rlen, ", ");
82 rlen += scnprintf(buf + rlen, maxlen - rlen, "%s", base_types[*q - 'A']);
83 while (array--)
84 rlen += scnprintf(buf + rlen, maxlen - rlen, "[]");
85 array = 0;
86 narg++;
87 } else
88 buf[rlen++] = *q;
89 break;
90 case 'V':
91 if (mode == MODE_TYPE) {
92 rlen += scnprintf(buf + rlen, maxlen - rlen, "void");
93 while (array--)
94 rlen += scnprintf(buf + rlen, maxlen - rlen, "[]");
95 array = 0;
96 } else
97 buf[rlen++] = *q;
98 break;
99 case '[':
100 if (mode != MODE_TYPE)
101 goto error;
102 array++;
103 break;
104 case '(':
105 if (mode != MODE_FUNC)
106 goto error;
107 buf[rlen++] = *q;
108 mode = MODE_TYPE;
109 break;
110 case ')':
111 if (mode != MODE_TYPE)
112 goto error;
113 buf[rlen++] = *q;
114 narg = 0;
115 break;
116 case ';':
117 if (mode != MODE_CLASS && mode != MODE_CTYPE)
118 goto error;
119 /* safe because at least one other char to process */
120 if (isalpha(*(q + 1)))
121 rlen += scnprintf(buf + rlen, maxlen - rlen, ".");
122 if (mode == MODE_CLASS)
123 mode = MODE_FUNC;
124 else if (mode == MODE_CTYPE)
125 mode = MODE_TYPE;
126 break;
127 case '/':
128 if (mode != MODE_CLASS && mode != MODE_CTYPE)
129 goto error;
130 rlen += scnprintf(buf + rlen, maxlen - rlen, ".");
131 break;
132 default :
133 buf[rlen++] = *q;
134 }
135 }
136 buf[rlen] = '\0';
137 return buf;
138error:
139 return NULL;
140}
141
142/*
143 * Demangle Java function signature (openJDK, not GCJ)
144 * input:
145 * str: string to parse. String is not modified
146 * flags: comobination of JAVA_DEMANGLE_* flags to modify demangling
147 * return:
148 * if input can be demangled, then a newly allocated string is returned.
149 * if input cannot be demangled, then NULL is returned
150 *
151 * Note: caller is responsible for freeing demangled string
152 */
153char *
154java_demangle_sym(const char *str, int flags)
155{
156 char *buf, *ptr;
157 char *p;
158 size_t len, l1 = 0;
159
160 if (!str)
161 return NULL;
162
163 /* find start of retunr type */
164 p = strrchr(str, ')');
165 if (!p)
166 return NULL;
167
168 /*
169 * expansion factor estimated to 3x
170 */
171 len = strlen(str) * 3 + 1;
172 buf = malloc(len);
173 if (!buf)
174 return NULL;
175
176 buf[0] = '\0';
177 if (!(flags & JAVA_DEMANGLE_NORET)) {
178 /*
179 * get return type first
180 */
181 ptr = __demangle_java_sym(p + 1, NULL, buf, len, MODE_TYPE);
182 if (!ptr)
183 goto error;
184
185 /* add space between return type and function prototype */
186 l1 = strlen(buf);
187 buf[l1++] = ' ';
188 }
189
190 /* process function up to return type */
191 ptr = __demangle_java_sym(str, p + 1, buf + l1, len - l1, MODE_PREFIX);
192 if (!ptr)
193 goto error;
194
195 return buf;
196error:
197 free(buf);
198 return NULL;
199}
diff --git a/tools/perf/util/demangle-java.h b/tools/perf/util/demangle-java.h
new file mode 100644
index 000000000000..a981c1f968fe
--- /dev/null
+++ b/tools/perf/util/demangle-java.h
@@ -0,0 +1,10 @@
1#ifndef __PERF_DEMANGLE_JAVA
2#define __PERF_DEMANGLE_JAVA 1
3/*
4 * demangle function flags
5 */
6#define JAVA_DEMANGLE_NORET 0x1 /* do not process return type */
7
8char * java_demangle_sym(const char *str, int flags);
9
10#endif /* __PERF_DEMANGLE_JAVA */
diff --git a/tools/perf/util/dso.c b/tools/perf/util/dso.c
index e8e9a9dbf5e3..8e6395439ca0 100644
--- a/tools/perf/util/dso.c
+++ b/tools/perf/util/dso.c
@@ -52,6 +52,11 @@ int dso__read_binary_type_filename(const struct dso *dso,
52 debuglink--; 52 debuglink--;
53 if (*debuglink == '/') 53 if (*debuglink == '/')
54 debuglink++; 54 debuglink++;
55
56 ret = -1;
57 if (!is_regular_file(filename))
58 break;
59
55 ret = filename__read_debuglink(filename, debuglink, 60 ret = filename__read_debuglink(filename, debuglink,
56 size - (debuglink - filename)); 61 size - (debuglink - filename));
57 } 62 }
diff --git a/tools/perf/util/dso.h b/tools/perf/util/dso.h
index 45ec4d0a50ed..0953280629cf 100644
--- a/tools/perf/util/dso.h
+++ b/tools/perf/util/dso.h
@@ -162,6 +162,7 @@ struct dso {
162 u8 loaded; 162 u8 loaded;
163 u8 rel; 163 u8 rel;
164 u8 build_id[BUILD_ID_SIZE]; 164 u8 build_id[BUILD_ID_SIZE];
165 u64 text_offset;
165 const char *short_name; 166 const char *short_name;
166 const char *long_name; 167 const char *long_name;
167 u16 long_name_len; 168 u16 long_name_len;
@@ -301,7 +302,7 @@ int __kmod_path__parse(struct kmod_path *m, const char *path,
301 * TODO 302 * TODO
302*/ 303*/
303int dso__data_get_fd(struct dso *dso, struct machine *machine); 304int dso__data_get_fd(struct dso *dso, struct machine *machine);
304void dso__data_put_fd(struct dso *dso __maybe_unused); 305void dso__data_put_fd(struct dso *dso);
305void dso__data_close(struct dso *dso); 306void dso__data_close(struct dso *dso);
306 307
307off_t dso__data_size(struct dso *dso, struct machine *machine); 308off_t dso__data_size(struct dso *dso, struct machine *machine);
diff --git a/tools/perf/util/dwarf-aux.c b/tools/perf/util/dwarf-aux.c
index a509aa8433a1..577e600c8eb1 100644
--- a/tools/perf/util/dwarf-aux.c
+++ b/tools/perf/util/dwarf-aux.c
@@ -915,7 +915,7 @@ int die_get_typename(Dwarf_Die *vr_die, struct strbuf *buf)
915 tmp = "*"; 915 tmp = "*";
916 else if (tag == DW_TAG_subroutine_type) { 916 else if (tag == DW_TAG_subroutine_type) {
917 /* Function pointer */ 917 /* Function pointer */
918 strbuf_addf(buf, "(function_type)"); 918 strbuf_add(buf, "(function_type)", 15);
919 return 0; 919 return 0;
920 } else { 920 } else {
921 if (!dwarf_diename(&type)) 921 if (!dwarf_diename(&type))
@@ -932,7 +932,7 @@ int die_get_typename(Dwarf_Die *vr_die, struct strbuf *buf)
932 } 932 }
933 ret = die_get_typename(&type, buf); 933 ret = die_get_typename(&type, buf);
934 if (ret == 0) 934 if (ret == 0)
935 strbuf_addf(buf, "%s", tmp); 935 strbuf_addstr(buf, tmp);
936 936
937 return ret; 937 return ret;
938} 938}
@@ -951,7 +951,7 @@ int die_get_varname(Dwarf_Die *vr_die, struct strbuf *buf)
951 ret = die_get_typename(vr_die, buf); 951 ret = die_get_typename(vr_die, buf);
952 if (ret < 0) { 952 if (ret < 0) {
953 pr_debug("Failed to get type, make it unknown.\n"); 953 pr_debug("Failed to get type, make it unknown.\n");
954 strbuf_addf(buf, "(unknown_type)"); 954 strbuf_add(buf, " (unknown_type)", 14);
955 } 955 }
956 956
957 strbuf_addf(buf, "\t%s", dwarf_diename(vr_die)); 957 strbuf_addf(buf, "\t%s", dwarf_diename(vr_die));
@@ -1013,7 +1013,7 @@ static int die_get_var_innermost_scope(Dwarf_Die *sp_die, Dwarf_Die *vr_die,
1013 } 1013 }
1014 1014
1015 if (!first) 1015 if (!first)
1016 strbuf_addf(buf, "]>"); 1016 strbuf_add(buf, "]>", 2);
1017 1017
1018out: 1018out:
1019 free(scopes); 1019 free(scopes);
@@ -1076,7 +1076,7 @@ int die_get_var_range(Dwarf_Die *sp_die, Dwarf_Die *vr_die, struct strbuf *buf)
1076 } 1076 }
1077 1077
1078 if (!first) 1078 if (!first)
1079 strbuf_addf(buf, "]>"); 1079 strbuf_add(buf, "]>", 2);
1080 1080
1081 return ret; 1081 return ret;
1082} 1082}
diff --git a/tools/perf/util/dwarf-aux.h b/tools/perf/util/dwarf-aux.h
index c42ec366f2a7..dc0ce1adb075 100644
--- a/tools/perf/util/dwarf-aux.h
+++ b/tools/perf/util/dwarf-aux.h
@@ -25,48 +25,48 @@
25#include <elfutils/version.h> 25#include <elfutils/version.h>
26 26
27/* Find the realpath of the target file */ 27/* Find the realpath of the target file */
28extern const char *cu_find_realpath(Dwarf_Die *cu_die, const char *fname); 28const char *cu_find_realpath(Dwarf_Die *cu_die, const char *fname);
29 29
30/* Get DW_AT_comp_dir (should be NULL with older gcc) */ 30/* Get DW_AT_comp_dir (should be NULL with older gcc) */
31extern const char *cu_get_comp_dir(Dwarf_Die *cu_die); 31const char *cu_get_comp_dir(Dwarf_Die *cu_die);
32 32
33/* Get a line number and file name for given address */ 33/* Get a line number and file name for given address */
34extern int cu_find_lineinfo(Dwarf_Die *cudie, unsigned long addr, 34int cu_find_lineinfo(Dwarf_Die *cudie, unsigned long addr,
35 const char **fname, int *lineno); 35 const char **fname, int *lineno);
36 36
37/* Walk on funcitons at given address */ 37/* Walk on funcitons at given address */
38extern int cu_walk_functions_at(Dwarf_Die *cu_die, Dwarf_Addr addr, 38int cu_walk_functions_at(Dwarf_Die *cu_die, Dwarf_Addr addr,
39 int (*callback)(Dwarf_Die *, void *), void *data); 39 int (*callback)(Dwarf_Die *, void *), void *data);
40 40
41/* Ensure that this DIE is a subprogram and definition (not declaration) */ 41/* Ensure that this DIE is a subprogram and definition (not declaration) */
42extern bool die_is_func_def(Dwarf_Die *dw_die); 42bool die_is_func_def(Dwarf_Die *dw_die);
43 43
44/* Ensure that this DIE is an instance of a subprogram */ 44/* Ensure that this DIE is an instance of a subprogram */
45extern bool die_is_func_instance(Dwarf_Die *dw_die); 45bool die_is_func_instance(Dwarf_Die *dw_die);
46 46
47/* Compare diename and tname */ 47/* Compare diename and tname */
48extern bool die_compare_name(Dwarf_Die *dw_die, const char *tname); 48bool die_compare_name(Dwarf_Die *dw_die, const char *tname);
49 49
50/* Matching diename with glob pattern */ 50/* Matching diename with glob pattern */
51extern bool die_match_name(Dwarf_Die *dw_die, const char *glob); 51bool die_match_name(Dwarf_Die *dw_die, const char *glob);
52 52
53/* Get callsite line number of inline-function instance */ 53/* Get callsite line number of inline-function instance */
54extern int die_get_call_lineno(Dwarf_Die *in_die); 54int die_get_call_lineno(Dwarf_Die *in_die);
55 55
56/* Get callsite file name of inlined function instance */ 56/* Get callsite file name of inlined function instance */
57extern const char *die_get_call_file(Dwarf_Die *in_die); 57const char *die_get_call_file(Dwarf_Die *in_die);
58 58
59/* Get type die */ 59/* Get type die */
60extern Dwarf_Die *die_get_type(Dwarf_Die *vr_die, Dwarf_Die *die_mem); 60Dwarf_Die *die_get_type(Dwarf_Die *vr_die, Dwarf_Die *die_mem);
61 61
62/* Get a type die, but skip qualifiers and typedef */ 62/* Get a type die, but skip qualifiers and typedef */
63extern Dwarf_Die *die_get_real_type(Dwarf_Die *vr_die, Dwarf_Die *die_mem); 63Dwarf_Die *die_get_real_type(Dwarf_Die *vr_die, Dwarf_Die *die_mem);
64 64
65/* Check whether the DIE is signed or not */ 65/* Check whether the DIE is signed or not */
66extern bool die_is_signed_type(Dwarf_Die *tp_die); 66bool die_is_signed_type(Dwarf_Die *tp_die);
67 67
68/* Get data_member_location offset */ 68/* Get data_member_location offset */
69extern int die_get_data_member_location(Dwarf_Die *mb_die, Dwarf_Word *offs); 69int die_get_data_member_location(Dwarf_Die *mb_die, Dwarf_Word *offs);
70 70
71/* Return values for die_find_child() callbacks */ 71/* Return values for die_find_child() callbacks */
72enum { 72enum {
@@ -77,29 +77,29 @@ enum {
77}; 77};
78 78
79/* Search child DIEs */ 79/* Search child DIEs */
80extern Dwarf_Die *die_find_child(Dwarf_Die *rt_die, 80Dwarf_Die *die_find_child(Dwarf_Die *rt_die,
81 int (*callback)(Dwarf_Die *, void *), 81 int (*callback)(Dwarf_Die *, void *),
82 void *data, Dwarf_Die *die_mem); 82 void *data, Dwarf_Die *die_mem);
83 83
84/* Search a non-inlined function including given address */ 84/* Search a non-inlined function including given address */
85extern Dwarf_Die *die_find_realfunc(Dwarf_Die *cu_die, Dwarf_Addr addr, 85Dwarf_Die *die_find_realfunc(Dwarf_Die *cu_die, Dwarf_Addr addr,
86 Dwarf_Die *die_mem); 86 Dwarf_Die *die_mem);
87 87
88/* Search a non-inlined function with tail call at given address */ 88/* Search a non-inlined function with tail call at given address */
89Dwarf_Die *die_find_tailfunc(Dwarf_Die *cu_die, Dwarf_Addr addr, 89Dwarf_Die *die_find_tailfunc(Dwarf_Die *cu_die, Dwarf_Addr addr,
90 Dwarf_Die *die_mem); 90 Dwarf_Die *die_mem);
91 91
92/* Search the top inlined function including given address */ 92/* Search the top inlined function including given address */
93extern Dwarf_Die *die_find_top_inlinefunc(Dwarf_Die *sp_die, Dwarf_Addr addr, 93Dwarf_Die *die_find_top_inlinefunc(Dwarf_Die *sp_die, Dwarf_Addr addr,
94 Dwarf_Die *die_mem); 94 Dwarf_Die *die_mem);
95 95
96/* Search the deepest inlined function including given address */ 96/* Search the deepest inlined function including given address */
97extern Dwarf_Die *die_find_inlinefunc(Dwarf_Die *sp_die, Dwarf_Addr addr, 97Dwarf_Die *die_find_inlinefunc(Dwarf_Die *sp_die, Dwarf_Addr addr,
98 Dwarf_Die *die_mem); 98 Dwarf_Die *die_mem);
99 99
100/* Walk on the instances of given DIE */ 100/* Walk on the instances of given DIE */
101extern int die_walk_instances(Dwarf_Die *in_die, 101int die_walk_instances(Dwarf_Die *in_die,
102 int (*callback)(Dwarf_Die *, void *), void *data); 102 int (*callback)(Dwarf_Die *, void *), void *data);
103 103
104/* Walker on lines (Note: line number will not be sorted) */ 104/* Walker on lines (Note: line number will not be sorted) */
105typedef int (* line_walk_callback_t) (const char *fname, int lineno, 105typedef int (* line_walk_callback_t) (const char *fname, int lineno,
@@ -109,22 +109,20 @@ typedef int (* line_walk_callback_t) (const char *fname, int lineno,
109 * Walk on lines inside given DIE. If the DIE is a subprogram, walk only on 109 * Walk on lines inside given DIE. If the DIE is a subprogram, walk only on
110 * the lines inside the subprogram, otherwise the DIE must be a CU DIE. 110 * the lines inside the subprogram, otherwise the DIE must be a CU DIE.
111 */ 111 */
112extern int die_walk_lines(Dwarf_Die *rt_die, line_walk_callback_t callback, 112int die_walk_lines(Dwarf_Die *rt_die, line_walk_callback_t callback, void *data);
113 void *data);
114 113
115/* Find a variable called 'name' at given address */ 114/* Find a variable called 'name' at given address */
116extern Dwarf_Die *die_find_variable_at(Dwarf_Die *sp_die, const char *name, 115Dwarf_Die *die_find_variable_at(Dwarf_Die *sp_die, const char *name,
117 Dwarf_Addr addr, Dwarf_Die *die_mem); 116 Dwarf_Addr addr, Dwarf_Die *die_mem);
118 117
119/* Find a member called 'name' */ 118/* Find a member called 'name' */
120extern Dwarf_Die *die_find_member(Dwarf_Die *st_die, const char *name, 119Dwarf_Die *die_find_member(Dwarf_Die *st_die, const char *name,
121 Dwarf_Die *die_mem); 120 Dwarf_Die *die_mem);
122 121
123/* Get the name of given variable DIE */ 122/* Get the name of given variable DIE */
124extern int die_get_typename(Dwarf_Die *vr_die, struct strbuf *buf); 123int die_get_typename(Dwarf_Die *vr_die, struct strbuf *buf);
125 124
126/* Get the name and type of given variable DIE, stored as "type\tname" */ 125/* Get the name and type of given variable DIE, stored as "type\tname" */
127extern int die_get_varname(Dwarf_Die *vr_die, struct strbuf *buf); 126int die_get_varname(Dwarf_Die *vr_die, struct strbuf *buf);
128extern int die_get_var_range(Dwarf_Die *sp_die, Dwarf_Die *vr_die, 127int die_get_var_range(Dwarf_Die *sp_die, Dwarf_Die *vr_die, struct strbuf *buf);
129 struct strbuf *buf);
130#endif 128#endif
diff --git a/tools/perf/util/env.c b/tools/perf/util/env.c
index 7dd5939dea2e..49a11d9d8b8f 100644
--- a/tools/perf/util/env.c
+++ b/tools/perf/util/env.c
@@ -6,6 +6,8 @@ struct perf_env perf_env;
6 6
7void perf_env__exit(struct perf_env *env) 7void perf_env__exit(struct perf_env *env)
8{ 8{
9 int i;
10
9 zfree(&env->hostname); 11 zfree(&env->hostname);
10 zfree(&env->os_release); 12 zfree(&env->os_release);
11 zfree(&env->version); 13 zfree(&env->version);
@@ -19,6 +21,10 @@ void perf_env__exit(struct perf_env *env)
19 zfree(&env->numa_nodes); 21 zfree(&env->numa_nodes);
20 zfree(&env->pmu_mappings); 22 zfree(&env->pmu_mappings);
21 zfree(&env->cpu); 23 zfree(&env->cpu);
24
25 for (i = 0; i < env->caches_cnt; i++)
26 cpu_cache_level__free(&env->caches[i]);
27 zfree(&env->caches);
22} 28}
23 29
24int perf_env__set_cmdline(struct perf_env *env, int argc, const char *argv[]) 30int perf_env__set_cmdline(struct perf_env *env, int argc, const char *argv[])
@@ -75,3 +81,10 @@ int perf_env__read_cpu_topology_map(struct perf_env *env)
75 env->nr_cpus_avail = nr_cpus; 81 env->nr_cpus_avail = nr_cpus;
76 return 0; 82 return 0;
77} 83}
84
85void cpu_cache_level__free(struct cpu_cache_level *cache)
86{
87 free(cache->type);
88 free(cache->map);
89 free(cache->size);
90}
diff --git a/tools/perf/util/env.h b/tools/perf/util/env.h
index 0132b9557c02..56cffb60a0b4 100644
--- a/tools/perf/util/env.h
+++ b/tools/perf/util/env.h
@@ -1,11 +1,23 @@
1#ifndef __PERF_ENV_H 1#ifndef __PERF_ENV_H
2#define __PERF_ENV_H 2#define __PERF_ENV_H
3 3
4#include <linux/types.h>
5
4struct cpu_topology_map { 6struct cpu_topology_map {
5 int socket_id; 7 int socket_id;
6 int core_id; 8 int core_id;
7}; 9};
8 10
11struct cpu_cache_level {
12 u32 level;
13 u32 line_size;
14 u32 sets;
15 u32 ways;
16 char *type;
17 char *size;
18 char *map;
19};
20
9struct perf_env { 21struct perf_env {
10 char *hostname; 22 char *hostname;
11 char *os_release; 23 char *os_release;
@@ -31,6 +43,8 @@ struct perf_env {
31 char *numa_nodes; 43 char *numa_nodes;
32 char *pmu_mappings; 44 char *pmu_mappings;
33 struct cpu_topology_map *cpu; 45 struct cpu_topology_map *cpu;
46 struct cpu_cache_level *caches;
47 int caches_cnt;
34}; 48};
35 49
36extern struct perf_env perf_env; 50extern struct perf_env perf_env;
@@ -41,4 +55,5 @@ int perf_env__set_cmdline(struct perf_env *env, int argc, const char *argv[]);
41 55
42int perf_env__read_cpu_topology_map(struct perf_env *env); 56int perf_env__read_cpu_topology_map(struct perf_env *env);
43 57
58void cpu_cache_level__free(struct cpu_cache_level *cache);
44#endif /* __PERF_ENV_H */ 59#endif /* __PERF_ENV_H */
diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c
index 85155e91b61b..dad55d04ffdd 100644
--- a/tools/perf/util/event.c
+++ b/tools/perf/util/event.c
@@ -56,13 +56,22 @@ const char *perf_event__name(unsigned int id)
56 return perf_event__names[id]; 56 return perf_event__names[id];
57} 57}
58 58
59static struct perf_sample synth_sample = { 59static int perf_tool__process_synth_event(struct perf_tool *tool,
60 union perf_event *event,
61 struct machine *machine,
62 perf_event__handler_t process)
63{
64 struct perf_sample synth_sample = {
60 .pid = -1, 65 .pid = -1,
61 .tid = -1, 66 .tid = -1,
62 .time = -1, 67 .time = -1,
63 .stream_id = -1, 68 .stream_id = -1,
64 .cpu = -1, 69 .cpu = -1,
65 .period = 1, 70 .period = 1,
71 .cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK,
72 };
73
74 return process(tool, event, &synth_sample, machine);
66}; 75};
67 76
68/* 77/*
@@ -186,7 +195,7 @@ pid_t perf_event__synthesize_comm(struct perf_tool *tool,
186 if (perf_event__prepare_comm(event, pid, machine, &tgid, &ppid) != 0) 195 if (perf_event__prepare_comm(event, pid, machine, &tgid, &ppid) != 0)
187 return -1; 196 return -1;
188 197
189 if (process(tool, event, &synth_sample, machine) != 0) 198 if (perf_tool__process_synth_event(tool, event, machine, process) != 0)
190 return -1; 199 return -1;
191 200
192 return tgid; 201 return tgid;
@@ -218,7 +227,7 @@ static int perf_event__synthesize_fork(struct perf_tool *tool,
218 227
219 event->fork.header.size = (sizeof(event->fork) + machine->id_hdr_size); 228 event->fork.header.size = (sizeof(event->fork) + machine->id_hdr_size);
220 229
221 if (process(tool, event, &synth_sample, machine) != 0) 230 if (perf_tool__process_synth_event(tool, event, machine, process) != 0)
222 return -1; 231 return -1;
223 232
224 return 0; 233 return 0;
@@ -282,7 +291,7 @@ int perf_event__synthesize_mmap_events(struct perf_tool *tool,
282 strcpy(execname, ""); 291 strcpy(execname, "");
283 292
284 /* 00400000-0040c000 r-xp 00000000 fd:01 41038 /bin/cat */ 293 /* 00400000-0040c000 r-xp 00000000 fd:01 41038 /bin/cat */
285 n = sscanf(bf, "%"PRIx64"-%"PRIx64" %s %"PRIx64" %x:%x %u %s\n", 294 n = sscanf(bf, "%"PRIx64"-%"PRIx64" %s %"PRIx64" %x:%x %u %[^\n]\n",
286 &event->mmap2.start, &event->mmap2.len, prot, 295 &event->mmap2.start, &event->mmap2.len, prot,
287 &event->mmap2.pgoff, &event->mmap2.maj, 296 &event->mmap2.pgoff, &event->mmap2.maj,
288 &event->mmap2.min, 297 &event->mmap2.min,
@@ -344,7 +353,7 @@ out:
344 event->mmap2.pid = tgid; 353 event->mmap2.pid = tgid;
345 event->mmap2.tid = pid; 354 event->mmap2.tid = pid;
346 355
347 if (process(tool, event, &synth_sample, machine) != 0) { 356 if (perf_tool__process_synth_event(tool, event, machine, process) != 0) {
348 rc = -1; 357 rc = -1;
349 break; 358 break;
350 } 359 }
@@ -402,7 +411,7 @@ int perf_event__synthesize_modules(struct perf_tool *tool,
402 411
403 memcpy(event->mmap.filename, pos->dso->long_name, 412 memcpy(event->mmap.filename, pos->dso->long_name,
404 pos->dso->long_name_len + 1); 413 pos->dso->long_name_len + 1);
405 if (process(tool, event, &synth_sample, machine) != 0) { 414 if (perf_tool__process_synth_event(tool, event, machine, process) != 0) {
406 rc = -1; 415 rc = -1;
407 break; 416 break;
408 } 417 }
@@ -472,7 +481,7 @@ static int __event__synthesize_thread(union perf_event *comm_event,
472 /* 481 /*
473 * Send the prepared comm event 482 * Send the prepared comm event
474 */ 483 */
475 if (process(tool, comm_event, &synth_sample, machine) != 0) 484 if (perf_tool__process_synth_event(tool, comm_event, machine, process) != 0)
476 break; 485 break;
477 486
478 rc = 0; 487 rc = 0;
@@ -701,7 +710,7 @@ int perf_event__synthesize_kernel_mmap(struct perf_tool *tool,
701 event->mmap.len = map->end - event->mmap.start; 710 event->mmap.len = map->end - event->mmap.start;
702 event->mmap.pid = machine->pid; 711 event->mmap.pid = machine->pid;
703 712
704 err = process(tool, event, &synth_sample, machine); 713 err = perf_tool__process_synth_event(tool, event, machine, process);
705 free(event); 714 free(event);
706 715
707 return err; 716 return err;
@@ -1295,12 +1304,9 @@ void thread__find_addr_location(struct thread *thread,
1295 * Callers need to drop the reference to al->thread, obtained in 1304 * Callers need to drop the reference to al->thread, obtained in
1296 * machine__findnew_thread() 1305 * machine__findnew_thread()
1297 */ 1306 */
1298int perf_event__preprocess_sample(const union perf_event *event, 1307int machine__resolve(struct machine *machine, struct addr_location *al,
1299 struct machine *machine, 1308 struct perf_sample *sample)
1300 struct addr_location *al,
1301 struct perf_sample *sample)
1302{ 1309{
1303 u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
1304 struct thread *thread = machine__findnew_thread(machine, sample->pid, 1310 struct thread *thread = machine__findnew_thread(machine, sample->pid,
1305 sample->tid); 1311 sample->tid);
1306 1312
@@ -1315,11 +1321,11 @@ int perf_event__preprocess_sample(const union perf_event *event,
1315 * events, but for older perf.data files there was no such thing, so do 1321 * events, but for older perf.data files there was no such thing, so do
1316 * it now. 1322 * it now.
1317 */ 1323 */
1318 if (cpumode == PERF_RECORD_MISC_KERNEL && 1324 if (sample->cpumode == PERF_RECORD_MISC_KERNEL &&
1319 machine__kernel_map(machine) == NULL) 1325 machine__kernel_map(machine) == NULL)
1320 machine__create_kernel_maps(machine); 1326 machine__create_kernel_maps(machine);
1321 1327
1322 thread__find_addr_map(thread, cpumode, MAP__FUNCTION, sample->ip, al); 1328 thread__find_addr_map(thread, sample->cpumode, MAP__FUNCTION, sample->ip, al);
1323 dump_printf(" ...... dso: %s\n", 1329 dump_printf(" ...... dso: %s\n",
1324 al->map ? al->map->dso->long_name : 1330 al->map ? al->map->dso->long_name :
1325 al->level == 'H' ? "[hypervisor]" : "<not found>"); 1331 al->level == 'H' ? "[hypervisor]" : "<not found>");
@@ -1395,16 +1401,12 @@ bool sample_addr_correlates_sym(struct perf_event_attr *attr)
1395 return false; 1401 return false;
1396} 1402}
1397 1403
1398void perf_event__preprocess_sample_addr(union perf_event *event, 1404void thread__resolve(struct thread *thread, struct addr_location *al,
1399 struct perf_sample *sample, 1405 struct perf_sample *sample)
1400 struct thread *thread,
1401 struct addr_location *al)
1402{ 1406{
1403 u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; 1407 thread__find_addr_map(thread, sample->cpumode, MAP__FUNCTION, sample->addr, al);
1404
1405 thread__find_addr_map(thread, cpumode, MAP__FUNCTION, sample->addr, al);
1406 if (!al->map) 1408 if (!al->map)
1407 thread__find_addr_map(thread, cpumode, MAP__VARIABLE, 1409 thread__find_addr_map(thread, sample->cpumode, MAP__VARIABLE,
1408 sample->addr, al); 1410 sample->addr, al);
1409 1411
1410 al->cpu = sample->cpu; 1412 al->cpu = sample->cpu;
diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h
index b7ffb7ee9971..6bb1c928350d 100644
--- a/tools/perf/util/event.h
+++ b/tools/perf/util/event.h
@@ -192,6 +192,7 @@ struct perf_sample {
192 u64 data_src; 192 u64 data_src;
193 u32 flags; 193 u32 flags;
194 u16 insn_len; 194 u16 insn_len;
195 u8 cpumode;
195 void *raw_data; 196 void *raw_data;
196 struct ip_callchain *callchain; 197 struct ip_callchain *callchain;
197 struct branch_stack *branch_stack; 198 struct branch_stack *branch_stack;
@@ -597,10 +598,8 @@ int perf_event__process(struct perf_tool *tool,
597 598
598struct addr_location; 599struct addr_location;
599 600
600int perf_event__preprocess_sample(const union perf_event *event, 601int machine__resolve(struct machine *machine, struct addr_location *al,
601 struct machine *machine, 602 struct perf_sample *sample);
602 struct addr_location *al,
603 struct perf_sample *sample);
604 603
605void addr_location__put(struct addr_location *al); 604void addr_location__put(struct addr_location *al);
606 605
@@ -608,10 +607,8 @@ struct thread;
608 607
609bool is_bts_event(struct perf_event_attr *attr); 608bool is_bts_event(struct perf_event_attr *attr);
610bool sample_addr_correlates_sym(struct perf_event_attr *attr); 609bool sample_addr_correlates_sym(struct perf_event_attr *attr);
611void perf_event__preprocess_sample_addr(union perf_event *event, 610void thread__resolve(struct thread *thread, struct addr_location *al,
612 struct perf_sample *sample, 611 struct perf_sample *sample);
613 struct thread *thread,
614 struct addr_location *al);
615 612
616const char *perf_event__name(unsigned int id); 613const char *perf_event__name(unsigned int id);
617 614
diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c
index d81f13de2476..86a03836a83f 100644
--- a/tools/perf/util/evlist.c
+++ b/tools/perf/util/evlist.c
@@ -1181,12 +1181,12 @@ void perf_evlist__set_maps(struct perf_evlist *evlist, struct cpu_map *cpus,
1181 */ 1181 */
1182 if (cpus != evlist->cpus) { 1182 if (cpus != evlist->cpus) {
1183 cpu_map__put(evlist->cpus); 1183 cpu_map__put(evlist->cpus);
1184 evlist->cpus = cpus; 1184 evlist->cpus = cpu_map__get(cpus);
1185 } 1185 }
1186 1186
1187 if (threads != evlist->threads) { 1187 if (threads != evlist->threads) {
1188 thread_map__put(evlist->threads); 1188 thread_map__put(evlist->threads);
1189 evlist->threads = threads; 1189 evlist->threads = thread_map__get(threads);
1190 } 1190 }
1191 1191
1192 perf_evlist__propagate_maps(evlist); 1192 perf_evlist__propagate_maps(evlist);
@@ -1223,6 +1223,9 @@ int perf_evlist__set_filter(struct perf_evlist *evlist, const char *filter)
1223 int err = 0; 1223 int err = 0;
1224 1224
1225 evlist__for_each(evlist, evsel) { 1225 evlist__for_each(evlist, evsel) {
1226 if (evsel->attr.type != PERF_TYPE_TRACEPOINT)
1227 continue;
1228
1226 err = perf_evsel__set_filter(evsel, filter); 1229 err = perf_evsel__set_filter(evsel, filter);
1227 if (err) 1230 if (err)
1228 break; 1231 break;
@@ -1624,7 +1627,7 @@ size_t perf_evlist__fprintf(struct perf_evlist *evlist, FILE *fp)
1624 return printed + fprintf(fp, "\n"); 1627 return printed + fprintf(fp, "\n");
1625} 1628}
1626 1629
1627int perf_evlist__strerror_open(struct perf_evlist *evlist __maybe_unused, 1630int perf_evlist__strerror_open(struct perf_evlist *evlist,
1628 int err, char *buf, size_t size) 1631 int err, char *buf, size_t size)
1629{ 1632{
1630 int printed, value; 1633 int printed, value;
@@ -1652,7 +1655,25 @@ int perf_evlist__strerror_open(struct perf_evlist *evlist __maybe_unused,
1652 "Hint:\tTry: 'sudo sh -c \"echo -1 > /proc/sys/kernel/perf_event_paranoid\"'\n" 1655 "Hint:\tTry: 'sudo sh -c \"echo -1 > /proc/sys/kernel/perf_event_paranoid\"'\n"
1653 "Hint:\tThe current value is %d.", value); 1656 "Hint:\tThe current value is %d.", value);
1654 break; 1657 break;
1658 case EINVAL: {
1659 struct perf_evsel *first = perf_evlist__first(evlist);
1660 int max_freq;
1661
1662 if (sysctl__read_int("kernel/perf_event_max_sample_rate", &max_freq) < 0)
1663 goto out_default;
1664
1665 if (first->attr.sample_freq < (u64)max_freq)
1666 goto out_default;
1667
1668 printed = scnprintf(buf, size,
1669 "Error:\t%s.\n"
1670 "Hint:\tCheck /proc/sys/kernel/perf_event_max_sample_rate.\n"
1671 "Hint:\tThe current value is %d and %" PRIu64 " is being requested.",
1672 emsg, max_freq, first->attr.sample_freq);
1673 break;
1674 }
1655 default: 1675 default:
1676out_default:
1656 scnprintf(buf, size, "%s", emsg); 1677 scnprintf(buf, size, "%s", emsg);
1657 break; 1678 break;
1658 } 1679 }
@@ -1723,3 +1744,19 @@ void perf_evlist__set_tracking_event(struct perf_evlist *evlist,
1723 1744
1724 tracking_evsel->tracking = true; 1745 tracking_evsel->tracking = true;
1725} 1746}
1747
1748struct perf_evsel *
1749perf_evlist__find_evsel_by_str(struct perf_evlist *evlist,
1750 const char *str)
1751{
1752 struct perf_evsel *evsel;
1753
1754 evlist__for_each(evlist, evsel) {
1755 if (!evsel->name)
1756 continue;
1757 if (strcmp(str, evsel->name) == 0)
1758 return evsel;
1759 }
1760
1761 return NULL;
1762}
diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h
index 7c4d9a206776..a0d15221db6e 100644
--- a/tools/perf/util/evlist.h
+++ b/tools/perf/util/evlist.h
@@ -294,4 +294,7 @@ void perf_evlist__set_tracking_event(struct perf_evlist *evlist,
294 struct perf_evsel *tracking_evsel); 294 struct perf_evsel *tracking_evsel);
295 295
296void perf_event_attr__set_max_precise_ip(struct perf_event_attr *attr); 296void perf_event_attr__set_max_precise_ip(struct perf_event_attr *attr);
297
298struct perf_evsel *
299perf_evlist__find_evsel_by_str(struct perf_evlist *evlist, const char *str);
297#endif /* __PERF_EVLIST_H */ 300#endif /* __PERF_EVLIST_H */
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c
index cdbaf9b51e42..738ce226002b 100644
--- a/tools/perf/util/evsel.c
+++ b/tools/perf/util/evsel.c
@@ -225,6 +225,11 @@ struct perf_evsel *perf_evsel__new_idx(struct perf_event_attr *attr, int idx)
225 if (evsel != NULL) 225 if (evsel != NULL)
226 perf_evsel__init(evsel, attr, idx); 226 perf_evsel__init(evsel, attr, idx);
227 227
228 if (perf_evsel__is_bpf_output(evsel)) {
229 evsel->attr.sample_type |= PERF_SAMPLE_RAW;
230 evsel->attr.sample_period = 1;
231 }
232
228 return evsel; 233 return evsel;
229} 234}
230 235
@@ -898,6 +903,16 @@ void perf_evsel__config(struct perf_evsel *evsel, struct record_opts *opts)
898 if (evsel->precise_max) 903 if (evsel->precise_max)
899 perf_event_attr__set_max_precise_ip(attr); 904 perf_event_attr__set_max_precise_ip(attr);
900 905
906 if (opts->all_user) {
907 attr->exclude_kernel = 1;
908 attr->exclude_user = 0;
909 }
910
911 if (opts->all_kernel) {
912 attr->exclude_kernel = 0;
913 attr->exclude_user = 1;
914 }
915
901 /* 916 /*
902 * Apply event specific term settings, 917 * Apply event specific term settings,
903 * it overloads any global configuration. 918 * it overloads any global configuration.
@@ -1628,6 +1643,7 @@ int perf_evsel__parse_sample(struct perf_evsel *evsel, union perf_event *event,
1628 data->stream_id = data->id = data->time = -1ULL; 1643 data->stream_id = data->id = data->time = -1ULL;
1629 data->period = evsel->attr.sample_period; 1644 data->period = evsel->attr.sample_period;
1630 data->weight = 0; 1645 data->weight = 0;
1646 data->cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
1631 1647
1632 if (event->header.type != PERF_RECORD_SAMPLE) { 1648 if (event->header.type != PERF_RECORD_SAMPLE) {
1633 if (!evsel->attr.sample_id_all) 1649 if (!evsel->attr.sample_id_all)
@@ -2362,12 +2378,15 @@ int perf_evsel__open_strerror(struct perf_evsel *evsel, struct target *target,
2362 case EPERM: 2378 case EPERM:
2363 case EACCES: 2379 case EACCES:
2364 return scnprintf(msg, size, 2380 return scnprintf(msg, size,
2365 "You may not have permission to collect %sstats.\n" 2381 "You may not have permission to collect %sstats.\n\n"
2366 "Consider tweaking /proc/sys/kernel/perf_event_paranoid:\n" 2382 "Consider tweaking /proc/sys/kernel/perf_event_paranoid,\n"
2367 " -1 - Not paranoid at all\n" 2383 "which controls use of the performance events system by\n"
2368 " 0 - Disallow raw tracepoint access for unpriv\n" 2384 "unprivileged users (without CAP_SYS_ADMIN).\n\n"
2369 " 1 - Disallow cpu events for unpriv\n" 2385 "The default value is 1:\n\n"
2370 " 2 - Disallow kernel profiling for unpriv", 2386 " -1: Allow use of (almost) all events by all users\n"
2387 ">= 0: Disallow raw tracepoint access by users without CAP_IOC_LOCK\n"
2388 ">= 1: Disallow CPU event access by users without CAP_SYS_ADMIN\n"
2389 ">= 2: Disallow kernel profiling by users without CAP_SYS_ADMIN",
2371 target->system_wide ? "system-wide " : ""); 2390 target->system_wide ? "system-wide " : "");
2372 case ENOENT: 2391 case ENOENT:
2373 return scnprintf(msg, size, "The %s event is not supported.", 2392 return scnprintf(msg, size, "The %s event is not supported.",
diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h
index 8e75434bd01c..501ea6e565f1 100644
--- a/tools/perf/util/evsel.h
+++ b/tools/perf/util/evsel.h
@@ -93,10 +93,8 @@ struct perf_evsel {
93 const char *unit; 93 const char *unit;
94 struct event_format *tp_format; 94 struct event_format *tp_format;
95 off_t id_offset; 95 off_t id_offset;
96 union { 96 void *priv;
97 void *priv; 97 u64 db_id;
98 u64 db_id;
99 };
100 struct cgroup_sel *cgrp; 98 struct cgroup_sel *cgrp;
101 void *handler; 99 void *handler;
102 struct cpu_map *cpus; 100 struct cpu_map *cpus;
@@ -364,6 +362,14 @@ static inline bool perf_evsel__is_function_event(struct perf_evsel *evsel)
364#undef FUNCTION_EVENT 362#undef FUNCTION_EVENT
365} 363}
366 364
365static inline bool perf_evsel__is_bpf_output(struct perf_evsel *evsel)
366{
367 struct perf_event_attr *attr = &evsel->attr;
368
369 return (attr->config == PERF_COUNT_SW_BPF_OUTPUT) &&
370 (attr->type == PERF_TYPE_SOFTWARE);
371}
372
367struct perf_attr_details { 373struct perf_attr_details {
368 bool freq; 374 bool freq;
369 bool verbose; 375 bool verbose;
diff --git a/tools/perf/util/genelf.c b/tools/perf/util/genelf.c
new file mode 100644
index 000000000000..c1ef805c6a8f
--- /dev/null
+++ b/tools/perf/util/genelf.c
@@ -0,0 +1,449 @@
1/*
2 * genelf.c
3 * Copyright (C) 2014, Google, Inc
4 *
5 * Contributed by:
6 * Stephane Eranian <eranian@gmail.com>
7 *
8 * Released under the GPL v2. (and only v2, not any later version)
9 */
10
11#include <sys/types.h>
12#include <stdio.h>
13#include <getopt.h>
14#include <stddef.h>
15#include <libelf.h>
16#include <string.h>
17#include <stdlib.h>
18#include <inttypes.h>
19#include <limits.h>
20#include <fcntl.h>
21#include <err.h>
22#include <dwarf.h>
23
24#include "perf.h"
25#include "genelf.h"
26#include "../util/jitdump.h"
27
28#define JVMTI
29
30#define BUILD_ID_URANDOM /* different uuid for each run */
31
32#ifdef HAVE_LIBCRYPTO
33
34#define BUILD_ID_MD5
35#undef BUILD_ID_SHA /* does not seem to work well when linked with Java */
36#undef BUILD_ID_URANDOM /* different uuid for each run */
37
38#ifdef BUILD_ID_SHA
39#include <openssl/sha.h>
40#endif
41
42#ifdef BUILD_ID_MD5
43#include <openssl/md5.h>
44#endif
45#endif
46
47
48typedef struct {
49 unsigned int namesz; /* Size of entry's owner string */
50 unsigned int descsz; /* Size of the note descriptor */
51 unsigned int type; /* Interpretation of the descriptor */
52 char name[0]; /* Start of the name+desc data */
53} Elf_Note;
54
55struct options {
56 char *output;
57 int fd;
58};
59
60static char shd_string_table[] = {
61 0,
62 '.', 't', 'e', 'x', 't', 0, /* 1 */
63 '.', 's', 'h', 's', 't', 'r', 't', 'a', 'b', 0, /* 7 */
64 '.', 's', 'y', 'm', 't', 'a', 'b', 0, /* 17 */
65 '.', 's', 't', 'r', 't', 'a', 'b', 0, /* 25 */
66 '.', 'n', 'o', 't', 'e', '.', 'g', 'n', 'u', '.', 'b', 'u', 'i', 'l', 'd', '-', 'i', 'd', 0, /* 33 */
67 '.', 'd', 'e', 'b', 'u', 'g', '_', 'l', 'i', 'n', 'e', 0, /* 52 */
68 '.', 'd', 'e', 'b', 'u', 'g', '_', 'i', 'n', 'f', 'o', 0, /* 64 */
69 '.', 'd', 'e', 'b', 'u', 'g', '_', 'a', 'b', 'b', 'r', 'e', 'v', 0, /* 76 */
70};
71
72static struct buildid_note {
73 Elf_Note desc; /* descsz: size of build-id, must be multiple of 4 */
74 char name[4]; /* GNU\0 */
75 char build_id[20];
76} bnote;
77
78static Elf_Sym symtab[]={
79 /* symbol 0 MUST be the undefined symbol */
80 { .st_name = 0, /* index in sym_string table */
81 .st_info = ELF_ST_TYPE(STT_NOTYPE),
82 .st_shndx = 0, /* for now */
83 .st_value = 0x0,
84 .st_other = ELF_ST_VIS(STV_DEFAULT),
85 .st_size = 0,
86 },
87 { .st_name = 1, /* index in sym_string table */
88 .st_info = ELF_ST_BIND(STB_LOCAL) | ELF_ST_TYPE(STT_FUNC),
89 .st_shndx = 1,
90 .st_value = 0, /* for now */
91 .st_other = ELF_ST_VIS(STV_DEFAULT),
92 .st_size = 0, /* for now */
93 }
94};
95
96#ifdef BUILD_ID_URANDOM
97static void
98gen_build_id(struct buildid_note *note,
99 unsigned long load_addr __maybe_unused,
100 const void *code __maybe_unused,
101 size_t csize __maybe_unused)
102{
103 int fd;
104 size_t sz = sizeof(note->build_id);
105 ssize_t sret;
106
107 fd = open("/dev/urandom", O_RDONLY);
108 if (fd == -1)
109 err(1, "cannot access /dev/urandom for builid");
110
111 sret = read(fd, note->build_id, sz);
112
113 close(fd);
114
115 if (sret != (ssize_t)sz)
116 memset(note->build_id, 0, sz);
117}
118#endif
119
120#ifdef BUILD_ID_SHA
121static void
122gen_build_id(struct buildid_note *note,
123 unsigned long load_addr __maybe_unused,
124 const void *code,
125 size_t csize)
126{
127 if (sizeof(note->build_id) < SHA_DIGEST_LENGTH)
128 errx(1, "build_id too small for SHA1");
129
130 SHA1(code, csize, (unsigned char *)note->build_id);
131}
132#endif
133
134#ifdef BUILD_ID_MD5
135static void
136gen_build_id(struct buildid_note *note, unsigned long load_addr, const void *code, size_t csize)
137{
138 MD5_CTX context;
139
140 if (sizeof(note->build_id) < 16)
141 errx(1, "build_id too small for MD5");
142
143 MD5_Init(&context);
144 MD5_Update(&context, &load_addr, sizeof(load_addr));
145 MD5_Update(&context, code, csize);
146 MD5_Final((unsigned char *)note->build_id, &context);
147}
148#endif
149
150/*
151 * fd: file descriptor open for writing for the output file
152 * load_addr: code load address (could be zero, just used for buildid)
153 * sym: function name (for native code - used as the symbol)
154 * code: the native code
155 * csize: the code size in bytes
156 */
157int
158jit_write_elf(int fd, uint64_t load_addr, const char *sym,
159 const void *code, int csize,
160 void *debug, int nr_debug_entries)
161{
162 Elf *e;
163 Elf_Data *d;
164 Elf_Scn *scn;
165 Elf_Ehdr *ehdr;
166 Elf_Shdr *shdr;
167 char *strsym = NULL;
168 int symlen;
169 int retval = -1;
170
171 if (elf_version(EV_CURRENT) == EV_NONE) {
172 warnx("ELF initialization failed");
173 return -1;
174 }
175
176 e = elf_begin(fd, ELF_C_WRITE, NULL);
177 if (!e) {
178 warnx("elf_begin failed");
179 goto error;
180 }
181
182 /*
183 * setup ELF header
184 */
185 ehdr = elf_newehdr(e);
186 if (!ehdr) {
187 warnx("cannot get ehdr");
188 goto error;
189 }
190
191 ehdr->e_ident[EI_DATA] = GEN_ELF_ENDIAN;
192 ehdr->e_ident[EI_CLASS] = GEN_ELF_CLASS;
193 ehdr->e_machine = GEN_ELF_ARCH;
194 ehdr->e_type = ET_DYN;
195 ehdr->e_entry = GEN_ELF_TEXT_OFFSET;
196 ehdr->e_version = EV_CURRENT;
197 ehdr->e_shstrndx= 2; /* shdr index for section name */
198
199 /*
200 * setup text section
201 */
202 scn = elf_newscn(e);
203 if (!scn) {
204 warnx("cannot create section");
205 goto error;
206 }
207
208 d = elf_newdata(scn);
209 if (!d) {
210 warnx("cannot get new data");
211 goto error;
212 }
213
214 d->d_align = 16;
215 d->d_off = 0LL;
216 d->d_buf = (void *)code;
217 d->d_type = ELF_T_BYTE;
218 d->d_size = csize;
219 d->d_version = EV_CURRENT;
220
221 shdr = elf_getshdr(scn);
222 if (!shdr) {
223 warnx("cannot get section header");
224 goto error;
225 }
226
227 shdr->sh_name = 1;
228 shdr->sh_type = SHT_PROGBITS;
229 shdr->sh_addr = GEN_ELF_TEXT_OFFSET;
230 shdr->sh_flags = SHF_EXECINSTR | SHF_ALLOC;
231 shdr->sh_entsize = 0;
232
233 /*
234 * setup section headers string table
235 */
236 scn = elf_newscn(e);
237 if (!scn) {
238 warnx("cannot create section");
239 goto error;
240 }
241
242 d = elf_newdata(scn);
243 if (!d) {
244 warnx("cannot get new data");
245 goto error;
246 }
247
248 d->d_align = 1;
249 d->d_off = 0LL;
250 d->d_buf = shd_string_table;
251 d->d_type = ELF_T_BYTE;
252 d->d_size = sizeof(shd_string_table);
253 d->d_version = EV_CURRENT;
254
255 shdr = elf_getshdr(scn);
256 if (!shdr) {
257 warnx("cannot get section header");
258 goto error;
259 }
260
261 shdr->sh_name = 7; /* offset of '.shstrtab' in shd_string_table */
262 shdr->sh_type = SHT_STRTAB;
263 shdr->sh_flags = 0;
264 shdr->sh_entsize = 0;
265
266 /*
267 * setup symtab section
268 */
269 symtab[1].st_size = csize;
270 symtab[1].st_value = GEN_ELF_TEXT_OFFSET;
271
272 scn = elf_newscn(e);
273 if (!scn) {
274 warnx("cannot create section");
275 goto error;
276 }
277
278 d = elf_newdata(scn);
279 if (!d) {
280 warnx("cannot get new data");
281 goto error;
282 }
283
284 d->d_align = 8;
285 d->d_off = 0LL;
286 d->d_buf = symtab;
287 d->d_type = ELF_T_SYM;
288 d->d_size = sizeof(symtab);
289 d->d_version = EV_CURRENT;
290
291 shdr = elf_getshdr(scn);
292 if (!shdr) {
293 warnx("cannot get section header");
294 goto error;
295 }
296
297 shdr->sh_name = 17; /* offset of '.symtab' in shd_string_table */
298 shdr->sh_type = SHT_SYMTAB;
299 shdr->sh_flags = 0;
300 shdr->sh_entsize = sizeof(Elf_Sym);
301 shdr->sh_link = 4; /* index of .strtab section */
302
303 /*
304 * setup symbols string table
305 * 2 = 1 for 0 in 1st entry, 1 for the 0 at end of symbol for 2nd entry
306 */
307 symlen = 2 + strlen(sym);
308 strsym = calloc(1, symlen);
309 if (!strsym) {
310 warnx("cannot allocate strsym");
311 goto error;
312 }
313 strcpy(strsym + 1, sym);
314
315 scn = elf_newscn(e);
316 if (!scn) {
317 warnx("cannot create section");
318 goto error;
319 }
320
321 d = elf_newdata(scn);
322 if (!d) {
323 warnx("cannot get new data");
324 goto error;
325 }
326
327 d->d_align = 1;
328 d->d_off = 0LL;
329 d->d_buf = strsym;
330 d->d_type = ELF_T_BYTE;
331 d->d_size = symlen;
332 d->d_version = EV_CURRENT;
333
334 shdr = elf_getshdr(scn);
335 if (!shdr) {
336 warnx("cannot get section header");
337 goto error;
338 }
339
340 shdr->sh_name = 25; /* offset in shd_string_table */
341 shdr->sh_type = SHT_STRTAB;
342 shdr->sh_flags = 0;
343 shdr->sh_entsize = 0;
344
345 /*
346 * setup build-id section
347 */
348 scn = elf_newscn(e);
349 if (!scn) {
350 warnx("cannot create section");
351 goto error;
352 }
353
354 d = elf_newdata(scn);
355 if (!d) {
356 warnx("cannot get new data");
357 goto error;
358 }
359
360 /*
361 * build-id generation
362 */
363 gen_build_id(&bnote, load_addr, code, csize);
364 bnote.desc.namesz = sizeof(bnote.name); /* must include 0 termination */
365 bnote.desc.descsz = sizeof(bnote.build_id);
366 bnote.desc.type = NT_GNU_BUILD_ID;
367 strcpy(bnote.name, "GNU");
368
369 d->d_align = 4;
370 d->d_off = 0LL;
371 d->d_buf = &bnote;
372 d->d_type = ELF_T_BYTE;
373 d->d_size = sizeof(bnote);
374 d->d_version = EV_CURRENT;
375
376 shdr = elf_getshdr(scn);
377 if (!shdr) {
378 warnx("cannot get section header");
379 goto error;
380 }
381
382 shdr->sh_name = 33; /* offset in shd_string_table */
383 shdr->sh_type = SHT_NOTE;
384 shdr->sh_addr = 0x0;
385 shdr->sh_flags = SHF_ALLOC;
386 shdr->sh_size = sizeof(bnote);
387 shdr->sh_entsize = 0;
388
389 if (debug && nr_debug_entries) {
390 retval = jit_add_debug_info(e, load_addr, debug, nr_debug_entries);
391 if (retval)
392 goto error;
393 } else {
394 if (elf_update(e, ELF_C_WRITE) < 0) {
395 warnx("elf_update 4 failed");
396 goto error;
397 }
398 }
399
400 retval = 0;
401error:
402 (void)elf_end(e);
403
404 free(strsym);
405
406
407 return retval;
408}
409
410#ifndef JVMTI
411
412static unsigned char x86_code[] = {
413 0xBB, 0x2A, 0x00, 0x00, 0x00, /* movl $42, %ebx */
414 0xB8, 0x01, 0x00, 0x00, 0x00, /* movl $1, %eax */
415 0xCD, 0x80 /* int $0x80 */
416};
417
418static struct options options;
419
420int main(int argc, char **argv)
421{
422 int c, fd, ret;
423
424 while ((c = getopt(argc, argv, "o:h")) != -1) {
425 switch (c) {
426 case 'o':
427 options.output = optarg;
428 break;
429 case 'h':
430 printf("Usage: genelf -o output_file [-h]\n");
431 return 0;
432 default:
433 errx(1, "unknown option");
434 }
435 }
436
437 fd = open(options.output, O_CREAT|O_TRUNC|O_RDWR, 0666);
438 if (fd == -1)
439 err(1, "cannot create file %s", options.output);
440
441 ret = jit_write_elf(fd, "main", x86_code, sizeof(x86_code));
442 close(fd);
443
444 if (ret != 0)
445 unlink(options.output);
446
447 return ret;
448}
449#endif
diff --git a/tools/perf/util/genelf.h b/tools/perf/util/genelf.h
new file mode 100644
index 000000000000..2fbeb59c4bdd
--- /dev/null
+++ b/tools/perf/util/genelf.h
@@ -0,0 +1,61 @@
1#ifndef __GENELF_H__
2#define __GENELF_H__
3
4/* genelf.c */
5int jit_write_elf(int fd, uint64_t code_addr, const char *sym,
6 const void *code, int csize, void *debug, int nr_debug_entries);
7/* genelf_debug.c */
8int jit_add_debug_info(Elf *e, uint64_t code_addr, void *debug, int nr_debug_entries);
9
10#if defined(__arm__)
11#define GEN_ELF_ARCH EM_ARM
12#define GEN_ELF_CLASS ELFCLASS32
13#elif defined(__aarch64__)
14#define GEN_ELF_ARCH EM_AARCH64
15#define GEN_ELF_CLASS ELFCLASS64
16#elif defined(__x86_64__)
17#define GEN_ELF_ARCH EM_X86_64
18#define GEN_ELF_CLASS ELFCLASS64
19#elif defined(__i386__)
20#define GEN_ELF_ARCH EM_386
21#define GEN_ELF_CLASS ELFCLASS32
22#elif defined(__powerpc64__)
23#define GEN_ELF_ARCH EM_PPC64
24#define GEN_ELF_CLASS ELFCLASS64
25#elif defined(__powerpc__)
26#define GEN_ELF_ARCH EM_PPC
27#define GEN_ELF_CLASS ELFCLASS32
28#else
29#error "unsupported architecture"
30#endif
31
32#if __BYTE_ORDER == __BIG_ENDIAN
33#define GEN_ELF_ENDIAN ELFDATA2MSB
34#else
35#define GEN_ELF_ENDIAN ELFDATA2LSB
36#endif
37
38#if GEN_ELF_CLASS == ELFCLASS64
39#define elf_newehdr elf64_newehdr
40#define elf_getshdr elf64_getshdr
41#define Elf_Ehdr Elf64_Ehdr
42#define Elf_Shdr Elf64_Shdr
43#define Elf_Sym Elf64_Sym
44#define ELF_ST_TYPE(a) ELF64_ST_TYPE(a)
45#define ELF_ST_BIND(a) ELF64_ST_BIND(a)
46#define ELF_ST_VIS(a) ELF64_ST_VISIBILITY(a)
47#else
48#define elf_newehdr elf32_newehdr
49#define elf_getshdr elf32_getshdr
50#define Elf_Ehdr Elf32_Ehdr
51#define Elf_Shdr Elf32_Shdr
52#define Elf_Sym Elf32_Sym
53#define ELF_ST_TYPE(a) ELF32_ST_TYPE(a)
54#define ELF_ST_BIND(a) ELF32_ST_BIND(a)
55#define ELF_ST_VIS(a) ELF32_ST_VISIBILITY(a)
56#endif
57
58/* The .text section is directly after the ELF header */
59#define GEN_ELF_TEXT_OFFSET sizeof(Elf_Ehdr)
60
61#endif
diff --git a/tools/perf/util/genelf_debug.c b/tools/perf/util/genelf_debug.c
new file mode 100644
index 000000000000..5980f7d256b1
--- /dev/null
+++ b/tools/perf/util/genelf_debug.c
@@ -0,0 +1,610 @@
1/*
2 * genelf_debug.c
3 * Copyright (C) 2015, Google, Inc
4 *
5 * Contributed by:
6 * Stephane Eranian <eranian@google.com>
7 *
8 * Released under the GPL v2.
9 *
10 * based on GPLv2 source code from Oprofile
11 * @remark Copyright 2007 OProfile authors
12 * @author Philippe Elie
13 */
14#include <sys/types.h>
15#include <stdio.h>
16#include <getopt.h>
17#include <stddef.h>
18#include <libelf.h>
19#include <string.h>
20#include <stdlib.h>
21#include <inttypes.h>
22#include <limits.h>
23#include <fcntl.h>
24#include <err.h>
25#include <dwarf.h>
26
27#include "perf.h"
28#include "genelf.h"
29#include "../util/jitdump.h"
30
31#define BUFFER_EXT_DFL_SIZE (4 * 1024)
32
33typedef uint32_t uword;
34typedef uint16_t uhalf;
35typedef int32_t sword;
36typedef int16_t shalf;
37typedef uint8_t ubyte;
38typedef int8_t sbyte;
39
40struct buffer_ext {
41 size_t cur_pos;
42 size_t max_sz;
43 void *data;
44};
45
46static void
47buffer_ext_dump(struct buffer_ext *be, const char *msg)
48{
49 size_t i;
50 warnx("DUMP for %s", msg);
51 for (i = 0 ; i < be->cur_pos; i++)
52 warnx("%4zu 0x%02x", i, (((char *)be->data)[i]) & 0xff);
53}
54
55static inline int
56buffer_ext_add(struct buffer_ext *be, void *addr, size_t sz)
57{
58 void *tmp;
59 size_t be_sz = be->max_sz;
60
61retry:
62 if ((be->cur_pos + sz) < be_sz) {
63 memcpy(be->data + be->cur_pos, addr, sz);
64 be->cur_pos += sz;
65 return 0;
66 }
67
68 if (!be_sz)
69 be_sz = BUFFER_EXT_DFL_SIZE;
70 else
71 be_sz <<= 1;
72
73 tmp = realloc(be->data, be_sz);
74 if (!tmp)
75 return -1;
76
77 be->data = tmp;
78 be->max_sz = be_sz;
79
80 goto retry;
81}
82
83static void
84buffer_ext_init(struct buffer_ext *be)
85{
86 be->data = NULL;
87 be->cur_pos = 0;
88 be->max_sz = 0;
89}
90
91static inline size_t
92buffer_ext_size(struct buffer_ext *be)
93{
94 return be->cur_pos;
95}
96
97static inline void *
98buffer_ext_addr(struct buffer_ext *be)
99{
100 return be->data;
101}
102
103struct debug_line_header {
104 // Not counting this field
105 uword total_length;
106 // version number (2 currently)
107 uhalf version;
108 // relative offset from next field to
109 // program statement
110 uword prolog_length;
111 ubyte minimum_instruction_length;
112 ubyte default_is_stmt;
113 // line_base - see DWARF 2 specs
114 sbyte line_base;
115 // line_range - see DWARF 2 specs
116 ubyte line_range;
117 // number of opcode + 1
118 ubyte opcode_base;
119 /* follow the array of opcode args nr: ubytes [nr_opcode_base] */
120 /* follow the search directories index, zero terminated string
121 * terminated by an empty string.
122 */
123 /* follow an array of { filename, LEB128, LEB128, LEB128 }, first is
124 * the directory index entry, 0 means current directory, then mtime
125 * and filesize, last entry is followed by en empty string.
126 */
127 /* follow the first program statement */
128} __attribute__((packed));
129
130/* DWARF 2 spec talk only about one possible compilation unit header while
131 * binutils can handle two flavours of dwarf 2, 32 and 64 bits, this is not
132 * related to the used arch, an ELF 32 can hold more than 4 Go of debug
133 * information. For now we handle only DWARF 2 32 bits comp unit. It'll only
134 * become a problem if we generate more than 4GB of debug information.
135 */
136struct compilation_unit_header {
137 uword total_length;
138 uhalf version;
139 uword debug_abbrev_offset;
140 ubyte pointer_size;
141} __attribute__((packed));
142
143#define DW_LNS_num_opcode (DW_LNS_set_isa + 1)
144
145/* field filled at run time are marked with -1 */
146static struct debug_line_header const default_debug_line_header = {
147 .total_length = -1,
148 .version = 2,
149 .prolog_length = -1,
150 .minimum_instruction_length = 1, /* could be better when min instruction size != 1 */
151 .default_is_stmt = 1, /* we don't take care about basic block */
152 .line_base = -5, /* sensible value for line base ... */
153 .line_range = -14, /* ... and line range are guessed statically */
154 .opcode_base = DW_LNS_num_opcode
155};
156
157static ubyte standard_opcode_length[] =
158{
159 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1
160};
161#if 0
162{
163 [DW_LNS_advance_pc] = 1,
164 [DW_LNS_advance_line] = 1,
165 [DW_LNS_set_file] = 1,
166 [DW_LNS_set_column] = 1,
167 [DW_LNS_fixed_advance_pc] = 1,
168 [DW_LNS_set_isa] = 1,
169};
170#endif
171
172/* field filled at run time are marked with -1 */
173static struct compilation_unit_header default_comp_unit_header = {
174 .total_length = -1,
175 .version = 2,
176 .debug_abbrev_offset = 0, /* we reuse the same abbrev entries for all comp unit */
177 .pointer_size = sizeof(void *)
178};
179
180static void emit_uword(struct buffer_ext *be, uword data)
181{
182 buffer_ext_add(be, &data, sizeof(uword));
183}
184
185static void emit_string(struct buffer_ext *be, const char *s)
186{
187 buffer_ext_add(be, (void *)s, strlen(s) + 1);
188}
189
190static void emit_unsigned_LEB128(struct buffer_ext *be,
191 unsigned long data)
192{
193 do {
194 ubyte cur = data & 0x7F;
195 data >>= 7;
196 if (data)
197 cur |= 0x80;
198 buffer_ext_add(be, &cur, 1);
199 } while (data);
200}
201
202static void emit_signed_LEB128(struct buffer_ext *be, long data)
203{
204 int more = 1;
205 int negative = data < 0;
206 int size = sizeof(long) * CHAR_BIT;
207 while (more) {
208 ubyte cur = data & 0x7F;
209 data >>= 7;
210 if (negative)
211 data |= - (1 << (size - 7));
212 if ((data == 0 && !(cur & 0x40)) ||
213 (data == -1l && (cur & 0x40)))
214 more = 0;
215 else
216 cur |= 0x80;
217 buffer_ext_add(be, &cur, 1);
218 }
219}
220
221static void emit_extended_opcode(struct buffer_ext *be, ubyte opcode,
222 void *data, size_t data_len)
223{
224 buffer_ext_add(be, (char *)"", 1);
225
226 emit_unsigned_LEB128(be, data_len + 1);
227
228 buffer_ext_add(be, &opcode, 1);
229 buffer_ext_add(be, data, data_len);
230}
231
232static void emit_opcode(struct buffer_ext *be, ubyte opcode)
233{
234 buffer_ext_add(be, &opcode, 1);
235}
236
237static void emit_opcode_signed(struct buffer_ext *be,
238 ubyte opcode, long data)
239{
240 buffer_ext_add(be, &opcode, 1);
241 emit_signed_LEB128(be, data);
242}
243
244static void emit_opcode_unsigned(struct buffer_ext *be, ubyte opcode,
245 unsigned long data)
246{
247 buffer_ext_add(be, &opcode, 1);
248 emit_unsigned_LEB128(be, data);
249}
250
251static void emit_advance_pc(struct buffer_ext *be, unsigned long delta_pc)
252{
253 emit_opcode_unsigned(be, DW_LNS_advance_pc, delta_pc);
254}
255
256static void emit_advance_lineno(struct buffer_ext *be, long delta_lineno)
257{
258 emit_opcode_signed(be, DW_LNS_advance_line, delta_lineno);
259}
260
261static void emit_lne_end_of_sequence(struct buffer_ext *be)
262{
263 emit_extended_opcode(be, DW_LNE_end_sequence, NULL, 0);
264}
265
266static void emit_set_file(struct buffer_ext *be, unsigned long idx)
267{
268 emit_opcode_unsigned(be, DW_LNS_set_file, idx);
269}
270
271static void emit_lne_define_filename(struct buffer_ext *be,
272 const char *filename)
273{
274 buffer_ext_add(be, (void *)"", 1);
275
276 /* LNE field, strlen(filename) + zero termination, 3 bytes for: the dir entry, timestamp, filesize */
277 emit_unsigned_LEB128(be, strlen(filename) + 5);
278 emit_opcode(be, DW_LNE_define_file);
279 emit_string(be, filename);
280 /* directory index 0=do not know */
281 emit_unsigned_LEB128(be, 0);
282 /* last modification date on file 0=do not know */
283 emit_unsigned_LEB128(be, 0);
284 /* filesize 0=do not know */
285 emit_unsigned_LEB128(be, 0);
286}
287
288static void emit_lne_set_address(struct buffer_ext *be,
289 void *address)
290{
291 emit_extended_opcode(be, DW_LNE_set_address, &address, sizeof(unsigned long));
292}
293
294static ubyte get_special_opcode(struct debug_entry *ent,
295 unsigned int last_line,
296 unsigned long last_vma)
297{
298 unsigned int temp;
299 unsigned long delta_addr;
300
301 /*
302 * delta from line_base
303 */
304 temp = (ent->lineno - last_line) - default_debug_line_header.line_base;
305
306 if (temp >= default_debug_line_header.line_range)
307 return 0;
308
309 /*
310 * delta of addresses
311 */
312 delta_addr = (ent->addr - last_vma) / default_debug_line_header.minimum_instruction_length;
313
314 /* This is not sufficient to ensure opcode will be in [0-256] but
315 * sufficient to ensure when summing with the delta lineno we will
316 * not overflow the unsigned long opcode */
317
318 if (delta_addr <= 256 / default_debug_line_header.line_range) {
319 unsigned long opcode = temp +
320 (delta_addr * default_debug_line_header.line_range) +
321 default_debug_line_header.opcode_base;
322
323 return opcode <= 255 ? opcode : 0;
324 }
325 return 0;
326}
327
328static void emit_lineno_info(struct buffer_ext *be,
329 struct debug_entry *ent, size_t nr_entry,
330 unsigned long code_addr)
331{
332 size_t i;
333
334 /*
335 * Machine state at start of a statement program
336 * address = 0
337 * file = 1
338 * line = 1
339 * column = 0
340 * is_stmt = default_is_stmt as given in the debug_line_header
341 * basic block = 0
342 * end sequence = 0
343 */
344
345 /* start state of the state machine we take care of */
346 unsigned long last_vma = code_addr;
347 char const *cur_filename = NULL;
348 unsigned long cur_file_idx = 0;
349 int last_line = 1;
350
351 emit_lne_set_address(be, (void *)code_addr);
352
353 for (i = 0; i < nr_entry; i++, ent = debug_entry_next(ent)) {
354 int need_copy = 0;
355 ubyte special_opcode;
356
357 /*
358 * check if filename changed, if so add it
359 */
360 if (!cur_filename || strcmp(cur_filename, ent->name)) {
361 emit_lne_define_filename(be, ent->name);
362 cur_filename = ent->name;
363 emit_set_file(be, ++cur_file_idx);
364 need_copy = 1;
365 }
366
367 special_opcode = get_special_opcode(ent, last_line, last_vma);
368 if (special_opcode != 0) {
369 last_line = ent->lineno;
370 last_vma = ent->addr;
371 emit_opcode(be, special_opcode);
372 } else {
373 /*
374 * lines differ, emit line delta
375 */
376 if (last_line != ent->lineno) {
377 emit_advance_lineno(be, ent->lineno - last_line);
378 last_line = ent->lineno;
379 need_copy = 1;
380 }
381 /*
382 * addresses differ, emit address delta
383 */
384 if (last_vma != ent->addr) {
385 emit_advance_pc(be, ent->addr - last_vma);
386 last_vma = ent->addr;
387 need_copy = 1;
388 }
389 /*
390 * add new row to matrix
391 */
392 if (need_copy)
393 emit_opcode(be, DW_LNS_copy);
394 }
395 }
396}
397
398static void add_debug_line(struct buffer_ext *be,
399 struct debug_entry *ent, size_t nr_entry,
400 unsigned long code_addr)
401{
402 struct debug_line_header * dbg_header;
403 size_t old_size;
404
405 old_size = buffer_ext_size(be);
406
407 buffer_ext_add(be, (void *)&default_debug_line_header,
408 sizeof(default_debug_line_header));
409
410 buffer_ext_add(be, &standard_opcode_length, sizeof(standard_opcode_length));
411
412 // empty directory entry
413 buffer_ext_add(be, (void *)"", 1);
414
415 // empty filename directory
416 buffer_ext_add(be, (void *)"", 1);
417
418 dbg_header = buffer_ext_addr(be) + old_size;
419 dbg_header->prolog_length = (buffer_ext_size(be) - old_size) -
420 offsetof(struct debug_line_header, minimum_instruction_length);
421
422 emit_lineno_info(be, ent, nr_entry, code_addr);
423
424 emit_lne_end_of_sequence(be);
425
426 dbg_header = buffer_ext_addr(be) + old_size;
427 dbg_header->total_length = (buffer_ext_size(be) - old_size) -
428 offsetof(struct debug_line_header, version);
429}
430
431static void
432add_debug_abbrev(struct buffer_ext *be)
433{
434 emit_unsigned_LEB128(be, 1);
435 emit_unsigned_LEB128(be, DW_TAG_compile_unit);
436 emit_unsigned_LEB128(be, DW_CHILDREN_yes);
437 emit_unsigned_LEB128(be, DW_AT_stmt_list);
438 emit_unsigned_LEB128(be, DW_FORM_data4);
439 emit_unsigned_LEB128(be, 0);
440 emit_unsigned_LEB128(be, 0);
441 emit_unsigned_LEB128(be, 0);
442}
443
444static void
445add_compilation_unit(struct buffer_ext *be,
446 size_t offset_debug_line)
447{
448 struct compilation_unit_header *comp_unit_header;
449 size_t old_size = buffer_ext_size(be);
450
451 buffer_ext_add(be, &default_comp_unit_header,
452 sizeof(default_comp_unit_header));
453
454 emit_unsigned_LEB128(be, 1);
455 emit_uword(be, offset_debug_line);
456
457 comp_unit_header = buffer_ext_addr(be) + old_size;
458 comp_unit_header->total_length = (buffer_ext_size(be) - old_size) -
459 offsetof(struct compilation_unit_header, version);
460}
461
462static int
463jit_process_debug_info(uint64_t code_addr,
464 void *debug, int nr_debug_entries,
465 struct buffer_ext *dl,
466 struct buffer_ext *da,
467 struct buffer_ext *di)
468{
469 struct debug_entry *ent = debug;
470 int i;
471
472 for (i = 0; i < nr_debug_entries; i++) {
473 ent->addr = ent->addr - code_addr;
474 ent = debug_entry_next(ent);
475 }
476 add_compilation_unit(di, buffer_ext_size(dl));
477 add_debug_line(dl, debug, nr_debug_entries, 0);
478 add_debug_abbrev(da);
479 if (0) buffer_ext_dump(da, "abbrev");
480
481 return 0;
482}
483
484int
485jit_add_debug_info(Elf *e, uint64_t code_addr, void *debug, int nr_debug_entries)
486{
487 Elf_Data *d;
488 Elf_Scn *scn;
489 Elf_Shdr *shdr;
490 struct buffer_ext dl, di, da;
491 int ret;
492
493 buffer_ext_init(&dl);
494 buffer_ext_init(&di);
495 buffer_ext_init(&da);
496
497 ret = jit_process_debug_info(code_addr, debug, nr_debug_entries, &dl, &da, &di);
498 if (ret)
499 return -1;
500 /*
501 * setup .debug_line section
502 */
503 scn = elf_newscn(e);
504 if (!scn) {
505 warnx("cannot create section");
506 return -1;
507 }
508
509 d = elf_newdata(scn);
510 if (!d) {
511 warnx("cannot get new data");
512 return -1;
513 }
514
515 d->d_align = 1;
516 d->d_off = 0LL;
517 d->d_buf = buffer_ext_addr(&dl);
518 d->d_type = ELF_T_BYTE;
519 d->d_size = buffer_ext_size(&dl);
520 d->d_version = EV_CURRENT;
521
522 shdr = elf_getshdr(scn);
523 if (!shdr) {
524 warnx("cannot get section header");
525 return -1;
526 }
527
528 shdr->sh_name = 52; /* .debug_line */
529 shdr->sh_type = SHT_PROGBITS;
530 shdr->sh_addr = 0; /* must be zero or == sh_offset -> dynamic object */
531 shdr->sh_flags = 0;
532 shdr->sh_entsize = 0;
533
534 /*
535 * setup .debug_info section
536 */
537 scn = elf_newscn(e);
538 if (!scn) {
539 warnx("cannot create section");
540 return -1;
541 }
542
543 d = elf_newdata(scn);
544 if (!d) {
545 warnx("cannot get new data");
546 return -1;
547 }
548
549 d->d_align = 1;
550 d->d_off = 0LL;
551 d->d_buf = buffer_ext_addr(&di);
552 d->d_type = ELF_T_BYTE;
553 d->d_size = buffer_ext_size(&di);
554 d->d_version = EV_CURRENT;
555
556 shdr = elf_getshdr(scn);
557 if (!shdr) {
558 warnx("cannot get section header");
559 return -1;
560 }
561
562 shdr->sh_name = 64; /* .debug_info */
563 shdr->sh_type = SHT_PROGBITS;
564 shdr->sh_addr = 0; /* must be zero or == sh_offset -> dynamic object */
565 shdr->sh_flags = 0;
566 shdr->sh_entsize = 0;
567
568 /*
569 * setup .debug_abbrev section
570 */
571 scn = elf_newscn(e);
572 if (!scn) {
573 warnx("cannot create section");
574 return -1;
575 }
576
577 d = elf_newdata(scn);
578 if (!d) {
579 warnx("cannot get new data");
580 return -1;
581 }
582
583 d->d_align = 1;
584 d->d_off = 0LL;
585 d->d_buf = buffer_ext_addr(&da);
586 d->d_type = ELF_T_BYTE;
587 d->d_size = buffer_ext_size(&da);
588 d->d_version = EV_CURRENT;
589
590 shdr = elf_getshdr(scn);
591 if (!shdr) {
592 warnx("cannot get section header");
593 return -1;
594 }
595
596 shdr->sh_name = 76; /* .debug_info */
597 shdr->sh_type = SHT_PROGBITS;
598 shdr->sh_addr = 0; /* must be zero or == sh_offset -> dynamic object */
599 shdr->sh_flags = 0;
600 shdr->sh_entsize = 0;
601
602 /*
603 * now we update the ELF image with all the sections
604 */
605 if (elf_update(e, ELF_C_WRITE) < 0) {
606 warnx("elf_update debug failed");
607 return -1;
608 }
609 return 0;
610}
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
index f50b7235ecb6..90680ec9f8b8 100644
--- a/tools/perf/util/header.c
+++ b/tools/perf/util/header.c
@@ -23,6 +23,8 @@
23#include "strbuf.h" 23#include "strbuf.h"
24#include "build-id.h" 24#include "build-id.h"
25#include "data.h" 25#include "data.h"
26#include <api/fs/fs.h>
27#include "asm/bug.h"
26 28
27/* 29/*
28 * magic2 = "PERFILE2" 30 * magic2 = "PERFILE2"
@@ -868,6 +870,199 @@ static int write_auxtrace(int fd, struct perf_header *h,
868 return err; 870 return err;
869} 871}
870 872
873static int cpu_cache_level__sort(const void *a, const void *b)
874{
875 struct cpu_cache_level *cache_a = (struct cpu_cache_level *)a;
876 struct cpu_cache_level *cache_b = (struct cpu_cache_level *)b;
877
878 return cache_a->level - cache_b->level;
879}
880
881static bool cpu_cache_level__cmp(struct cpu_cache_level *a, struct cpu_cache_level *b)
882{
883 if (a->level != b->level)
884 return false;
885
886 if (a->line_size != b->line_size)
887 return false;
888
889 if (a->sets != b->sets)
890 return false;
891
892 if (a->ways != b->ways)
893 return false;
894
895 if (strcmp(a->type, b->type))
896 return false;
897
898 if (strcmp(a->size, b->size))
899 return false;
900
901 if (strcmp(a->map, b->map))
902 return false;
903
904 return true;
905}
906
907static int cpu_cache_level__read(struct cpu_cache_level *cache, u32 cpu, u16 level)
908{
909 char path[PATH_MAX], file[PATH_MAX];
910 struct stat st;
911 size_t len;
912
913 scnprintf(path, PATH_MAX, "devices/system/cpu/cpu%d/cache/index%d/", cpu, level);
914 scnprintf(file, PATH_MAX, "%s/%s", sysfs__mountpoint(), path);
915
916 if (stat(file, &st))
917 return 1;
918
919 scnprintf(file, PATH_MAX, "%s/level", path);
920 if (sysfs__read_int(file, (int *) &cache->level))
921 return -1;
922
923 scnprintf(file, PATH_MAX, "%s/coherency_line_size", path);
924 if (sysfs__read_int(file, (int *) &cache->line_size))
925 return -1;
926
927 scnprintf(file, PATH_MAX, "%s/number_of_sets", path);
928 if (sysfs__read_int(file, (int *) &cache->sets))
929 return -1;
930
931 scnprintf(file, PATH_MAX, "%s/ways_of_associativity", path);
932 if (sysfs__read_int(file, (int *) &cache->ways))
933 return -1;
934
935 scnprintf(file, PATH_MAX, "%s/type", path);
936 if (sysfs__read_str(file, &cache->type, &len))
937 return -1;
938
939 cache->type[len] = 0;
940 cache->type = rtrim(cache->type);
941
942 scnprintf(file, PATH_MAX, "%s/size", path);
943 if (sysfs__read_str(file, &cache->size, &len)) {
944 free(cache->type);
945 return -1;
946 }
947
948 cache->size[len] = 0;
949 cache->size = rtrim(cache->size);
950
951 scnprintf(file, PATH_MAX, "%s/shared_cpu_list", path);
952 if (sysfs__read_str(file, &cache->map, &len)) {
953 free(cache->map);
954 free(cache->type);
955 return -1;
956 }
957
958 cache->map[len] = 0;
959 cache->map = rtrim(cache->map);
960 return 0;
961}
962
963static void cpu_cache_level__fprintf(FILE *out, struct cpu_cache_level *c)
964{
965 fprintf(out, "L%d %-15s %8s [%s]\n", c->level, c->type, c->size, c->map);
966}
967
968static int build_caches(struct cpu_cache_level caches[], u32 size, u32 *cntp)
969{
970 u32 i, cnt = 0;
971 long ncpus;
972 u32 nr, cpu;
973 u16 level;
974
975 ncpus = sysconf(_SC_NPROCESSORS_CONF);
976 if (ncpus < 0)
977 return -1;
978
979 nr = (u32)(ncpus & UINT_MAX);
980
981 for (cpu = 0; cpu < nr; cpu++) {
982 for (level = 0; level < 10; level++) {
983 struct cpu_cache_level c;
984 int err;
985
986 err = cpu_cache_level__read(&c, cpu, level);
987 if (err < 0)
988 return err;
989
990 if (err == 1)
991 break;
992
993 for (i = 0; i < cnt; i++) {
994 if (cpu_cache_level__cmp(&c, &caches[i]))
995 break;
996 }
997
998 if (i == cnt)
999 caches[cnt++] = c;
1000 else
1001 cpu_cache_level__free(&c);
1002
1003 if (WARN_ONCE(cnt == size, "way too many cpu caches.."))
1004 goto out;
1005 }
1006 }
1007 out:
1008 *cntp = cnt;
1009 return 0;
1010}
1011
1012#define MAX_CACHES 2000
1013
1014static int write_cache(int fd, struct perf_header *h __maybe_unused,
1015 struct perf_evlist *evlist __maybe_unused)
1016{
1017 struct cpu_cache_level caches[MAX_CACHES];
1018 u32 cnt = 0, i, version = 1;
1019 int ret;
1020
1021 ret = build_caches(caches, MAX_CACHES, &cnt);
1022 if (ret)
1023 goto out;
1024
1025 qsort(&caches, cnt, sizeof(struct cpu_cache_level), cpu_cache_level__sort);
1026
1027 ret = do_write(fd, &version, sizeof(u32));
1028 if (ret < 0)
1029 goto out;
1030
1031 ret = do_write(fd, &cnt, sizeof(u32));
1032 if (ret < 0)
1033 goto out;
1034
1035 for (i = 0; i < cnt; i++) {
1036 struct cpu_cache_level *c = &caches[i];
1037
1038 #define _W(v) \
1039 ret = do_write(fd, &c->v, sizeof(u32)); \
1040 if (ret < 0) \
1041 goto out;
1042
1043 _W(level)
1044 _W(line_size)
1045 _W(sets)
1046 _W(ways)
1047 #undef _W
1048
1049 #define _W(v) \
1050 ret = do_write_string(fd, (const char *) c->v); \
1051 if (ret < 0) \
1052 goto out;
1053
1054 _W(type)
1055 _W(size)
1056 _W(map)
1057 #undef _W
1058 }
1059
1060out:
1061 for (i = 0; i < cnt; i++)
1062 cpu_cache_level__free(&caches[i]);
1063 return ret;
1064}
1065
871static int write_stat(int fd __maybe_unused, 1066static int write_stat(int fd __maybe_unused,
872 struct perf_header *h __maybe_unused, 1067 struct perf_header *h __maybe_unused,
873 struct perf_evlist *evlist __maybe_unused) 1068 struct perf_evlist *evlist __maybe_unused)
@@ -1172,6 +1367,18 @@ static void print_stat(struct perf_header *ph __maybe_unused,
1172 fprintf(fp, "# contains stat data\n"); 1367 fprintf(fp, "# contains stat data\n");
1173} 1368}
1174 1369
1370static void print_cache(struct perf_header *ph __maybe_unused,
1371 int fd __maybe_unused, FILE *fp __maybe_unused)
1372{
1373 int i;
1374
1375 fprintf(fp, "# CPU cache info:\n");
1376 for (i = 0; i < ph->env.caches_cnt; i++) {
1377 fprintf(fp, "# ");
1378 cpu_cache_level__fprintf(fp, &ph->env.caches[i]);
1379 }
1380}
1381
1175static void print_pmu_mappings(struct perf_header *ph, int fd __maybe_unused, 1382static void print_pmu_mappings(struct perf_header *ph, int fd __maybe_unused,
1176 FILE *fp) 1383 FILE *fp)
1177{ 1384{
@@ -1665,11 +1872,6 @@ static int process_cpu_topology(struct perf_file_section *section,
1665 if (ph->needs_swap) 1872 if (ph->needs_swap)
1666 nr = bswap_32(nr); 1873 nr = bswap_32(nr);
1667 1874
1668 if (nr > (u32)cpu_nr) {
1669 pr_debug("core_id number is too big."
1670 "You may need to upgrade the perf tool.\n");
1671 goto free_cpu;
1672 }
1673 ph->env.cpu[i].core_id = nr; 1875 ph->env.cpu[i].core_id = nr;
1674 1876
1675 ret = readn(fd, &nr, sizeof(nr)); 1877 ret = readn(fd, &nr, sizeof(nr));
@@ -1920,6 +2122,68 @@ static int process_auxtrace(struct perf_file_section *section,
1920 return err; 2122 return err;
1921} 2123}
1922 2124
2125static int process_cache(struct perf_file_section *section __maybe_unused,
2126 struct perf_header *ph __maybe_unused, int fd __maybe_unused,
2127 void *data __maybe_unused)
2128{
2129 struct cpu_cache_level *caches;
2130 u32 cnt, i, version;
2131
2132 if (readn(fd, &version, sizeof(version)) != sizeof(version))
2133 return -1;
2134
2135 if (ph->needs_swap)
2136 version = bswap_32(version);
2137
2138 if (version != 1)
2139 return -1;
2140
2141 if (readn(fd, &cnt, sizeof(cnt)) != sizeof(cnt))
2142 return -1;
2143
2144 if (ph->needs_swap)
2145 cnt = bswap_32(cnt);
2146
2147 caches = zalloc(sizeof(*caches) * cnt);
2148 if (!caches)
2149 return -1;
2150
2151 for (i = 0; i < cnt; i++) {
2152 struct cpu_cache_level c;
2153
2154 #define _R(v) \
2155 if (readn(fd, &c.v, sizeof(u32)) != sizeof(u32))\
2156 goto out_free_caches; \
2157 if (ph->needs_swap) \
2158 c.v = bswap_32(c.v); \
2159
2160 _R(level)
2161 _R(line_size)
2162 _R(sets)
2163 _R(ways)
2164 #undef _R
2165
2166 #define _R(v) \
2167 c.v = do_read_string(fd, ph); \
2168 if (!c.v) \
2169 goto out_free_caches;
2170
2171 _R(type)
2172 _R(size)
2173 _R(map)
2174 #undef _R
2175
2176 caches[i] = c;
2177 }
2178
2179 ph->env.caches = caches;
2180 ph->env.caches_cnt = cnt;
2181 return 0;
2182out_free_caches:
2183 free(caches);
2184 return -1;
2185}
2186
1923struct feature_ops { 2187struct feature_ops {
1924 int (*write)(int fd, struct perf_header *h, struct perf_evlist *evlist); 2188 int (*write)(int fd, struct perf_header *h, struct perf_evlist *evlist);
1925 void (*print)(struct perf_header *h, int fd, FILE *fp); 2189 void (*print)(struct perf_header *h, int fd, FILE *fp);
@@ -1962,6 +2226,7 @@ static const struct feature_ops feat_ops[HEADER_LAST_FEATURE] = {
1962 FEAT_OPP(HEADER_GROUP_DESC, group_desc), 2226 FEAT_OPP(HEADER_GROUP_DESC, group_desc),
1963 FEAT_OPP(HEADER_AUXTRACE, auxtrace), 2227 FEAT_OPP(HEADER_AUXTRACE, auxtrace),
1964 FEAT_OPA(HEADER_STAT, stat), 2228 FEAT_OPA(HEADER_STAT, stat),
2229 FEAT_OPF(HEADER_CACHE, cache),
1965}; 2230};
1966 2231
1967struct header_print_data { 2232struct header_print_data {
diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h
index cff9892452ee..d306ca118449 100644
--- a/tools/perf/util/header.h
+++ b/tools/perf/util/header.h
@@ -32,6 +32,7 @@ enum {
32 HEADER_GROUP_DESC, 32 HEADER_GROUP_DESC,
33 HEADER_AUXTRACE, 33 HEADER_AUXTRACE,
34 HEADER_STAT, 34 HEADER_STAT,
35 HEADER_CACHE,
35 HEADER_LAST_FEATURE, 36 HEADER_LAST_FEATURE,
36 HEADER_FEAT_BITS = 256, 37 HEADER_FEAT_BITS = 256,
37}; 38};
@@ -120,7 +121,7 @@ int perf_event__synthesize_event_update_cpus(struct perf_tool *tool,
120 perf_event__handler_t process); 121 perf_event__handler_t process);
121int perf_event__process_attr(struct perf_tool *tool, union perf_event *event, 122int perf_event__process_attr(struct perf_tool *tool, union perf_event *event,
122 struct perf_evlist **pevlist); 123 struct perf_evlist **pevlist);
123int perf_event__process_event_update(struct perf_tool *tool __maybe_unused, 124int perf_event__process_event_update(struct perf_tool *tool,
124 union perf_event *event, 125 union perf_event *event,
125 struct perf_evlist **pevlist); 126 struct perf_evlist **pevlist);
126size_t perf_event__fprintf_event_update(union perf_event *event, FILE *fp); 127size_t perf_event__fprintf_event_update(union perf_event *event, FILE *fp);
diff --git a/tools/perf/util/help-unknown-cmd.c b/tools/perf/util/help-unknown-cmd.c
index dc1e41c9b054..43a98a4dc1e1 100644
--- a/tools/perf/util/help-unknown-cmd.c
+++ b/tools/perf/util/help-unknown-cmd.c
@@ -6,7 +6,8 @@
6static int autocorrect; 6static int autocorrect;
7static struct cmdnames aliases; 7static struct cmdnames aliases;
8 8
9static int perf_unknown_cmd_config(const char *var, const char *value, void *cb) 9static int perf_unknown_cmd_config(const char *var, const char *value,
10 void *cb __maybe_unused)
10{ 11{
11 if (!strcmp(var, "help.autocorrect")) 12 if (!strcmp(var, "help.autocorrect"))
12 autocorrect = perf_config_int(var,value); 13 autocorrect = perf_config_int(var,value);
@@ -14,7 +15,7 @@ static int perf_unknown_cmd_config(const char *var, const char *value, void *cb)
14 if (!prefixcmp(var, "alias.")) 15 if (!prefixcmp(var, "alias."))
15 add_cmdname(&aliases, var + 6, strlen(var + 6)); 16 add_cmdname(&aliases, var + 6, strlen(var + 6));
16 17
17 return perf_default_config(var, value, cb); 18 return 0;
18} 19}
19 20
20static int levenshtein_compare(const void *p1, const void *p2) 21static int levenshtein_compare(const void *p1, const void *p2)
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c
index 68a7612019dc..31c4641fe5ff 100644
--- a/tools/perf/util/hist.c
+++ b/tools/perf/util/hist.c
@@ -179,6 +179,9 @@ void hists__calc_col_len(struct hists *hists, struct hist_entry *h)
179 if (h->transaction) 179 if (h->transaction)
180 hists__new_col_len(hists, HISTC_TRANSACTION, 180 hists__new_col_len(hists, HISTC_TRANSACTION,
181 hist_entry__transaction_len()); 181 hist_entry__transaction_len());
182
183 if (h->trace_output)
184 hists__new_col_len(hists, HISTC_TRACE, strlen(h->trace_output));
182} 185}
183 186
184void hists__output_recalc_col_len(struct hists *hists, int max_rows) 187void hists__output_recalc_col_len(struct hists *hists, int max_rows)
@@ -245,6 +248,8 @@ static void he_stat__decay(struct he_stat *he_stat)
245 /* XXX need decay for weight too? */ 248 /* XXX need decay for weight too? */
246} 249}
247 250
251static void hists__delete_entry(struct hists *hists, struct hist_entry *he);
252
248static bool hists__decay_entry(struct hists *hists, struct hist_entry *he) 253static bool hists__decay_entry(struct hists *hists, struct hist_entry *he)
249{ 254{
250 u64 prev_period = he->stat.period; 255 u64 prev_period = he->stat.period;
@@ -260,21 +265,45 @@ static bool hists__decay_entry(struct hists *hists, struct hist_entry *he)
260 265
261 diff = prev_period - he->stat.period; 266 diff = prev_period - he->stat.period;
262 267
263 hists->stats.total_period -= diff; 268 if (!he->depth) {
264 if (!he->filtered) 269 hists->stats.total_period -= diff;
265 hists->stats.total_non_filtered_period -= diff; 270 if (!he->filtered)
271 hists->stats.total_non_filtered_period -= diff;
272 }
273
274 if (!he->leaf) {
275 struct hist_entry *child;
276 struct rb_node *node = rb_first(&he->hroot_out);
277 while (node) {
278 child = rb_entry(node, struct hist_entry, rb_node);
279 node = rb_next(node);
280
281 if (hists__decay_entry(hists, child))
282 hists__delete_entry(hists, child);
283 }
284 }
266 285
267 return he->stat.period == 0; 286 return he->stat.period == 0;
268} 287}
269 288
270static void hists__delete_entry(struct hists *hists, struct hist_entry *he) 289static void hists__delete_entry(struct hists *hists, struct hist_entry *he)
271{ 290{
272 rb_erase(&he->rb_node, &hists->entries); 291 struct rb_root *root_in;
292 struct rb_root *root_out;
273 293
274 if (sort__need_collapse) 294 if (he->parent_he) {
275 rb_erase(&he->rb_node_in, &hists->entries_collapsed); 295 root_in = &he->parent_he->hroot_in;
276 else 296 root_out = &he->parent_he->hroot_out;
277 rb_erase(&he->rb_node_in, hists->entries_in); 297 } else {
298 if (sort__need_collapse)
299 root_in = &hists->entries_collapsed;
300 else
301 root_in = hists->entries_in;
302 root_out = &hists->entries;
303 }
304
305 rb_erase(&he->rb_node_in, root_in);
306 rb_erase(&he->rb_node, root_out);
278 307
279 --hists->nr_entries; 308 --hists->nr_entries;
280 if (!he->filtered) 309 if (!he->filtered)
@@ -393,6 +422,9 @@ static struct hist_entry *hist_entry__new(struct hist_entry *template,
393 } 422 }
394 INIT_LIST_HEAD(&he->pairs.node); 423 INIT_LIST_HEAD(&he->pairs.node);
395 thread__get(he->thread); 424 thread__get(he->thread);
425
426 if (!symbol_conf.report_hierarchy)
427 he->leaf = true;
396 } 428 }
397 429
398 return he; 430 return he;
@@ -405,6 +437,16 @@ static u8 symbol__parent_filter(const struct symbol *parent)
405 return 0; 437 return 0;
406} 438}
407 439
440static void hist_entry__add_callchain_period(struct hist_entry *he, u64 period)
441{
442 if (!symbol_conf.use_callchain)
443 return;
444
445 he->hists->callchain_period += period;
446 if (!he->filtered)
447 he->hists->callchain_non_filtered_period += period;
448}
449
408static struct hist_entry *hists__findnew_entry(struct hists *hists, 450static struct hist_entry *hists__findnew_entry(struct hists *hists,
409 struct hist_entry *entry, 451 struct hist_entry *entry,
410 struct addr_location *al, 452 struct addr_location *al,
@@ -432,8 +474,10 @@ static struct hist_entry *hists__findnew_entry(struct hists *hists,
432 cmp = hist_entry__cmp(he, entry); 474 cmp = hist_entry__cmp(he, entry);
433 475
434 if (!cmp) { 476 if (!cmp) {
435 if (sample_self) 477 if (sample_self) {
436 he_stat__add_period(&he->stat, period, weight); 478 he_stat__add_period(&he->stat, period, weight);
479 hist_entry__add_callchain_period(he, period);
480 }
437 if (symbol_conf.cumulate_callchain) 481 if (symbol_conf.cumulate_callchain)
438 he_stat__add_period(he->stat_acc, period, weight); 482 he_stat__add_period(he->stat_acc, period, weight);
439 483
@@ -466,6 +510,8 @@ static struct hist_entry *hists__findnew_entry(struct hists *hists,
466 if (!he) 510 if (!he)
467 return NULL; 511 return NULL;
468 512
513 if (sample_self)
514 hist_entry__add_callchain_period(he, period);
469 hists->nr_entries++; 515 hists->nr_entries++;
470 516
471 rb_link_node(&he->rb_node_in, parent, p); 517 rb_link_node(&he->rb_node_in, parent, p);
@@ -624,7 +670,7 @@ iter_prepare_branch_entry(struct hist_entry_iter *iter, struct addr_location *al
624} 670}
625 671
626static int 672static int
627iter_add_single_branch_entry(struct hist_entry_iter *iter __maybe_unused, 673iter_add_single_branch_entry(struct hist_entry_iter *iter,
628 struct addr_location *al __maybe_unused) 674 struct addr_location *al __maybe_unused)
629{ 675{
630 /* to avoid calling callback function */ 676 /* to avoid calling callback function */
@@ -951,10 +997,15 @@ out:
951int64_t 997int64_t
952hist_entry__cmp(struct hist_entry *left, struct hist_entry *right) 998hist_entry__cmp(struct hist_entry *left, struct hist_entry *right)
953{ 999{
1000 struct hists *hists = left->hists;
954 struct perf_hpp_fmt *fmt; 1001 struct perf_hpp_fmt *fmt;
955 int64_t cmp = 0; 1002 int64_t cmp = 0;
956 1003
957 perf_hpp__for_each_sort_list(fmt) { 1004 hists__for_each_sort_list(hists, fmt) {
1005 if (perf_hpp__is_dynamic_entry(fmt) &&
1006 !perf_hpp__defined_dynamic_entry(fmt, hists))
1007 continue;
1008
958 cmp = fmt->cmp(fmt, left, right); 1009 cmp = fmt->cmp(fmt, left, right);
959 if (cmp) 1010 if (cmp)
960 break; 1011 break;
@@ -966,10 +1017,15 @@ hist_entry__cmp(struct hist_entry *left, struct hist_entry *right)
966int64_t 1017int64_t
967hist_entry__collapse(struct hist_entry *left, struct hist_entry *right) 1018hist_entry__collapse(struct hist_entry *left, struct hist_entry *right)
968{ 1019{
1020 struct hists *hists = left->hists;
969 struct perf_hpp_fmt *fmt; 1021 struct perf_hpp_fmt *fmt;
970 int64_t cmp = 0; 1022 int64_t cmp = 0;
971 1023
972 perf_hpp__for_each_sort_list(fmt) { 1024 hists__for_each_sort_list(hists, fmt) {
1025 if (perf_hpp__is_dynamic_entry(fmt) &&
1026 !perf_hpp__defined_dynamic_entry(fmt, hists))
1027 continue;
1028
973 cmp = fmt->collapse(fmt, left, right); 1029 cmp = fmt->collapse(fmt, left, right);
974 if (cmp) 1030 if (cmp)
975 break; 1031 break;
@@ -1006,17 +1062,250 @@ void hist_entry__delete(struct hist_entry *he)
1006} 1062}
1007 1063
1008/* 1064/*
1065 * If this is not the last column, then we need to pad it according to the
1066 * pre-calculated max lenght for this column, otherwise don't bother adding
1067 * spaces because that would break viewing this with, for instance, 'less',
1068 * that would show tons of trailing spaces when a long C++ demangled method
1069 * names is sampled.
1070*/
1071int hist_entry__snprintf_alignment(struct hist_entry *he, struct perf_hpp *hpp,
1072 struct perf_hpp_fmt *fmt, int printed)
1073{
1074 if (!list_is_last(&fmt->list, &he->hists->hpp_list->fields)) {
1075 const int width = fmt->width(fmt, hpp, hists_to_evsel(he->hists));
1076 if (printed < width) {
1077 advance_hpp(hpp, printed);
1078 printed = scnprintf(hpp->buf, hpp->size, "%-*s", width - printed, " ");
1079 }
1080 }
1081
1082 return printed;
1083}
1084
1085/*
1009 * collapse the histogram 1086 * collapse the histogram
1010 */ 1087 */
1011 1088
1012bool hists__collapse_insert_entry(struct hists *hists __maybe_unused, 1089static void hists__apply_filters(struct hists *hists, struct hist_entry *he);
1013 struct rb_root *root, struct hist_entry *he) 1090static void hists__remove_entry_filter(struct hists *hists, struct hist_entry *he,
1091 enum hist_filter type);
1092
1093typedef bool (*fmt_chk_fn)(struct perf_hpp_fmt *fmt);
1094
1095static bool check_thread_entry(struct perf_hpp_fmt *fmt)
1096{
1097 return perf_hpp__is_thread_entry(fmt) || perf_hpp__is_comm_entry(fmt);
1098}
1099
1100static void hist_entry__check_and_remove_filter(struct hist_entry *he,
1101 enum hist_filter type,
1102 fmt_chk_fn check)
1103{
1104 struct perf_hpp_fmt *fmt;
1105 bool type_match = false;
1106 struct hist_entry *parent = he->parent_he;
1107
1108 switch (type) {
1109 case HIST_FILTER__THREAD:
1110 if (symbol_conf.comm_list == NULL &&
1111 symbol_conf.pid_list == NULL &&
1112 symbol_conf.tid_list == NULL)
1113 return;
1114 break;
1115 case HIST_FILTER__DSO:
1116 if (symbol_conf.dso_list == NULL)
1117 return;
1118 break;
1119 case HIST_FILTER__SYMBOL:
1120 if (symbol_conf.sym_list == NULL)
1121 return;
1122 break;
1123 case HIST_FILTER__PARENT:
1124 case HIST_FILTER__GUEST:
1125 case HIST_FILTER__HOST:
1126 case HIST_FILTER__SOCKET:
1127 default:
1128 return;
1129 }
1130
1131 /* if it's filtered by own fmt, it has to have filter bits */
1132 perf_hpp_list__for_each_format(he->hpp_list, fmt) {
1133 if (check(fmt)) {
1134 type_match = true;
1135 break;
1136 }
1137 }
1138
1139 if (type_match) {
1140 /*
1141 * If the filter is for current level entry, propagate
1142 * filter marker to parents. The marker bit was
1143 * already set by default so it only needs to clear
1144 * non-filtered entries.
1145 */
1146 if (!(he->filtered & (1 << type))) {
1147 while (parent) {
1148 parent->filtered &= ~(1 << type);
1149 parent = parent->parent_he;
1150 }
1151 }
1152 } else {
1153 /*
1154 * If current entry doesn't have matching formats, set
1155 * filter marker for upper level entries. it will be
1156 * cleared if its lower level entries is not filtered.
1157 *
1158 * For lower-level entries, it inherits parent's
1159 * filter bit so that lower level entries of a
1160 * non-filtered entry won't set the filter marker.
1161 */
1162 if (parent == NULL)
1163 he->filtered |= (1 << type);
1164 else
1165 he->filtered |= (parent->filtered & (1 << type));
1166 }
1167}
1168
1169static void hist_entry__apply_hierarchy_filters(struct hist_entry *he)
1170{
1171 hist_entry__check_and_remove_filter(he, HIST_FILTER__THREAD,
1172 check_thread_entry);
1173
1174 hist_entry__check_and_remove_filter(he, HIST_FILTER__DSO,
1175 perf_hpp__is_dso_entry);
1176
1177 hist_entry__check_and_remove_filter(he, HIST_FILTER__SYMBOL,
1178 perf_hpp__is_sym_entry);
1179
1180 hists__apply_filters(he->hists, he);
1181}
1182
1183static struct hist_entry *hierarchy_insert_entry(struct hists *hists,
1184 struct rb_root *root,
1185 struct hist_entry *he,
1186 struct hist_entry *parent_he,
1187 struct perf_hpp_list *hpp_list)
1188{
1189 struct rb_node **p = &root->rb_node;
1190 struct rb_node *parent = NULL;
1191 struct hist_entry *iter, *new;
1192 struct perf_hpp_fmt *fmt;
1193 int64_t cmp;
1194
1195 while (*p != NULL) {
1196 parent = *p;
1197 iter = rb_entry(parent, struct hist_entry, rb_node_in);
1198
1199 cmp = 0;
1200 perf_hpp_list__for_each_sort_list(hpp_list, fmt) {
1201 cmp = fmt->collapse(fmt, iter, he);
1202 if (cmp)
1203 break;
1204 }
1205
1206 if (!cmp) {
1207 he_stat__add_stat(&iter->stat, &he->stat);
1208 return iter;
1209 }
1210
1211 if (cmp < 0)
1212 p = &parent->rb_left;
1213 else
1214 p = &parent->rb_right;
1215 }
1216
1217 new = hist_entry__new(he, true);
1218 if (new == NULL)
1219 return NULL;
1220
1221 hists->nr_entries++;
1222
1223 /* save related format list for output */
1224 new->hpp_list = hpp_list;
1225 new->parent_he = parent_he;
1226
1227 hist_entry__apply_hierarchy_filters(new);
1228
1229 /* some fields are now passed to 'new' */
1230 perf_hpp_list__for_each_sort_list(hpp_list, fmt) {
1231 if (perf_hpp__is_trace_entry(fmt) || perf_hpp__is_dynamic_entry(fmt))
1232 he->trace_output = NULL;
1233 else
1234 new->trace_output = NULL;
1235
1236 if (perf_hpp__is_srcline_entry(fmt))
1237 he->srcline = NULL;
1238 else
1239 new->srcline = NULL;
1240
1241 if (perf_hpp__is_srcfile_entry(fmt))
1242 he->srcfile = NULL;
1243 else
1244 new->srcfile = NULL;
1245 }
1246
1247 rb_link_node(&new->rb_node_in, parent, p);
1248 rb_insert_color(&new->rb_node_in, root);
1249 return new;
1250}
1251
1252static int hists__hierarchy_insert_entry(struct hists *hists,
1253 struct rb_root *root,
1254 struct hist_entry *he)
1255{
1256 struct perf_hpp_list_node *node;
1257 struct hist_entry *new_he = NULL;
1258 struct hist_entry *parent = NULL;
1259 int depth = 0;
1260 int ret = 0;
1261
1262 list_for_each_entry(node, &hists->hpp_formats, list) {
1263 /* skip period (overhead) and elided columns */
1264 if (node->level == 0 || node->skip)
1265 continue;
1266
1267 /* insert copy of 'he' for each fmt into the hierarchy */
1268 new_he = hierarchy_insert_entry(hists, root, he, parent, &node->hpp);
1269 if (new_he == NULL) {
1270 ret = -1;
1271 break;
1272 }
1273
1274 root = &new_he->hroot_in;
1275 new_he->depth = depth++;
1276 parent = new_he;
1277 }
1278
1279 if (new_he) {
1280 new_he->leaf = true;
1281
1282 if (symbol_conf.use_callchain) {
1283 callchain_cursor_reset(&callchain_cursor);
1284 if (callchain_merge(&callchain_cursor,
1285 new_he->callchain,
1286 he->callchain) < 0)
1287 ret = -1;
1288 }
1289 }
1290
1291 /* 'he' is no longer used */
1292 hist_entry__delete(he);
1293
1294 /* return 0 (or -1) since it already applied filters */
1295 return ret;
1296}
1297
1298int hists__collapse_insert_entry(struct hists *hists, struct rb_root *root,
1299 struct hist_entry *he)
1014{ 1300{
1015 struct rb_node **p = &root->rb_node; 1301 struct rb_node **p = &root->rb_node;
1016 struct rb_node *parent = NULL; 1302 struct rb_node *parent = NULL;
1017 struct hist_entry *iter; 1303 struct hist_entry *iter;
1018 int64_t cmp; 1304 int64_t cmp;
1019 1305
1306 if (symbol_conf.report_hierarchy)
1307 return hists__hierarchy_insert_entry(hists, root, he);
1308
1020 while (*p != NULL) { 1309 while (*p != NULL) {
1021 parent = *p; 1310 parent = *p;
1022 iter = rb_entry(parent, struct hist_entry, rb_node_in); 1311 iter = rb_entry(parent, struct hist_entry, rb_node_in);
@@ -1024,18 +1313,21 @@ bool hists__collapse_insert_entry(struct hists *hists __maybe_unused,
1024 cmp = hist_entry__collapse(iter, he); 1313 cmp = hist_entry__collapse(iter, he);
1025 1314
1026 if (!cmp) { 1315 if (!cmp) {
1316 int ret = 0;
1317
1027 he_stat__add_stat(&iter->stat, &he->stat); 1318 he_stat__add_stat(&iter->stat, &he->stat);
1028 if (symbol_conf.cumulate_callchain) 1319 if (symbol_conf.cumulate_callchain)
1029 he_stat__add_stat(iter->stat_acc, he->stat_acc); 1320 he_stat__add_stat(iter->stat_acc, he->stat_acc);
1030 1321
1031 if (symbol_conf.use_callchain) { 1322 if (symbol_conf.use_callchain) {
1032 callchain_cursor_reset(&callchain_cursor); 1323 callchain_cursor_reset(&callchain_cursor);
1033 callchain_merge(&callchain_cursor, 1324 if (callchain_merge(&callchain_cursor,
1034 iter->callchain, 1325 iter->callchain,
1035 he->callchain); 1326 he->callchain) < 0)
1327 ret = -1;
1036 } 1328 }
1037 hist_entry__delete(he); 1329 hist_entry__delete(he);
1038 return false; 1330 return ret;
1039 } 1331 }
1040 1332
1041 if (cmp < 0) 1333 if (cmp < 0)
@@ -1047,7 +1339,7 @@ bool hists__collapse_insert_entry(struct hists *hists __maybe_unused,
1047 1339
1048 rb_link_node(&he->rb_node_in, parent, p); 1340 rb_link_node(&he->rb_node_in, parent, p);
1049 rb_insert_color(&he->rb_node_in, root); 1341 rb_insert_color(&he->rb_node_in, root);
1050 return true; 1342 return 1;
1051} 1343}
1052 1344
1053struct rb_root *hists__get_rotate_entries_in(struct hists *hists) 1345struct rb_root *hists__get_rotate_entries_in(struct hists *hists)
@@ -1073,14 +1365,15 @@ static void hists__apply_filters(struct hists *hists, struct hist_entry *he)
1073 hists__filter_entry_by_socket(hists, he); 1365 hists__filter_entry_by_socket(hists, he);
1074} 1366}
1075 1367
1076void hists__collapse_resort(struct hists *hists, struct ui_progress *prog) 1368int hists__collapse_resort(struct hists *hists, struct ui_progress *prog)
1077{ 1369{
1078 struct rb_root *root; 1370 struct rb_root *root;
1079 struct rb_node *next; 1371 struct rb_node *next;
1080 struct hist_entry *n; 1372 struct hist_entry *n;
1373 int ret;
1081 1374
1082 if (!sort__need_collapse) 1375 if (!sort__need_collapse)
1083 return; 1376 return 0;
1084 1377
1085 hists->nr_entries = 0; 1378 hists->nr_entries = 0;
1086 1379
@@ -1095,7 +1388,11 @@ void hists__collapse_resort(struct hists *hists, struct ui_progress *prog)
1095 next = rb_next(&n->rb_node_in); 1388 next = rb_next(&n->rb_node_in);
1096 1389
1097 rb_erase(&n->rb_node_in, root); 1390 rb_erase(&n->rb_node_in, root);
1098 if (hists__collapse_insert_entry(hists, &hists->entries_collapsed, n)) { 1391 ret = hists__collapse_insert_entry(hists, &hists->entries_collapsed, n);
1392 if (ret < 0)
1393 return -1;
1394
1395 if (ret) {
1099 /* 1396 /*
1100 * If it wasn't combined with one of the entries already 1397 * If it wasn't combined with one of the entries already
1101 * collapsed, we need to apply the filters that may have 1398 * collapsed, we need to apply the filters that may have
@@ -1106,14 +1403,16 @@ void hists__collapse_resort(struct hists *hists, struct ui_progress *prog)
1106 if (prog) 1403 if (prog)
1107 ui_progress__update(prog, 1); 1404 ui_progress__update(prog, 1);
1108 } 1405 }
1406 return 0;
1109} 1407}
1110 1408
1111static int hist_entry__sort(struct hist_entry *a, struct hist_entry *b) 1409static int hist_entry__sort(struct hist_entry *a, struct hist_entry *b)
1112{ 1410{
1411 struct hists *hists = a->hists;
1113 struct perf_hpp_fmt *fmt; 1412 struct perf_hpp_fmt *fmt;
1114 int64_t cmp = 0; 1413 int64_t cmp = 0;
1115 1414
1116 perf_hpp__for_each_sort_list(fmt) { 1415 hists__for_each_sort_list(hists, fmt) {
1117 if (perf_hpp__should_skip(fmt, a->hists)) 1416 if (perf_hpp__should_skip(fmt, a->hists))
1118 continue; 1417 continue;
1119 1418
@@ -1154,6 +1453,113 @@ void hists__inc_stats(struct hists *hists, struct hist_entry *h)
1154 hists->stats.total_period += h->stat.period; 1453 hists->stats.total_period += h->stat.period;
1155} 1454}
1156 1455
1456static void hierarchy_recalc_total_periods(struct hists *hists)
1457{
1458 struct rb_node *node;
1459 struct hist_entry *he;
1460
1461 node = rb_first(&hists->entries);
1462
1463 hists->stats.total_period = 0;
1464 hists->stats.total_non_filtered_period = 0;
1465
1466 /*
1467 * recalculate total period using top-level entries only
1468 * since lower level entries only see non-filtered entries
1469 * but upper level entries have sum of both entries.
1470 */
1471 while (node) {
1472 he = rb_entry(node, struct hist_entry, rb_node);
1473 node = rb_next(node);
1474
1475 hists->stats.total_period += he->stat.period;
1476 if (!he->filtered)
1477 hists->stats.total_non_filtered_period += he->stat.period;
1478 }
1479}
1480
1481static void hierarchy_insert_output_entry(struct rb_root *root,
1482 struct hist_entry *he)
1483{
1484 struct rb_node **p = &root->rb_node;
1485 struct rb_node *parent = NULL;
1486 struct hist_entry *iter;
1487 struct perf_hpp_fmt *fmt;
1488
1489 while (*p != NULL) {
1490 parent = *p;
1491 iter = rb_entry(parent, struct hist_entry, rb_node);
1492
1493 if (hist_entry__sort(he, iter) > 0)
1494 p = &parent->rb_left;
1495 else
1496 p = &parent->rb_right;
1497 }
1498
1499 rb_link_node(&he->rb_node, parent, p);
1500 rb_insert_color(&he->rb_node, root);
1501
1502 /* update column width of dynamic entry */
1503 perf_hpp_list__for_each_sort_list(he->hpp_list, fmt) {
1504 if (perf_hpp__is_dynamic_entry(fmt))
1505 fmt->sort(fmt, he, NULL);
1506 }
1507}
1508
1509static void hists__hierarchy_output_resort(struct hists *hists,
1510 struct ui_progress *prog,
1511 struct rb_root *root_in,
1512 struct rb_root *root_out,
1513 u64 min_callchain_hits,
1514 bool use_callchain)
1515{
1516 struct rb_node *node;
1517 struct hist_entry *he;
1518
1519 *root_out = RB_ROOT;
1520 node = rb_first(root_in);
1521
1522 while (node) {
1523 he = rb_entry(node, struct hist_entry, rb_node_in);
1524 node = rb_next(node);
1525
1526 hierarchy_insert_output_entry(root_out, he);
1527
1528 if (prog)
1529 ui_progress__update(prog, 1);
1530
1531 if (!he->leaf) {
1532 hists__hierarchy_output_resort(hists, prog,
1533 &he->hroot_in,
1534 &he->hroot_out,
1535 min_callchain_hits,
1536 use_callchain);
1537 hists->nr_entries++;
1538 if (!he->filtered) {
1539 hists->nr_non_filtered_entries++;
1540 hists__calc_col_len(hists, he);
1541 }
1542
1543 continue;
1544 }
1545
1546 if (!use_callchain)
1547 continue;
1548
1549 if (callchain_param.mode == CHAIN_GRAPH_REL) {
1550 u64 total = he->stat.period;
1551
1552 if (symbol_conf.cumulate_callchain)
1553 total = he->stat_acc->period;
1554
1555 min_callchain_hits = total * (callchain_param.min_percent / 100);
1556 }
1557
1558 callchain_param.sort(&he->sorted_chain, he->callchain,
1559 min_callchain_hits, &callchain_param);
1560 }
1561}
1562
1157static void __hists__insert_output_entry(struct rb_root *entries, 1563static void __hists__insert_output_entry(struct rb_root *entries,
1158 struct hist_entry *he, 1564 struct hist_entry *he,
1159 u64 min_callchain_hits, 1565 u64 min_callchain_hits,
@@ -1162,10 +1568,20 @@ static void __hists__insert_output_entry(struct rb_root *entries,
1162 struct rb_node **p = &entries->rb_node; 1568 struct rb_node **p = &entries->rb_node;
1163 struct rb_node *parent = NULL; 1569 struct rb_node *parent = NULL;
1164 struct hist_entry *iter; 1570 struct hist_entry *iter;
1571 struct perf_hpp_fmt *fmt;
1572
1573 if (use_callchain) {
1574 if (callchain_param.mode == CHAIN_GRAPH_REL) {
1575 u64 total = he->stat.period;
1576
1577 if (symbol_conf.cumulate_callchain)
1578 total = he->stat_acc->period;
1165 1579
1166 if (use_callchain) 1580 min_callchain_hits = total * (callchain_param.min_percent / 100);
1581 }
1167 callchain_param.sort(&he->sorted_chain, he->callchain, 1582 callchain_param.sort(&he->sorted_chain, he->callchain,
1168 min_callchain_hits, &callchain_param); 1583 min_callchain_hits, &callchain_param);
1584 }
1169 1585
1170 while (*p != NULL) { 1586 while (*p != NULL) {
1171 parent = *p; 1587 parent = *p;
@@ -1179,23 +1595,41 @@ static void __hists__insert_output_entry(struct rb_root *entries,
1179 1595
1180 rb_link_node(&he->rb_node, parent, p); 1596 rb_link_node(&he->rb_node, parent, p);
1181 rb_insert_color(&he->rb_node, entries); 1597 rb_insert_color(&he->rb_node, entries);
1598
1599 perf_hpp_list__for_each_sort_list(&perf_hpp_list, fmt) {
1600 if (perf_hpp__is_dynamic_entry(fmt) &&
1601 perf_hpp__defined_dynamic_entry(fmt, he->hists))
1602 fmt->sort(fmt, he, NULL); /* update column width */
1603 }
1182} 1604}
1183 1605
1184void hists__output_resort(struct hists *hists, struct ui_progress *prog) 1606static void output_resort(struct hists *hists, struct ui_progress *prog,
1607 bool use_callchain)
1185{ 1608{
1186 struct rb_root *root; 1609 struct rb_root *root;
1187 struct rb_node *next; 1610 struct rb_node *next;
1188 struct hist_entry *n; 1611 struct hist_entry *n;
1612 u64 callchain_total;
1189 u64 min_callchain_hits; 1613 u64 min_callchain_hits;
1190 struct perf_evsel *evsel = hists_to_evsel(hists);
1191 bool use_callchain;
1192 1614
1193 if (evsel && symbol_conf.use_callchain && !symbol_conf.show_ref_callgraph) 1615 callchain_total = hists->callchain_period;
1194 use_callchain = evsel->attr.sample_type & PERF_SAMPLE_CALLCHAIN; 1616 if (symbol_conf.filter_relative)
1195 else 1617 callchain_total = hists->callchain_non_filtered_period;
1196 use_callchain = symbol_conf.use_callchain;
1197 1618
1198 min_callchain_hits = hists->stats.total_period * (callchain_param.min_percent / 100); 1619 min_callchain_hits = callchain_total * (callchain_param.min_percent / 100);
1620
1621 hists__reset_stats(hists);
1622 hists__reset_col_len(hists);
1623
1624 if (symbol_conf.report_hierarchy) {
1625 hists__hierarchy_output_resort(hists, prog,
1626 &hists->entries_collapsed,
1627 &hists->entries,
1628 min_callchain_hits,
1629 use_callchain);
1630 hierarchy_recalc_total_periods(hists);
1631 return;
1632 }
1199 1633
1200 if (sort__need_collapse) 1634 if (sort__need_collapse)
1201 root = &hists->entries_collapsed; 1635 root = &hists->entries_collapsed;
@@ -1205,9 +1639,6 @@ void hists__output_resort(struct hists *hists, struct ui_progress *prog)
1205 next = rb_first(root); 1639 next = rb_first(root);
1206 hists->entries = RB_ROOT; 1640 hists->entries = RB_ROOT;
1207 1641
1208 hists__reset_stats(hists);
1209 hists__reset_col_len(hists);
1210
1211 while (next) { 1642 while (next) {
1212 n = rb_entry(next, struct hist_entry, rb_node_in); 1643 n = rb_entry(next, struct hist_entry, rb_node_in);
1213 next = rb_next(&n->rb_node_in); 1644 next = rb_next(&n->rb_node_in);
@@ -1223,15 +1654,136 @@ void hists__output_resort(struct hists *hists, struct ui_progress *prog)
1223 } 1654 }
1224} 1655}
1225 1656
1657void perf_evsel__output_resort(struct perf_evsel *evsel, struct ui_progress *prog)
1658{
1659 bool use_callchain;
1660
1661 if (evsel && symbol_conf.use_callchain && !symbol_conf.show_ref_callgraph)
1662 use_callchain = evsel->attr.sample_type & PERF_SAMPLE_CALLCHAIN;
1663 else
1664 use_callchain = symbol_conf.use_callchain;
1665
1666 output_resort(evsel__hists(evsel), prog, use_callchain);
1667}
1668
1669void hists__output_resort(struct hists *hists, struct ui_progress *prog)
1670{
1671 output_resort(hists, prog, symbol_conf.use_callchain);
1672}
1673
1674static bool can_goto_child(struct hist_entry *he, enum hierarchy_move_dir hmd)
1675{
1676 if (he->leaf || hmd == HMD_FORCE_SIBLING)
1677 return false;
1678
1679 if (he->unfolded || hmd == HMD_FORCE_CHILD)
1680 return true;
1681
1682 return false;
1683}
1684
1685struct rb_node *rb_hierarchy_last(struct rb_node *node)
1686{
1687 struct hist_entry *he = rb_entry(node, struct hist_entry, rb_node);
1688
1689 while (can_goto_child(he, HMD_NORMAL)) {
1690 node = rb_last(&he->hroot_out);
1691 he = rb_entry(node, struct hist_entry, rb_node);
1692 }
1693 return node;
1694}
1695
1696struct rb_node *__rb_hierarchy_next(struct rb_node *node, enum hierarchy_move_dir hmd)
1697{
1698 struct hist_entry *he = rb_entry(node, struct hist_entry, rb_node);
1699
1700 if (can_goto_child(he, hmd))
1701 node = rb_first(&he->hroot_out);
1702 else
1703 node = rb_next(node);
1704
1705 while (node == NULL) {
1706 he = he->parent_he;
1707 if (he == NULL)
1708 break;
1709
1710 node = rb_next(&he->rb_node);
1711 }
1712 return node;
1713}
1714
1715struct rb_node *rb_hierarchy_prev(struct rb_node *node)
1716{
1717 struct hist_entry *he = rb_entry(node, struct hist_entry, rb_node);
1718
1719 node = rb_prev(node);
1720 if (node)
1721 return rb_hierarchy_last(node);
1722
1723 he = he->parent_he;
1724 if (he == NULL)
1725 return NULL;
1726
1727 return &he->rb_node;
1728}
1729
1730bool hist_entry__has_hierarchy_children(struct hist_entry *he, float limit)
1731{
1732 struct rb_node *node;
1733 struct hist_entry *child;
1734 float percent;
1735
1736 if (he->leaf)
1737 return false;
1738
1739 node = rb_first(&he->hroot_out);
1740 child = rb_entry(node, struct hist_entry, rb_node);
1741
1742 while (node && child->filtered) {
1743 node = rb_next(node);
1744 child = rb_entry(node, struct hist_entry, rb_node);
1745 }
1746
1747 if (node)
1748 percent = hist_entry__get_percent_limit(child);
1749 else
1750 percent = 0;
1751
1752 return node && percent >= limit;
1753}
1754
1226static void hists__remove_entry_filter(struct hists *hists, struct hist_entry *h, 1755static void hists__remove_entry_filter(struct hists *hists, struct hist_entry *h,
1227 enum hist_filter filter) 1756 enum hist_filter filter)
1228{ 1757{
1229 h->filtered &= ~(1 << filter); 1758 h->filtered &= ~(1 << filter);
1759
1760 if (symbol_conf.report_hierarchy) {
1761 struct hist_entry *parent = h->parent_he;
1762
1763 while (parent) {
1764 he_stat__add_stat(&parent->stat, &h->stat);
1765
1766 parent->filtered &= ~(1 << filter);
1767
1768 if (parent->filtered)
1769 goto next;
1770
1771 /* force fold unfiltered entry for simplicity */
1772 parent->unfolded = false;
1773 parent->has_no_entry = false;
1774 parent->row_offset = 0;
1775 parent->nr_rows = 0;
1776next:
1777 parent = parent->parent_he;
1778 }
1779 }
1780
1230 if (h->filtered) 1781 if (h->filtered)
1231 return; 1782 return;
1232 1783
1233 /* force fold unfiltered entry for simplicity */ 1784 /* force fold unfiltered entry for simplicity */
1234 h->unfolded = false; 1785 h->unfolded = false;
1786 h->has_no_entry = false;
1235 h->row_offset = 0; 1787 h->row_offset = 0;
1236 h->nr_rows = 0; 1788 h->nr_rows = 0;
1237 1789
@@ -1254,28 +1806,6 @@ static bool hists__filter_entry_by_dso(struct hists *hists,
1254 return false; 1806 return false;
1255} 1807}
1256 1808
1257void hists__filter_by_dso(struct hists *hists)
1258{
1259 struct rb_node *nd;
1260
1261 hists->stats.nr_non_filtered_samples = 0;
1262
1263 hists__reset_filter_stats(hists);
1264 hists__reset_col_len(hists);
1265
1266 for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) {
1267 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
1268
1269 if (symbol_conf.exclude_other && !h->parent)
1270 continue;
1271
1272 if (hists__filter_entry_by_dso(hists, h))
1273 continue;
1274
1275 hists__remove_entry_filter(hists, h, HIST_FILTER__DSO);
1276 }
1277}
1278
1279static bool hists__filter_entry_by_thread(struct hists *hists, 1809static bool hists__filter_entry_by_thread(struct hists *hists,
1280 struct hist_entry *he) 1810 struct hist_entry *he)
1281{ 1811{
@@ -1288,25 +1818,6 @@ static bool hists__filter_entry_by_thread(struct hists *hists,
1288 return false; 1818 return false;
1289} 1819}
1290 1820
1291void hists__filter_by_thread(struct hists *hists)
1292{
1293 struct rb_node *nd;
1294
1295 hists->stats.nr_non_filtered_samples = 0;
1296
1297 hists__reset_filter_stats(hists);
1298 hists__reset_col_len(hists);
1299
1300 for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) {
1301 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
1302
1303 if (hists__filter_entry_by_thread(hists, h))
1304 continue;
1305
1306 hists__remove_entry_filter(hists, h, HIST_FILTER__THREAD);
1307 }
1308}
1309
1310static bool hists__filter_entry_by_symbol(struct hists *hists, 1821static bool hists__filter_entry_by_symbol(struct hists *hists,
1311 struct hist_entry *he) 1822 struct hist_entry *he)
1312{ 1823{
@@ -1320,7 +1831,21 @@ static bool hists__filter_entry_by_symbol(struct hists *hists,
1320 return false; 1831 return false;
1321} 1832}
1322 1833
1323void hists__filter_by_symbol(struct hists *hists) 1834static bool hists__filter_entry_by_socket(struct hists *hists,
1835 struct hist_entry *he)
1836{
1837 if ((hists->socket_filter > -1) &&
1838 (he->socket != hists->socket_filter)) {
1839 he->filtered |= (1 << HIST_FILTER__SOCKET);
1840 return true;
1841 }
1842
1843 return false;
1844}
1845
1846typedef bool (*filter_fn_t)(struct hists *hists, struct hist_entry *he);
1847
1848static void hists__filter_by_type(struct hists *hists, int type, filter_fn_t filter)
1324{ 1849{
1325 struct rb_node *nd; 1850 struct rb_node *nd;
1326 1851
@@ -1332,42 +1857,155 @@ void hists__filter_by_symbol(struct hists *hists)
1332 for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) { 1857 for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) {
1333 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); 1858 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
1334 1859
1335 if (hists__filter_entry_by_symbol(hists, h)) 1860 if (filter(hists, h))
1336 continue; 1861 continue;
1337 1862
1338 hists__remove_entry_filter(hists, h, HIST_FILTER__SYMBOL); 1863 hists__remove_entry_filter(hists, h, type);
1339 } 1864 }
1340} 1865}
1341 1866
1342static bool hists__filter_entry_by_socket(struct hists *hists, 1867static void resort_filtered_entry(struct rb_root *root, struct hist_entry *he)
1343 struct hist_entry *he)
1344{ 1868{
1345 if ((hists->socket_filter > -1) && 1869 struct rb_node **p = &root->rb_node;
1346 (he->socket != hists->socket_filter)) { 1870 struct rb_node *parent = NULL;
1347 he->filtered |= (1 << HIST_FILTER__SOCKET); 1871 struct hist_entry *iter;
1348 return true; 1872 struct rb_root new_root = RB_ROOT;
1873 struct rb_node *nd;
1874
1875 while (*p != NULL) {
1876 parent = *p;
1877 iter = rb_entry(parent, struct hist_entry, rb_node);
1878
1879 if (hist_entry__sort(he, iter) > 0)
1880 p = &(*p)->rb_left;
1881 else
1882 p = &(*p)->rb_right;
1349 } 1883 }
1350 1884
1351 return false; 1885 rb_link_node(&he->rb_node, parent, p);
1886 rb_insert_color(&he->rb_node, root);
1887
1888 if (he->leaf || he->filtered)
1889 return;
1890
1891 nd = rb_first(&he->hroot_out);
1892 while (nd) {
1893 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
1894
1895 nd = rb_next(nd);
1896 rb_erase(&h->rb_node, &he->hroot_out);
1897
1898 resort_filtered_entry(&new_root, h);
1899 }
1900
1901 he->hroot_out = new_root;
1352} 1902}
1353 1903
1354void hists__filter_by_socket(struct hists *hists) 1904static void hists__filter_hierarchy(struct hists *hists, int type, const void *arg)
1355{ 1905{
1356 struct rb_node *nd; 1906 struct rb_node *nd;
1907 struct rb_root new_root = RB_ROOT;
1357 1908
1358 hists->stats.nr_non_filtered_samples = 0; 1909 hists->stats.nr_non_filtered_samples = 0;
1359 1910
1360 hists__reset_filter_stats(hists); 1911 hists__reset_filter_stats(hists);
1361 hists__reset_col_len(hists); 1912 hists__reset_col_len(hists);
1362 1913
1363 for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) { 1914 nd = rb_first(&hists->entries);
1915 while (nd) {
1364 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); 1916 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
1917 int ret;
1365 1918
1366 if (hists__filter_entry_by_socket(hists, h)) 1919 ret = hist_entry__filter(h, type, arg);
1367 continue;
1368 1920
1369 hists__remove_entry_filter(hists, h, HIST_FILTER__SOCKET); 1921 /*
1922 * case 1. non-matching type
1923 * zero out the period, set filter marker and move to child
1924 */
1925 if (ret < 0) {
1926 memset(&h->stat, 0, sizeof(h->stat));
1927 h->filtered |= (1 << type);
1928
1929 nd = __rb_hierarchy_next(&h->rb_node, HMD_FORCE_CHILD);
1930 }
1931 /*
1932 * case 2. matched type (filter out)
1933 * set filter marker and move to next
1934 */
1935 else if (ret == 1) {
1936 h->filtered |= (1 << type);
1937
1938 nd = __rb_hierarchy_next(&h->rb_node, HMD_FORCE_SIBLING);
1939 }
1940 /*
1941 * case 3. ok (not filtered)
1942 * add period to hists and parents, erase the filter marker
1943 * and move to next sibling
1944 */
1945 else {
1946 hists__remove_entry_filter(hists, h, type);
1947
1948 nd = __rb_hierarchy_next(&h->rb_node, HMD_FORCE_SIBLING);
1949 }
1950 }
1951
1952 hierarchy_recalc_total_periods(hists);
1953
1954 /*
1955 * resort output after applying a new filter since filter in a lower
1956 * hierarchy can change periods in a upper hierarchy.
1957 */
1958 nd = rb_first(&hists->entries);
1959 while (nd) {
1960 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
1961
1962 nd = rb_next(nd);
1963 rb_erase(&h->rb_node, &hists->entries);
1964
1965 resort_filtered_entry(&new_root, h);
1370 } 1966 }
1967
1968 hists->entries = new_root;
1969}
1970
1971void hists__filter_by_thread(struct hists *hists)
1972{
1973 if (symbol_conf.report_hierarchy)
1974 hists__filter_hierarchy(hists, HIST_FILTER__THREAD,
1975 hists->thread_filter);
1976 else
1977 hists__filter_by_type(hists, HIST_FILTER__THREAD,
1978 hists__filter_entry_by_thread);
1979}
1980
1981void hists__filter_by_dso(struct hists *hists)
1982{
1983 if (symbol_conf.report_hierarchy)
1984 hists__filter_hierarchy(hists, HIST_FILTER__DSO,
1985 hists->dso_filter);
1986 else
1987 hists__filter_by_type(hists, HIST_FILTER__DSO,
1988 hists__filter_entry_by_dso);
1989}
1990
1991void hists__filter_by_symbol(struct hists *hists)
1992{
1993 if (symbol_conf.report_hierarchy)
1994 hists__filter_hierarchy(hists, HIST_FILTER__SYMBOL,
1995 hists->symbol_filter_str);
1996 else
1997 hists__filter_by_type(hists, HIST_FILTER__SYMBOL,
1998 hists__filter_entry_by_symbol);
1999}
2000
2001void hists__filter_by_socket(struct hists *hists)
2002{
2003 if (symbol_conf.report_hierarchy)
2004 hists__filter_hierarchy(hists, HIST_FILTER__SOCKET,
2005 &hists->socket_filter);
2006 else
2007 hists__filter_by_type(hists, HIST_FILTER__SOCKET,
2008 hists__filter_entry_by_socket);
1371} 2009}
1372 2010
1373void events_stats__inc(struct events_stats *stats, u32 type) 2011void events_stats__inc(struct events_stats *stats, u32 type)
@@ -1585,7 +2223,7 @@ int perf_hist_config(const char *var, const char *value)
1585 return 0; 2223 return 0;
1586} 2224}
1587 2225
1588int __hists__init(struct hists *hists) 2226int __hists__init(struct hists *hists, struct perf_hpp_list *hpp_list)
1589{ 2227{
1590 memset(hists, 0, sizeof(*hists)); 2228 memset(hists, 0, sizeof(*hists));
1591 hists->entries_in_array[0] = hists->entries_in_array[1] = RB_ROOT; 2229 hists->entries_in_array[0] = hists->entries_in_array[1] = RB_ROOT;
@@ -1594,6 +2232,8 @@ int __hists__init(struct hists *hists)
1594 hists->entries = RB_ROOT; 2232 hists->entries = RB_ROOT;
1595 pthread_mutex_init(&hists->lock, NULL); 2233 pthread_mutex_init(&hists->lock, NULL);
1596 hists->socket_filter = -1; 2234 hists->socket_filter = -1;
2235 hists->hpp_list = hpp_list;
2236 INIT_LIST_HEAD(&hists->hpp_formats);
1597 return 0; 2237 return 0;
1598} 2238}
1599 2239
@@ -1622,15 +2262,26 @@ static void hists__delete_all_entries(struct hists *hists)
1622static void hists_evsel__exit(struct perf_evsel *evsel) 2262static void hists_evsel__exit(struct perf_evsel *evsel)
1623{ 2263{
1624 struct hists *hists = evsel__hists(evsel); 2264 struct hists *hists = evsel__hists(evsel);
2265 struct perf_hpp_fmt *fmt, *pos;
2266 struct perf_hpp_list_node *node, *tmp;
1625 2267
1626 hists__delete_all_entries(hists); 2268 hists__delete_all_entries(hists);
2269
2270 list_for_each_entry_safe(node, tmp, &hists->hpp_formats, list) {
2271 perf_hpp_list__for_each_format_safe(&node->hpp, fmt, pos) {
2272 list_del(&fmt->list);
2273 free(fmt);
2274 }
2275 list_del(&node->list);
2276 free(node);
2277 }
1627} 2278}
1628 2279
1629static int hists_evsel__init(struct perf_evsel *evsel) 2280static int hists_evsel__init(struct perf_evsel *evsel)
1630{ 2281{
1631 struct hists *hists = evsel__hists(evsel); 2282 struct hists *hists = evsel__hists(evsel);
1632 2283
1633 __hists__init(hists); 2284 __hists__init(hists, &perf_hpp_list);
1634 return 0; 2285 return 0;
1635} 2286}
1636 2287
@@ -1649,3 +2300,9 @@ int hists__init(void)
1649 2300
1650 return err; 2301 return err;
1651} 2302}
2303
2304void perf_hpp_list__init(struct perf_hpp_list *list)
2305{
2306 INIT_LIST_HEAD(&list->fields);
2307 INIT_LIST_HEAD(&list->sorts);
2308}
diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h
index d4ec4822a103..bec0cd660fbd 100644
--- a/tools/perf/util/hist.h
+++ b/tools/perf/util/hist.h
@@ -66,6 +66,8 @@ struct hists {
66 struct rb_root entries_collapsed; 66 struct rb_root entries_collapsed;
67 u64 nr_entries; 67 u64 nr_entries;
68 u64 nr_non_filtered_entries; 68 u64 nr_non_filtered_entries;
69 u64 callchain_period;
70 u64 callchain_non_filtered_period;
69 struct thread *thread_filter; 71 struct thread *thread_filter;
70 const struct dso *dso_filter; 72 const struct dso *dso_filter;
71 const char *uid_filter_str; 73 const char *uid_filter_str;
@@ -75,6 +77,9 @@ struct hists {
75 u64 event_stream; 77 u64 event_stream;
76 u16 col_len[HISTC_NR_COLS]; 78 u16 col_len[HISTC_NR_COLS];
77 int socket_filter; 79 int socket_filter;
80 struct perf_hpp_list *hpp_list;
81 struct list_head hpp_formats;
82 int nr_hpp_node;
78}; 83};
79 84
80struct hist_entry_iter; 85struct hist_entry_iter;
@@ -121,15 +126,21 @@ struct hist_entry *__hists__add_entry(struct hists *hists,
121int hist_entry_iter__add(struct hist_entry_iter *iter, struct addr_location *al, 126int hist_entry_iter__add(struct hist_entry_iter *iter, struct addr_location *al,
122 int max_stack_depth, void *arg); 127 int max_stack_depth, void *arg);
123 128
129struct perf_hpp;
130struct perf_hpp_fmt;
131
124int64_t hist_entry__cmp(struct hist_entry *left, struct hist_entry *right); 132int64_t hist_entry__cmp(struct hist_entry *left, struct hist_entry *right);
125int64_t hist_entry__collapse(struct hist_entry *left, struct hist_entry *right); 133int64_t hist_entry__collapse(struct hist_entry *left, struct hist_entry *right);
126int hist_entry__transaction_len(void); 134int hist_entry__transaction_len(void);
127int hist_entry__sort_snprintf(struct hist_entry *he, char *bf, size_t size, 135int hist_entry__sort_snprintf(struct hist_entry *he, char *bf, size_t size,
128 struct hists *hists); 136 struct hists *hists);
137int hist_entry__snprintf_alignment(struct hist_entry *he, struct perf_hpp *hpp,
138 struct perf_hpp_fmt *fmt, int printed);
129void hist_entry__delete(struct hist_entry *he); 139void hist_entry__delete(struct hist_entry *he);
130 140
141void perf_evsel__output_resort(struct perf_evsel *evsel, struct ui_progress *prog);
131void hists__output_resort(struct hists *hists, struct ui_progress *prog); 142void hists__output_resort(struct hists *hists, struct ui_progress *prog);
132void hists__collapse_resort(struct hists *hists, struct ui_progress *prog); 143int hists__collapse_resort(struct hists *hists, struct ui_progress *prog);
133 144
134void hists__decay_entries(struct hists *hists, bool zap_user, bool zap_kernel); 145void hists__decay_entries(struct hists *hists, bool zap_user, bool zap_kernel);
135void hists__delete_entries(struct hists *hists); 146void hists__delete_entries(struct hists *hists);
@@ -185,10 +196,10 @@ static inline struct hists *evsel__hists(struct perf_evsel *evsel)
185} 196}
186 197
187int hists__init(void); 198int hists__init(void);
188int __hists__init(struct hists *hists); 199int __hists__init(struct hists *hists, struct perf_hpp_list *hpp_list);
189 200
190struct rb_root *hists__get_rotate_entries_in(struct hists *hists); 201struct rb_root *hists__get_rotate_entries_in(struct hists *hists);
191bool hists__collapse_insert_entry(struct hists *hists __maybe_unused, 202int hists__collapse_insert_entry(struct hists *hists,
192 struct rb_root *root, struct hist_entry *he); 203 struct rb_root *root, struct hist_entry *he);
193 204
194struct perf_hpp { 205struct perf_hpp {
@@ -214,28 +225,64 @@ struct perf_hpp_fmt {
214 struct hist_entry *a, struct hist_entry *b); 225 struct hist_entry *a, struct hist_entry *b);
215 int64_t (*sort)(struct perf_hpp_fmt *fmt, 226 int64_t (*sort)(struct perf_hpp_fmt *fmt,
216 struct hist_entry *a, struct hist_entry *b); 227 struct hist_entry *a, struct hist_entry *b);
228 bool (*equal)(struct perf_hpp_fmt *a, struct perf_hpp_fmt *b);
229 void (*free)(struct perf_hpp_fmt *fmt);
217 230
218 struct list_head list; 231 struct list_head list;
219 struct list_head sort_list; 232 struct list_head sort_list;
220 bool elide; 233 bool elide;
221 int len; 234 int len;
222 int user_len; 235 int user_len;
236 int idx;
237 int level;
238};
239
240struct perf_hpp_list {
241 struct list_head fields;
242 struct list_head sorts;
223}; 243};
224 244
225extern struct list_head perf_hpp__list; 245extern struct perf_hpp_list perf_hpp_list;
226extern struct list_head perf_hpp__sort_list; 246
247struct perf_hpp_list_node {
248 struct list_head list;
249 struct perf_hpp_list hpp;
250 int level;
251 bool skip;
252};
253
254void perf_hpp_list__column_register(struct perf_hpp_list *list,
255 struct perf_hpp_fmt *format);
256void perf_hpp_list__register_sort_field(struct perf_hpp_list *list,
257 struct perf_hpp_fmt *format);
258
259static inline void perf_hpp__column_register(struct perf_hpp_fmt *format)
260{
261 perf_hpp_list__column_register(&perf_hpp_list, format);
262}
263
264static inline void perf_hpp__register_sort_field(struct perf_hpp_fmt *format)
265{
266 perf_hpp_list__register_sort_field(&perf_hpp_list, format);
267}
268
269#define perf_hpp_list__for_each_format(_list, format) \
270 list_for_each_entry(format, &(_list)->fields, list)
227 271
228#define perf_hpp__for_each_format(format) \ 272#define perf_hpp_list__for_each_format_safe(_list, format, tmp) \
229 list_for_each_entry(format, &perf_hpp__list, list) 273 list_for_each_entry_safe(format, tmp, &(_list)->fields, list)
230 274
231#define perf_hpp__for_each_format_safe(format, tmp) \ 275#define perf_hpp_list__for_each_sort_list(_list, format) \
232 list_for_each_entry_safe(format, tmp, &perf_hpp__list, list) 276 list_for_each_entry(format, &(_list)->sorts, sort_list)
233 277
234#define perf_hpp__for_each_sort_list(format) \ 278#define perf_hpp_list__for_each_sort_list_safe(_list, format, tmp) \
235 list_for_each_entry(format, &perf_hpp__sort_list, sort_list) 279 list_for_each_entry_safe(format, tmp, &(_list)->sorts, sort_list)
236 280
237#define perf_hpp__for_each_sort_list_safe(format, tmp) \ 281#define hists__for_each_format(hists, format) \
238 list_for_each_entry_safe(format, tmp, &perf_hpp__sort_list, sort_list) 282 perf_hpp_list__for_each_format((hists)->hpp_list, fmt)
283
284#define hists__for_each_sort_list(hists, format) \
285 perf_hpp_list__for_each_sort_list((hists)->hpp_list, fmt)
239 286
240extern struct perf_hpp_fmt perf_hpp__format[]; 287extern struct perf_hpp_fmt perf_hpp__format[];
241 288
@@ -254,21 +301,29 @@ enum {
254}; 301};
255 302
256void perf_hpp__init(void); 303void perf_hpp__init(void);
257void perf_hpp__column_register(struct perf_hpp_fmt *format);
258void perf_hpp__column_unregister(struct perf_hpp_fmt *format); 304void perf_hpp__column_unregister(struct perf_hpp_fmt *format);
259void perf_hpp__column_enable(unsigned col);
260void perf_hpp__column_disable(unsigned col);
261void perf_hpp__cancel_cumulate(void); 305void perf_hpp__cancel_cumulate(void);
306void perf_hpp__setup_output_field(struct perf_hpp_list *list);
307void perf_hpp__reset_output_field(struct perf_hpp_list *list);
308void perf_hpp__append_sort_keys(struct perf_hpp_list *list);
309int perf_hpp__setup_hists_formats(struct perf_hpp_list *list,
310 struct perf_evlist *evlist);
262 311
263void perf_hpp__register_sort_field(struct perf_hpp_fmt *format);
264void perf_hpp__setup_output_field(void);
265void perf_hpp__reset_output_field(void);
266void perf_hpp__append_sort_keys(void);
267 312
268bool perf_hpp__is_sort_entry(struct perf_hpp_fmt *format); 313bool perf_hpp__is_sort_entry(struct perf_hpp_fmt *format);
269bool perf_hpp__same_sort_entry(struct perf_hpp_fmt *a, struct perf_hpp_fmt *b);
270bool perf_hpp__is_dynamic_entry(struct perf_hpp_fmt *format); 314bool perf_hpp__is_dynamic_entry(struct perf_hpp_fmt *format);
271bool perf_hpp__defined_dynamic_entry(struct perf_hpp_fmt *fmt, struct hists *hists); 315bool perf_hpp__defined_dynamic_entry(struct perf_hpp_fmt *fmt, struct hists *hists);
316bool perf_hpp__is_trace_entry(struct perf_hpp_fmt *fmt);
317bool perf_hpp__is_srcline_entry(struct perf_hpp_fmt *fmt);
318bool perf_hpp__is_srcfile_entry(struct perf_hpp_fmt *fmt);
319bool perf_hpp__is_thread_entry(struct perf_hpp_fmt *fmt);
320bool perf_hpp__is_comm_entry(struct perf_hpp_fmt *fmt);
321bool perf_hpp__is_dso_entry(struct perf_hpp_fmt *fmt);
322bool perf_hpp__is_sym_entry(struct perf_hpp_fmt *fmt);
323
324struct perf_hpp_fmt *perf_hpp_fmt__dup(struct perf_hpp_fmt *fmt);
325
326int hist_entry__filter(struct hist_entry *he, int type, const void *arg);
272 327
273static inline bool perf_hpp__should_skip(struct perf_hpp_fmt *format, 328static inline bool perf_hpp__should_skip(struct perf_hpp_fmt *format,
274 struct hists *hists) 329 struct hists *hists)
@@ -372,13 +427,35 @@ static inline int script_browse(const char *script_opt __maybe_unused)
372#endif 427#endif
373 428
374unsigned int hists__sort_list_width(struct hists *hists); 429unsigned int hists__sort_list_width(struct hists *hists);
430unsigned int hists__overhead_width(struct hists *hists);
375 431
376void hist__account_cycles(struct branch_stack *bs, struct addr_location *al, 432void hist__account_cycles(struct branch_stack *bs, struct addr_location *al,
377 struct perf_sample *sample, bool nonany_branch_mode); 433 struct perf_sample *sample, bool nonany_branch_mode);
378 434
379struct option; 435struct option;
380int parse_filter_percentage(const struct option *opt __maybe_unused, 436int parse_filter_percentage(const struct option *opt, const char *arg, int unset);
381 const char *arg, int unset __maybe_unused);
382int perf_hist_config(const char *var, const char *value); 437int perf_hist_config(const char *var, const char *value);
383 438
439void perf_hpp_list__init(struct perf_hpp_list *list);
440
441enum hierarchy_move_dir {
442 HMD_NORMAL,
443 HMD_FORCE_SIBLING,
444 HMD_FORCE_CHILD,
445};
446
447struct rb_node *rb_hierarchy_last(struct rb_node *node);
448struct rb_node *__rb_hierarchy_next(struct rb_node *node,
449 enum hierarchy_move_dir hmd);
450struct rb_node *rb_hierarchy_prev(struct rb_node *node);
451
452static inline struct rb_node *rb_hierarchy_next(struct rb_node *node)
453{
454 return __rb_hierarchy_next(node, HMD_NORMAL);
455}
456
457#define HIERARCHY_INDENT 3
458
459bool hist_entry__has_hierarchy_children(struct hist_entry *he, float limit);
460
384#endif /* __PERF_HIST_H */ 461#endif /* __PERF_HIST_H */
diff --git a/tools/perf/util/intel-bts.c b/tools/perf/util/intel-bts.c
index eb0e7f8bf515..abf1366e2a24 100644
--- a/tools/perf/util/intel-bts.c
+++ b/tools/perf/util/intel-bts.c
@@ -279,6 +279,7 @@ static int intel_bts_synth_branch_sample(struct intel_bts_queue *btsq,
279 event.sample.header.misc = PERF_RECORD_MISC_USER; 279 event.sample.header.misc = PERF_RECORD_MISC_USER;
280 event.sample.header.size = sizeof(struct perf_event_header); 280 event.sample.header.size = sizeof(struct perf_event_header);
281 281
282 sample.cpumode = PERF_RECORD_MISC_USER;
282 sample.ip = le64_to_cpu(branch->from); 283 sample.ip = le64_to_cpu(branch->from);
283 sample.pid = btsq->pid; 284 sample.pid = btsq->pid;
284 sample.tid = btsq->tid; 285 sample.tid = btsq->tid;
@@ -678,7 +679,7 @@ static int intel_bts_process_auxtrace_event(struct perf_session *session,
678 return 0; 679 return 0;
679} 680}
680 681
681static int intel_bts_flush(struct perf_session *session __maybe_unused, 682static int intel_bts_flush(struct perf_session *session,
682 struct perf_tool *tool __maybe_unused) 683 struct perf_tool *tool __maybe_unused)
683{ 684{
684 struct intel_bts *bts = container_of(session->auxtrace, struct intel_bts, 685 struct intel_bts *bts = container_of(session->auxtrace, struct intel_bts,
diff --git a/tools/perf/util/intel-pt-decoder/insn.c b/tools/perf/util/intel-pt-decoder/insn.c
index 47314a64399c..9f26eae6c9f0 100644
--- a/tools/perf/util/intel-pt-decoder/insn.c
+++ b/tools/perf/util/intel-pt-decoder/insn.c
@@ -374,7 +374,7 @@ void insn_get_displacement(struct insn *insn)
374 if (mod == 3) 374 if (mod == 3)
375 goto out; 375 goto out;
376 if (mod == 1) { 376 if (mod == 1) {
377 insn->displacement.value = get_next(char, insn); 377 insn->displacement.value = get_next(signed char, insn);
378 insn->displacement.nbytes = 1; 378 insn->displacement.nbytes = 1;
379 } else if (insn->addr_bytes == 2) { 379 } else if (insn->addr_bytes == 2) {
380 if ((mod == 0 && rm == 6) || mod == 2) { 380 if ((mod == 0 && rm == 6) || mod == 2) {
@@ -532,7 +532,7 @@ void insn_get_immediate(struct insn *insn)
532 532
533 switch (inat_immediate_size(insn->attr)) { 533 switch (inat_immediate_size(insn->attr)) {
534 case INAT_IMM_BYTE: 534 case INAT_IMM_BYTE:
535 insn->immediate.value = get_next(char, insn); 535 insn->immediate.value = get_next(signed char, insn);
536 insn->immediate.nbytes = 1; 536 insn->immediate.nbytes = 1;
537 break; 537 break;
538 case INAT_IMM_WORD: 538 case INAT_IMM_WORD:
@@ -566,7 +566,7 @@ void insn_get_immediate(struct insn *insn)
566 goto err_out; 566 goto err_out;
567 } 567 }
568 if (inat_has_second_immediate(insn->attr)) { 568 if (inat_has_second_immediate(insn->attr)) {
569 insn->immediate2.value = get_next(char, insn); 569 insn->immediate2.value = get_next(signed char, insn);
570 insn->immediate2.nbytes = 1; 570 insn->immediate2.nbytes = 1;
571 } 571 }
572done: 572done:
diff --git a/tools/perf/util/intel-pt.c b/tools/perf/util/intel-pt.c
index 05d815851be1..407f11b97c8d 100644
--- a/tools/perf/util/intel-pt.c
+++ b/tools/perf/util/intel-pt.c
@@ -979,6 +979,7 @@ static int intel_pt_synth_branch_sample(struct intel_pt_queue *ptq)
979 if (!pt->timeless_decoding) 979 if (!pt->timeless_decoding)
980 sample.time = tsc_to_perf_time(ptq->timestamp, &pt->tc); 980 sample.time = tsc_to_perf_time(ptq->timestamp, &pt->tc);
981 981
982 sample.cpumode = PERF_RECORD_MISC_USER;
982 sample.ip = ptq->state->from_ip; 983 sample.ip = ptq->state->from_ip;
983 sample.pid = ptq->pid; 984 sample.pid = ptq->pid;
984 sample.tid = ptq->tid; 985 sample.tid = ptq->tid;
@@ -1035,6 +1036,7 @@ static int intel_pt_synth_instruction_sample(struct intel_pt_queue *ptq)
1035 if (!pt->timeless_decoding) 1036 if (!pt->timeless_decoding)
1036 sample.time = tsc_to_perf_time(ptq->timestamp, &pt->tc); 1037 sample.time = tsc_to_perf_time(ptq->timestamp, &pt->tc);
1037 1038
1039 sample.cpumode = PERF_RECORD_MISC_USER;
1038 sample.ip = ptq->state->from_ip; 1040 sample.ip = ptq->state->from_ip;
1039 sample.pid = ptq->pid; 1041 sample.pid = ptq->pid;
1040 sample.tid = ptq->tid; 1042 sample.tid = ptq->tid;
@@ -1092,6 +1094,7 @@ static int intel_pt_synth_transaction_sample(struct intel_pt_queue *ptq)
1092 if (!pt->timeless_decoding) 1094 if (!pt->timeless_decoding)
1093 sample.time = tsc_to_perf_time(ptq->timestamp, &pt->tc); 1095 sample.time = tsc_to_perf_time(ptq->timestamp, &pt->tc);
1094 1096
1097 sample.cpumode = PERF_RECORD_MISC_USER;
1095 sample.ip = ptq->state->from_ip; 1098 sample.ip = ptq->state->from_ip;
1096 sample.pid = ptq->pid; 1099 sample.pid = ptq->pid;
1097 sample.tid = ptq->tid; 1100 sample.tid = ptq->tid;
diff --git a/tools/perf/util/jit.h b/tools/perf/util/jit.h
new file mode 100644
index 000000000000..3f42ee4d2a0b
--- /dev/null
+++ b/tools/perf/util/jit.h
@@ -0,0 +1,11 @@
1#ifndef __JIT_H__
2#define __JIT_H__
3
4#include <data.h>
5
6int jit_process(struct perf_session *session, struct perf_data_file *output,
7 struct machine *machine, char *filename, pid_t pid, u64 *nbytes);
8
9int jit_inject_record(const char *filename);
10
11#endif /* __JIT_H__ */
diff --git a/tools/perf/util/jitdump.c b/tools/perf/util/jitdump.c
new file mode 100644
index 000000000000..ad0c0bb1fbc7
--- /dev/null
+++ b/tools/perf/util/jitdump.c
@@ -0,0 +1,699 @@
1#include <sys/types.h>
2#include <stdio.h>
3#include <stdlib.h>
4#include <string.h>
5#include <fcntl.h>
6#include <unistd.h>
7#include <inttypes.h>
8#include <byteswap.h>
9#include <sys/stat.h>
10#include <sys/mman.h>
11
12#include "util.h"
13#include "event.h"
14#include "debug.h"
15#include "evlist.h"
16#include "symbol.h"
17#include "strlist.h"
18#include <elf.h>
19
20#include "session.h"
21#include "jit.h"
22#include "jitdump.h"
23#include "genelf.h"
24#include "../builtin.h"
25
26struct jit_buf_desc {
27 struct perf_data_file *output;
28 struct perf_session *session;
29 struct machine *machine;
30 union jr_entry *entry;
31 void *buf;
32 uint64_t sample_type;
33 size_t bufsize;
34 FILE *in;
35 bool needs_bswap; /* handles cross-endianess */
36 void *debug_data;
37 size_t nr_debug_entries;
38 uint32_t code_load_count;
39 u64 bytes_written;
40 struct rb_root code_root;
41 char dir[PATH_MAX];
42};
43
44struct debug_line_info {
45 unsigned long vma;
46 unsigned int lineno;
47 /* The filename format is unspecified, absolute path, relative etc. */
48 char const filename[0];
49};
50
51struct jit_tool {
52 struct perf_tool tool;
53 struct perf_data_file output;
54 struct perf_data_file input;
55 u64 bytes_written;
56};
57
58#define hmax(a, b) ((a) > (b) ? (a) : (b))
59#define get_jit_tool(t) (container_of(tool, struct jit_tool, tool))
60
61static int
62jit_emit_elf(char *filename,
63 const char *sym,
64 uint64_t code_addr,
65 const void *code,
66 int csize,
67 void *debug,
68 int nr_debug_entries)
69{
70 int ret, fd;
71
72 if (verbose > 0)
73 fprintf(stderr, "write ELF image %s\n", filename);
74
75 fd = open(filename, O_CREAT|O_TRUNC|O_WRONLY, 0644);
76 if (fd == -1) {
77 pr_warning("cannot create jit ELF %s: %s\n", filename, strerror(errno));
78 return -1;
79 }
80
81 ret = jit_write_elf(fd, code_addr, sym, (const void *)code, csize, debug, nr_debug_entries);
82
83 close(fd);
84
85 if (ret)
86 unlink(filename);
87
88 return ret;
89}
90
91static void
92jit_close(struct jit_buf_desc *jd)
93{
94 if (!(jd && jd->in))
95 return;
96 funlockfile(jd->in);
97 fclose(jd->in);
98 jd->in = NULL;
99}
100
101static int
102jit_validate_events(struct perf_session *session)
103{
104 struct perf_evsel *evsel;
105
106 /*
107 * check that all events use CLOCK_MONOTONIC
108 */
109 evlist__for_each(session->evlist, evsel) {
110 if (evsel->attr.use_clockid == 0 || evsel->attr.clockid != CLOCK_MONOTONIC)
111 return -1;
112 }
113 return 0;
114}
115
116static int
117jit_open(struct jit_buf_desc *jd, const char *name)
118{
119 struct jitheader header;
120 struct jr_prefix *prefix;
121 ssize_t bs, bsz = 0;
122 void *n, *buf = NULL;
123 int ret, retval = -1;
124
125 jd->in = fopen(name, "r");
126 if (!jd->in)
127 return -1;
128
129 bsz = hmax(sizeof(header), sizeof(*prefix));
130
131 buf = malloc(bsz);
132 if (!buf)
133 goto error;
134
135 /*
136 * protect from writer modifying the file while we are reading it
137 */
138 flockfile(jd->in);
139
140 ret = fread(buf, sizeof(header), 1, jd->in);
141 if (ret != 1)
142 goto error;
143
144 memcpy(&header, buf, sizeof(header));
145
146 if (header.magic != JITHEADER_MAGIC) {
147 if (header.magic != JITHEADER_MAGIC_SW)
148 goto error;
149 jd->needs_bswap = true;
150 }
151
152 if (jd->needs_bswap) {
153 header.version = bswap_32(header.version);
154 header.total_size = bswap_32(header.total_size);
155 header.pid = bswap_32(header.pid);
156 header.elf_mach = bswap_32(header.elf_mach);
157 header.timestamp = bswap_64(header.timestamp);
158 header.flags = bswap_64(header.flags);
159 }
160
161 if (verbose > 2)
162 pr_debug("version=%u\nhdr.size=%u\nts=0x%llx\npid=%d\nelf_mach=%d\n",
163 header.version,
164 header.total_size,
165 (unsigned long long)header.timestamp,
166 header.pid,
167 header.elf_mach);
168
169 if (header.flags & JITDUMP_FLAGS_RESERVED) {
170 pr_err("jitdump file contains invalid or unsupported flags 0x%llx\n",
171 (unsigned long long)header.flags & JITDUMP_FLAGS_RESERVED);
172 goto error;
173 }
174
175 /*
176 * validate event is using the correct clockid
177 */
178 if (jit_validate_events(jd->session)) {
179 pr_err("error, jitted code must be sampled with perf record -k 1\n");
180 goto error;
181 }
182
183 bs = header.total_size - sizeof(header);
184
185 if (bs > bsz) {
186 n = realloc(buf, bs);
187 if (!n)
188 goto error;
189 bsz = bs;
190 buf = n;
191 /* read extra we do not know about */
192 ret = fread(buf, bs - bsz, 1, jd->in);
193 if (ret != 1)
194 goto error;
195 }
196 /*
197 * keep dirname for generating files and mmap records
198 */
199 strcpy(jd->dir, name);
200 dirname(jd->dir);
201
202 return 0;
203error:
204 funlockfile(jd->in);
205 fclose(jd->in);
206 return retval;
207}
208
209static union jr_entry *
210jit_get_next_entry(struct jit_buf_desc *jd)
211{
212 struct jr_prefix *prefix;
213 union jr_entry *jr;
214 void *addr;
215 size_t bs, size;
216 int id, ret;
217
218 if (!(jd && jd->in))
219 return NULL;
220
221 if (jd->buf == NULL) {
222 size_t sz = getpagesize();
223 if (sz < sizeof(*prefix))
224 sz = sizeof(*prefix);
225
226 jd->buf = malloc(sz);
227 if (jd->buf == NULL)
228 return NULL;
229
230 jd->bufsize = sz;
231 }
232
233 prefix = jd->buf;
234
235 /*
236 * file is still locked at this point
237 */
238 ret = fread(prefix, sizeof(*prefix), 1, jd->in);
239 if (ret != 1)
240 return NULL;
241
242 if (jd->needs_bswap) {
243 prefix->id = bswap_32(prefix->id);
244 prefix->total_size = bswap_32(prefix->total_size);
245 prefix->timestamp = bswap_64(prefix->timestamp);
246 }
247 id = prefix->id;
248 size = prefix->total_size;
249
250 bs = (size_t)size;
251 if (bs < sizeof(*prefix))
252 return NULL;
253
254 if (id >= JIT_CODE_MAX) {
255 pr_warning("next_entry: unknown prefix %d, skipping\n", id);
256 return NULL;
257 }
258 if (bs > jd->bufsize) {
259 void *n;
260 n = realloc(jd->buf, bs);
261 if (!n)
262 return NULL;
263 jd->buf = n;
264 jd->bufsize = bs;
265 }
266
267 addr = ((void *)jd->buf) + sizeof(*prefix);
268
269 ret = fread(addr, bs - sizeof(*prefix), 1, jd->in);
270 if (ret != 1)
271 return NULL;
272
273 jr = (union jr_entry *)jd->buf;
274
275 switch(id) {
276 case JIT_CODE_DEBUG_INFO:
277 if (jd->needs_bswap) {
278 uint64_t n;
279 jr->info.code_addr = bswap_64(jr->info.code_addr);
280 jr->info.nr_entry = bswap_64(jr->info.nr_entry);
281 for (n = 0 ; n < jr->info.nr_entry; n++) {
282 jr->info.entries[n].addr = bswap_64(jr->info.entries[n].addr);
283 jr->info.entries[n].lineno = bswap_32(jr->info.entries[n].lineno);
284 jr->info.entries[n].discrim = bswap_32(jr->info.entries[n].discrim);
285 }
286 }
287 break;
288 case JIT_CODE_CLOSE:
289 break;
290 case JIT_CODE_LOAD:
291 if (jd->needs_bswap) {
292 jr->load.pid = bswap_32(jr->load.pid);
293 jr->load.tid = bswap_32(jr->load.tid);
294 jr->load.vma = bswap_64(jr->load.vma);
295 jr->load.code_addr = bswap_64(jr->load.code_addr);
296 jr->load.code_size = bswap_64(jr->load.code_size);
297 jr->load.code_index= bswap_64(jr->load.code_index);
298 }
299 jd->code_load_count++;
300 break;
301 case JIT_CODE_MOVE:
302 if (jd->needs_bswap) {
303 jr->move.pid = bswap_32(jr->move.pid);
304 jr->move.tid = bswap_32(jr->move.tid);
305 jr->move.vma = bswap_64(jr->move.vma);
306 jr->move.old_code_addr = bswap_64(jr->move.old_code_addr);
307 jr->move.new_code_addr = bswap_64(jr->move.new_code_addr);
308 jr->move.code_size = bswap_64(jr->move.code_size);
309 jr->move.code_index = bswap_64(jr->move.code_index);
310 }
311 break;
312 case JIT_CODE_MAX:
313 default:
314 return NULL;
315 }
316 return jr;
317}
318
319static int
320jit_inject_event(struct jit_buf_desc *jd, union perf_event *event)
321{
322 ssize_t size;
323
324 size = perf_data_file__write(jd->output, event, event->header.size);
325 if (size < 0)
326 return -1;
327
328 jd->bytes_written += size;
329 return 0;
330}
331
332static int jit_repipe_code_load(struct jit_buf_desc *jd, union jr_entry *jr)
333{
334 struct perf_sample sample;
335 union perf_event *event;
336 struct perf_tool *tool = jd->session->tool;
337 uint64_t code, addr;
338 uintptr_t uaddr;
339 char *filename;
340 struct stat st;
341 size_t size;
342 u16 idr_size;
343 const char *sym;
344 uint32_t count;
345 int ret, csize;
346 pid_t pid, tid;
347 struct {
348 u32 pid, tid;
349 u64 time;
350 } *id;
351
352 pid = jr->load.pid;
353 tid = jr->load.tid;
354 csize = jr->load.code_size;
355 addr = jr->load.code_addr;
356 sym = (void *)((unsigned long)jr + sizeof(jr->load));
357 code = (unsigned long)jr + jr->load.p.total_size - csize;
358 count = jr->load.code_index;
359 idr_size = jd->machine->id_hdr_size;
360
361 event = calloc(1, sizeof(*event) + idr_size);
362 if (!event)
363 return -1;
364
365 filename = event->mmap2.filename;
366 size = snprintf(filename, PATH_MAX, "%s/jitted-%d-%u.so",
367 jd->dir,
368 pid,
369 count);
370
371 size++; /* for \0 */
372
373 size = PERF_ALIGN(size, sizeof(u64));
374 uaddr = (uintptr_t)code;
375 ret = jit_emit_elf(filename, sym, addr, (const void *)uaddr, csize, jd->debug_data, jd->nr_debug_entries);
376
377 if (jd->debug_data && jd->nr_debug_entries) {
378 free(jd->debug_data);
379 jd->debug_data = NULL;
380 jd->nr_debug_entries = 0;
381 }
382
383 if (ret) {
384 free(event);
385 return -1;
386 }
387 if (stat(filename, &st))
388 memset(&st, 0, sizeof(stat));
389
390 event->mmap2.header.type = PERF_RECORD_MMAP2;
391 event->mmap2.header.misc = PERF_RECORD_MISC_USER;
392 event->mmap2.header.size = (sizeof(event->mmap2) -
393 (sizeof(event->mmap2.filename) - size) + idr_size);
394
395 event->mmap2.pgoff = GEN_ELF_TEXT_OFFSET;
396 event->mmap2.start = addr;
397 event->mmap2.len = csize;
398 event->mmap2.pid = pid;
399 event->mmap2.tid = tid;
400 event->mmap2.ino = st.st_ino;
401 event->mmap2.maj = major(st.st_dev);
402 event->mmap2.min = minor(st.st_dev);
403 event->mmap2.prot = st.st_mode;
404 event->mmap2.flags = MAP_SHARED;
405 event->mmap2.ino_generation = 1;
406
407 id = (void *)((unsigned long)event + event->mmap.header.size - idr_size);
408 if (jd->sample_type & PERF_SAMPLE_TID) {
409 id->pid = pid;
410 id->tid = tid;
411 }
412 if (jd->sample_type & PERF_SAMPLE_TIME)
413 id->time = jr->load.p.timestamp;
414
415 /*
416 * create pseudo sample to induce dso hit increment
417 * use first address as sample address
418 */
419 memset(&sample, 0, sizeof(sample));
420 sample.cpumode = PERF_RECORD_MISC_USER;
421 sample.pid = pid;
422 sample.tid = tid;
423 sample.time = id->time;
424 sample.ip = addr;
425
426 ret = perf_event__process_mmap2(tool, event, &sample, jd->machine);
427 if (ret)
428 return ret;
429
430 ret = jit_inject_event(jd, event);
431 /*
432 * mark dso as use to generate buildid in the header
433 */
434 if (!ret)
435 build_id__mark_dso_hit(tool, event, &sample, NULL, jd->machine);
436
437 return ret;
438}
439
440static int jit_repipe_code_move(struct jit_buf_desc *jd, union jr_entry *jr)
441{
442 struct perf_sample sample;
443 union perf_event *event;
444 struct perf_tool *tool = jd->session->tool;
445 char *filename;
446 size_t size;
447 struct stat st;
448 u16 idr_size;
449 int ret;
450 pid_t pid, tid;
451 struct {
452 u32 pid, tid;
453 u64 time;
454 } *id;
455
456 pid = jr->move.pid;
457 tid = jr->move.tid;
458 idr_size = jd->machine->id_hdr_size;
459
460 /*
461 * +16 to account for sample_id_all (hack)
462 */
463 event = calloc(1, sizeof(*event) + 16);
464 if (!event)
465 return -1;
466
467 filename = event->mmap2.filename;
468 size = snprintf(filename, PATH_MAX, "%s/jitted-%d-%"PRIu64,
469 jd->dir,
470 pid,
471 jr->move.code_index);
472
473 size++; /* for \0 */
474
475 if (stat(filename, &st))
476 memset(&st, 0, sizeof(stat));
477
478 size = PERF_ALIGN(size, sizeof(u64));
479
480 event->mmap2.header.type = PERF_RECORD_MMAP2;
481 event->mmap2.header.misc = PERF_RECORD_MISC_USER;
482 event->mmap2.header.size = (sizeof(event->mmap2) -
483 (sizeof(event->mmap2.filename) - size) + idr_size);
484 event->mmap2.pgoff = GEN_ELF_TEXT_OFFSET;
485 event->mmap2.start = jr->move.new_code_addr;
486 event->mmap2.len = jr->move.code_size;
487 event->mmap2.pid = pid;
488 event->mmap2.tid = tid;
489 event->mmap2.ino = st.st_ino;
490 event->mmap2.maj = major(st.st_dev);
491 event->mmap2.min = minor(st.st_dev);
492 event->mmap2.prot = st.st_mode;
493 event->mmap2.flags = MAP_SHARED;
494 event->mmap2.ino_generation = 1;
495
496 id = (void *)((unsigned long)event + event->mmap.header.size - idr_size);
497 if (jd->sample_type & PERF_SAMPLE_TID) {
498 id->pid = pid;
499 id->tid = tid;
500 }
501 if (jd->sample_type & PERF_SAMPLE_TIME)
502 id->time = jr->load.p.timestamp;
503
504 /*
505 * create pseudo sample to induce dso hit increment
506 * use first address as sample address
507 */
508 memset(&sample, 0, sizeof(sample));
509 sample.cpumode = PERF_RECORD_MISC_USER;
510 sample.pid = pid;
511 sample.tid = tid;
512 sample.time = id->time;
513 sample.ip = jr->move.new_code_addr;
514
515 ret = perf_event__process_mmap2(tool, event, &sample, jd->machine);
516 if (ret)
517 return ret;
518
519 ret = jit_inject_event(jd, event);
520 if (!ret)
521 build_id__mark_dso_hit(tool, event, &sample, NULL, jd->machine);
522
523 return ret;
524}
525
526static int jit_repipe_debug_info(struct jit_buf_desc *jd, union jr_entry *jr)
527{
528 void *data;
529 size_t sz;
530
531 if (!(jd && jr))
532 return -1;
533
534 sz = jr->prefix.total_size - sizeof(jr->info);
535 data = malloc(sz);
536 if (!data)
537 return -1;
538
539 memcpy(data, &jr->info.entries, sz);
540
541 jd->debug_data = data;
542
543 /*
544 * we must use nr_entry instead of size here because
545 * we cannot distinguish actual entry from padding otherwise
546 */
547 jd->nr_debug_entries = jr->info.nr_entry;
548
549 return 0;
550}
551
552static int
553jit_process_dump(struct jit_buf_desc *jd)
554{
555 union jr_entry *jr;
556 int ret;
557
558 while ((jr = jit_get_next_entry(jd))) {
559 switch(jr->prefix.id) {
560 case JIT_CODE_LOAD:
561 ret = jit_repipe_code_load(jd, jr);
562 break;
563 case JIT_CODE_MOVE:
564 ret = jit_repipe_code_move(jd, jr);
565 break;
566 case JIT_CODE_DEBUG_INFO:
567 ret = jit_repipe_debug_info(jd, jr);
568 break;
569 default:
570 ret = 0;
571 continue;
572 }
573 }
574 return ret;
575}
576
577static int
578jit_inject(struct jit_buf_desc *jd, char *path)
579{
580 int ret;
581
582 if (verbose > 0)
583 fprintf(stderr, "injecting: %s\n", path);
584
585 ret = jit_open(jd, path);
586 if (ret)
587 return -1;
588
589 ret = jit_process_dump(jd);
590
591 jit_close(jd);
592
593 if (verbose > 0)
594 fprintf(stderr, "injected: %s (%d)\n", path, ret);
595
596 return 0;
597}
598
599/*
600 * File must be with pattern .../jit-XXXX.dump
601 * where XXXX is the PID of the process which did the mmap()
602 * as captured in the RECORD_MMAP record
603 */
604static int
605jit_detect(char *mmap_name, pid_t pid)
606 {
607 char *p;
608 char *end = NULL;
609 pid_t pid2;
610
611 if (verbose > 2)
612 fprintf(stderr, "jit marker trying : %s\n", mmap_name);
613 /*
614 * get file name
615 */
616 p = strrchr(mmap_name, '/');
617 if (!p)
618 return -1;
619
620 /*
621 * match prefix
622 */
623 if (strncmp(p, "/jit-", 5))
624 return -1;
625
626 /*
627 * skip prefix
628 */
629 p += 5;
630
631 /*
632 * must be followed by a pid
633 */
634 if (!isdigit(*p))
635 return -1;
636
637 pid2 = (int)strtol(p, &end, 10);
638 if (!end)
639 return -1;
640
641 /*
642 * pid does not match mmap pid
643 * pid==0 in system-wide mode (synthesized)
644 */
645 if (pid && pid2 != pid)
646 return -1;
647 /*
648 * validate suffix
649 */
650 if (strcmp(end, ".dump"))
651 return -1;
652
653 if (verbose > 0)
654 fprintf(stderr, "jit marker found: %s\n", mmap_name);
655
656 return 0;
657}
658
659int
660jit_process(struct perf_session *session,
661 struct perf_data_file *output,
662 struct machine *machine,
663 char *filename,
664 pid_t pid,
665 u64 *nbytes)
666{
667 struct perf_evsel *first;
668 struct jit_buf_desc jd;
669 int ret;
670
671 /*
672 * first, detect marker mmap (i.e., the jitdump mmap)
673 */
674 if (jit_detect(filename, pid))
675 return 0;
676
677 memset(&jd, 0, sizeof(jd));
678
679 jd.session = session;
680 jd.output = output;
681 jd.machine = machine;
682
683 /*
684 * track sample_type to compute id_all layout
685 * perf sets the same sample type to all events as of now
686 */
687 first = perf_evlist__first(session->evlist);
688 jd.sample_type = first->attr.sample_type;
689
690 *nbytes = 0;
691
692 ret = jit_inject(&jd, filename);
693 if (!ret) {
694 *nbytes = jd.bytes_written;
695 ret = 1;
696 }
697
698 return ret;
699}
diff --git a/tools/perf/util/jitdump.h b/tools/perf/util/jitdump.h
new file mode 100644
index 000000000000..b66c1f503d9e
--- /dev/null
+++ b/tools/perf/util/jitdump.h
@@ -0,0 +1,124 @@
1/*
2 * jitdump.h: jitted code info encapsulation file format
3 *
4 * Adapted from OProfile GPLv2 support jidump.h:
5 * Copyright 2007 OProfile authors
6 * Jens Wilke
7 * Daniel Hansel
8 * Copyright IBM Corporation 2007
9 */
10#ifndef JITDUMP_H
11#define JITDUMP_H
12
13#include <sys/time.h>
14#include <time.h>
15#include <stdint.h>
16
17/* JiTD */
18#define JITHEADER_MAGIC 0x4A695444
19#define JITHEADER_MAGIC_SW 0x4454694A
20
21#define PADDING_8ALIGNED(x) ((((x) + 7) & 7) ^ 7)
22
23#define JITHEADER_VERSION 1
24
25enum jitdump_flags_bits {
26 JITDUMP_FLAGS_MAX_BIT,
27};
28
29#define JITDUMP_FLAGS_RESERVED (JITDUMP_FLAGS_MAX_BIT < 64 ? \
30 (~((1ULL << JITDUMP_FLAGS_MAX_BIT) - 1)) : 0)
31
32struct jitheader {
33 uint32_t magic; /* characters "jItD" */
34 uint32_t version; /* header version */
35 uint32_t total_size; /* total size of header */
36 uint32_t elf_mach; /* elf mach target */
37 uint32_t pad1; /* reserved */
38 uint32_t pid; /* JIT process id */
39 uint64_t timestamp; /* timestamp */
40 uint64_t flags; /* flags */
41};
42
43enum jit_record_type {
44 JIT_CODE_LOAD = 0,
45 JIT_CODE_MOVE = 1,
46 JIT_CODE_DEBUG_INFO = 2,
47 JIT_CODE_CLOSE = 3,
48
49 JIT_CODE_MAX,
50};
51
52/* record prefix (mandatory in each record) */
53struct jr_prefix {
54 uint32_t id;
55 uint32_t total_size;
56 uint64_t timestamp;
57};
58
59struct jr_code_load {
60 struct jr_prefix p;
61
62 uint32_t pid;
63 uint32_t tid;
64 uint64_t vma;
65 uint64_t code_addr;
66 uint64_t code_size;
67 uint64_t code_index;
68};
69
70struct jr_code_close {
71 struct jr_prefix p;
72};
73
74struct jr_code_move {
75 struct jr_prefix p;
76
77 uint32_t pid;
78 uint32_t tid;
79 uint64_t vma;
80 uint64_t old_code_addr;
81 uint64_t new_code_addr;
82 uint64_t code_size;
83 uint64_t code_index;
84};
85
86struct debug_entry {
87 uint64_t addr;
88 int lineno; /* source line number starting at 1 */
89 int discrim; /* column discriminator, 0 is default */
90 const char name[0]; /* null terminated filename, \xff\0 if same as previous entry */
91};
92
93struct jr_code_debug_info {
94 struct jr_prefix p;
95
96 uint64_t code_addr;
97 uint64_t nr_entry;
98 struct debug_entry entries[0];
99};
100
101union jr_entry {
102 struct jr_code_debug_info info;
103 struct jr_code_close close;
104 struct jr_code_load load;
105 struct jr_code_move move;
106 struct jr_prefix prefix;
107};
108
109static inline struct debug_entry *
110debug_entry_next(struct debug_entry *ent)
111{
112 void *a = ent + 1;
113 size_t l = strlen(ent->name) + 1;
114 return a + l;
115}
116
117static inline char *
118debug_entry_file(struct debug_entry *ent)
119{
120 void *a = ent + 1;
121 return a;
122}
123
124#endif /* !JITDUMP_H */
diff --git a/tools/perf/util/kvm-stat.h b/tools/perf/util/kvm-stat.h
index ae825d4ec110..d01e73592f6e 100644
--- a/tools/perf/util/kvm-stat.h
+++ b/tools/perf/util/kvm-stat.h
@@ -122,6 +122,7 @@ void exit_event_decode_key(struct perf_kvm_stat *kvm,
122 122
123bool kvm_exit_event(struct perf_evsel *evsel); 123bool kvm_exit_event(struct perf_evsel *evsel);
124bool kvm_entry_event(struct perf_evsel *evsel); 124bool kvm_entry_event(struct perf_evsel *evsel);
125int setup_kvm_events_tp(struct perf_kvm_stat *kvm);
125 126
126#define define_exit_reasons_table(name, symbols) \ 127#define define_exit_reasons_table(name, symbols) \
127 static struct exit_reasons_table name[] = { \ 128 static struct exit_reasons_table name[] = { \
@@ -133,8 +134,13 @@ bool kvm_entry_event(struct perf_evsel *evsel);
133 */ 134 */
134int cpu_isa_init(struct perf_kvm_stat *kvm, const char *cpuid); 135int cpu_isa_init(struct perf_kvm_stat *kvm, const char *cpuid);
135 136
136extern const char * const kvm_events_tp[]; 137extern const char *kvm_events_tp[];
137extern struct kvm_reg_events_ops kvm_reg_events_ops[]; 138extern struct kvm_reg_events_ops kvm_reg_events_ops[];
138extern const char * const kvm_skip_events[]; 139extern const char * const kvm_skip_events[];
140extern const char *vcpu_id_str;
141extern const int decode_str_len;
142extern const char *kvm_exit_reason;
143extern const char *kvm_entry_trace;
144extern const char *kvm_exit_trace;
139 145
140#endif /* __PERF_KVM_STAT_H */ 146#endif /* __PERF_KVM_STAT_H */
diff --git a/tools/perf/util/llvm-utils.c b/tools/perf/util/llvm-utils.c
index 00724d496d38..33071d6159bc 100644
--- a/tools/perf/util/llvm-utils.c
+++ b/tools/perf/util/llvm-utils.c
@@ -3,11 +3,11 @@
3 * Copyright (C) 2015, Huawei Inc. 3 * Copyright (C) 2015, Huawei Inc.
4 */ 4 */
5 5
6#include <limits.h>
6#include <stdio.h> 7#include <stdio.h>
7#include "util.h" 8#include <stdlib.h>
8#include "debug.h" 9#include "debug.h"
9#include "llvm-utils.h" 10#include "llvm-utils.h"
10#include "cache.h"
11 11
12#define CLANG_BPF_CMD_DEFAULT_TEMPLATE \ 12#define CLANG_BPF_CMD_DEFAULT_TEMPLATE \
13 "$CLANG_EXEC -D__KERNEL__ -D__NR_CPUS__=$NR_CPUS "\ 13 "$CLANG_EXEC -D__KERNEL__ -D__NR_CPUS__=$NR_CPUS "\
@@ -98,11 +98,12 @@ read_from_pipe(const char *cmd, void **p_buf, size_t *p_read_sz)
98 void *buf = NULL; 98 void *buf = NULL;
99 FILE *file = NULL; 99 FILE *file = NULL;
100 size_t read_sz = 0, buf_sz = 0; 100 size_t read_sz = 0, buf_sz = 0;
101 char serr[STRERR_BUFSIZE];
101 102
102 file = popen(cmd, "r"); 103 file = popen(cmd, "r");
103 if (!file) { 104 if (!file) {
104 pr_err("ERROR: unable to popen cmd: %s\n", 105 pr_err("ERROR: unable to popen cmd: %s\n",
105 strerror(errno)); 106 strerror_r(errno, serr, sizeof(serr)));
106 return -EINVAL; 107 return -EINVAL;
107 } 108 }
108 109
@@ -136,7 +137,7 @@ read_from_pipe(const char *cmd, void **p_buf, size_t *p_read_sz)
136 137
137 if (ferror(file)) { 138 if (ferror(file)) {
138 pr_err("ERROR: error occurred when reading from pipe: %s\n", 139 pr_err("ERROR: error occurred when reading from pipe: %s\n",
139 strerror(errno)); 140 strerror_r(errno, serr, sizeof(serr)));
140 err = -EIO; 141 err = -EIO;
141 goto errout; 142 goto errout;
142 } 143 }
@@ -334,10 +335,18 @@ int llvm__compile_bpf(const char *path, void **p_obj_buf,
334 unsigned int kernel_version; 335 unsigned int kernel_version;
335 char linux_version_code_str[64]; 336 char linux_version_code_str[64];
336 const char *clang_opt = llvm_param.clang_opt; 337 const char *clang_opt = llvm_param.clang_opt;
337 char clang_path[PATH_MAX], nr_cpus_avail_str[64]; 338 char clang_path[PATH_MAX], abspath[PATH_MAX], nr_cpus_avail_str[64];
339 char serr[STRERR_BUFSIZE];
338 char *kbuild_dir = NULL, *kbuild_include_opts = NULL; 340 char *kbuild_dir = NULL, *kbuild_include_opts = NULL;
339 const char *template = llvm_param.clang_bpf_cmd_template; 341 const char *template = llvm_param.clang_bpf_cmd_template;
340 342
343 if (path[0] != '-' && realpath(path, abspath) == NULL) {
344 err = errno;
345 pr_err("ERROR: problems with path %s: %s\n",
346 path, strerror_r(err, serr, sizeof(serr)));
347 return -err;
348 }
349
341 if (!template) 350 if (!template)
342 template = CLANG_BPF_CMD_DEFAULT_TEMPLATE; 351 template = CLANG_BPF_CMD_DEFAULT_TEMPLATE;
343 352
@@ -362,7 +371,7 @@ int llvm__compile_bpf(const char *path, void **p_obj_buf,
362 if (nr_cpus_avail <= 0) { 371 if (nr_cpus_avail <= 0) {
363 pr_err( 372 pr_err(
364"WARNING:\tunable to get available CPUs in this system: %s\n" 373"WARNING:\tunable to get available CPUs in this system: %s\n"
365" \tUse 128 instead.\n", strerror(errno)); 374" \tUse 128 instead.\n", strerror_r(errno, serr, sizeof(serr)));
366 nr_cpus_avail = 128; 375 nr_cpus_avail = 128;
367 } 376 }
368 snprintf(nr_cpus_avail_str, sizeof(nr_cpus_avail_str), "%d", 377 snprintf(nr_cpus_avail_str, sizeof(nr_cpus_avail_str), "%d",
@@ -387,8 +396,7 @@ int llvm__compile_bpf(const char *path, void **p_obj_buf,
387 * stdin to be source file (testing). 396 * stdin to be source file (testing).
388 */ 397 */
389 force_set_env("CLANG_SOURCE", 398 force_set_env("CLANG_SOURCE",
390 (path[0] == '-') ? path : 399 (path[0] == '-') ? path : abspath);
391 make_nonrelative_path(path));
392 400
393 pr_debug("llvm compiling command template: %s\n", template); 401 pr_debug("llvm compiling command template: %s\n", template);
394 err = read_from_pipe(template, &obj_buf, &obj_buf_sz); 402 err = read_from_pipe(template, &obj_buf, &obj_buf_sz);
diff --git a/tools/perf/util/llvm-utils.h b/tools/perf/util/llvm-utils.h
index 5b3cf1c229e2..23b9a743fe72 100644
--- a/tools/perf/util/llvm-utils.h
+++ b/tools/perf/util/llvm-utils.h
@@ -39,11 +39,10 @@ struct llvm_param {
39}; 39};
40 40
41extern struct llvm_param llvm_param; 41extern struct llvm_param llvm_param;
42extern int perf_llvm_config(const char *var, const char *value); 42int perf_llvm_config(const char *var, const char *value);
43 43
44extern int llvm__compile_bpf(const char *path, void **p_obj_buf, 44int llvm__compile_bpf(const char *path, void **p_obj_buf, size_t *p_obj_buf_sz);
45 size_t *p_obj_buf_sz);
46 45
47/* This function is for test__llvm() use only */ 46/* This function is for test__llvm() use only */
48extern int llvm__search_clang(void); 47int llvm__search_clang(void);
49#endif 48#endif
diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c
index ad79297c76c8..80b9b6a87990 100644
--- a/tools/perf/util/machine.c
+++ b/tools/perf/util/machine.c
@@ -1301,9 +1301,8 @@ out_problem:
1301 1301
1302int machine__process_mmap2_event(struct machine *machine, 1302int machine__process_mmap2_event(struct machine *machine,
1303 union perf_event *event, 1303 union perf_event *event,
1304 struct perf_sample *sample __maybe_unused) 1304 struct perf_sample *sample)
1305{ 1305{
1306 u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
1307 struct thread *thread; 1306 struct thread *thread;
1308 struct map *map; 1307 struct map *map;
1309 enum map_type type; 1308 enum map_type type;
@@ -1312,8 +1311,8 @@ int machine__process_mmap2_event(struct machine *machine,
1312 if (dump_trace) 1311 if (dump_trace)
1313 perf_event__fprintf_mmap2(event, stdout); 1312 perf_event__fprintf_mmap2(event, stdout);
1314 1313
1315 if (cpumode == PERF_RECORD_MISC_GUEST_KERNEL || 1314 if (sample->cpumode == PERF_RECORD_MISC_GUEST_KERNEL ||
1316 cpumode == PERF_RECORD_MISC_KERNEL) { 1315 sample->cpumode == PERF_RECORD_MISC_KERNEL) {
1317 ret = machine__process_kernel_mmap_event(machine, event); 1316 ret = machine__process_kernel_mmap_event(machine, event);
1318 if (ret < 0) 1317 if (ret < 0)
1319 goto out_problem; 1318 goto out_problem;
@@ -1355,9 +1354,8 @@ out_problem:
1355} 1354}
1356 1355
1357int machine__process_mmap_event(struct machine *machine, union perf_event *event, 1356int machine__process_mmap_event(struct machine *machine, union perf_event *event,
1358 struct perf_sample *sample __maybe_unused) 1357 struct perf_sample *sample)
1359{ 1358{
1360 u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
1361 struct thread *thread; 1359 struct thread *thread;
1362 struct map *map; 1360 struct map *map;
1363 enum map_type type; 1361 enum map_type type;
@@ -1366,8 +1364,8 @@ int machine__process_mmap_event(struct machine *machine, union perf_event *event
1366 if (dump_trace) 1364 if (dump_trace)
1367 perf_event__fprintf_mmap(event, stdout); 1365 perf_event__fprintf_mmap(event, stdout);
1368 1366
1369 if (cpumode == PERF_RECORD_MISC_GUEST_KERNEL || 1367 if (sample->cpumode == PERF_RECORD_MISC_GUEST_KERNEL ||
1370 cpumode == PERF_RECORD_MISC_KERNEL) { 1368 sample->cpumode == PERF_RECORD_MISC_KERNEL) {
1371 ret = machine__process_kernel_mmap_event(machine, event); 1369 ret = machine__process_kernel_mmap_event(machine, event);
1372 if (ret < 0) 1370 if (ret < 0)
1373 goto out_problem; 1371 goto out_problem;
diff --git a/tools/perf/util/machine.h b/tools/perf/util/machine.h
index 2c2b443df5ba..8499db281158 100644
--- a/tools/perf/util/machine.h
+++ b/tools/perf/util/machine.h
@@ -94,7 +94,7 @@ int machine__process_aux_event(struct machine *machine,
94 union perf_event *event); 94 union perf_event *event);
95int machine__process_itrace_start_event(struct machine *machine, 95int machine__process_itrace_start_event(struct machine *machine,
96 union perf_event *event); 96 union perf_event *event);
97int machine__process_switch_event(struct machine *machine __maybe_unused, 97int machine__process_switch_event(struct machine *machine,
98 union perf_event *event); 98 union perf_event *event);
99int machine__process_mmap_event(struct machine *machine, union perf_event *event, 99int machine__process_mmap_event(struct machine *machine, union perf_event *event,
100 struct perf_sample *sample); 100 struct perf_sample *sample);
@@ -180,6 +180,16 @@ struct symbol *machine__find_kernel_symbol(struct machine *machine,
180} 180}
181 181
182static inline 182static inline
183struct symbol *machine__find_kernel_symbol_by_name(struct machine *machine,
184 enum map_type type, const char *name,
185 struct map **mapp,
186 symbol_filter_t filter)
187{
188 return map_groups__find_symbol_by_name(&machine->kmaps, type, name,
189 mapp, filter);
190}
191
192static inline
183struct symbol *machine__find_kernel_function(struct machine *machine, u64 addr, 193struct symbol *machine__find_kernel_function(struct machine *machine, u64 addr,
184 struct map **mapp, 194 struct map **mapp,
185 symbol_filter_t filter) 195 symbol_filter_t filter)
diff --git a/tools/perf/util/mem-events.c b/tools/perf/util/mem-events.c
new file mode 100644
index 000000000000..75465f89a413
--- /dev/null
+++ b/tools/perf/util/mem-events.c
@@ -0,0 +1,255 @@
1#include <stddef.h>
2#include <stdlib.h>
3#include <string.h>
4#include <errno.h>
5#include <sys/types.h>
6#include <sys/stat.h>
7#include <unistd.h>
8#include <api/fs/fs.h>
9#include "mem-events.h"
10#include "debug.h"
11#include "symbol.h"
12
13#define E(t, n, s) { .tag = t, .name = n, .sysfs_name = s }
14
15struct perf_mem_event perf_mem_events[PERF_MEM_EVENTS__MAX] = {
16 E("ldlat-loads", "cpu/mem-loads,ldlat=30/P", "mem-loads"),
17 E("ldlat-stores", "cpu/mem-stores/P", "mem-stores"),
18};
19#undef E
20
21#undef E
22
23char *perf_mem_events__name(int i)
24{
25 return (char *)perf_mem_events[i].name;
26}
27
28int perf_mem_events__parse(const char *str)
29{
30 char *tok, *saveptr = NULL;
31 bool found = false;
32 char *buf;
33 int j;
34
35 /* We need buffer that we know we can write to. */
36 buf = malloc(strlen(str) + 1);
37 if (!buf)
38 return -ENOMEM;
39
40 strcpy(buf, str);
41
42 tok = strtok_r((char *)buf, ",", &saveptr);
43
44 while (tok) {
45 for (j = 0; j < PERF_MEM_EVENTS__MAX; j++) {
46 struct perf_mem_event *e = &perf_mem_events[j];
47
48 if (strstr(e->tag, tok))
49 e->record = found = true;
50 }
51
52 tok = strtok_r(NULL, ",", &saveptr);
53 }
54
55 free(buf);
56
57 if (found)
58 return 0;
59
60 pr_err("failed: event '%s' not found, use '-e list' to get list of available events\n", str);
61 return -1;
62}
63
64int perf_mem_events__init(void)
65{
66 const char *mnt = sysfs__mount();
67 bool found = false;
68 int j;
69
70 if (!mnt)
71 return -ENOENT;
72
73 for (j = 0; j < PERF_MEM_EVENTS__MAX; j++) {
74 char path[PATH_MAX];
75 struct perf_mem_event *e = &perf_mem_events[j];
76 struct stat st;
77
78 scnprintf(path, PATH_MAX, "%s/devices/cpu/events/%s",
79 mnt, e->sysfs_name);
80
81 if (!stat(path, &st))
82 e->supported = found = true;
83 }
84
85 return found ? 0 : -ENOENT;
86}
87
88static const char * const tlb_access[] = {
89 "N/A",
90 "HIT",
91 "MISS",
92 "L1",
93 "L2",
94 "Walker",
95 "Fault",
96};
97
98int perf_mem__tlb_scnprintf(char *out, size_t sz, struct mem_info *mem_info)
99{
100 size_t l = 0, i;
101 u64 m = PERF_MEM_TLB_NA;
102 u64 hit, miss;
103
104 sz -= 1; /* -1 for null termination */
105 out[0] = '\0';
106
107 if (mem_info)
108 m = mem_info->data_src.mem_dtlb;
109
110 hit = m & PERF_MEM_TLB_HIT;
111 miss = m & PERF_MEM_TLB_MISS;
112
113 /* already taken care of */
114 m &= ~(PERF_MEM_TLB_HIT|PERF_MEM_TLB_MISS);
115
116 for (i = 0; m && i < ARRAY_SIZE(tlb_access); i++, m >>= 1) {
117 if (!(m & 0x1))
118 continue;
119 if (l) {
120 strcat(out, " or ");
121 l += 4;
122 }
123 l += scnprintf(out + l, sz - l, tlb_access[i]);
124 }
125 if (*out == '\0')
126 l += scnprintf(out, sz - l, "N/A");
127 if (hit)
128 l += scnprintf(out + l, sz - l, " hit");
129 if (miss)
130 l += scnprintf(out + l, sz - l, " miss");
131
132 return l;
133}
134
135static const char * const mem_lvl[] = {
136 "N/A",
137 "HIT",
138 "MISS",
139 "L1",
140 "LFB",
141 "L2",
142 "L3",
143 "Local RAM",
144 "Remote RAM (1 hop)",
145 "Remote RAM (2 hops)",
146 "Remote Cache (1 hop)",
147 "Remote Cache (2 hops)",
148 "I/O",
149 "Uncached",
150};
151
152int perf_mem__lvl_scnprintf(char *out, size_t sz, struct mem_info *mem_info)
153{
154 size_t i, l = 0;
155 u64 m = PERF_MEM_LVL_NA;
156 u64 hit, miss;
157
158 if (mem_info)
159 m = mem_info->data_src.mem_lvl;
160
161 sz -= 1; /* -1 for null termination */
162 out[0] = '\0';
163
164 hit = m & PERF_MEM_LVL_HIT;
165 miss = m & PERF_MEM_LVL_MISS;
166
167 /* already taken care of */
168 m &= ~(PERF_MEM_LVL_HIT|PERF_MEM_LVL_MISS);
169
170 for (i = 0; m && i < ARRAY_SIZE(mem_lvl); i++, m >>= 1) {
171 if (!(m & 0x1))
172 continue;
173 if (l) {
174 strcat(out, " or ");
175 l += 4;
176 }
177 l += scnprintf(out + l, sz - l, mem_lvl[i]);
178 }
179 if (*out == '\0')
180 l += scnprintf(out, sz - l, "N/A");
181 if (hit)
182 l += scnprintf(out + l, sz - l, " hit");
183 if (miss)
184 l += scnprintf(out + l, sz - l, " miss");
185
186 return l;
187}
188
189static const char * const snoop_access[] = {
190 "N/A",
191 "None",
192 "Miss",
193 "Hit",
194 "HitM",
195};
196
197int perf_mem__snp_scnprintf(char *out, size_t sz, struct mem_info *mem_info)
198{
199 size_t i, l = 0;
200 u64 m = PERF_MEM_SNOOP_NA;
201
202 sz -= 1; /* -1 for null termination */
203 out[0] = '\0';
204
205 if (mem_info)
206 m = mem_info->data_src.mem_snoop;
207
208 for (i = 0; m && i < ARRAY_SIZE(snoop_access); i++, m >>= 1) {
209 if (!(m & 0x1))
210 continue;
211 if (l) {
212 strcat(out, " or ");
213 l += 4;
214 }
215 l += scnprintf(out + l, sz - l, snoop_access[i]);
216 }
217
218 if (*out == '\0')
219 l += scnprintf(out, sz - l, "N/A");
220
221 return l;
222}
223
224int perf_mem__lck_scnprintf(char *out, size_t sz, struct mem_info *mem_info)
225{
226 u64 mask = PERF_MEM_LOCK_NA;
227 int l;
228
229 if (mem_info)
230 mask = mem_info->data_src.mem_lock;
231
232 if (mask & PERF_MEM_LOCK_NA)
233 l = scnprintf(out, sz, "N/A");
234 else if (mask & PERF_MEM_LOCK_LOCKED)
235 l = scnprintf(out, sz, "Yes");
236 else
237 l = scnprintf(out, sz, "No");
238
239 return l;
240}
241
242int perf_script__meminfo_scnprintf(char *out, size_t sz, struct mem_info *mem_info)
243{
244 int i = 0;
245
246 i += perf_mem__lvl_scnprintf(out, sz, mem_info);
247 i += scnprintf(out + i, sz - i, "|SNP ");
248 i += perf_mem__snp_scnprintf(out + i, sz - i, mem_info);
249 i += scnprintf(out + i, sz - i, "|TLB ");
250 i += perf_mem__tlb_scnprintf(out + i, sz - i, mem_info);
251 i += scnprintf(out + i, sz - i, "|LCK ");
252 i += perf_mem__lck_scnprintf(out + i, sz - i, mem_info);
253
254 return i;
255}
diff --git a/tools/perf/util/mem-events.h b/tools/perf/util/mem-events.h
new file mode 100644
index 000000000000..5d6d93066a6e
--- /dev/null
+++ b/tools/perf/util/mem-events.h
@@ -0,0 +1,35 @@
1#ifndef __PERF_MEM_EVENTS_H
2#define __PERF_MEM_EVENTS_H
3
4#include <stdbool.h>
5
6struct perf_mem_event {
7 bool record;
8 bool supported;
9 const char *tag;
10 const char *name;
11 const char *sysfs_name;
12};
13
14enum {
15 PERF_MEM_EVENTS__LOAD,
16 PERF_MEM_EVENTS__STORE,
17 PERF_MEM_EVENTS__MAX,
18};
19
20extern struct perf_mem_event perf_mem_events[PERF_MEM_EVENTS__MAX];
21
22int perf_mem_events__parse(const char *str);
23int perf_mem_events__init(void);
24
25char *perf_mem_events__name(int i);
26
27struct mem_info;
28int perf_mem__tlb_scnprintf(char *out, size_t sz, struct mem_info *mem_info);
29int perf_mem__lvl_scnprintf(char *out, size_t sz, struct mem_info *mem_info);
30int perf_mem__snp_scnprintf(char *out, size_t sz, struct mem_info *mem_info);
31int perf_mem__lck_scnprintf(char *out, size_t sz, struct mem_info *mem_info);
32
33int perf_script__meminfo_scnprintf(char *bf, size_t size, struct mem_info *mem_info);
34
35#endif /* __PERF_MEM_EVENTS_H */
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index 813d9b272c81..4c19d5e79d8c 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -279,7 +279,24 @@ const char *event_type(int type)
279 return "unknown"; 279 return "unknown";
280} 280}
281 281
282static int parse_events__is_name_term(struct parse_events_term *term)
283{
284 return term->type_term == PARSE_EVENTS__TERM_TYPE_NAME;
285}
282 286
287static char *get_config_name(struct list_head *head_terms)
288{
289 struct parse_events_term *term;
290
291 if (!head_terms)
292 return NULL;
293
294 list_for_each_entry(term, head_terms, list)
295 if (parse_events__is_name_term(term))
296 return term->val.str;
297
298 return NULL;
299}
283 300
284static struct perf_evsel * 301static struct perf_evsel *
285__add_event(struct list_head *list, int *idx, 302__add_event(struct list_head *list, int *idx,
@@ -333,11 +350,25 @@ static int parse_aliases(char *str, const char *names[][PERF_EVSEL__MAX_ALIASES]
333 return -1; 350 return -1;
334} 351}
335 352
353typedef int config_term_func_t(struct perf_event_attr *attr,
354 struct parse_events_term *term,
355 struct parse_events_error *err);
356static int config_term_common(struct perf_event_attr *attr,
357 struct parse_events_term *term,
358 struct parse_events_error *err);
359static int config_attr(struct perf_event_attr *attr,
360 struct list_head *head,
361 struct parse_events_error *err,
362 config_term_func_t config_term);
363
336int parse_events_add_cache(struct list_head *list, int *idx, 364int parse_events_add_cache(struct list_head *list, int *idx,
337 char *type, char *op_result1, char *op_result2) 365 char *type, char *op_result1, char *op_result2,
366 struct parse_events_error *err,
367 struct list_head *head_config)
338{ 368{
339 struct perf_event_attr attr; 369 struct perf_event_attr attr;
340 char name[MAX_NAME_LEN]; 370 LIST_HEAD(config_terms);
371 char name[MAX_NAME_LEN], *config_name;
341 int cache_type = -1, cache_op = -1, cache_result = -1; 372 int cache_type = -1, cache_op = -1, cache_result = -1;
342 char *op_result[2] = { op_result1, op_result2 }; 373 char *op_result[2] = { op_result1, op_result2 };
343 int i, n; 374 int i, n;
@@ -351,6 +382,7 @@ int parse_events_add_cache(struct list_head *list, int *idx,
351 if (cache_type == -1) 382 if (cache_type == -1)
352 return -EINVAL; 383 return -EINVAL;
353 384
385 config_name = get_config_name(head_config);
354 n = snprintf(name, MAX_NAME_LEN, "%s", type); 386 n = snprintf(name, MAX_NAME_LEN, "%s", type);
355 387
356 for (i = 0; (i < 2) && (op_result[i]); i++) { 388 for (i = 0; (i < 2) && (op_result[i]); i++) {
@@ -391,7 +423,16 @@ int parse_events_add_cache(struct list_head *list, int *idx,
391 memset(&attr, 0, sizeof(attr)); 423 memset(&attr, 0, sizeof(attr));
392 attr.config = cache_type | (cache_op << 8) | (cache_result << 16); 424 attr.config = cache_type | (cache_op << 8) | (cache_result << 16);
393 attr.type = PERF_TYPE_HW_CACHE; 425 attr.type = PERF_TYPE_HW_CACHE;
394 return add_event(list, idx, &attr, name, NULL); 426
427 if (head_config) {
428 if (config_attr(&attr, head_config, err,
429 config_term_common))
430 return -EINVAL;
431
432 if (get_config_terms(head_config, &config_terms))
433 return -ENOMEM;
434 }
435 return add_event(list, idx, &attr, config_name ? : name, &config_terms);
395} 436}
396 437
397static void tracepoint_error(struct parse_events_error *e, int err, 438static void tracepoint_error(struct parse_events_error *e, int err,
@@ -540,6 +581,7 @@ static int add_tracepoint_multi_sys(struct list_head *list, int *idx,
540struct __add_bpf_event_param { 581struct __add_bpf_event_param {
541 struct parse_events_evlist *data; 582 struct parse_events_evlist *data;
542 struct list_head *list; 583 struct list_head *list;
584 struct list_head *head_config;
543}; 585};
544 586
545static int add_bpf_event(struct probe_trace_event *tev, int fd, 587static int add_bpf_event(struct probe_trace_event *tev, int fd,
@@ -556,7 +598,8 @@ static int add_bpf_event(struct probe_trace_event *tev, int fd,
556 tev->group, tev->event, fd); 598 tev->group, tev->event, fd);
557 599
558 err = parse_events_add_tracepoint(&new_evsels, &evlist->idx, tev->group, 600 err = parse_events_add_tracepoint(&new_evsels, &evlist->idx, tev->group,
559 tev->event, evlist->error, NULL); 601 tev->event, evlist->error,
602 param->head_config);
560 if (err) { 603 if (err) {
561 struct perf_evsel *evsel, *tmp; 604 struct perf_evsel *evsel, *tmp;
562 605
@@ -581,11 +624,12 @@ static int add_bpf_event(struct probe_trace_event *tev, int fd,
581 624
582int parse_events_load_bpf_obj(struct parse_events_evlist *data, 625int parse_events_load_bpf_obj(struct parse_events_evlist *data,
583 struct list_head *list, 626 struct list_head *list,
584 struct bpf_object *obj) 627 struct bpf_object *obj,
628 struct list_head *head_config)
585{ 629{
586 int err; 630 int err;
587 char errbuf[BUFSIZ]; 631 char errbuf[BUFSIZ];
588 struct __add_bpf_event_param param = {data, list}; 632 struct __add_bpf_event_param param = {data, list, head_config};
589 static bool registered_unprobe_atexit = false; 633 static bool registered_unprobe_atexit = false;
590 634
591 if (IS_ERR(obj) || !obj) { 635 if (IS_ERR(obj) || !obj) {
@@ -631,17 +675,99 @@ errout:
631 return err; 675 return err;
632} 676}
633 677
678static int
679parse_events_config_bpf(struct parse_events_evlist *data,
680 struct bpf_object *obj,
681 struct list_head *head_config)
682{
683 struct parse_events_term *term;
684 int error_pos;
685
686 if (!head_config || list_empty(head_config))
687 return 0;
688
689 list_for_each_entry(term, head_config, list) {
690 char errbuf[BUFSIZ];
691 int err;
692
693 if (term->type_term != PARSE_EVENTS__TERM_TYPE_USER) {
694 snprintf(errbuf, sizeof(errbuf),
695 "Invalid config term for BPF object");
696 errbuf[BUFSIZ - 1] = '\0';
697
698 data->error->idx = term->err_term;
699 data->error->str = strdup(errbuf);
700 return -EINVAL;
701 }
702
703 err = bpf__config_obj(obj, term, data->evlist, &error_pos);
704 if (err) {
705 bpf__strerror_config_obj(obj, term, data->evlist,
706 &error_pos, err, errbuf,
707 sizeof(errbuf));
708 data->error->help = strdup(
709"Hint:\tValid config terms:\n"
710" \tmap:[<arraymap>].value<indices>=[value]\n"
711" \tmap:[<eventmap>].event<indices>=[event]\n"
712"\n"
713" \twhere <indices> is something like [0,3...5] or [all]\n"
714" \t(add -v to see detail)");
715 data->error->str = strdup(errbuf);
716 if (err == -BPF_LOADER_ERRNO__OBJCONF_MAP_VALUE)
717 data->error->idx = term->err_val;
718 else
719 data->error->idx = term->err_term + error_pos;
720 return err;
721 }
722 }
723 return 0;
724}
725
726/*
727 * Split config terms:
728 * perf record -e bpf.c/call-graph=fp,map:array.value[0]=1/ ...
729 * 'call-graph=fp' is 'evt config', should be applied to each
730 * events in bpf.c.
731 * 'map:array.value[0]=1' is 'obj config', should be processed
732 * with parse_events_config_bpf.
733 *
734 * Move object config terms from the first list to obj_head_config.
735 */
736static void
737split_bpf_config_terms(struct list_head *evt_head_config,
738 struct list_head *obj_head_config)
739{
740 struct parse_events_term *term, *temp;
741
742 /*
743 * Currectly, all possible user config term
744 * belong to bpf object. parse_events__is_hardcoded_term()
745 * happends to be a good flag.
746 *
747 * See parse_events_config_bpf() and
748 * config_term_tracepoint().
749 */
750 list_for_each_entry_safe(term, temp, evt_head_config, list)
751 if (!parse_events__is_hardcoded_term(term))
752 list_move_tail(&term->list, obj_head_config);
753}
754
634int parse_events_load_bpf(struct parse_events_evlist *data, 755int parse_events_load_bpf(struct parse_events_evlist *data,
635 struct list_head *list, 756 struct list_head *list,
636 char *bpf_file_name, 757 char *bpf_file_name,
637 bool source) 758 bool source,
759 struct list_head *head_config)
638{ 760{
761 int err;
639 struct bpf_object *obj; 762 struct bpf_object *obj;
763 LIST_HEAD(obj_head_config);
764
765 if (head_config)
766 split_bpf_config_terms(head_config, &obj_head_config);
640 767
641 obj = bpf__prepare_load(bpf_file_name, source); 768 obj = bpf__prepare_load(bpf_file_name, source);
642 if (IS_ERR(obj)) { 769 if (IS_ERR(obj)) {
643 char errbuf[BUFSIZ]; 770 char errbuf[BUFSIZ];
644 int err;
645 771
646 err = PTR_ERR(obj); 772 err = PTR_ERR(obj);
647 773
@@ -659,7 +785,18 @@ int parse_events_load_bpf(struct parse_events_evlist *data,
659 return err; 785 return err;
660 } 786 }
661 787
662 return parse_events_load_bpf_obj(data, list, obj); 788 err = parse_events_load_bpf_obj(data, list, obj, head_config);
789 if (err)
790 return err;
791 err = parse_events_config_bpf(data, obj, &obj_head_config);
792
793 /*
794 * Caller doesn't know anything about obj_head_config,
795 * so combine them together again before returnning.
796 */
797 if (head_config)
798 list_splice_tail(&obj_head_config, head_config);
799 return err;
663} 800}
664 801
665static int 802static int
@@ -746,9 +883,59 @@ static int check_type_val(struct parse_events_term *term,
746 return -EINVAL; 883 return -EINVAL;
747} 884}
748 885
749typedef int config_term_func_t(struct perf_event_attr *attr, 886/*
750 struct parse_events_term *term, 887 * Update according to parse-events.l
751 struct parse_events_error *err); 888 */
889static const char *config_term_names[__PARSE_EVENTS__TERM_TYPE_NR] = {
890 [PARSE_EVENTS__TERM_TYPE_USER] = "<sysfs term>",
891 [PARSE_EVENTS__TERM_TYPE_CONFIG] = "config",
892 [PARSE_EVENTS__TERM_TYPE_CONFIG1] = "config1",
893 [PARSE_EVENTS__TERM_TYPE_CONFIG2] = "config2",
894 [PARSE_EVENTS__TERM_TYPE_NAME] = "name",
895 [PARSE_EVENTS__TERM_TYPE_SAMPLE_PERIOD] = "period",
896 [PARSE_EVENTS__TERM_TYPE_SAMPLE_FREQ] = "freq",
897 [PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE] = "branch_type",
898 [PARSE_EVENTS__TERM_TYPE_TIME] = "time",
899 [PARSE_EVENTS__TERM_TYPE_CALLGRAPH] = "call-graph",
900 [PARSE_EVENTS__TERM_TYPE_STACKSIZE] = "stack-size",
901 [PARSE_EVENTS__TERM_TYPE_NOINHERIT] = "no-inherit",
902 [PARSE_EVENTS__TERM_TYPE_INHERIT] = "inherit",
903};
904
905static bool config_term_shrinked;
906
907static bool
908config_term_avail(int term_type, struct parse_events_error *err)
909{
910 if (term_type < 0 || term_type >= __PARSE_EVENTS__TERM_TYPE_NR) {
911 err->str = strdup("Invalid term_type");
912 return false;
913 }
914 if (!config_term_shrinked)
915 return true;
916
917 switch (term_type) {
918 case PARSE_EVENTS__TERM_TYPE_CONFIG:
919 case PARSE_EVENTS__TERM_TYPE_CONFIG1:
920 case PARSE_EVENTS__TERM_TYPE_CONFIG2:
921 case PARSE_EVENTS__TERM_TYPE_NAME:
922 return true;
923 default:
924 if (!err)
925 return false;
926
927 /* term_type is validated so indexing is safe */
928 if (asprintf(&err->str, "'%s' is not usable in 'perf stat'",
929 config_term_names[term_type]) < 0)
930 err->str = NULL;
931 return false;
932 }
933}
934
935void parse_events__shrink_config_terms(void)
936{
937 config_term_shrinked = true;
938}
752 939
753static int config_term_common(struct perf_event_attr *attr, 940static int config_term_common(struct perf_event_attr *attr,
754 struct parse_events_term *term, 941 struct parse_events_term *term,
@@ -815,6 +1002,17 @@ do { \
815 return -EINVAL; 1002 return -EINVAL;
816 } 1003 }
817 1004
1005 /*
1006 * Check term availbility after basic checking so
1007 * PARSE_EVENTS__TERM_TYPE_USER can be found and filtered.
1008 *
1009 * If check availbility at the entry of this function,
1010 * user will see "'<sysfs term>' is not usable in 'perf stat'"
1011 * if an invalid config term is provided for legacy events
1012 * (for example, instructions/badterm/...), which is confusing.
1013 */
1014 if (!config_term_avail(term->type_term, err))
1015 return -EINVAL;
818 return 0; 1016 return 0;
819#undef CHECK_TYPE_VAL 1017#undef CHECK_TYPE_VAL
820} 1018}
@@ -961,23 +1159,8 @@ int parse_events_add_numeric(struct parse_events_evlist *data,
961 return -ENOMEM; 1159 return -ENOMEM;
962 } 1160 }
963 1161
964 return add_event(list, &data->idx, &attr, NULL, &config_terms); 1162 return add_event(list, &data->idx, &attr,
965} 1163 get_config_name(head_config), &config_terms);
966
967static int parse_events__is_name_term(struct parse_events_term *term)
968{
969 return term->type_term == PARSE_EVENTS__TERM_TYPE_NAME;
970}
971
972static char *pmu_event_name(struct list_head *head_terms)
973{
974 struct parse_events_term *term;
975
976 list_for_each_entry(term, head_terms, list)
977 if (parse_events__is_name_term(term))
978 return term->val.str;
979
980 return NULL;
981} 1164}
982 1165
983int parse_events_add_pmu(struct parse_events_evlist *data, 1166int parse_events_add_pmu(struct parse_events_evlist *data,
@@ -1024,7 +1207,7 @@ int parse_events_add_pmu(struct parse_events_evlist *data,
1024 return -EINVAL; 1207 return -EINVAL;
1025 1208
1026 evsel = __add_event(list, &data->idx, &attr, 1209 evsel = __add_event(list, &data->idx, &attr,
1027 pmu_event_name(head_config), pmu->cpus, 1210 get_config_name(head_config), pmu->cpus,
1028 &config_terms); 1211 &config_terms);
1029 if (evsel) { 1212 if (evsel) {
1030 evsel->unit = info.unit; 1213 evsel->unit = info.unit;
@@ -1386,8 +1569,7 @@ int parse_events_terms(struct list_head *terms, const char *str)
1386 return 0; 1569 return 0;
1387 } 1570 }
1388 1571
1389 if (data.terms) 1572 parse_events_terms__delete(data.terms);
1390 parse_events__free_terms(data.terms);
1391 return ret; 1573 return ret;
1392} 1574}
1393 1575
@@ -1395,9 +1577,10 @@ int parse_events(struct perf_evlist *evlist, const char *str,
1395 struct parse_events_error *err) 1577 struct parse_events_error *err)
1396{ 1578{
1397 struct parse_events_evlist data = { 1579 struct parse_events_evlist data = {
1398 .list = LIST_HEAD_INIT(data.list), 1580 .list = LIST_HEAD_INIT(data.list),
1399 .idx = evlist->nr_entries, 1581 .idx = evlist->nr_entries,
1400 .error = err, 1582 .error = err,
1583 .evlist = evlist,
1401 }; 1584 };
1402 int ret; 1585 int ret;
1403 1586
@@ -2068,12 +2251,29 @@ int parse_events_term__clone(struct parse_events_term **new,
2068 term->err_term, term->err_val); 2251 term->err_term, term->err_val);
2069} 2252}
2070 2253
2071void parse_events__free_terms(struct list_head *terms) 2254void parse_events_terms__purge(struct list_head *terms)
2072{ 2255{
2073 struct parse_events_term *term, *h; 2256 struct parse_events_term *term, *h;
2074 2257
2075 list_for_each_entry_safe(term, h, terms, list) 2258 list_for_each_entry_safe(term, h, terms, list) {
2259 if (term->array.nr_ranges)
2260 free(term->array.ranges);
2261 list_del_init(&term->list);
2076 free(term); 2262 free(term);
2263 }
2264}
2265
2266void parse_events_terms__delete(struct list_head *terms)
2267{
2268 if (!terms)
2269 return;
2270 parse_events_terms__purge(terms);
2271 free(terms);
2272}
2273
2274void parse_events__clear_array(struct parse_events_array *a)
2275{
2276 free(a->ranges);
2077} 2277}
2078 2278
2079void parse_events_evlist_error(struct parse_events_evlist *data, 2279void parse_events_evlist_error(struct parse_events_evlist *data,
@@ -2088,6 +2288,33 @@ void parse_events_evlist_error(struct parse_events_evlist *data,
2088 WARN_ONCE(!err->str, "WARNING: failed to allocate error string"); 2288 WARN_ONCE(!err->str, "WARNING: failed to allocate error string");
2089} 2289}
2090 2290
2291static void config_terms_list(char *buf, size_t buf_sz)
2292{
2293 int i;
2294 bool first = true;
2295
2296 buf[0] = '\0';
2297 for (i = 0; i < __PARSE_EVENTS__TERM_TYPE_NR; i++) {
2298 const char *name = config_term_names[i];
2299
2300 if (!config_term_avail(i, NULL))
2301 continue;
2302 if (!name)
2303 continue;
2304 if (name[0] == '<')
2305 continue;
2306
2307 if (strlen(buf) + strlen(name) + 2 >= buf_sz)
2308 return;
2309
2310 if (!first)
2311 strcat(buf, ",");
2312 else
2313 first = false;
2314 strcat(buf, name);
2315 }
2316}
2317
2091/* 2318/*
2092 * Return string contains valid config terms of an event. 2319 * Return string contains valid config terms of an event.
2093 * @additional_terms: For terms such as PMU sysfs terms. 2320 * @additional_terms: For terms such as PMU sysfs terms.
@@ -2095,17 +2322,18 @@ void parse_events_evlist_error(struct parse_events_evlist *data,
2095char *parse_events_formats_error_string(char *additional_terms) 2322char *parse_events_formats_error_string(char *additional_terms)
2096{ 2323{
2097 char *str; 2324 char *str;
2098 static const char *static_terms = "config,config1,config2,name," 2325 /* "branch_type" is the longest name */
2099 "period,freq,branch_type,time," 2326 char static_terms[__PARSE_EVENTS__TERM_TYPE_NR *
2100 "call-graph,stack-size\n"; 2327 (sizeof("branch_type") - 1)];
2101 2328
2329 config_terms_list(static_terms, sizeof(static_terms));
2102 /* valid terms */ 2330 /* valid terms */
2103 if (additional_terms) { 2331 if (additional_terms) {
2104 if (!asprintf(&str, "valid terms: %s,%s", 2332 if (asprintf(&str, "valid terms: %s,%s",
2105 additional_terms, static_terms)) 2333 additional_terms, static_terms) < 0)
2106 goto fail; 2334 goto fail;
2107 } else { 2335 } else {
2108 if (!asprintf(&str, "valid terms: %s", static_terms)) 2336 if (asprintf(&str, "valid terms: %s", static_terms) < 0)
2109 goto fail; 2337 goto fail;
2110 } 2338 }
2111 return str; 2339 return str;
diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h
index f1a6db107241..d740c3ca9a1d 100644
--- a/tools/perf/util/parse-events.h
+++ b/tools/perf/util/parse-events.h
@@ -22,19 +22,18 @@ struct tracepoint_path {
22 struct tracepoint_path *next; 22 struct tracepoint_path *next;
23}; 23};
24 24
25extern struct tracepoint_path *tracepoint_id_to_path(u64 config); 25struct tracepoint_path *tracepoint_id_to_path(u64 config);
26extern struct tracepoint_path *tracepoint_name_to_path(const char *name); 26struct tracepoint_path *tracepoint_name_to_path(const char *name);
27extern bool have_tracepoints(struct list_head *evlist); 27bool have_tracepoints(struct list_head *evlist);
28 28
29const char *event_type(int type); 29const char *event_type(int type);
30 30
31extern int parse_events_option(const struct option *opt, const char *str, 31int parse_events_option(const struct option *opt, const char *str, int unset);
32 int unset); 32int parse_events(struct perf_evlist *evlist, const char *str,
33extern int parse_events(struct perf_evlist *evlist, const char *str, 33 struct parse_events_error *error);
34 struct parse_events_error *error); 34int parse_events_terms(struct list_head *terms, const char *str);
35extern int parse_events_terms(struct list_head *terms, const char *str); 35int parse_filter(const struct option *opt, const char *str, int unset);
36extern int parse_filter(const struct option *opt, const char *str, int unset); 36int exclude_perf(const struct option *opt, const char *arg, int unset);
37extern int exclude_perf(const struct option *opt, const char *arg, int unset);
38 37
39#define EVENTS_HELP_MAX (128*1024) 38#define EVENTS_HELP_MAX (128*1024)
40 39
@@ -68,11 +67,21 @@ enum {
68 PARSE_EVENTS__TERM_TYPE_CALLGRAPH, 67 PARSE_EVENTS__TERM_TYPE_CALLGRAPH,
69 PARSE_EVENTS__TERM_TYPE_STACKSIZE, 68 PARSE_EVENTS__TERM_TYPE_STACKSIZE,
70 PARSE_EVENTS__TERM_TYPE_NOINHERIT, 69 PARSE_EVENTS__TERM_TYPE_NOINHERIT,
71 PARSE_EVENTS__TERM_TYPE_INHERIT 70 PARSE_EVENTS__TERM_TYPE_INHERIT,
71 __PARSE_EVENTS__TERM_TYPE_NR,
72};
73
74struct parse_events_array {
75 size_t nr_ranges;
76 struct {
77 unsigned int start;
78 size_t length;
79 } *ranges;
72}; 80};
73 81
74struct parse_events_term { 82struct parse_events_term {
75 char *config; 83 char *config;
84 struct parse_events_array array;
76 union { 85 union {
77 char *str; 86 char *str;
78 u64 num; 87 u64 num;
@@ -98,12 +107,14 @@ struct parse_events_evlist {
98 int idx; 107 int idx;
99 int nr_groups; 108 int nr_groups;
100 struct parse_events_error *error; 109 struct parse_events_error *error;
110 struct perf_evlist *evlist;
101}; 111};
102 112
103struct parse_events_terms { 113struct parse_events_terms {
104 struct list_head *terms; 114 struct list_head *terms;
105}; 115};
106 116
117void parse_events__shrink_config_terms(void);
107int parse_events__is_hardcoded_term(struct parse_events_term *term); 118int parse_events__is_hardcoded_term(struct parse_events_term *term);
108int parse_events_term__num(struct parse_events_term **term, 119int parse_events_term__num(struct parse_events_term **term,
109 int type_term, char *config, u64 num, 120 int type_term, char *config, u64 num,
@@ -115,7 +126,9 @@ int parse_events_term__sym_hw(struct parse_events_term **term,
115 char *config, unsigned idx); 126 char *config, unsigned idx);
116int parse_events_term__clone(struct parse_events_term **new, 127int parse_events_term__clone(struct parse_events_term **new,
117 struct parse_events_term *term); 128 struct parse_events_term *term);
118void parse_events__free_terms(struct list_head *terms); 129void parse_events_terms__delete(struct list_head *terms);
130void parse_events_terms__purge(struct list_head *terms);
131void parse_events__clear_array(struct parse_events_array *a);
119int parse_events__modifier_event(struct list_head *list, char *str, bool add); 132int parse_events__modifier_event(struct list_head *list, char *str, bool add);
120int parse_events__modifier_group(struct list_head *list, char *event_mod); 133int parse_events__modifier_group(struct list_head *list, char *event_mod);
121int parse_events_name(struct list_head *list, char *name); 134int parse_events_name(struct list_head *list, char *name);
@@ -126,18 +139,22 @@ int parse_events_add_tracepoint(struct list_head *list, int *idx,
126int parse_events_load_bpf(struct parse_events_evlist *data, 139int parse_events_load_bpf(struct parse_events_evlist *data,
127 struct list_head *list, 140 struct list_head *list,
128 char *bpf_file_name, 141 char *bpf_file_name,
129 bool source); 142 bool source,
143 struct list_head *head_config);
130/* Provide this function for perf test */ 144/* Provide this function for perf test */
131struct bpf_object; 145struct bpf_object;
132int parse_events_load_bpf_obj(struct parse_events_evlist *data, 146int parse_events_load_bpf_obj(struct parse_events_evlist *data,
133 struct list_head *list, 147 struct list_head *list,
134 struct bpf_object *obj); 148 struct bpf_object *obj,
149 struct list_head *head_config);
135int parse_events_add_numeric(struct parse_events_evlist *data, 150int parse_events_add_numeric(struct parse_events_evlist *data,
136 struct list_head *list, 151 struct list_head *list,
137 u32 type, u64 config, 152 u32 type, u64 config,
138 struct list_head *head_config); 153 struct list_head *head_config);
139int parse_events_add_cache(struct list_head *list, int *idx, 154int parse_events_add_cache(struct list_head *list, int *idx,
140 char *type, char *op_result1, char *op_result2); 155 char *type, char *op_result1, char *op_result2,
156 struct parse_events_error *error,
157 struct list_head *head_config);
141int parse_events_add_breakpoint(struct list_head *list, int *idx, 158int parse_events_add_breakpoint(struct list_head *list, int *idx,
142 void *ptr, char *type, u64 len); 159 void *ptr, char *type, u64 len);
143int parse_events_add_pmu(struct parse_events_evlist *data, 160int parse_events_add_pmu(struct parse_events_evlist *data,
@@ -165,7 +182,7 @@ void print_symbol_events(const char *event_glob, unsigned type,
165void print_tracepoint_events(const char *subsys_glob, const char *event_glob, 182void print_tracepoint_events(const char *subsys_glob, const char *event_glob,
166 bool name_only); 183 bool name_only);
167int print_hwcache_events(const char *event_glob, bool name_only); 184int print_hwcache_events(const char *event_glob, bool name_only);
168extern int is_valid_tracepoint(const char *event_string); 185int is_valid_tracepoint(const char *event_string);
169 186
170int valid_event_mount(const char *eventfs); 187int valid_event_mount(const char *eventfs);
171char *parse_events_formats_error_string(char *additional_terms); 188char *parse_events_formats_error_string(char *additional_terms);
diff --git a/tools/perf/util/parse-events.l b/tools/perf/util/parse-events.l
index 58c5831ffd5c..1477fbc78993 100644
--- a/tools/perf/util/parse-events.l
+++ b/tools/perf/util/parse-events.l
@@ -9,8 +9,8 @@
9%{ 9%{
10#include <errno.h> 10#include <errno.h>
11#include "../perf.h" 11#include "../perf.h"
12#include "parse-events-bison.h"
13#include "parse-events.h" 12#include "parse-events.h"
13#include "parse-events-bison.h"
14 14
15char *parse_events_get_text(yyscan_t yyscanner); 15char *parse_events_get_text(yyscan_t yyscanner);
16YYSTYPE *parse_events_get_lval(yyscan_t yyscanner); 16YYSTYPE *parse_events_get_lval(yyscan_t yyscanner);
@@ -111,6 +111,7 @@ do { \
111%x mem 111%x mem
112%s config 112%s config
113%x event 113%x event
114%x array
114 115
115group [^,{}/]*[{][^}]*[}][^,{}/]* 116group [^,{}/]*[{][^}]*[}][^,{}/]*
116event_pmu [^,{}/]+[/][^/]*[/][^,{}/]* 117event_pmu [^,{}/]+[/][^/]*[/][^,{}/]*
@@ -122,7 +123,7 @@ num_dec [0-9]+
122num_hex 0x[a-fA-F0-9]+ 123num_hex 0x[a-fA-F0-9]+
123num_raw_hex [a-fA-F0-9]+ 124num_raw_hex [a-fA-F0-9]+
124name [a-zA-Z_*?][a-zA-Z0-9_*?.]* 125name [a-zA-Z_*?][a-zA-Z0-9_*?.]*
125name_minus [a-zA-Z_*?][a-zA-Z0-9\-_*?.]* 126name_minus [a-zA-Z_*?][a-zA-Z0-9\-_*?.:]*
126/* If you add a modifier you need to update check_modifier() */ 127/* If you add a modifier you need to update check_modifier() */
127modifier_event [ukhpPGHSDI]+ 128modifier_event [ukhpPGHSDI]+
128modifier_bp [rwx]{1,3} 129modifier_bp [rwx]{1,3}
@@ -176,10 +177,17 @@ modifier_bp [rwx]{1,3}
176 177
177} 178}
178 179
180<array>{
181"]" { BEGIN(config); return ']'; }
182{num_dec} { return value(yyscanner, 10); }
183{num_hex} { return value(yyscanner, 16); }
184, { return ','; }
185"\.\.\." { return PE_ARRAY_RANGE; }
186}
187
179<config>{ 188<config>{
180 /* 189 /*
181 * Please update parse_events_formats_error_string any time 190 * Please update config_term_names when new static term is added.
182 * new static term is added.
183 */ 191 */
184config { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_CONFIG); } 192config { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_CONFIG); }
185config1 { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_CONFIG1); } 193config1 { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_CONFIG1); }
@@ -196,6 +204,8 @@ no-inherit { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_NOINHERIT); }
196, { return ','; } 204, { return ','; }
197"/" { BEGIN(INITIAL); return '/'; } 205"/" { BEGIN(INITIAL); return '/'; }
198{name_minus} { return str(yyscanner, PE_NAME); } 206{name_minus} { return str(yyscanner, PE_NAME); }
207\[all\] { return PE_ARRAY_ALL; }
208"[" { BEGIN(array); return '['; }
199} 209}
200 210
201<mem>{ 211<mem>{
@@ -238,6 +248,7 @@ cpu-migrations|migrations { return sym(yyscanner, PERF_TYPE_SOFTWARE, PERF_COU
238alignment-faults { return sym(yyscanner, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_ALIGNMENT_FAULTS); } 248alignment-faults { return sym(yyscanner, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_ALIGNMENT_FAULTS); }
239emulation-faults { return sym(yyscanner, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_EMULATION_FAULTS); } 249emulation-faults { return sym(yyscanner, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_EMULATION_FAULTS); }
240dummy { return sym(yyscanner, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_DUMMY); } 250dummy { return sym(yyscanner, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_DUMMY); }
251bpf-output { return sym(yyscanner, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_BPF_OUTPUT); }
241 252
242 /* 253 /*
243 * We have to handle the kernel PMU event cycles-ct/cycles-t/mem-loads/mem-stores separately. 254 * We have to handle the kernel PMU event cycles-ct/cycles-t/mem-loads/mem-stores separately.
diff --git a/tools/perf/util/parse-events.y b/tools/perf/util/parse-events.y
index ad379968d4c1..5be4a5f216d6 100644
--- a/tools/perf/util/parse-events.y
+++ b/tools/perf/util/parse-events.y
@@ -28,7 +28,7 @@ do { \
28 INIT_LIST_HEAD(list); \ 28 INIT_LIST_HEAD(list); \
29} while (0) 29} while (0)
30 30
31static inc_group_count(struct list_head *list, 31static void inc_group_count(struct list_head *list,
32 struct parse_events_evlist *data) 32 struct parse_events_evlist *data)
33{ 33{
34 /* Count groups only have more than 1 members */ 34 /* Count groups only have more than 1 members */
@@ -48,6 +48,7 @@ static inc_group_count(struct list_head *list,
48%token PE_PREFIX_MEM PE_PREFIX_RAW PE_PREFIX_GROUP 48%token PE_PREFIX_MEM PE_PREFIX_RAW PE_PREFIX_GROUP
49%token PE_ERROR 49%token PE_ERROR
50%token PE_PMU_EVENT_PRE PE_PMU_EVENT_SUF PE_KERNEL_PMU_EVENT 50%token PE_PMU_EVENT_PRE PE_PMU_EVENT_SUF PE_KERNEL_PMU_EVENT
51%token PE_ARRAY_ALL PE_ARRAY_RANGE
51%type <num> PE_VALUE 52%type <num> PE_VALUE
52%type <num> PE_VALUE_SYM_HW 53%type <num> PE_VALUE_SYM_HW
53%type <num> PE_VALUE_SYM_SW 54%type <num> PE_VALUE_SYM_SW
@@ -64,6 +65,7 @@ static inc_group_count(struct list_head *list,
64%type <str> PE_PMU_EVENT_PRE PE_PMU_EVENT_SUF PE_KERNEL_PMU_EVENT 65%type <str> PE_PMU_EVENT_PRE PE_PMU_EVENT_SUF PE_KERNEL_PMU_EVENT
65%type <num> value_sym 66%type <num> value_sym
66%type <head> event_config 67%type <head> event_config
68%type <head> opt_event_config
67%type <term> event_term 69%type <term> event_term
68%type <head> event_pmu 70%type <head> event_pmu
69%type <head> event_legacy_symbol 71%type <head> event_legacy_symbol
@@ -82,6 +84,9 @@ static inc_group_count(struct list_head *list,
82%type <head> group_def 84%type <head> group_def
83%type <head> group 85%type <head> group
84%type <head> groups 86%type <head> groups
87%type <array> array
88%type <array> array_term
89%type <array> array_terms
85 90
86%union 91%union
87{ 92{
@@ -93,6 +98,7 @@ static inc_group_count(struct list_head *list,
93 char *sys; 98 char *sys;
94 char *event; 99 char *event;
95 } tracepoint_name; 100 } tracepoint_name;
101 struct parse_events_array array;
96} 102}
97%% 103%%
98 104
@@ -211,24 +217,14 @@ event_def: event_pmu |
211 event_bpf_file 217 event_bpf_file
212 218
213event_pmu: 219event_pmu:
214PE_NAME '/' event_config '/' 220PE_NAME opt_event_config
215{ 221{
216 struct parse_events_evlist *data = _data; 222 struct parse_events_evlist *data = _data;
217 struct list_head *list; 223 struct list_head *list;
218 224
219 ALLOC_LIST(list); 225 ALLOC_LIST(list);
220 ABORT_ON(parse_events_add_pmu(data, list, $1, $3)); 226 ABORT_ON(parse_events_add_pmu(data, list, $1, $2));
221 parse_events__free_terms($3); 227 parse_events_terms__delete($2);
222 $$ = list;
223}
224|
225PE_NAME '/' '/'
226{
227 struct parse_events_evlist *data = _data;
228 struct list_head *list;
229
230 ALLOC_LIST(list);
231 ABORT_ON(parse_events_add_pmu(data, list, $1, NULL));
232 $$ = list; 228 $$ = list;
233} 229}
234| 230|
@@ -246,7 +242,7 @@ PE_KERNEL_PMU_EVENT sep_dc
246 242
247 ALLOC_LIST(list); 243 ALLOC_LIST(list);
248 ABORT_ON(parse_events_add_pmu(data, list, "cpu", head)); 244 ABORT_ON(parse_events_add_pmu(data, list, "cpu", head));
249 parse_events__free_terms(head); 245 parse_events_terms__delete(head);
250 $$ = list; 246 $$ = list;
251} 247}
252| 248|
@@ -266,7 +262,7 @@ PE_PMU_EVENT_PRE '-' PE_PMU_EVENT_SUF sep_dc
266 262
267 ALLOC_LIST(list); 263 ALLOC_LIST(list);
268 ABORT_ON(parse_events_add_pmu(data, list, "cpu", head)); 264 ABORT_ON(parse_events_add_pmu(data, list, "cpu", head));
269 parse_events__free_terms(head); 265 parse_events_terms__delete(head);
270 $$ = list; 266 $$ = list;
271} 267}
272 268
@@ -285,7 +281,7 @@ value_sym '/' event_config '/'
285 281
286 ALLOC_LIST(list); 282 ALLOC_LIST(list);
287 ABORT_ON(parse_events_add_numeric(data, list, type, config, $3)); 283 ABORT_ON(parse_events_add_numeric(data, list, type, config, $3));
288 parse_events__free_terms($3); 284 parse_events_terms__delete($3);
289 $$ = list; 285 $$ = list;
290} 286}
291| 287|
@@ -302,33 +298,39 @@ value_sym sep_slash_dc
302} 298}
303 299
304event_legacy_cache: 300event_legacy_cache:
305PE_NAME_CACHE_TYPE '-' PE_NAME_CACHE_OP_RESULT '-' PE_NAME_CACHE_OP_RESULT 301PE_NAME_CACHE_TYPE '-' PE_NAME_CACHE_OP_RESULT '-' PE_NAME_CACHE_OP_RESULT opt_event_config
306{ 302{
307 struct parse_events_evlist *data = _data; 303 struct parse_events_evlist *data = _data;
304 struct parse_events_error *error = data->error;
308 struct list_head *list; 305 struct list_head *list;
309 306
310 ALLOC_LIST(list); 307 ALLOC_LIST(list);
311 ABORT_ON(parse_events_add_cache(list, &data->idx, $1, $3, $5)); 308 ABORT_ON(parse_events_add_cache(list, &data->idx, $1, $3, $5, error, $6));
309 parse_events_terms__delete($6);
312 $$ = list; 310 $$ = list;
313} 311}
314| 312|
315PE_NAME_CACHE_TYPE '-' PE_NAME_CACHE_OP_RESULT 313PE_NAME_CACHE_TYPE '-' PE_NAME_CACHE_OP_RESULT opt_event_config
316{ 314{
317 struct parse_events_evlist *data = _data; 315 struct parse_events_evlist *data = _data;
316 struct parse_events_error *error = data->error;
318 struct list_head *list; 317 struct list_head *list;
319 318
320 ALLOC_LIST(list); 319 ALLOC_LIST(list);
321 ABORT_ON(parse_events_add_cache(list, &data->idx, $1, $3, NULL)); 320 ABORT_ON(parse_events_add_cache(list, &data->idx, $1, $3, NULL, error, $4));
321 parse_events_terms__delete($4);
322 $$ = list; 322 $$ = list;
323} 323}
324| 324|
325PE_NAME_CACHE_TYPE 325PE_NAME_CACHE_TYPE opt_event_config
326{ 326{
327 struct parse_events_evlist *data = _data; 327 struct parse_events_evlist *data = _data;
328 struct parse_events_error *error = data->error;
328 struct list_head *list; 329 struct list_head *list;
329 330
330 ALLOC_LIST(list); 331 ALLOC_LIST(list);
331 ABORT_ON(parse_events_add_cache(list, &data->idx, $1, NULL, NULL)); 332 ABORT_ON(parse_events_add_cache(list, &data->idx, $1, NULL, NULL, error, $2));
333 parse_events_terms__delete($2);
332 $$ = list; 334 $$ = list;
333} 335}
334 336
@@ -378,24 +380,7 @@ PE_PREFIX_MEM PE_VALUE sep_dc
378} 380}
379 381
380event_legacy_tracepoint: 382event_legacy_tracepoint:
381tracepoint_name 383tracepoint_name opt_event_config
382{
383 struct parse_events_evlist *data = _data;
384 struct parse_events_error *error = data->error;
385 struct list_head *list;
386
387 ALLOC_LIST(list);
388 if (error)
389 error->idx = @1.first_column;
390
391 if (parse_events_add_tracepoint(list, &data->idx, $1.sys, $1.event,
392 error, NULL))
393 return -1;
394
395 $$ = list;
396}
397|
398tracepoint_name '/' event_config '/'
399{ 384{
400 struct parse_events_evlist *data = _data; 385 struct parse_events_evlist *data = _data;
401 struct parse_events_error *error = data->error; 386 struct parse_events_error *error = data->error;
@@ -406,7 +391,7 @@ tracepoint_name '/' event_config '/'
406 error->idx = @1.first_column; 391 error->idx = @1.first_column;
407 392
408 if (parse_events_add_tracepoint(list, &data->idx, $1.sys, $1.event, 393 if (parse_events_add_tracepoint(list, &data->idx, $1.sys, $1.event,
409 error, $3)) 394 error, $2))
410 return -1; 395 return -1;
411 396
412 $$ = list; 397 $$ = list;
@@ -433,49 +418,68 @@ PE_NAME ':' PE_NAME
433} 418}
434 419
435event_legacy_numeric: 420event_legacy_numeric:
436PE_VALUE ':' PE_VALUE 421PE_VALUE ':' PE_VALUE opt_event_config
437{ 422{
438 struct parse_events_evlist *data = _data; 423 struct parse_events_evlist *data = _data;
439 struct list_head *list; 424 struct list_head *list;
440 425
441 ALLOC_LIST(list); 426 ALLOC_LIST(list);
442 ABORT_ON(parse_events_add_numeric(data, list, (u32)$1, $3, NULL)); 427 ABORT_ON(parse_events_add_numeric(data, list, (u32)$1, $3, $4));
428 parse_events_terms__delete($4);
443 $$ = list; 429 $$ = list;
444} 430}
445 431
446event_legacy_raw: 432event_legacy_raw:
447PE_RAW 433PE_RAW opt_event_config
448{ 434{
449 struct parse_events_evlist *data = _data; 435 struct parse_events_evlist *data = _data;
450 struct list_head *list; 436 struct list_head *list;
451 437
452 ALLOC_LIST(list); 438 ALLOC_LIST(list);
453 ABORT_ON(parse_events_add_numeric(data, list, PERF_TYPE_RAW, $1, NULL)); 439 ABORT_ON(parse_events_add_numeric(data, list, PERF_TYPE_RAW, $1, $2));
440 parse_events_terms__delete($2);
454 $$ = list; 441 $$ = list;
455} 442}
456 443
457event_bpf_file: 444event_bpf_file:
458PE_BPF_OBJECT 445PE_BPF_OBJECT opt_event_config
459{ 446{
460 struct parse_events_evlist *data = _data; 447 struct parse_events_evlist *data = _data;
461 struct parse_events_error *error = data->error; 448 struct parse_events_error *error = data->error;
462 struct list_head *list; 449 struct list_head *list;
463 450
464 ALLOC_LIST(list); 451 ALLOC_LIST(list);
465 ABORT_ON(parse_events_load_bpf(data, list, $1, false)); 452 ABORT_ON(parse_events_load_bpf(data, list, $1, false, $2));
453 parse_events_terms__delete($2);
466 $$ = list; 454 $$ = list;
467} 455}
468| 456|
469PE_BPF_SOURCE 457PE_BPF_SOURCE opt_event_config
470{ 458{
471 struct parse_events_evlist *data = _data; 459 struct parse_events_evlist *data = _data;
472 struct list_head *list; 460 struct list_head *list;
473 461
474 ALLOC_LIST(list); 462 ALLOC_LIST(list);
475 ABORT_ON(parse_events_load_bpf(data, list, $1, true)); 463 ABORT_ON(parse_events_load_bpf(data, list, $1, true, $2));
464 parse_events_terms__delete($2);
476 $$ = list; 465 $$ = list;
477} 466}
478 467
468opt_event_config:
469'/' event_config '/'
470{
471 $$ = $2;
472}
473|
474'/' '/'
475{
476 $$ = NULL;
477}
478|
479{
480 $$ = NULL;
481}
482
479start_terms: event_config 483start_terms: event_config
480{ 484{
481 struct parse_events_terms *data = _data; 485 struct parse_events_terms *data = _data;
@@ -573,6 +577,86 @@ PE_TERM
573 ABORT_ON(parse_events_term__num(&term, (int)$1, NULL, 1, &@1, NULL)); 577 ABORT_ON(parse_events_term__num(&term, (int)$1, NULL, 1, &@1, NULL));
574 $$ = term; 578 $$ = term;
575} 579}
580|
581PE_NAME array '=' PE_NAME
582{
583 struct parse_events_term *term;
584 int i;
585
586 ABORT_ON(parse_events_term__str(&term, PARSE_EVENTS__TERM_TYPE_USER,
587 $1, $4, &@1, &@4));
588
589 term->array = $2;
590 $$ = term;
591}
592|
593PE_NAME array '=' PE_VALUE
594{
595 struct parse_events_term *term;
596
597 ABORT_ON(parse_events_term__num(&term, PARSE_EVENTS__TERM_TYPE_USER,
598 $1, $4, &@1, &@4));
599 term->array = $2;
600 $$ = term;
601}
602
603array:
604'[' array_terms ']'
605{
606 $$ = $2;
607}
608|
609PE_ARRAY_ALL
610{
611 $$.nr_ranges = 0;
612 $$.ranges = NULL;
613}
614
615array_terms:
616array_terms ',' array_term
617{
618 struct parse_events_array new_array;
619
620 new_array.nr_ranges = $1.nr_ranges + $3.nr_ranges;
621 new_array.ranges = malloc(sizeof(new_array.ranges[0]) *
622 new_array.nr_ranges);
623 ABORT_ON(!new_array.ranges);
624 memcpy(&new_array.ranges[0], $1.ranges,
625 $1.nr_ranges * sizeof(new_array.ranges[0]));
626 memcpy(&new_array.ranges[$1.nr_ranges], $3.ranges,
627 $3.nr_ranges * sizeof(new_array.ranges[0]));
628 free($1.ranges);
629 free($3.ranges);
630 $$ = new_array;
631}
632|
633array_term
634
635array_term:
636PE_VALUE
637{
638 struct parse_events_array array;
639
640 array.nr_ranges = 1;
641 array.ranges = malloc(sizeof(array.ranges[0]));
642 ABORT_ON(!array.ranges);
643 array.ranges[0].start = $1;
644 array.ranges[0].length = 1;
645 $$ = array;
646}
647|
648PE_VALUE PE_ARRAY_RANGE PE_VALUE
649{
650 struct parse_events_array array;
651
652 ABORT_ON($3 < $1);
653 array.nr_ranges = 1;
654 array.ranges = malloc(sizeof(array.ranges[0]));
655 ABORT_ON(!array.ranges);
656 array.ranges[0].start = $1;
657 array.ranges[0].length = $3 - $1 + 1;
658 $$ = array;
659}
576 660
577sep_dc: ':' | 661sep_dc: ':' |
578 662
diff --git a/tools/perf/util/path.c b/tools/perf/util/path.c
index 3654d964e49d..3bf6bf82ff2d 100644
--- a/tools/perf/util/path.c
+++ b/tools/perf/util/path.c
@@ -41,36 +41,6 @@ static char *cleanup_path(char *path)
41 return path; 41 return path;
42} 42}
43 43
44static char *perf_vsnpath(char *buf, size_t n, const char *fmt, va_list args)
45{
46 const char *perf_dir = get_perf_dir();
47 size_t len;
48
49 len = strlen(perf_dir);
50 if (n < len + 1)
51 goto bad;
52 memcpy(buf, perf_dir, len);
53 if (len && !is_dir_sep(perf_dir[len-1]))
54 buf[len++] = '/';
55 len += vsnprintf(buf + len, n - len, fmt, args);
56 if (len >= n)
57 goto bad;
58 return cleanup_path(buf);
59bad:
60 strlcpy(buf, bad_path, n);
61 return buf;
62}
63
64char *perf_pathdup(const char *fmt, ...)
65{
66 char path[PATH_MAX];
67 va_list args;
68 va_start(args, fmt);
69 (void)perf_vsnpath(path, sizeof(path), fmt, args);
70 va_end(args);
71 return xstrdup(path);
72}
73
74char *mkpath(const char *fmt, ...) 44char *mkpath(const char *fmt, ...)
75{ 45{
76 va_list args; 46 va_list args;
diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c
index b597bcc8fc78..adef23b1352e 100644
--- a/tools/perf/util/pmu.c
+++ b/tools/perf/util/pmu.c
@@ -98,7 +98,7 @@ static int perf_pmu__parse_scale(struct perf_pmu_alias *alias, char *dir, char *
98 char scale[128]; 98 char scale[128];
99 int fd, ret = -1; 99 int fd, ret = -1;
100 char path[PATH_MAX]; 100 char path[PATH_MAX];
101 const char *lc; 101 char *lc;
102 102
103 snprintf(path, PATH_MAX, "%s/%s.scale", dir, name); 103 snprintf(path, PATH_MAX, "%s/%s.scale", dir, name);
104 104
@@ -124,6 +124,17 @@ static int perf_pmu__parse_scale(struct perf_pmu_alias *alias, char *dir, char *
124 lc = setlocale(LC_NUMERIC, NULL); 124 lc = setlocale(LC_NUMERIC, NULL);
125 125
126 /* 126 /*
127 * The lc string may be allocated in static storage,
128 * so get a dynamic copy to make it survive setlocale
129 * call below.
130 */
131 lc = strdup(lc);
132 if (!lc) {
133 ret = -ENOMEM;
134 goto error;
135 }
136
137 /*
127 * force to C locale to ensure kernel 138 * force to C locale to ensure kernel
128 * scale string is converted correctly. 139 * scale string is converted correctly.
129 * kernel uses default C locale. 140 * kernel uses default C locale.
@@ -135,6 +146,8 @@ static int perf_pmu__parse_scale(struct perf_pmu_alias *alias, char *dir, char *
135 /* restore locale */ 146 /* restore locale */
136 setlocale(LC_NUMERIC, lc); 147 setlocale(LC_NUMERIC, lc);
137 148
149 free(lc);
150
138 ret = 0; 151 ret = 0;
139error: 152error:
140 close(fd); 153 close(fd);
@@ -153,7 +166,7 @@ static int perf_pmu__parse_unit(struct perf_pmu_alias *alias, char *dir, char *n
153 if (fd == -1) 166 if (fd == -1)
154 return -1; 167 return -1;
155 168
156 sret = read(fd, alias->unit, UNIT_MAX_LEN); 169 sret = read(fd, alias->unit, UNIT_MAX_LEN);
157 if (sret < 0) 170 if (sret < 0)
158 goto error; 171 goto error;
159 172
@@ -284,13 +297,12 @@ static int pmu_aliases_parse(char *dir, struct list_head *head)
284{ 297{
285 struct dirent *evt_ent; 298 struct dirent *evt_ent;
286 DIR *event_dir; 299 DIR *event_dir;
287 int ret = 0;
288 300
289 event_dir = opendir(dir); 301 event_dir = opendir(dir);
290 if (!event_dir) 302 if (!event_dir)
291 return -EINVAL; 303 return -EINVAL;
292 304
293 while (!ret && (evt_ent = readdir(event_dir))) { 305 while ((evt_ent = readdir(event_dir))) {
294 char path[PATH_MAX]; 306 char path[PATH_MAX];
295 char *name = evt_ent->d_name; 307 char *name = evt_ent->d_name;
296 FILE *file; 308 FILE *file;
@@ -306,17 +318,19 @@ static int pmu_aliases_parse(char *dir, struct list_head *head)
306 318
307 snprintf(path, PATH_MAX, "%s/%s", dir, name); 319 snprintf(path, PATH_MAX, "%s/%s", dir, name);
308 320
309 ret = -EINVAL;
310 file = fopen(path, "r"); 321 file = fopen(path, "r");
311 if (!file) 322 if (!file) {
312 break; 323 pr_debug("Cannot open %s\n", path);
324 continue;
325 }
313 326
314 ret = perf_pmu__new_alias(head, dir, name, file); 327 if (perf_pmu__new_alias(head, dir, name, file) < 0)
328 pr_debug("Cannot set up %s\n", name);
315 fclose(file); 329 fclose(file);
316 } 330 }
317 331
318 closedir(event_dir); 332 closedir(event_dir);
319 return ret; 333 return 0;
320} 334}
321 335
322/* 336/*
@@ -354,7 +368,7 @@ static int pmu_alias_terms(struct perf_pmu_alias *alias,
354 list_for_each_entry(term, &alias->terms, list) { 368 list_for_each_entry(term, &alias->terms, list) {
355 ret = parse_events_term__clone(&cloned, term); 369 ret = parse_events_term__clone(&cloned, term);
356 if (ret) { 370 if (ret) {
357 parse_events__free_terms(&list); 371 parse_events_terms__purge(&list);
358 return ret; 372 return ret;
359 } 373 }
360 list_add_tail(&cloned->list, &list); 374 list_add_tail(&cloned->list, &list);
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index 93996ec4bbe3..8319fbb08636 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -2179,7 +2179,7 @@ static int perf_probe_event__sprintf(const char *group, const char *event,
2179 strbuf_addf(result, " in %s", module); 2179 strbuf_addf(result, " in %s", module);
2180 2180
2181 if (pev->nargs > 0) { 2181 if (pev->nargs > 0) {
2182 strbuf_addstr(result, " with"); 2182 strbuf_add(result, " with", 5);
2183 for (i = 0; i < pev->nargs; i++) { 2183 for (i = 0; i < pev->nargs; i++) {
2184 ret = synthesize_perf_probe_arg(&pev->args[i], 2184 ret = synthesize_perf_probe_arg(&pev->args[i],
2185 buf, 128); 2185 buf, 128);
diff --git a/tools/perf/util/probe-event.h b/tools/perf/util/probe-event.h
index ba926c30f8cd..e54e7b011577 100644
--- a/tools/perf/util/probe-event.h
+++ b/tools/perf/util/probe-event.h
@@ -114,49 +114,44 @@ int init_probe_symbol_maps(bool user_only);
114void exit_probe_symbol_maps(void); 114void exit_probe_symbol_maps(void);
115 115
116/* Command string to events */ 116/* Command string to events */
117extern int parse_perf_probe_command(const char *cmd, 117int parse_perf_probe_command(const char *cmd, struct perf_probe_event *pev);
118 struct perf_probe_event *pev); 118int parse_probe_trace_command(const char *cmd, struct probe_trace_event *tev);
119extern int parse_probe_trace_command(const char *cmd,
120 struct probe_trace_event *tev);
121 119
122/* Events to command string */ 120/* Events to command string */
123extern char *synthesize_perf_probe_command(struct perf_probe_event *pev); 121char *synthesize_perf_probe_command(struct perf_probe_event *pev);
124extern char *synthesize_probe_trace_command(struct probe_trace_event *tev); 122char *synthesize_probe_trace_command(struct probe_trace_event *tev);
125extern int synthesize_perf_probe_arg(struct perf_probe_arg *pa, char *buf, 123int synthesize_perf_probe_arg(struct perf_probe_arg *pa, char *buf, size_t len);
126 size_t len);
127 124
128/* Check the perf_probe_event needs debuginfo */ 125/* Check the perf_probe_event needs debuginfo */
129extern bool perf_probe_event_need_dwarf(struct perf_probe_event *pev); 126bool perf_probe_event_need_dwarf(struct perf_probe_event *pev);
130 127
131/* Release event contents */ 128/* Release event contents */
132extern void clear_perf_probe_event(struct perf_probe_event *pev); 129void clear_perf_probe_event(struct perf_probe_event *pev);
133extern void clear_probe_trace_event(struct probe_trace_event *tev); 130void clear_probe_trace_event(struct probe_trace_event *tev);
134 131
135/* Command string to line-range */ 132/* Command string to line-range */
136extern int parse_line_range_desc(const char *cmd, struct line_range *lr); 133int parse_line_range_desc(const char *cmd, struct line_range *lr);
137 134
138/* Release line range members */ 135/* Release line range members */
139extern void line_range__clear(struct line_range *lr); 136void line_range__clear(struct line_range *lr);
140 137
141/* Initialize line range */ 138/* Initialize line range */
142extern int line_range__init(struct line_range *lr); 139int line_range__init(struct line_range *lr);
143 140
144extern int add_perf_probe_events(struct perf_probe_event *pevs, int npevs); 141int add_perf_probe_events(struct perf_probe_event *pevs, int npevs);
145extern int convert_perf_probe_events(struct perf_probe_event *pevs, int npevs); 142int convert_perf_probe_events(struct perf_probe_event *pevs, int npevs);
146extern int apply_perf_probe_events(struct perf_probe_event *pevs, int npevs); 143int apply_perf_probe_events(struct perf_probe_event *pevs, int npevs);
147extern void cleanup_perf_probe_events(struct perf_probe_event *pevs, int npevs); 144void cleanup_perf_probe_events(struct perf_probe_event *pevs, int npevs);
148extern int del_perf_probe_events(struct strfilter *filter); 145int del_perf_probe_events(struct strfilter *filter);
149 146
150extern int show_perf_probe_event(const char *group, const char *event, 147int show_perf_probe_event(const char *group, const char *event,
151 struct perf_probe_event *pev, 148 struct perf_probe_event *pev,
152 const char *module, bool use_stdout); 149 const char *module, bool use_stdout);
153extern int show_perf_probe_events(struct strfilter *filter); 150int show_perf_probe_events(struct strfilter *filter);
154extern int show_line_range(struct line_range *lr, const char *module, 151int show_line_range(struct line_range *lr, const char *module, bool user);
155 bool user); 152int show_available_vars(struct perf_probe_event *pevs, int npevs,
156extern int show_available_vars(struct perf_probe_event *pevs, int npevs, 153 struct strfilter *filter);
157 struct strfilter *filter); 154int show_available_funcs(const char *module, struct strfilter *filter, bool user);
158extern int show_available_funcs(const char *module, struct strfilter *filter,
159 bool user);
160bool arch__prefers_symtab(void); 155bool arch__prefers_symtab(void);
161void arch__fix_tev_from_maps(struct perf_probe_event *pev, 156void arch__fix_tev_from_maps(struct perf_probe_event *pev,
162 struct probe_trace_event *tev, struct map *map); 157 struct probe_trace_event *tev, struct map *map);
diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c
index 4ce5c5e18f48..b3bd0fba0237 100644
--- a/tools/perf/util/probe-finder.c
+++ b/tools/perf/util/probe-finder.c
@@ -1314,18 +1314,18 @@ static int collect_variables_cb(Dwarf_Die *die_mem, void *data)
1314 if (probe_conf.show_location_range) { 1314 if (probe_conf.show_location_range) {
1315 if (!externs) { 1315 if (!externs) {
1316 if (ret) 1316 if (ret)
1317 strbuf_addf(&buf, "[INV]\t"); 1317 strbuf_add(&buf, "[INV]\t", 6);
1318 else 1318 else
1319 strbuf_addf(&buf, "[VAL]\t"); 1319 strbuf_add(&buf, "[VAL]\t", 6);
1320 } else 1320 } else
1321 strbuf_addf(&buf, "[EXT]\t"); 1321 strbuf_add(&buf, "[EXT]\t", 6);
1322 } 1322 }
1323 1323
1324 ret2 = die_get_varname(die_mem, &buf); 1324 ret2 = die_get_varname(die_mem, &buf);
1325 1325
1326 if (!ret2 && probe_conf.show_location_range && 1326 if (!ret2 && probe_conf.show_location_range &&
1327 !externs) { 1327 !externs) {
1328 strbuf_addf(&buf, "\t"); 1328 strbuf_addch(&buf, '\t');
1329 ret2 = die_get_var_range(&af->pf.sp_die, 1329 ret2 = die_get_var_range(&af->pf.sp_die,
1330 die_mem, &buf); 1330 die_mem, &buf);
1331 } 1331 }
diff --git a/tools/perf/util/probe-finder.h b/tools/perf/util/probe-finder.h
index 0aec7704e395..51137fccb9c8 100644
--- a/tools/perf/util/probe-finder.h
+++ b/tools/perf/util/probe-finder.h
@@ -34,27 +34,25 @@ struct debuginfo {
34}; 34};
35 35
36/* This also tries to open distro debuginfo */ 36/* This also tries to open distro debuginfo */
37extern struct debuginfo *debuginfo__new(const char *path); 37struct debuginfo *debuginfo__new(const char *path);
38extern void debuginfo__delete(struct debuginfo *dbg); 38void debuginfo__delete(struct debuginfo *dbg);
39 39
40/* Find probe_trace_events specified by perf_probe_event from debuginfo */ 40/* Find probe_trace_events specified by perf_probe_event from debuginfo */
41extern int debuginfo__find_trace_events(struct debuginfo *dbg, 41int debuginfo__find_trace_events(struct debuginfo *dbg,
42 struct perf_probe_event *pev, 42 struct perf_probe_event *pev,
43 struct probe_trace_event **tevs); 43 struct probe_trace_event **tevs);
44 44
45/* Find a perf_probe_point from debuginfo */ 45/* Find a perf_probe_point from debuginfo */
46extern int debuginfo__find_probe_point(struct debuginfo *dbg, 46int debuginfo__find_probe_point(struct debuginfo *dbg, unsigned long addr,
47 unsigned long addr, 47 struct perf_probe_point *ppt);
48 struct perf_probe_point *ppt);
49 48
50/* Find a line range */ 49/* Find a line range */
51extern int debuginfo__find_line_range(struct debuginfo *dbg, 50int debuginfo__find_line_range(struct debuginfo *dbg, struct line_range *lr);
52 struct line_range *lr);
53 51
54/* Find available variables */ 52/* Find available variables */
55extern int debuginfo__find_available_vars_at(struct debuginfo *dbg, 53int debuginfo__find_available_vars_at(struct debuginfo *dbg,
56 struct perf_probe_event *pev, 54 struct perf_probe_event *pev,
57 struct variable_list **vls); 55 struct variable_list **vls);
58 56
59/* Find a src file from a DWARF tag path */ 57/* Find a src file from a DWARF tag path */
60int get_real_path(const char *raw_path, const char *comp_dir, 58int get_real_path(const char *raw_path, const char *comp_dir,
diff --git a/tools/perf/util/quote.h b/tools/perf/util/quote.h
index 172889ea234f..3340c9c4a6ca 100644
--- a/tools/perf/util/quote.h
+++ b/tools/perf/util/quote.h
@@ -24,6 +24,6 @@
24 * sq_quote() in a real application. 24 * sq_quote() in a real application.
25 */ 25 */
26 26
27extern void sq_quote_argv(struct strbuf *, const char **argv, size_t maxlen); 27void sq_quote_argv(struct strbuf *, const char **argv, size_t maxlen);
28 28
29#endif /* __PERF_QUOTE_H */ 29#endif /* __PERF_QUOTE_H */
diff --git a/tools/perf/util/scripting-engines/trace-event-perl.c b/tools/perf/util/scripting-engines/trace-event-perl.c
index 544509c159ce..b3aabc0d4eb0 100644
--- a/tools/perf/util/scripting-engines/trace-event-perl.c
+++ b/tools/perf/util/scripting-engines/trace-event-perl.c
@@ -187,6 +187,9 @@ static void define_event_symbols(struct event_format *event,
187 const char *ev_name, 187 const char *ev_name,
188 struct print_arg *args) 188 struct print_arg *args)
189{ 189{
190 if (args == NULL)
191 return;
192
190 switch (args->type) { 193 switch (args->type) {
191 case PRINT_NULL: 194 case PRINT_NULL:
192 break; 195 break;
diff --git a/tools/perf/util/scripting-engines/trace-event-python.c b/tools/perf/util/scripting-engines/trace-event-python.c
index d72fafc1c800..fbd05242b4e5 100644
--- a/tools/perf/util/scripting-engines/trace-event-python.c
+++ b/tools/perf/util/scripting-engines/trace-event-python.c
@@ -205,6 +205,9 @@ static void define_event_symbols(struct event_format *event,
205 const char *ev_name, 205 const char *ev_name,
206 struct print_arg *args) 206 struct print_arg *args)
207{ 207{
208 if (args == NULL)
209 return;
210
208 switch (args->type) { 211 switch (args->type) {
209 case PRINT_NULL: 212 case PRINT_NULL:
210 break; 213 break;
@@ -1091,8 +1094,6 @@ static int python_start_script(const char *script, int argc, const char **argv)
1091 goto error; 1094 goto error;
1092 } 1095 }
1093 1096
1094 free(command_line);
1095
1096 set_table_handlers(tables); 1097 set_table_handlers(tables);
1097 1098
1098 if (tables->db_export_mode) { 1099 if (tables->db_export_mode) {
@@ -1101,6 +1102,8 @@ static int python_start_script(const char *script, int argc, const char **argv)
1101 goto error; 1102 goto error;
1102 } 1103 }
1103 1104
1105 free(command_line);
1106
1104 return err; 1107 return err;
1105error: 1108error:
1106 Py_Finalize(); 1109 Py_Finalize();
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
index 40b7a0d0905b..4abd85c6346d 100644
--- a/tools/perf/util/session.c
+++ b/tools/perf/util/session.c
@@ -240,14 +240,6 @@ static int process_event_stub(struct perf_tool *tool __maybe_unused,
240 return 0; 240 return 0;
241} 241}
242 242
243static int process_build_id_stub(struct perf_tool *tool __maybe_unused,
244 union perf_event *event __maybe_unused,
245 struct perf_session *session __maybe_unused)
246{
247 dump_printf(": unhandled!\n");
248 return 0;
249}
250
251static int process_finished_round_stub(struct perf_tool *tool __maybe_unused, 243static int process_finished_round_stub(struct perf_tool *tool __maybe_unused,
252 union perf_event *event __maybe_unused, 244 union perf_event *event __maybe_unused,
253 struct ordered_events *oe __maybe_unused) 245 struct ordered_events *oe __maybe_unused)
@@ -260,23 +252,6 @@ static int process_finished_round(struct perf_tool *tool,
260 union perf_event *event, 252 union perf_event *event,
261 struct ordered_events *oe); 253 struct ordered_events *oe);
262 254
263static int process_id_index_stub(struct perf_tool *tool __maybe_unused,
264 union perf_event *event __maybe_unused,
265 struct perf_session *perf_session
266 __maybe_unused)
267{
268 dump_printf(": unhandled!\n");
269 return 0;
270}
271
272static int process_event_auxtrace_info_stub(struct perf_tool *tool __maybe_unused,
273 union perf_event *event __maybe_unused,
274 struct perf_session *session __maybe_unused)
275{
276 dump_printf(": unhandled!\n");
277 return 0;
278}
279
280static int skipn(int fd, off_t n) 255static int skipn(int fd, off_t n)
281{ 256{
282 char buf[4096]; 257 char buf[4096];
@@ -303,10 +278,9 @@ static s64 process_event_auxtrace_stub(struct perf_tool *tool __maybe_unused,
303 return event->auxtrace.size; 278 return event->auxtrace.size;
304} 279}
305 280
306static 281static int process_event_op2_stub(struct perf_tool *tool __maybe_unused,
307int process_event_auxtrace_error_stub(struct perf_tool *tool __maybe_unused, 282 union perf_event *event __maybe_unused,
308 union perf_event *event __maybe_unused, 283 struct perf_session *session __maybe_unused)
309 struct perf_session *session __maybe_unused)
310{ 284{
311 dump_printf(": unhandled!\n"); 285 dump_printf(": unhandled!\n");
312 return 0; 286 return 0;
@@ -410,7 +384,7 @@ void perf_tool__fill_defaults(struct perf_tool *tool)
410 if (tool->tracing_data == NULL) 384 if (tool->tracing_data == NULL)
411 tool->tracing_data = process_event_synth_tracing_data_stub; 385 tool->tracing_data = process_event_synth_tracing_data_stub;
412 if (tool->build_id == NULL) 386 if (tool->build_id == NULL)
413 tool->build_id = process_build_id_stub; 387 tool->build_id = process_event_op2_stub;
414 if (tool->finished_round == NULL) { 388 if (tool->finished_round == NULL) {
415 if (tool->ordered_events) 389 if (tool->ordered_events)
416 tool->finished_round = process_finished_round; 390 tool->finished_round = process_finished_round;
@@ -418,13 +392,13 @@ void perf_tool__fill_defaults(struct perf_tool *tool)
418 tool->finished_round = process_finished_round_stub; 392 tool->finished_round = process_finished_round_stub;
419 } 393 }
420 if (tool->id_index == NULL) 394 if (tool->id_index == NULL)
421 tool->id_index = process_id_index_stub; 395 tool->id_index = process_event_op2_stub;
422 if (tool->auxtrace_info == NULL) 396 if (tool->auxtrace_info == NULL)
423 tool->auxtrace_info = process_event_auxtrace_info_stub; 397 tool->auxtrace_info = process_event_op2_stub;
424 if (tool->auxtrace == NULL) 398 if (tool->auxtrace == NULL)
425 tool->auxtrace = process_event_auxtrace_stub; 399 tool->auxtrace = process_event_auxtrace_stub;
426 if (tool->auxtrace_error == NULL) 400 if (tool->auxtrace_error == NULL)
427 tool->auxtrace_error = process_event_auxtrace_error_stub; 401 tool->auxtrace_error = process_event_op2_stub;
428 if (tool->thread_map == NULL) 402 if (tool->thread_map == NULL)
429 tool->thread_map = process_event_thread_map_stub; 403 tool->thread_map = process_event_thread_map_stub;
430 if (tool->cpu_map == NULL) 404 if (tool->cpu_map == NULL)
@@ -1133,12 +1107,11 @@ static struct machine *machines__find_for_cpumode(struct machines *machines,
1133 union perf_event *event, 1107 union perf_event *event,
1134 struct perf_sample *sample) 1108 struct perf_sample *sample)
1135{ 1109{
1136 const u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
1137 struct machine *machine; 1110 struct machine *machine;
1138 1111
1139 if (perf_guest && 1112 if (perf_guest &&
1140 ((cpumode == PERF_RECORD_MISC_GUEST_KERNEL) || 1113 ((sample->cpumode == PERF_RECORD_MISC_GUEST_KERNEL) ||
1141 (cpumode == PERF_RECORD_MISC_GUEST_USER))) { 1114 (sample->cpumode == PERF_RECORD_MISC_GUEST_USER))) {
1142 u32 pid; 1115 u32 pid;
1143 1116
1144 if (event->header.type == PERF_RECORD_MMAP 1117 if (event->header.type == PERF_RECORD_MMAP
diff --git a/tools/perf/util/setup.py b/tools/perf/util/setup.py
index 1833103768cb..c8680984d2d6 100644
--- a/tools/perf/util/setup.py
+++ b/tools/perf/util/setup.py
@@ -22,6 +22,7 @@ cflags = getenv('CFLAGS', '').split()
22# switch off several checks (need to be at the end of cflags list) 22# switch off several checks (need to be at the end of cflags list)
23cflags += ['-fno-strict-aliasing', '-Wno-write-strings', '-Wno-unused-parameter' ] 23cflags += ['-fno-strict-aliasing', '-Wno-write-strings', '-Wno-unused-parameter' ]
24 24
25src_perf = getenv('srctree') + '/tools/perf'
25build_lib = getenv('PYTHON_EXTBUILD_LIB') 26build_lib = getenv('PYTHON_EXTBUILD_LIB')
26build_tmp = getenv('PYTHON_EXTBUILD_TMP') 27build_tmp = getenv('PYTHON_EXTBUILD_TMP')
27libtraceevent = getenv('LIBTRACEEVENT') 28libtraceevent = getenv('LIBTRACEEVENT')
@@ -30,6 +31,9 @@ libapikfs = getenv('LIBAPI')
30ext_sources = [f.strip() for f in file('util/python-ext-sources') 31ext_sources = [f.strip() for f in file('util/python-ext-sources')
31 if len(f.strip()) > 0 and f[0] != '#'] 32 if len(f.strip()) > 0 and f[0] != '#']
32 33
34# use full paths with source files
35ext_sources = map(lambda x: '%s/%s' % (src_perf, x) , ext_sources)
36
33perf = Extension('perf', 37perf = Extension('perf',
34 sources = ext_sources, 38 sources = ext_sources,
35 include_dirs = ['util/include'], 39 include_dirs = ['util/include'],
diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c
index ec722346e6ff..47966a1618c7 100644
--- a/tools/perf/util/sort.c
+++ b/tools/perf/util/sort.c
@@ -6,6 +6,7 @@
6#include "evsel.h" 6#include "evsel.h"
7#include "evlist.h" 7#include "evlist.h"
8#include <traceevent/event-parse.h> 8#include <traceevent/event-parse.h>
9#include "mem-events.h"
9 10
10regex_t parent_regex; 11regex_t parent_regex;
11const char default_parent_pattern[] = "^sys_|^do_page_fault"; 12const char default_parent_pattern[] = "^sys_|^do_page_fault";
@@ -25,9 +26,19 @@ int sort__has_parent = 0;
25int sort__has_sym = 0; 26int sort__has_sym = 0;
26int sort__has_dso = 0; 27int sort__has_dso = 0;
27int sort__has_socket = 0; 28int sort__has_socket = 0;
29int sort__has_thread = 0;
30int sort__has_comm = 0;
28enum sort_mode sort__mode = SORT_MODE__NORMAL; 31enum sort_mode sort__mode = SORT_MODE__NORMAL;
29 32
30 33/*
34 * Replaces all occurrences of a char used with the:
35 *
36 * -t, --field-separator
37 *
38 * option, that uses a special separator character and don't pad with spaces,
39 * replacing all occurances of this separator in symbol names (and other
40 * output) with a '.' character, that thus it's the only non valid separator.
41*/
31static int repsep_snprintf(char *bf, size_t size, const char *fmt, ...) 42static int repsep_snprintf(char *bf, size_t size, const char *fmt, ...)
32{ 43{
33 int n; 44 int n;
@@ -80,10 +91,21 @@ static int hist_entry__thread_snprintf(struct hist_entry *he, char *bf,
80 width, width, comm ?: ""); 91 width, width, comm ?: "");
81} 92}
82 93
94static int hist_entry__thread_filter(struct hist_entry *he, int type, const void *arg)
95{
96 const struct thread *th = arg;
97
98 if (type != HIST_FILTER__THREAD)
99 return -1;
100
101 return th && he->thread != th;
102}
103
83struct sort_entry sort_thread = { 104struct sort_entry sort_thread = {
84 .se_header = " Pid:Command", 105 .se_header = " Pid:Command",
85 .se_cmp = sort__thread_cmp, 106 .se_cmp = sort__thread_cmp,
86 .se_snprintf = hist_entry__thread_snprintf, 107 .se_snprintf = hist_entry__thread_snprintf,
108 .se_filter = hist_entry__thread_filter,
87 .se_width_idx = HISTC_THREAD, 109 .se_width_idx = HISTC_THREAD,
88}; 110};
89 111
@@ -121,6 +143,7 @@ struct sort_entry sort_comm = {
121 .se_collapse = sort__comm_collapse, 143 .se_collapse = sort__comm_collapse,
122 .se_sort = sort__comm_sort, 144 .se_sort = sort__comm_sort,
123 .se_snprintf = hist_entry__comm_snprintf, 145 .se_snprintf = hist_entry__comm_snprintf,
146 .se_filter = hist_entry__thread_filter,
124 .se_width_idx = HISTC_COMM, 147 .se_width_idx = HISTC_COMM,
125}; 148};
126 149
@@ -170,10 +193,21 @@ static int hist_entry__dso_snprintf(struct hist_entry *he, char *bf,
170 return _hist_entry__dso_snprintf(he->ms.map, bf, size, width); 193 return _hist_entry__dso_snprintf(he->ms.map, bf, size, width);
171} 194}
172 195
196static int hist_entry__dso_filter(struct hist_entry *he, int type, const void *arg)
197{
198 const struct dso *dso = arg;
199
200 if (type != HIST_FILTER__DSO)
201 return -1;
202
203 return dso && (!he->ms.map || he->ms.map->dso != dso);
204}
205
173struct sort_entry sort_dso = { 206struct sort_entry sort_dso = {
174 .se_header = "Shared Object", 207 .se_header = "Shared Object",
175 .se_cmp = sort__dso_cmp, 208 .se_cmp = sort__dso_cmp,
176 .se_snprintf = hist_entry__dso_snprintf, 209 .se_snprintf = hist_entry__dso_snprintf,
210 .se_filter = hist_entry__dso_filter,
177 .se_width_idx = HISTC_DSO, 211 .se_width_idx = HISTC_DSO,
178}; 212};
179 213
@@ -246,10 +280,8 @@ static int _hist_entry__sym_snprintf(struct map *map, struct symbol *sym,
246 ret += repsep_snprintf(bf + ret, size - ret, "%s", sym->name); 280 ret += repsep_snprintf(bf + ret, size - ret, "%s", sym->name);
247 ret += repsep_snprintf(bf + ret, size - ret, "+0x%llx", 281 ret += repsep_snprintf(bf + ret, size - ret, "+0x%llx",
248 ip - map->unmap_ip(map, sym->start)); 282 ip - map->unmap_ip(map, sym->start));
249 ret += repsep_snprintf(bf + ret, size - ret, "%-*s",
250 width - ret, "");
251 } else { 283 } else {
252 ret += repsep_snprintf(bf + ret, size - ret, "%-*s", 284 ret += repsep_snprintf(bf + ret, size - ret, "%.*s",
253 width - ret, 285 width - ret,
254 sym->name); 286 sym->name);
255 } 287 }
@@ -257,14 +289,9 @@ static int _hist_entry__sym_snprintf(struct map *map, struct symbol *sym,
257 size_t len = BITS_PER_LONG / 4; 289 size_t len = BITS_PER_LONG / 4;
258 ret += repsep_snprintf(bf + ret, size - ret, "%-#.*llx", 290 ret += repsep_snprintf(bf + ret, size - ret, "%-#.*llx",
259 len, ip); 291 len, ip);
260 ret += repsep_snprintf(bf + ret, size - ret, "%-*s",
261 width - ret, "");
262 } 292 }
263 293
264 if (ret > width) 294 return ret;
265 bf[width] = '\0';
266
267 return width;
268} 295}
269 296
270static int hist_entry__sym_snprintf(struct hist_entry *he, char *bf, 297static int hist_entry__sym_snprintf(struct hist_entry *he, char *bf,
@@ -274,46 +301,56 @@ static int hist_entry__sym_snprintf(struct hist_entry *he, char *bf,
274 he->level, bf, size, width); 301 he->level, bf, size, width);
275} 302}
276 303
304static int hist_entry__sym_filter(struct hist_entry *he, int type, const void *arg)
305{
306 const char *sym = arg;
307
308 if (type != HIST_FILTER__SYMBOL)
309 return -1;
310
311 return sym && (!he->ms.sym || !strstr(he->ms.sym->name, sym));
312}
313
277struct sort_entry sort_sym = { 314struct sort_entry sort_sym = {
278 .se_header = "Symbol", 315 .se_header = "Symbol",
279 .se_cmp = sort__sym_cmp, 316 .se_cmp = sort__sym_cmp,
280 .se_sort = sort__sym_sort, 317 .se_sort = sort__sym_sort,
281 .se_snprintf = hist_entry__sym_snprintf, 318 .se_snprintf = hist_entry__sym_snprintf,
319 .se_filter = hist_entry__sym_filter,
282 .se_width_idx = HISTC_SYMBOL, 320 .se_width_idx = HISTC_SYMBOL,
283}; 321};
284 322
285/* --sort srcline */ 323/* --sort srcline */
286 324
325static char *hist_entry__get_srcline(struct hist_entry *he)
326{
327 struct map *map = he->ms.map;
328
329 if (!map)
330 return SRCLINE_UNKNOWN;
331
332 return get_srcline(map->dso, map__rip_2objdump(map, he->ip),
333 he->ms.sym, true);
334}
335
287static int64_t 336static int64_t
288sort__srcline_cmp(struct hist_entry *left, struct hist_entry *right) 337sort__srcline_cmp(struct hist_entry *left, struct hist_entry *right)
289{ 338{
290 if (!left->srcline) { 339 if (!left->srcline)
291 if (!left->ms.map) 340 left->srcline = hist_entry__get_srcline(left);
292 left->srcline = SRCLINE_UNKNOWN; 341 if (!right->srcline)
293 else { 342 right->srcline = hist_entry__get_srcline(right);
294 struct map *map = left->ms.map; 343
295 left->srcline = get_srcline(map->dso,
296 map__rip_2objdump(map, left->ip),
297 left->ms.sym, true);
298 }
299 }
300 if (!right->srcline) {
301 if (!right->ms.map)
302 right->srcline = SRCLINE_UNKNOWN;
303 else {
304 struct map *map = right->ms.map;
305 right->srcline = get_srcline(map->dso,
306 map__rip_2objdump(map, right->ip),
307 right->ms.sym, true);
308 }
309 }
310 return strcmp(right->srcline, left->srcline); 344 return strcmp(right->srcline, left->srcline);
311} 345}
312 346
313static int hist_entry__srcline_snprintf(struct hist_entry *he, char *bf, 347static int hist_entry__srcline_snprintf(struct hist_entry *he, char *bf,
314 size_t size, unsigned int width) 348 size_t size, unsigned int width)
315{ 349{
316 return repsep_snprintf(bf, size, "%-*.*s", width, width, he->srcline); 350 if (!he->srcline)
351 he->srcline = hist_entry__get_srcline(he);
352
353 return repsep_snprintf(bf, size, "%-.*s", width, he->srcline);
317} 354}
318 355
319struct sort_entry sort_srcline = { 356struct sort_entry sort_srcline = {
@@ -327,11 +364,14 @@ struct sort_entry sort_srcline = {
327 364
328static char no_srcfile[1]; 365static char no_srcfile[1];
329 366
330static char *get_srcfile(struct hist_entry *e) 367static char *hist_entry__get_srcfile(struct hist_entry *e)
331{ 368{
332 char *sf, *p; 369 char *sf, *p;
333 struct map *map = e->ms.map; 370 struct map *map = e->ms.map;
334 371
372 if (!map)
373 return no_srcfile;
374
335 sf = __get_srcline(map->dso, map__rip_2objdump(map, e->ip), 375 sf = __get_srcline(map->dso, map__rip_2objdump(map, e->ip),
336 e->ms.sym, false, true); 376 e->ms.sym, false, true);
337 if (!strcmp(sf, SRCLINE_UNKNOWN)) 377 if (!strcmp(sf, SRCLINE_UNKNOWN))
@@ -348,25 +388,21 @@ static char *get_srcfile(struct hist_entry *e)
348static int64_t 388static int64_t
349sort__srcfile_cmp(struct hist_entry *left, struct hist_entry *right) 389sort__srcfile_cmp(struct hist_entry *left, struct hist_entry *right)
350{ 390{
351 if (!left->srcfile) { 391 if (!left->srcfile)
352 if (!left->ms.map) 392 left->srcfile = hist_entry__get_srcfile(left);
353 left->srcfile = no_srcfile; 393 if (!right->srcfile)
354 else 394 right->srcfile = hist_entry__get_srcfile(right);
355 left->srcfile = get_srcfile(left); 395
356 }
357 if (!right->srcfile) {
358 if (!right->ms.map)
359 right->srcfile = no_srcfile;
360 else
361 right->srcfile = get_srcfile(right);
362 }
363 return strcmp(right->srcfile, left->srcfile); 396 return strcmp(right->srcfile, left->srcfile);
364} 397}
365 398
366static int hist_entry__srcfile_snprintf(struct hist_entry *he, char *bf, 399static int hist_entry__srcfile_snprintf(struct hist_entry *he, char *bf,
367 size_t size, unsigned int width) 400 size_t size, unsigned int width)
368{ 401{
369 return repsep_snprintf(bf, size, "%-*.*s", width, width, he->srcfile); 402 if (!he->srcfile)
403 he->srcfile = hist_entry__get_srcfile(he);
404
405 return repsep_snprintf(bf, size, "%-.*s", width, he->srcfile);
370} 406}
371 407
372struct sort_entry sort_srcfile = { 408struct sort_entry sort_srcfile = {
@@ -439,10 +475,21 @@ static int hist_entry__socket_snprintf(struct hist_entry *he, char *bf,
439 return repsep_snprintf(bf, size, "%*.*d", width, width-3, he->socket); 475 return repsep_snprintf(bf, size, "%*.*d", width, width-3, he->socket);
440} 476}
441 477
478static int hist_entry__socket_filter(struct hist_entry *he, int type, const void *arg)
479{
480 int sk = *(const int *)arg;
481
482 if (type != HIST_FILTER__SOCKET)
483 return -1;
484
485 return sk >= 0 && he->socket != sk;
486}
487
442struct sort_entry sort_socket = { 488struct sort_entry sort_socket = {
443 .se_header = "Socket", 489 .se_header = "Socket",
444 .se_cmp = sort__socket_cmp, 490 .se_cmp = sort__socket_cmp,
445 .se_snprintf = hist_entry__socket_snprintf, 491 .se_snprintf = hist_entry__socket_snprintf,
492 .se_filter = hist_entry__socket_filter,
446 .se_width_idx = HISTC_SOCKET, 493 .se_width_idx = HISTC_SOCKET,
447}; 494};
448 495
@@ -483,9 +530,6 @@ sort__trace_cmp(struct hist_entry *left, struct hist_entry *right)
483 if (right->trace_output == NULL) 530 if (right->trace_output == NULL)
484 right->trace_output = get_trace_output(right); 531 right->trace_output = get_trace_output(right);
485 532
486 hists__new_col_len(left->hists, HISTC_TRACE, strlen(left->trace_output));
487 hists__new_col_len(right->hists, HISTC_TRACE, strlen(right->trace_output));
488
489 return strcmp(right->trace_output, left->trace_output); 533 return strcmp(right->trace_output, left->trace_output);
490} 534}
491 535
@@ -496,11 +540,11 @@ static int hist_entry__trace_snprintf(struct hist_entry *he, char *bf,
496 540
497 evsel = hists_to_evsel(he->hists); 541 evsel = hists_to_evsel(he->hists);
498 if (evsel->attr.type != PERF_TYPE_TRACEPOINT) 542 if (evsel->attr.type != PERF_TYPE_TRACEPOINT)
499 return scnprintf(bf, size, "%-*.*s", width, width, "N/A"); 543 return scnprintf(bf, size, "%-.*s", width, "N/A");
500 544
501 if (he->trace_output == NULL) 545 if (he->trace_output == NULL)
502 he->trace_output = get_trace_output(he); 546 he->trace_output = get_trace_output(he);
503 return repsep_snprintf(bf, size, "%-*.*s", width, width, he->trace_output); 547 return repsep_snprintf(bf, size, "%-.*s", width, he->trace_output);
504} 548}
505 549
506struct sort_entry sort_trace = { 550struct sort_entry sort_trace = {
@@ -532,6 +576,18 @@ static int hist_entry__dso_from_snprintf(struct hist_entry *he, char *bf,
532 return repsep_snprintf(bf, size, "%-*.*s", width, width, "N/A"); 576 return repsep_snprintf(bf, size, "%-*.*s", width, width, "N/A");
533} 577}
534 578
579static int hist_entry__dso_from_filter(struct hist_entry *he, int type,
580 const void *arg)
581{
582 const struct dso *dso = arg;
583
584 if (type != HIST_FILTER__DSO)
585 return -1;
586
587 return dso && (!he->branch_info || !he->branch_info->from.map ||
588 he->branch_info->from.map->dso != dso);
589}
590
535static int64_t 591static int64_t
536sort__dso_to_cmp(struct hist_entry *left, struct hist_entry *right) 592sort__dso_to_cmp(struct hist_entry *left, struct hist_entry *right)
537{ 593{
@@ -552,6 +608,18 @@ static int hist_entry__dso_to_snprintf(struct hist_entry *he, char *bf,
552 return repsep_snprintf(bf, size, "%-*.*s", width, width, "N/A"); 608 return repsep_snprintf(bf, size, "%-*.*s", width, width, "N/A");
553} 609}
554 610
611static int hist_entry__dso_to_filter(struct hist_entry *he, int type,
612 const void *arg)
613{
614 const struct dso *dso = arg;
615
616 if (type != HIST_FILTER__DSO)
617 return -1;
618
619 return dso && (!he->branch_info || !he->branch_info->to.map ||
620 he->branch_info->to.map->dso != dso);
621}
622
555static int64_t 623static int64_t
556sort__sym_from_cmp(struct hist_entry *left, struct hist_entry *right) 624sort__sym_from_cmp(struct hist_entry *left, struct hist_entry *right)
557{ 625{
@@ -613,10 +681,35 @@ static int hist_entry__sym_to_snprintf(struct hist_entry *he, char *bf,
613 return repsep_snprintf(bf, size, "%-*.*s", width, width, "N/A"); 681 return repsep_snprintf(bf, size, "%-*.*s", width, width, "N/A");
614} 682}
615 683
684static int hist_entry__sym_from_filter(struct hist_entry *he, int type,
685 const void *arg)
686{
687 const char *sym = arg;
688
689 if (type != HIST_FILTER__SYMBOL)
690 return -1;
691
692 return sym && !(he->branch_info && he->branch_info->from.sym &&
693 strstr(he->branch_info->from.sym->name, sym));
694}
695
696static int hist_entry__sym_to_filter(struct hist_entry *he, int type,
697 const void *arg)
698{
699 const char *sym = arg;
700
701 if (type != HIST_FILTER__SYMBOL)
702 return -1;
703
704 return sym && !(he->branch_info && he->branch_info->to.sym &&
705 strstr(he->branch_info->to.sym->name, sym));
706}
707
616struct sort_entry sort_dso_from = { 708struct sort_entry sort_dso_from = {
617 .se_header = "Source Shared Object", 709 .se_header = "Source Shared Object",
618 .se_cmp = sort__dso_from_cmp, 710 .se_cmp = sort__dso_from_cmp,
619 .se_snprintf = hist_entry__dso_from_snprintf, 711 .se_snprintf = hist_entry__dso_from_snprintf,
712 .se_filter = hist_entry__dso_from_filter,
620 .se_width_idx = HISTC_DSO_FROM, 713 .se_width_idx = HISTC_DSO_FROM,
621}; 714};
622 715
@@ -624,6 +717,7 @@ struct sort_entry sort_dso_to = {
624 .se_header = "Target Shared Object", 717 .se_header = "Target Shared Object",
625 .se_cmp = sort__dso_to_cmp, 718 .se_cmp = sort__dso_to_cmp,
626 .se_snprintf = hist_entry__dso_to_snprintf, 719 .se_snprintf = hist_entry__dso_to_snprintf,
720 .se_filter = hist_entry__dso_to_filter,
627 .se_width_idx = HISTC_DSO_TO, 721 .se_width_idx = HISTC_DSO_TO,
628}; 722};
629 723
@@ -631,6 +725,7 @@ struct sort_entry sort_sym_from = {
631 .se_header = "Source Symbol", 725 .se_header = "Source Symbol",
632 .se_cmp = sort__sym_from_cmp, 726 .se_cmp = sort__sym_from_cmp,
633 .se_snprintf = hist_entry__sym_from_snprintf, 727 .se_snprintf = hist_entry__sym_from_snprintf,
728 .se_filter = hist_entry__sym_from_filter,
634 .se_width_idx = HISTC_SYMBOL_FROM, 729 .se_width_idx = HISTC_SYMBOL_FROM,
635}; 730};
636 731
@@ -638,6 +733,7 @@ struct sort_entry sort_sym_to = {
638 .se_header = "Target Symbol", 733 .se_header = "Target Symbol",
639 .se_cmp = sort__sym_to_cmp, 734 .se_cmp = sort__sym_to_cmp,
640 .se_snprintf = hist_entry__sym_to_snprintf, 735 .se_snprintf = hist_entry__sym_to_snprintf,
736 .se_filter = hist_entry__sym_to_filter,
641 .se_width_idx = HISTC_SYMBOL_TO, 737 .se_width_idx = HISTC_SYMBOL_TO,
642}; 738};
643 739
@@ -797,20 +893,10 @@ sort__locked_cmp(struct hist_entry *left, struct hist_entry *right)
797static int hist_entry__locked_snprintf(struct hist_entry *he, char *bf, 893static int hist_entry__locked_snprintf(struct hist_entry *he, char *bf,
798 size_t size, unsigned int width) 894 size_t size, unsigned int width)
799{ 895{
800 const char *out; 896 char out[10];
801 u64 mask = PERF_MEM_LOCK_NA;
802 897
803 if (he->mem_info) 898 perf_mem__lck_scnprintf(out, sizeof(out), he->mem_info);
804 mask = he->mem_info->data_src.mem_lock; 899 return repsep_snprintf(bf, size, "%.*s", width, out);
805
806 if (mask & PERF_MEM_LOCK_NA)
807 out = "N/A";
808 else if (mask & PERF_MEM_LOCK_LOCKED)
809 out = "Yes";
810 else
811 out = "No";
812
813 return repsep_snprintf(bf, size, "%-*s", width, out);
814} 900}
815 901
816static int64_t 902static int64_t
@@ -832,54 +918,12 @@ sort__tlb_cmp(struct hist_entry *left, struct hist_entry *right)
832 return (int64_t)(data_src_r.mem_dtlb - data_src_l.mem_dtlb); 918 return (int64_t)(data_src_r.mem_dtlb - data_src_l.mem_dtlb);
833} 919}
834 920
835static const char * const tlb_access[] = {
836 "N/A",
837 "HIT",
838 "MISS",
839 "L1",
840 "L2",
841 "Walker",
842 "Fault",
843};
844#define NUM_TLB_ACCESS (sizeof(tlb_access)/sizeof(const char *))
845
846static int hist_entry__tlb_snprintf(struct hist_entry *he, char *bf, 921static int hist_entry__tlb_snprintf(struct hist_entry *he, char *bf,
847 size_t size, unsigned int width) 922 size_t size, unsigned int width)
848{ 923{
849 char out[64]; 924 char out[64];
850 size_t sz = sizeof(out) - 1; /* -1 for null termination */
851 size_t l = 0, i;
852 u64 m = PERF_MEM_TLB_NA;
853 u64 hit, miss;
854
855 out[0] = '\0';
856
857 if (he->mem_info)
858 m = he->mem_info->data_src.mem_dtlb;
859
860 hit = m & PERF_MEM_TLB_HIT;
861 miss = m & PERF_MEM_TLB_MISS;
862
863 /* already taken care of */
864 m &= ~(PERF_MEM_TLB_HIT|PERF_MEM_TLB_MISS);
865
866 for (i = 0; m && i < NUM_TLB_ACCESS; i++, m >>= 1) {
867 if (!(m & 0x1))
868 continue;
869 if (l) {
870 strcat(out, " or ");
871 l += 4;
872 }
873 strncat(out, tlb_access[i], sz - l);
874 l += strlen(tlb_access[i]);
875 }
876 if (*out == '\0')
877 strcpy(out, "N/A");
878 if (hit)
879 strncat(out, " hit", sz - l);
880 if (miss)
881 strncat(out, " miss", sz - l);
882 925
926 perf_mem__tlb_scnprintf(out, sizeof(out), he->mem_info);
883 return repsep_snprintf(bf, size, "%-*s", width, out); 927 return repsep_snprintf(bf, size, "%-*s", width, out);
884} 928}
885 929
@@ -902,61 +946,12 @@ sort__lvl_cmp(struct hist_entry *left, struct hist_entry *right)
902 return (int64_t)(data_src_r.mem_lvl - data_src_l.mem_lvl); 946 return (int64_t)(data_src_r.mem_lvl - data_src_l.mem_lvl);
903} 947}
904 948
905static const char * const mem_lvl[] = {
906 "N/A",
907 "HIT",
908 "MISS",
909 "L1",
910 "LFB",
911 "L2",
912 "L3",
913 "Local RAM",
914 "Remote RAM (1 hop)",
915 "Remote RAM (2 hops)",
916 "Remote Cache (1 hop)",
917 "Remote Cache (2 hops)",
918 "I/O",
919 "Uncached",
920};
921#define NUM_MEM_LVL (sizeof(mem_lvl)/sizeof(const char *))
922
923static int hist_entry__lvl_snprintf(struct hist_entry *he, char *bf, 949static int hist_entry__lvl_snprintf(struct hist_entry *he, char *bf,
924 size_t size, unsigned int width) 950 size_t size, unsigned int width)
925{ 951{
926 char out[64]; 952 char out[64];
927 size_t sz = sizeof(out) - 1; /* -1 for null termination */
928 size_t i, l = 0;
929 u64 m = PERF_MEM_LVL_NA;
930 u64 hit, miss;
931
932 if (he->mem_info)
933 m = he->mem_info->data_src.mem_lvl;
934
935 out[0] = '\0';
936
937 hit = m & PERF_MEM_LVL_HIT;
938 miss = m & PERF_MEM_LVL_MISS;
939
940 /* already taken care of */
941 m &= ~(PERF_MEM_LVL_HIT|PERF_MEM_LVL_MISS);
942
943 for (i = 0; m && i < NUM_MEM_LVL; i++, m >>= 1) {
944 if (!(m & 0x1))
945 continue;
946 if (l) {
947 strcat(out, " or ");
948 l += 4;
949 }
950 strncat(out, mem_lvl[i], sz - l);
951 l += strlen(mem_lvl[i]);
952 }
953 if (*out == '\0')
954 strcpy(out, "N/A");
955 if (hit)
956 strncat(out, " hit", sz - l);
957 if (miss)
958 strncat(out, " miss", sz - l);
959 953
954 perf_mem__lvl_scnprintf(out, sizeof(out), he->mem_info);
960 return repsep_snprintf(bf, size, "%-*s", width, out); 955 return repsep_snprintf(bf, size, "%-*s", width, out);
961} 956}
962 957
@@ -979,51 +974,15 @@ sort__snoop_cmp(struct hist_entry *left, struct hist_entry *right)
979 return (int64_t)(data_src_r.mem_snoop - data_src_l.mem_snoop); 974 return (int64_t)(data_src_r.mem_snoop - data_src_l.mem_snoop);
980} 975}
981 976
982static const char * const snoop_access[] = {
983 "N/A",
984 "None",
985 "Miss",
986 "Hit",
987 "HitM",
988};
989#define NUM_SNOOP_ACCESS (sizeof(snoop_access)/sizeof(const char *))
990
991static int hist_entry__snoop_snprintf(struct hist_entry *he, char *bf, 977static int hist_entry__snoop_snprintf(struct hist_entry *he, char *bf,
992 size_t size, unsigned int width) 978 size_t size, unsigned int width)
993{ 979{
994 char out[64]; 980 char out[64];
995 size_t sz = sizeof(out) - 1; /* -1 for null termination */
996 size_t i, l = 0;
997 u64 m = PERF_MEM_SNOOP_NA;
998
999 out[0] = '\0';
1000
1001 if (he->mem_info)
1002 m = he->mem_info->data_src.mem_snoop;
1003
1004 for (i = 0; m && i < NUM_SNOOP_ACCESS; i++, m >>= 1) {
1005 if (!(m & 0x1))
1006 continue;
1007 if (l) {
1008 strcat(out, " or ");
1009 l += 4;
1010 }
1011 strncat(out, snoop_access[i], sz - l);
1012 l += strlen(snoop_access[i]);
1013 }
1014
1015 if (*out == '\0')
1016 strcpy(out, "N/A");
1017 981
982 perf_mem__snp_scnprintf(out, sizeof(out), he->mem_info);
1018 return repsep_snprintf(bf, size, "%-*s", width, out); 983 return repsep_snprintf(bf, size, "%-*s", width, out);
1019} 984}
1020 985
1021static inline u64 cl_address(u64 address)
1022{
1023 /* return the cacheline of the address */
1024 return (address & ~(cacheline_size - 1));
1025}
1026
1027static int64_t 986static int64_t
1028sort__dcacheline_cmp(struct hist_entry *left, struct hist_entry *right) 987sort__dcacheline_cmp(struct hist_entry *left, struct hist_entry *right)
1029{ 988{
@@ -1440,20 +1399,6 @@ struct hpp_sort_entry {
1440 struct sort_entry *se; 1399 struct sort_entry *se;
1441}; 1400};
1442 1401
1443bool perf_hpp__same_sort_entry(struct perf_hpp_fmt *a, struct perf_hpp_fmt *b)
1444{
1445 struct hpp_sort_entry *hse_a;
1446 struct hpp_sort_entry *hse_b;
1447
1448 if (!perf_hpp__is_sort_entry(a) || !perf_hpp__is_sort_entry(b))
1449 return false;
1450
1451 hse_a = container_of(a, struct hpp_sort_entry, hpp);
1452 hse_b = container_of(b, struct hpp_sort_entry, hpp);
1453
1454 return hse_a->se == hse_b->se;
1455}
1456
1457void perf_hpp__reset_sort_width(struct perf_hpp_fmt *fmt, struct hists *hists) 1402void perf_hpp__reset_sort_width(struct perf_hpp_fmt *fmt, struct hists *hists)
1458{ 1403{
1459 struct hpp_sort_entry *hse; 1404 struct hpp_sort_entry *hse;
@@ -1539,8 +1484,56 @@ static int64_t __sort__hpp_sort(struct perf_hpp_fmt *fmt,
1539 return sort_fn(a, b); 1484 return sort_fn(a, b);
1540} 1485}
1541 1486
1487bool perf_hpp__is_sort_entry(struct perf_hpp_fmt *format)
1488{
1489 return format->header == __sort__hpp_header;
1490}
1491
1492#define MK_SORT_ENTRY_CHK(key) \
1493bool perf_hpp__is_ ## key ## _entry(struct perf_hpp_fmt *fmt) \
1494{ \
1495 struct hpp_sort_entry *hse; \
1496 \
1497 if (!perf_hpp__is_sort_entry(fmt)) \
1498 return false; \
1499 \
1500 hse = container_of(fmt, struct hpp_sort_entry, hpp); \
1501 return hse->se == &sort_ ## key ; \
1502}
1503
1504MK_SORT_ENTRY_CHK(trace)
1505MK_SORT_ENTRY_CHK(srcline)
1506MK_SORT_ENTRY_CHK(srcfile)
1507MK_SORT_ENTRY_CHK(thread)
1508MK_SORT_ENTRY_CHK(comm)
1509MK_SORT_ENTRY_CHK(dso)
1510MK_SORT_ENTRY_CHK(sym)
1511
1512
1513static bool __sort__hpp_equal(struct perf_hpp_fmt *a, struct perf_hpp_fmt *b)
1514{
1515 struct hpp_sort_entry *hse_a;
1516 struct hpp_sort_entry *hse_b;
1517
1518 if (!perf_hpp__is_sort_entry(a) || !perf_hpp__is_sort_entry(b))
1519 return false;
1520
1521 hse_a = container_of(a, struct hpp_sort_entry, hpp);
1522 hse_b = container_of(b, struct hpp_sort_entry, hpp);
1523
1524 return hse_a->se == hse_b->se;
1525}
1526
1527static void hse_free(struct perf_hpp_fmt *fmt)
1528{
1529 struct hpp_sort_entry *hse;
1530
1531 hse = container_of(fmt, struct hpp_sort_entry, hpp);
1532 free(hse);
1533}
1534
1542static struct hpp_sort_entry * 1535static struct hpp_sort_entry *
1543__sort_dimension__alloc_hpp(struct sort_dimension *sd) 1536__sort_dimension__alloc_hpp(struct sort_dimension *sd, int level)
1544{ 1537{
1545 struct hpp_sort_entry *hse; 1538 struct hpp_sort_entry *hse;
1546 1539
@@ -1560,40 +1553,92 @@ __sort_dimension__alloc_hpp(struct sort_dimension *sd)
1560 hse->hpp.cmp = __sort__hpp_cmp; 1553 hse->hpp.cmp = __sort__hpp_cmp;
1561 hse->hpp.collapse = __sort__hpp_collapse; 1554 hse->hpp.collapse = __sort__hpp_collapse;
1562 hse->hpp.sort = __sort__hpp_sort; 1555 hse->hpp.sort = __sort__hpp_sort;
1556 hse->hpp.equal = __sort__hpp_equal;
1557 hse->hpp.free = hse_free;
1563 1558
1564 INIT_LIST_HEAD(&hse->hpp.list); 1559 INIT_LIST_HEAD(&hse->hpp.list);
1565 INIT_LIST_HEAD(&hse->hpp.sort_list); 1560 INIT_LIST_HEAD(&hse->hpp.sort_list);
1566 hse->hpp.elide = false; 1561 hse->hpp.elide = false;
1567 hse->hpp.len = 0; 1562 hse->hpp.len = 0;
1568 hse->hpp.user_len = 0; 1563 hse->hpp.user_len = 0;
1564 hse->hpp.level = level;
1569 1565
1570 return hse; 1566 return hse;
1571} 1567}
1572 1568
1573bool perf_hpp__is_sort_entry(struct perf_hpp_fmt *format) 1569static void hpp_free(struct perf_hpp_fmt *fmt)
1574{ 1570{
1575 return format->header == __sort__hpp_header; 1571 free(fmt);
1572}
1573
1574static struct perf_hpp_fmt *__hpp_dimension__alloc_hpp(struct hpp_dimension *hd,
1575 int level)
1576{
1577 struct perf_hpp_fmt *fmt;
1578
1579 fmt = memdup(hd->fmt, sizeof(*fmt));
1580 if (fmt) {
1581 INIT_LIST_HEAD(&fmt->list);
1582 INIT_LIST_HEAD(&fmt->sort_list);
1583 fmt->free = hpp_free;
1584 fmt->level = level;
1585 }
1586
1587 return fmt;
1588}
1589
1590int hist_entry__filter(struct hist_entry *he, int type, const void *arg)
1591{
1592 struct perf_hpp_fmt *fmt;
1593 struct hpp_sort_entry *hse;
1594 int ret = -1;
1595 int r;
1596
1597 perf_hpp_list__for_each_format(he->hpp_list, fmt) {
1598 if (!perf_hpp__is_sort_entry(fmt))
1599 continue;
1600
1601 hse = container_of(fmt, struct hpp_sort_entry, hpp);
1602 if (hse->se->se_filter == NULL)
1603 continue;
1604
1605 /*
1606 * hist entry is filtered if any of sort key in the hpp list
1607 * is applied. But it should skip non-matched filter types.
1608 */
1609 r = hse->se->se_filter(he, type, arg);
1610 if (r >= 0) {
1611 if (ret < 0)
1612 ret = 0;
1613 ret |= r;
1614 }
1615 }
1616
1617 return ret;
1576} 1618}
1577 1619
1578static int __sort_dimension__add_hpp_sort(struct sort_dimension *sd) 1620static int __sort_dimension__add_hpp_sort(struct sort_dimension *sd,
1621 struct perf_hpp_list *list,
1622 int level)
1579{ 1623{
1580 struct hpp_sort_entry *hse = __sort_dimension__alloc_hpp(sd); 1624 struct hpp_sort_entry *hse = __sort_dimension__alloc_hpp(sd, level);
1581 1625
1582 if (hse == NULL) 1626 if (hse == NULL)
1583 return -1; 1627 return -1;
1584 1628
1585 perf_hpp__register_sort_field(&hse->hpp); 1629 perf_hpp_list__register_sort_field(list, &hse->hpp);
1586 return 0; 1630 return 0;
1587} 1631}
1588 1632
1589static int __sort_dimension__add_hpp_output(struct sort_dimension *sd) 1633static int __sort_dimension__add_hpp_output(struct sort_dimension *sd,
1634 struct perf_hpp_list *list)
1590{ 1635{
1591 struct hpp_sort_entry *hse = __sort_dimension__alloc_hpp(sd); 1636 struct hpp_sort_entry *hse = __sort_dimension__alloc_hpp(sd, 0);
1592 1637
1593 if (hse == NULL) 1638 if (hse == NULL)
1594 return -1; 1639 return -1;
1595 1640
1596 perf_hpp__column_register(&hse->hpp); 1641 perf_hpp_list__column_register(list, &hse->hpp);
1597 return 0; 1642 return 0;
1598} 1643}
1599 1644
@@ -1727,6 +1772,9 @@ static int __sort__hde_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
1727 if (hde->raw_trace) 1772 if (hde->raw_trace)
1728 goto raw_field; 1773 goto raw_field;
1729 1774
1775 if (!he->trace_output)
1776 he->trace_output = get_trace_output(he);
1777
1730 field = hde->field; 1778 field = hde->field;
1731 namelen = strlen(field->name); 1779 namelen = strlen(field->name);
1732 str = he->trace_output; 1780 str = he->trace_output;
@@ -1776,6 +1824,11 @@ static int64_t __sort__hde_cmp(struct perf_hpp_fmt *fmt,
1776 1824
1777 hde = container_of(fmt, struct hpp_dynamic_entry, hpp); 1825 hde = container_of(fmt, struct hpp_dynamic_entry, hpp);
1778 1826
1827 if (b == NULL) {
1828 update_dynamic_len(hde, a);
1829 return 0;
1830 }
1831
1779 field = hde->field; 1832 field = hde->field;
1780 if (field->flags & FIELD_IS_DYNAMIC) { 1833 if (field->flags & FIELD_IS_DYNAMIC) {
1781 unsigned long long dyn; 1834 unsigned long long dyn;
@@ -1790,9 +1843,6 @@ static int64_t __sort__hde_cmp(struct perf_hpp_fmt *fmt,
1790 } else { 1843 } else {
1791 offset = field->offset; 1844 offset = field->offset;
1792 size = field->size; 1845 size = field->size;
1793
1794 update_dynamic_len(hde, a);
1795 update_dynamic_len(hde, b);
1796 } 1846 }
1797 1847
1798 return memcmp(a->raw_data + offset, b->raw_data + offset, size); 1848 return memcmp(a->raw_data + offset, b->raw_data + offset, size);
@@ -1803,8 +1853,31 @@ bool perf_hpp__is_dynamic_entry(struct perf_hpp_fmt *fmt)
1803 return fmt->cmp == __sort__hde_cmp; 1853 return fmt->cmp == __sort__hde_cmp;
1804} 1854}
1805 1855
1856static bool __sort__hde_equal(struct perf_hpp_fmt *a, struct perf_hpp_fmt *b)
1857{
1858 struct hpp_dynamic_entry *hde_a;
1859 struct hpp_dynamic_entry *hde_b;
1860
1861 if (!perf_hpp__is_dynamic_entry(a) || !perf_hpp__is_dynamic_entry(b))
1862 return false;
1863
1864 hde_a = container_of(a, struct hpp_dynamic_entry, hpp);
1865 hde_b = container_of(b, struct hpp_dynamic_entry, hpp);
1866
1867 return hde_a->field == hde_b->field;
1868}
1869
1870static void hde_free(struct perf_hpp_fmt *fmt)
1871{
1872 struct hpp_dynamic_entry *hde;
1873
1874 hde = container_of(fmt, struct hpp_dynamic_entry, hpp);
1875 free(hde);
1876}
1877
1806static struct hpp_dynamic_entry * 1878static struct hpp_dynamic_entry *
1807__alloc_dynamic_entry(struct perf_evsel *evsel, struct format_field *field) 1879__alloc_dynamic_entry(struct perf_evsel *evsel, struct format_field *field,
1880 int level)
1808{ 1881{
1809 struct hpp_dynamic_entry *hde; 1882 struct hpp_dynamic_entry *hde;
1810 1883
@@ -1827,16 +1900,47 @@ __alloc_dynamic_entry(struct perf_evsel *evsel, struct format_field *field)
1827 hde->hpp.cmp = __sort__hde_cmp; 1900 hde->hpp.cmp = __sort__hde_cmp;
1828 hde->hpp.collapse = __sort__hde_cmp; 1901 hde->hpp.collapse = __sort__hde_cmp;
1829 hde->hpp.sort = __sort__hde_cmp; 1902 hde->hpp.sort = __sort__hde_cmp;
1903 hde->hpp.equal = __sort__hde_equal;
1904 hde->hpp.free = hde_free;
1830 1905
1831 INIT_LIST_HEAD(&hde->hpp.list); 1906 INIT_LIST_HEAD(&hde->hpp.list);
1832 INIT_LIST_HEAD(&hde->hpp.sort_list); 1907 INIT_LIST_HEAD(&hde->hpp.sort_list);
1833 hde->hpp.elide = false; 1908 hde->hpp.elide = false;
1834 hde->hpp.len = 0; 1909 hde->hpp.len = 0;
1835 hde->hpp.user_len = 0; 1910 hde->hpp.user_len = 0;
1911 hde->hpp.level = level;
1836 1912
1837 return hde; 1913 return hde;
1838} 1914}
1839 1915
1916struct perf_hpp_fmt *perf_hpp_fmt__dup(struct perf_hpp_fmt *fmt)
1917{
1918 struct perf_hpp_fmt *new_fmt = NULL;
1919
1920 if (perf_hpp__is_sort_entry(fmt)) {
1921 struct hpp_sort_entry *hse, *new_hse;
1922
1923 hse = container_of(fmt, struct hpp_sort_entry, hpp);
1924 new_hse = memdup(hse, sizeof(*hse));
1925 if (new_hse)
1926 new_fmt = &new_hse->hpp;
1927 } else if (perf_hpp__is_dynamic_entry(fmt)) {
1928 struct hpp_dynamic_entry *hde, *new_hde;
1929
1930 hde = container_of(fmt, struct hpp_dynamic_entry, hpp);
1931 new_hde = memdup(hde, sizeof(*hde));
1932 if (new_hde)
1933 new_fmt = &new_hde->hpp;
1934 } else {
1935 new_fmt = memdup(fmt, sizeof(*fmt));
1936 }
1937
1938 INIT_LIST_HEAD(&new_fmt->list);
1939 INIT_LIST_HEAD(&new_fmt->sort_list);
1940
1941 return new_fmt;
1942}
1943
1840static int parse_field_name(char *str, char **event, char **field, char **opt) 1944static int parse_field_name(char *str, char **event, char **field, char **opt)
1841{ 1945{
1842 char *event_name, *field_name, *opt_name; 1946 char *event_name, *field_name, *opt_name;
@@ -1908,11 +2012,11 @@ static struct perf_evsel *find_evsel(struct perf_evlist *evlist, char *event_nam
1908 2012
1909static int __dynamic_dimension__add(struct perf_evsel *evsel, 2013static int __dynamic_dimension__add(struct perf_evsel *evsel,
1910 struct format_field *field, 2014 struct format_field *field,
1911 bool raw_trace) 2015 bool raw_trace, int level)
1912{ 2016{
1913 struct hpp_dynamic_entry *hde; 2017 struct hpp_dynamic_entry *hde;
1914 2018
1915 hde = __alloc_dynamic_entry(evsel, field); 2019 hde = __alloc_dynamic_entry(evsel, field, level);
1916 if (hde == NULL) 2020 if (hde == NULL)
1917 return -ENOMEM; 2021 return -ENOMEM;
1918 2022
@@ -1922,14 +2026,14 @@ static int __dynamic_dimension__add(struct perf_evsel *evsel,
1922 return 0; 2026 return 0;
1923} 2027}
1924 2028
1925static int add_evsel_fields(struct perf_evsel *evsel, bool raw_trace) 2029static int add_evsel_fields(struct perf_evsel *evsel, bool raw_trace, int level)
1926{ 2030{
1927 int ret; 2031 int ret;
1928 struct format_field *field; 2032 struct format_field *field;
1929 2033
1930 field = evsel->tp_format->format.fields; 2034 field = evsel->tp_format->format.fields;
1931 while (field) { 2035 while (field) {
1932 ret = __dynamic_dimension__add(evsel, field, raw_trace); 2036 ret = __dynamic_dimension__add(evsel, field, raw_trace, level);
1933 if (ret < 0) 2037 if (ret < 0)
1934 return ret; 2038 return ret;
1935 2039
@@ -1938,7 +2042,8 @@ static int add_evsel_fields(struct perf_evsel *evsel, bool raw_trace)
1938 return 0; 2042 return 0;
1939} 2043}
1940 2044
1941static int add_all_dynamic_fields(struct perf_evlist *evlist, bool raw_trace) 2045static int add_all_dynamic_fields(struct perf_evlist *evlist, bool raw_trace,
2046 int level)
1942{ 2047{
1943 int ret; 2048 int ret;
1944 struct perf_evsel *evsel; 2049 struct perf_evsel *evsel;
@@ -1947,7 +2052,7 @@ static int add_all_dynamic_fields(struct perf_evlist *evlist, bool raw_trace)
1947 if (evsel->attr.type != PERF_TYPE_TRACEPOINT) 2052 if (evsel->attr.type != PERF_TYPE_TRACEPOINT)
1948 continue; 2053 continue;
1949 2054
1950 ret = add_evsel_fields(evsel, raw_trace); 2055 ret = add_evsel_fields(evsel, raw_trace, level);
1951 if (ret < 0) 2056 if (ret < 0)
1952 return ret; 2057 return ret;
1953 } 2058 }
@@ -1955,7 +2060,7 @@ static int add_all_dynamic_fields(struct perf_evlist *evlist, bool raw_trace)
1955} 2060}
1956 2061
1957static int add_all_matching_fields(struct perf_evlist *evlist, 2062static int add_all_matching_fields(struct perf_evlist *evlist,
1958 char *field_name, bool raw_trace) 2063 char *field_name, bool raw_trace, int level)
1959{ 2064{
1960 int ret = -ESRCH; 2065 int ret = -ESRCH;
1961 struct perf_evsel *evsel; 2066 struct perf_evsel *evsel;
@@ -1969,14 +2074,15 @@ static int add_all_matching_fields(struct perf_evlist *evlist,
1969 if (field == NULL) 2074 if (field == NULL)
1970 continue; 2075 continue;
1971 2076
1972 ret = __dynamic_dimension__add(evsel, field, raw_trace); 2077 ret = __dynamic_dimension__add(evsel, field, raw_trace, level);
1973 if (ret < 0) 2078 if (ret < 0)
1974 break; 2079 break;
1975 } 2080 }
1976 return ret; 2081 return ret;
1977} 2082}
1978 2083
1979static int add_dynamic_entry(struct perf_evlist *evlist, const char *tok) 2084static int add_dynamic_entry(struct perf_evlist *evlist, const char *tok,
2085 int level)
1980{ 2086{
1981 char *str, *event_name, *field_name, *opt_name; 2087 char *str, *event_name, *field_name, *opt_name;
1982 struct perf_evsel *evsel; 2088 struct perf_evsel *evsel;
@@ -2006,12 +2112,12 @@ static int add_dynamic_entry(struct perf_evlist *evlist, const char *tok)
2006 } 2112 }
2007 2113
2008 if (!strcmp(field_name, "trace_fields")) { 2114 if (!strcmp(field_name, "trace_fields")) {
2009 ret = add_all_dynamic_fields(evlist, raw_trace); 2115 ret = add_all_dynamic_fields(evlist, raw_trace, level);
2010 goto out; 2116 goto out;
2011 } 2117 }
2012 2118
2013 if (event_name == NULL) { 2119 if (event_name == NULL) {
2014 ret = add_all_matching_fields(evlist, field_name, raw_trace); 2120 ret = add_all_matching_fields(evlist, field_name, raw_trace, level);
2015 goto out; 2121 goto out;
2016 } 2122 }
2017 2123
@@ -2029,7 +2135,7 @@ static int add_dynamic_entry(struct perf_evlist *evlist, const char *tok)
2029 } 2135 }
2030 2136
2031 if (!strcmp(field_name, "*")) { 2137 if (!strcmp(field_name, "*")) {
2032 ret = add_evsel_fields(evsel, raw_trace); 2138 ret = add_evsel_fields(evsel, raw_trace, level);
2033 } else { 2139 } else {
2034 field = pevent_find_any_field(evsel->tp_format, field_name); 2140 field = pevent_find_any_field(evsel->tp_format, field_name);
2035 if (field == NULL) { 2141 if (field == NULL) {
@@ -2038,7 +2144,7 @@ static int add_dynamic_entry(struct perf_evlist *evlist, const char *tok)
2038 return -ENOENT; 2144 return -ENOENT;
2039 } 2145 }
2040 2146
2041 ret = __dynamic_dimension__add(evsel, field, raw_trace); 2147 ret = __dynamic_dimension__add(evsel, field, raw_trace, level);
2042 } 2148 }
2043 2149
2044out: 2150out:
@@ -2046,12 +2152,14 @@ out:
2046 return ret; 2152 return ret;
2047} 2153}
2048 2154
2049static int __sort_dimension__add(struct sort_dimension *sd) 2155static int __sort_dimension__add(struct sort_dimension *sd,
2156 struct perf_hpp_list *list,
2157 int level)
2050{ 2158{
2051 if (sd->taken) 2159 if (sd->taken)
2052 return 0; 2160 return 0;
2053 2161
2054 if (__sort_dimension__add_hpp_sort(sd) < 0) 2162 if (__sort_dimension__add_hpp_sort(sd, list, level) < 0)
2055 return -1; 2163 return -1;
2056 2164
2057 if (sd->entry->se_collapse) 2165 if (sd->entry->se_collapse)
@@ -2062,46 +2170,63 @@ static int __sort_dimension__add(struct sort_dimension *sd)
2062 return 0; 2170 return 0;
2063} 2171}
2064 2172
2065static int __hpp_dimension__add(struct hpp_dimension *hd) 2173static int __hpp_dimension__add(struct hpp_dimension *hd,
2174 struct perf_hpp_list *list,
2175 int level)
2066{ 2176{
2067 if (!hd->taken) { 2177 struct perf_hpp_fmt *fmt;
2068 hd->taken = 1;
2069 2178
2070 perf_hpp__register_sort_field(hd->fmt); 2179 if (hd->taken)
2071 } 2180 return 0;
2181
2182 fmt = __hpp_dimension__alloc_hpp(hd, level);
2183 if (!fmt)
2184 return -1;
2185
2186 hd->taken = 1;
2187 perf_hpp_list__register_sort_field(list, fmt);
2072 return 0; 2188 return 0;
2073} 2189}
2074 2190
2075static int __sort_dimension__add_output(struct sort_dimension *sd) 2191static int __sort_dimension__add_output(struct perf_hpp_list *list,
2192 struct sort_dimension *sd)
2076{ 2193{
2077 if (sd->taken) 2194 if (sd->taken)
2078 return 0; 2195 return 0;
2079 2196
2080 if (__sort_dimension__add_hpp_output(sd) < 0) 2197 if (__sort_dimension__add_hpp_output(sd, list) < 0)
2081 return -1; 2198 return -1;
2082 2199
2083 sd->taken = 1; 2200 sd->taken = 1;
2084 return 0; 2201 return 0;
2085} 2202}
2086 2203
2087static int __hpp_dimension__add_output(struct hpp_dimension *hd) 2204static int __hpp_dimension__add_output(struct perf_hpp_list *list,
2205 struct hpp_dimension *hd)
2088{ 2206{
2089 if (!hd->taken) { 2207 struct perf_hpp_fmt *fmt;
2090 hd->taken = 1;
2091 2208
2092 perf_hpp__column_register(hd->fmt); 2209 if (hd->taken)
2093 } 2210 return 0;
2211
2212 fmt = __hpp_dimension__alloc_hpp(hd, 0);
2213 if (!fmt)
2214 return -1;
2215
2216 hd->taken = 1;
2217 perf_hpp_list__column_register(list, fmt);
2094 return 0; 2218 return 0;
2095} 2219}
2096 2220
2097int hpp_dimension__add_output(unsigned col) 2221int hpp_dimension__add_output(unsigned col)
2098{ 2222{
2099 BUG_ON(col >= PERF_HPP__MAX_INDEX); 2223 BUG_ON(col >= PERF_HPP__MAX_INDEX);
2100 return __hpp_dimension__add_output(&hpp_sort_dimensions[col]); 2224 return __hpp_dimension__add_output(&perf_hpp_list, &hpp_sort_dimensions[col]);
2101} 2225}
2102 2226
2103static int sort_dimension__add(const char *tok, 2227static int sort_dimension__add(struct perf_hpp_list *list, const char *tok,
2104 struct perf_evlist *evlist __maybe_unused) 2228 struct perf_evlist *evlist,
2229 int level)
2105{ 2230{
2106 unsigned int i; 2231 unsigned int i;
2107 2232
@@ -2136,9 +2261,13 @@ static int sort_dimension__add(const char *tok,
2136 sort__has_dso = 1; 2261 sort__has_dso = 1;
2137 } else if (sd->entry == &sort_socket) { 2262 } else if (sd->entry == &sort_socket) {
2138 sort__has_socket = 1; 2263 sort__has_socket = 1;
2264 } else if (sd->entry == &sort_thread) {
2265 sort__has_thread = 1;
2266 } else if (sd->entry == &sort_comm) {
2267 sort__has_comm = 1;
2139 } 2268 }
2140 2269
2141 return __sort_dimension__add(sd); 2270 return __sort_dimension__add(sd, list, level);
2142 } 2271 }
2143 2272
2144 for (i = 0; i < ARRAY_SIZE(hpp_sort_dimensions); i++) { 2273 for (i = 0; i < ARRAY_SIZE(hpp_sort_dimensions); i++) {
@@ -2147,7 +2276,7 @@ static int sort_dimension__add(const char *tok,
2147 if (strncasecmp(tok, hd->name, strlen(tok))) 2276 if (strncasecmp(tok, hd->name, strlen(tok)))
2148 continue; 2277 continue;
2149 2278
2150 return __hpp_dimension__add(hd); 2279 return __hpp_dimension__add(hd, list, level);
2151 } 2280 }
2152 2281
2153 for (i = 0; i < ARRAY_SIZE(bstack_sort_dimensions); i++) { 2282 for (i = 0; i < ARRAY_SIZE(bstack_sort_dimensions); i++) {
@@ -2162,7 +2291,7 @@ static int sort_dimension__add(const char *tok,
2162 if (sd->entry == &sort_sym_from || sd->entry == &sort_sym_to) 2291 if (sd->entry == &sort_sym_from || sd->entry == &sort_sym_to)
2163 sort__has_sym = 1; 2292 sort__has_sym = 1;
2164 2293
2165 __sort_dimension__add(sd); 2294 __sort_dimension__add(sd, list, level);
2166 return 0; 2295 return 0;
2167 } 2296 }
2168 2297
@@ -2178,16 +2307,60 @@ static int sort_dimension__add(const char *tok,
2178 if (sd->entry == &sort_mem_daddr_sym) 2307 if (sd->entry == &sort_mem_daddr_sym)
2179 sort__has_sym = 1; 2308 sort__has_sym = 1;
2180 2309
2181 __sort_dimension__add(sd); 2310 __sort_dimension__add(sd, list, level);
2182 return 0; 2311 return 0;
2183 } 2312 }
2184 2313
2185 if (!add_dynamic_entry(evlist, tok)) 2314 if (!add_dynamic_entry(evlist, tok, level))
2186 return 0; 2315 return 0;
2187 2316
2188 return -ESRCH; 2317 return -ESRCH;
2189} 2318}
2190 2319
2320static int setup_sort_list(struct perf_hpp_list *list, char *str,
2321 struct perf_evlist *evlist)
2322{
2323 char *tmp, *tok;
2324 int ret = 0;
2325 int level = 0;
2326 int next_level = 1;
2327 bool in_group = false;
2328
2329 do {
2330 tok = str;
2331 tmp = strpbrk(str, "{}, ");
2332 if (tmp) {
2333 if (in_group)
2334 next_level = level;
2335 else
2336 next_level = level + 1;
2337
2338 if (*tmp == '{')
2339 in_group = true;
2340 else if (*tmp == '}')
2341 in_group = false;
2342
2343 *tmp = '\0';
2344 str = tmp + 1;
2345 }
2346
2347 if (*tok) {
2348 ret = sort_dimension__add(list, tok, evlist, level);
2349 if (ret == -EINVAL) {
2350 error("Invalid --sort key: `%s'", tok);
2351 break;
2352 } else if (ret == -ESRCH) {
2353 error("Unknown --sort key: `%s'", tok);
2354 break;
2355 }
2356 }
2357
2358 level = next_level;
2359 } while (tmp);
2360
2361 return ret;
2362}
2363
2191static const char *get_default_sort_order(struct perf_evlist *evlist) 2364static const char *get_default_sort_order(struct perf_evlist *evlist)
2192{ 2365{
2193 const char *default_sort_orders[] = { 2366 const char *default_sort_orders[] = {
@@ -2282,7 +2455,7 @@ static char *setup_overhead(char *keys)
2282 2455
2283static int __setup_sorting(struct perf_evlist *evlist) 2456static int __setup_sorting(struct perf_evlist *evlist)
2284{ 2457{
2285 char *tmp, *tok, *str; 2458 char *str;
2286 const char *sort_keys; 2459 const char *sort_keys;
2287 int ret = 0; 2460 int ret = 0;
2288 2461
@@ -2320,17 +2493,7 @@ static int __setup_sorting(struct perf_evlist *evlist)
2320 } 2493 }
2321 } 2494 }
2322 2495
2323 for (tok = strtok_r(str, ", ", &tmp); 2496 ret = setup_sort_list(&perf_hpp_list, str, evlist);
2324 tok; tok = strtok_r(NULL, ", ", &tmp)) {
2325 ret = sort_dimension__add(tok, evlist);
2326 if (ret == -EINVAL) {
2327 error("Invalid --sort key: `%s'", tok);
2328 break;
2329 } else if (ret == -ESRCH) {
2330 error("Unknown --sort key: `%s'", tok);
2331 break;
2332 }
2333 }
2334 2497
2335 free(str); 2498 free(str);
2336 return ret; 2499 return ret;
@@ -2341,7 +2504,7 @@ void perf_hpp__set_elide(int idx, bool elide)
2341 struct perf_hpp_fmt *fmt; 2504 struct perf_hpp_fmt *fmt;
2342 struct hpp_sort_entry *hse; 2505 struct hpp_sort_entry *hse;
2343 2506
2344 perf_hpp__for_each_format(fmt) { 2507 perf_hpp_list__for_each_format(&perf_hpp_list, fmt) {
2345 if (!perf_hpp__is_sort_entry(fmt)) 2508 if (!perf_hpp__is_sort_entry(fmt))
2346 continue; 2509 continue;
2347 2510
@@ -2401,7 +2564,7 @@ void sort__setup_elide(FILE *output)
2401 struct perf_hpp_fmt *fmt; 2564 struct perf_hpp_fmt *fmt;
2402 struct hpp_sort_entry *hse; 2565 struct hpp_sort_entry *hse;
2403 2566
2404 perf_hpp__for_each_format(fmt) { 2567 perf_hpp_list__for_each_format(&perf_hpp_list, fmt) {
2405 if (!perf_hpp__is_sort_entry(fmt)) 2568 if (!perf_hpp__is_sort_entry(fmt))
2406 continue; 2569 continue;
2407 2570
@@ -2413,7 +2576,7 @@ void sort__setup_elide(FILE *output)
2413 * It makes no sense to elide all of sort entries. 2576 * It makes no sense to elide all of sort entries.
2414 * Just revert them to show up again. 2577 * Just revert them to show up again.
2415 */ 2578 */
2416 perf_hpp__for_each_format(fmt) { 2579 perf_hpp_list__for_each_format(&perf_hpp_list, fmt) {
2417 if (!perf_hpp__is_sort_entry(fmt)) 2580 if (!perf_hpp__is_sort_entry(fmt))
2418 continue; 2581 continue;
2419 2582
@@ -2421,7 +2584,7 @@ void sort__setup_elide(FILE *output)
2421 return; 2584 return;
2422 } 2585 }
2423 2586
2424 perf_hpp__for_each_format(fmt) { 2587 perf_hpp_list__for_each_format(&perf_hpp_list, fmt) {
2425 if (!perf_hpp__is_sort_entry(fmt)) 2588 if (!perf_hpp__is_sort_entry(fmt))
2426 continue; 2589 continue;
2427 2590
@@ -2429,7 +2592,7 @@ void sort__setup_elide(FILE *output)
2429 } 2592 }
2430} 2593}
2431 2594
2432static int output_field_add(char *tok) 2595static int output_field_add(struct perf_hpp_list *list, char *tok)
2433{ 2596{
2434 unsigned int i; 2597 unsigned int i;
2435 2598
@@ -2439,7 +2602,7 @@ static int output_field_add(char *tok)
2439 if (strncasecmp(tok, sd->name, strlen(tok))) 2602 if (strncasecmp(tok, sd->name, strlen(tok)))
2440 continue; 2603 continue;
2441 2604
2442 return __sort_dimension__add_output(sd); 2605 return __sort_dimension__add_output(list, sd);
2443 } 2606 }
2444 2607
2445 for (i = 0; i < ARRAY_SIZE(hpp_sort_dimensions); i++) { 2608 for (i = 0; i < ARRAY_SIZE(hpp_sort_dimensions); i++) {
@@ -2448,7 +2611,7 @@ static int output_field_add(char *tok)
2448 if (strncasecmp(tok, hd->name, strlen(tok))) 2611 if (strncasecmp(tok, hd->name, strlen(tok)))
2449 continue; 2612 continue;
2450 2613
2451 return __hpp_dimension__add_output(hd); 2614 return __hpp_dimension__add_output(list, hd);
2452 } 2615 }
2453 2616
2454 for (i = 0; i < ARRAY_SIZE(bstack_sort_dimensions); i++) { 2617 for (i = 0; i < ARRAY_SIZE(bstack_sort_dimensions); i++) {
@@ -2457,7 +2620,7 @@ static int output_field_add(char *tok)
2457 if (strncasecmp(tok, sd->name, strlen(tok))) 2620 if (strncasecmp(tok, sd->name, strlen(tok)))
2458 continue; 2621 continue;
2459 2622
2460 return __sort_dimension__add_output(sd); 2623 return __sort_dimension__add_output(list, sd);
2461 } 2624 }
2462 2625
2463 for (i = 0; i < ARRAY_SIZE(memory_sort_dimensions); i++) { 2626 for (i = 0; i < ARRAY_SIZE(memory_sort_dimensions); i++) {
@@ -2466,12 +2629,32 @@ static int output_field_add(char *tok)
2466 if (strncasecmp(tok, sd->name, strlen(tok))) 2629 if (strncasecmp(tok, sd->name, strlen(tok)))
2467 continue; 2630 continue;
2468 2631
2469 return __sort_dimension__add_output(sd); 2632 return __sort_dimension__add_output(list, sd);
2470 } 2633 }
2471 2634
2472 return -ESRCH; 2635 return -ESRCH;
2473} 2636}
2474 2637
2638static int setup_output_list(struct perf_hpp_list *list, char *str)
2639{
2640 char *tmp, *tok;
2641 int ret = 0;
2642
2643 for (tok = strtok_r(str, ", ", &tmp);
2644 tok; tok = strtok_r(NULL, ", ", &tmp)) {
2645 ret = output_field_add(list, tok);
2646 if (ret == -EINVAL) {
2647 error("Invalid --fields key: `%s'", tok);
2648 break;
2649 } else if (ret == -ESRCH) {
2650 error("Unknown --fields key: `%s'", tok);
2651 break;
2652 }
2653 }
2654
2655 return ret;
2656}
2657
2475static void reset_dimensions(void) 2658static void reset_dimensions(void)
2476{ 2659{
2477 unsigned int i; 2660 unsigned int i;
@@ -2496,7 +2679,7 @@ bool is_strict_order(const char *order)
2496 2679
2497static int __setup_output_field(void) 2680static int __setup_output_field(void)
2498{ 2681{
2499 char *tmp, *tok, *str, *strp; 2682 char *str, *strp;
2500 int ret = -EINVAL; 2683 int ret = -EINVAL;
2501 2684
2502 if (field_order == NULL) 2685 if (field_order == NULL)
@@ -2516,17 +2699,7 @@ static int __setup_output_field(void)
2516 goto out; 2699 goto out;
2517 } 2700 }
2518 2701
2519 for (tok = strtok_r(strp, ", ", &tmp); 2702 ret = setup_output_list(&perf_hpp_list, strp);
2520 tok; tok = strtok_r(NULL, ", ", &tmp)) {
2521 ret = output_field_add(tok);
2522 if (ret == -EINVAL) {
2523 error("Invalid --fields key: `%s'", tok);
2524 break;
2525 } else if (ret == -ESRCH) {
2526 error("Unknown --fields key: `%s'", tok);
2527 break;
2528 }
2529 }
2530 2703
2531out: 2704out:
2532 free(str); 2705 free(str);
@@ -2542,7 +2715,7 @@ int setup_sorting(struct perf_evlist *evlist)
2542 return err; 2715 return err;
2543 2716
2544 if (parent_pattern != default_parent_pattern) { 2717 if (parent_pattern != default_parent_pattern) {
2545 err = sort_dimension__add("parent", evlist); 2718 err = sort_dimension__add(&perf_hpp_list, "parent", evlist, -1);
2546 if (err < 0) 2719 if (err < 0)
2547 return err; 2720 return err;
2548 } 2721 }
@@ -2560,9 +2733,13 @@ int setup_sorting(struct perf_evlist *evlist)
2560 return err; 2733 return err;
2561 2734
2562 /* copy sort keys to output fields */ 2735 /* copy sort keys to output fields */
2563 perf_hpp__setup_output_field(); 2736 perf_hpp__setup_output_field(&perf_hpp_list);
2564 /* and then copy output fields to sort keys */ 2737 /* and then copy output fields to sort keys */
2565 perf_hpp__append_sort_keys(); 2738 perf_hpp__append_sort_keys(&perf_hpp_list);
2739
2740 /* setup hists-specific output fields */
2741 if (perf_hpp__setup_hists_formats(&perf_hpp_list, evlist) < 0)
2742 return -1;
2566 2743
2567 return 0; 2744 return 0;
2568} 2745}
@@ -2578,5 +2755,5 @@ void reset_output_field(void)
2578 sort_order = NULL; 2755 sort_order = NULL;
2579 2756
2580 reset_dimensions(); 2757 reset_dimensions();
2581 perf_hpp__reset_output_field(); 2758 perf_hpp__reset_output_field(&perf_hpp_list);
2582} 2759}
diff --git a/tools/perf/util/sort.h b/tools/perf/util/sort.h
index 687bbb124428..3f4e35998119 100644
--- a/tools/perf/util/sort.h
+++ b/tools/perf/util/sort.h
@@ -32,9 +32,12 @@ extern const char default_sort_order[];
32extern regex_t ignore_callees_regex; 32extern regex_t ignore_callees_regex;
33extern int have_ignore_callees; 33extern int have_ignore_callees;
34extern int sort__need_collapse; 34extern int sort__need_collapse;
35extern int sort__has_dso;
35extern int sort__has_parent; 36extern int sort__has_parent;
36extern int sort__has_sym; 37extern int sort__has_sym;
37extern int sort__has_socket; 38extern int sort__has_socket;
39extern int sort__has_thread;
40extern int sort__has_comm;
38extern enum sort_mode sort__mode; 41extern enum sort_mode sort__mode;
39extern struct sort_entry sort_comm; 42extern struct sort_entry sort_comm;
40extern struct sort_entry sort_dso; 43extern struct sort_entry sort_dso;
@@ -94,9 +97,11 @@ struct hist_entry {
94 s32 socket; 97 s32 socket;
95 s32 cpu; 98 s32 cpu;
96 u8 cpumode; 99 u8 cpumode;
100 u8 depth;
97 101
98 /* We are added by hists__add_dummy_entry. */ 102 /* We are added by hists__add_dummy_entry. */
99 bool dummy; 103 bool dummy;
104 bool leaf;
100 105
101 char level; 106 char level;
102 u8 filtered; 107 u8 filtered;
@@ -113,18 +118,28 @@ struct hist_entry {
113 bool init_have_children; 118 bool init_have_children;
114 bool unfolded; 119 bool unfolded;
115 bool has_children; 120 bool has_children;
121 bool has_no_entry;
116 }; 122 };
117 }; 123 };
118 char *srcline; 124 char *srcline;
119 char *srcfile; 125 char *srcfile;
120 struct symbol *parent; 126 struct symbol *parent;
121 struct rb_root sorted_chain;
122 struct branch_info *branch_info; 127 struct branch_info *branch_info;
123 struct hists *hists; 128 struct hists *hists;
124 struct mem_info *mem_info; 129 struct mem_info *mem_info;
125 void *raw_data; 130 void *raw_data;
126 u32 raw_size; 131 u32 raw_size;
127 void *trace_output; 132 void *trace_output;
133 struct perf_hpp_list *hpp_list;
134 struct hist_entry *parent_he;
135 union {
136 /* this is for hierarchical entry structure */
137 struct {
138 struct rb_root hroot_in;
139 struct rb_root hroot_out;
140 }; /* non-leaf entries */
141 struct rb_root sorted_chain; /* leaf entry has callchains */
142 };
128 struct callchain_root callchain[0]; /* must be last member */ 143 struct callchain_root callchain[0]; /* must be last member */
129}; 144};
130 145
@@ -160,6 +175,17 @@ static inline float hist_entry__get_percent_limit(struct hist_entry *he)
160 return period * 100.0 / total_period; 175 return period * 100.0 / total_period;
161} 176}
162 177
178static inline u64 cl_address(u64 address)
179{
180 /* return the cacheline of the address */
181 return (address & ~(cacheline_size - 1));
182}
183
184static inline u64 cl_offset(u64 address)
185{
186 /* return the cacheline of the address */
187 return (address & (cacheline_size - 1));
188}
163 189
164enum sort_mode { 190enum sort_mode {
165 SORT_MODE__NORMAL, 191 SORT_MODE__NORMAL,
@@ -221,6 +247,7 @@ struct sort_entry {
221 int64_t (*se_sort)(struct hist_entry *, struct hist_entry *); 247 int64_t (*se_sort)(struct hist_entry *, struct hist_entry *);
222 int (*se_snprintf)(struct hist_entry *he, char *bf, size_t size, 248 int (*se_snprintf)(struct hist_entry *he, char *bf, size_t size,
223 unsigned int width); 249 unsigned int width);
250 int (*se_filter)(struct hist_entry *he, int type, const void *arg);
224 u8 se_width_idx; 251 u8 se_width_idx;
225}; 252};
226 253
diff --git a/tools/perf/util/stat-shadow.c b/tools/perf/util/stat-shadow.c
index 6ac03146889d..fdb71961143e 100644
--- a/tools/perf/util/stat-shadow.c
+++ b/tools/perf/util/stat-shadow.c
@@ -2,6 +2,7 @@
2#include "evsel.h" 2#include "evsel.h"
3#include "stat.h" 3#include "stat.h"
4#include "color.h" 4#include "color.h"
5#include "pmu.h"
5 6
6enum { 7enum {
7 CTX_BIT_USER = 1 << 0, 8 CTX_BIT_USER = 1 << 0,
@@ -14,6 +15,13 @@ enum {
14 15
15#define NUM_CTX CTX_BIT_MAX 16#define NUM_CTX CTX_BIT_MAX
16 17
18/*
19 * AGGR_GLOBAL: Use CPU 0
20 * AGGR_SOCKET: Use first CPU of socket
21 * AGGR_CORE: Use first CPU of core
22 * AGGR_NONE: Use matching CPU
23 * AGGR_THREAD: Not supported?
24 */
17static struct stats runtime_nsecs_stats[MAX_NR_CPUS]; 25static struct stats runtime_nsecs_stats[MAX_NR_CPUS];
18static struct stats runtime_cycles_stats[NUM_CTX][MAX_NR_CPUS]; 26static struct stats runtime_cycles_stats[NUM_CTX][MAX_NR_CPUS];
19static struct stats runtime_stalled_cycles_front_stats[NUM_CTX][MAX_NR_CPUS]; 27static struct stats runtime_stalled_cycles_front_stats[NUM_CTX][MAX_NR_CPUS];
@@ -28,9 +36,15 @@ static struct stats runtime_dtlb_cache_stats[NUM_CTX][MAX_NR_CPUS];
28static struct stats runtime_cycles_in_tx_stats[NUM_CTX][MAX_NR_CPUS]; 36static struct stats runtime_cycles_in_tx_stats[NUM_CTX][MAX_NR_CPUS];
29static struct stats runtime_transaction_stats[NUM_CTX][MAX_NR_CPUS]; 37static struct stats runtime_transaction_stats[NUM_CTX][MAX_NR_CPUS];
30static struct stats runtime_elision_stats[NUM_CTX][MAX_NR_CPUS]; 38static struct stats runtime_elision_stats[NUM_CTX][MAX_NR_CPUS];
39static bool have_frontend_stalled;
31 40
32struct stats walltime_nsecs_stats; 41struct stats walltime_nsecs_stats;
33 42
43void perf_stat__init_shadow_stats(void)
44{
45 have_frontend_stalled = pmu_have_event("cpu", "stalled-cycles-frontend");
46}
47
34static int evsel_context(struct perf_evsel *evsel) 48static int evsel_context(struct perf_evsel *evsel)
35{ 49{
36 int ctx = 0; 50 int ctx = 0;
@@ -137,9 +151,9 @@ static const char *get_ratio_color(enum grc_type type, double ratio)
137 return color; 151 return color;
138} 152}
139 153
140static void print_stalled_cycles_frontend(FILE *out, int cpu, 154static void print_stalled_cycles_frontend(int cpu,
141 struct perf_evsel *evsel 155 struct perf_evsel *evsel, double avg,
142 __maybe_unused, double avg) 156 struct perf_stat_output_ctx *out)
143{ 157{
144 double total, ratio = 0.0; 158 double total, ratio = 0.0;
145 const char *color; 159 const char *color;
@@ -152,14 +166,16 @@ static void print_stalled_cycles_frontend(FILE *out, int cpu,
152 166
153 color = get_ratio_color(GRC_STALLED_CYCLES_FE, ratio); 167 color = get_ratio_color(GRC_STALLED_CYCLES_FE, ratio);
154 168
155 fprintf(out, " # "); 169 if (ratio)
156 color_fprintf(out, color, "%6.2f%%", ratio); 170 out->print_metric(out->ctx, color, "%7.2f%%", "frontend cycles idle",
157 fprintf(out, " frontend cycles idle "); 171 ratio);
172 else
173 out->print_metric(out->ctx, NULL, NULL, "frontend cycles idle", 0);
158} 174}
159 175
160static void print_stalled_cycles_backend(FILE *out, int cpu, 176static void print_stalled_cycles_backend(int cpu,
161 struct perf_evsel *evsel 177 struct perf_evsel *evsel, double avg,
162 __maybe_unused, double avg) 178 struct perf_stat_output_ctx *out)
163{ 179{
164 double total, ratio = 0.0; 180 double total, ratio = 0.0;
165 const char *color; 181 const char *color;
@@ -172,14 +188,13 @@ static void print_stalled_cycles_backend(FILE *out, int cpu,
172 188
173 color = get_ratio_color(GRC_STALLED_CYCLES_BE, ratio); 189 color = get_ratio_color(GRC_STALLED_CYCLES_BE, ratio);
174 190
175 fprintf(out, " # "); 191 out->print_metric(out->ctx, color, "%6.2f%%", "backend cycles idle", ratio);
176 color_fprintf(out, color, "%6.2f%%", ratio);
177 fprintf(out, " backend cycles idle ");
178} 192}
179 193
180static void print_branch_misses(FILE *out, int cpu, 194static void print_branch_misses(int cpu,
181 struct perf_evsel *evsel __maybe_unused, 195 struct perf_evsel *evsel,
182 double avg) 196 double avg,
197 struct perf_stat_output_ctx *out)
183{ 198{
184 double total, ratio = 0.0; 199 double total, ratio = 0.0;
185 const char *color; 200 const char *color;
@@ -192,14 +207,13 @@ static void print_branch_misses(FILE *out, int cpu,
192 207
193 color = get_ratio_color(GRC_CACHE_MISSES, ratio); 208 color = get_ratio_color(GRC_CACHE_MISSES, ratio);
194 209
195 fprintf(out, " # "); 210 out->print_metric(out->ctx, color, "%7.2f%%", "of all branches", ratio);
196 color_fprintf(out, color, "%6.2f%%", ratio);
197 fprintf(out, " of all branches ");
198} 211}
199 212
200static void print_l1_dcache_misses(FILE *out, int cpu, 213static void print_l1_dcache_misses(int cpu,
201 struct perf_evsel *evsel __maybe_unused, 214 struct perf_evsel *evsel,
202 double avg) 215 double avg,
216 struct perf_stat_output_ctx *out)
203{ 217{
204 double total, ratio = 0.0; 218 double total, ratio = 0.0;
205 const char *color; 219 const char *color;
@@ -212,14 +226,13 @@ static void print_l1_dcache_misses(FILE *out, int cpu,
212 226
213 color = get_ratio_color(GRC_CACHE_MISSES, ratio); 227 color = get_ratio_color(GRC_CACHE_MISSES, ratio);
214 228
215 fprintf(out, " # "); 229 out->print_metric(out->ctx, color, "%7.2f%%", "of all L1-dcache hits", ratio);
216 color_fprintf(out, color, "%6.2f%%", ratio);
217 fprintf(out, " of all L1-dcache hits ");
218} 230}
219 231
220static void print_l1_icache_misses(FILE *out, int cpu, 232static void print_l1_icache_misses(int cpu,
221 struct perf_evsel *evsel __maybe_unused, 233 struct perf_evsel *evsel,
222 double avg) 234 double avg,
235 struct perf_stat_output_ctx *out)
223{ 236{
224 double total, ratio = 0.0; 237 double total, ratio = 0.0;
225 const char *color; 238 const char *color;
@@ -231,15 +244,13 @@ static void print_l1_icache_misses(FILE *out, int cpu,
231 ratio = avg / total * 100.0; 244 ratio = avg / total * 100.0;
232 245
233 color = get_ratio_color(GRC_CACHE_MISSES, ratio); 246 color = get_ratio_color(GRC_CACHE_MISSES, ratio);
234 247 out->print_metric(out->ctx, color, "%7.2f%%", "of all L1-icache hits", ratio);
235 fprintf(out, " # ");
236 color_fprintf(out, color, "%6.2f%%", ratio);
237 fprintf(out, " of all L1-icache hits ");
238} 248}
239 249
240static void print_dtlb_cache_misses(FILE *out, int cpu, 250static void print_dtlb_cache_misses(int cpu,
241 struct perf_evsel *evsel __maybe_unused, 251 struct perf_evsel *evsel,
242 double avg) 252 double avg,
253 struct perf_stat_output_ctx *out)
243{ 254{
244 double total, ratio = 0.0; 255 double total, ratio = 0.0;
245 const char *color; 256 const char *color;
@@ -251,15 +262,13 @@ static void print_dtlb_cache_misses(FILE *out, int cpu,
251 ratio = avg / total * 100.0; 262 ratio = avg / total * 100.0;
252 263
253 color = get_ratio_color(GRC_CACHE_MISSES, ratio); 264 color = get_ratio_color(GRC_CACHE_MISSES, ratio);
254 265 out->print_metric(out->ctx, color, "%7.2f%%", "of all dTLB cache hits", ratio);
255 fprintf(out, " # ");
256 color_fprintf(out, color, "%6.2f%%", ratio);
257 fprintf(out, " of all dTLB cache hits ");
258} 266}
259 267
260static void print_itlb_cache_misses(FILE *out, int cpu, 268static void print_itlb_cache_misses(int cpu,
261 struct perf_evsel *evsel __maybe_unused, 269 struct perf_evsel *evsel,
262 double avg) 270 double avg,
271 struct perf_stat_output_ctx *out)
263{ 272{
264 double total, ratio = 0.0; 273 double total, ratio = 0.0;
265 const char *color; 274 const char *color;
@@ -271,15 +280,13 @@ static void print_itlb_cache_misses(FILE *out, int cpu,
271 ratio = avg / total * 100.0; 280 ratio = avg / total * 100.0;
272 281
273 color = get_ratio_color(GRC_CACHE_MISSES, ratio); 282 color = get_ratio_color(GRC_CACHE_MISSES, ratio);
274 283 out->print_metric(out->ctx, color, "%7.2f%%", "of all iTLB cache hits", ratio);
275 fprintf(out, " # ");
276 color_fprintf(out, color, "%6.2f%%", ratio);
277 fprintf(out, " of all iTLB cache hits ");
278} 284}
279 285
280static void print_ll_cache_misses(FILE *out, int cpu, 286static void print_ll_cache_misses(int cpu,
281 struct perf_evsel *evsel __maybe_unused, 287 struct perf_evsel *evsel,
282 double avg) 288 double avg,
289 struct perf_stat_output_ctx *out)
283{ 290{
284 double total, ratio = 0.0; 291 double total, ratio = 0.0;
285 const char *color; 292 const char *color;
@@ -291,15 +298,15 @@ static void print_ll_cache_misses(FILE *out, int cpu,
291 ratio = avg / total * 100.0; 298 ratio = avg / total * 100.0;
292 299
293 color = get_ratio_color(GRC_CACHE_MISSES, ratio); 300 color = get_ratio_color(GRC_CACHE_MISSES, ratio);
294 301 out->print_metric(out->ctx, color, "%7.2f%%", "of all LL-cache hits", ratio);
295 fprintf(out, " # ");
296 color_fprintf(out, color, "%6.2f%%", ratio);
297 fprintf(out, " of all LL-cache hits ");
298} 302}
299 303
300void perf_stat__print_shadow_stats(FILE *out, struct perf_evsel *evsel, 304void perf_stat__print_shadow_stats(struct perf_evsel *evsel,
301 double avg, int cpu, enum aggr_mode aggr) 305 double avg, int cpu,
306 struct perf_stat_output_ctx *out)
302{ 307{
308 void *ctxp = out->ctx;
309 print_metric_t print_metric = out->print_metric;
303 double total, ratio = 0.0, total2; 310 double total, ratio = 0.0, total2;
304 int ctx = evsel_context(evsel); 311 int ctx = evsel_context(evsel);
305 312
@@ -307,119 +314,145 @@ void perf_stat__print_shadow_stats(FILE *out, struct perf_evsel *evsel,
307 total = avg_stats(&runtime_cycles_stats[ctx][cpu]); 314 total = avg_stats(&runtime_cycles_stats[ctx][cpu]);
308 if (total) { 315 if (total) {
309 ratio = avg / total; 316 ratio = avg / total;
310 fprintf(out, " # %5.2f insns per cycle ", ratio); 317 print_metric(ctxp, NULL, "%7.2f ",
318 "insn per cycle", ratio);
311 } else { 319 } else {
312 fprintf(out, " "); 320 print_metric(ctxp, NULL, NULL, "insn per cycle", 0);
313 } 321 }
314 total = avg_stats(&runtime_stalled_cycles_front_stats[ctx][cpu]); 322 total = avg_stats(&runtime_stalled_cycles_front_stats[ctx][cpu]);
315 total = max(total, avg_stats(&runtime_stalled_cycles_back_stats[ctx][cpu])); 323 total = max(total, avg_stats(&runtime_stalled_cycles_back_stats[ctx][cpu]));
316 324
317 if (total && avg) { 325 if (total && avg) {
326 out->new_line(ctxp);
318 ratio = total / avg; 327 ratio = total / avg;
319 fprintf(out, "\n"); 328 print_metric(ctxp, NULL, "%7.2f ",
320 if (aggr == AGGR_NONE) 329 "stalled cycles per insn",
321 fprintf(out, " "); 330 ratio);
322 fprintf(out, " # %5.2f stalled cycles per insn", ratio); 331 } else if (have_frontend_stalled) {
332 print_metric(ctxp, NULL, NULL,
333 "stalled cycles per insn", 0);
323 } 334 }
324 335 } else if (perf_evsel__match(evsel, HARDWARE, HW_BRANCH_MISSES)) {
325 } else if (perf_evsel__match(evsel, HARDWARE, HW_BRANCH_MISSES) && 336 if (runtime_branches_stats[ctx][cpu].n != 0)
326 runtime_branches_stats[ctx][cpu].n != 0) { 337 print_branch_misses(cpu, evsel, avg, out);
327 print_branch_misses(out, cpu, evsel, avg); 338 else
339 print_metric(ctxp, NULL, NULL, "of all branches", 0);
328 } else if ( 340 } else if (
329 evsel->attr.type == PERF_TYPE_HW_CACHE && 341 evsel->attr.type == PERF_TYPE_HW_CACHE &&
330 evsel->attr.config == ( PERF_COUNT_HW_CACHE_L1D | 342 evsel->attr.config == ( PERF_COUNT_HW_CACHE_L1D |
331 ((PERF_COUNT_HW_CACHE_OP_READ) << 8) | 343 ((PERF_COUNT_HW_CACHE_OP_READ) << 8) |
332 ((PERF_COUNT_HW_CACHE_RESULT_MISS) << 16)) && 344 ((PERF_COUNT_HW_CACHE_RESULT_MISS) << 16))) {
333 runtime_l1_dcache_stats[ctx][cpu].n != 0) { 345 if (runtime_l1_dcache_stats[ctx][cpu].n != 0)
334 print_l1_dcache_misses(out, cpu, evsel, avg); 346 print_l1_dcache_misses(cpu, evsel, avg, out);
347 else
348 print_metric(ctxp, NULL, NULL, "of all L1-dcache hits", 0);
335 } else if ( 349 } else if (
336 evsel->attr.type == PERF_TYPE_HW_CACHE && 350 evsel->attr.type == PERF_TYPE_HW_CACHE &&
337 evsel->attr.config == ( PERF_COUNT_HW_CACHE_L1I | 351 evsel->attr.config == ( PERF_COUNT_HW_CACHE_L1I |
338 ((PERF_COUNT_HW_CACHE_OP_READ) << 8) | 352 ((PERF_COUNT_HW_CACHE_OP_READ) << 8) |
339 ((PERF_COUNT_HW_CACHE_RESULT_MISS) << 16)) && 353 ((PERF_COUNT_HW_CACHE_RESULT_MISS) << 16))) {
340 runtime_l1_icache_stats[ctx][cpu].n != 0) { 354 if (runtime_l1_icache_stats[ctx][cpu].n != 0)
341 print_l1_icache_misses(out, cpu, evsel, avg); 355 print_l1_icache_misses(cpu, evsel, avg, out);
356 else
357 print_metric(ctxp, NULL, NULL, "of all L1-icache hits", 0);
342 } else if ( 358 } else if (
343 evsel->attr.type == PERF_TYPE_HW_CACHE && 359 evsel->attr.type == PERF_TYPE_HW_CACHE &&
344 evsel->attr.config == ( PERF_COUNT_HW_CACHE_DTLB | 360 evsel->attr.config == ( PERF_COUNT_HW_CACHE_DTLB |
345 ((PERF_COUNT_HW_CACHE_OP_READ) << 8) | 361 ((PERF_COUNT_HW_CACHE_OP_READ) << 8) |
346 ((PERF_COUNT_HW_CACHE_RESULT_MISS) << 16)) && 362 ((PERF_COUNT_HW_CACHE_RESULT_MISS) << 16))) {
347 runtime_dtlb_cache_stats[ctx][cpu].n != 0) { 363 if (runtime_dtlb_cache_stats[ctx][cpu].n != 0)
348 print_dtlb_cache_misses(out, cpu, evsel, avg); 364 print_dtlb_cache_misses(cpu, evsel, avg, out);
365 else
366 print_metric(ctxp, NULL, NULL, "of all dTLB cache hits", 0);
349 } else if ( 367 } else if (
350 evsel->attr.type == PERF_TYPE_HW_CACHE && 368 evsel->attr.type == PERF_TYPE_HW_CACHE &&
351 evsel->attr.config == ( PERF_COUNT_HW_CACHE_ITLB | 369 evsel->attr.config == ( PERF_COUNT_HW_CACHE_ITLB |
352 ((PERF_COUNT_HW_CACHE_OP_READ) << 8) | 370 ((PERF_COUNT_HW_CACHE_OP_READ) << 8) |
353 ((PERF_COUNT_HW_CACHE_RESULT_MISS) << 16)) && 371 ((PERF_COUNT_HW_CACHE_RESULT_MISS) << 16))) {
354 runtime_itlb_cache_stats[ctx][cpu].n != 0) { 372 if (runtime_itlb_cache_stats[ctx][cpu].n != 0)
355 print_itlb_cache_misses(out, cpu, evsel, avg); 373 print_itlb_cache_misses(cpu, evsel, avg, out);
374 else
375 print_metric(ctxp, NULL, NULL, "of all iTLB cache hits", 0);
356 } else if ( 376 } else if (
357 evsel->attr.type == PERF_TYPE_HW_CACHE && 377 evsel->attr.type == PERF_TYPE_HW_CACHE &&
358 evsel->attr.config == ( PERF_COUNT_HW_CACHE_LL | 378 evsel->attr.config == ( PERF_COUNT_HW_CACHE_LL |
359 ((PERF_COUNT_HW_CACHE_OP_READ) << 8) | 379 ((PERF_COUNT_HW_CACHE_OP_READ) << 8) |
360 ((PERF_COUNT_HW_CACHE_RESULT_MISS) << 16)) && 380 ((PERF_COUNT_HW_CACHE_RESULT_MISS) << 16))) {
361 runtime_ll_cache_stats[ctx][cpu].n != 0) { 381 if (runtime_ll_cache_stats[ctx][cpu].n != 0)
362 print_ll_cache_misses(out, cpu, evsel, avg); 382 print_ll_cache_misses(cpu, evsel, avg, out);
363 } else if (perf_evsel__match(evsel, HARDWARE, HW_CACHE_MISSES) && 383 else
364 runtime_cacherefs_stats[ctx][cpu].n != 0) { 384 print_metric(ctxp, NULL, NULL, "of all LL-cache hits", 0);
385 } else if (perf_evsel__match(evsel, HARDWARE, HW_CACHE_MISSES)) {
365 total = avg_stats(&runtime_cacherefs_stats[ctx][cpu]); 386 total = avg_stats(&runtime_cacherefs_stats[ctx][cpu]);
366 387
367 if (total) 388 if (total)
368 ratio = avg * 100 / total; 389 ratio = avg * 100 / total;
369 390
370 fprintf(out, " # %8.3f %% of all cache refs ", ratio); 391 if (runtime_cacherefs_stats[ctx][cpu].n != 0)
371 392 print_metric(ctxp, NULL, "%8.3f %%",
393 "of all cache refs", ratio);
394 else
395 print_metric(ctxp, NULL, NULL, "of all cache refs", 0);
372 } else if (perf_evsel__match(evsel, HARDWARE, HW_STALLED_CYCLES_FRONTEND)) { 396 } else if (perf_evsel__match(evsel, HARDWARE, HW_STALLED_CYCLES_FRONTEND)) {
373 print_stalled_cycles_frontend(out, cpu, evsel, avg); 397 print_stalled_cycles_frontend(cpu, evsel, avg, out);
374 } else if (perf_evsel__match(evsel, HARDWARE, HW_STALLED_CYCLES_BACKEND)) { 398 } else if (perf_evsel__match(evsel, HARDWARE, HW_STALLED_CYCLES_BACKEND)) {
375 print_stalled_cycles_backend(out, cpu, evsel, avg); 399 print_stalled_cycles_backend(cpu, evsel, avg, out);
376 } else if (perf_evsel__match(evsel, HARDWARE, HW_CPU_CYCLES)) { 400 } else if (perf_evsel__match(evsel, HARDWARE, HW_CPU_CYCLES)) {
377 total = avg_stats(&runtime_nsecs_stats[cpu]); 401 total = avg_stats(&runtime_nsecs_stats[cpu]);
378 402
379 if (total) { 403 if (total) {
380 ratio = avg / total; 404 ratio = avg / total;
381 fprintf(out, " # %8.3f GHz ", ratio); 405 print_metric(ctxp, NULL, "%8.3f", "GHz", ratio);
382 } else { 406 } else {
383 fprintf(out, " "); 407 print_metric(ctxp, NULL, NULL, "Ghz", 0);
384 } 408 }
385 } else if (perf_stat_evsel__is(evsel, CYCLES_IN_TX)) { 409 } else if (perf_stat_evsel__is(evsel, CYCLES_IN_TX)) {
386 total = avg_stats(&runtime_cycles_stats[ctx][cpu]); 410 total = avg_stats(&runtime_cycles_stats[ctx][cpu]);
387 if (total) 411 if (total)
388 fprintf(out, 412 print_metric(ctxp, NULL,
389 " # %5.2f%% transactional cycles ", 413 "%7.2f%%", "transactional cycles",
390 100.0 * (avg / total)); 414 100.0 * (avg / total));
415 else
416 print_metric(ctxp, NULL, NULL, "transactional cycles",
417 0);
391 } else if (perf_stat_evsel__is(evsel, CYCLES_IN_TX_CP)) { 418 } else if (perf_stat_evsel__is(evsel, CYCLES_IN_TX_CP)) {
392 total = avg_stats(&runtime_cycles_stats[ctx][cpu]); 419 total = avg_stats(&runtime_cycles_stats[ctx][cpu]);
393 total2 = avg_stats(&runtime_cycles_in_tx_stats[ctx][cpu]); 420 total2 = avg_stats(&runtime_cycles_in_tx_stats[ctx][cpu]);
394 if (total2 < avg) 421 if (total2 < avg)
395 total2 = avg; 422 total2 = avg;
396 if (total) 423 if (total)
397 fprintf(out, 424 print_metric(ctxp, NULL, "%7.2f%%", "aborted cycles",
398 " # %5.2f%% aborted cycles ",
399 100.0 * ((total2-avg) / total)); 425 100.0 * ((total2-avg) / total));
400 } else if (perf_stat_evsel__is(evsel, TRANSACTION_START) && 426 else
401 runtime_cycles_in_tx_stats[ctx][cpu].n != 0) { 427 print_metric(ctxp, NULL, NULL, "aborted cycles", 0);
428 } else if (perf_stat_evsel__is(evsel, TRANSACTION_START)) {
402 total = avg_stats(&runtime_cycles_in_tx_stats[ctx][cpu]); 429 total = avg_stats(&runtime_cycles_in_tx_stats[ctx][cpu]);
403 430
404 if (avg) 431 if (avg)
405 ratio = total / avg; 432 ratio = total / avg;
406 433
407 fprintf(out, " # %8.0f cycles / transaction ", ratio); 434 if (runtime_cycles_in_tx_stats[ctx][cpu].n != 0)
408 } else if (perf_stat_evsel__is(evsel, ELISION_START) && 435 print_metric(ctxp, NULL, "%8.0f",
409 runtime_cycles_in_tx_stats[ctx][cpu].n != 0) { 436 "cycles / transaction", ratio);
437 else
438 print_metric(ctxp, NULL, NULL, "cycles / transaction",
439 0);
440 } else if (perf_stat_evsel__is(evsel, ELISION_START)) {
410 total = avg_stats(&runtime_cycles_in_tx_stats[ctx][cpu]); 441 total = avg_stats(&runtime_cycles_in_tx_stats[ctx][cpu]);
411 442
412 if (avg) 443 if (avg)
413 ratio = total / avg; 444 ratio = total / avg;
414 445
415 fprintf(out, " # %8.0f cycles / elision ", ratio); 446 print_metric(ctxp, NULL, "%8.0f", "cycles / elision", ratio);
416 } else if (perf_evsel__match(evsel, SOFTWARE, SW_TASK_CLOCK)) { 447 } else if (perf_evsel__match(evsel, SOFTWARE, SW_TASK_CLOCK)) {
417 if ((ratio = avg_stats(&walltime_nsecs_stats)) != 0) 448 if ((ratio = avg_stats(&walltime_nsecs_stats)) != 0)
418 fprintf(out, " # %8.3f CPUs utilized ", avg / ratio); 449 print_metric(ctxp, NULL, "%8.3f", "CPUs utilized",
450 avg / ratio);
419 else 451 else
420 fprintf(out, " "); 452 print_metric(ctxp, NULL, NULL, "CPUs utilized", 0);
421 } else if (runtime_nsecs_stats[cpu].n != 0) { 453 } else if (runtime_nsecs_stats[cpu].n != 0) {
422 char unit = 'M'; 454 char unit = 'M';
455 char unit_buf[10];
423 456
424 total = avg_stats(&runtime_nsecs_stats[cpu]); 457 total = avg_stats(&runtime_nsecs_stats[cpu]);
425 458
@@ -429,9 +462,9 @@ void perf_stat__print_shadow_stats(FILE *out, struct perf_evsel *evsel,
429 ratio *= 1000; 462 ratio *= 1000;
430 unit = 'K'; 463 unit = 'K';
431 } 464 }
432 465 snprintf(unit_buf, sizeof(unit_buf), "%c/sec", unit);
433 fprintf(out, " # %8.3f %c/sec ", ratio, unit); 466 print_metric(ctxp, NULL, "%8.3f", unit_buf, ratio);
434 } else { 467 } else {
435 fprintf(out, " "); 468 print_metric(ctxp, NULL, NULL, NULL, 0);
436 } 469 }
437} 470}
diff --git a/tools/perf/util/stat.c b/tools/perf/util/stat.c
index afb0c45eba34..4d9b481cf3b6 100644
--- a/tools/perf/util/stat.c
+++ b/tools/perf/util/stat.c
@@ -97,7 +97,7 @@ void perf_stat_evsel_id_init(struct perf_evsel *evsel)
97 } 97 }
98} 98}
99 99
100void perf_evsel__reset_stat_priv(struct perf_evsel *evsel) 100static void perf_evsel__reset_stat_priv(struct perf_evsel *evsel)
101{ 101{
102 int i; 102 int i;
103 struct perf_stat_evsel *ps = evsel->priv; 103 struct perf_stat_evsel *ps = evsel->priv;
@@ -108,7 +108,7 @@ void perf_evsel__reset_stat_priv(struct perf_evsel *evsel)
108 perf_stat_evsel_id_init(evsel); 108 perf_stat_evsel_id_init(evsel);
109} 109}
110 110
111int perf_evsel__alloc_stat_priv(struct perf_evsel *evsel) 111static int perf_evsel__alloc_stat_priv(struct perf_evsel *evsel)
112{ 112{
113 evsel->priv = zalloc(sizeof(struct perf_stat_evsel)); 113 evsel->priv = zalloc(sizeof(struct perf_stat_evsel));
114 if (evsel->priv == NULL) 114 if (evsel->priv == NULL)
@@ -117,13 +117,13 @@ int perf_evsel__alloc_stat_priv(struct perf_evsel *evsel)
117 return 0; 117 return 0;
118} 118}
119 119
120void perf_evsel__free_stat_priv(struct perf_evsel *evsel) 120static void perf_evsel__free_stat_priv(struct perf_evsel *evsel)
121{ 121{
122 zfree(&evsel->priv); 122 zfree(&evsel->priv);
123} 123}
124 124
125int perf_evsel__alloc_prev_raw_counts(struct perf_evsel *evsel, 125static int perf_evsel__alloc_prev_raw_counts(struct perf_evsel *evsel,
126 int ncpus, int nthreads) 126 int ncpus, int nthreads)
127{ 127{
128 struct perf_counts *counts; 128 struct perf_counts *counts;
129 129
@@ -134,13 +134,13 @@ int perf_evsel__alloc_prev_raw_counts(struct perf_evsel *evsel,
134 return counts ? 0 : -ENOMEM; 134 return counts ? 0 : -ENOMEM;
135} 135}
136 136
137void perf_evsel__free_prev_raw_counts(struct perf_evsel *evsel) 137static void perf_evsel__free_prev_raw_counts(struct perf_evsel *evsel)
138{ 138{
139 perf_counts__delete(evsel->prev_raw_counts); 139 perf_counts__delete(evsel->prev_raw_counts);
140 evsel->prev_raw_counts = NULL; 140 evsel->prev_raw_counts = NULL;
141} 141}
142 142
143int perf_evsel__alloc_stats(struct perf_evsel *evsel, bool alloc_raw) 143static int perf_evsel__alloc_stats(struct perf_evsel *evsel, bool alloc_raw)
144{ 144{
145 int ncpus = perf_evsel__nr_cpus(evsel); 145 int ncpus = perf_evsel__nr_cpus(evsel);
146 int nthreads = thread_map__nr(evsel->threads); 146 int nthreads = thread_map__nr(evsel->threads);
diff --git a/tools/perf/util/stat.h b/tools/perf/util/stat.h
index 086f4e128d63..0150e786ccc7 100644
--- a/tools/perf/util/stat.h
+++ b/tools/perf/util/stat.h
@@ -68,21 +68,23 @@ void perf_stat_evsel_id_init(struct perf_evsel *evsel);
68 68
69extern struct stats walltime_nsecs_stats; 69extern struct stats walltime_nsecs_stats;
70 70
71typedef void (*print_metric_t)(void *ctx, const char *color, const char *unit,
72 const char *fmt, double val);
73typedef void (*new_line_t )(void *ctx);
74
75void perf_stat__init_shadow_stats(void);
71void perf_stat__reset_shadow_stats(void); 76void perf_stat__reset_shadow_stats(void);
72void perf_stat__update_shadow_stats(struct perf_evsel *counter, u64 *count, 77void perf_stat__update_shadow_stats(struct perf_evsel *counter, u64 *count,
73 int cpu); 78 int cpu);
74void perf_stat__print_shadow_stats(FILE *out, struct perf_evsel *evsel, 79struct perf_stat_output_ctx {
75 double avg, int cpu, enum aggr_mode aggr); 80 void *ctx;
76 81 print_metric_t print_metric;
77void perf_evsel__reset_stat_priv(struct perf_evsel *evsel); 82 new_line_t new_line;
78int perf_evsel__alloc_stat_priv(struct perf_evsel *evsel); 83};
79void perf_evsel__free_stat_priv(struct perf_evsel *evsel);
80
81int perf_evsel__alloc_prev_raw_counts(struct perf_evsel *evsel,
82 int ncpus, int nthreads);
83void perf_evsel__free_prev_raw_counts(struct perf_evsel *evsel);
84 84
85int perf_evsel__alloc_stats(struct perf_evsel *evsel, bool alloc_raw); 85void perf_stat__print_shadow_stats(struct perf_evsel *evsel,
86 double avg, int cpu,
87 struct perf_stat_output_ctx *out);
86 88
87int perf_evlist__alloc_stats(struct perf_evlist *evlist, bool alloc_raw); 89int perf_evlist__alloc_stats(struct perf_evlist *evlist, bool alloc_raw);
88void perf_evlist__free_stats(struct perf_evlist *evlist); 90void perf_evlist__free_stats(struct perf_evlist *evlist);
diff --git a/tools/perf/util/strbuf.c b/tools/perf/util/strbuf.c
index 25671fa16618..8fb73295ec34 100644
--- a/tools/perf/util/strbuf.c
+++ b/tools/perf/util/strbuf.c
@@ -51,28 +51,11 @@ void strbuf_grow(struct strbuf *sb, size_t extra)
51 ALLOC_GROW(sb->buf, sb->len + extra + 1, sb->alloc); 51 ALLOC_GROW(sb->buf, sb->len + extra + 1, sb->alloc);
52} 52}
53 53
54static void strbuf_splice(struct strbuf *sb, size_t pos, size_t len, 54void strbuf_addch(struct strbuf *sb, int c)
55 const void *data, size_t dlen)
56{ 55{
57 if (pos + len < pos) 56 strbuf_grow(sb, 1);
58 die("you want to use way too much memory"); 57 sb->buf[sb->len++] = c;
59 if (pos > sb->len) 58 sb->buf[sb->len] = '\0';
60 die("`pos' is too far after the end of the buffer");
61 if (pos + len > sb->len)
62 die("`pos + len' is too far after the end of the buffer");
63
64 if (dlen >= len)
65 strbuf_grow(sb, dlen - len);
66 memmove(sb->buf + pos + dlen,
67 sb->buf + pos + len,
68 sb->len - pos - len);
69 memcpy(sb->buf + pos, data, dlen);
70 strbuf_setlen(sb, sb->len + dlen - len);
71}
72
73void strbuf_remove(struct strbuf *sb, size_t pos, size_t len)
74{
75 strbuf_splice(sb, pos, len, NULL, 0);
76} 59}
77 60
78void strbuf_add(struct strbuf *sb, const void *data, size_t len) 61void strbuf_add(struct strbuf *sb, const void *data, size_t len)
@@ -82,7 +65,7 @@ void strbuf_add(struct strbuf *sb, const void *data, size_t len)
82 strbuf_setlen(sb, sb->len + len); 65 strbuf_setlen(sb, sb->len + len);
83} 66}
84 67
85void strbuf_addv(struct strbuf *sb, const char *fmt, va_list ap) 68static void strbuf_addv(struct strbuf *sb, const char *fmt, va_list ap)
86{ 69{
87 int len; 70 int len;
88 va_list ap_saved; 71 va_list ap_saved;
diff --git a/tools/perf/util/strbuf.h b/tools/perf/util/strbuf.h
index 529f2f035249..ab9be0fbbd40 100644
--- a/tools/perf/util/strbuf.h
+++ b/tools/perf/util/strbuf.h
@@ -51,16 +51,16 @@ struct strbuf {
51#define STRBUF_INIT { 0, 0, strbuf_slopbuf } 51#define STRBUF_INIT { 0, 0, strbuf_slopbuf }
52 52
53/*----- strbuf life cycle -----*/ 53/*----- strbuf life cycle -----*/
54extern void strbuf_init(struct strbuf *buf, ssize_t hint); 54void strbuf_init(struct strbuf *buf, ssize_t hint);
55extern void strbuf_release(struct strbuf *); 55void strbuf_release(struct strbuf *buf);
56extern char *strbuf_detach(struct strbuf *, size_t *); 56char *strbuf_detach(struct strbuf *buf, size_t *);
57 57
58/*----- strbuf size related -----*/ 58/*----- strbuf size related -----*/
59static inline ssize_t strbuf_avail(const struct strbuf *sb) { 59static inline ssize_t strbuf_avail(const struct strbuf *sb) {
60 return sb->alloc ? sb->alloc - sb->len - 1 : 0; 60 return sb->alloc ? sb->alloc - sb->len - 1 : 0;
61} 61}
62 62
63extern void strbuf_grow(struct strbuf *, size_t); 63void strbuf_grow(struct strbuf *buf, size_t);
64 64
65static inline void strbuf_setlen(struct strbuf *sb, size_t len) { 65static inline void strbuf_setlen(struct strbuf *sb, size_t len) {
66 if (!sb->alloc) 66 if (!sb->alloc)
@@ -71,24 +71,17 @@ static inline void strbuf_setlen(struct strbuf *sb, size_t len) {
71} 71}
72 72
73/*----- add data in your buffer -----*/ 73/*----- add data in your buffer -----*/
74static inline void strbuf_addch(struct strbuf *sb, int c) { 74void strbuf_addch(struct strbuf *sb, int c);
75 strbuf_grow(sb, 1);
76 sb->buf[sb->len++] = c;
77 sb->buf[sb->len] = '\0';
78}
79
80extern void strbuf_remove(struct strbuf *, size_t pos, size_t len);
81 75
82extern void strbuf_add(struct strbuf *, const void *, size_t); 76void strbuf_add(struct strbuf *buf, const void *, size_t);
83static inline void strbuf_addstr(struct strbuf *sb, const char *s) { 77static inline void strbuf_addstr(struct strbuf *sb, const char *s) {
84 strbuf_add(sb, s, strlen(s)); 78 strbuf_add(sb, s, strlen(s));
85} 79}
86 80
87__attribute__((format(printf,2,3))) 81__attribute__((format(printf,2,3)))
88extern void strbuf_addf(struct strbuf *sb, const char *fmt, ...); 82void strbuf_addf(struct strbuf *sb, const char *fmt, ...);
89extern void strbuf_addv(struct strbuf *sb, const char *fmt, va_list ap);
90 83
91/* XXX: if read fails, any partial read is undone */ 84/* XXX: if read fails, any partial read is undone */
92extern ssize_t strbuf_read(struct strbuf *, int fd, ssize_t hint); 85ssize_t strbuf_read(struct strbuf *, int fd, ssize_t hint);
93 86
94#endif /* __PERF_STRBUF_H */ 87#endif /* __PERF_STRBUF_H */
diff --git a/tools/perf/util/svghelper.h b/tools/perf/util/svghelper.h
index 9292a5291445..946fdf2db97c 100644
--- a/tools/perf/util/svghelper.h
+++ b/tools/perf/util/svghelper.h
@@ -3,32 +3,31 @@
3 3
4#include <linux/types.h> 4#include <linux/types.h>
5 5
6extern void open_svg(const char *filename, int cpus, int rows, u64 start, u64 end); 6void open_svg(const char *filename, int cpus, int rows, u64 start, u64 end);
7extern void svg_ubox(int Yslot, u64 start, u64 end, double height, const char *type, int fd, int err, int merges); 7void svg_ubox(int Yslot, u64 start, u64 end, double height, const char *type, int fd, int err, int merges);
8extern void svg_lbox(int Yslot, u64 start, u64 end, double height, const char *type, int fd, int err, int merges); 8void svg_lbox(int Yslot, u64 start, u64 end, double height, const char *type, int fd, int err, int merges);
9extern void svg_fbox(int Yslot, u64 start, u64 end, double height, const char *type, int fd, int err, int merges); 9void svg_fbox(int Yslot, u64 start, u64 end, double height, const char *type, int fd, int err, int merges);
10extern void svg_box(int Yslot, u64 start, u64 end, const char *type); 10void svg_box(int Yslot, u64 start, u64 end, const char *type);
11extern void svg_blocked(int Yslot, int cpu, u64 start, u64 end, const char *backtrace); 11void svg_blocked(int Yslot, int cpu, u64 start, u64 end, const char *backtrace);
12extern void svg_running(int Yslot, int cpu, u64 start, u64 end, const char *backtrace); 12void svg_running(int Yslot, int cpu, u64 start, u64 end, const char *backtrace);
13extern void svg_waiting(int Yslot, int cpu, u64 start, u64 end, const char *backtrace); 13void svg_waiting(int Yslot, int cpu, u64 start, u64 end, const char *backtrace);
14extern void svg_cpu_box(int cpu, u64 max_frequency, u64 turbo_frequency); 14void svg_cpu_box(int cpu, u64 max_frequency, u64 turbo_frequency);
15 15
16 16
17extern void svg_process(int cpu, u64 start, u64 end, int pid, const char *name, const char *backtrace); 17void svg_process(int cpu, u64 start, u64 end, int pid, const char *name, const char *backtrace);
18extern void svg_cstate(int cpu, u64 start, u64 end, int type); 18void svg_cstate(int cpu, u64 start, u64 end, int type);
19extern void svg_pstate(int cpu, u64 start, u64 end, u64 freq); 19void svg_pstate(int cpu, u64 start, u64 end, u64 freq);
20 20
21 21
22extern void svg_time_grid(double min_thickness); 22void svg_time_grid(double min_thickness);
23extern void svg_io_legenda(void); 23void svg_io_legenda(void);
24extern void svg_legenda(void); 24void svg_legenda(void);
25extern void svg_wakeline(u64 start, int row1, int row2, const char *backtrace); 25void svg_wakeline(u64 start, int row1, int row2, const char *backtrace);
26extern void svg_partial_wakeline(u64 start, int row1, char *desc1, int row2, char *desc2, const char *backtrace); 26void svg_partial_wakeline(u64 start, int row1, char *desc1, int row2, char *desc2, const char *backtrace);
27extern void svg_interrupt(u64 start, int row, const char *backtrace); 27void svg_interrupt(u64 start, int row, const char *backtrace);
28extern void svg_text(int Yslot, u64 start, const char *text); 28void svg_text(int Yslot, u64 start, const char *text);
29extern void svg_close(void); 29void svg_close(void);
30extern int svg_build_topology_map(char *sib_core, int sib_core_nr, 30int svg_build_topology_map(char *sib_core, int sib_core_nr, char *sib_thr, int sib_thr_nr);
31 char *sib_thr, int sib_thr_nr);
32 31
33extern int svg_page_width; 32extern int svg_page_width;
34extern u64 svg_highlight; 33extern u64 svg_highlight;
diff --git a/tools/perf/util/symbol-elf.c b/tools/perf/util/symbol-elf.c
index 562b8ebeae5b..bc229a74c6a9 100644
--- a/tools/perf/util/symbol-elf.c
+++ b/tools/perf/util/symbol-elf.c
@@ -6,6 +6,7 @@
6#include <inttypes.h> 6#include <inttypes.h>
7 7
8#include "symbol.h" 8#include "symbol.h"
9#include "demangle-java.h"
9#include "machine.h" 10#include "machine.h"
10#include "vdso.h" 11#include "vdso.h"
11#include <symbol/kallsyms.h> 12#include <symbol/kallsyms.h>
@@ -792,6 +793,7 @@ int dso__load_sym(struct dso *dso, struct map *map,
792 uint32_t idx; 793 uint32_t idx;
793 GElf_Ehdr ehdr; 794 GElf_Ehdr ehdr;
794 GElf_Shdr shdr; 795 GElf_Shdr shdr;
796 GElf_Shdr tshdr;
795 Elf_Data *syms, *opddata = NULL; 797 Elf_Data *syms, *opddata = NULL;
796 GElf_Sym sym; 798 GElf_Sym sym;
797 Elf_Scn *sec, *sec_strndx; 799 Elf_Scn *sec, *sec_strndx;
@@ -831,6 +833,9 @@ int dso__load_sym(struct dso *dso, struct map *map,
831 sec = syms_ss->symtab; 833 sec = syms_ss->symtab;
832 shdr = syms_ss->symshdr; 834 shdr = syms_ss->symshdr;
833 835
836 if (elf_section_by_name(elf, &ehdr, &tshdr, ".text", NULL))
837 dso->text_offset = tshdr.sh_addr - tshdr.sh_offset;
838
834 if (runtime_ss->opdsec) 839 if (runtime_ss->opdsec)
835 opddata = elf_rawdata(runtime_ss->opdsec, NULL); 840 opddata = elf_rawdata(runtime_ss->opdsec, NULL);
836 841
@@ -879,12 +884,8 @@ int dso__load_sym(struct dso *dso, struct map *map,
879 * Handle any relocation of vdso necessary because older kernels 884 * Handle any relocation of vdso necessary because older kernels
880 * attempted to prelink vdso to its virtual address. 885 * attempted to prelink vdso to its virtual address.
881 */ 886 */
882 if (dso__is_vdso(dso)) { 887 if (dso__is_vdso(dso))
883 GElf_Shdr tshdr; 888 map->reloc = map->start - dso->text_offset;
884
885 if (elf_section_by_name(elf, &ehdr, &tshdr, ".text", NULL))
886 map->reloc = map->start - tshdr.sh_addr + tshdr.sh_offset;
887 }
888 889
889 dso->adjust_symbols = runtime_ss->adjust_symbols || ref_reloc(kmap); 890 dso->adjust_symbols = runtime_ss->adjust_symbols || ref_reloc(kmap);
890 /* 891 /*
@@ -1077,6 +1078,8 @@ new_symbol:
1077 demangle_flags = DMGL_PARAMS | DMGL_ANSI; 1078 demangle_flags = DMGL_PARAMS | DMGL_ANSI;
1078 1079
1079 demangled = bfd_demangle(NULL, elf_name, demangle_flags); 1080 demangled = bfd_demangle(NULL, elf_name, demangle_flags);
1081 if (demangled == NULL)
1082 demangled = java_demangle_sym(elf_name, JAVA_DEMANGLE_NORET);
1080 if (demangled != NULL) 1083 if (demangled != NULL)
1081 elf_name = demangled; 1084 elf_name = demangled;
1082 } 1085 }
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
index ab02209a7cf3..e7588dc91518 100644
--- a/tools/perf/util/symbol.c
+++ b/tools/perf/util/symbol.c
@@ -1466,7 +1466,8 @@ int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter)
1466 * Read the build id if possible. This is required for 1466 * Read the build id if possible. This is required for
1467 * DSO_BINARY_TYPE__BUILDID_DEBUGINFO to work 1467 * DSO_BINARY_TYPE__BUILDID_DEBUGINFO to work
1468 */ 1468 */
1469 if (filename__read_build_id(dso->long_name, build_id, BUILD_ID_SIZE) > 0) 1469 if (is_regular_file(name) &&
1470 filename__read_build_id(dso->long_name, build_id, BUILD_ID_SIZE) > 0)
1470 dso__set_build_id(dso, build_id); 1471 dso__set_build_id(dso, build_id);
1471 1472
1472 /* 1473 /*
@@ -1487,6 +1488,9 @@ int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter)
1487 root_dir, name, PATH_MAX)) 1488 root_dir, name, PATH_MAX))
1488 continue; 1489 continue;
1489 1490
1491 if (!is_regular_file(name))
1492 continue;
1493
1490 /* Name is now the name of the next image to try */ 1494 /* Name is now the name of the next image to try */
1491 if (symsrc__init(ss, dso, name, symtab_type) < 0) 1495 if (symsrc__init(ss, dso, name, symtab_type) < 0)
1492 continue; 1496 continue;
@@ -1525,6 +1529,10 @@ int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter)
1525 if (!runtime_ss && syms_ss) 1529 if (!runtime_ss && syms_ss)
1526 runtime_ss = syms_ss; 1530 runtime_ss = syms_ss;
1527 1531
1532 if (syms_ss && syms_ss->type == DSO_BINARY_TYPE__BUILD_ID_CACHE)
1533 if (dso__build_id_is_kmod(dso, name, PATH_MAX))
1534 kmod = true;
1535
1528 if (syms_ss) 1536 if (syms_ss)
1529 ret = dso__load_sym(dso, map, syms_ss, runtime_ss, filter, kmod); 1537 ret = dso__load_sym(dso, map, syms_ss, runtime_ss, filter, kmod);
1530 else 1538 else
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h
index ccd1caa40e11..c8b7544d9267 100644
--- a/tools/perf/util/symbol.h
+++ b/tools/perf/util/symbol.h
@@ -34,8 +34,8 @@
34#endif 34#endif
35 35
36#ifdef HAVE_LIBELF_SUPPORT 36#ifdef HAVE_LIBELF_SUPPORT
37extern Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep, 37Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep,
38 GElf_Shdr *shp, const char *name, size_t *idx); 38 GElf_Shdr *shp, const char *name, size_t *idx);
39#endif 39#endif
40 40
41#ifndef DMGL_PARAMS 41#ifndef DMGL_PARAMS
@@ -110,7 +110,8 @@ struct symbol_conf {
110 has_filter, 110 has_filter,
111 show_ref_callgraph, 111 show_ref_callgraph,
112 hide_unresolved, 112 hide_unresolved,
113 raw_trace; 113 raw_trace,
114 report_hierarchy;
114 const char *vmlinux_name, 115 const char *vmlinux_name,
115 *kallsyms_name, 116 *kallsyms_name,
116 *source_prefix, 117 *source_prefix,
diff --git a/tools/perf/util/trace-event.c b/tools/perf/util/trace-event.c
index 802bb868d446..8ae051e0ec79 100644
--- a/tools/perf/util/trace-event.c
+++ b/tools/perf/util/trace-event.c
@@ -10,6 +10,7 @@
10#include <linux/err.h> 10#include <linux/err.h>
11#include <traceevent/event-parse.h> 11#include <traceevent/event-parse.h>
12#include <api/fs/tracing_path.h> 12#include <api/fs/tracing_path.h>
13#include <api/fs/fs.h>
13#include "trace-event.h" 14#include "trace-event.h"
14#include "machine.h" 15#include "machine.h"
15#include "util.h" 16#include "util.h"
diff --git a/tools/perf/util/tsc.c b/tools/perf/util/tsc.c
index 4d4210d4e13d..1b741646eed0 100644
--- a/tools/perf/util/tsc.c
+++ b/tools/perf/util/tsc.c
@@ -19,7 +19,7 @@ u64 tsc_to_perf_time(u64 cyc, struct perf_tsc_conversion *tc)
19 u64 quot, rem; 19 u64 quot, rem;
20 20
21 quot = cyc >> tc->time_shift; 21 quot = cyc >> tc->time_shift;
22 rem = cyc & ((1 << tc->time_shift) - 1); 22 rem = cyc & (((u64)1 << tc->time_shift) - 1);
23 return tc->time_zero + quot * tc->time_mult + 23 return tc->time_zero + quot * tc->time_mult +
24 ((rem * tc->time_mult) >> tc->time_shift); 24 ((rem * tc->time_mult) >> tc->time_shift);
25} 25}
diff --git a/tools/perf/util/usage.c b/tools/perf/util/usage.c
index 6adfa18cdd4e..996046a66fe5 100644
--- a/tools/perf/util/usage.c
+++ b/tools/perf/util/usage.c
@@ -41,15 +41,9 @@ static void warn_builtin(const char *warn, va_list params)
41/* If we are in a dlopen()ed .so write to a global variable would segfault 41/* If we are in a dlopen()ed .so write to a global variable would segfault
42 * (ugh), so keep things static. */ 42 * (ugh), so keep things static. */
43static void (*usage_routine)(const char *err) NORETURN = usage_builtin; 43static void (*usage_routine)(const char *err) NORETURN = usage_builtin;
44static void (*die_routine)(const char *err, va_list params) NORETURN = die_builtin;
45static void (*error_routine)(const char *err, va_list params) = error_builtin; 44static void (*error_routine)(const char *err, va_list params) = error_builtin;
46static void (*warn_routine)(const char *err, va_list params) = warn_builtin; 45static void (*warn_routine)(const char *err, va_list params) = warn_builtin;
47 46
48void set_die_routine(void (*routine)(const char *err, va_list params) NORETURN)
49{
50 die_routine = routine;
51}
52
53void set_warning_routine(void (*routine)(const char *err, va_list params)) 47void set_warning_routine(void (*routine)(const char *err, va_list params))
54{ 48{
55 warn_routine = routine; 49 warn_routine = routine;
@@ -65,7 +59,7 @@ void die(const char *err, ...)
65 va_list params; 59 va_list params;
66 60
67 va_start(params, err); 61 va_start(params, err);
68 die_routine(err, params); 62 die_builtin(err, params);
69 va_end(params); 63 va_end(params);
70} 64}
71 65
diff --git a/tools/perf/util/util.c b/tools/perf/util/util.c
index ead9509835d2..b7766c577b01 100644
--- a/tools/perf/util/util.c
+++ b/tools/perf/util/util.c
@@ -14,6 +14,7 @@
14#include <limits.h> 14#include <limits.h>
15#include <byteswap.h> 15#include <byteswap.h>
16#include <linux/kernel.h> 16#include <linux/kernel.h>
17#include <linux/log2.h>
17#include <unistd.h> 18#include <unistd.h>
18#include "callchain.h" 19#include "callchain.h"
19#include "strlist.h" 20#include "strlist.h"
@@ -507,54 +508,6 @@ int parse_callchain_record(const char *arg, struct callchain_param *param)
507 return ret; 508 return ret;
508} 509}
509 510
510int filename__read_str(const char *filename, char **buf, size_t *sizep)
511{
512 size_t size = 0, alloc_size = 0;
513 void *bf = NULL, *nbf;
514 int fd, n, err = 0;
515 char sbuf[STRERR_BUFSIZE];
516
517 fd = open(filename, O_RDONLY);
518 if (fd < 0)
519 return -errno;
520
521 do {
522 if (size == alloc_size) {
523 alloc_size += BUFSIZ;
524 nbf = realloc(bf, alloc_size);
525 if (!nbf) {
526 err = -ENOMEM;
527 break;
528 }
529
530 bf = nbf;
531 }
532
533 n = read(fd, bf + size, alloc_size - size);
534 if (n < 0) {
535 if (size) {
536 pr_warning("read failed %d: %s\n", errno,
537 strerror_r(errno, sbuf, sizeof(sbuf)));
538 err = 0;
539 } else
540 err = -errno;
541
542 break;
543 }
544
545 size += n;
546 } while (n > 0);
547
548 if (!err) {
549 *sizep = size;
550 *buf = bf;
551 } else
552 free(bf);
553
554 close(fd);
555 return err;
556}
557
558const char *get_filename_for_perf_kvm(void) 511const char *get_filename_for_perf_kvm(void)
559{ 512{
560 const char *filename; 513 const char *filename;
@@ -691,3 +644,66 @@ out:
691 644
692 return tip; 645 return tip;
693} 646}
647
648bool is_regular_file(const char *file)
649{
650 struct stat st;
651
652 if (stat(file, &st))
653 return false;
654
655 return S_ISREG(st.st_mode);
656}
657
658int fetch_current_timestamp(char *buf, size_t sz)
659{
660 struct timeval tv;
661 struct tm tm;
662 char dt[32];
663
664 if (gettimeofday(&tv, NULL) || !localtime_r(&tv.tv_sec, &tm))
665 return -1;
666
667 if (!strftime(dt, sizeof(dt), "%Y%m%d%H%M%S", &tm))
668 return -1;
669
670 scnprintf(buf, sz, "%s%02u", dt, (unsigned)tv.tv_usec / 10000);
671
672 return 0;
673}
674
675void print_binary(unsigned char *data, size_t len,
676 size_t bytes_per_line, print_binary_t printer,
677 void *extra)
678{
679 size_t i, j, mask;
680
681 if (!printer)
682 return;
683
684 bytes_per_line = roundup_pow_of_two(bytes_per_line);
685 mask = bytes_per_line - 1;
686
687 printer(BINARY_PRINT_DATA_BEGIN, 0, extra);
688 for (i = 0; i < len; i++) {
689 if ((i & mask) == 0) {
690 printer(BINARY_PRINT_LINE_BEGIN, -1, extra);
691 printer(BINARY_PRINT_ADDR, i, extra);
692 }
693
694 printer(BINARY_PRINT_NUM_DATA, data[i], extra);
695
696 if (((i & mask) == mask) || i == len - 1) {
697 for (j = 0; j < mask-(i & mask); j++)
698 printer(BINARY_PRINT_NUM_PAD, -1, extra);
699
700 printer(BINARY_PRINT_SEP, i, extra);
701 for (j = i & ~mask; j <= i; j++)
702 printer(BINARY_PRINT_CHAR_DATA, data[j], extra);
703 for (j = 0; j < mask-(i & mask); j++)
704 printer(BINARY_PRINT_CHAR_PAD, i, extra);
705 printer(BINARY_PRINT_LINE_END, -1, extra);
706 }
707 }
708 printer(BINARY_PRINT_DATA_END, -1, extra);
709}
diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h
index fe915e616f9b..8298d607c738 100644
--- a/tools/perf/util/util.h
+++ b/tools/perf/util/util.h
@@ -82,6 +82,8 @@
82 82
83extern const char *graph_line; 83extern const char *graph_line;
84extern const char *graph_dotted_line; 84extern const char *graph_dotted_line;
85extern const char *spaces;
86extern const char *dots;
85extern char buildid_dir[]; 87extern char buildid_dir[];
86 88
87/* On most systems <limits.h> would have given us this, but 89/* On most systems <limits.h> would have given us this, but
@@ -131,25 +133,15 @@ extern char buildid_dir[];
131#define PERF_GTK_DSO "libperf-gtk.so" 133#define PERF_GTK_DSO "libperf-gtk.so"
132 134
133/* General helper functions */ 135/* General helper functions */
134extern void usage(const char *err) NORETURN; 136void usage(const char *err) NORETURN;
135extern void die(const char *err, ...) NORETURN __attribute__((format (printf, 1, 2))); 137void die(const char *err, ...) NORETURN __attribute__((format (printf, 1, 2)));
136extern int error(const char *err, ...) __attribute__((format (printf, 1, 2))); 138int error(const char *err, ...) __attribute__((format (printf, 1, 2)));
137extern void warning(const char *err, ...) __attribute__((format (printf, 1, 2))); 139void warning(const char *err, ...) __attribute__((format (printf, 1, 2)));
138 140
139#include "../../../include/linux/stringify.h" 141void set_warning_routine(void (*routine)(const char *err, va_list params));
140 142
141#define DIE_IF(cnd) \ 143int prefixcmp(const char *str, const char *prefix);
142 do { if (cnd) \ 144void set_buildid_dir(const char *dir);
143 die(" at (" __FILE__ ":" __stringify(__LINE__) "): " \
144 __stringify(cnd) "\n"); \
145 } while (0)
146
147
148extern void set_die_routine(void (*routine)(const char *err, va_list params) NORETURN);
149extern void set_warning_routine(void (*routine)(const char *err, va_list params));
150
151extern int prefixcmp(const char *str, const char *prefix);
152extern void set_buildid_dir(const char *dir);
153 145
154#ifdef __GLIBC_PREREQ 146#ifdef __GLIBC_PREREQ
155#if __GLIBC_PREREQ(2, 1) 147#if __GLIBC_PREREQ(2, 1)
@@ -170,8 +162,7 @@ static inline char *gitstrchrnul(const char *s, int c)
170/* 162/*
171 * Wrappers: 163 * Wrappers:
172 */ 164 */
173extern char *xstrdup(const char *str); 165void *xrealloc(void *ptr, size_t size) __attribute__((weak));
174extern void *xrealloc(void *ptr, size_t size) __attribute__((weak));
175 166
176 167
177static inline void *zalloc(size_t size) 168static inline void *zalloc(size_t size)
@@ -303,7 +294,6 @@ char *__get_srcline(struct dso *dso, u64 addr, struct symbol *sym,
303 bool show_sym, bool unwind_inlines); 294 bool show_sym, bool unwind_inlines);
304void free_srcline(char *srcline); 295void free_srcline(char *srcline);
305 296
306int filename__read_str(const char *filename, char **buf, size_t *sizep);
307int perf_event_paranoid(void); 297int perf_event_paranoid(void);
308 298
309void mem_bswap_64(void *src, int byte_size); 299void mem_bswap_64(void *src, int byte_size);
@@ -343,5 +333,27 @@ int fetch_kernel_version(unsigned int *puint,
343#define KVER_PARAM(x) KVER_VERSION(x), KVER_PATCHLEVEL(x), KVER_SUBLEVEL(x) 333#define KVER_PARAM(x) KVER_VERSION(x), KVER_PATCHLEVEL(x), KVER_SUBLEVEL(x)
344 334
345const char *perf_tip(const char *dirpath); 335const char *perf_tip(const char *dirpath);
336bool is_regular_file(const char *file);
337int fetch_current_timestamp(char *buf, size_t sz);
338
339enum binary_printer_ops {
340 BINARY_PRINT_DATA_BEGIN,
341 BINARY_PRINT_LINE_BEGIN,
342 BINARY_PRINT_ADDR,
343 BINARY_PRINT_NUM_DATA,
344 BINARY_PRINT_NUM_PAD,
345 BINARY_PRINT_SEP,
346 BINARY_PRINT_CHAR_DATA,
347 BINARY_PRINT_CHAR_PAD,
348 BINARY_PRINT_LINE_END,
349 BINARY_PRINT_DATA_END,
350};
351
352typedef void (*print_binary_t)(enum binary_printer_ops,
353 unsigned int val,
354 void *extra);
346 355
356void print_binary(unsigned char *data, size_t len,
357 size_t bytes_per_line, print_binary_t printer,
358 void *extra);
347#endif /* GIT_COMPAT_UTIL_H */ 359#endif /* GIT_COMPAT_UTIL_H */
diff --git a/tools/perf/util/wrapper.c b/tools/perf/util/wrapper.c
index 19f15b650703..5f1a07c4b87b 100644
--- a/tools/perf/util/wrapper.c
+++ b/tools/perf/util/wrapper.c
@@ -12,18 +12,6 @@ static inline void release_pack_memory(size_t size __maybe_unused,
12{ 12{
13} 13}
14 14
15char *xstrdup(const char *str)
16{
17 char *ret = strdup(str);
18 if (!ret) {
19 release_pack_memory(strlen(str) + 1, -1);
20 ret = strdup(str);
21 if (!ret)
22 die("Out of memory, strdup failed");
23 }
24 return ret;
25}
26
27void *xrealloc(void *ptr, size_t size) 15void *xrealloc(void *ptr, size_t size)
28{ 16{
29 void *ret = realloc(ptr, size); 17 void *ret = realloc(ptr, size);