aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf
diff options
context:
space:
mode:
authorJiri Kosina <jkosina@suse.cz>2016-04-18 05:18:55 -0400
committerJiri Kosina <jkosina@suse.cz>2016-04-18 05:18:55 -0400
commit9938b04472d5c59f8bd8152a548533a8599596a2 (patch)
tree0fc8318100878c5e446076613ec02a97aa179119 /tools/perf
parentbd7ced98812dbb906950d8b0ec786f14f631cede (diff)
parentc3b46c73264b03000d1e18b22f5caf63332547c9 (diff)
Merge branch 'master' into for-next
Sync with Linus' tree so that patches against newer codebase can be applied. Signed-off-by: Jiri Kosina <jkosina@suse.cz>
Diffstat (limited to 'tools/perf')
-rw-r--r--tools/perf/Build9
-rw-r--r--tools/perf/Documentation/Makefile2
-rw-r--r--tools/perf/Documentation/perf-config.txt456
-rw-r--r--tools/perf/Documentation/perf-evlist.txt3
-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.txt33
-rw-r--r--tools/perf/Documentation/perf-report.txt81
-rw-r--r--tools/perf/Documentation/perf-stat.txt69
-rw-r--r--tools/perf/Documentation/perf-top.txt6
-rw-r--r--tools/perf/Documentation/perf-trace.txt1
-rw-r--r--tools/perf/Documentation/perfconfig.example2
-rw-r--r--tools/perf/Documentation/tips.txt30
-rw-r--r--tools/perf/MANIFEST10
-rw-r--r--tools/perf/Makefile25
-rw-r--r--tools/perf/Makefile.perf83
-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/include/arch-tests.h8
-rw-r--r--tools/perf/arch/x86/tests/insn-x86.c2
-rw-r--r--tools/perf/arch/x86/tests/intel-cqm.c6
-rw-r--r--tools/perf/arch/x86/tests/perf-time-to-tsc.c3
-rw-r--r--tools/perf/arch/x86/tests/rdpmc.c5
-rw-r--r--tools/perf/arch/x86/util/Build1
-rw-r--r--tools/perf/arch/x86/util/intel-bts.c8
-rw-r--r--tools/perf/arch/x86/util/intel-pt.c12
-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/futex-hash.c2
-rw-r--r--tools/perf/bench/futex-lock-pi.c2
-rw-r--r--tools/perf/bench/futex-requeue.c2
-rw-r--r--tools/perf/bench/futex-wake-parallel.c2
-rw-r--r--tools/perf/bench/futex-wake.c2
-rw-r--r--tools/perf/bench/mem-functions.c2
-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.c4
-rw-r--r--tools/perf/bench/sched-messaging.c2
-rw-r--r--tools/perf/bench/sched-pipe.c2
-rw-r--r--tools/perf/builtin-annotate.c48
-rw-r--r--tools/perf/builtin-bench.c2
-rw-r--r--tools/perf/builtin-buildid-cache.c16
-rw-r--r--tools/perf/builtin-buildid-list.c4
-rw-r--r--tools/perf/builtin-config.c87
-rw-r--r--tools/perf/builtin-data.c2
-rw-r--r--tools/perf/builtin-diff.c19
-rw-r--r--tools/perf/builtin-evlist.c13
-rw-r--r--tools/perf/builtin-help.c84
-rw-r--r--tools/perf/builtin-inject.c116
-rw-r--r--tools/perf/builtin-kmem.c55
-rw-r--r--tools/perf/builtin-kvm.c43
-rw-r--r--tools/perf/builtin-list.c2
-rw-r--r--tools/perf/builtin-lock.c2
-rw-r--r--tools/perf/builtin-mem.c88
-rw-r--r--tools/perf/builtin-probe.c17
-rw-r--r--tools/perf/builtin-record.c267
-rw-r--r--tools/perf/builtin-report.c125
-rw-r--r--tools/perf/builtin-sched.c7
-rw-r--r--tools/perf/builtin-script.c438
-rw-r--r--tools/perf/builtin-stat.c1422
-rw-r--r--tools/perf/builtin-timechart.c4
-rw-r--r--tools/perf/builtin-top.c126
-rw-r--r--tools/perf/builtin-trace.c67
-rw-r--r--tools/perf/builtin-version.c10
-rw-r--r--tools/perf/builtin.h63
-rw-r--r--tools/perf/command-list.txt3
-rw-r--r--tools/perf/config/Makefile156
-rw-r--r--tools/perf/config/Makefile.arch18
-rw-r--r--tools/perf/config/utilities.mak198
-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.c42
-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/scripts/python/stat-cpi.py77
-rw-r--r--tools/perf/tests/.gitignore4
-rw-r--r--tools/perf/tests/Build34
-rw-r--r--tools/perf/tests/attr.c9
-rw-r--r--tools/perf/tests/bp_signal.c142
-rw-r--r--tools/perf/tests/bp_signal_overflow.c2
-rw-r--r--tools/perf/tests/bpf-script-example.c4
-rw-r--r--tools/perf/tests/bpf-script-test-kbuild.c21
-rw-r--r--tools/perf/tests/bpf-script-test-prologue.c35
-rw-r--r--tools/perf/tests/bpf-script-test-relocation.c50
-rw-r--r--tools/perf/tests/bpf.c315
-rw-r--r--tools/perf/tests/builtin-test.c147
-rw-r--r--tools/perf/tests/code-reading.c39
-rw-r--r--tools/perf/tests/cpumap.c88
-rw-r--r--tools/perf/tests/dso-data.c6
-rw-r--r--tools/perf/tests/dwarf-unwind.c41
-rw-r--r--tools/perf/tests/event_update.c117
-rw-r--r--tools/perf/tests/evsel-roundtrip-name.c5
-rw-r--r--tools/perf/tests/evsel-tp-sched.c2
-rw-r--r--tools/perf/tests/fdarray.c4
-rw-r--r--tools/perf/tests/hists_common.c7
-rw-r--r--tools/perf/tests/hists_cumulate.c22
-rw-r--r--tools/perf/tests/hists_filter.c16
-rw-r--r--tools/perf/tests/hists_link.c31
-rw-r--r--tools/perf/tests/hists_output.c32
-rw-r--r--tools/perf/tests/keep-tracking.c9
-rw-r--r--tools/perf/tests/kmod-path.c2
-rw-r--r--tools/perf/tests/llvm.c158
-rw-r--r--tools/perf/tests/llvm.h23
-rw-r--r--tools/perf/tests/make125
-rw-r--r--tools/perf/tests/mmap-basic.c2
-rw-r--r--tools/perf/tests/mmap-thread-lookup.c8
-rw-r--r--tools/perf/tests/openat-syscall-all-cpus.c2
-rw-r--r--tools/perf/tests/openat-syscall-tp-fields.c2
-rw-r--r--tools/perf/tests/openat-syscall.c2
-rw-r--r--tools/perf/tests/parse-events.c56
-rw-r--r--tools/perf/tests/parse-no-sample-id-all.c2
-rw-r--r--tools/perf/tests/perf-record.c8
-rwxr-xr-xtools/perf/tests/perf-targz-src-pkg2
-rw-r--r--tools/perf/tests/pmu.c2
-rw-r--r--tools/perf/tests/python-use.c3
-rw-r--r--tools/perf/tests/sample-parsing.c2
-rw-r--r--tools/perf/tests/stat.c111
-rw-r--r--tools/perf/tests/sw-clock.c2
-rw-r--r--tools/perf/tests/switch-tracking.c12
-rw-r--r--tools/perf/tests/task-exit.c2
-rw-r--r--tools/perf/tests/tests.h94
-rw-r--r--tools/perf/tests/thread-map.c45
-rw-r--r--tools/perf/tests/thread-mg-share.c2
-rw-r--r--tools/perf/tests/topology.c2
-rw-r--r--tools/perf/tests/vmlinux-kallsyms.c26
-rw-r--r--tools/perf/ui/browser.c6
-rw-r--r--tools/perf/ui/browser.h2
-rw-r--r--tools/perf/ui/browsers/annotate.c6
-rw-r--r--tools/perf/ui/browsers/hists.c1199
-rw-r--r--tools/perf/ui/gtk/hists.c353
-rw-r--r--tools/perf/ui/hist.c274
-rw-r--r--tools/perf/ui/stdio/hist.c400
-rw-r--r--tools/perf/util/Build39
-rw-r--r--tools/perf/util/abspath.c37
-rw-r--r--tools/perf/util/annotate.c44
-rw-r--r--tools/perf/util/annotate.h2
-rw-r--r--tools/perf/util/auxtrace.c9
-rw-r--r--tools/perf/util/auxtrace.h8
-rw-r--r--tools/perf/util/bitmap.c31
-rw-r--r--tools/perf/util/bpf-loader.c1298
-rw-r--r--tools/perf/util/bpf-loader.h96
-rw-r--r--tools/perf/util/bpf-prologue.c455
-rw-r--r--tools/perf/util/bpf-prologue.h34
-rw-r--r--tools/perf/util/build-id.c56
-rw-r--r--tools/perf/util/build-id.h1
-rw-r--r--tools/perf/util/cache.h39
-rw-r--r--tools/perf/util/callchain.c266
-rw-r--r--tools/perf/util/callchain.h34
-rw-r--r--tools/perf/util/cgroup.c2
-rw-r--r--tools/perf/util/cgroup.h4
-rw-r--r--tools/perf/util/cloexec.h2
-rw-r--r--tools/perf/util/color.c7
-rw-r--r--tools/perf/util/config.c6
-rw-r--r--tools/perf/util/cpumap.c81
-rw-r--r--tools/perf/util/cpumap.h33
-rw-r--r--tools/perf/util/ctype.c9
-rw-r--r--tools/perf/util/data-convert-bt.c142
-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.c24
-rw-r--r--tools/perf/util/dso.h4
-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.c22
-rw-r--r--tools/perf/util/env.h15
-rw-r--r--tools/perf/util/environment.c8
-rw-r--r--tools/perf/util/event.c360
-rw-r--r--tools/perf/util/event.h163
-rw-r--r--tools/perf/util/evlist.c155
-rw-r--r--tools/perf/util/evlist.h13
-rw-r--r--tools/perf/util/evsel.c84
-rw-r--r--tools/perf/util/evsel.h18
-rw-r--r--tools/perf/util/exec_cmd.c148
-rw-r--r--tools/perf/util/exec_cmd.h12
-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
-rwxr-xr-xtools/perf/util/generate-cmdlist.sh15
-rw-r--r--tools/perf/util/header.c482
-rw-r--r--tools/perf/util/header.h18
-rw-r--r--tools/perf/util/help-unknown-cmd.c104
-rw-r--r--tools/perf/util/help-unknown-cmd.h0
-rw-r--r--tools/perf/util/help.c339
-rw-r--r--tools/perf/util/help.h29
-rw-r--r--tools/perf/util/hist.c939
-rw-r--r--tools/perf/util/hist.h145
-rw-r--r--tools/perf/util/include/linux/bitmap.h66
-rw-r--r--tools/perf/util/include/linux/string.h3
-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.c16
-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.c74
-rw-r--r--tools/perf/util/llvm-utils.h7
-rw-r--r--tools/perf/util/machine.c89
-rw-r--r--tools/perf/util/machine.h12
-rw-r--r--tools/perf/util/map.c17
-rw-r--r--tools/perf/util/mem-events.c255
-rw-r--r--tools/perf/util/mem-events.h35
-rw-r--r--tools/perf/util/pager.c95
-rw-r--r--tools/perf/util/parse-branch-options.c2
-rw-r--r--tools/perf/util/parse-events.c338
-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/parse-options.c867
-rw-r--r--tools/perf/util/parse-options.h229
-rw-r--r--tools/perf/util/parse-regs-options.c2
-rw-r--r--tools/perf/util/path.c48
-rw-r--r--tools/perf/util/pmu.c35
-rw-r--r--tools/perf/util/probe-event.c15
-rw-r--r--tools/perf/util/probe-event.h57
-rw-r--r--tools/perf/util/probe-file.c6
-rw-r--r--tools/perf/util/probe-finder.c100
-rw-r--r--tools/perf/util/probe-finder.h29
-rw-r--r--tools/perf/util/python-ext-sources2
-rw-r--r--tools/perf/util/quote.h2
-rw-r--r--tools/perf/util/run-command.c219
-rw-r--r--tools/perf/util/run-command.h58
-rw-r--r--tools/perf/util/scripting-engines/trace-event-perl.c3
-rw-r--r--tools/perf/util/scripting-engines/trace-event-python.c122
-rw-r--r--tools/perf/util/session.c253
-rw-r--r--tools/perf/util/session.h2
-rw-r--r--tools/perf/util/setup.py4
-rw-r--r--tools/perf/util/sigchain.c52
-rw-r--r--tools/perf/util/sigchain.h10
-rw-r--r--tools/perf/util/sort.c1304
-rw-r--r--tools/perf/util/sort.h43
-rw-r--r--tools/perf/util/stat-shadow.c240
-rw-r--r--tools/perf/util/stat.c87
-rw-r--r--tools/perf/util/stat.h34
-rw-r--r--tools/perf/util/strbuf.c27
-rw-r--r--tools/perf/util/strbuf.h23
-rw-r--r--tools/perf/util/string.c16
-rw-r--r--tools/perf/util/strlist.c8
-rw-r--r--tools/perf/util/strlist.h9
-rw-r--r--tools/perf/util/svghelper.h51
-rw-r--r--tools/perf/util/symbol-elf.c24
-rw-r--r--tools/perf/util/symbol.c110
-rw-r--r--tools/perf/util/symbol.h10
-rw-r--r--tools/perf/util/term.c35
-rw-r--r--tools/perf/util/term.h10
-rw-r--r--tools/perf/util/thread.c10
-rw-r--r--tools/perf/util/thread_map.c28
-rw-r--r--tools/perf/util/thread_map.h3
-rw-r--r--tools/perf/util/tool.h8
-rw-r--r--tools/perf/util/trace-event-parse.c2
-rw-r--r--tools/perf/util/trace-event.c1
-rw-r--r--tools/perf/util/trace-event.h4
-rw-r--r--tools/perf/util/tsc.c2
-rw-r--r--tools/perf/util/unwind-libdw.c63
-rw-r--r--tools/perf/util/unwind-libdw.h2
-rw-r--r--tools/perf/util/unwind-libunwind.c80
-rw-r--r--tools/perf/util/usage.c8
-rw-r--r--tools/perf/util/util.c210
-rw-r--r--tools/perf/util/util.h80
-rw-r--r--tools/perf/util/wrapper.c12
274 files changed, 18500 insertions, 5551 deletions
diff --git a/tools/perf/Build b/tools/perf/Build
index 72237455b400..a43fae7f439a 100644
--- a/tools/perf/Build
+++ b/tools/perf/Build
@@ -1,5 +1,6 @@
1perf-y += builtin-bench.o 1perf-y += builtin-bench.o
2perf-y += builtin-annotate.o 2perf-y += builtin-annotate.o
3perf-y += builtin-config.o
3perf-y += builtin-diff.o 4perf-y += builtin-diff.o
4perf-y += builtin-evlist.o 5perf-y += builtin-evlist.o
5perf-y += builtin-help.o 6perf-y += builtin-help.o
@@ -19,6 +20,7 @@ perf-y += builtin-kvm.o
19perf-y += builtin-inject.o 20perf-y += builtin-inject.o
20perf-y += builtin-mem.o 21perf-y += builtin-mem.o
21perf-y += builtin-data.o 22perf-y += builtin-data.o
23perf-y += builtin-version.o
22 24
23perf-$(CONFIG_AUDIT) += builtin-trace.o 25perf-$(CONFIG_AUDIT) += builtin-trace.o
24perf-$(CONFIG_LIBELF) += builtin-probe.o 26perf-$(CONFIG_LIBELF) += builtin-probe.o
@@ -34,8 +36,13 @@ paths += -DPERF_MAN_PATH="BUILD_STR($(mandir_SQ))"
34 36
35CFLAGS_builtin-help.o += $(paths) 37CFLAGS_builtin-help.o += $(paths)
36CFLAGS_builtin-timechart.o += $(paths) 38CFLAGS_builtin-timechart.o += $(paths)
37CFLAGS_perf.o += -DPERF_HTML_PATH="BUILD_STR($(htmldir_SQ))" -include $(OUTPUT)PERF-VERSION-FILE 39CFLAGS_perf.o += -DPERF_HTML_PATH="BUILD_STR($(htmldir_SQ))" \
40 -DPERF_EXEC_PATH="BUILD_STR($(perfexecdir_SQ))" \
41 -DPREFIX="BUILD_STR($(prefix_SQ))" \
42 -include $(OUTPUT)PERF-VERSION-FILE
38CFLAGS_builtin-trace.o += -DSTRACE_GROUPS_DIR="BUILD_STR($(STRACE_GROUPS_DIR_SQ))" 43CFLAGS_builtin-trace.o += -DSTRACE_GROUPS_DIR="BUILD_STR($(STRACE_GROUPS_DIR_SQ))"
44CFLAGS_builtin-report.o += -DTIPDIR="BUILD_STR($(tipdir_SQ))"
45CFLAGS_builtin-report.o += -DDOCDIR="BUILD_STR($(srcdir_SQ)/Documentation)"
39 46
40libperf-y += util/ 47libperf-y += util/
41libperf-y += arch/ 48libperf-y += arch/
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
new file mode 100644
index 000000000000..15949e2a7805
--- /dev/null
+++ b/tools/perf/Documentation/perf-config.txt
@@ -0,0 +1,456 @@
1perf-config(1)
2==============
3
4NAME
5----
6perf-config - Get and set variables in a configuration file.
7
8SYNOPSIS
9--------
10[verse]
11'perf config' [<file-option>] -l | --list
12
13DESCRIPTION
14-----------
15You can manage variables in a configuration file with this command.
16
17OPTIONS
18-------
19
20-l::
21--list::
22 Show current config variables, name and value, for all sections.
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
32CONFIGURATION FILE
33------------------
34
35The perf configuration file contains many variables to change various
36aspects of each of its tools, including output, disk usage, etc.
37The '$HOME/.perfconfig' file is used to store a per-user configuration.
38The file '$(sysconfdir)/perfconfig' can be used to
39store a system-wide default configuration.
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
45Syntax
46~~~~~~
47
48The file consist of sections. A section starts with its name
49surrounded by square brackets and continues till the next section
50begins. Each variable must be in a section, and have the form
51'name = value', for example:
52
53 [section]
54 name1 = value1
55 name2 = value2
56
57Section names are case sensitive and can contain any characters except
58newline (double quote `"` and backslash have to be escaped as `\"` and `\\`,
59respectively). Section headers can't span multiple lines.
60
61Example
62~~~~~~~
63
64Given a $HOME/.perfconfig like this:
65
66#
67# This is the config file, and
68# a '#' and ';' character indicates a comment
69#
70
71 [colors]
72 # Color variables
73 top = red, default
74 medium = green, default
75 normal = lightgray, default
76 selected = white, lightgray
77 jump_arrows = blue, default
78 addr = magenta, default
79 root = white, blue
80
81 [tui]
82 # Defaults if linked with libslang
83 report = on
84 annotate = on
85 top = on
86
87 [buildid]
88 # Default, disable using /dev/null
89 dir = ~/.debug
90
91 [annotate]
92 # Defaults
93 hide_src_code = false
94 use_offset = true
95 jump_arrows = true
96 show_nr_jumps = false
97
98 [help]
99 # Format can be man, info, web or html
100 format = man
101 autocorrect = 0
102
103 [ui]
104 show-headers = true
105
106 [call-graph]
107 # fp (framepointer), dwarf
108 record-mode = fp
109 print-type = graph
110 order = caller
111 sort-key = function
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
454SEE ALSO
455--------
456linkperf:perf[1]
diff --git a/tools/perf/Documentation/perf-evlist.txt b/tools/perf/Documentation/perf-evlist.txt
index 1ceb3700ffbb..6f7200fb85cf 100644
--- a/tools/perf/Documentation/perf-evlist.txt
+++ b/tools/perf/Documentation/perf-evlist.txt
@@ -32,6 +32,9 @@ OPTIONS
32--group:: 32--group::
33 Show event group information. 33 Show event group information.
34 34
35--trace-fields::
36 Show tracepoint field names.
37
35SEE ALSO 38SEE ALSO
36-------- 39--------
37linkperf:perf-record[1], linkperf:perf-list[1], 40linkperf:perf-record[1], linkperf:perf-list[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 e630a7d2c348..19aa17532a16 100644
--- a/tools/perf/Documentation/perf-record.txt
+++ b/tools/perf/Documentation/perf-record.txt
@@ -207,11 +207,23 @@ comma-separated list with no space: 0,1. Ranges of CPUs are specified with -: 0-
207In per-thread mode with inheritance mode on (default), samples are captured only when 207In per-thread mode with inheritance mode on (default), samples are captured only when
208the thread executes on the designated CPUs. Default is to monitor all CPUs. 208the thread executes on the designated CPUs. Default is to monitor all CPUs.
209 209
210-B::
211--no-buildid::
212Do not save the build ids of binaries in the perf.data files. This skips
213post processing after recording, which sometimes makes the final step in
214the recording process to take a long time, as it needs to process all
215events looking for mmap records. The downside is that it can misresolve
216symbols if the workload binaries used when recording get locally rebuilt
217or upgraded, because the only key available in this case is the
218pathname. You can also set the "record.build-id" config variable to
219'skip to have this behaviour permanently.
220
210-N:: 221-N::
211--no-buildid-cache:: 222--no-buildid-cache::
212Do not update the buildid cache. This saves some overhead in situations 223Do not update the buildid cache. This saves some overhead in situations
213where the information in the perf.data file (which includes buildids) 224where the information in the perf.data file (which includes buildids)
214is sufficient. 225is sufficient. You can also set the "record.build-id" config variable to
226'no-cache' to have the same effect.
215 227
216-G name,...:: 228-G name,...::
217--cgroup name,...:: 229--cgroup name,...::
@@ -314,11 +326,26 @@ This option sets the time out limit. The default value is 500 ms.
314Record context switch events i.e. events of type PERF_RECORD_SWITCH or 326Record context switch events i.e. events of type PERF_RECORD_SWITCH or
315PERF_RECORD_SWITCH_CPU_WIDE. 327PERF_RECORD_SWITCH_CPU_WIDE.
316 328
317--clang-path:: 329--clang-path=PATH::
318Path to clang binary to use for compiling BPF scriptlets. 330Path to clang binary to use for compiling BPF scriptlets.
331(enabled when BPF support is on)
319 332
320--clang-opt:: 333--clang-opt=OPTIONS::
321Options passed to clang when compiling BPF scriptlets. 334Options passed to clang when compiling BPF scriptlets.
335(enabled when BPF support is on)
336
337--vmlinux=PATH::
338Specify vmlinux path which has debuginfo.
339(enabled when BPF prologue is on)
340
341--buildid-all::
342Record build-id of all DSOs regardless whether it's actually hit or not.
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.
322 349
323SEE ALSO 350SEE ALSO
324-------- 351--------
diff --git a/tools/perf/Documentation/perf-report.txt b/tools/perf/Documentation/perf-report.txt
index 5ce8da1e1256..12113992ac9d 100644
--- a/tools/perf/Documentation/perf-report.txt
+++ b/tools/perf/Documentation/perf-report.txt
@@ -117,6 +117,46 @@ 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
136 If the data file has tracepoint event(s), following (dynamic) sort keys
137 are also available:
138 trace, trace_fields, [<event>.]<field>[/raw]
139
140 - trace: pretty printed trace output in a single column
141 - trace_fields: fields in tracepoints in separate columns
142 - <field name>: optional event and field name for a specific field
143
144 The last form consists of event and field names. If event name is
145 omitted, it searches all events for matching field name. The matched
146 field will be shown only for the event has the field. The event name
147 supports substring match so user doesn't need to specify full subsystem
148 and event name everytime. For example, 'sched:sched_switch' event can
149 be shortened to 'switch' as long as it's not ambiguous. Also event can
150 be specified by its index (starting from 1) preceded by the '%'.
151 So '%1' is the first event, '%2' is the second, and so on.
152
153 The field name can have '/raw' suffix which disables pretty printing
154 and shows raw field value like hex numbers. The --raw-trace option
155 has the same effect for all dynamic sort keys.
156
157 The default sort keys are changed to 'trace' if all events in the data
158 file are tracepoint.
159
120-F:: 160-F::
121--fields=:: 161--fields=::
122 Specify output field - multiple keys can be specified in CSV format. 162 Specify output field - multiple keys can be specified in CSV format.
@@ -127,22 +167,6 @@ OPTIONS
127 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
128 automatically. 168 automatically.
129 169
130 If --mem-mode option is used, following sort keys are also available
131 (incompatible with --branch-stack):
132 symbol_daddr, dso_daddr, locked, tlb, mem, snoop, dcacheline.
133
134 - symbol_daddr: name of data symbol being executed on at the time of sample
135 - dso_daddr: name of library or module containing the data being executed
136 on at the time of sample
137 - locked: whether the bus was locked at the time of sample
138 - tlb: type of tlb access for the data at the time of sample
139 - mem: type of memory access for the data at the time of sample
140 - snoop: type of snoop (if any) for the data at the time of sample
141 - dcacheline: the cacheline the data address is on at the time of sample
142
143 And default sort keys are changed to local_weight, mem, sym, dso,
144 symbol_daddr, dso_daddr, snoop, tlb, locked, see '--mem-mode'.
145
146-p:: 170-p::
147--parent=<regex>:: 171--parent=<regex>::
148 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
@@ -170,17 +194,18 @@ OPTIONS
170 Dump raw trace in ASCII. 194 Dump raw trace in ASCII.
171 195
172-g:: 196-g::
173--call-graph=<print_type,threshold[,print_limit],order,sort_key,branch>:: 197--call-graph=<print_type,threshold[,print_limit],order,sort_key[,branch],value>::
174 Display call chains using type, min percent threshold, print limit, 198 Display call chains using type, min percent threshold, print limit,
175 call order, sort key and branch. Note that ordering of parameters is not 199 call order, sort key, optional branch and value. Note that ordering of
176 fixed so any parement can be given in an arbitraty order. One exception 200 parameters is not fixed so any parement can be given in an arbitraty order.
177 is the print_limit which should be preceded by threshold. 201 One exception is the print_limit which should be preceded by threshold.
178 202
179 print_type can be either: 203 print_type can be either:
180 - flat: single column, linear exposure of call chains. 204 - flat: single column, linear exposure of call chains.
181 - graph: use a graph tree, displaying absolute overhead rates. (default) 205 - graph: use a graph tree, displaying absolute overhead rates. (default)
182 - fractal: like graph, but displays relative rates. Each branch of 206 - fractal: like graph, but displays relative rates. Each branch of
183 the tree is considered as a new profiled object. 207 the tree is considered as a new profiled object.
208 - folded: call chains are displayed in a line, separated by semicolons
184 - none: disable call chain display. 209 - none: disable call chain display.
185 210
186 threshold is a percentage value which specifies a minimum percent to be 211 threshold is a percentage value which specifies a minimum percent to be
@@ -204,6 +229,11 @@ OPTIONS
204 - branch: include last branch information in callgraph when available. 229 - branch: include last branch information in callgraph when available.
205 Usually more convenient to use --branch-history for this. 230 Usually more convenient to use --branch-history for this.
206 231
232 value can be:
233 - percent: diplay overhead percent (default)
234 - period: display event period
235 - count: display event count
236
207--children:: 237--children::
208 Accumulate callchain of children to parent entry so that then can 238 Accumulate callchain of children to parent entry so that then can
209 show up in the output. The output will have a new "Children" column 239 show up in the output. The output will have a new "Children" column
@@ -321,7 +351,10 @@ OPTIONS
321 351
322--percent-limit:: 352--percent-limit::
323 Do not show entries which have an overhead under that percent. 353 Do not show entries which have an overhead under that percent.
324 (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.
325 358
326--percentage:: 359--percentage::
327 Determine how to display the overhead percentage of filtered entries. 360 Determine how to display the overhead percentage of filtered entries.
@@ -365,6 +398,12 @@ include::itrace.txt[]
365--socket-filter:: 398--socket-filter::
366 Only report the samples on the processor socket that match with this filter 399 Only report the samples on the processor socket that match with this filter
367 400
401--raw-trace::
402 When displaying traceevent output, do not use print fmt or plugins.
403
404--hierarchy::
405 Enable hierarchical output.
406
368include::callchain-overhead-calculation.txt[] 407include::callchain-overhead-calculation.txt[]
369 408
370SEE ALSO 409SEE ALSO
diff --git a/tools/perf/Documentation/perf-stat.txt b/tools/perf/Documentation/perf-stat.txt
index 4e074a660826..04f23b404bbc 100644
--- a/tools/perf/Documentation/perf-stat.txt
+++ b/tools/perf/Documentation/perf-stat.txt
@@ -10,6 +10,8 @@ SYNOPSIS
10[verse] 10[verse]
11'perf stat' [-e <EVENT> | --event=EVENT] [-a] <command> 11'perf stat' [-e <EVENT> | --event=EVENT] [-a] <command>
12'perf stat' [-e <EVENT> | --event=EVENT] [-a] -- <command> [<options>] 12'perf stat' [-e <EVENT> | --event=EVENT] [-a] -- <command> [<options>]
13'perf stat' [-e <EVENT> | --event=EVENT] [-a] record [-o file] -- <command> [<options>]
14'perf stat' report [-i file]
13 15
14DESCRIPTION 16DESCRIPTION
15----------- 17-----------
@@ -22,6 +24,11 @@ OPTIONS
22<command>...:: 24<command>...::
23 Any command you can specify in a shell. 25 Any command you can specify in a shell.
24 26
27record::
28 See STAT RECORD.
29
30report::
31 See STAT REPORT.
25 32
26-e:: 33-e::
27--event=:: 34--event=::
@@ -62,6 +69,14 @@ OPTIONS
62--scale:: 69--scale::
63 scale/normalize counter values 70 scale/normalize counter values
64 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
65-r:: 80-r::
66--repeat=<n>:: 81--repeat=<n>::
67 repeat command and print average + stddev (max: 100). 0 means forever. 82 repeat command and print average + stddev (max: 100). 0 means forever.
@@ -132,6 +147,10 @@ Print count deltas every N milliseconds (minimum: 10ms)
132The 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.
133 example: 'perf stat -I 1000 -e cycles -a sleep 5' 148 example: 'perf stat -I 1000 -e cycles -a sleep 5'
134 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
135--per-socket:: 154--per-socket::
136Aggregate counts per processor socket for system-wide mode measurements. This 155Aggregate counts per processor socket for system-wide mode measurements. This
137is 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,
@@ -159,6 +178,33 @@ filter out the startup phase of the program, which is often very different.
159 178
160Print statistics of transactional execution if supported. 179Print statistics of transactional execution if supported.
161 180
181STAT RECORD
182-----------
183Stores stat data into perf data file.
184
185-o file::
186--output file::
187Output file name.
188
189STAT REPORT
190-----------
191Reads and reports stat data from perf data file.
192
193-i file::
194--input file::
195Input file name.
196
197--per-socket::
198Aggregate counts per processor socket for system-wide mode measurements.
199
200--per-core::
201Aggregate counts per physical processor for system-wide mode measurements.
202
203-A::
204--no-aggr::
205Do not aggregate counts across all monitored CPUs.
206
207
162EXAMPLES 208EXAMPLES
163-------- 209--------
164 210
@@ -177,6 +223,29 @@ $ perf stat -- make -j
177 223
178 Wall-clock time elapsed: 719.554352 msecs 224 Wall-clock time elapsed: 719.554352 msecs
179 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
180SEE ALSO 249SEE ALSO
181-------- 250--------
182linkperf: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 556cec09bf50..19f046f027cd 100644
--- a/tools/perf/Documentation/perf-top.txt
+++ b/tools/perf/Documentation/perf-top.txt
@@ -230,6 +230,12 @@ Default is to monitor all CPUS.
230 The various filters must be specified as a comma separated list: --branch-filter any_ret,u,k 230 The various filters must be specified as a comma separated list: --branch-filter any_ret,u,k
231 Note that this feature may not be available on all processors. 231 Note that this feature may not be available on all processors.
232 232
233--raw-trace::
234 When displaying traceevent output, do not use print fmt or plugins.
235
236--hierarchy::
237 Enable hierarchy output.
238
233INTERACTIVE PROMPTING KEYS 239INTERACTIVE PROMPTING KEYS
234-------------------------- 240--------------------------
235 241
diff --git a/tools/perf/Documentation/perf-trace.txt b/tools/perf/Documentation/perf-trace.txt
index 7ea078658a87..13293de8869f 100644
--- a/tools/perf/Documentation/perf-trace.txt
+++ b/tools/perf/Documentation/perf-trace.txt
@@ -62,7 +62,6 @@ OPTIONS
62--verbose=:: 62--verbose=::
63 Verbosity level. 63 Verbosity level.
64 64
65-i::
66--no-inherit:: 65--no-inherit::
67 Child tasks do not inherit counters. 66 Child tasks do not inherit counters.
68 67
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
new file mode 100644
index 000000000000..5950b5a24efd
--- /dev/null
+++ b/tools/perf/Documentation/tips.txt
@@ -0,0 +1,30 @@
1For a higher level overview, try: perf report --sort comm,dso
2Sample related events with: perf record -e '{cycles,instructions}:S'
3Compare performance results with: perf diff [<old file> <new file>]
4Boolean options have negative forms, e.g.: perf report --no-children
5Customize output of perf script with: perf script -F event,ip,sym
6Generate a script for your data: perf script -g <lang>
7Save output of perf stat using: perf stat record <target workload>
8Create an archive with symtabs to analyse on other machine: perf archive
9Search options using a keyword: perf report -h <keyword>
10Use parent filter to see specific call path: perf report -p <regex>
11List events using substring match: perf list <keyword>
12To see list of saved events and attributes: perf evlist -v
13Use --symfs <dir> if your symbol files are in non-standard locations
14To see callchains in a more compact form: perf report -g folded
15Show individual samples with: perf script
16Limit to show entries above 5% only: perf report --percent-limit 5
17Profiling branch (mis)predictions with: perf record -b / perf report
18Treat branches as callchains: perf report --branch-history
19To count events in every 1000 msec: perf stat -I 1000
20Print event counts in CSV format with: perf stat -x,
21If you have debuginfo enabled, try: perf report -s sym,srcline
22For memory address profiling, try: perf mem record / perf mem report
23For tracepoint events, try: perf report -s trace_fields
24To record callchains for each sample: perf record -g
25To record every process run by an user: perf record -u <user>
26Skip collecing build-id when recording: perf record -B
27To change sampling frequency to 100 Hz: perf record -F 100
28See assembly instructions with percentage: perf annotate <symbol>
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 39c38cb45b00..8c8c6b9ce915 100644
--- a/tools/perf/MANIFEST
+++ b/tools/perf/MANIFEST
@@ -1,6 +1,7 @@
1tools/perf 1tools/perf
2tools/arch/alpha/include/asm/barrier.h 2tools/arch/alpha/include/asm/barrier.h
3tools/arch/arm/include/asm/barrier.h 3tools/arch/arm/include/asm/barrier.h
4tools/arch/arm64/include/asm/barrier.h
4tools/arch/ia64/include/asm/barrier.h 5tools/arch/ia64/include/asm/barrier.h
5tools/arch/mips/include/asm/barrier.h 6tools/arch/mips/include/asm/barrier.h
6tools/arch/powerpc/include/asm/barrier.h 7tools/arch/powerpc/include/asm/barrier.h
@@ -20,14 +21,18 @@ tools/lib/traceevent
20tools/lib/bpf 21tools/lib/bpf
21tools/lib/api 22tools/lib/api
22tools/lib/bpf 23tools/lib/bpf
24tools/lib/subcmd
23tools/lib/hweight.c 25tools/lib/hweight.c
24tools/lib/rbtree.c 26tools/lib/rbtree.c
27tools/lib/string.c
25tools/lib/symbol/kallsyms.c 28tools/lib/symbol/kallsyms.c
26tools/lib/symbol/kallsyms.h 29tools/lib/symbol/kallsyms.h
27tools/lib/util/find_next_bit.c 30tools/lib/find_bit.c
31tools/lib/bitmap.c
28tools/include/asm/atomic.h 32tools/include/asm/atomic.h
29tools/include/asm/barrier.h 33tools/include/asm/barrier.h
30tools/include/asm/bug.h 34tools/include/asm/bug.h
35tools/include/asm-generic/atomic-gcc.h
31tools/include/asm-generic/barrier.h 36tools/include/asm-generic/barrier.h
32tools/include/asm-generic/bitops/arch_hweight.h 37tools/include/asm-generic/bitops/arch_hweight.h
33tools/include/asm-generic/bitops/atomic.h 38tools/include/asm-generic/bitops/atomic.h
@@ -50,8 +55,10 @@ tools/include/linux/log2.h
50tools/include/linux/poison.h 55tools/include/linux/poison.h
51tools/include/linux/rbtree.h 56tools/include/linux/rbtree.h
52tools/include/linux/rbtree_augmented.h 57tools/include/linux/rbtree_augmented.h
58tools/include/linux/string.h
53tools/include/linux/types.h 59tools/include/linux/types.h
54tools/include/linux/err.h 60tools/include/linux/err.h
61tools/include/linux/bitmap.h
55include/asm-generic/bitops/arch_hweight.h 62include/asm-generic/bitops/arch_hweight.h
56include/asm-generic/bitops/const_hweight.h 63include/asm-generic/bitops/const_hweight.h
57include/asm-generic/bitops/fls64.h 64include/asm-generic/bitops/fls64.h
@@ -67,6 +74,7 @@ arch/*/include/uapi/asm/unistd*.h
67arch/*/include/uapi/asm/perf_regs.h 74arch/*/include/uapi/asm/perf_regs.h
68arch/*/lib/memcpy*.S 75arch/*/lib/memcpy*.S
69arch/*/lib/memset*.S 76arch/*/lib/memset*.S
77arch/*/include/asm/*features.h
70include/linux/poison.h 78include/linux/poison.h
71include/linux/hw_breakpoint.h 79include/linux/hw_breakpoint.h
72include/uapi/linux/perf_event.h 80include/uapi/linux/perf_event.h
diff --git a/tools/perf/Makefile b/tools/perf/Makefile
index 480546d5f13b..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) -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 0d19d5447d6c..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#
@@ -77,6 +80,9 @@ include config/utilities.mak
77# Define NO_AUXTRACE if you do not want AUX area tracing support 80# Define NO_AUXTRACE if you do not want AUX area tracing support
78# 81#
79# Define NO_LIBBPF if you do not want BPF support 82# Define NO_LIBBPF if you do not want BPF support
83#
84# Define FEATURES_DUMP to provide features detection dump file
85# and bypass the feature detection
80 86
81# As per kernel Makefile, avoid funny character set dependencies 87# As per kernel Makefile, avoid funny character set dependencies
82unexport LC_ALL 88unexport LC_ALL
@@ -133,6 +139,8 @@ $(call allow-override,CC,$(CROSS_COMPILE)gcc)
133$(call allow-override,AR,$(CROSS_COMPILE)ar) 139$(call allow-override,AR,$(CROSS_COMPILE)ar)
134$(call allow-override,LD,$(CROSS_COMPILE)ld) 140$(call allow-override,LD,$(CROSS_COMPILE)ld)
135 141
142LD += $(EXTRA_LDFLAGS)
143
136PKG_CONFIG = $(CROSS_COMPILE)pkg-config 144PKG_CONFIG = $(CROSS_COMPILE)pkg-config
137 145
138RM = rm -f 146RM = rm -f
@@ -145,9 +153,10 @@ BISON = bison
145STRIP = strip 153STRIP = strip
146AWK = awk 154AWK = awk
147 155
148LIB_DIR = $(srctree)/tools/lib/api/ 156LIB_DIR = $(srctree)/tools/lib/api/
149TRACE_EVENT_DIR = $(srctree)/tools/lib/traceevent/ 157TRACE_EVENT_DIR = $(srctree)/tools/lib/traceevent/
150BPF_DIR = $(srctree)/tools/lib/bpf/ 158BPF_DIR = $(srctree)/tools/lib/bpf/
159SUBCMD_DIR = $(srctree)/tools/lib/subcmd/
151 160
152# include config/Makefile by default and rule out 161# include config/Makefile by default and rule out
153# non-config cases 162# non-config cases
@@ -161,10 +170,28 @@ ifeq ($(filter-out $(NON_CONFIG_TARGETS),$(MAKECMDGOALS)),)
161endif 170endif
162endif 171endif
163 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.
164ifeq ($(config),1) 177ifeq ($(config),1)
178ifdef MAKECMDGOALS
179ifeq ($(filter feature-dump,$(MAKECMDGOALS)),feature-dump)
180FEATURE_TESTS := all
181endif
182endif
165include config/Makefile 183include config/Makefile
166endif 184endif
167 185
186# The FEATURE_DUMP_EXPORT holds location of the actual
187# FEATURE_DUMP file to be used to bypass feature detection
188# (for bpf or any other subproject)
189ifeq ($(FEATURES_DUMP),)
190FEATURE_DUMP_EXPORT := $(realpath $(OUTPUT)FEATURE-DUMP)
191else
192FEATURE_DUMP_EXPORT := $(FEATURES_DUMP)
193endif
194
168export prefix bindir sharedir sysconfdir DESTDIR 195export prefix bindir sharedir sysconfdir DESTDIR
169 196
170# sparse is architecture-neutral, which means that we need to tell it 197# sparse is architecture-neutral, which means that we need to tell it
@@ -184,15 +211,17 @@ strip-libs = $(filter-out -l%,$(1))
184ifneq ($(OUTPUT),) 211ifneq ($(OUTPUT),)
185 TE_PATH=$(OUTPUT) 212 TE_PATH=$(OUTPUT)
186 BPF_PATH=$(OUTPUT) 213 BPF_PATH=$(OUTPUT)
214 SUBCMD_PATH=$(OUTPUT)
187ifneq ($(subdir),) 215ifneq ($(subdir),)
188 LIB_PATH=$(OUTPUT)/../lib/api/ 216 API_PATH=$(OUTPUT)/../lib/api/
189else 217else
190 LIB_PATH=$(OUTPUT) 218 API_PATH=$(OUTPUT)
191endif 219endif
192else 220else
193 TE_PATH=$(TRACE_EVENT_DIR) 221 TE_PATH=$(TRACE_EVENT_DIR)
194 LIB_PATH=$(LIB_DIR) 222 API_PATH=$(LIB_DIR)
195 BPF_PATH=$(BPF_DIR) 223 BPF_PATH=$(BPF_DIR)
224 SUBCMD_PATH=$(SUBCMD_DIR)
196endif 225endif
197 226
198LIBTRACEEVENT = $(TE_PATH)libtraceevent.a 227LIBTRACEEVENT = $(TE_PATH)libtraceevent.a
@@ -201,11 +230,13 @@ export LIBTRACEEVENT
201LIBTRACEEVENT_DYNAMIC_LIST = $(TE_PATH)libtraceevent-dynamic-list 230LIBTRACEEVENT_DYNAMIC_LIST = $(TE_PATH)libtraceevent-dynamic-list
202LIBTRACEEVENT_DYNAMIC_LIST_LDFLAGS = -Xlinker --dynamic-list=$(LIBTRACEEVENT_DYNAMIC_LIST) 231LIBTRACEEVENT_DYNAMIC_LIST_LDFLAGS = -Xlinker --dynamic-list=$(LIBTRACEEVENT_DYNAMIC_LIST)
203 232
204LIBAPI = $(LIB_PATH)libapi.a 233LIBAPI = $(API_PATH)libapi.a
205export LIBAPI 234export LIBAPI
206 235
207LIBBPF = $(BPF_PATH)libbpf.a 236LIBBPF = $(BPF_PATH)libbpf.a
208 237
238LIBSUBCMD = $(SUBCMD_PATH)libsubcmd.a
239
209# python extension build directories 240# python extension build directories
210PYTHON_EXTBUILD := $(OUTPUT)python_ext_build/ 241PYTHON_EXTBUILD := $(OUTPUT)python_ext_build/
211PYTHON_EXTBUILD_LIB := $(PYTHON_EXTBUILD)lib/ 242PYTHON_EXTBUILD_LIB := $(PYTHON_EXTBUILD)lib/
@@ -257,7 +288,7 @@ export PERL_PATH
257 288
258LIB_FILE=$(OUTPUT)libperf.a 289LIB_FILE=$(OUTPUT)libperf.a
259 290
260PERFLIBS = $(LIB_FILE) $(LIBAPI) $(LIBTRACEEVENT) 291PERFLIBS = $(LIB_FILE) $(LIBAPI) $(LIBTRACEEVENT) $(LIBSUBCMD)
261ifndef NO_LIBBPF 292ifndef NO_LIBBPF
262 PERFLIBS += $(LIBBPF) 293 PERFLIBS += $(LIBBPF)
263endif 294endif
@@ -420,7 +451,7 @@ $(LIBTRACEEVENT)-clean:
420 $(call QUIET_CLEAN, libtraceevent) 451 $(call QUIET_CLEAN, libtraceevent)
421 $(Q)$(MAKE) -C $(TRACE_EVENT_DIR) O=$(OUTPUT) clean >/dev/null 452 $(Q)$(MAKE) -C $(TRACE_EVENT_DIR) O=$(OUTPUT) clean >/dev/null
422 453
423install-traceevent-plugins: $(LIBTRACEEVENT) 454install-traceevent-plugins: libtraceevent_plugins
424 $(Q)$(MAKE) -C $(TRACE_EVENT_DIR) $(LIBTRACEEVENT_FLAGS) O=$(OUTPUT) install_plugins 455 $(Q)$(MAKE) -C $(TRACE_EVENT_DIR) $(LIBTRACEEVENT_FLAGS) O=$(OUTPUT) install_plugins
425 456
426$(LIBAPI): fixdep FORCE 457$(LIBAPI): fixdep FORCE
@@ -431,12 +462,19 @@ $(LIBAPI)-clean:
431 $(Q)$(MAKE) -C $(LIB_DIR) O=$(OUTPUT) clean >/dev/null 462 $(Q)$(MAKE) -C $(LIB_DIR) O=$(OUTPUT) clean >/dev/null
432 463
433$(LIBBPF): fixdep FORCE 464$(LIBBPF): fixdep FORCE
434 $(Q)$(MAKE) -C $(BPF_DIR) O=$(OUTPUT) $(OUTPUT)libbpf.a 465 $(Q)$(MAKE) -C $(BPF_DIR) O=$(OUTPUT) $(OUTPUT)libbpf.a FEATURES_DUMP=$(FEATURE_DUMP_EXPORT)
435 466
436$(LIBBPF)-clean: 467$(LIBBPF)-clean:
437 $(call QUIET_CLEAN, libbpf) 468 $(call QUIET_CLEAN, libbpf)
438 $(Q)$(MAKE) -C $(BPF_DIR) O=$(OUTPUT) clean >/dev/null 469 $(Q)$(MAKE) -C $(BPF_DIR) O=$(OUTPUT) clean >/dev/null
439 470
471$(LIBSUBCMD): fixdep FORCE
472 $(Q)$(MAKE) -C $(SUBCMD_DIR) O=$(OUTPUT) $(OUTPUT)libsubcmd.a
473
474$(LIBSUBCMD)-clean:
475 $(call QUIET_CLEAN, libsubcmd)
476 $(Q)$(MAKE) -C $(SUBCMD_DIR) O=$(OUTPUT) clean
477
440help: 478help:
441 @echo 'Perf make targets:' 479 @echo 'Perf make targets:'
442 @echo ' doc - make *all* documentation (see below)' 480 @echo ' doc - make *all* documentation (see below)'
@@ -476,7 +514,7 @@ INSTALL_DOC_TARGETS += quick-install-doc quick-install-man quick-install-html
476$(DOC_TARGETS): 514$(DOC_TARGETS):
477 $(QUIET_SUBDIR0)Documentation $(QUIET_SUBDIR1) $(@:doc=all) 515 $(QUIET_SUBDIR0)Documentation $(QUIET_SUBDIR1) $(@:doc=all)
478 516
479TAG_FOLDERS= . ../lib/traceevent ../lib/api ../lib/symbol ../include ../lib/bpf 517TAG_FOLDERS= . ../lib ../include
480TAG_FILES= ../../include/uapi/linux/perf_event.h 518TAG_FILES= ../../include/uapi/linux/perf_event.h
481 519
482TAGS: 520TAGS:
@@ -555,6 +593,9 @@ endif
555 $(call QUIET_INSTALL, perf_completion-script) \ 593 $(call QUIET_INSTALL, perf_completion-script) \
556 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(sysconfdir_SQ)/bash_completion.d'; \ 594 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(sysconfdir_SQ)/bash_completion.d'; \
557 $(INSTALL) perf-completion.sh '$(DESTDIR_SQ)$(sysconfdir_SQ)/bash_completion.d/perf' 595 $(INSTALL) perf-completion.sh '$(DESTDIR_SQ)$(sysconfdir_SQ)/bash_completion.d/perf'
596 $(call QUIET_INSTALL, perf-tip) \
597 $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(tip_instdir_SQ)'; \
598 $(INSTALL) Documentation/tips.txt -t '$(DESTDIR_SQ)$(tip_instdir_SQ)'
558 599
559install-tests: all install-gtk 600install-tests: all install-gtk
560 $(call QUIET_INSTALL, tests) \ 601 $(call QUIET_INSTALL, tests) \
@@ -582,19 +623,31 @@ $(INSTALL_DOC_TARGETS):
582# 623#
583config-clean: 624config-clean:
584 $(call QUIET_CLEAN, config) 625 $(call QUIET_CLEAN, config)
585 $(Q)$(MAKE) -C $(srctree)/tools/build/feature/ clean >/dev/null 626 $(Q)$(MAKE) -C $(srctree)/tools/build/feature/ $(if $(OUTPUT),OUTPUT=$(OUTPUT)feature/,) clean >/dev/null
586 627
587clean: $(LIBTRACEEVENT)-clean $(LIBAPI)-clean $(LIBBPF)-clean config-clean 628clean: $(LIBTRACEEVENT)-clean $(LIBAPI)-clean $(LIBBPF)-clean $(LIBSUBCMD)-clean config-clean
588 $(call QUIET_CLEAN, core-objs) $(RM) $(LIB_FILE) $(OUTPUT)perf-archive $(OUTPUT)perf-with-kcore $(LANG_BINDINGS) 629 $(call QUIET_CLEAN, core-objs) $(RM) $(LIB_FILE) $(OUTPUT)perf-archive $(OUTPUT)perf-with-kcore $(LANG_BINDINGS)
589 $(Q)find . -name '*.o' -delete -o -name '\.*.cmd' -delete -o -name '\.*.d' -delete 630 $(Q)find $(if $(OUTPUT),$(OUTPUT),.) -name '*.o' -delete -o -name '\.*.cmd' -delete -o -name '\.*.d' -delete
590 $(Q)$(RM) $(OUTPUT).config-detected 631 $(Q)$(RM) $(OUTPUT).config-detected
591 $(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
592 $(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* \
593 $(OUTPUT)util/intel-pt-decoder/inat-tables.c 634 $(OUTPUT)util/intel-pt-decoder/inat-tables.c $(OUTPUT)fixdep \
635 $(OUTPUT)tests/llvm-src-{base,kbuild,prologue,relocation}.c
594 $(QUIET_SUBDIR0)Documentation $(QUIET_SUBDIR1) clean 636 $(QUIET_SUBDIR0)Documentation $(QUIET_SUBDIR1) clean
595 $(python-clean) 637 $(python-clean)
596 638
597# 639#
640# To provide FEATURE-DUMP into $(FEATURE_DUMP_COPY)
641# file if defined, with no further action.
642feature-dump:
643ifdef FEATURE_DUMP_COPY
644 @cp $(OUTPUT)FEATURE-DUMP $(FEATURE_DUMP_COPY)
645 @echo "FEATURE-DUMP file copied into $(FEATURE_DUMP_COPY)"
646else
647 @echo "FEATURE-DUMP file available in $(OUTPUT)FEATURE-DUMP"
648endif
649
650#
598# Trick: if ../../.git does not exist - we are building out of tree for example, 651# Trick: if ../../.git does not exist - we are building out of tree for example,
599# then force version regeneration: 652# then force version regeneration:
600# 653#
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/include/arch-tests.h b/tools/perf/arch/x86/include/arch-tests.h
index 7ed00f4b0908..b48de2f5813c 100644
--- a/tools/perf/arch/x86/include/arch-tests.h
+++ b/tools/perf/arch/x86/include/arch-tests.h
@@ -2,10 +2,10 @@
2#define ARCH_TESTS_H 2#define ARCH_TESTS_H
3 3
4/* Tests */ 4/* Tests */
5int test__rdpmc(void); 5int test__rdpmc(int subtest);
6int test__perf_time_to_tsc(void); 6int test__perf_time_to_tsc(int subtest);
7int test__insn_x86(void); 7int test__insn_x86(int subtest);
8int test__intel_cqm_count_nmi_context(void); 8int test__intel_cqm_count_nmi_context(int subtest);
9 9
10#ifdef HAVE_DWARF_UNWIND_SUPPORT 10#ifdef HAVE_DWARF_UNWIND_SUPPORT
11struct thread; 11struct thread;
diff --git a/tools/perf/arch/x86/tests/insn-x86.c b/tools/perf/arch/x86/tests/insn-x86.c
index b6115dfd28f0..08d9b2bc185c 100644
--- a/tools/perf/arch/x86/tests/insn-x86.c
+++ b/tools/perf/arch/x86/tests/insn-x86.c
@@ -171,7 +171,7 @@ static int test_data_set(struct test_data *dat_set, int x86_64)
171 * verbose (-v) option to see all the instructions and whether or not they 171 * verbose (-v) option to see all the instructions and whether or not they
172 * decoded successfuly. 172 * decoded successfuly.
173 */ 173 */
174int test__insn_x86(void) 174int test__insn_x86(int subtest __maybe_unused)
175{ 175{
176 int ret = 0; 176 int ret = 0;
177 177
diff --git a/tools/perf/arch/x86/tests/intel-cqm.c b/tools/perf/arch/x86/tests/intel-cqm.c
index d28c1b6a3b54..7f064eb37158 100644
--- a/tools/perf/arch/x86/tests/intel-cqm.c
+++ b/tools/perf/arch/x86/tests/intel-cqm.c
@@ -17,7 +17,7 @@ static pid_t spawn(void)
17 if (pid) 17 if (pid)
18 return pid; 18 return pid;
19 19
20 while(1); 20 while(1)
21 sleep(5); 21 sleep(5);
22 return 0; 22 return 0;
23} 23}
@@ -33,7 +33,7 @@ static pid_t spawn(void)
33 * the last read counter value to avoid triggering a WARN_ON_ONCE() in 33 * the last read counter value to avoid triggering a WARN_ON_ONCE() in
34 * smp_call_function_many() caused by sending IPIs from NMI context. 34 * smp_call_function_many() caused by sending IPIs from NMI context.
35 */ 35 */
36int test__intel_cqm_count_nmi_context(void) 36int test__intel_cqm_count_nmi_context(int subtest __maybe_unused)
37{ 37{
38 struct perf_evlist *evlist = NULL; 38 struct perf_evlist *evlist = NULL;
39 struct perf_evsel *evsel = NULL; 39 struct perf_evsel *evsel = NULL;
@@ -54,7 +54,7 @@ int test__intel_cqm_count_nmi_context(void)
54 54
55 ret = parse_events(evlist, "intel_cqm/llc_occupancy/", NULL); 55 ret = parse_events(evlist, "intel_cqm/llc_occupancy/", NULL);
56 if (ret) { 56 if (ret) {
57 pr_debug("parse_events failed\n"); 57 pr_debug("parse_events failed, is \"intel_cqm/llc_occupancy/\" available?\n");
58 err = TEST_SKIP; 58 err = TEST_SKIP;
59 goto out; 59 goto out;
60 } 60 }
diff --git a/tools/perf/arch/x86/tests/perf-time-to-tsc.c b/tools/perf/arch/x86/tests/perf-time-to-tsc.c
index 658cd200af74..9d29ee283ac5 100644
--- a/tools/perf/arch/x86/tests/perf-time-to-tsc.c
+++ b/tools/perf/arch/x86/tests/perf-time-to-tsc.c
@@ -35,13 +35,12 @@
35 * %0 is returned, otherwise %-1 is returned. If TSC conversion is not 35 * %0 is returned, otherwise %-1 is returned. If TSC conversion is not
36 * supported then then the test passes but " (not supported)" is printed. 36 * supported then then the test passes but " (not supported)" is printed.
37 */ 37 */
38int test__perf_time_to_tsc(void) 38int test__perf_time_to_tsc(int subtest __maybe_unused)
39{ 39{
40 struct record_opts opts = { 40 struct record_opts opts = {
41 .mmap_pages = UINT_MAX, 41 .mmap_pages = UINT_MAX,
42 .user_freq = UINT_MAX, 42 .user_freq = UINT_MAX,
43 .user_interval = ULLONG_MAX, 43 .user_interval = ULLONG_MAX,
44 .freq = 4000,
45 .target = { 44 .target = {
46 .uses_mmap = true, 45 .uses_mmap = true,
47 }, 46 },
diff --git a/tools/perf/arch/x86/tests/rdpmc.c b/tools/perf/arch/x86/tests/rdpmc.c
index e7688214c7cf..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,
@@ -149,7 +150,7 @@ out_close:
149 return 0; 150 return 0;
150} 151}
151 152
152int test__rdpmc(void) 153int test__rdpmc(int subtest __maybe_unused)
153{ 154{
154 int status = 0; 155 int status = 0;
155 int wret = 0; 156 int wret = 0;
diff --git a/tools/perf/arch/x86/util/Build b/tools/perf/arch/x86/util/Build
index ff63649fa9ac..465970370f3e 100644
--- a/tools/perf/arch/x86/util/Build
+++ b/tools/perf/arch/x86/util/Build
@@ -5,6 +5,7 @@ libperf-y += kvm-stat.o
5libperf-y += perf_regs.o 5libperf-y += perf_regs.o
6 6
7libperf-$(CONFIG_DWARF) += dwarf-regs.o 7libperf-$(CONFIG_DWARF) += dwarf-regs.o
8libperf-$(CONFIG_BPF_PROLOGUE) += dwarf-regs.o
8 9
9libperf-$(CONFIG_LIBUNWIND) += unwind-libunwind.o 10libperf-$(CONFIG_LIBUNWIND) += unwind-libunwind.o
10libperf-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw.o 11libperf-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw.o
diff --git a/tools/perf/arch/x86/util/intel-bts.c b/tools/perf/arch/x86/util/intel-bts.c
index 9b94ce520917..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}
@@ -327,7 +329,7 @@ static int intel_bts_snapshot_start(struct auxtrace_record *itr)
327 329
328 evlist__for_each(btsr->evlist, evsel) { 330 evlist__for_each(btsr->evlist, evsel) {
329 if (evsel->attr.type == btsr->intel_bts_pmu->type) 331 if (evsel->attr.type == btsr->intel_bts_pmu->type)
330 return perf_evlist__disable_event(btsr->evlist, evsel); 332 return perf_evsel__disable(evsel);
331 } 333 }
332 return -EINVAL; 334 return -EINVAL;
333} 335}
@@ -340,7 +342,7 @@ static int intel_bts_snapshot_finish(struct auxtrace_record *itr)
340 342
341 evlist__for_each(btsr->evlist, evsel) { 343 evlist__for_each(btsr->evlist, evsel) {
342 if (evsel->attr.type == btsr->intel_bts_pmu->type) 344 if (evsel->attr.type == btsr->intel_bts_pmu->type)
343 return perf_evlist__enable_event(btsr->evlist, evsel); 345 return perf_evsel__enable(evsel);
344 } 346 }
345 return -EINVAL; 347 return -EINVAL;
346} 348}
diff --git a/tools/perf/arch/x86/util/intel-pt.c b/tools/perf/arch/x86/util/intel-pt.c
index b02af064f0f9..a3395179c9ee 100644
--- a/tools/perf/arch/x86/util/intel-pt.c
+++ b/tools/perf/arch/x86/util/intel-pt.c
@@ -26,7 +26,7 @@
26#include "../../util/evlist.h" 26#include "../../util/evlist.h"
27#include "../../util/evsel.h" 27#include "../../util/evsel.h"
28#include "../../util/cpumap.h" 28#include "../../util/cpumap.h"
29#include "../../util/parse-options.h" 29#include <subcmd/parse-options.h>
30#include "../../util/parse-events.h" 30#include "../../util/parse-events.h"
31#include "../../util/pmu.h" 31#include "../../util/pmu.h"
32#include "../../util/debug.h" 32#include "../../util/debug.h"
@@ -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}
@@ -725,7 +727,7 @@ static int intel_pt_snapshot_start(struct auxtrace_record *itr)
725 727
726 evlist__for_each(ptr->evlist, evsel) { 728 evlist__for_each(ptr->evlist, evsel) {
727 if (evsel->attr.type == ptr->intel_pt_pmu->type) 729 if (evsel->attr.type == ptr->intel_pt_pmu->type)
728 return perf_evlist__disable_event(ptr->evlist, evsel); 730 return perf_evsel__disable(evsel);
729 } 731 }
730 return -EINVAL; 732 return -EINVAL;
731} 733}
@@ -738,7 +740,7 @@ static int intel_pt_snapshot_finish(struct auxtrace_record *itr)
738 740
739 evlist__for_each(ptr->evlist, evsel) { 741 evlist__for_each(ptr->evlist, evsel) {
740 if (evsel->attr.type == ptr->intel_pt_pmu->type) 742 if (evsel->attr.type == ptr->intel_pt_pmu->type)
741 return perf_evlist__enable_event(ptr->evlist, evsel); 743 return perf_evsel__enable(evsel);
742 } 744 }
743 return -EINVAL; 745 return -EINVAL;
744} 746}
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/futex-hash.c b/tools/perf/bench/futex-hash.c
index fc9bebd2cca0..0999ac536d86 100644
--- a/tools/perf/bench/futex-hash.c
+++ b/tools/perf/bench/futex-hash.c
@@ -11,7 +11,7 @@
11#include "../perf.h" 11#include "../perf.h"
12#include "../util/util.h" 12#include "../util/util.h"
13#include "../util/stat.h" 13#include "../util/stat.h"
14#include "../util/parse-options.h" 14#include <subcmd/parse-options.h>
15#include "../util/header.h" 15#include "../util/header.h"
16#include "bench.h" 16#include "bench.h"
17#include "futex.h" 17#include "futex.h"
diff --git a/tools/perf/bench/futex-lock-pi.c b/tools/perf/bench/futex-lock-pi.c
index bc6a16adbca8..6a18ce21f865 100644
--- a/tools/perf/bench/futex-lock-pi.c
+++ b/tools/perf/bench/futex-lock-pi.c
@@ -5,7 +5,7 @@
5#include "../perf.h" 5#include "../perf.h"
6#include "../util/util.h" 6#include "../util/util.h"
7#include "../util/stat.h" 7#include "../util/stat.h"
8#include "../util/parse-options.h" 8#include <subcmd/parse-options.h>
9#include "../util/header.h" 9#include "../util/header.h"
10#include "bench.h" 10#include "bench.h"
11#include "futex.h" 11#include "futex.h"
diff --git a/tools/perf/bench/futex-requeue.c b/tools/perf/bench/futex-requeue.c
index ad0d9b5342fb..718238683013 100644
--- a/tools/perf/bench/futex-requeue.c
+++ b/tools/perf/bench/futex-requeue.c
@@ -11,7 +11,7 @@
11#include "../perf.h" 11#include "../perf.h"
12#include "../util/util.h" 12#include "../util/util.h"
13#include "../util/stat.h" 13#include "../util/stat.h"
14#include "../util/parse-options.h" 14#include <subcmd/parse-options.h>
15#include "../util/header.h" 15#include "../util/header.h"
16#include "bench.h" 16#include "bench.h"
17#include "futex.h" 17#include "futex.h"
diff --git a/tools/perf/bench/futex-wake-parallel.c b/tools/perf/bench/futex-wake-parallel.c
index 6d8c9fa2a16c..91aaf2a1fa90 100644
--- a/tools/perf/bench/futex-wake-parallel.c
+++ b/tools/perf/bench/futex-wake-parallel.c
@@ -10,7 +10,7 @@
10#include "../perf.h" 10#include "../perf.h"
11#include "../util/util.h" 11#include "../util/util.h"
12#include "../util/stat.h" 12#include "../util/stat.h"
13#include "../util/parse-options.h" 13#include <subcmd/parse-options.h>
14#include "../util/header.h" 14#include "../util/header.h"
15#include "bench.h" 15#include "bench.h"
16#include "futex.h" 16#include "futex.h"
diff --git a/tools/perf/bench/futex-wake.c b/tools/perf/bench/futex-wake.c
index e5e41d3bdce7..f416bd705f66 100644
--- a/tools/perf/bench/futex-wake.c
+++ b/tools/perf/bench/futex-wake.c
@@ -11,7 +11,7 @@
11#include "../perf.h" 11#include "../perf.h"
12#include "../util/util.h" 12#include "../util/util.h"
13#include "../util/stat.h" 13#include "../util/stat.h"
14#include "../util/parse-options.h" 14#include <subcmd/parse-options.h>
15#include "../util/header.h" 15#include "../util/header.h"
16#include "bench.h" 16#include "bench.h"
17#include "futex.h" 17#include "futex.h"
diff --git a/tools/perf/bench/mem-functions.c b/tools/perf/bench/mem-functions.c
index 9419b944220f..a91aa85d80ff 100644
--- a/tools/perf/bench/mem-functions.c
+++ b/tools/perf/bench/mem-functions.c
@@ -8,7 +8,7 @@
8 8
9#include "../perf.h" 9#include "../perf.h"
10#include "../util/util.h" 10#include "../util/util.h"
11#include "../util/parse-options.h" 11#include <subcmd/parse-options.h>
12#include "../util/header.h" 12#include "../util/header.h"
13#include "../util/cloexec.h" 13#include "../util/cloexec.h"
14#include "bench.h" 14#include "bench.h"
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 492df2752a2d..7500d959d7eb 100644
--- a/tools/perf/bench/numa.c
+++ b/tools/perf/bench/numa.c
@@ -7,7 +7,7 @@
7#include "../perf.h" 7#include "../perf.h"
8#include "../builtin.h" 8#include "../builtin.h"
9#include "../util/util.h" 9#include "../util/util.h"
10#include "../util/parse-options.h" 10#include <subcmd/parse-options.h>
11#include "../util/cloexec.h" 11#include "../util/cloexec.h"
12 12
13#include "bench.h" 13#include "bench.h"
@@ -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/bench/sched-messaging.c b/tools/perf/bench/sched-messaging.c
index d4ff1b539cfd..bfaf9503de8e 100644
--- a/tools/perf/bench/sched-messaging.c
+++ b/tools/perf/bench/sched-messaging.c
@@ -11,7 +11,7 @@
11 11
12#include "../perf.h" 12#include "../perf.h"
13#include "../util/util.h" 13#include "../util/util.h"
14#include "../util/parse-options.h" 14#include <subcmd/parse-options.h>
15#include "../builtin.h" 15#include "../builtin.h"
16#include "bench.h" 16#include "bench.h"
17 17
diff --git a/tools/perf/bench/sched-pipe.c b/tools/perf/bench/sched-pipe.c
index 005cc283790c..1dc2d13cc272 100644
--- a/tools/perf/bench/sched-pipe.c
+++ b/tools/perf/bench/sched-pipe.c
@@ -10,7 +10,7 @@
10 */ 10 */
11#include "../perf.h" 11#include "../perf.h"
12#include "../util/util.h" 12#include "../util/util.h"
13#include "../util/parse-options.h" 13#include <subcmd/parse-options.h>
14#include "../builtin.h" 14#include "../builtin.h"
15#include "bench.h" 15#include "bench.h"
16 16
diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c
index 2bf9b3fd9e61..814158393656 100644
--- a/tools/perf/builtin-annotate.c
+++ b/tools/perf/builtin-annotate.c
@@ -21,7 +21,7 @@
21#include "util/evsel.h" 21#include "util/evsel.h"
22#include "util/annotate.h" 22#include "util/annotate.h"
23#include "util/event.h" 23#include "util/event.h"
24#include "util/parse-options.h" 24#include <subcmd/parse-options.h>
25#include "util/parse-events.h" 25#include "util/parse-events.h"
26#include "util/thread.h" 26#include "util/thread.h"
27#include "util/sort.h" 27#include "util/sort.h"
@@ -47,7 +47,7 @@ struct perf_annotate {
47}; 47};
48 48
49static int perf_evsel__add_sample(struct perf_evsel *evsel, 49static int perf_evsel__add_sample(struct perf_evsel *evsel,
50 struct perf_sample *sample __maybe_unused, 50 struct perf_sample *sample,
51 struct addr_location *al, 51 struct addr_location *al,
52 struct perf_annotate *ann) 52 struct perf_annotate *ann)
53{ 53{
@@ -72,7 +72,10 @@ static int perf_evsel__add_sample(struct perf_evsel *evsel,
72 return 0; 72 return 0;
73 } 73 }
74 74
75 he = __hists__add_entry(hists, al, NULL, NULL, NULL, 1, 1, 0, true); 75 sample->period = 1;
76 sample->weight = 1;
77
78 he = __hists__add_entry(hists, al, NULL, NULL, NULL, sample, true);
76 if (he == NULL) 79 if (he == NULL)
77 return -ENOMEM; 80 return -ENOMEM;
78 81
@@ -91,7 +94,7 @@ static int process_sample_event(struct perf_tool *tool,
91 struct addr_location al; 94 struct addr_location al;
92 int ret = 0; 95 int ret = 0;
93 96
94 if (perf_event__preprocess_sample(event, machine, &al, sample) < 0) { 97 if (machine__resolve(machine, &al, sample) < 0) {
95 pr_warning("problem processing %d event, skipping it.\n", 98 pr_warning("problem processing %d event, skipping it.\n",
96 event->header.type); 99 event->header.type);
97 return -1; 100 return -1;
@@ -242,7 +245,7 @@ static int __cmd_annotate(struct perf_annotate *ann)
242 hists__collapse_resort(hists, NULL); 245 hists__collapse_resort(hists, NULL);
243 /* Don't sort callchain */ 246 /* Don't sort callchain */
244 perf_evsel__reset_sample_bit(pos, CALLCHAIN); 247 perf_evsel__reset_sample_bit(pos, CALLCHAIN);
245 hists__output_resort(hists, NULL); 248 perf_evsel__output_resort(pos, NULL);
246 249
247 if (symbol_conf.event_group && 250 if (symbol_conf.event_group &&
248 !perf_evsel__is_group_leader(pos)) 251 !perf_evsel__is_group_leader(pos))
@@ -343,18 +346,19 @@ int cmd_annotate(int argc, const char **argv, const char *prefix __maybe_unused)
343 return ret; 346 return ret;
344 347
345 argc = parse_options(argc, argv, options, annotate_usage, 0); 348 argc = parse_options(argc, argv, options, annotate_usage, 0);
349 if (argc) {
350 /*
351 * Special case: if there's an argument left then assume that
352 * it's a symbol filter:
353 */
354 if (argc > 1)
355 usage_with_options(annotate_usage, options);
346 356
347 if (annotate.use_stdio) 357 annotate.sym_hist_filter = argv[0];
348 use_browser = 0; 358 }
349 else if (annotate.use_tui)
350 use_browser = 1;
351 else if (annotate.use_gtk)
352 use_browser = 2;
353 359
354 file.path = input_name; 360 file.path = input_name;
355 361
356 setup_browser(true);
357
358 annotate.session = perf_session__new(&file, false, &annotate.tool); 362 annotate.session = perf_session__new(&file, false, &annotate.tool);
359 if (annotate.session == NULL) 363 if (annotate.session == NULL)
360 return -1; 364 return -1;
@@ -366,19 +370,17 @@ int cmd_annotate(int argc, const char **argv, const char *prefix __maybe_unused)
366 if (ret < 0) 370 if (ret < 0)
367 goto out_delete; 371 goto out_delete;
368 372
369 if (setup_sorting() < 0) 373 if (setup_sorting(NULL) < 0)
370 usage_with_options(annotate_usage, options); 374 usage_with_options(annotate_usage, options);
371 375
372 if (argc) { 376 if (annotate.use_stdio)
373 /* 377 use_browser = 0;
374 * Special case: if there's an argument left then assume that 378 else if (annotate.use_tui)
375 * it's a symbol filter: 379 use_browser = 1;
376 */ 380 else if (annotate.use_gtk)
377 if (argc > 1) 381 use_browser = 2;
378 usage_with_options(annotate_usage, options);
379 382
380 annotate.sym_hist_filter = argv[0]; 383 setup_browser(true);
381 }
382 384
383 ret = __cmd_annotate(&annotate); 385 ret = __cmd_annotate(&annotate);
384 386
diff --git a/tools/perf/builtin-bench.c b/tools/perf/builtin-bench.c
index b17aed36ca16..a1cddc6bbf0f 100644
--- a/tools/perf/builtin-bench.c
+++ b/tools/perf/builtin-bench.c
@@ -16,7 +16,7 @@
16 */ 16 */
17#include "perf.h" 17#include "perf.h"
18#include "util/util.h" 18#include "util/util.h"
19#include "util/parse-options.h" 19#include <subcmd/parse-options.h>
20#include "builtin.h" 20#include "builtin.h"
21#include "bench/bench.h" 21#include "bench/bench.h"
22 22
diff --git a/tools/perf/builtin-buildid-cache.c b/tools/perf/builtin-buildid-cache.c
index 7b8450cd33c2..632efc6b79a0 100644
--- a/tools/perf/builtin-buildid-cache.c
+++ b/tools/perf/builtin-buildid-cache.c
@@ -16,7 +16,7 @@
16#include "util/cache.h" 16#include "util/cache.h"
17#include "util/debug.h" 17#include "util/debug.h"
18#include "util/header.h" 18#include "util/header.h"
19#include "util/parse-options.h" 19#include <subcmd/parse-options.h>
20#include "util/strlist.h" 20#include "util/strlist.h"
21#include "util/build-id.h" 21#include "util/build-id.h"
22#include "util/session.h" 22#include "util/session.h"
@@ -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-buildid-list.c b/tools/perf/builtin-buildid-list.c
index 918b4de29de4..5e914ee79eb3 100644
--- a/tools/perf/builtin-buildid-list.c
+++ b/tools/perf/builtin-buildid-list.c
@@ -12,7 +12,7 @@
12#include "util/build-id.h" 12#include "util/build-id.h"
13#include "util/cache.h" 13#include "util/cache.h"
14#include "util/debug.h" 14#include "util/debug.h"
15#include "util/parse-options.h" 15#include <subcmd/parse-options.h>
16#include "util/session.h" 16#include "util/session.h"
17#include "util/symbol.h" 17#include "util/symbol.h"
18#include "util/data.h" 18#include "util/data.h"
@@ -110,7 +110,7 @@ int cmd_buildid_list(int argc, const char **argv,
110 setup_pager(); 110 setup_pager();
111 111
112 if (show_kernel) 112 if (show_kernel)
113 return sysfs__fprintf_build_id(stdout); 113 return !(sysfs__fprintf_build_id(stdout) > 0);
114 114
115 return perf_session__list_build_ids(force, with_hits); 115 return perf_session__list_build_ids(force, with_hits);
116} 116}
diff --git a/tools/perf/builtin-config.c b/tools/perf/builtin-config.c
new file mode 100644
index 000000000000..c42448ed5dfe
--- /dev/null
+++ b/tools/perf/builtin-config.c
@@ -0,0 +1,87 @@
1/*
2 * builtin-config.c
3 *
4 * Copyright (C) 2015, Taeung Song <treeze.taeung@gmail.com>
5 *
6 */
7#include "builtin.h"
8
9#include "perf.h"
10
11#include "util/cache.h"
12#include <subcmd/parse-options.h>
13#include "util/util.h"
14#include "util/debug.h"
15
16static bool use_system_config, use_user_config;
17
18static const char * const config_usage[] = {
19 "perf config [<file-option>] [options]",
20 NULL
21};
22
23enum actions {
24 ACTION_LIST = 1
25} actions;
26
27static struct option config_options[] = {
28 OPT_SET_UINT('l', "list", &actions,
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"),
32 OPT_END()
33};
34
35static int show_config(const char *key, const char *value,
36 void *cb __maybe_unused)
37{
38 if (value)
39 printf("%s=%s\n", key, value);
40 else
41 printf("%s\n", key);
42
43 return 0;
44}
45
46int cmd_config(int argc, const char **argv, const char *prefix __maybe_unused)
47{
48 int ret = 0;
49 char *user_config = mkpath("%s/.perfconfig", getenv("HOME"));
50
51 argc = parse_options(argc, argv, config_options, config_usage,
52 PARSE_OPT_STOP_AT_NON_OPTION);
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
66 switch (actions) {
67 case ACTION_LIST:
68 if (argc) {
69 pr_err("Error: takes no arguments\n");
70 parse_options_usage(config_usage, config_options, "l", 1);
71 } else {
72 ret = perf_config(show_config, NULL);
73 if (ret < 0) {
74 const char * config_filename = config_exclusive_filename;
75 if (!config_exclusive_filename)
76 config_filename = user_config;
77 pr_err("Nothing configured, "
78 "please check your %s \n", config_filename);
79 }
80 }
81 break;
82 default:
83 usage_with_options(config_usage, config_options);
84 }
85
86 return ret;
87}
diff --git a/tools/perf/builtin-data.c b/tools/perf/builtin-data.c
index d6525bc54d13..b97bc1518b44 100644
--- a/tools/perf/builtin-data.c
+++ b/tools/perf/builtin-data.c
@@ -2,7 +2,7 @@
2#include "builtin.h" 2#include "builtin.h"
3#include "perf.h" 3#include "perf.h"
4#include "debug.h" 4#include "debug.h"
5#include "parse-options.h" 5#include <subcmd/parse-options.h>
6#include "data-convert-bt.h" 6#include "data-convert-bt.h"
7 7
8typedef int (*data_cmd_fn_t)(int argc, const char **argv, const char *prefix); 8typedef int (*data_cmd_fn_t)(int argc, const char **argv, const char *prefix);
diff --git a/tools/perf/builtin-diff.c b/tools/perf/builtin-diff.c
index 0b180a885ba3..8053a8ceefda 100644
--- a/tools/perf/builtin-diff.c
+++ b/tools/perf/builtin-diff.c
@@ -311,11 +311,11 @@ static int formula_fprintf(struct hist_entry *he, struct hist_entry *pair,
311} 311}
312 312
313static int hists__add_entry(struct hists *hists, 313static int hists__add_entry(struct hists *hists,
314 struct addr_location *al, u64 period, 314 struct addr_location *al,
315 u64 weight, u64 transaction) 315 struct perf_sample *sample)
316{ 316{
317 if (__hists__add_entry(hists, al, NULL, NULL, NULL, period, weight, 317 if (__hists__add_entry(hists, al, NULL, NULL, NULL,
318 transaction, true) != NULL) 318 sample, true) != NULL)
319 return 0; 319 return 0;
320 return -ENOMEM; 320 return -ENOMEM;
321} 321}
@@ -330,14 +330,13 @@ 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;
337 } 337 }
338 338
339 if (hists__add_entry(hists, &al, sample->period, 339 if (hists__add_entry(hists, &al, sample)) {
340 sample->weight, sample->transaction)) {
341 pr_warning("problem incrementing symbol period, skipping event\n"); 340 pr_warning("problem incrementing symbol period, skipping event\n");
342 goto out_put; 341 goto out_put;
343 } 342 }
@@ -1208,7 +1207,7 @@ static int ui_init(void)
1208 BUG_ON(1); 1207 BUG_ON(1);
1209 } 1208 }
1210 1209
1211 list_add(&fmt->sort_list, &perf_hpp__sort_list); 1210 perf_hpp__register_sort_field(fmt);
1212 return 0; 1211 return 0;
1213} 1212}
1214 1213
@@ -1265,8 +1264,6 @@ int cmd_diff(int argc, const char **argv, const char *prefix __maybe_unused)
1265 if (ret < 0) 1264 if (ret < 0)
1266 return ret; 1265 return ret;
1267 1266
1268 perf_config(perf_default_config, NULL);
1269
1270 argc = parse_options(argc, argv, options, diff_usage, 0); 1267 argc = parse_options(argc, argv, options, diff_usage, 0);
1271 1268
1272 if (symbol__init(NULL) < 0) 1269 if (symbol__init(NULL) < 0)
@@ -1280,7 +1277,7 @@ int cmd_diff(int argc, const char **argv, const char *prefix __maybe_unused)
1280 1277
1281 sort__mode = SORT_MODE__DIFF; 1278 sort__mode = SORT_MODE__DIFF;
1282 1279
1283 if (setup_sorting() < 0) 1280 if (setup_sorting(NULL) < 0)
1284 usage_with_options(diff_usage, options); 1281 usage_with_options(diff_usage, options);
1285 1282
1286 setup_pager(); 1283 setup_pager();
diff --git a/tools/perf/builtin-evlist.c b/tools/perf/builtin-evlist.c
index f4d62510acbb..8a31f511e1a0 100644
--- a/tools/perf/builtin-evlist.c
+++ b/tools/perf/builtin-evlist.c
@@ -12,7 +12,7 @@
12#include "util/evlist.h" 12#include "util/evlist.h"
13#include "util/evsel.h" 13#include "util/evsel.h"
14#include "util/parse-events.h" 14#include "util/parse-events.h"
15#include "util/parse-options.h" 15#include <subcmd/parse-options.h>
16#include "util/session.h" 16#include "util/session.h"
17#include "util/data.h" 17#include "util/data.h"
18#include "util/debug.h" 18#include "util/debug.h"
@@ -26,14 +26,22 @@ static int __cmd_evlist(const char *file_name, struct perf_attr_details *details
26 .mode = PERF_DATA_MODE_READ, 26 .mode = PERF_DATA_MODE_READ,
27 .force = details->force, 27 .force = details->force,
28 }; 28 };
29 bool has_tracepoint = false;
29 30
30 session = perf_session__new(&file, 0, NULL); 31 session = perf_session__new(&file, 0, NULL);
31 if (session == NULL) 32 if (session == NULL)
32 return -1; 33 return -1;
33 34
34 evlist__for_each(session->evlist, pos) 35 evlist__for_each(session->evlist, pos) {
35 perf_evsel__fprintf(pos, details, stdout); 36 perf_evsel__fprintf(pos, details, stdout);
36 37
38 if (pos->attr.type == PERF_TYPE_TRACEPOINT)
39 has_tracepoint = true;
40 }
41
42 if (has_tracepoint && !details->trace_fields)
43 printf("# Tip: use 'perf evlist --trace-fields' to show fields for tracepoint events\n");
44
37 perf_session__delete(session); 45 perf_session__delete(session);
38 return 0; 46 return 0;
39} 47}
@@ -49,6 +57,7 @@ int cmd_evlist(int argc, const char **argv, const char *prefix __maybe_unused)
49 OPT_BOOLEAN('g', "group", &details.event_group, 57 OPT_BOOLEAN('g', "group", &details.event_group,
50 "Show event group information"), 58 "Show event group information"),
51 OPT_BOOLEAN('f', "force", &details.force, "don't complain, do it"), 59 OPT_BOOLEAN('f', "force", &details.force, "don't complain, do it"),
60 OPT_BOOLEAN(0, "trace-fields", &details.trace_fields, "Show tracepoint fields"),
52 OPT_END() 61 OPT_END()
53 }; 62 };
54 const char * const evlist_usage[] = { 63 const char * const evlist_usage[] = {
diff --git a/tools/perf/builtin-help.c b/tools/perf/builtin-help.c
index a7d588bf3cdd..bc1de9b8fd67 100644
--- a/tools/perf/builtin-help.c
+++ b/tools/perf/builtin-help.c
@@ -6,11 +6,11 @@
6#include "perf.h" 6#include "perf.h"
7#include "util/cache.h" 7#include "util/cache.h"
8#include "builtin.h" 8#include "builtin.h"
9#include "util/exec_cmd.h" 9#include <subcmd/exec-cmd.h>
10#include "common-cmds.h" 10#include "common-cmds.h"
11#include "util/parse-options.h" 11#include <subcmd/parse-options.h>
12#include "util/run-command.h" 12#include <subcmd/run-command.h>
13#include "util/help.h" 13#include <subcmd/help.h>
14#include "util/debug.h" 14#include "util/debug.h"
15 15
16static struct man_viewer_list { 16static struct man_viewer_list {
@@ -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/*
@@ -407,19 +399,19 @@ static int get_html_page_path(struct strbuf *page_path, const char *page)
407#ifndef open_html 399#ifndef open_html
408static void open_html(const char *path) 400static void open_html(const char *path)
409{ 401{
410 execl_perf_cmd("web--browse", "-c", "help.browser", path, NULL); 402 execl_cmd("web--browse", "-c", "help.browser", path, NULL);
411} 403}
412#endif 404#endif
413 405
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 0a945d2e8ca5..d1a2d104f2bc 100644
--- a/tools/perf/builtin-inject.c
+++ b/tools/perf/builtin-inject.c
@@ -17,8 +17,9 @@
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 "util/parse-options.h" 22#include <subcmd/parse-options.h>
22 23
23#include <linux/list.h> 24#include <linux/list.h>
24 25
@@ -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
@@ -675,6 +736,7 @@ int cmd_inject(int argc, const char **argv, const char *prefix __maybe_unused)
675 .fork = perf_event__repipe, 736 .fork = perf_event__repipe,
676 .exit = perf_event__repipe, 737 .exit = perf_event__repipe,
677 .lost = perf_event__repipe, 738 .lost = perf_event__repipe,
739 .lost_samples = perf_event__repipe,
678 .aux = perf_event__repipe, 740 .aux = perf_event__repipe,
679 .itrace_start = perf_event__repipe, 741 .itrace_start = perf_event__repipe,
680 .context_switch = perf_event__repipe, 742 .context_switch = perf_event__repipe,
@@ -702,7 +764,7 @@ int cmd_inject(int argc, const char **argv, const char *prefix __maybe_unused)
702 }; 764 };
703 int ret; 765 int ret;
704 766
705 const struct option options[] = { 767 struct option options[] = {
706 OPT_BOOLEAN('b', "build-ids", &inject.build_ids, 768 OPT_BOOLEAN('b', "build-ids", &inject.build_ids,
707 "Inject build-ids into the output stream"), 769 "Inject build-ids into the output stream"),
708 OPT_STRING('i', "input", &inject.input_name, "file", 770 OPT_STRING('i', "input", &inject.input_name, "file",
@@ -712,6 +774,9 @@ int cmd_inject(int argc, const char **argv, const char *prefix __maybe_unused)
712 OPT_BOOLEAN('s', "sched-stat", &inject.sched_stat, 774 OPT_BOOLEAN('s', "sched-stat", &inject.sched_stat,
713 "Merge sched-stat and sched-switch for getting events " 775 "Merge sched-stat and sched-switch for getting events "
714 "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
715 OPT_INCR('v', "verbose", &verbose, 780 OPT_INCR('v', "verbose", &verbose,
716 "be more verbose (show build ids, etc)"), 781 "be more verbose (show build ids, etc)"),
717 OPT_STRING(0, "kallsyms", &symbol_conf.kallsyms_name, "file", 782 OPT_STRING(0, "kallsyms", &symbol_conf.kallsyms_name, "file",
@@ -728,7 +793,9 @@ int cmd_inject(int argc, const char **argv, const char *prefix __maybe_unused)
728 "perf inject [<options>]", 793 "perf inject [<options>]",
729 NULL 794 NULL
730 }; 795 };
731 796#ifndef HAVE_JITDUMP
797 set_option_nobuild(options, 'j', "jit", "NO_LIBELF=1", true);
798#endif
732 argc = parse_options(argc, argv, options, inject_usage, 0); 799 argc = parse_options(argc, argv, options, inject_usage, 0);
733 800
734 /* 801 /*
@@ -754,6 +821,29 @@ int cmd_inject(int argc, const char **argv, const char *prefix __maybe_unused)
754 if (inject.session == NULL) 821 if (inject.session == NULL)
755 return -1; 822 return -1;
756 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
757 ret = symbol__init(&inject.session->header.env); 847 ret = symbol__init(&inject.session->header.env);
758 if (ret < 0) 848 if (ret < 0)
759 goto out_delete; 849 goto out_delete;
diff --git a/tools/perf/builtin-kmem.c b/tools/perf/builtin-kmem.c
index 93ce665f976f..c9cb3be47cff 100644
--- a/tools/perf/builtin-kmem.c
+++ b/tools/perf/builtin-kmem.c
@@ -12,7 +12,7 @@
12#include "util/tool.h" 12#include "util/tool.h"
13#include "util/callchain.h" 13#include "util/callchain.h"
14 14
15#include "util/parse-options.h" 15#include <subcmd/parse-options.h>
16#include "util/trace-event.h" 16#include "util/trace-event.h"
17#include "util/data.h" 17#include "util/data.h"
18#include "util/cpumap.h" 18#include "util/cpumap.h"
@@ -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 dd94b4ca2213..bff666458b28 100644
--- a/tools/perf/builtin-kvm.c
+++ b/tools/perf/builtin-kvm.c
@@ -10,7 +10,7 @@
10#include "util/header.h" 10#include "util/header.h"
11#include "util/session.h" 11#include "util/session.h"
12#include "util/intlist.h" 12#include "util/intlist.h"
13#include "util/parse-options.h" 13#include <subcmd/parse-options.h>
14#include "util/trace-event.h" 14#include "util/trace-event.h"
15#include "util/debug.h" 15#include "util/debug.h"
16#include "util/tool.h" 16#include "util/tool.h"
@@ -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++;
@@ -1351,7 +1363,6 @@ static int kvm_events_live(struct perf_kvm_stat *kvm,
1351 disable_buildid_cache(); 1363 disable_buildid_cache();
1352 1364
1353 use_browser = 0; 1365 use_browser = 0;
1354 setup_browser(false);
1355 1366
1356 if (argc) { 1367 if (argc) {
1357 argc = parse_options(argc, argv, live_options, 1368 argc = parse_options(argc, argv, live_options,
@@ -1378,6 +1389,12 @@ static int kvm_events_live(struct perf_kvm_stat *kvm,
1378 /* 1389 /*
1379 * generate the event list 1390 * generate the event list
1380 */ 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
1381 kvm->evlist = kvm_live_event_list(); 1398 kvm->evlist = kvm_live_event_list();
1382 if (kvm->evlist == NULL) { 1399 if (kvm->evlist == NULL) {
1383 err = -1; 1400 err = -1;
@@ -1409,8 +1426,6 @@ static int kvm_events_live(struct perf_kvm_stat *kvm,
1409 err = kvm_events_live_report(kvm); 1426 err = kvm_events_live_report(kvm);
1410 1427
1411out: 1428out:
1412 exit_browser(0);
1413
1414 if (kvm->session) 1429 if (kvm->session)
1415 perf_session__delete(kvm->session); 1430 perf_session__delete(kvm->session);
1416 kvm->session = NULL; 1431 kvm->session = NULL;
diff --git a/tools/perf/builtin-list.c b/tools/perf/builtin-list.c
index bf679e2c978b..5e22db4684b8 100644
--- a/tools/perf/builtin-list.c
+++ b/tools/perf/builtin-list.c
@@ -14,7 +14,7 @@
14#include "util/parse-events.h" 14#include "util/parse-events.h"
15#include "util/cache.h" 15#include "util/cache.h"
16#include "util/pmu.h" 16#include "util/pmu.h"
17#include "util/parse-options.h" 17#include <subcmd/parse-options.h>
18 18
19int cmd_list(int argc, const char **argv, const char *prefix __maybe_unused) 19int cmd_list(int argc, const char **argv, const char *prefix __maybe_unused)
20{ 20{
diff --git a/tools/perf/builtin-lock.c b/tools/perf/builtin-lock.c
index de16aaed516e..ce3bfb48b26f 100644
--- a/tools/perf/builtin-lock.c
+++ b/tools/perf/builtin-lock.c
@@ -9,7 +9,7 @@
9#include "util/thread.h" 9#include "util/thread.h"
10#include "util/header.h" 10#include "util/header.h"
11 11
12#include "util/parse-options.h" 12#include <subcmd/parse-options.h>
13#include "util/trace-event.h" 13#include "util/trace-event.h"
14 14
15#include "util/debug.h" 15#include "util/debug.h"
diff --git a/tools/perf/builtin-mem.c b/tools/perf/builtin-mem.c
index 80170aace5d4..85db3be4b3cb 100644
--- a/tools/perf/builtin-mem.c
+++ b/tools/perf/builtin-mem.c
@@ -1,11 +1,13 @@
1#include "builtin.h" 1#include "builtin.h"
2#include "perf.h" 2#include "perf.h"
3 3
4#include "util/parse-options.h" 4#include <subcmd/parse-options.h>
5#include "util/trace-event.h" 5#include "util/trace-event.h"
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-probe.c b/tools/perf/builtin-probe.c
index 132afc97676c..9af859b28b15 100644
--- a/tools/perf/builtin-probe.c
+++ b/tools/perf/builtin-probe.c
@@ -37,7 +37,7 @@
37#include "util/strfilter.h" 37#include "util/strfilter.h"
38#include "util/symbol.h" 38#include "util/symbol.h"
39#include "util/debug.h" 39#include "util/debug.h"
40#include "util/parse-options.h" 40#include <subcmd/parse-options.h>
41#include "util/probe-finder.h" 41#include "util/probe-finder.h"
42#include "util/probe-event.h" 42#include "util/probe-event.h"
43#include "util/probe-file.h" 43#include "util/probe-file.h"
@@ -249,6 +249,9 @@ static int opt_show_vars(const struct option *opt,
249 249
250 return ret; 250 return ret;
251} 251}
252#else
253# define opt_show_lines NULL
254# define opt_show_vars NULL
252#endif 255#endif
253static int opt_add_probe_event(const struct option *opt, 256static int opt_add_probe_event(const struct option *opt,
254 const char *str, int unset __maybe_unused) 257 const char *str, int unset __maybe_unused)
@@ -473,7 +476,6 @@ __cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused)
473 opt_add_probe_event), 476 opt_add_probe_event),
474 OPT_BOOLEAN('f', "force", &probe_conf.force_add, "forcibly add events" 477 OPT_BOOLEAN('f', "force", &probe_conf.force_add, "forcibly add events"
475 " with existing name"), 478 " with existing name"),
476#ifdef HAVE_DWARF_SUPPORT
477 OPT_CALLBACK('L', "line", NULL, 479 OPT_CALLBACK('L', "line", NULL,
478 "FUNC[:RLN[+NUM|-RLN2]]|SRC:ALN[+NUM|-ALN2]", 480 "FUNC[:RLN[+NUM|-RLN2]]|SRC:ALN[+NUM|-ALN2]",
479 "Show source code lines.", opt_show_lines), 481 "Show source code lines.", opt_show_lines),
@@ -490,7 +492,6 @@ __cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused)
490 "directory", "path to kernel source"), 492 "directory", "path to kernel source"),
491 OPT_BOOLEAN('\0', "no-inlines", &probe_conf.no_inlines, 493 OPT_BOOLEAN('\0', "no-inlines", &probe_conf.no_inlines,
492 "Don't search inlined functions"), 494 "Don't search inlined functions"),
493#endif
494 OPT__DRY_RUN(&probe_event_dry_run), 495 OPT__DRY_RUN(&probe_event_dry_run),
495 OPT_INTEGER('\0', "max-probes", &probe_conf.max_probes, 496 OPT_INTEGER('\0', "max-probes", &probe_conf.max_probes,
496 "Set how many probe points can be found for a probe."), 497 "Set how many probe points can be found for a probe."),
@@ -521,6 +522,16 @@ __cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused)
521#ifdef HAVE_DWARF_SUPPORT 522#ifdef HAVE_DWARF_SUPPORT
522 set_option_flag(options, 'L', "line", PARSE_OPT_EXCLUSIVE); 523 set_option_flag(options, 'L', "line", PARSE_OPT_EXCLUSIVE);
523 set_option_flag(options, 'V', "vars", PARSE_OPT_EXCLUSIVE); 524 set_option_flag(options, 'V', "vars", PARSE_OPT_EXCLUSIVE);
525#else
526# define set_nobuild(s, l, c) set_option_nobuild(options, s, l, "NO_DWARF=1", c)
527 set_nobuild('L', "line", false);
528 set_nobuild('V', "vars", false);
529 set_nobuild('\0', "externs", false);
530 set_nobuild('\0', "range", false);
531 set_nobuild('k', "vmlinux", true);
532 set_nobuild('s', "source", true);
533 set_nobuild('\0', "no-inlines", true);
534# undef set_nobuild
524#endif 535#endif
525 set_option_flag(options, 'F', "funcs", PARSE_OPT_EXCLUSIVE); 536 set_option_flag(options, 'F', "funcs", PARSE_OPT_EXCLUSIVE);
526 537
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index 199fc31e3919..515510ecc76a 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -11,7 +11,7 @@
11 11
12#include "util/build-id.h" 12#include "util/build-id.h"
13#include "util/util.h" 13#include "util/util.h"
14#include "util/parse-options.h" 14#include <subcmd/parse-options.h>
15#include "util/parse-events.h" 15#include "util/parse-events.h"
16 16
17#include "util/callchain.h" 17#include "util/callchain.h"
@@ -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,10 @@ 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;
57 bool buildid_all;
53 unsigned long long samples; 58 unsigned long long samples;
54}; 59};
55 60
@@ -319,7 +324,10 @@ try_again:
319 } else { 324 } else {
320 pr_err("failed to mmap with %d (%s)\n", errno, 325 pr_err("failed to mmap with %d (%s)\n", errno,
321 strerror_r(errno, msg, sizeof(msg))); 326 strerror_r(errno, msg, sizeof(msg)));
322 rc = -errno; 327 if (errno)
328 rc = -errno;
329 else
330 rc = -EINVAL;
323 } 331 }
324 goto out; 332 goto out;
325 } 333 }
@@ -362,6 +370,13 @@ static int process_buildids(struct record *rec)
362 */ 370 */
363 symbol_conf.ignore_vmlinux_buildid = true; 371 symbol_conf.ignore_vmlinux_buildid = true;
364 372
373 /*
374 * If --buildid-all is given, it marks all DSO regardless of hits,
375 * so no need to process samples.
376 */
377 if (rec->buildid_all)
378 rec->tool.sample = NULL;
379
365 return perf_session__process_events(session); 380 return perf_session__process_events(session);
366} 381}
367 382
@@ -452,6 +467,31 @@ static void record__init_features(struct record *rec)
452 467
453 if (!rec->opts.full_auxtrace) 468 if (!rec->opts.full_auxtrace)
454 perf_header__clear_feat(&session->header, HEADER_AUXTRACE); 469 perf_header__clear_feat(&session->header, HEADER_AUXTRACE);
470
471 perf_header__clear_feat(&session->header, HEADER_STAT);
472}
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;
455} 495}
456 496
457static volatile int workload_exec_errno; 497static volatile int workload_exec_errno;
@@ -472,6 +512,74 @@ static void workload_exec_failed_signal(int signo __maybe_unused,
472 512
473static void snapshot_sig_handler(int sig); 513static void snapshot_sig_handler(int sig);
474 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
475static int __cmd_record(struct record *rec, int argc, const char **argv) 583static int __cmd_record(struct record *rec, int argc, const char **argv)
476{ 584{
477 int err; 585 int err;
@@ -524,6 +632,16 @@ static int __cmd_record(struct record *rec, int argc, const char **argv)
524 goto out_child; 632 goto out_child;
525 } 633 }
526 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
527 /* 645 /*
528 * 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
529 * evlist. 647 * evlist.
@@ -556,63 +674,8 @@ static int __cmd_record(struct record *rec, int argc, const char **argv)
556 674
557 machine = &session->machines.host; 675 machine = &session->machines.host;
558 676
559 if (file->is_pipe) { 677 err = record__synthesize(rec);
560 err = perf_event__synthesize_attrs(tool, session,
561 process_synthesized_event);
562 if (err < 0) {
563 pr_err("Couldn't synthesize attrs.\n");
564 goto out_child;
565 }
566
567 if (have_tracepoints(&rec->evlist->entries)) {
568 /*
569 * FIXME err <= 0 here actually means that
570 * there were no tracepoints so its not really
571 * an error, just that we don't need to
572 * synthesize anything. We really have to
573 * return this more properly and also
574 * propagate errors that now are calling die()
575 */
576 err = perf_event__synthesize_tracing_data(tool, fd, rec->evlist,
577 process_synthesized_event);
578 if (err <= 0) {
579 pr_err("Couldn't record tracing data.\n");
580 goto out_child;
581 }
582 rec->bytes_written += err;
583 }
584 }
585
586 if (rec->opts.full_auxtrace) {
587 err = perf_event__synthesize_auxtrace_info(rec->itr, tool,
588 session, process_synthesized_event);
589 if (err)
590 goto out_delete_session;
591 }
592
593 err = perf_event__synthesize_kernel_mmap(tool, process_synthesized_event,
594 machine);
595 if (err < 0)
596 pr_err("Couldn't record kernel reference relocation symbol\n"
597 "Symbol resolution may be skewed if relocation was used (e.g. kexec).\n"
598 "Check /proc/kallsyms permission or run as root.\n");
599
600 err = perf_event__synthesize_modules(tool, process_synthesized_event,
601 machine);
602 if (err < 0) 678 if (err < 0)
603 pr_err("Couldn't record kernel module information.\n"
604 "Symbol resolution may be skewed if relocation was used (e.g. kexec).\n"
605 "Check /proc/modules permission or run as root.\n");
606
607 if (perf_guest) {
608 machines__process_guests(&session->machines,
609 perf_event__synthesize_guest_os, tool);
610 }
611
612 err = __machine__synthesize_threads(machine, tool, &opts->target, rec->evlist->threads,
613 process_synthesized_event, opts->sample_address,
614 opts->proc_map_timeout);
615 if (err != 0)
616 goto out_child; 679 goto out_child;
617 680
618 if (rec->realtime_prio) { 681 if (rec->realtime_prio) {
@@ -748,22 +811,8 @@ out_child:
748 /* this will be recalculated during process_buildids() */ 811 /* this will be recalculated during process_buildids() */
749 rec->samples = 0; 812 rec->samples = 0;
750 813
751 if (!err && !file->is_pipe) { 814 if (!err)
752 rec->session->header.data_size += rec->bytes_written; 815 record__finish_output(rec);
753 file->size = lseek(perf_data_file__fd(file), 0, SEEK_CUR);
754
755 if (!rec->no_buildid) {
756 process_buildids(rec);
757 /*
758 * We take all buildids when the file contains
759 * AUX area tracing data because we do not decode the
760 * trace because it would take too long.
761 */
762 if (rec->opts.full_auxtrace)
763 dsos__hit_all(rec->session);
764 }
765 perf_session__write_header(rec->session, rec->evlist, fd, true);
766 }
767 816
768 if (!err && !quiet) { 817 if (!err && !quiet) {
769 char samples[128]; 818 char samples[128];
@@ -813,8 +862,12 @@ int record_parse_callchain_opt(const struct option *opt,
813 } 862 }
814 863
815 ret = parse_callchain_record_opt(arg, &callchain_param); 864 ret = parse_callchain_record_opt(arg, &callchain_param);
816 if (!ret) 865 if (!ret) {
866 /* Enable data address sampling for DWARF unwind. */
867 if (callchain_param.record_mode == CALLCHAIN_DWARF)
868 record->sample_address = true;
817 callchain_debug(); 869 callchain_debug();
870 }
818 871
819 return ret; 872 return ret;
820} 873}
@@ -837,6 +890,19 @@ int record_callchain_opt(const struct option *opt,
837 890
838static int perf_record_config(const char *var, const char *value, void *cb) 891static int perf_record_config(const char *var, const char *value, void *cb)
839{ 892{
893 struct record *rec = cb;
894
895 if (!strcmp(var, "record.build-id")) {
896 if (!strcmp(value, "cache"))
897 rec->no_buildid_cache = false;
898 else if (!strcmp(value, "no-cache"))
899 rec->no_buildid_cache = true;
900 else if (!strcmp(value, "skip"))
901 rec->no_buildid = true;
902 else
903 return -1;
904 return 0;
905 }
840 if (!strcmp(var, "record.call-graph")) 906 if (!strcmp(var, "record.call-graph"))
841 var = "call-graph.record-mode"; /* fall-through */ 907 var = "call-graph.record-mode"; /* fall-through */
842 908
@@ -1074,10 +1140,12 @@ struct option __record_options[] = {
1074 OPT_BOOLEAN('P', "period", &record.opts.period, "Record the sample period"), 1140 OPT_BOOLEAN('P', "period", &record.opts.period, "Record the sample period"),
1075 OPT_BOOLEAN('n', "no-samples", &record.opts.no_samples, 1141 OPT_BOOLEAN('n', "no-samples", &record.opts.no_samples,
1076 "don't sample"), 1142 "don't sample"),
1077 OPT_BOOLEAN('N', "no-buildid-cache", &record.no_buildid_cache, 1143 OPT_BOOLEAN_SET('N', "no-buildid-cache", &record.no_buildid_cache,
1078 "do not update the buildid cache"), 1144 &record.no_buildid_cache_set,
1079 OPT_BOOLEAN('B', "no-buildid", &record.no_buildid, 1145 "do not update the buildid cache"),
1080 "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"),
1081 OPT_CALLBACK('G', "cgroup", &record.evlist, "name", 1149 OPT_CALLBACK('G', "cgroup", &record.evlist, "name",
1082 "monitor event in cgroup name only", 1150 "monitor event in cgroup name only",
1083 parse_cgroups), 1151 parse_cgroups),
@@ -1113,12 +1181,20 @@ struct option __record_options[] = {
1113 "per thread proc mmap processing timeout in ms"), 1181 "per thread proc mmap processing timeout in ms"),
1114 OPT_BOOLEAN(0, "switch-events", &record.opts.record_switch_events, 1182 OPT_BOOLEAN(0, "switch-events", &record.opts.record_switch_events,
1115 "Record context switch events"), 1183 "Record context switch events"),
1116#ifdef HAVE_LIBBPF_SUPPORT 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),
1117 OPT_STRING(0, "clang-path", &llvm_param.clang_path, "clang path", 1190 OPT_STRING(0, "clang-path", &llvm_param.clang_path, "clang path",
1118 "clang binary to use for compiling BPF scriptlets"), 1191 "clang binary to use for compiling BPF scriptlets"),
1119 OPT_STRING(0, "clang-opt", &llvm_param.clang_opt, "clang options", 1192 OPT_STRING(0, "clang-opt", &llvm_param.clang_opt, "clang options",
1120 "options passed to clang when compiling BPF scriptlets"), 1193 "options passed to clang when compiling BPF scriptlets"),
1121#endif 1194 OPT_STRING(0, "vmlinux", &symbol_conf.vmlinux_name,
1195 "file", "vmlinux pathname"),
1196 OPT_BOOLEAN(0, "buildid-all", &record.buildid_all,
1197 "Record build-id of all DSOs regardless of hits"),
1122 OPT_END() 1198 OPT_END()
1123}; 1199};
1124 1200
@@ -1130,6 +1206,27 @@ int cmd_record(int argc, const char **argv, const char *prefix __maybe_unused)
1130 struct record *rec = &record; 1206 struct record *rec = &record;
1131 char errbuf[BUFSIZ]; 1207 char errbuf[BUFSIZ];
1132 1208
1209#ifndef HAVE_LIBBPF_SUPPORT
1210# define set_nobuild(s, l, c) set_option_nobuild(record_options, s, l, "NO_LIBBPF=1", c)
1211 set_nobuild('\0', "clang-path", true);
1212 set_nobuild('\0', "clang-opt", true);
1213# undef set_nobuild
1214#endif
1215
1216#ifndef HAVE_BPF_PROLOGUE
1217# if !defined (HAVE_DWARF_SUPPORT)
1218# define REASON "NO_DWARF=1"
1219# elif !defined (HAVE_LIBBPF_SUPPORT)
1220# define REASON "NO_LIBBPF=1"
1221# else
1222# define REASON "this architecture doesn't support BPF prologue"
1223# endif
1224# define set_nobuild(s, l, c) set_option_nobuild(record_options, s, l, REASON, c)
1225 set_nobuild('\0', "vmlinux", true);
1226# undef set_nobuild
1227# undef REASON
1228#endif
1229
1133 rec->evlist = perf_evlist__new(); 1230 rec->evlist = perf_evlist__new();
1134 if (rec->evlist == NULL) 1231 if (rec->evlist == NULL)
1135 return -ENOMEM; 1232 return -ENOMEM;
@@ -1215,6 +1312,14 @@ int cmd_record(int argc, const char **argv, const char *prefix __maybe_unused)
1215 if (err) 1312 if (err)
1216 goto out_symbol_exit; 1313 goto out_symbol_exit;
1217 1314
1315 /*
1316 * We take all buildids when the file contains
1317 * AUX area tracing data because we do not decode the
1318 * trace because it would take too long.
1319 */
1320 if (rec->opts.full_auxtrace)
1321 rec->buildid_all = true;
1322
1218 if (record_opts__config(&rec->opts)) { 1323 if (record_opts__config(&rec->opts)) {
1219 err = -EINVAL; 1324 err = -EINVAL;
1220 goto out_symbol_exit; 1325 goto out_symbol_exit;
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
index 2853ad2bd435..160ea23b45aa 100644
--- a/tools/perf/builtin-report.c
+++ b/tools/perf/builtin-report.c
@@ -27,7 +27,8 @@
27#include "util/session.h" 27#include "util/session.h"
28#include "util/tool.h" 28#include "util/tool.h"
29 29
30#include "util/parse-options.h" 30#include <subcmd/parse-options.h>
31#include <subcmd/exec-cmd.h>
31#include "util/parse-events.h" 32#include "util/parse-events.h"
32 33
33#include "util/thread.h" 34#include "util/thread.h"
@@ -40,12 +41,12 @@
40 41
41#include <dlfcn.h> 42#include <dlfcn.h>
42#include <linux/bitmap.h> 43#include <linux/bitmap.h>
44#include <linux/stringify.h>
43 45
44struct report { 46struct report {
45 struct perf_tool tool; 47 struct perf_tool tool;
46 struct perf_session *session; 48 struct perf_session *session;
47 bool force, use_tui, use_gtk, use_stdio; 49 bool use_tui, use_gtk, use_stdio;
48 bool hide_unresolved;
49 bool dont_use_callchains; 50 bool dont_use_callchains;
50 bool show_full_info; 51 bool show_full_info;
51 bool show_threads; 52 bool show_threads;
@@ -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,
@@ -146,18 +150,18 @@ static int process_sample_event(struct perf_tool *tool,
146 struct hist_entry_iter iter = { 150 struct hist_entry_iter iter = {
147 .evsel = evsel, 151 .evsel = evsel,
148 .sample = sample, 152 .sample = sample,
149 .hide_unresolved = rep->hide_unresolved, 153 .hide_unresolved = symbol_conf.hide_unresolved,
150 .add_entry_cb = hist_iter__report_callback, 154 .add_entry_cb = hist_iter__report_callback,
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;
158 } 162 }
159 163
160 if (rep->hide_unresolved && al.sym == NULL) 164 if (symbol_conf.hide_unresolved && al.sym == NULL)
161 goto out_put; 165 goto out_put;
162 166
163 if (rep->cpu_list && !test_bit(sample->cpu, rep->cpu_bitmap)) 167 if (rep->cpu_list && !test_bit(sample->cpu, rep->cpu_bitmap))
@@ -434,7 +438,14 @@ static int report__browse_hists(struct report *rep)
434 int ret; 438 int ret;
435 struct perf_session *session = rep->session; 439 struct perf_session *session = rep->session;
436 struct perf_evlist *evlist = session->evlist; 440 struct perf_evlist *evlist = session->evlist;
437 const char *help = "For a higher level overview, try: perf report --sort comm,dso"; 441 const char *help = perf_tip(system_path(TIPDIR));
442
443 if (help == NULL) {
444 /* fallback for people who don't install perf ;-) */
445 help = perf_tip(DOCDIR);
446 if (help == NULL)
447 help = "Cannot load tips.txt file, please install perf!";
448 }
438 449
439 switch (use_browser) { 450 switch (use_browser) {
440 case 1: 451 case 1:
@@ -459,10 +470,11 @@ static int report__browse_hists(struct report *rep)
459 return ret; 470 return ret;
460} 471}
461 472
462static void report__collapse_hists(struct report *rep) 473static int report__collapse_hists(struct report *rep)
463{ 474{
464 struct ui_progress prog; 475 struct ui_progress prog;
465 struct perf_evsel *pos; 476 struct perf_evsel *pos;
477 int ret = 0;
466 478
467 ui_progress__init(&prog, rep->nr_entries, "Merging related events..."); 479 ui_progress__init(&prog, rep->nr_entries, "Merging related events...");
468 480
@@ -474,7 +486,9 @@ static void report__collapse_hists(struct report *rep)
474 486
475 hists->socket_filter = rep->socket_filter; 487 hists->socket_filter = rep->socket_filter;
476 488
477 hists__collapse_resort(hists, &prog); 489 ret = hists__collapse_resort(hists, &prog);
490 if (ret < 0)
491 break;
478 492
479 /* Non-group events are considered as leader */ 493 /* Non-group events are considered as leader */
480 if (symbol_conf.event_group && 494 if (symbol_conf.event_group &&
@@ -487,6 +501,7 @@ static void report__collapse_hists(struct report *rep)
487 } 501 }
488 502
489 ui_progress__finish(); 503 ui_progress__finish();
504 return ret;
490} 505}
491 506
492static void report__output_resort(struct report *rep) 507static void report__output_resort(struct report *rep)
@@ -497,7 +512,7 @@ static void report__output_resort(struct report *rep)
497 ui_progress__init(&prog, rep->nr_entries, "Sorting events for output..."); 512 ui_progress__init(&prog, rep->nr_entries, "Sorting events for output...");
498 513
499 evlist__for_each(rep->session->evlist, pos) 514 evlist__for_each(rep->session->evlist, pos)
500 hists__output_resort(evsel__hists(pos), &prog); 515 perf_evsel__output_resort(pos, &prog);
501 516
502 ui_progress__finish(); 517 ui_progress__finish();
503} 518}
@@ -514,20 +529,26 @@ static int __cmd_report(struct report *rep)
514 if (rep->cpu_list) { 529 if (rep->cpu_list) {
515 ret = perf_session__cpu_bitmap(session, rep->cpu_list, 530 ret = perf_session__cpu_bitmap(session, rep->cpu_list,
516 rep->cpu_bitmap); 531 rep->cpu_bitmap);
517 if (ret) 532 if (ret) {
533 ui__error("failed to set cpu bitmap\n");
518 return ret; 534 return ret;
535 }
519 } 536 }
520 537
521 if (rep->show_threads) 538 if (rep->show_threads)
522 perf_read_values_init(&rep->show_threads_values); 539 perf_read_values_init(&rep->show_threads_values);
523 540
524 ret = report__setup_sample_type(rep); 541 ret = report__setup_sample_type(rep);
525 if (ret) 542 if (ret) {
543 /* report__setup_sample_type() already showed error message */
526 return ret; 544 return ret;
545 }
527 546
528 ret = perf_session__process_events(session); 547 ret = perf_session__process_events(session);
529 if (ret) 548 if (ret) {
549 ui__error("failed to process sample\n");
530 return ret; 550 return ret;
551 }
531 552
532 report__warn_kptr_restrict(rep); 553 report__warn_kptr_restrict(rep);
533 554
@@ -548,7 +569,11 @@ static int __cmd_report(struct report *rep)
548 } 569 }
549 } 570 }
550 571
551 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 }
552 577
553 if (session_done()) 578 if (session_done())
554 return 0; 579 return 0;
@@ -620,12 +645,14 @@ parse_percent_limit(const struct option *opt, const char *str,
620 int unset __maybe_unused) 645 int unset __maybe_unused)
621{ 646{
622 struct report *rep = opt->value; 647 struct report *rep = opt->value;
648 double pcnt = strtof(str, NULL);
623 649
624 rep->min_percent = strtof(str, NULL); 650 rep->min_percent = pcnt;
651 callchain_param.min_percent = pcnt;
625 return 0; 652 return 0;
626} 653}
627 654
628#define CALLCHAIN_DEFAULT_OPT "graph,0.5,caller,function" 655#define CALLCHAIN_DEFAULT_OPT "graph,0.5,caller,function,percent"
629 656
630const char report_callchain_help[] = "Display call graph (stack chain/backtrace):\n\n" 657const char report_callchain_help[] = "Display call graph (stack chain/backtrace):\n\n"
631 CALLCHAIN_REPORT_HELP 658 CALLCHAIN_REPORT_HELP
@@ -678,7 +705,7 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
678 "file", "vmlinux pathname"), 705 "file", "vmlinux pathname"),
679 OPT_STRING(0, "kallsyms", &symbol_conf.kallsyms_name, 706 OPT_STRING(0, "kallsyms", &symbol_conf.kallsyms_name,
680 "file", "kallsyms pathname"), 707 "file", "kallsyms pathname"),
681 OPT_BOOLEAN('f', "force", &report.force, "don't complain, do it"), 708 OPT_BOOLEAN('f', "force", &symbol_conf.force, "don't complain, do it"),
682 OPT_BOOLEAN('m', "modules", &symbol_conf.use_modules, 709 OPT_BOOLEAN('m', "modules", &symbol_conf.use_modules,
683 "load module symbols - WARNING: use only with -k and LIVE kernel"), 710 "load module symbols - WARNING: use only with -k and LIVE kernel"),
684 OPT_BOOLEAN('n', "show-nr-samples", &symbol_conf.show_nr_samples, 711 OPT_BOOLEAN('n', "show-nr-samples", &symbol_conf.show_nr_samples,
@@ -708,7 +735,7 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
708 OPT_BOOLEAN('x', "exclude-other", &symbol_conf.exclude_other, 735 OPT_BOOLEAN('x', "exclude-other", &symbol_conf.exclude_other,
709 "Only display entries with parent-match"), 736 "Only display entries with parent-match"),
710 OPT_CALLBACK_DEFAULT('g', "call-graph", &report, 737 OPT_CALLBACK_DEFAULT('g', "call-graph", &report,
711 "print_type,threshold[,print_limit],order,sort_key[,branch]", 738 "print_type,threshold[,print_limit],order,sort_key[,branch],value",
712 report_callchain_help, &report_parse_callchain_opt, 739 report_callchain_help, &report_parse_callchain_opt,
713 callchain_default_opt), 740 callchain_default_opt),
714 OPT_BOOLEAN(0, "children", &symbol_conf.cumulate_callchain, 741 OPT_BOOLEAN(0, "children", &symbol_conf.cumulate_callchain,
@@ -740,7 +767,7 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
740 OPT_STRING_NOEMPTY('t', "field-separator", &symbol_conf.field_sep, "separator", 767 OPT_STRING_NOEMPTY('t', "field-separator", &symbol_conf.field_sep, "separator",
741 "separator for columns, no spaces will be added between " 768 "separator for columns, no spaces will be added between "
742 "columns '.' is reserved."), 769 "columns '.' is reserved."),
743 OPT_BOOLEAN('U', "hide-unresolved", &report.hide_unresolved, 770 OPT_BOOLEAN('U', "hide-unresolved", &symbol_conf.hide_unresolved,
744 "Only display entries resolved to a symbol"), 771 "Only display entries resolved to a symbol"),
745 OPT_STRING(0, "symfs", &symbol_conf.symfs, "directory", 772 OPT_STRING(0, "symfs", &symbol_conf.symfs, "directory",
746 "Look for files with symbols relative to this directory"), 773 "Look for files with symbols relative to this directory"),
@@ -783,6 +810,10 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
783 "Show callgraph from reference event"), 810 "Show callgraph from reference event"),
784 OPT_INTEGER(0, "socket-filter", &report.socket_filter, 811 OPT_INTEGER(0, "socket-filter", &report.socket_filter,
785 "only show processor socket that match with this filter"), 812 "only show processor socket that match with this filter"),
813 OPT_BOOLEAN(0, "raw-trace", &symbol_conf.raw_trace,
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"),
786 OPT_END() 817 OPT_END()
787 }; 818 };
788 struct perf_data_file file = { 819 struct perf_data_file file = {
@@ -796,6 +827,16 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
796 perf_config(report__config, &report); 827 perf_config(report__config, &report);
797 828
798 argc = parse_options(argc, argv, options, report_usage, 0); 829 argc = parse_options(argc, argv, options, report_usage, 0);
830 if (argc) {
831 /*
832 * Special case: if there's an argument left then assume that
833 * it's a symbol filter:
834 */
835 if (argc > 1)
836 usage_with_options(report_usage, options);
837
838 report.symbol_filter_str = argv[0];
839 }
799 840
800 if (symbol_conf.vmlinux_name && 841 if (symbol_conf.vmlinux_name &&
801 access(symbol_conf.vmlinux_name, R_OK)) { 842 access(symbol_conf.vmlinux_name, R_OK)) {
@@ -832,7 +873,7 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
832 } 873 }
833 874
834 file.path = input_name; 875 file.path = input_name;
835 file.force = report.force; 876 file.force = symbol_conf.force;
836 877
837repeat: 878repeat:
838 session = perf_session__new(&file, false, &report.tool); 879 session = perf_session__new(&file, false, &report.tool);
@@ -882,13 +923,19 @@ repeat:
882 symbol_conf.cumulate_callchain = false; 923 symbol_conf.cumulate_callchain = false;
883 } 924 }
884 925
885 if (setup_sorting() < 0) { 926 if (symbol_conf.report_hierarchy) {
886 if (sort_order) 927 /* disable incompatible options */
887 parse_options_usage(report_usage, options, "s", 1); 928 symbol_conf.event_group = false;
888 if (field_order) 929 symbol_conf.cumulate_callchain = false;
889 parse_options_usage(sort_order ? NULL : report_usage, 930
890 options, "F", 1); 931 if (field_order) {
891 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;
892 } 939 }
893 940
894 /* Force tty output for header output and per-thread stat. */ 941 /* Force tty output for header output and per-thread stat. */
@@ -900,6 +947,15 @@ repeat:
900 else 947 else
901 use_browser = 0; 948 use_browser = 0;
902 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
903 if (report.header || report.header_only) { 959 if (report.header || report.header_only) {
904 perf_session__fprintf_info(session, stdout, 960 perf_session__fprintf_info(session, stdout,
905 report.show_full_info); 961 report.show_full_info);
@@ -941,17 +997,6 @@ repeat:
941 if (symbol__init(&session->header.env) < 0) 997 if (symbol__init(&session->header.env) < 0)
942 goto error; 998 goto error;
943 999
944 if (argc) {
945 /*
946 * Special case: if there's an argument left then assume that
947 * it's a symbol filter:
948 */
949 if (argc > 1)
950 usage_with_options(report_usage, options);
951
952 report.symbol_filter_str = argv[0];
953 }
954
955 sort__setup_elide(stdout); 1000 sort__setup_elide(stdout);
956 1001
957 ret = __cmd_report(&report); 1002 ret = __cmd_report(&report);
diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c
index 0ee6d900e100..871b55ae22a4 100644
--- a/tools/perf/builtin-sched.c
+++ b/tools/perf/builtin-sched.c
@@ -12,7 +12,7 @@
12#include "util/tool.h" 12#include "util/tool.h"
13#include "util/cloexec.h" 13#include "util/cloexec.h"
14 14
15#include "util/parse-options.h" 15#include <subcmd/parse-options.h>
16#include "util/trace-event.h" 16#include "util/trace-event.h"
17 17
18#include "util/debug.h" 18#include "util/debug.h"
@@ -1203,12 +1203,13 @@ static void output_lat_thread(struct perf_sched *sched, struct work_atoms *work_
1203 1203
1204static int pid_cmp(struct work_atoms *l, struct work_atoms *r) 1204static int pid_cmp(struct work_atoms *l, struct work_atoms *r)
1205{ 1205{
1206 if (l->thread == r->thread)
1207 return 0;
1206 if (l->thread->tid < r->thread->tid) 1208 if (l->thread->tid < r->thread->tid)
1207 return -1; 1209 return -1;
1208 if (l->thread->tid > r->thread->tid) 1210 if (l->thread->tid > r->thread->tid)
1209 return 1; 1211 return 1;
1210 1212 return (int)(l->thread - r->thread);
1211 return 0;
1212} 1213}
1213 1214
1214static int avg_cmp(struct work_atoms *l, struct work_atoms *r) 1215static int avg_cmp(struct work_atoms *l, struct work_atoms *r)
diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c
index 72b5deb4bd79..3770c3dffe5e 100644
--- a/tools/perf/builtin-script.c
+++ b/tools/perf/builtin-script.c
@@ -3,9 +3,9 @@
3#include "perf.h" 3#include "perf.h"
4#include "util/cache.h" 4#include "util/cache.h"
5#include "util/debug.h" 5#include "util/debug.h"
6#include "util/exec_cmd.h" 6#include <subcmd/exec-cmd.h>
7#include "util/header.h" 7#include "util/header.h"
8#include "util/parse-options.h" 8#include <subcmd/parse-options.h>
9#include "util/perf_regs.h" 9#include "util/perf_regs.h"
10#include "util/session.h" 10#include "util/session.h"
11#include "util/tool.h" 11#include "util/tool.h"
@@ -18,7 +18,12 @@
18#include "util/sort.h" 18#include "util/sort.h"
19#include "util/data.h" 19#include "util/data.h"
20#include "util/auxtrace.h" 20#include "util/auxtrace.h"
21#include "util/cpumap.h"
22#include "util/thread_map.h"
23#include "util/stat.h"
21#include <linux/bitmap.h> 24#include <linux/bitmap.h>
25#include "asm/bug.h"
26#include "util/mem-events.h"
22 27
23static char const *script_name; 28static char const *script_name;
24static char const *generate_script_lang; 29static char const *generate_script_lang;
@@ -32,6 +37,7 @@ static bool print_flags;
32static bool nanosecs; 37static bool nanosecs;
33static const char *cpu_list; 38static const char *cpu_list;
34static DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS); 39static DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS);
40static struct perf_stat_config stat_config;
35 41
36unsigned int scripting_max_stack = PERF_MAX_STACK_DEPTH; 42unsigned int scripting_max_stack = PERF_MAX_STACK_DEPTH;
37 43
@@ -53,6 +59,9 @@ enum perf_output_field {
53 PERF_OUTPUT_IREGS = 1U << 14, 59 PERF_OUTPUT_IREGS = 1U << 14,
54 PERF_OUTPUT_BRSTACK = 1U << 15, 60 PERF_OUTPUT_BRSTACK = 1U << 15,
55 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,
56}; 65};
57 66
58struct output_option { 67struct output_option {
@@ -76,6 +85,9 @@ struct output_option {
76 {.str = "iregs", .field = PERF_OUTPUT_IREGS}, 85 {.str = "iregs", .field = PERF_OUTPUT_IREGS},
77 {.str = "brstack", .field = PERF_OUTPUT_BRSTACK}, 86 {.str = "brstack", .field = PERF_OUTPUT_BRSTACK},
78 {.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},
79}; 91};
80 92
81/* default set to maintain compatibility with current format */ 93/* default set to maintain compatibility with current format */
@@ -96,7 +108,7 @@ static struct {
96 PERF_OUTPUT_SYM | PERF_OUTPUT_DSO | 108 PERF_OUTPUT_SYM | PERF_OUTPUT_DSO |
97 PERF_OUTPUT_PERIOD, 109 PERF_OUTPUT_PERIOD,
98 110
99 .invalid_fields = PERF_OUTPUT_TRACE, 111 .invalid_fields = PERF_OUTPUT_TRACE | PERF_OUTPUT_BPF_OUTPUT,
100 }, 112 },
101 113
102 [PERF_TYPE_SOFTWARE] = { 114 [PERF_TYPE_SOFTWARE] = {
@@ -106,7 +118,7 @@ static struct {
106 PERF_OUTPUT_CPU | PERF_OUTPUT_TIME | 118 PERF_OUTPUT_CPU | PERF_OUTPUT_TIME |
107 PERF_OUTPUT_EVNAME | PERF_OUTPUT_IP | 119 PERF_OUTPUT_EVNAME | PERF_OUTPUT_IP |
108 PERF_OUTPUT_SYM | PERF_OUTPUT_DSO | 120 PERF_OUTPUT_SYM | PERF_OUTPUT_DSO |
109 PERF_OUTPUT_PERIOD, 121 PERF_OUTPUT_PERIOD | PERF_OUTPUT_BPF_OUTPUT,
110 122
111 .invalid_fields = PERF_OUTPUT_TRACE, 123 .invalid_fields = PERF_OUTPUT_TRACE,
112 }, 124 },
@@ -116,7 +128,7 @@ static struct {
116 128
117 .fields = PERF_OUTPUT_COMM | PERF_OUTPUT_TID | 129 .fields = PERF_OUTPUT_COMM | PERF_OUTPUT_TID |
118 PERF_OUTPUT_CPU | PERF_OUTPUT_TIME | 130 PERF_OUTPUT_CPU | PERF_OUTPUT_TIME |
119 PERF_OUTPUT_EVNAME | PERF_OUTPUT_TRACE, 131 PERF_OUTPUT_EVNAME | PERF_OUTPUT_TRACE
120 }, 132 },
121 133
122 [PERF_TYPE_RAW] = { 134 [PERF_TYPE_RAW] = {
@@ -126,9 +138,22 @@ static struct {
126 PERF_OUTPUT_CPU | PERF_OUTPUT_TIME | 138 PERF_OUTPUT_CPU | PERF_OUTPUT_TIME |
127 PERF_OUTPUT_EVNAME | PERF_OUTPUT_IP | 139 PERF_OUTPUT_EVNAME | PERF_OUTPUT_IP |
128 PERF_OUTPUT_SYM | PERF_OUTPUT_DSO | 140 PERF_OUTPUT_SYM | PERF_OUTPUT_DSO |
141 PERF_OUTPUT_PERIOD | PERF_OUTPUT_ADDR |
142 PERF_OUTPUT_DATA_SRC | PERF_OUTPUT_WEIGHT,
143
144 .invalid_fields = PERF_OUTPUT_TRACE | PERF_OUTPUT_BPF_OUTPUT,
145 },
146
147 [PERF_TYPE_BREAKPOINT] = {
148 .user_set = false,
149
150 .fields = PERF_OUTPUT_COMM | PERF_OUTPUT_TID |
151 PERF_OUTPUT_CPU | PERF_OUTPUT_TIME |
152 PERF_OUTPUT_EVNAME | PERF_OUTPUT_IP |
153 PERF_OUTPUT_SYM | PERF_OUTPUT_DSO |
129 PERF_OUTPUT_PERIOD, 154 PERF_OUTPUT_PERIOD,
130 155
131 .invalid_fields = PERF_OUTPUT_TRACE, 156 .invalid_fields = PERF_OUTPUT_TRACE | PERF_OUTPUT_BPF_OUTPUT,
132 }, 157 },
133}; 158};
134 159
@@ -204,6 +229,9 @@ static int perf_evsel__check_attr(struct perf_evsel *evsel,
204 struct perf_event_attr *attr = &evsel->attr; 229 struct perf_event_attr *attr = &evsel->attr;
205 bool allow_user_set; 230 bool allow_user_set;
206 231
232 if (perf_header__has_feat(&session->header, HEADER_STAT))
233 return 0;
234
207 allow_user_set = perf_header__has_feat(&session->header, 235 allow_user_set = perf_header__has_feat(&session->header,
208 HEADER_AUXTRACE); 236 HEADER_AUXTRACE);
209 237
@@ -222,6 +250,16 @@ static int perf_evsel__check_attr(struct perf_evsel *evsel,
222 PERF_OUTPUT_ADDR, allow_user_set)) 250 PERF_OUTPUT_ADDR, allow_user_set))
223 return -EINVAL; 251 return -EINVAL;
224 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
225 if (PRINT_FIELD(SYM) && !PRINT_FIELD(IP) && !PRINT_FIELD(ADDR)) { 263 if (PRINT_FIELD(SYM) && !PRINT_FIELD(IP) && !PRINT_FIELD(ADDR)) {
226 pr_err("Display of symbols requested but neither sample IP nor " 264 pr_err("Display of symbols requested but neither sample IP nor "
227 "sample address\nis selected. Hence, no addresses to convert " 265 "sample address\nis selected. Hence, no addresses to convert "
@@ -367,9 +405,7 @@ out:
367 return 0; 405 return 0;
368} 406}
369 407
370static void print_sample_iregs(union perf_event *event __maybe_unused, 408static void print_sample_iregs(struct perf_sample *sample,
371 struct perf_sample *sample,
372 struct thread *thread __maybe_unused,
373 struct perf_event_attr *attr) 409 struct perf_event_attr *attr)
374{ 410{
375 struct regs_dump *regs = &sample->intr_regs; 411 struct regs_dump *regs = &sample->intr_regs;
@@ -438,10 +474,7 @@ mispred_str(struct branch_entry *br)
438 return br->flags.predicted ? 'P' : 'M'; 474 return br->flags.predicted ? 'P' : 'M';
439} 475}
440 476
441static void print_sample_brstack(union perf_event *event __maybe_unused, 477static void print_sample_brstack(struct perf_sample *sample)
442 struct perf_sample *sample,
443 struct thread *thread __maybe_unused,
444 struct perf_event_attr *attr __maybe_unused)
445{ 478{
446 struct branch_stack *br = sample->branch_stack; 479 struct branch_stack *br = sample->branch_stack;
447 u64 i; 480 u64 i;
@@ -460,14 +493,11 @@ static void print_sample_brstack(union perf_event *event __maybe_unused,
460 } 493 }
461} 494}
462 495
463static void print_sample_brstacksym(union perf_event *event __maybe_unused, 496static void print_sample_brstacksym(struct perf_sample *sample,
464 struct perf_sample *sample, 497 struct thread *thread)
465 struct thread *thread __maybe_unused,
466 struct perf_event_attr *attr __maybe_unused)
467{ 498{
468 struct branch_stack *br = sample->branch_stack; 499 struct branch_stack *br = sample->branch_stack;
469 struct addr_location alf, alt; 500 struct addr_location alf, alt;
470 u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
471 u64 i, from, to; 501 u64 i, from, to;
472 502
473 if (!(br && br->nr)) 503 if (!(br && br->nr))
@@ -480,11 +510,11 @@ static void print_sample_brstacksym(union perf_event *event __maybe_unused,
480 from = br->entries[i].from; 510 from = br->entries[i].from;
481 to = br->entries[i].to; 511 to = br->entries[i].to;
482 512
483 thread__find_addr_map(thread, cpumode, MAP__FUNCTION, from, &alf); 513 thread__find_addr_map(thread, sample->cpumode, MAP__FUNCTION, from, &alf);
484 if (alf.map) 514 if (alf.map)
485 alf.sym = map__find_symbol(alf.map, alf.addr, NULL); 515 alf.sym = map__find_symbol(alf.map, alf.addr, NULL);
486 516
487 thread__find_addr_map(thread, cpumode, MAP__FUNCTION, to, &alt); 517 thread__find_addr_map(thread, sample->cpumode, MAP__FUNCTION, to, &alt);
488 if (alt.map) 518 if (alt.map)
489 alt.sym = map__find_symbol(alt.map, alt.addr, NULL); 519 alt.sym = map__find_symbol(alt.map, alt.addr, NULL);
490 520
@@ -500,8 +530,7 @@ static void print_sample_brstacksym(union perf_event *event __maybe_unused,
500} 530}
501 531
502 532
503static void print_sample_addr(union perf_event *event, 533static void print_sample_addr(struct perf_sample *sample,
504 struct perf_sample *sample,
505 struct thread *thread, 534 struct thread *thread,
506 struct perf_event_attr *attr) 535 struct perf_event_attr *attr)
507{ 536{
@@ -512,7 +541,7 @@ static void print_sample_addr(union perf_event *event,
512 if (!sample_addr_correlates_sym(attr)) 541 if (!sample_addr_correlates_sym(attr))
513 return; 542 return;
514 543
515 perf_event__preprocess_sample_addr(event, sample, thread, &al); 544 thread__resolve(thread, &al, sample);
516 545
517 if (PRINT_FIELD(SYM)) { 546 if (PRINT_FIELD(SYM)) {
518 printf(" "); 547 printf(" ");
@@ -529,8 +558,7 @@ static void print_sample_addr(union perf_event *event,
529 } 558 }
530} 559}
531 560
532static void print_sample_bts(union perf_event *event, 561static void print_sample_bts(struct perf_sample *sample,
533 struct perf_sample *sample,
534 struct perf_evsel *evsel, 562 struct perf_evsel *evsel,
535 struct thread *thread, 563 struct thread *thread,
536 struct addr_location *al) 564 struct addr_location *al)
@@ -560,7 +588,7 @@ static void print_sample_bts(union perf_event *event,
560 ((evsel->attr.sample_type & PERF_SAMPLE_ADDR) && 588 ((evsel->attr.sample_type & PERF_SAMPLE_ADDR) &&
561 !output[attr->type].user_set)) { 589 !output[attr->type].user_set)) {
562 printf(" => "); 590 printf(" => ");
563 print_sample_addr(event, sample, thread, attr); 591 print_sample_addr(sample, thread, attr);
564 } 592 }
565 593
566 if (print_srcline_last) 594 if (print_srcline_last)
@@ -588,8 +616,130 @@ static void print_sample_flags(u32 flags)
588 printf(" %-4s ", str); 616 printf(" %-4s ", str);
589} 617}
590 618
591static void process_event(union perf_event *event, struct perf_sample *sample, 619struct printer_data {
592 struct perf_evsel *evsel, struct addr_location *al) 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
697struct perf_script {
698 struct perf_tool tool;
699 struct perf_session *session;
700 bool show_task_events;
701 bool show_mmap_events;
702 bool show_switch_events;
703 bool allocated;
704 struct cpu_map *cpus;
705 struct thread_map *threads;
706 int name_width;
707};
708
709static int perf_evlist__max_name_len(struct perf_evlist *evlist)
710{
711 struct perf_evsel *evsel;
712 int max = 0;
713
714 evlist__for_each(evlist, evsel) {
715 int len = strlen(perf_evsel__name(evsel));
716
717 max = MAX(len, max);
718 }
719
720 return max;
721}
722
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,
741 struct perf_sample *sample, struct perf_evsel *evsel,
742 struct addr_location *al)
593{ 743{
594 struct thread *thread = al->thread; 744 struct thread *thread = al->thread;
595 struct perf_event_attr *attr = &evsel->attr; 745 struct perf_event_attr *attr = &evsel->attr;
@@ -604,14 +754,19 @@ static void process_event(union perf_event *event, struct perf_sample *sample,
604 754
605 if (PRINT_FIELD(EVNAME)) { 755 if (PRINT_FIELD(EVNAME)) {
606 const char *evname = perf_evsel__name(evsel); 756 const char *evname = perf_evsel__name(evsel);
607 printf("%s: ", evname ? evname : "[unknown]"); 757
758 if (!script->name_width)
759 script->name_width = perf_evlist__max_name_len(script->session->evlist);
760
761 printf("%*s: ", script->name_width,
762 evname ? evname : "[unknown]");
608 } 763 }
609 764
610 if (print_flags) 765 if (print_flags)
611 print_sample_flags(sample->flags); 766 print_sample_flags(sample->flags);
612 767
613 if (is_bts_event(attr)) { 768 if (is_bts_event(attr)) {
614 print_sample_bts(event, sample, evsel, thread, al); 769 print_sample_bts(sample, evsel, thread, al);
615 return; 770 return;
616 } 771 }
617 772
@@ -619,7 +774,13 @@ static void process_event(union perf_event *event, struct perf_sample *sample,
619 event_format__print(evsel->tp_format, sample->cpu, 774 event_format__print(evsel->tp_format, sample->cpu,
620 sample->raw_data, sample->raw_size); 775 sample->raw_data, sample->raw_size);
621 if (PRINT_FIELD(ADDR)) 776 if (PRINT_FIELD(ADDR))
622 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);
623 784
624 if (PRINT_FIELD(IP)) { 785 if (PRINT_FIELD(IP)) {
625 if (!symbol_conf.use_callchain) 786 if (!symbol_conf.use_callchain)
@@ -633,75 +794,94 @@ static void process_event(union perf_event *event, struct perf_sample *sample,
633 } 794 }
634 795
635 if (PRINT_FIELD(IREGS)) 796 if (PRINT_FIELD(IREGS))
636 print_sample_iregs(event, sample, thread, attr); 797 print_sample_iregs(sample, attr);
637 798
638 if (PRINT_FIELD(BRSTACK)) 799 if (PRINT_FIELD(BRSTACK))
639 print_sample_brstack(event, sample, thread, attr); 800 print_sample_brstack(sample);
640 else if (PRINT_FIELD(BRSTACKSYM)) 801 else if (PRINT_FIELD(BRSTACKSYM))
641 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);
642 806
643 printf("\n"); 807 printf("\n");
644} 808}
645 809
646static int default_start_script(const char *script __maybe_unused, 810static struct scripting_ops *scripting_ops;
647 int argc __maybe_unused,
648 const char **argv __maybe_unused)
649{
650 return 0;
651}
652 811
653static int default_flush_script(void) 812static void __process_stat(struct perf_evsel *counter, u64 tstamp)
654{ 813{
655 return 0; 814 int nthreads = thread_map__nr(counter->threads);
815 int ncpus = perf_evsel__nr_cpus(counter);
816 int cpu, thread;
817 static int header_printed;
818
819 if (counter->system_wide)
820 nthreads = 1;
821
822 if (!header_printed) {
823 printf("%3s %8s %15s %15s %15s %15s %s\n",
824 "CPU", "THREAD", "VAL", "ENA", "RUN", "TIME", "EVENT");
825 header_printed = 1;
826 }
827
828 for (thread = 0; thread < nthreads; thread++) {
829 for (cpu = 0; cpu < ncpus; cpu++) {
830 struct perf_counts_values *counts;
831
832 counts = perf_counts(counter->counts, cpu, thread);
833
834 printf("%3d %8d %15" PRIu64 " %15" PRIu64 " %15" PRIu64 " %15" PRIu64 " %s\n",
835 counter->cpus->map[cpu],
836 thread_map__pid(counter->threads, thread),
837 counts->val,
838 counts->ena,
839 counts->run,
840 tstamp,
841 perf_evsel__name(counter));
842 }
843 }
656} 844}
657 845
658static int default_stop_script(void) 846static void process_stat(struct perf_evsel *counter, u64 tstamp)
659{ 847{
660 return 0; 848 if (scripting_ops && scripting_ops->process_stat)
849 scripting_ops->process_stat(&stat_config, counter, tstamp);
850 else
851 __process_stat(counter, tstamp);
661} 852}
662 853
663static int default_generate_script(struct pevent *pevent __maybe_unused, 854static void process_stat_interval(u64 tstamp)
664 const char *outfile __maybe_unused)
665{ 855{
666 return 0; 856 if (scripting_ops && scripting_ops->process_stat_interval)
857 scripting_ops->process_stat_interval(tstamp);
667} 858}
668 859
669static struct scripting_ops default_scripting_ops = {
670 .start_script = default_start_script,
671 .flush_script = default_flush_script,
672 .stop_script = default_stop_script,
673 .process_event = process_event,
674 .generate_script = default_generate_script,
675};
676
677static struct scripting_ops *scripting_ops;
678
679static void setup_scripting(void) 860static void setup_scripting(void)
680{ 861{
681 setup_perl_scripting(); 862 setup_perl_scripting();
682 setup_python_scripting(); 863 setup_python_scripting();
683
684 scripting_ops = &default_scripting_ops;
685} 864}
686 865
687static int flush_scripting(void) 866static int flush_scripting(void)
688{ 867{
689 return scripting_ops->flush_script(); 868 return scripting_ops ? scripting_ops->flush_script() : 0;
690} 869}
691 870
692static int cleanup_scripting(void) 871static int cleanup_scripting(void)
693{ 872{
694 pr_debug("\nperf script stopped\n"); 873 pr_debug("\nperf script stopped\n");
695 874
696 return scripting_ops->stop_script(); 875 return scripting_ops ? scripting_ops->stop_script() : 0;
697} 876}
698 877
699static int process_sample_event(struct perf_tool *tool __maybe_unused, 878static int process_sample_event(struct perf_tool *tool,
700 union perf_event *event, 879 union perf_event *event,
701 struct perf_sample *sample, 880 struct perf_sample *sample,
702 struct perf_evsel *evsel, 881 struct perf_evsel *evsel,
703 struct machine *machine) 882 struct machine *machine)
704{ 883{
884 struct perf_script *scr = container_of(tool, struct perf_script, tool);
705 struct addr_location al; 885 struct addr_location al;
706 886
707 if (debug_mode) { 887 if (debug_mode) {
@@ -715,7 +895,7 @@ static int process_sample_event(struct perf_tool *tool __maybe_unused,
715 return 0; 895 return 0;
716 } 896 }
717 897
718 if (perf_event__preprocess_sample(event, machine, &al, sample) < 0) { 898 if (machine__resolve(machine, &al, sample) < 0) {
719 pr_err("problem processing %d event, skipping it.\n", 899 pr_err("problem processing %d event, skipping it.\n",
720 event->header.type); 900 event->header.type);
721 return -1; 901 return -1;
@@ -727,20 +907,16 @@ static int process_sample_event(struct perf_tool *tool __maybe_unused,
727 if (cpu_list && !test_bit(sample->cpu, cpu_bitmap)) 907 if (cpu_list && !test_bit(sample->cpu, cpu_bitmap))
728 goto out_put; 908 goto out_put;
729 909
730 scripting_ops->process_event(event, sample, evsel, &al); 910 if (scripting_ops)
911 scripting_ops->process_event(event, sample, evsel, &al);
912 else
913 process_event(scr, sample, evsel, &al);
914
731out_put: 915out_put:
732 addr_location__put(&al); 916 addr_location__put(&al);
733 return 0; 917 return 0;
734} 918}
735 919
736struct perf_script {
737 struct perf_tool tool;
738 struct perf_session *session;
739 bool show_task_events;
740 bool show_mmap_events;
741 bool show_switch_events;
742};
743
744static int process_attr(struct perf_tool *tool, union perf_event *event, 920static int process_attr(struct perf_tool *tool, union perf_event *event,
745 struct perf_evlist **pevlist) 921 struct perf_evlist **pevlist)
746{ 922{
@@ -1026,23 +1202,6 @@ static struct script_spec *script_spec__find(const char *spec)
1026 return NULL; 1202 return NULL;
1027} 1203}
1028 1204
1029static struct script_spec *script_spec__findnew(const char *spec,
1030 struct scripting_ops *ops)
1031{
1032 struct script_spec *s = script_spec__find(spec);
1033
1034 if (s)
1035 return s;
1036
1037 s = script_spec__new(spec, ops);
1038 if (!s)
1039 return NULL;
1040
1041 script_spec__add(s);
1042
1043 return s;
1044}
1045
1046int script_spec_register(const char *spec, struct scripting_ops *ops) 1205int script_spec_register(const char *spec, struct scripting_ops *ops)
1047{ 1206{
1048 struct script_spec *s; 1207 struct script_spec *s;
@@ -1051,9 +1210,11 @@ int script_spec_register(const char *spec, struct scripting_ops *ops)
1051 if (s) 1210 if (s)
1052 return -1; 1211 return -1;
1053 1212
1054 s = script_spec__findnew(spec, ops); 1213 s = script_spec__new(spec, ops);
1055 if (!s) 1214 if (!s)
1056 return -1; 1215 return -1;
1216 else
1217 script_spec__add(s);
1057 1218
1058 return 0; 1219 return 0;
1059} 1220}
@@ -1156,6 +1317,8 @@ static int parse_output_fields(const struct option *opt __maybe_unused,
1156 type = PERF_TYPE_TRACEPOINT; 1317 type = PERF_TYPE_TRACEPOINT;
1157 else if (!strcmp(str, "raw")) 1318 else if (!strcmp(str, "raw"))
1158 type = PERF_TYPE_RAW; 1319 type = PERF_TYPE_RAW;
1320 else if (!strcmp(str, "break"))
1321 type = PERF_TYPE_BREAKPOINT;
1159 else { 1322 else {
1160 fprintf(stderr, "Invalid event type in field string.\n"); 1323 fprintf(stderr, "Invalid event type in field string.\n");
1161 rc = -EINVAL; 1324 rc = -EINVAL;
@@ -1421,7 +1584,7 @@ static int list_available_scripts(const struct option *opt __maybe_unused,
1421 char first_half[BUFSIZ]; 1584 char first_half[BUFSIZ];
1422 char *script_root; 1585 char *script_root;
1423 1586
1424 snprintf(scripts_path, MAXPATHLEN, "%s/scripts", perf_exec_path()); 1587 snprintf(scripts_path, MAXPATHLEN, "%s/scripts", get_argv_exec_path());
1425 1588
1426 scripts_dir = opendir(scripts_path); 1589 scripts_dir = opendir(scripts_path);
1427 if (!scripts_dir) 1590 if (!scripts_dir)
@@ -1542,7 +1705,7 @@ int find_scripts(char **scripts_array, char **scripts_path_array)
1542 if (!session) 1705 if (!session)
1543 return -1; 1706 return -1;
1544 1707
1545 snprintf(scripts_path, MAXPATHLEN, "%s/scripts", perf_exec_path()); 1708 snprintf(scripts_path, MAXPATHLEN, "%s/scripts", get_argv_exec_path());
1546 1709
1547 scripts_dir = opendir(scripts_path); 1710 scripts_dir = opendir(scripts_path);
1548 if (!scripts_dir) { 1711 if (!scripts_dir) {
@@ -1600,7 +1763,7 @@ static char *get_script_path(const char *script_root, const char *suffix)
1600 char lang_path[MAXPATHLEN]; 1763 char lang_path[MAXPATHLEN];
1601 char *__script_root; 1764 char *__script_root;
1602 1765
1603 snprintf(scripts_path, MAXPATHLEN, "%s/scripts", perf_exec_path()); 1766 snprintf(scripts_path, MAXPATHLEN, "%s/scripts", get_argv_exec_path());
1604 1767
1605 scripts_dir = opendir(scripts_path); 1768 scripts_dir = opendir(scripts_path);
1606 if (!scripts_dir) 1769 if (!scripts_dir)
@@ -1695,6 +1858,87 @@ static void script__setup_sample_type(struct perf_script *script)
1695 } 1858 }
1696} 1859}
1697 1860
1861static int process_stat_round_event(struct perf_tool *tool __maybe_unused,
1862 union perf_event *event,
1863 struct perf_session *session)
1864{
1865 struct stat_round_event *round = &event->stat_round;
1866 struct perf_evsel *counter;
1867
1868 evlist__for_each(session->evlist, counter) {
1869 perf_stat_process_counter(&stat_config, counter);
1870 process_stat(counter, round->time);
1871 }
1872
1873 process_stat_interval(round->time);
1874 return 0;
1875}
1876
1877static int process_stat_config_event(struct perf_tool *tool __maybe_unused,
1878 union perf_event *event,
1879 struct perf_session *session __maybe_unused)
1880{
1881 perf_event__read_stat_config(&stat_config, &event->stat_config);
1882 return 0;
1883}
1884
1885static int set_maps(struct perf_script *script)
1886{
1887 struct perf_evlist *evlist = script->session->evlist;
1888
1889 if (!script->cpus || !script->threads)
1890 return 0;
1891
1892 if (WARN_ONCE(script->allocated, "stats double allocation\n"))
1893 return -EINVAL;
1894
1895 perf_evlist__set_maps(evlist, script->cpus, script->threads);
1896
1897 if (perf_evlist__alloc_stats(evlist, true))
1898 return -ENOMEM;
1899
1900 script->allocated = true;
1901 return 0;
1902}
1903
1904static
1905int process_thread_map_event(struct perf_tool *tool,
1906 union perf_event *event,
1907 struct perf_session *session __maybe_unused)
1908{
1909 struct perf_script *script = container_of(tool, struct perf_script, tool);
1910
1911 if (script->threads) {
1912 pr_warning("Extra thread map event, ignoring.\n");
1913 return 0;
1914 }
1915
1916 script->threads = thread_map__new_event(&event->thread_map);
1917 if (!script->threads)
1918 return -ENOMEM;
1919
1920 return set_maps(script);
1921}
1922
1923static
1924int process_cpu_map_event(struct perf_tool *tool __maybe_unused,
1925 union perf_event *event,
1926 struct perf_session *session __maybe_unused)
1927{
1928 struct perf_script *script = container_of(tool, struct perf_script, tool);
1929
1930 if (script->cpus) {
1931 pr_warning("Extra cpu map event, ignoring.\n");
1932 return 0;
1933 }
1934
1935 script->cpus = cpu_map__new_data(&event->cpu_map.data);
1936 if (!script->cpus)
1937 return -ENOMEM;
1938
1939 return set_maps(script);
1940}
1941
1698int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused) 1942int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused)
1699{ 1943{
1700 bool show_full_info = false; 1944 bool show_full_info = false;
@@ -1723,6 +1967,11 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused)
1723 .auxtrace_info = perf_event__process_auxtrace_info, 1967 .auxtrace_info = perf_event__process_auxtrace_info,
1724 .auxtrace = perf_event__process_auxtrace, 1968 .auxtrace = perf_event__process_auxtrace,
1725 .auxtrace_error = perf_event__process_auxtrace_error, 1969 .auxtrace_error = perf_event__process_auxtrace_error,
1970 .stat = perf_event__process_stat_event,
1971 .stat_round = process_stat_round_event,
1972 .stat_config = process_stat_config_event,
1973 .thread_map = process_thread_map_event,
1974 .cpu_map = process_cpu_map_event,
1726 .ordered_events = true, 1975 .ordered_events = true,
1727 .ordering_requires_timestamps = true, 1976 .ordering_requires_timestamps = true,
1728 }, 1977 },
@@ -1836,7 +2085,7 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused)
1836 scripting_max_stack = itrace_synth_opts.callchain_sz; 2085 scripting_max_stack = itrace_synth_opts.callchain_sz;
1837 2086
1838 /* make sure PERF_EXEC_PATH is set for scripts */ 2087 /* make sure PERF_EXEC_PATH is set for scripts */
1839 perf_set_argv_exec_path(perf_exec_path()); 2088 set_argv_exec_path(get_argv_exec_path());
1840 2089
1841 if (argc && !script_name && !rec_script_path && !rep_script_path) { 2090 if (argc && !script_name && !rec_script_path && !rep_script_path) {
1842 int live_pipe[2]; 2091 int live_pipe[2];
@@ -2076,6 +2325,7 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused)
2076 flush_scripting(); 2325 flush_scripting();
2077 2326
2078out_delete: 2327out_delete:
2328 perf_evlist__free_stats(session->evlist);
2079 perf_session__delete(session); 2329 perf_session__delete(session);
2080 2330
2081 if (script_started) 2331 if (script_started)
diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c
index 2f438f76cceb..1f19f2f999c8 100644
--- a/tools/perf/builtin-stat.c
+++ b/tools/perf/builtin-stat.c
@@ -45,7 +45,7 @@
45#include "builtin.h" 45#include "builtin.h"
46#include "util/cgroup.h" 46#include "util/cgroup.h"
47#include "util/util.h" 47#include "util/util.h"
48#include "util/parse-options.h" 48#include <subcmd/parse-options.h>
49#include "util/parse-events.h" 49#include "util/parse-events.h"
50#include "util/pmu.h" 50#include "util/pmu.h"
51#include "util/event.h" 51#include "util/event.h"
@@ -59,6 +59,9 @@
59#include "util/thread.h" 59#include "util/thread.h"
60#include "util/thread_map.h" 60#include "util/thread_map.h"
61#include "util/counts.h" 61#include "util/counts.h"
62#include "util/session.h"
63#include "util/tool.h"
64#include "asm/bug.h"
62 65
63#include <stdlib.h> 66#include <stdlib.h>
64#include <sys/prctl.h> 67#include <sys/prctl.h>
@@ -119,9 +122,28 @@ static bool sync_run = false;
119static unsigned int initial_delay = 0; 122static unsigned int initial_delay = 0;
120static unsigned int unit_width = 4; /* strlen("unit") */ 123static unsigned int unit_width = 4; /* strlen("unit") */
121static bool forever = false; 124static bool forever = false;
125static bool metric_only = false;
122static struct timespec ref_time; 126static struct timespec ref_time;
123static struct cpu_map *aggr_map; 127static struct cpu_map *aggr_map;
124static aggr_get_id_t aggr_get_id; 128static aggr_get_id_t aggr_get_id;
129static bool append_file;
130static const char *output_name;
131static int output_fd;
132
133struct perf_stat {
134 bool record;
135 struct perf_data_file file;
136 struct perf_session *session;
137 u64 bytes_written;
138 struct perf_tool tool;
139 bool maps_allocated;
140 struct cpu_map *cpus;
141 struct thread_map *threads;
142 enum aggr_mode aggr_mode;
143};
144
145static struct perf_stat perf_stat;
146#define STAT_RECORD perf_stat.record
125 147
126static volatile int done = 0; 148static volatile int done = 0;
127 149
@@ -158,15 +180,43 @@ static int create_perf_stat_counter(struct perf_evsel *evsel)
158 180
159 attr->inherit = !no_inherit; 181 attr->inherit = !no_inherit;
160 182
161 if (target__has_cpu(&target)) 183 /*
162 return perf_evsel__open_per_cpu(evsel, perf_evsel__cpus(evsel)); 184 * Some events get initialized with sample_(period/type) set,
185 * like tracepoints. Clear it up for counting.
186 */
187 attr->sample_period = 0;
163 188
164 if (!target__has_task(&target) && perf_evsel__is_group_leader(evsel)) { 189 /*
190 * But set sample_type to PERF_SAMPLE_IDENTIFIER, which should be harmless
191 * while avoiding that older tools show confusing messages.
192 *
193 * However for pipe sessions we need to keep it zero,
194 * because script's perf_evsel__check_attr is triggered
195 * by attr->sample_type != 0, and we can't run it on
196 * stat sessions.
197 */
198 if (!(STAT_RECORD && perf_stat.file.is_pipe))
199 attr->sample_type = PERF_SAMPLE_IDENTIFIER;
200
201 /*
202 * Disabling all counters initially, they will be enabled
203 * either manually by us or by kernel via enable_on_exec
204 * set later.
205 */
206 if (perf_evsel__is_group_leader(evsel)) {
165 attr->disabled = 1; 207 attr->disabled = 1;
166 if (!initial_delay) 208
209 /*
210 * In case of initial_delay we enable tracee
211 * events manually.
212 */
213 if (target__none(&target) && !initial_delay)
167 attr->enable_on_exec = 1; 214 attr->enable_on_exec = 1;
168 } 215 }
169 216
217 if (target__has_cpu(&target))
218 return perf_evsel__open_per_cpu(evsel, perf_evsel__cpus(evsel));
219
170 return perf_evsel__open_per_thread(evsel, evsel_list->threads); 220 return perf_evsel__open_per_thread(evsel, evsel_list->threads);
171} 221}
172 222
@@ -182,6 +232,42 @@ static inline int nsec_counter(struct perf_evsel *evsel)
182 return 0; 232 return 0;
183} 233}
184 234
235static int process_synthesized_event(struct perf_tool *tool __maybe_unused,
236 union perf_event *event,
237 struct perf_sample *sample __maybe_unused,
238 struct machine *machine __maybe_unused)
239{
240 if (perf_data_file__write(&perf_stat.file, event, event->header.size) < 0) {
241 pr_err("failed to write perf data, error: %m\n");
242 return -1;
243 }
244
245 perf_stat.bytes_written += event->header.size;
246 return 0;
247}
248
249static int write_stat_round_event(u64 tm, u64 type)
250{
251 return perf_event__synthesize_stat_round(NULL, tm, type,
252 process_synthesized_event,
253 NULL);
254}
255
256#define WRITE_STAT_ROUND_EVENT(time, interval) \
257 write_stat_round_event(time, PERF_STAT_ROUND_TYPE__ ## interval)
258
259#define SID(e, x, y) xyarray__entry(e->sample_id, x, y)
260
261static int
262perf_evsel__write_stat_event(struct perf_evsel *counter, u32 cpu, u32 thread,
263 struct perf_counts_values *count)
264{
265 struct perf_sample_id *sid = SID(counter, cpu, thread);
266
267 return perf_event__synthesize_stat(NULL, cpu, thread, sid->id, count,
268 process_synthesized_event, NULL);
269}
270
185/* 271/*
186 * Read out the results of a single counter: 272 * Read out the results of a single counter:
187 * do not aggregate counts across CPUs in system-wide mode 273 * do not aggregate counts across CPUs in system-wide mode
@@ -205,6 +291,13 @@ static int read_counter(struct perf_evsel *counter)
205 count = perf_counts(counter->counts, cpu, thread); 291 count = perf_counts(counter->counts, cpu, thread);
206 if (perf_evsel__read(counter, cpu, thread, count)) 292 if (perf_evsel__read(counter, cpu, thread, count))
207 return -1; 293 return -1;
294
295 if (STAT_RECORD) {
296 if (perf_evsel__write_stat_event(counter, cpu, thread, count)) {
297 pr_err("failed to write stat event\n");
298 return -1;
299 }
300 }
208 } 301 }
209 } 302 }
210 303
@@ -238,21 +331,26 @@ static void process_interval(void)
238 clock_gettime(CLOCK_MONOTONIC, &ts); 331 clock_gettime(CLOCK_MONOTONIC, &ts);
239 diff_timespec(&rs, &ts, &ref_time); 332 diff_timespec(&rs, &ts, &ref_time);
240 333
334 if (STAT_RECORD) {
335 if (WRITE_STAT_ROUND_EVENT(rs.tv_sec * NSECS_PER_SEC + rs.tv_nsec, INTERVAL))
336 pr_err("failed to write stat round event\n");
337 }
338
241 print_counters(&rs, 0, NULL); 339 print_counters(&rs, 0, NULL);
242} 340}
243 341
244static void handle_initial_delay(void) 342static void enable_counters(void)
245{ 343{
246 struct perf_evsel *counter; 344 if (initial_delay)
247
248 if (initial_delay) {
249 const int ncpus = cpu_map__nr(evsel_list->cpus),
250 nthreads = thread_map__nr(evsel_list->threads);
251
252 usleep(initial_delay * 1000); 345 usleep(initial_delay * 1000);
253 evlist__for_each(evsel_list, counter) 346
254 perf_evsel__enable(counter, ncpus, nthreads); 347 /*
255 } 348 * We need to enable counters only if:
349 * - we don't have tracee (attaching to task or cpu)
350 * - we have initial delay configured
351 */
352 if (!target__none(&target) || initial_delay)
353 perf_evlist__enable(evsel_list);
256} 354}
257 355
258static volatile int workload_exec_errno; 356static volatile int workload_exec_errno;
@@ -268,6 +366,135 @@ static void workload_exec_failed_signal(int signo __maybe_unused, siginfo_t *inf
268 workload_exec_errno = info->si_value.sival_int; 366 workload_exec_errno = info->si_value.sival_int;
269} 367}
270 368
369static bool has_unit(struct perf_evsel *counter)
370{
371 return counter->unit && *counter->unit;
372}
373
374static bool has_scale(struct perf_evsel *counter)
375{
376 return counter->scale != 1;
377}
378
379static int perf_stat_synthesize_config(bool is_pipe)
380{
381 struct perf_evsel *counter;
382 int err;
383
384 if (is_pipe) {
385 err = perf_event__synthesize_attrs(NULL, perf_stat.session,
386 process_synthesized_event);
387 if (err < 0) {
388 pr_err("Couldn't synthesize attrs.\n");
389 return err;
390 }
391 }
392
393 /*
394 * Synthesize other events stuff not carried within
395 * attr event - unit, scale, name
396 */
397 evlist__for_each(evsel_list, counter) {
398 if (!counter->supported)
399 continue;
400
401 /*
402 * Synthesize unit and scale only if it's defined.
403 */
404 if (has_unit(counter)) {
405 err = perf_event__synthesize_event_update_unit(NULL, counter, process_synthesized_event);
406 if (err < 0) {
407 pr_err("Couldn't synthesize evsel unit.\n");
408 return err;
409 }
410 }
411
412 if (has_scale(counter)) {
413 err = perf_event__synthesize_event_update_scale(NULL, counter, process_synthesized_event);
414 if (err < 0) {
415 pr_err("Couldn't synthesize evsel scale.\n");
416 return err;
417 }
418 }
419
420 if (counter->own_cpus) {
421 err = perf_event__synthesize_event_update_cpus(NULL, counter, process_synthesized_event);
422 if (err < 0) {
423 pr_err("Couldn't synthesize evsel scale.\n");
424 return err;
425 }
426 }
427
428 /*
429 * Name is needed only for pipe output,
430 * perf.data carries event names.
431 */
432 if (is_pipe) {
433 err = perf_event__synthesize_event_update_name(NULL, counter, process_synthesized_event);
434 if (err < 0) {
435 pr_err("Couldn't synthesize evsel name.\n");
436 return err;
437 }
438 }
439 }
440
441 err = perf_event__synthesize_thread_map2(NULL, evsel_list->threads,
442 process_synthesized_event,
443 NULL);
444 if (err < 0) {
445 pr_err("Couldn't synthesize thread map.\n");
446 return err;
447 }
448
449 err = perf_event__synthesize_cpu_map(NULL, evsel_list->cpus,
450 process_synthesized_event, NULL);
451 if (err < 0) {
452 pr_err("Couldn't synthesize thread map.\n");
453 return err;
454 }
455
456 err = perf_event__synthesize_stat_config(NULL, &stat_config,
457 process_synthesized_event, NULL);
458 if (err < 0) {
459 pr_err("Couldn't synthesize config.\n");
460 return err;
461 }
462
463 return 0;
464}
465
466#define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y))
467
468static int __store_counter_ids(struct perf_evsel *counter,
469 struct cpu_map *cpus,
470 struct thread_map *threads)
471{
472 int cpu, thread;
473
474 for (cpu = 0; cpu < cpus->nr; cpu++) {
475 for (thread = 0; thread < threads->nr; thread++) {
476 int fd = FD(counter, cpu, thread);
477
478 if (perf_evlist__id_add_fd(evsel_list, counter,
479 cpu, thread, fd) < 0)
480 return -1;
481 }
482 }
483
484 return 0;
485}
486
487static int store_counter_ids(struct perf_evsel *counter)
488{
489 struct cpu_map *cpus = counter->cpus;
490 struct thread_map *threads = counter->threads;
491
492 if (perf_evsel__alloc_id(counter, cpus->nr, threads->nr))
493 return -ENOMEM;
494
495 return __store_counter_ids(counter, cpus, threads);
496}
497
271static int __run_perf_stat(int argc, const char **argv) 498static int __run_perf_stat(int argc, const char **argv)
272{ 499{
273 int interval = stat_config.interval; 500 int interval = stat_config.interval;
@@ -278,6 +505,7 @@ static int __run_perf_stat(int argc, const char **argv)
278 size_t l; 505 size_t l;
279 int status = 0; 506 int status = 0;
280 const bool forks = (argc > 0); 507 const bool forks = (argc > 0);
508 bool is_pipe = STAT_RECORD ? perf_stat.file.is_pipe : false;
281 509
282 if (interval) { 510 if (interval) {
283 ts.tv_sec = interval / 1000; 511 ts.tv_sec = interval / 1000;
@@ -288,7 +516,7 @@ static int __run_perf_stat(int argc, const char **argv)
288 } 516 }
289 517
290 if (forks) { 518 if (forks) {
291 if (perf_evlist__prepare_workload(evsel_list, &target, argv, false, 519 if (perf_evlist__prepare_workload(evsel_list, &target, argv, is_pipe,
292 workload_exec_failed_signal) < 0) { 520 workload_exec_failed_signal) < 0) {
293 perror("failed to prepare workload"); 521 perror("failed to prepare workload");
294 return -1; 522 return -1;
@@ -332,6 +560,9 @@ static int __run_perf_stat(int argc, const char **argv)
332 l = strlen(counter->unit); 560 l = strlen(counter->unit);
333 if (l > unit_width) 561 if (l > unit_width)
334 unit_width = l; 562 unit_width = l;
563
564 if (STAT_RECORD && store_counter_ids(counter))
565 return -1;
335 } 566 }
336 567
337 if (perf_evlist__apply_filters(evsel_list, &counter)) { 568 if (perf_evlist__apply_filters(evsel_list, &counter)) {
@@ -341,6 +572,24 @@ static int __run_perf_stat(int argc, const char **argv)
341 return -1; 572 return -1;
342 } 573 }
343 574
575 if (STAT_RECORD) {
576 int err, fd = perf_data_file__fd(&perf_stat.file);
577
578 if (is_pipe) {
579 err = perf_header__write_pipe(perf_data_file__fd(&perf_stat.file));
580 } else {
581 err = perf_session__write_header(perf_stat.session, evsel_list,
582 fd, false);
583 }
584
585 if (err < 0)
586 return err;
587
588 err = perf_stat_synthesize_config(is_pipe);
589 if (err < 0)
590 return err;
591 }
592
344 /* 593 /*
345 * Enable counters and exec the command: 594 * Enable counters and exec the command:
346 */ 595 */
@@ -349,7 +598,7 @@ static int __run_perf_stat(int argc, const char **argv)
349 598
350 if (forks) { 599 if (forks) {
351 perf_evlist__start_workload(evsel_list); 600 perf_evlist__start_workload(evsel_list);
352 handle_initial_delay(); 601 enable_counters();
353 602
354 if (interval) { 603 if (interval) {
355 while (!waitpid(child_pid, &status, WNOHANG)) { 604 while (!waitpid(child_pid, &status, WNOHANG)) {
@@ -368,7 +617,7 @@ static int __run_perf_stat(int argc, const char **argv)
368 if (WIFSIGNALED(status)) 617 if (WIFSIGNALED(status))
369 psignal(WTERMSIG(status), argv[0]); 618 psignal(WTERMSIG(status), argv[0]);
370 } else { 619 } else {
371 handle_initial_delay(); 620 enable_counters();
372 while (!done) { 621 while (!done) {
373 nanosleep(&ts, NULL); 622 nanosleep(&ts, NULL);
374 if (interval) 623 if (interval)
@@ -487,6 +736,191 @@ static void aggr_printout(struct perf_evsel *evsel, int id, int nr)
487 } 736 }
488} 737}
489 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
490static 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)
491{ 925{
492 FILE *output = stat_config.output; 926 FILE *output = stat_config.output;
@@ -513,15 +947,28 @@ static void nsec_printout(int id, int nr, struct perf_evsel *evsel, double avg)
513 947
514 if (evsel->cgrp) 948 if (evsel->cgrp)
515 fprintf(output, "%s%s", csv_sep, evsel->cgrp->name); 949 fprintf(output, "%s%s", csv_sep, evsel->cgrp->name);
950}
516 951
517 if (csv_output || stat_config.interval) 952static int first_shadow_cpu(struct perf_evsel *evsel, int id)
518 return; 953{
954 int i;
519 955
520 if (perf_evsel__match(evsel, SOFTWARE, SW_TASK_CLOCK)) 956 if (!aggr_get_id)
521 fprintf(output, " # %8.3f CPUs utilized ", 957 return 0;
522 avg / avg_stats(&walltime_nsecs_stats)); 958
523 else 959 if (stat_config.aggr_mode == AGGR_NONE)
524 fprintf(output, " "); 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;
525} 972}
526 973
527static 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)
@@ -529,7 +976,6 @@ static void abs_printout(int id, int nr, struct perf_evsel *evsel, double avg)
529 FILE *output = stat_config.output; 976 FILE *output = stat_config.output;
530 double sc = evsel->scale; 977 double sc = evsel->scale;
531 const char *fmt; 978 const char *fmt;
532 int cpu = cpu_map__id_to_cpu(id);
533 979
534 if (csv_output) { 980 if (csv_output) {
535 fmt = sc != 1.0 ? "%.2f%s" : "%.0f%s"; 981 fmt = sc != 1.0 ? "%.2f%s" : "%.0f%s";
@@ -542,9 +988,6 @@ static void abs_printout(int id, int nr, struct perf_evsel *evsel, double avg)
542 988
543 aggr_printout(evsel, id, nr); 989 aggr_printout(evsel, id, nr);
544 990
545 if (stat_config.aggr_mode == AGGR_GLOBAL)
546 cpu = 0;
547
548 fprintf(output, fmt, avg, csv_sep); 991 fprintf(output, fmt, avg, csv_sep);
549 992
550 if (evsel->unit) 993 if (evsel->unit)
@@ -556,12 +999,126 @@ static void abs_printout(int id, int nr, struct perf_evsel *evsel, double avg)
556 999
557 if (evsel->cgrp) 1000 if (evsel->cgrp)
558 fprintf(output, "%s%s", csv_sep, evsel->cgrp->name); 1001 fprintf(output, "%s%s", csv_sep, evsel->cgrp->name);
1002}
1003
1004static void printout(int id, int nr, struct perf_evsel *counter, double uval,
1005 char *prefix, u64 run, u64 ena, double noise)
1006{
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 *);
1017
1018 if (metric_only) {
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);
559 1066
560 if (csv_output || stat_config.interval) 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);
561 return; 1073 return;
1074 }
1075
1076 if (metric_only)
1077 /* nothing */;
1078 else if (nsec_counter(counter))
1079 nsec_printout(id, nr, counter, uval);
1080 else
1081 abs_printout(id, nr, counter, uval);
562 1082
563 perf_stat__print_shadow_stats(output, evsel, avg, cpu, 1083 out.print_metric = pm;
564 stat_config.aggr_mode); 1084 out.new_line = nl;
1085 out.ctx = &os;
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 }
565} 1122}
566 1123
567static void print_aggr(char *prefix) 1124static void print_aggr(char *prefix)
@@ -571,12 +1128,23 @@ static void print_aggr(char *prefix)
571 int cpu, s, s2, id, nr; 1128 int cpu, s, s2, id, nr;
572 double uval; 1129 double uval;
573 u64 ena, run, val; 1130 u64 ena, run, val;
1131 bool first;
574 1132
575 if (!(aggr_map || aggr_get_id)) 1133 if (!(aggr_map || aggr_get_id))
576 return; 1134 return;
577 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 */
578 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
579 id = aggr_map->map[s]; 1146 id = aggr_map->map[s];
1147 first = true;
580 evlist__for_each(evsel_list, counter) { 1148 evlist__for_each(evsel_list, counter) {
581 val = ena = run = 0; 1149 val = ena = run = 0;
582 nr = 0; 1150 nr = 0;
@@ -589,46 +1157,20 @@ static void print_aggr(char *prefix)
589 run += perf_counts(counter->counts, cpu, 0)->run; 1157 run += perf_counts(counter->counts, cpu, 0)->run;
590 nr++; 1158 nr++;
591 } 1159 }
592 if (prefix) 1160 if (first && metric_only) {
593 fprintf(output, "%s", prefix); 1161 first = false;
594
595 if (run == 0 || ena == 0) {
596 aggr_printout(counter, id, nr); 1162 aggr_printout(counter, id, nr);
597
598 fprintf(output, "%*s%s",
599 csv_output ? 0 : 18,
600 counter->supported ? CNTR_NOT_COUNTED : CNTR_NOT_SUPPORTED,
601 csv_sep);
602
603 fprintf(output, "%-*s%s",
604 csv_output ? 0 : unit_width,
605 counter->unit, csv_sep);
606
607 fprintf(output, "%*s",
608 csv_output ? 0 : -25,
609 perf_evsel__name(counter));
610
611 if (counter->cgrp)
612 fprintf(output, "%s%s",
613 csv_sep, counter->cgrp->name);
614
615 print_running(run, ena);
616 fputc('\n', output);
617 continue;
618 } 1163 }
619 uval = val * counter->scale; 1164 if (prefix && !metric_only)
620 1165 fprintf(output, "%s", prefix);
621 if (nsec_counter(counter))
622 nsec_printout(id, nr, counter, uval);
623 else
624 abs_printout(id, nr, counter, uval);
625
626 if (!csv_output)
627 print_noise(counter, 1.0);
628 1166
629 print_running(run, ena); 1167 uval = val * counter->scale;
630 fputc('\n', output); 1168 printout(id, nr, counter, uval, prefix, run, ena, 1.0);
1169 if (!metric_only)
1170 fputc('\n', output);
631 } 1171 }
1172 if (metric_only)
1173 fputc('\n', output);
632 } 1174 }
633} 1175}
634 1176
@@ -653,16 +1195,7 @@ static void print_aggr_thread(struct perf_evsel *counter, char *prefix)
653 fprintf(output, "%s", prefix); 1195 fprintf(output, "%s", prefix);
654 1196
655 uval = val * counter->scale; 1197 uval = val * counter->scale;
656 1198 printout(thread, 0, counter, uval, prefix, run, ena, 1.0);
657 if (nsec_counter(counter))
658 nsec_printout(thread, 0, counter, uval);
659 else
660 abs_printout(thread, 0, counter, uval);
661
662 if (!csv_output)
663 print_noise(counter, 1.0);
664
665 print_running(run, ena);
666 fputc('\n', output); 1199 fputc('\n', output);
667 } 1200 }
668} 1201}
@@ -676,47 +1209,19 @@ static void print_counter_aggr(struct perf_evsel *counter, char *prefix)
676 FILE *output = stat_config.output; 1209 FILE *output = stat_config.output;
677 struct perf_stat_evsel *ps = counter->priv; 1210 struct perf_stat_evsel *ps = counter->priv;
678 double avg = avg_stats(&ps->res_stats[0]); 1211 double avg = avg_stats(&ps->res_stats[0]);
679 int scaled = counter->counts->scaled;
680 double uval; 1212 double uval;
681 double avg_enabled, avg_running; 1213 double avg_enabled, avg_running;
682 1214
683 avg_enabled = avg_stats(&ps->res_stats[1]); 1215 avg_enabled = avg_stats(&ps->res_stats[1]);
684 avg_running = avg_stats(&ps->res_stats[2]); 1216 avg_running = avg_stats(&ps->res_stats[2]);
685 1217
686 if (prefix) 1218 if (prefix && !metric_only)
687 fprintf(output, "%s", prefix); 1219 fprintf(output, "%s", prefix);
688 1220
689 if (scaled == -1 || !counter->supported) {
690 fprintf(output, "%*s%s",
691 csv_output ? 0 : 18,
692 counter->supported ? CNTR_NOT_COUNTED : CNTR_NOT_SUPPORTED,
693 csv_sep);
694 fprintf(output, "%-*s%s",
695 csv_output ? 0 : unit_width,
696 counter->unit, csv_sep);
697 fprintf(output, "%*s",
698 csv_output ? 0 : -25,
699 perf_evsel__name(counter));
700
701 if (counter->cgrp)
702 fprintf(output, "%s%s", csv_sep, counter->cgrp->name);
703
704 print_running(avg_running, avg_enabled);
705 fputc('\n', output);
706 return;
707 }
708
709 uval = avg * counter->scale; 1221 uval = avg * counter->scale;
710 1222 printout(-1, 0, counter, uval, prefix, avg_running, avg_enabled, avg);
711 if (nsec_counter(counter)) 1223 if (!metric_only)
712 nsec_printout(-1, 0, counter, uval); 1224 fprintf(output, "\n");
713 else
714 abs_printout(-1, 0, counter, uval);
715
716 print_noise(counter, avg);
717
718 print_running(avg_running, avg_enabled);
719 fprintf(output, "\n");
720} 1225}
721 1226
722/* 1227/*
@@ -738,44 +1243,78 @@ static void print_counter(struct perf_evsel *counter, char *prefix)
738 if (prefix) 1243 if (prefix)
739 fprintf(output, "%s", prefix); 1244 fprintf(output, "%s", prefix);
740 1245
741 if (run == 0 || ena == 0) { 1246 uval = val * counter->scale;
742 fprintf(output, "CPU%*d%s%*s%s", 1247 printout(cpu, 0, counter, uval, prefix, run, ena, 1.0);
743 csv_output ? 0 : -4,
744 perf_evsel__cpus(counter)->map[cpu], csv_sep,
745 csv_output ? 0 : 18,
746 counter->supported ? CNTR_NOT_COUNTED : CNTR_NOT_SUPPORTED,
747 csv_sep);
748 1248
749 fprintf(output, "%-*s%s", 1249 fputc('\n', output);
750 csv_output ? 0 : unit_width, 1250 }
751 counter->unit, csv_sep); 1251}
752 1252
753 fprintf(output, "%*s", 1253static void print_no_aggr_metric(char *prefix)
754 csv_output ? 0 : -25, 1254{
755 perf_evsel__name(counter)); 1255 int cpu;
1256 int nrcpus = 0;
1257 struct perf_evsel *counter;
1258 u64 ena, run, val;
1259 double uval;
756 1260
757 if (counter->cgrp) 1261 nrcpus = evsel_list->cpus->nr;
758 fprintf(output, "%s%s", 1262 for (cpu = 0; cpu < nrcpus; cpu++) {
759 csv_sep, counter->cgrp->name); 1263 bool first = true;
760 1264
761 print_running(run, ena); 1265 if (prefix)
762 fputc('\n', output); 1266 fputs(prefix, stat_config.output);
763 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);
764 } 1278 }
1279 fputc('\n', stat_config.output);
1280 }
1281}
765 1282
766 uval = val * counter->scale; 1283static int aggr_header_lens[] = {
1284 [AGGR_CORE] = 18,
1285 [AGGR_SOCKET] = 12,
1286 [AGGR_NONE] = 6,
1287 [AGGR_THREAD] = 24,
1288 [AGGR_GLOBAL] = 0,
1289};
767 1290
768 if (nsec_counter(counter)) 1291static void print_metric_headers(char *prefix)
769 nsec_printout(cpu, 0, counter, uval); 1292{
770 else 1293 struct perf_stat_output_ctx out;
771 abs_printout(cpu, 0, counter, uval); 1294 struct perf_evsel *counter;
1295 struct outstate os = {
1296 .fh = stat_config.output
1297 };
772 1298
773 if (!csv_output) 1299 if (prefix)
774 print_noise(counter, 1.0); 1300 fprintf(stat_config.output, "%s", prefix);
775 print_running(run, ena);
776 1301
777 fputc('\n', output); 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);
778 } 1316 }
1317 fputc('\n', stat_config.output);
779} 1318}
780 1319
781static void print_interval(char *prefix, struct timespec *ts) 1320static void print_interval(char *prefix, struct timespec *ts)
@@ -785,7 +1324,7 @@ static void print_interval(char *prefix, struct timespec *ts)
785 1324
786 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);
787 1326
788 if (num_print_interval == 0 && !csv_output) { 1327 if (num_print_interval == 0 && !csv_output && !metric_only) {
789 switch (stat_config.aggr_mode) { 1328 switch (stat_config.aggr_mode) {
790 case AGGR_SOCKET: 1329 case AGGR_SOCKET:
791 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");
@@ -826,8 +1365,8 @@ static void print_header(int argc, const char **argv)
826 else if (target.cpu_list) 1365 else if (target.cpu_list)
827 fprintf(output, "\'CPU(s) %s", target.cpu_list); 1366 fprintf(output, "\'CPU(s) %s", target.cpu_list);
828 else if (!target__has_task(&target)) { 1367 else if (!target__has_task(&target)) {
829 fprintf(output, "\'%s", argv[0]); 1368 fprintf(output, "\'%s", argv ? argv[0] : "pipe");
830 for (i = 1; i < argc; i++) 1369 for (i = 1; argv && (i < argc); i++)
831 fprintf(output, " %s", argv[i]); 1370 fprintf(output, " %s", argv[i]);
832 } else if (target.pid) 1371 } else if (target.pid)
833 fprintf(output, "process id \'%s", target.pid); 1372 fprintf(output, "process id \'%s", target.pid);
@@ -863,11 +1402,26 @@ static void print_counters(struct timespec *ts, int argc, const char **argv)
863 struct perf_evsel *counter; 1402 struct perf_evsel *counter;
864 char buf[64], *prefix = NULL; 1403 char buf[64], *prefix = NULL;
865 1404
1405 /* Do not print anything if we record to the pipe. */
1406 if (STAT_RECORD && perf_stat.file.is_pipe)
1407 return;
1408
866 if (interval) 1409 if (interval)
867 print_interval(prefix = buf, ts); 1410 print_interval(prefix = buf, ts);
868 else 1411 else
869 print_header(argc, argv); 1412 print_header(argc, argv);
870 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
871 switch (stat_config.aggr_mode) { 1425 switch (stat_config.aggr_mode) {
872 case AGGR_CORE: 1426 case AGGR_CORE:
873 case AGGR_SOCKET: 1427 case AGGR_SOCKET:
@@ -880,10 +1434,16 @@ static void print_counters(struct timespec *ts, int argc, const char **argv)
880 case AGGR_GLOBAL: 1434 case AGGR_GLOBAL:
881 evlist__for_each(evsel_list, counter) 1435 evlist__for_each(evsel_list, counter)
882 print_counter_aggr(counter, prefix); 1436 print_counter_aggr(counter, prefix);
1437 if (metric_only)
1438 fputc('\n', stat_config.output);
883 break; 1439 break;
884 case AGGR_NONE: 1440 case AGGR_NONE:
885 evlist__for_each(evsel_list, counter) 1441 if (metric_only)
886 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 }
887 break; 1447 break;
888 case AGGR_UNSET: 1448 case AGGR_UNSET:
889 default: 1449 default:
@@ -946,6 +1506,69 @@ static int stat__set_big_num(const struct option *opt __maybe_unused,
946 return 0; 1506 return 0;
947} 1507}
948 1508
1509static const struct option stat_options[] = {
1510 OPT_BOOLEAN('T', "transaction", &transaction_run,
1511 "hardware transaction statistics"),
1512 OPT_CALLBACK('e', "event", &evsel_list, "event",
1513 "event selector. use 'perf list' to list available events",
1514 parse_events_option),
1515 OPT_CALLBACK(0, "filter", &evsel_list, "filter",
1516 "event filter", parse_filter),
1517 OPT_BOOLEAN('i', "no-inherit", &no_inherit,
1518 "child tasks do not inherit counters"),
1519 OPT_STRING('p', "pid", &target.pid, "pid",
1520 "stat events on existing process id"),
1521 OPT_STRING('t', "tid", &target.tid, "tid",
1522 "stat events on existing thread id"),
1523 OPT_BOOLEAN('a', "all-cpus", &target.system_wide,
1524 "system-wide collection from all CPUs"),
1525 OPT_BOOLEAN('g', "group", &group,
1526 "put the counters into a counter group"),
1527 OPT_BOOLEAN('c', "scale", &stat_config.scale, "scale/normalize counters"),
1528 OPT_INCR('v', "verbose", &verbose,
1529 "be more verbose (show counter open errors, etc)"),
1530 OPT_INTEGER('r', "repeat", &run_count,
1531 "repeat command and print average + stddev (max: 100, forever: 0)"),
1532 OPT_BOOLEAN('n', "null", &null_run,
1533 "null run - dont start any counters"),
1534 OPT_INCR('d', "detailed", &detailed_run,
1535 "detailed run - start a lot of events"),
1536 OPT_BOOLEAN('S', "sync", &sync_run,
1537 "call sync() before starting a run"),
1538 OPT_CALLBACK_NOOPT('B', "big-num", NULL, NULL,
1539 "print large numbers with thousands\' separators",
1540 stat__set_big_num),
1541 OPT_STRING('C', "cpu", &target.cpu_list, "cpu",
1542 "list of cpus to monitor in system-wide"),
1543 OPT_SET_UINT('A', "no-aggr", &stat_config.aggr_mode,
1544 "disable CPU count aggregation", AGGR_NONE),
1545 OPT_STRING('x', "field-separator", &csv_sep, "separator",
1546 "print counts with custom separator"),
1547 OPT_CALLBACK('G', "cgroup", &evsel_list, "name",
1548 "monitor event in cgroup name only", parse_cgroups),
1549 OPT_STRING('o', "output", &output_name, "file", "output file name"),
1550 OPT_BOOLEAN(0, "append", &append_file, "append to the output file"),
1551 OPT_INTEGER(0, "log-fd", &output_fd,
1552 "log output to fd, instead of stderr"),
1553 OPT_STRING(0, "pre", &pre_cmd, "command",
1554 "command to run prior to the measured command"),
1555 OPT_STRING(0, "post", &post_cmd, "command",
1556 "command to run after to the measured command"),
1557 OPT_UINTEGER('I', "interval-print", &stat_config.interval,
1558 "print counts at regular interval in ms (>= 10)"),
1559 OPT_SET_UINT(0, "per-socket", &stat_config.aggr_mode,
1560 "aggregate counts per processor socket", AGGR_SOCKET),
1561 OPT_SET_UINT(0, "per-core", &stat_config.aggr_mode,
1562 "aggregate counts per physical processor core", AGGR_CORE),
1563 OPT_SET_UINT(0, "per-thread", &stat_config.aggr_mode,
1564 "aggregate counts per thread", AGGR_THREAD),
1565 OPT_UINTEGER('D', "delay", &initial_delay,
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"),
1569 OPT_END()
1570};
1571
949static int perf_stat__get_socket(struct cpu_map *map, int cpu) 1572static int perf_stat__get_socket(struct cpu_map *map, int cpu)
950{ 1573{
951 return cpu_map__get_socket(map, cpu, NULL); 1574 return cpu_map__get_socket(map, cpu, NULL);
@@ -1032,13 +1655,116 @@ static int perf_stat_init_aggr_mode(void)
1032 return cpus_aggr_map ? 0 : -ENOMEM; 1655 return cpus_aggr_map ? 0 : -ENOMEM;
1033} 1656}
1034 1657
1658static void perf_stat__exit_aggr_mode(void)
1659{
1660 cpu_map__put(aggr_map);
1661 cpu_map__put(cpus_aggr_map);
1662 aggr_map = NULL;
1663 cpus_aggr_map = NULL;
1664}
1665
1666static inline int perf_env__get_cpu(struct perf_env *env, struct cpu_map *map, int idx)
1667{
1668 int cpu;
1669
1670 if (idx > map->nr)
1671 return -1;
1672
1673 cpu = map->map[idx];
1674
1675 if (cpu >= env->nr_cpus_online)
1676 return -1;
1677
1678 return cpu;
1679}
1680
1681static int perf_env__get_socket(struct cpu_map *map, int idx, void *data)
1682{
1683 struct perf_env *env = data;
1684 int cpu = perf_env__get_cpu(env, map, idx);
1685
1686 return cpu == -1 ? -1 : env->cpu[cpu].socket_id;
1687}
1688
1689static int perf_env__get_core(struct cpu_map *map, int idx, void *data)
1690{
1691 struct perf_env *env = data;
1692 int core = -1, cpu = perf_env__get_cpu(env, map, idx);
1693
1694 if (cpu != -1) {
1695 int socket_id = env->cpu[cpu].socket_id;
1696
1697 /*
1698 * Encode socket in upper 16 bits
1699 * core_id is relative to socket, and
1700 * we need a global id. So we combine
1701 * socket + core id.
1702 */
1703 core = (socket_id << 16) | (env->cpu[cpu].core_id & 0xffff);
1704 }
1705
1706 return core;
1707}
1708
1709static int perf_env__build_socket_map(struct perf_env *env, struct cpu_map *cpus,
1710 struct cpu_map **sockp)
1711{
1712 return cpu_map__build_map(cpus, sockp, perf_env__get_socket, env);
1713}
1714
1715static int perf_env__build_core_map(struct perf_env *env, struct cpu_map *cpus,
1716 struct cpu_map **corep)
1717{
1718 return cpu_map__build_map(cpus, corep, perf_env__get_core, env);
1719}
1720
1721static int perf_stat__get_socket_file(struct cpu_map *map, int idx)
1722{
1723 return perf_env__get_socket(map, idx, &perf_stat.session->header.env);
1724}
1725
1726static int perf_stat__get_core_file(struct cpu_map *map, int idx)
1727{
1728 return perf_env__get_core(map, idx, &perf_stat.session->header.env);
1729}
1730
1731static int perf_stat_init_aggr_mode_file(struct perf_stat *st)
1732{
1733 struct perf_env *env = &st->session->header.env;
1734
1735 switch (stat_config.aggr_mode) {
1736 case AGGR_SOCKET:
1737 if (perf_env__build_socket_map(env, evsel_list->cpus, &aggr_map)) {
1738 perror("cannot build socket map");
1739 return -1;
1740 }
1741 aggr_get_id = perf_stat__get_socket_file;
1742 break;
1743 case AGGR_CORE:
1744 if (perf_env__build_core_map(env, evsel_list->cpus, &aggr_map)) {
1745 perror("cannot build core map");
1746 return -1;
1747 }
1748 aggr_get_id = perf_stat__get_core_file;
1749 break;
1750 case AGGR_NONE:
1751 case AGGR_GLOBAL:
1752 case AGGR_THREAD:
1753 case AGGR_UNSET:
1754 default:
1755 break;
1756 }
1757
1758 return 0;
1759}
1760
1035/* 1761/*
1036 * Add default attributes, if there were no attributes specified or 1762 * Add default attributes, if there were no attributes specified or
1037 * if -d/--detailed, -d -d or -d -d -d is used: 1763 * if -d/--detailed, -d -d or -d -d -d is used:
1038 */ 1764 */
1039static int add_default_attributes(void) 1765static int add_default_attributes(void)
1040{ 1766{
1041 struct perf_event_attr default_attrs[] = { 1767 struct perf_event_attr default_attrs0[] = {
1042 1768
1043 { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_TASK_CLOCK }, 1769 { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_TASK_CLOCK },
1044 { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_CONTEXT_SWITCHES }, 1770 { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_CONTEXT_SWITCHES },
@@ -1046,8 +1772,14 @@ static int add_default_attributes(void)
1046 { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_PAGE_FAULTS }, 1772 { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_PAGE_FAULTS },
1047 1773
1048 { .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[] = {
1049 { .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[] = {
1050 { .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[] = {
1051 { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_INSTRUCTIONS }, 1783 { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_INSTRUCTIONS },
1052 { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_BRANCH_INSTRUCTIONS }, 1784 { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_BRANCH_INSTRUCTIONS },
1053 { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_BRANCH_MISSES }, 1785 { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_BRANCH_MISSES },
@@ -1164,7 +1896,19 @@ static int add_default_attributes(void)
1164 } 1896 }
1165 1897
1166 if (!evsel_list->nr_entries) { 1898 if (!evsel_list->nr_entries) {
1167 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)
1168 return -1; 1912 return -1;
1169 } 1913 }
1170 1914
@@ -1191,71 +1935,227 @@ static int add_default_attributes(void)
1191 return perf_evlist__add_default_attrs(evsel_list, very_very_detailed_attrs); 1935 return perf_evlist__add_default_attrs(evsel_list, very_very_detailed_attrs);
1192} 1936}
1193 1937
1194int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused) 1938static const char * const stat_record_usage[] = {
1939 "perf stat record [<options>]",
1940 NULL,
1941};
1942
1943static void init_features(struct perf_session *session)
1944{
1945 int feat;
1946
1947 for (feat = HEADER_FIRST_FEATURE; feat < HEADER_LAST_FEATURE; feat++)
1948 perf_header__set_feat(&session->header, feat);
1949
1950 perf_header__clear_feat(&session->header, HEADER_BUILD_ID);
1951 perf_header__clear_feat(&session->header, HEADER_TRACING_DATA);
1952 perf_header__clear_feat(&session->header, HEADER_BRANCH_STACK);
1953 perf_header__clear_feat(&session->header, HEADER_AUXTRACE);
1954}
1955
1956static int __cmd_record(int argc, const char **argv)
1957{
1958 struct perf_session *session;
1959 struct perf_data_file *file = &perf_stat.file;
1960
1961 argc = parse_options(argc, argv, stat_options, stat_record_usage,
1962 PARSE_OPT_STOP_AT_NON_OPTION);
1963
1964 if (output_name)
1965 file->path = output_name;
1966
1967 if (run_count != 1 || forever) {
1968 pr_err("Cannot use -r option with perf stat record.\n");
1969 return -1;
1970 }
1971
1972 session = perf_session__new(file, false, NULL);
1973 if (session == NULL) {
1974 pr_err("Perf session creation failed.\n");
1975 return -1;
1976 }
1977
1978 init_features(session);
1979
1980 session->evlist = evsel_list;
1981 perf_stat.session = session;
1982 perf_stat.record = true;
1983 return argc;
1984}
1985
1986static int process_stat_round_event(struct perf_tool *tool __maybe_unused,
1987 union perf_event *event,
1988 struct perf_session *session)
1989{
1990 struct stat_round_event *round = &event->stat_round;
1991 struct perf_evsel *counter;
1992 struct timespec tsh, *ts = NULL;
1993 const char **argv = session->header.env.cmdline_argv;
1994 int argc = session->header.env.nr_cmdline;
1995
1996 evlist__for_each(evsel_list, counter)
1997 perf_stat_process_counter(&stat_config, counter);
1998
1999 if (round->type == PERF_STAT_ROUND_TYPE__FINAL)
2000 update_stats(&walltime_nsecs_stats, round->time);
2001
2002 if (stat_config.interval && round->time) {
2003 tsh.tv_sec = round->time / NSECS_PER_SEC;
2004 tsh.tv_nsec = round->time % NSECS_PER_SEC;
2005 ts = &tsh;
2006 }
2007
2008 print_counters(ts, argc, argv);
2009 return 0;
2010}
2011
2012static
2013int process_stat_config_event(struct perf_tool *tool __maybe_unused,
2014 union perf_event *event,
2015 struct perf_session *session __maybe_unused)
2016{
2017 struct perf_stat *st = container_of(tool, struct perf_stat, tool);
2018
2019 perf_event__read_stat_config(&stat_config, &event->stat_config);
2020
2021 if (cpu_map__empty(st->cpus)) {
2022 if (st->aggr_mode != AGGR_UNSET)
2023 pr_warning("warning: processing task data, aggregation mode not set\n");
2024 return 0;
2025 }
2026
2027 if (st->aggr_mode != AGGR_UNSET)
2028 stat_config.aggr_mode = st->aggr_mode;
2029
2030 if (perf_stat.file.is_pipe)
2031 perf_stat_init_aggr_mode();
2032 else
2033 perf_stat_init_aggr_mode_file(st);
2034
2035 return 0;
2036}
2037
2038static int set_maps(struct perf_stat *st)
2039{
2040 if (!st->cpus || !st->threads)
2041 return 0;
2042
2043 if (WARN_ONCE(st->maps_allocated, "stats double allocation\n"))
2044 return -EINVAL;
2045
2046 perf_evlist__set_maps(evsel_list, st->cpus, st->threads);
2047
2048 if (perf_evlist__alloc_stats(evsel_list, true))
2049 return -ENOMEM;
2050
2051 st->maps_allocated = true;
2052 return 0;
2053}
2054
2055static
2056int process_thread_map_event(struct perf_tool *tool __maybe_unused,
2057 union perf_event *event,
2058 struct perf_session *session __maybe_unused)
2059{
2060 struct perf_stat *st = container_of(tool, struct perf_stat, tool);
2061
2062 if (st->threads) {
2063 pr_warning("Extra thread map event, ignoring.\n");
2064 return 0;
2065 }
2066
2067 st->threads = thread_map__new_event(&event->thread_map);
2068 if (!st->threads)
2069 return -ENOMEM;
2070
2071 return set_maps(st);
2072}
2073
2074static
2075int process_cpu_map_event(struct perf_tool *tool __maybe_unused,
2076 union perf_event *event,
2077 struct perf_session *session __maybe_unused)
2078{
2079 struct perf_stat *st = container_of(tool, struct perf_stat, tool);
2080 struct cpu_map *cpus;
2081
2082 if (st->cpus) {
2083 pr_warning("Extra cpu map event, ignoring.\n");
2084 return 0;
2085 }
2086
2087 cpus = cpu_map__new_data(&event->cpu_map.data);
2088 if (!cpus)
2089 return -ENOMEM;
2090
2091 st->cpus = cpus;
2092 return set_maps(st);
2093}
2094
2095static const char * const stat_report_usage[] = {
2096 "perf stat report [<options>]",
2097 NULL,
2098};
2099
2100static struct perf_stat perf_stat = {
2101 .tool = {
2102 .attr = perf_event__process_attr,
2103 .event_update = perf_event__process_event_update,
2104 .thread_map = process_thread_map_event,
2105 .cpu_map = process_cpu_map_event,
2106 .stat_config = process_stat_config_event,
2107 .stat = perf_event__process_stat_event,
2108 .stat_round = process_stat_round_event,
2109 },
2110 .aggr_mode = AGGR_UNSET,
2111};
2112
2113static int __cmd_report(int argc, const char **argv)
1195{ 2114{
1196 bool append_file = false; 2115 struct perf_session *session;
1197 int output_fd = 0;
1198 const char *output_name = NULL;
1199 const struct option options[] = { 2116 const struct option options[] = {
1200 OPT_BOOLEAN('T', "transaction", &transaction_run, 2117 OPT_STRING('i', "input", &input_name, "file", "input file name"),
1201 "hardware transaction statistics"), 2118 OPT_SET_UINT(0, "per-socket", &perf_stat.aggr_mode,
1202 OPT_CALLBACK('e', "event", &evsel_list, "event",
1203 "event selector. use 'perf list' to list available events",
1204 parse_events_option),
1205 OPT_CALLBACK(0, "filter", &evsel_list, "filter",
1206 "event filter", parse_filter),
1207 OPT_BOOLEAN('i', "no-inherit", &no_inherit,
1208 "child tasks do not inherit counters"),
1209 OPT_STRING('p', "pid", &target.pid, "pid",
1210 "stat events on existing process id"),
1211 OPT_STRING('t', "tid", &target.tid, "tid",
1212 "stat events on existing thread id"),
1213 OPT_BOOLEAN('a', "all-cpus", &target.system_wide,
1214 "system-wide collection from all CPUs"),
1215 OPT_BOOLEAN('g', "group", &group,
1216 "put the counters into a counter group"),
1217 OPT_BOOLEAN('c', "scale", &stat_config.scale, "scale/normalize counters"),
1218 OPT_INCR('v', "verbose", &verbose,
1219 "be more verbose (show counter open errors, etc)"),
1220 OPT_INTEGER('r', "repeat", &run_count,
1221 "repeat command and print average + stddev (max: 100, forever: 0)"),
1222 OPT_BOOLEAN('n', "null", &null_run,
1223 "null run - dont start any counters"),
1224 OPT_INCR('d', "detailed", &detailed_run,
1225 "detailed run - start a lot of events"),
1226 OPT_BOOLEAN('S', "sync", &sync_run,
1227 "call sync() before starting a run"),
1228 OPT_CALLBACK_NOOPT('B', "big-num", NULL, NULL,
1229 "print large numbers with thousands\' separators",
1230 stat__set_big_num),
1231 OPT_STRING('C', "cpu", &target.cpu_list, "cpu",
1232 "list of cpus to monitor in system-wide"),
1233 OPT_SET_UINT('A', "no-aggr", &stat_config.aggr_mode,
1234 "disable CPU count aggregation", AGGR_NONE),
1235 OPT_STRING('x', "field-separator", &csv_sep, "separator",
1236 "print counts with custom separator"),
1237 OPT_CALLBACK('G', "cgroup", &evsel_list, "name",
1238 "monitor event in cgroup name only", parse_cgroups),
1239 OPT_STRING('o', "output", &output_name, "file", "output file name"),
1240 OPT_BOOLEAN(0, "append", &append_file, "append to the output file"),
1241 OPT_INTEGER(0, "log-fd", &output_fd,
1242 "log output to fd, instead of stderr"),
1243 OPT_STRING(0, "pre", &pre_cmd, "command",
1244 "command to run prior to the measured command"),
1245 OPT_STRING(0, "post", &post_cmd, "command",
1246 "command to run after to the measured command"),
1247 OPT_UINTEGER('I', "interval-print", &stat_config.interval,
1248 "print counts at regular interval in ms (>= 10)"),
1249 OPT_SET_UINT(0, "per-socket", &stat_config.aggr_mode,
1250 "aggregate counts per processor socket", AGGR_SOCKET), 2119 "aggregate counts per processor socket", AGGR_SOCKET),
1251 OPT_SET_UINT(0, "per-core", &stat_config.aggr_mode, 2120 OPT_SET_UINT(0, "per-core", &perf_stat.aggr_mode,
1252 "aggregate counts per physical processor core", AGGR_CORE), 2121 "aggregate counts per physical processor core", AGGR_CORE),
1253 OPT_SET_UINT(0, "per-thread", &stat_config.aggr_mode, 2122 OPT_SET_UINT('A', "no-aggr", &perf_stat.aggr_mode,
1254 "aggregate counts per thread", AGGR_THREAD), 2123 "disable CPU count aggregation", AGGR_NONE),
1255 OPT_UINTEGER('D', "delay", &initial_delay,
1256 "ms to wait before starting measurement after program start"),
1257 OPT_END() 2124 OPT_END()
1258 }; 2125 };
2126 struct stat st;
2127 int ret;
2128
2129 argc = parse_options(argc, argv, options, stat_report_usage, 0);
2130
2131 if (!input_name || !strlen(input_name)) {
2132 if (!fstat(STDIN_FILENO, &st) && S_ISFIFO(st.st_mode))
2133 input_name = "-";
2134 else
2135 input_name = "perf.data";
2136 }
2137
2138 perf_stat.file.path = input_name;
2139 perf_stat.file.mode = PERF_DATA_MODE_READ;
2140
2141 session = perf_session__new(&perf_stat.file, false, &perf_stat.tool);
2142 if (session == NULL)
2143 return -1;
2144
2145 perf_stat.session = session;
2146 stat_config.output = stderr;
2147 evsel_list = session->evlist;
2148
2149 ret = perf_session__process_events(session);
2150 if (ret)
2151 return ret;
2152
2153 perf_session__delete(session);
2154 return 0;
2155}
2156
2157int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
2158{
1259 const char * const stat_usage[] = { 2159 const char * const stat_usage[] = {
1260 "perf stat [<options>] [<command>]", 2160 "perf stat [<options>] [<command>]",
1261 NULL 2161 NULL
@@ -1264,6 +2164,7 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
1264 const char *mode; 2164 const char *mode;
1265 FILE *output = stderr; 2165 FILE *output = stderr;
1266 unsigned int interval; 2166 unsigned int interval;
2167 const char * const stat_subcommands[] = { "record", "report" };
1267 2168
1268 setlocale(LC_ALL, ""); 2169 setlocale(LC_ALL, "");
1269 2170
@@ -1271,24 +2172,54 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
1271 if (evsel_list == NULL) 2172 if (evsel_list == NULL)
1272 return -ENOMEM; 2173 return -ENOMEM;
1273 2174
1274 argc = parse_options(argc, argv, options, stat_usage, 2175 parse_events__shrink_config_terms();
1275 PARSE_OPT_STOP_AT_NON_OPTION); 2176 argc = parse_options_subcommand(argc, argv, stat_options, stat_subcommands,
2177 (const char **) stat_usage,
2178 PARSE_OPT_STOP_AT_NON_OPTION);
2179 perf_stat__init_shadow_stats();
2180
2181 if (csv_sep) {
2182 csv_output = true;
2183 if (!strcmp(csv_sep, "\\t"))
2184 csv_sep = "\t";
2185 } else
2186 csv_sep = DEFAULT_SEPARATOR;
2187
2188 if (argc && !strncmp(argv[0], "rec", 3)) {
2189 argc = __cmd_record(argc, argv);
2190 if (argc < 0)
2191 return -1;
2192 } else if (argc && !strncmp(argv[0], "rep", 3))
2193 return __cmd_report(argc, argv);
1276 2194
1277 interval = stat_config.interval; 2195 interval = stat_config.interval;
1278 2196
1279 if (output_name && strcmp(output_name, "-")) 2197 /*
2198 * For record command the -o is already taken care of.
2199 */
2200 if (!STAT_RECORD && output_name && strcmp(output_name, "-"))
1280 output = NULL; 2201 output = NULL;
1281 2202
1282 if (output_name && output_fd) { 2203 if (output_name && output_fd) {
1283 fprintf(stderr, "cannot use both --output and --log-fd\n"); 2204 fprintf(stderr, "cannot use both --output and --log-fd\n");
1284 parse_options_usage(stat_usage, options, "o", 1); 2205 parse_options_usage(stat_usage, stat_options, "o", 1);
1285 parse_options_usage(NULL, options, "log-fd", 0); 2206 parse_options_usage(NULL, stat_options, "log-fd", 0);
2207 goto out;
2208 }
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");
1286 goto out; 2217 goto out;
1287 } 2218 }
1288 2219
1289 if (output_fd < 0) { 2220 if (output_fd < 0) {
1290 fprintf(stderr, "argument to --log-fd must be a > 0\n"); 2221 fprintf(stderr, "argument to --log-fd must be a > 0\n");
1291 parse_options_usage(stat_usage, options, "log-fd", 0); 2222 parse_options_usage(stat_usage, stat_options, "log-fd", 0);
1292 goto out; 2223 goto out;
1293 } 2224 }
1294 2225
@@ -1314,13 +2245,6 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
1314 2245
1315 stat_config.output = output; 2246 stat_config.output = output;
1316 2247
1317 if (csv_sep) {
1318 csv_output = true;
1319 if (!strcmp(csv_sep, "\\t"))
1320 csv_sep = "\t";
1321 } else
1322 csv_sep = DEFAULT_SEPARATOR;
1323
1324 /* 2248 /*
1325 * let the spreadsheet do the pretty-printing 2249 * let the spreadsheet do the pretty-printing
1326 */ 2250 */
@@ -1328,8 +2252,8 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
1328 /* User explicitly passed -B? */ 2252 /* User explicitly passed -B? */
1329 if (big_num_opt == 1) { 2253 if (big_num_opt == 1) {
1330 fprintf(stderr, "-B option not supported with -x\n"); 2254 fprintf(stderr, "-B option not supported with -x\n");
1331 parse_options_usage(stat_usage, options, "B", 1); 2255 parse_options_usage(stat_usage, stat_options, "B", 1);
1332 parse_options_usage(NULL, options, "x", 1); 2256 parse_options_usage(NULL, stat_options, "x", 1);
1333 goto out; 2257 goto out;
1334 } else /* Nope, so disable big number formatting */ 2258 } else /* Nope, so disable big number formatting */
1335 big_num = false; 2259 big_num = false;
@@ -1337,11 +2261,11 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
1337 big_num = false; 2261 big_num = false;
1338 2262
1339 if (!argc && target__none(&target)) 2263 if (!argc && target__none(&target))
1340 usage_with_options(stat_usage, options); 2264 usage_with_options(stat_usage, stat_options);
1341 2265
1342 if (run_count < 0) { 2266 if (run_count < 0) {
1343 pr_err("Run count must be a positive number\n"); 2267 pr_err("Run count must be a positive number\n");
1344 parse_options_usage(stat_usage, options, "r", 1); 2268 parse_options_usage(stat_usage, stat_options, "r", 1);
1345 goto out; 2269 goto out;
1346 } else if (run_count == 0) { 2270 } else if (run_count == 0) {
1347 forever = true; 2271 forever = true;
@@ -1351,8 +2275,8 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
1351 if ((stat_config.aggr_mode == AGGR_THREAD) && !target__has_task(&target)) { 2275 if ((stat_config.aggr_mode == AGGR_THREAD) && !target__has_task(&target)) {
1352 fprintf(stderr, "The --per-thread option is only available " 2276 fprintf(stderr, "The --per-thread option is only available "
1353 "when monitoring via -p -t options.\n"); 2277 "when monitoring via -p -t options.\n");
1354 parse_options_usage(NULL, options, "p", 1); 2278 parse_options_usage(NULL, stat_options, "p", 1);
1355 parse_options_usage(NULL, options, "t", 1); 2279 parse_options_usage(NULL, stat_options, "t", 1);
1356 goto out; 2280 goto out;
1357 } 2281 }
1358 2282
@@ -1366,9 +2290,9 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
1366 fprintf(stderr, "both cgroup and no-aggregation " 2290 fprintf(stderr, "both cgroup and no-aggregation "
1367 "modes only available in system-wide mode\n"); 2291 "modes only available in system-wide mode\n");
1368 2292
1369 parse_options_usage(stat_usage, options, "G", 1); 2293 parse_options_usage(stat_usage, stat_options, "G", 1);
1370 parse_options_usage(NULL, options, "A", 1); 2294 parse_options_usage(NULL, stat_options, "A", 1);
1371 parse_options_usage(NULL, options, "a", 1); 2295 parse_options_usage(NULL, stat_options, "a", 1);
1372 goto out; 2296 goto out;
1373 } 2297 }
1374 2298
@@ -1380,12 +2304,12 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
1380 if (perf_evlist__create_maps(evsel_list, &target) < 0) { 2304 if (perf_evlist__create_maps(evsel_list, &target) < 0) {
1381 if (target__has_task(&target)) { 2305 if (target__has_task(&target)) {
1382 pr_err("Problems finding threads of monitor\n"); 2306 pr_err("Problems finding threads of monitor\n");
1383 parse_options_usage(stat_usage, options, "p", 1); 2307 parse_options_usage(stat_usage, stat_options, "p", 1);
1384 parse_options_usage(NULL, options, "t", 1); 2308 parse_options_usage(NULL, stat_options, "t", 1);
1385 } else if (target__has_cpu(&target)) { 2309 } else if (target__has_cpu(&target)) {
1386 perror("failed to parse CPUs map"); 2310 perror("failed to parse CPUs map");
1387 parse_options_usage(stat_usage, options, "C", 1); 2311 parse_options_usage(stat_usage, stat_options, "C", 1);
1388 parse_options_usage(NULL, options, "a", 1); 2312 parse_options_usage(NULL, stat_options, "a", 1);
1389 } 2313 }
1390 goto out; 2314 goto out;
1391 } 2315 }
@@ -1400,7 +2324,7 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
1400 if (interval && interval < 100) { 2324 if (interval && interval < 100) {
1401 if (interval < 10) { 2325 if (interval < 10) {
1402 pr_err("print interval must be >= 10ms\n"); 2326 pr_err("print interval must be >= 10ms\n");
1403 parse_options_usage(stat_usage, options, "I", 1); 2327 parse_options_usage(stat_usage, stat_options, "I", 1);
1404 goto out; 2328 goto out;
1405 } else 2329 } else
1406 pr_warning("print interval < 100ms. " 2330 pr_warning("print interval < 100ms. "
@@ -1443,6 +2367,42 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
1443 if (!forever && status != -1 && !interval) 2367 if (!forever && status != -1 && !interval)
1444 print_counters(NULL, argc, argv); 2368 print_counters(NULL, argc, argv);
1445 2369
2370 if (STAT_RECORD) {
2371 /*
2372 * We synthesize the kernel mmap record just so that older tools
2373 * don't emit warnings about not being able to resolve symbols
2374 * due to /proc/sys/kernel/kptr_restrict settings and instear provide
2375 * a saner message about no samples being in the perf.data file.
2376 *
2377 * This also serves to suppress a warning about f_header.data.size == 0
2378 * in header.c at the moment 'perf stat record' gets introduced, which
2379 * is not really needed once we start adding the stat specific PERF_RECORD_
2380 * records, but the need to suppress the kptr_restrict messages in older
2381 * tools remain -acme
2382 */
2383 int fd = perf_data_file__fd(&perf_stat.file);
2384 int err = perf_event__synthesize_kernel_mmap((void *)&perf_stat,
2385 process_synthesized_event,
2386 &perf_stat.session->machines.host);
2387 if (err) {
2388 pr_warning("Couldn't synthesize the kernel mmap record, harmless, "
2389 "older tools may produce warnings about this file\n.");
2390 }
2391
2392 if (!interval) {
2393 if (WRITE_STAT_ROUND_EVENT(walltime_nsecs_stats.max, FINAL))
2394 pr_err("failed to write stat round event\n");
2395 }
2396
2397 if (!perf_stat.file.is_pipe) {
2398 perf_stat.session->header.data_size += perf_stat.bytes_written;
2399 perf_session__write_header(perf_stat.session, evsel_list, fd, true);
2400 }
2401
2402 perf_session__delete(perf_stat.session);
2403 }
2404
2405 perf_stat__exit_aggr_mode();
1446 perf_evlist__free_stats(evsel_list); 2406 perf_evlist__free_stats(evsel_list);
1447out: 2407out:
1448 perf_evlist__delete(evsel_list); 2408 perf_evlist__delete(evsel_list);
diff --git a/tools/perf/builtin-timechart.c b/tools/perf/builtin-timechart.c
index 30e59620179d..40cc9bb3506c 100644
--- a/tools/perf/builtin-timechart.c
+++ b/tools/perf/builtin-timechart.c
@@ -30,7 +30,7 @@
30 30
31#include "perf.h" 31#include "perf.h"
32#include "util/header.h" 32#include "util/header.h"
33#include "util/parse-options.h" 33#include <subcmd/parse-options.h>
34#include "util/parse-events.h" 34#include "util/parse-events.h"
35#include "util/event.h" 35#include "util/event.h"
36#include "util/session.h" 36#include "util/session.h"
@@ -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 7e2e72e6d9d1..833214979c4f 100644
--- a/tools/perf/builtin-top.c
+++ b/tools/perf/builtin-top.c
@@ -34,7 +34,7 @@
34#include "util/top.h" 34#include "util/top.h"
35#include "util/util.h" 35#include "util/util.h"
36#include <linux/rbtree.h> 36#include <linux/rbtree.h>
37#include "util/parse-options.h" 37#include <subcmd/parse-options.h>
38#include "util/parse-events.h" 38#include "util/parse-events.h"
39#include "util/cpumap.h" 39#include "util/cpumap.h"
40#include "util/xyarray.h" 40#include "util/xyarray.h"
@@ -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;
@@ -175,42 +176,40 @@ static void perf_top__record_precise_ip(struct perf_top *top,
175 int counter, u64 ip) 176 int counter, u64 ip)
176{ 177{
177 struct annotation *notes; 178 struct annotation *notes;
178 struct symbol *sym; 179 struct symbol *sym = he->ms.sym;
179 int err = 0; 180 int err = 0;
180 181
181 if (he == NULL || he->ms.sym == NULL || 182 if (sym == NULL || (use_browser == 0 &&
182 ((top->sym_filter_entry == NULL || 183 (top->sym_filter_entry == NULL ||
183 top->sym_filter_entry->ms.sym != he->ms.sym) && use_browser != 1)) 184 top->sym_filter_entry->ms.sym != sym)))
184 return; 185 return;
185 186
186 sym = he->ms.sym;
187 notes = symbol__annotation(sym); 187 notes = symbol__annotation(sym);
188 188
189 if (pthread_mutex_trylock(&notes->lock)) 189 if (pthread_mutex_trylock(&notes->lock))
190 return; 190 return;
191 191
192 ip = he->ms.map->map_ip(he->ms.map, ip); 192 err = hist_entry__inc_addr_samples(he, counter, ip);
193
194 if (ui__has_annotation())
195 err = hist_entry__inc_addr_samples(he, counter, ip);
196 193
197 pthread_mutex_unlock(&notes->lock); 194 pthread_mutex_unlock(&notes->lock);
198 195
199 /* 196 if (unlikely(err)) {
200 * This function is now called with he->hists->lock held. 197 /*
201 * Release it before going to sleep. 198 * This function is now called with he->hists->lock held.
202 */ 199 * Release it before going to sleep.
203 pthread_mutex_unlock(&he->hists->lock); 200 */
201 pthread_mutex_unlock(&he->hists->lock);
202
203 if (err == -ERANGE && !he->ms.map->erange_warned)
204 ui__warn_map_erange(he->ms.map, sym, ip);
205 else if (err == -ENOMEM) {
206 pr_err("Not enough memory for annotating '%s' symbol!\n",
207 sym->name);
208 sleep(1);
209 }
204 210
205 if (err == -ERANGE && !he->ms.map->erange_warned) 211 pthread_mutex_lock(&he->hists->lock);
206 ui__warn_map_erange(he->ms.map, sym, ip);
207 else if (err == -ENOMEM) {
208 pr_err("Not enough memory for annotating '%s' symbol!\n",
209 sym->name);
210 sleep(1);
211 } 212 }
212
213 pthread_mutex_lock(&he->hists->lock);
214} 213}
215 214
216static void perf_top__show_details(struct perf_top *top) 215static void perf_top__show_details(struct perf_top *top)
@@ -254,7 +253,8 @@ static void perf_top__print_sym_table(struct perf_top *top)
254 char bf[160]; 253 char bf[160];
255 int printed = 0; 254 int printed = 0;
256 const int win_width = top->winsize.ws_col - 1; 255 const int win_width = top->winsize.ws_col - 1;
257 struct hists *hists = evsel__hists(top->sym_evsel); 256 struct perf_evsel *evsel = top->sym_evsel;
257 struct hists *hists = evsel__hists(evsel);
258 258
259 puts(CONSOLE_CLEAR); 259 puts(CONSOLE_CLEAR);
260 260
@@ -290,7 +290,7 @@ static void perf_top__print_sym_table(struct perf_top *top)
290 } 290 }
291 291
292 hists__collapse_resort(hists, NULL); 292 hists__collapse_resort(hists, NULL);
293 hists__output_resort(hists, NULL); 293 perf_evsel__output_resort(evsel, NULL);
294 294
295 hists__output_recalc_col_len(hists, top->print_entries - printed); 295 hists__output_recalc_col_len(hists, top->print_entries - printed);
296 putchar('\n'); 296 putchar('\n');
@@ -542,6 +542,7 @@ static bool perf_top__handle_keypress(struct perf_top *top, int c)
542static void perf_top__sort_new_samples(void *arg) 542static void perf_top__sort_new_samples(void *arg)
543{ 543{
544 struct perf_top *t = arg; 544 struct perf_top *t = arg;
545 struct perf_evsel *evsel = t->sym_evsel;
545 struct hists *hists; 546 struct hists *hists;
546 547
547 perf_top__reset_sample_counters(t); 548 perf_top__reset_sample_counters(t);
@@ -549,7 +550,7 @@ static void perf_top__sort_new_samples(void *arg)
549 if (t->evlist->selected != NULL) 550 if (t->evlist->selected != NULL)
550 t->sym_evsel = t->evlist->selected; 551 t->sym_evsel = t->evlist->selected;
551 552
552 hists = evsel__hists(t->sym_evsel); 553 hists = evsel__hists(evsel);
553 554
554 if (t->evlist->enabled) { 555 if (t->evlist->enabled) {
555 if (t->zero) { 556 if (t->zero) {
@@ -561,7 +562,7 @@ static void perf_top__sort_new_samples(void *arg)
561 } 562 }
562 563
563 hists__collapse_resort(hists, NULL); 564 hists__collapse_resort(hists, NULL);
564 hists__output_resort(hists, NULL); 565 perf_evsel__output_resort(evsel, NULL);
565} 566}
566 567
567static void *display_thread_tui(void *arg) 568static void *display_thread_tui(void *arg)
@@ -687,14 +688,8 @@ static int hist_iter__top_callback(struct hist_entry_iter *iter,
687 struct hist_entry *he = iter->he; 688 struct hist_entry *he = iter->he;
688 struct perf_evsel *evsel = iter->evsel; 689 struct perf_evsel *evsel = iter->evsel;
689 690
690 if (sort__has_sym && single) { 691 if (sort__has_sym && single)
691 u64 ip = al->addr; 692 perf_top__record_precise_ip(top, he, evsel->idx, al->addr);
692
693 if (al->map)
694 ip = al->map->unmap_ip(al->map, ip);
695
696 perf_top__record_precise_ip(top, he, evsel->idx, ip);
697 }
698 693
699 hist__account_cycles(iter->sample->branch_stack, al, iter->sample, 694 hist__account_cycles(iter->sample->branch_stack, al, iter->sample,
700 !(top->record_opts.branch_stack & PERF_SAMPLE_BRANCH_ANY)); 695 !(top->record_opts.branch_stack & PERF_SAMPLE_BRANCH_ANY));
@@ -734,7 +729,7 @@ static void perf_event__process_sample(struct perf_tool *tool,
734 if (event->header.misc & PERF_RECORD_MISC_EXACT_IP) 729 if (event->header.misc & PERF_RECORD_MISC_EXACT_IP)
735 top->exact_samples++; 730 top->exact_samples++;
736 731
737 if (perf_event__preprocess_sample(event, machine, &al, sample) < 0) 732 if (machine__resolve(machine, &al, sample) < 0)
738 return; 733 return;
739 734
740 if (!top->kptr_restrict_warned && 735 if (!top->kptr_restrict_warned &&
@@ -815,7 +810,6 @@ static void perf_top__mmap_read_idx(struct perf_top *top, int idx)
815 struct perf_session *session = top->session; 810 struct perf_session *session = top->session;
816 union perf_event *event; 811 union perf_event *event;
817 struct machine *machine; 812 struct machine *machine;
818 u8 origin;
819 int ret; 813 int ret;
820 814
821 while ((event = perf_evlist__mmap_read(top->evlist, idx)) != NULL) { 815 while ((event = perf_evlist__mmap_read(top->evlist, idx)) != NULL) {
@@ -828,12 +822,10 @@ static void perf_top__mmap_read_idx(struct perf_top *top, int idx)
828 evsel = perf_evlist__id2evsel(session->evlist, sample.id); 822 evsel = perf_evlist__id2evsel(session->evlist, sample.id);
829 assert(evsel != NULL); 823 assert(evsel != NULL);
830 824
831 origin = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
832
833 if (event->header.type == PERF_RECORD_SAMPLE) 825 if (event->header.type == PERF_RECORD_SAMPLE)
834 ++top->samples; 826 ++top->samples;
835 827
836 switch (origin) { 828 switch (sample.cpumode) {
837 case PERF_RECORD_MISC_USER: 829 case PERF_RECORD_MISC_USER:
838 ++top->us_samples; 830 ++top->us_samples;
839 if (top->hide_user_symbols) 831 if (top->hide_user_symbols)
@@ -964,7 +956,7 @@ static int __cmd_top(struct perf_top *top)
964 if (ret) 956 if (ret)
965 goto out_delete; 957 goto out_delete;
966 958
967 if (perf_session__register_idle_thread(top->session) == NULL) 959 if (perf_session__register_idle_thread(top->session) < 0)
968 goto out_delete; 960 goto out_delete;
969 961
970 machine__synthesize_threads(&top->session->machines.host, &opts->target, 962 machine__synthesize_threads(&top->session->machines.host, &opts->target,
@@ -1071,7 +1063,7 @@ parse_callchain_opt(const struct option *opt, const char *arg, int unset)
1071 return parse_callchain_top_opt(arg); 1063 return parse_callchain_top_opt(arg);
1072} 1064}
1073 1065
1074static 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)
1075{ 1067{
1076 if (!strcmp(var, "top.call-graph")) 1068 if (!strcmp(var, "top.call-graph"))
1077 var = "call-graph.record-mode"; /* fall-through */ 1069 var = "call-graph.record-mode"; /* fall-through */
@@ -1080,7 +1072,7 @@ static int perf_top_config(const char *var, const char *value, void *cb)
1080 return 0; 1072 return 0;
1081 } 1073 }
1082 1074
1083 return perf_default_config(var, value, cb); 1075 return 0;
1084} 1076}
1085 1077
1086static int 1078static int
@@ -1218,6 +1210,10 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused)
1218 OPT_CALLBACK('j', "branch-filter", &opts->branch_stack, 1210 OPT_CALLBACK('j', "branch-filter", &opts->branch_stack,
1219 "branch filter mask", "branch stack filter modes", 1211 "branch filter mask", "branch stack filter modes",
1220 parse_branch_stack), 1212 parse_branch_stack),
1213 OPT_BOOLEAN(0, "raw-trace", &symbol_conf.raw_trace,
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"),
1221 OPT_END() 1217 OPT_END()
1222 }; 1218 };
1223 const char * const top_usage[] = { 1219 const char * const top_usage[] = {
@@ -1239,11 +1235,37 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused)
1239 if (argc) 1235 if (argc)
1240 usage_with_options(top_usage, options); 1236 usage_with_options(top_usage, options);
1241 1237
1238 if (!top.evlist->nr_entries &&
1239 perf_evlist__add_default(top.evlist) < 0) {
1240 pr_err("Not enough memory for event selector list\n");
1241 goto out_delete_evlist;
1242 }
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
1246 if (setup_sorting() < 0) { 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
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);
1249 if (field_order) 1271 if (field_order)
@@ -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);
@@ -1279,12 +1294,9 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused)
1279 if (target__none(target)) 1294 if (target__none(target))
1280 target->system_wide = true; 1295 target->system_wide = true;
1281 1296
1282 if (perf_evlist__create_maps(top.evlist, target) < 0) 1297 if (perf_evlist__create_maps(top.evlist, target) < 0) {
1283 usage_with_options(top_usage, options); 1298 ui__error("Couldn't create thread/CPU maps: %s\n",
1284 1299 errno == ENOENT ? "No such process" : strerror_r(errno, errbuf, sizeof(errbuf)));
1285 if (!top.evlist->nr_entries &&
1286 perf_evlist__add_default(top.evlist) < 0) {
1287 ui__error("Not enough memory for event selector list\n");
1288 goto out_delete_evlist; 1300 goto out_delete_evlist;
1289 } 1301 }
1290 1302
diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c
index c783d8fd3a80..93ac724fb635 100644
--- a/tools/perf/builtin-trace.c
+++ b/tools/perf/builtin-trace.c
@@ -22,17 +22,18 @@
22#include "util/color.h" 22#include "util/color.h"
23#include "util/debug.h" 23#include "util/debug.h"
24#include "util/evlist.h" 24#include "util/evlist.h"
25#include "util/exec_cmd.h" 25#include <subcmd/exec-cmd.h>
26#include "util/machine.h" 26#include "util/machine.h"
27#include "util/session.h" 27#include "util/session.h"
28#include "util/thread.h" 28#include "util/thread.h"
29#include "util/parse-options.h" 29#include <subcmd/parse-options.h>
30#include "util/strlist.h" 30#include "util/strlist.h"
31#include "util/intlist.h" 31#include "util/intlist.h"
32#include "util/thread_map.h" 32#include "util/thread_map.h"
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-version.c b/tools/perf/builtin-version.c
new file mode 100644
index 000000000000..9b10cda6b6dc
--- /dev/null
+++ b/tools/perf/builtin-version.c
@@ -0,0 +1,10 @@
1#include "util/util.h"
2#include "builtin.h"
3#include "perf.h"
4
5int cmd_version(int argc __maybe_unused, const char **argv __maybe_unused,
6 const char *prefix __maybe_unused)
7{
8 printf("perf version %s\n", perf_version_string);
9 return 0;
10}
diff --git a/tools/perf/builtin.h b/tools/perf/builtin.h
index 3688ad29085f..41c24010ab43 100644
--- a/tools/perf/builtin.h
+++ b/tools/perf/builtin.h
@@ -7,37 +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_diff(int argc, const char **argv, const char *prefix); 20int cmd_config(int argc, const char **argv, const char *prefix);
21extern int cmd_evlist(int argc, const char **argv, const char *prefix); 21int cmd_diff(int argc, const char **argv, const char *prefix);
22extern int cmd_help(int argc, const char **argv, const char *prefix); 22int cmd_evlist(int argc, const char **argv, const char *prefix);
23extern int cmd_sched(int argc, const char **argv, const char *prefix); 23int cmd_help(int argc, const char **argv, const char *prefix);
24extern int cmd_list(int argc, const char **argv, const char *prefix); 24int cmd_sched(int argc, const char **argv, const char *prefix);
25extern int cmd_record(int argc, const char **argv, const char *prefix); 25int cmd_list(int argc, const char **argv, const char *prefix);
26extern int cmd_report(int argc, const char **argv, const char *prefix); 26int cmd_record(int argc, const char **argv, const char *prefix);
27extern int cmd_stat(int argc, const char **argv, const char *prefix); 27int cmd_report(int argc, const char **argv, const char *prefix);
28extern int cmd_timechart(int argc, const char **argv, const char *prefix); 28int cmd_stat(int argc, const char **argv, const char *prefix);
29extern int cmd_top(int argc, const char **argv, const char *prefix); 29int cmd_timechart(int argc, const char **argv, const char *prefix);
30extern int cmd_script(int argc, const char **argv, const char *prefix); 30int cmd_top(int argc, const char **argv, const char *prefix);
31extern int cmd_version(int argc, const char **argv, const char *prefix); 31int cmd_script(int argc, const char **argv, const char *prefix);
32extern int cmd_probe(int argc, const char **argv, const char *prefix); 32int cmd_version(int argc, const char **argv, const char *prefix);
33extern int cmd_kmem(int argc, const char **argv, const char *prefix); 33int cmd_probe(int argc, const char **argv, const char *prefix);
34extern int cmd_lock(int argc, const char **argv, const char *prefix); 34int cmd_kmem(int argc, const char **argv, const char *prefix);
35extern int cmd_kvm(int argc, const char **argv, const char *prefix); 35int cmd_lock(int argc, const char **argv, const char *prefix);
36extern int cmd_test(int argc, const char **argv, const char *prefix); 36int cmd_kvm(int argc, const char **argv, const char *prefix);
37extern int cmd_trace(int argc, const char **argv, const char *prefix); 37int cmd_test(int argc, const char **argv, const char *prefix);
38extern int cmd_inject(int argc, const char **argv, const char *prefix); 38int cmd_trace(int argc, const char **argv, const char *prefix);
39extern int cmd_mem(int argc, const char **argv, const char *prefix); 39int cmd_inject(int argc, const char **argv, const char *prefix);
40extern int cmd_data(int argc, const char **argv, const char *prefix); 40int cmd_mem(int argc, const char **argv, const char *prefix);
41int cmd_data(int argc, const char **argv, const char *prefix);
41 42
42extern int find_scripts(char **scripts_array, char **scripts_path_array); 43int find_scripts(char **scripts_array, char **scripts_path_array);
43#endif 44#endif
diff --git a/tools/perf/command-list.txt b/tools/perf/command-list.txt
index 00fcaf8a5b8d..ab5cbaa170d0 100644
--- a/tools/perf/command-list.txt
+++ b/tools/perf/command-list.txt
@@ -9,6 +9,7 @@ perf-buildid-cache mainporcelain common
9perf-buildid-list mainporcelain common 9perf-buildid-list mainporcelain common
10perf-data mainporcelain common 10perf-data mainporcelain common
11perf-diff mainporcelain common 11perf-diff mainporcelain common
12perf-config mainporcelain common
12perf-evlist mainporcelain common 13perf-evlist mainporcelain common
13perf-inject mainporcelain common 14perf-inject mainporcelain common
14perf-kmem mainporcelain common 15perf-kmem mainporcelain common
@@ -25,4 +26,4 @@ perf-stat mainporcelain common
25perf-test mainporcelain common 26perf-test mainporcelain common
26perf-timechart mainporcelain common 27perf-timechart mainporcelain common
27perf-top mainporcelain common 28perf-top mainporcelain common
28perf-trace mainporcelain common 29perf-trace mainporcelain audit
diff --git a/tools/perf/config/Makefile b/tools/perf/config/Makefile
index de89ec574361..f7d7f5a1cad5 100644
--- a/tools/perf/config/Makefile
+++ b/tools/perf/config/Makefile
@@ -17,7 +17,7 @@ detected_var = $(shell echo "$(1)=$($(1))" >> $(OUTPUT).config-detected)
17 17
18CFLAGS := $(EXTRA_CFLAGS) $(EXTRA_WARNINGS) 18CFLAGS := $(EXTRA_CFLAGS) $(EXTRA_WARNINGS)
19 19
20include $(src-perf)/config/Makefile.arch 20include $(srctree)/tools/scripts/Makefile.arch
21 21
22$(call detected_var,ARCH) 22$(call detected_var,ARCH)
23 23
@@ -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)
@@ -135,8 +130,6 @@ endif
135 130
136ifeq ($(DEBUG),0) 131ifeq ($(DEBUG),0)
137 CFLAGS += -O6 132 CFLAGS += -O6
138else
139 CFLAGS += $(call cc-option,-Og,-O0)
140endif 133endif
141 134
142ifdef PARSER_DEBUG 135ifdef PARSER_DEBUG
@@ -147,28 +140,26 @@ ifdef PARSER_DEBUG
147 $(call detected_var,PARSER_DEBUG_FLEX) 140 $(call detected_var,PARSER_DEBUG_FLEX)
148endif 141endif
149 142
150ifndef NO_LIBPYTHON 143# Try different combinations to accommodate systems that only have
151 # Try different combinations to accommodate systems that only have 144# python[2][-config] in weird combinations but always preferring
152 # python[2][-config] in weird combinations but always preferring 145# python2 and python2-config as per pep-0394. If we catch a
153 # python2 and python2-config as per pep-0394. If we catch a 146# python[-config] in version 3, the version check will kill it.
154 # python[-config] in version 3, the version check will kill it. 147PYTHON2 := $(if $(call get-executable,python2),python2,python)
155 PYTHON2 := $(if $(call get-executable,python2),python2,python) 148override PYTHON := $(call get-executable-or-default,PYTHON,$(PYTHON2))
156 override PYTHON := $(call get-executable-or-default,PYTHON,$(PYTHON2)) 149PYTHON2_CONFIG := \
157 PYTHON2_CONFIG := \ 150 $(if $(call get-executable,$(PYTHON)-config),$(PYTHON)-config,python-config)
158 $(if $(call get-executable,$(PYTHON)-config),$(PYTHON)-config,python-config) 151override PYTHON_CONFIG := \
159 override PYTHON_CONFIG := \ 152 $(call get-executable-or-default,PYTHON_CONFIG,$(PYTHON2_CONFIG))
160 $(call get-executable-or-default,PYTHON_CONFIG,$(PYTHON2_CONFIG))
161 153
162 PYTHON_CONFIG_SQ := $(call shell-sq,$(PYTHON_CONFIG)) 154PYTHON_CONFIG_SQ := $(call shell-sq,$(PYTHON_CONFIG))
163 155
164 PYTHON_EMBED_LDOPTS := $(shell $(PYTHON_CONFIG_SQ) --ldflags 2>/dev/null) 156PYTHON_EMBED_LDOPTS := $(shell $(PYTHON_CONFIG_SQ) --ldflags 2>/dev/null)
165 PYTHON_EMBED_CCOPTS := $(shell $(PYTHON_CONFIG_SQ) --cflags 2>/dev/null) 157PYTHON_EMBED_CCOPTS := $(shell $(PYTHON_CONFIG_SQ) --cflags 2>/dev/null)
166 158
167 FEATURE_CHECK_CFLAGS-libpython := $(PYTHON_EMBED_CCOPTS) 159FEATURE_CHECK_CFLAGS-libpython := $(PYTHON_EMBED_CCOPTS)
168 FEATURE_CHECK_LDFLAGS-libpython := $(PYTHON_EMBED_LDOPTS) 160FEATURE_CHECK_LDFLAGS-libpython := $(PYTHON_EMBED_LDOPTS)
169 FEATURE_CHECK_CFLAGS-libpython-version := $(PYTHON_EMBED_CCOPTS) 161FEATURE_CHECK_CFLAGS-libpython-version := $(PYTHON_EMBED_CCOPTS)
170 FEATURE_CHECK_LDFLAGS-libpython-version := $(PYTHON_EMBED_LDOPTS) 162FEATURE_CHECK_LDFLAGS-libpython-version := $(PYTHON_EMBED_LDOPTS)
171endif
172 163
173CFLAGS += -fno-omit-frame-pointer 164CFLAGS += -fno-omit-frame-pointer
174CFLAGS += -ggdb3 165CFLAGS += -ggdb3
@@ -183,7 +174,11 @@ LDFLAGS += -Wl,-z,noexecstack
183 174
184EXTLIBS = -lpthread -lrt -lm -ldl 175EXTLIBS = -lpthread -lrt -lm -ldl
185 176
177ifeq ($(FEATURES_DUMP),)
186include $(srctree)/tools/build/Makefile.feature 178include $(srctree)/tools/build/Makefile.feature
179else
180include $(FEATURES_DUMP)
181endif
187 182
188ifeq ($(feature-stackprotector-all), 1) 183ifeq ($(feature-stackprotector-all), 1)
189 CFLAGS += -fstack-protector-all 184 CFLAGS += -fstack-protector-all
@@ -318,9 +313,28 @@ ifndef NO_LIBELF
318 CFLAGS += -DHAVE_LIBBPF_SUPPORT 313 CFLAGS += -DHAVE_LIBBPF_SUPPORT
319 $(call detected,CONFIG_LIBBPF) 314 $(call detected,CONFIG_LIBBPF)
320 endif 315 endif
316
317 ifndef NO_DWARF
318 ifdef PERF_HAVE_ARCH_REGS_QUERY_REGISTER_OFFSET
319 CFLAGS += -DHAVE_BPF_PROLOGUE
320 $(call detected,CONFIG_BPF_PROLOGUE)
321 else
322 msg := $(warning BPF prologue is not supported by architecture $(ARCH), missing regs_query_register_offset());
323 endif
324 else
325 msg := $(warning DWARF support is off, BPF prologue is disabled);
326 endif
327
321 endif # NO_LIBBPF 328 endif # NO_LIBBPF
322endif # NO_LIBELF 329endif # NO_LIBELF
323 330
331ifdef PERF_HAVE_JITDUMP
332 ifndef NO_DWARF
333 $(call detected,CONFIG_JITDUMP)
334 CFLAGS += -DHAVE_JITDUMP
335 endif
336endif
337
324ifeq ($(ARCH),powerpc) 338ifeq ($(ARCH),powerpc)
325 ifndef NO_DWARF 339 ifndef NO_DWARF
326 CFLAGS += -DHAVE_SKIP_CALLCHAIN_IDX 340 CFLAGS += -DHAVE_SKIP_CALLCHAIN_IDX
@@ -397,6 +411,17 @@ ifndef NO_LIBAUDIT
397 endif 411 endif
398endif 412endif
399 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
400ifdef NO_NEWT 425ifdef NO_NEWT
401 NO_SLANG=1 426 NO_SLANG=1
402endif 427endif
@@ -483,7 +508,7 @@ else
483 508
484 PYTHON_EMBED_LDOPTS := $(shell $(PYTHON_CONFIG_SQ) --ldflags 2>/dev/null) 509 PYTHON_EMBED_LDOPTS := $(shell $(PYTHON_CONFIG_SQ) --ldflags 2>/dev/null)
485 PYTHON_EMBED_LDFLAGS := $(call strip-libs,$(PYTHON_EMBED_LDOPTS)) 510 PYTHON_EMBED_LDFLAGS := $(call strip-libs,$(PYTHON_EMBED_LDOPTS))
486 PYTHON_EMBED_LIBADD := $(call grep-libs,$(PYTHON_EMBED_LDOPTS)) 511 PYTHON_EMBED_LIBADD := $(call grep-libs,$(PYTHON_EMBED_LDOPTS)) -lutil
487 PYTHON_EMBED_CCOPTS := $(shell $(PYTHON_CONFIG_SQ) --cflags 2>/dev/null) 512 PYTHON_EMBED_CCOPTS := $(shell $(PYTHON_CONFIG_SQ) --cflags 2>/dev/null)
488 FLAGS_PYTHON_EMBED := $(PYTHON_EMBED_CCOPTS) $(PYTHON_EMBED_LDOPTS) 513 FLAGS_PYTHON_EMBED := $(PYTHON_EMBED_CCOPTS) $(PYTHON_EMBED_LDOPTS)
489 514
@@ -681,6 +706,8 @@ sharedir = $(prefix)/share
681template_dir = share/perf-core/templates 706template_dir = share/perf-core/templates
682STRACE_GROUPS_DIR = share/perf-core/strace/groups 707STRACE_GROUPS_DIR = share/perf-core/strace/groups
683htmldir = share/doc/perf-doc 708htmldir = share/doc/perf-doc
709tipdir = share/doc/perf-tip
710srcdir = $(srctree)/tools/perf
684ifeq ($(prefix),/usr) 711ifeq ($(prefix),/usr)
685sysconfdir = /etc 712sysconfdir = /etc
686ETC_PERFCONFIG = $(sysconfdir)/perfconfig 713ETC_PERFCONFIG = $(sysconfdir)/perfconfig
@@ -707,19 +734,24 @@ infodir_SQ = $(subst ','\'',$(infodir))
707perfexecdir_SQ = $(subst ','\'',$(perfexecdir)) 734perfexecdir_SQ = $(subst ','\'',$(perfexecdir))
708template_dir_SQ = $(subst ','\'',$(template_dir)) 735template_dir_SQ = $(subst ','\'',$(template_dir))
709htmldir_SQ = $(subst ','\'',$(htmldir)) 736htmldir_SQ = $(subst ','\'',$(htmldir))
737tipdir_SQ = $(subst ','\'',$(tipdir))
710prefix_SQ = $(subst ','\'',$(prefix)) 738prefix_SQ = $(subst ','\'',$(prefix))
711sysconfdir_SQ = $(subst ','\'',$(sysconfdir)) 739sysconfdir_SQ = $(subst ','\'',$(sysconfdir))
712libdir_SQ = $(subst ','\'',$(libdir)) 740libdir_SQ = $(subst ','\'',$(libdir))
741srcdir_SQ = $(subst ','\'',$(srcdir))
713 742
714ifneq ($(filter /%,$(firstword $(perfexecdir))),) 743ifneq ($(filter /%,$(firstword $(perfexecdir))),)
715perfexec_instdir = $(perfexecdir) 744perfexec_instdir = $(perfexecdir)
716STRACE_GROUPS_INSTDIR = $(STRACE_GROUPS_DIR) 745STRACE_GROUPS_INSTDIR = $(STRACE_GROUPS_DIR)
746tip_instdir = $(tipdir)
717else 747else
718perfexec_instdir = $(prefix)/$(perfexecdir) 748perfexec_instdir = $(prefix)/$(perfexecdir)
719STRACE_GROUPS_INSTDIR = $(prefix)/$(STRACE_GROUPS_DIR) 749STRACE_GROUPS_INSTDIR = $(prefix)/$(STRACE_GROUPS_DIR)
750tip_instdir = $(prefix)/$(tipdir)
720endif 751endif
721perfexec_instdir_SQ = $(subst ','\'',$(perfexec_instdir)) 752perfexec_instdir_SQ = $(subst ','\'',$(perfexec_instdir))
722STRACE_GROUPS_INSTDIR_SQ = $(subst ','\'',$(STRACE_GROUPS_INSTDIR)) 753STRACE_GROUPS_INSTDIR_SQ = $(subst ','\'',$(STRACE_GROUPS_INSTDIR))
754tip_instdir_SQ = $(subst ','\'',$(tip_instdir))
723 755
724# If we install to $(HOME) we keep the traceevent default: 756# If we install to $(HOME) we keep the traceevent default:
725# $(HOME)/.traceevent/plugins 757# $(HOME)/.traceevent/plugins
@@ -741,6 +773,10 @@ ifeq ($(VF),1)
741 $(call print_var,sysconfdir) 773 $(call print_var,sysconfdir)
742 $(call print_var,LIBUNWIND_DIR) 774 $(call print_var,LIBUNWIND_DIR)
743 $(call print_var,LIBDW_DIR) 775 $(call print_var,LIBDW_DIR)
776
777 ifeq ($(dwarf-post-unwind),1)
778 $(call feature_print_text,"DWARF post unwind library", $(dwarf-post-unwind-text))
779 endif
744 $(info ) 780 $(info )
745endif 781endif
746 782
@@ -756,6 +792,8 @@ $(call detected_var,ETC_PERFCONFIG_SQ)
756$(call detected_var,STRACE_GROUPS_DIR_SQ) 792$(call detected_var,STRACE_GROUPS_DIR_SQ)
757$(call detected_var,prefix_SQ) 793$(call detected_var,prefix_SQ)
758$(call detected_var,perfexecdir_SQ) 794$(call detected_var,perfexecdir_SQ)
795$(call detected_var,tipdir_SQ)
796$(call detected_var,srcdir_SQ)
759$(call detected_var,LIBDIR) 797$(call detected_var,LIBDIR)
760$(call detected_var,GTK_CFLAGS) 798$(call detected_var,GTK_CFLAGS)
761$(call detected_var,PERL_EMBED_CCOPTS) 799$(call detected_var,PERL_EMBED_CCOPTS)
diff --git a/tools/perf/config/Makefile.arch b/tools/perf/config/Makefile.arch
deleted file mode 100644
index e11fbd6fae78..000000000000
--- a/tools/perf/config/Makefile.arch
+++ /dev/null
@@ -1,18 +0,0 @@
1ifndef ARCH
2ARCH := $(shell uname -m 2>/dev/null || echo not)
3endif
4
5ARCH := $(shell echo $(ARCH) | sed -e s/i.86/x86/ -e s/x86_64/x86/ \
6 -e s/sun4u/sparc/ -e s/sparc64/sparc/ \
7 -e /arm64/!s/arm.*/arm/ -e s/sa110/arm/ \
8 -e s/s390x/s390/ -e s/parisc64/parisc/ \
9 -e s/ppc.*/powerpc/ -e s/mips.*/mips/ \
10 -e s/sh[234].*/sh/ -e s/aarch64.*/arm64/ \
11 -e s/tile.*/tile/ )
12
13LP64 := $(shell echo __LP64__ | ${CC} ${CFLAGS} -E -x c - | tail -n 1)
14ifeq ($(LP64), 1)
15 IS_64_BIT := 1
16else
17 IS_64_BIT := 0
18endif
diff --git a/tools/perf/config/utilities.mak b/tools/perf/config/utilities.mak
deleted file mode 100644
index 0ebef09c0842..000000000000
--- a/tools/perf/config/utilities.mak
+++ /dev/null
@@ -1,198 +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))
180
181# try-run
182# Usage: option = $(call try-run, $(CC)...-o "$$TMP",option-ok,otherwise)
183# Exit code chooses option. "$$TMP" is can be used as temporary file and
184# is automatically cleaned up.
185try-run = $(shell set -e; \
186 TMP="$(TMPOUT).$$$$.tmp"; \
187 TMPO="$(TMPOUT).$$$$.o"; \
188 if ($(1)) >/dev/null 2>&1; \
189 then echo "$(2)"; \
190 else echo "$(3)"; \
191 fi; \
192 rm -f "$$TMP" "$$TMPO")
193
194# cc-option
195# Usage: cflags-y += $(call cc-option,-march=winchip-c6,-march=i586)
196
197cc-option = $(call try-run,\
198 $(CC) $(KBUILD_CPPFLAGS) $(KBUILD_CFLAGS) $(1) -c -x c /dev/null -o "$$TMP",$(1),$(2))
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 3d4c7c09adea..aaee0a782747 100644
--- a/tools/perf/perf.c
+++ b/tools/perf/perf.c
@@ -9,16 +9,18 @@
9#include "builtin.h" 9#include "builtin.h"
10 10
11#include "util/env.h" 11#include "util/env.h"
12#include "util/exec_cmd.h" 12#include <subcmd/exec-cmd.h>
13#include "util/cache.h" 13#include "util/cache.h"
14#include "util/quote.h" 14#include "util/quote.h"
15#include "util/run-command.h" 15#include <subcmd/run-command.h>
16#include "util/parse-events.h" 16#include "util/parse-events.h"
17#include "util/parse-options.h" 17#include <subcmd/parse-options.h>
18#include "util/bpf-loader.h" 18#include "util/bpf-loader.h"
19#include "util/debug.h" 19#include "util/debug.h"
20#include <api/fs/tracing_path.h> 20#include <api/fs/tracing_path.h>
21#include <pthread.h> 21#include <pthread.h>
22#include <stdlib.h>
23#include <time.h>
22 24
23const char perf_usage_string[] = 25const char perf_usage_string[] =
24 "perf [--version] [--help] [OPTIONS] COMMAND [ARGS]"; 26 "perf [--version] [--help] [OPTIONS] COMMAND [ARGS]";
@@ -39,6 +41,7 @@ struct cmd_struct {
39static struct cmd_struct commands[] = { 41static struct cmd_struct commands[] = {
40 { "buildid-cache", cmd_buildid_cache, 0 }, 42 { "buildid-cache", cmd_buildid_cache, 0 },
41 { "buildid-list", cmd_buildid_list, 0 }, 43 { "buildid-list", cmd_buildid_list, 0 },
44 { "config", cmd_config, 0 },
42 { "diff", cmd_diff, 0 }, 45 { "diff", cmd_diff, 0 },
43 { "evlist", cmd_evlist, 0 }, 46 { "evlist", cmd_evlist, 0 },
44 { "help", cmd_help, 0 }, 47 { "help", cmd_help, 0 },
@@ -118,7 +121,7 @@ static void commit_pager_choice(void)
118{ 121{
119 switch (use_pager) { 122 switch (use_pager) {
120 case 0: 123 case 0:
121 setenv("PERF_PAGER", "cat", 1); 124 setenv(PERF_PAGER_ENVIRONMENT, "cat", 1);
122 break; 125 break;
123 case 1: 126 case 1:
124 /* setup_pager(); */ 127 /* setup_pager(); */
@@ -182,9 +185,9 @@ static int handle_options(const char ***argv, int *argc, int *envchanged)
182 if (!prefixcmp(cmd, CMD_EXEC_PATH)) { 185 if (!prefixcmp(cmd, CMD_EXEC_PATH)) {
183 cmd += strlen(CMD_EXEC_PATH); 186 cmd += strlen(CMD_EXEC_PATH);
184 if (*cmd == '=') 187 if (*cmd == '=')
185 perf_set_argv_exec_path(cmd + 1); 188 set_argv_exec_path(cmd + 1);
186 else { 189 else {
187 puts(perf_exec_path()); 190 puts(get_argv_exec_path());
188 exit(0); 191 exit(0);
189 } 192 }
190 } else if (!strcmp(cmd, "--html-path")) { 193 } else if (!strcmp(cmd, "--html-path")) {
@@ -383,6 +386,7 @@ static int run_builtin(struct cmd_struct *p, int argc, const char **argv)
383 use_pager = 1; 386 use_pager = 1;
384 commit_pager_choice(); 387 commit_pager_choice();
385 388
389 perf_env__set_cmdline(&perf_env, argc, argv);
386 status = p->fn(argc, argv, prefix); 390 status = p->fn(argc, argv, prefix);
387 exit_browser(status); 391 exit_browser(status);
388 perf_env__exit(&perf_env); 392 perf_env__exit(&perf_env);
@@ -450,11 +454,12 @@ static void handle_internal_command(int argc, const char **argv)
450 454
451static void execv_dashed_external(const char **argv) 455static void execv_dashed_external(const char **argv)
452{ 456{
453 struct strbuf cmd = STRBUF_INIT; 457 char *cmd;
454 const char *tmp; 458 const char *tmp;
455 int status; 459 int status;
456 460
457 strbuf_addf(&cmd, "perf-%s", argv[0]); 461 if (asprintf(&cmd, "perf-%s", argv[0]) < 0)
462 goto do_die;
458 463
459 /* 464 /*
460 * argv[0] must be the perf command, but the argv array 465 * argv[0] must be the perf command, but the argv array
@@ -463,7 +468,7 @@ static void execv_dashed_external(const char **argv)
463 * restore it on error. 468 * restore it on error.
464 */ 469 */
465 tmp = argv[0]; 470 tmp = argv[0];
466 argv[0] = cmd.buf; 471 argv[0] = cmd;
467 472
468 /* 473 /*
469 * if we fail because the command is not found, it is 474 * if we fail because the command is not found, it is
@@ -471,15 +476,16 @@ static void execv_dashed_external(const char **argv)
471 */ 476 */
472 status = run_command_v_opt(argv, 0); 477 status = run_command_v_opt(argv, 0);
473 if (status != -ERR_RUN_COMMAND_EXEC) { 478 if (status != -ERR_RUN_COMMAND_EXEC) {
474 if (IS_RUN_COMMAND_ERR(status)) 479 if (IS_RUN_COMMAND_ERR(status)) {
480do_die:
475 die("unable to run '%s'", argv[0]); 481 die("unable to run '%s'", argv[0]);
482 }
476 exit(-status); 483 exit(-status);
477 } 484 }
478 errno = ENOENT; /* as if we called execvp */ 485 errno = ENOENT; /* as if we called execvp */
479 486
480 argv[0] = tmp; 487 argv[0] = tmp;
481 488 zfree(&cmd);
482 strbuf_release(&cmd);
483} 489}
484 490
485static int run_argv(int *argcp, const char ***argv) 491static int run_argv(int *argcp, const char ***argv)
@@ -528,14 +534,22 @@ int main(int argc, const char **argv)
528 const char *cmd; 534 const char *cmd;
529 char sbuf[STRERR_BUFSIZE]; 535 char sbuf[STRERR_BUFSIZE];
530 536
537 /* libsubcmd init */
538 exec_cmd_init("perf", PREFIX, PERF_EXEC_PATH, EXEC_PATH_ENVIRONMENT);
539 pager_init(PERF_PAGER_ENVIRONMENT);
540
531 /* The page_size is placed in util object. */ 541 /* The page_size is placed in util object. */
532 page_size = sysconf(_SC_PAGE_SIZE); 542 page_size = sysconf(_SC_PAGE_SIZE);
533 cacheline_size = sysconf(_SC_LEVEL1_DCACHE_LINESIZE); 543 cacheline_size = sysconf(_SC_LEVEL1_DCACHE_LINESIZE);
534 544
535 cmd = perf_extract_argv0_path(argv[0]); 545 cmd = extract_argv0_path(argv[0]);
536 if (!cmd) 546 if (!cmd)
537 cmd = "perf-help"; 547 cmd = "perf-help";
538 548
549 srandom(time(NULL));
550
551 perf_config(perf_default_config, NULL);
552
539 /* get debugfs/tracefs mount point from /proc/mounts */ 553 /* get debugfs/tracefs mount point from /proc/mounts */
540 tracing_path_mount(); 554 tracing_path_mount();
541 555
@@ -603,6 +617,8 @@ int main(int argc, const char **argv)
603 */ 617 */
604 pthread__block_sigwinch(); 618 pthread__block_sigwinch();
605 619
620 perf_debug_setup();
621
606 while (1) { 622 while (1) {
607 static int done_help; 623 static int done_help;
608 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/scripts/python/stat-cpi.py b/tools/perf/scripts/python/stat-cpi.py
new file mode 100644
index 000000000000..8b60f343dd07
--- /dev/null
+++ b/tools/perf/scripts/python/stat-cpi.py
@@ -0,0 +1,77 @@
1#!/usr/bin/env python
2
3data = {}
4times = []
5threads = []
6cpus = []
7
8def get_key(time, event, cpu, thread):
9 return "%d-%s-%d-%d" % (time, event, cpu, thread)
10
11def store_key(time, cpu, thread):
12 if (time not in times):
13 times.append(time)
14
15 if (cpu not in cpus):
16 cpus.append(cpu)
17
18 if (thread not in threads):
19 threads.append(thread)
20
21def store(time, event, cpu, thread, val, ena, run):
22 #print "event %s cpu %d, thread %d, time %d, val %d, ena %d, run %d" % \
23 # (event, cpu, thread, time, val, ena, run)
24
25 store_key(time, cpu, thread)
26 key = get_key(time, event, cpu, thread)
27 data[key] = [ val, ena, run]
28
29def get(time, event, cpu, thread):
30 key = get_key(time, event, cpu, thread)
31 return data[key][0]
32
33def stat__cycles_k(cpu, thread, time, val, ena, run):
34 store(time, "cycles", cpu, thread, val, ena, run);
35
36def stat__instructions_k(cpu, thread, time, val, ena, run):
37 store(time, "instructions", cpu, thread, val, ena, run);
38
39def stat__cycles_u(cpu, thread, time, val, ena, run):
40 store(time, "cycles", cpu, thread, val, ena, run);
41
42def stat__instructions_u(cpu, thread, time, val, ena, run):
43 store(time, "instructions", cpu, thread, val, ena, run);
44
45def stat__cycles(cpu, thread, time, val, ena, run):
46 store(time, "cycles", cpu, thread, val, ena, run);
47
48def stat__instructions(cpu, thread, time, val, ena, run):
49 store(time, "instructions", cpu, thread, val, ena, run);
50
51def stat__interval(time):
52 for cpu in cpus:
53 for thread in threads:
54 cyc = get(time, "cycles", cpu, thread)
55 ins = get(time, "instructions", cpu, thread)
56 cpi = 0
57
58 if ins != 0:
59 cpi = cyc/float(ins)
60
61 print "%15f: cpu %d, thread %d -> cpi %f (%d/%d)" % (time/(float(1000000000)), cpu, thread, cpi, cyc, ins)
62
63def trace_end():
64 pass
65# XXX trace_end callback could be used as an alternative place
66# to compute same values as in the script above:
67#
68# for time in times:
69# for cpu in cpus:
70# for thread in threads:
71# cyc = get(time, "cycles", cpu, thread)
72# ins = get(time, "instructions", cpu, thread)
73#
74# if ins != 0:
75# cpi = cyc/float(ins)
76#
77# print "time %.9f, cpu %d, thread %d -> cpi %f" % (time/(float(1000000000)), cpu, thread, cpi)
diff --git a/tools/perf/tests/.gitignore b/tools/perf/tests/.gitignore
new file mode 100644
index 000000000000..8cc30e731c73
--- /dev/null
+++ b/tools/perf/tests/.gitignore
@@ -0,0 +1,4 @@
1llvm-src-base.c
2llvm-src-kbuild.c
3llvm-src-prologue.c
4llvm-src-relocation.c
diff --git a/tools/perf/tests/Build b/tools/perf/tests/Build
index 50de2253cff6..1ba628ed049a 100644
--- a/tools/perf/tests/Build
+++ b/tools/perf/tests/Build
@@ -31,8 +31,40 @@ 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 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 += topology.o 36perf-y += topology.o
37perf-y += cpumap.o
38perf-y += stat.o
39perf-y += event_update.o
40
41$(OUTPUT)tests/llvm-src-base.c: tests/bpf-script-example.c tests/Build
42 $(call rule_mkdir)
43 $(Q)echo '#include <tests/llvm.h>' > $@
44 $(Q)echo 'const char test_llvm__bpf_base_prog[] =' >> $@
45 $(Q)sed -e 's/"/\\"/g' -e 's/\(.*\)/"\1\\n"/g' $< >> $@
46 $(Q)echo ';' >> $@
47
48$(OUTPUT)tests/llvm-src-kbuild.c: tests/bpf-script-test-kbuild.c tests/Build
49 $(call rule_mkdir)
50 $(Q)echo '#include <tests/llvm.h>' > $@
51 $(Q)echo 'const char test_llvm__bpf_test_kbuild_prog[] =' >> $@
52 $(Q)sed -e 's/"/\\"/g' -e 's/\(.*\)/"\1\\n"/g' $< >> $@
53 $(Q)echo ';' >> $@
54
55$(OUTPUT)tests/llvm-src-prologue.c: tests/bpf-script-test-prologue.c tests/Build
56 $(call rule_mkdir)
57 $(Q)echo '#include <tests/llvm.h>' > $@
58 $(Q)echo 'const char test_llvm__bpf_test_prologue_prog[] =' >> $@
59 $(Q)sed -e 's/"/\\"/g' -e 's/\(.*\)/"\1\\n"/g' $< >> $@
60 $(Q)echo ';' >> $@
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 ';' >> $@
36 68
37ifeq ($(ARCH),$(filter $(ARCH),x86 arm arm64)) 69ifeq ($(ARCH),$(filter $(ARCH),x86 arm arm64))
38perf-$(CONFIG_DWARF_UNWIND) += dwarf-unwind.o 70perf-$(CONFIG_DWARF_UNWIND) += dwarf-unwind.o
diff --git a/tools/perf/tests/attr.c b/tools/perf/tests/attr.c
index 2dfc9ad0e6f2..28d1605b0338 100644
--- a/tools/perf/tests/attr.c
+++ b/tools/perf/tests/attr.c
@@ -24,7 +24,7 @@
24#include <linux/kernel.h> 24#include <linux/kernel.h>
25#include "../perf.h" 25#include "../perf.h"
26#include "util.h" 26#include "util.h"
27#include "exec_cmd.h" 27#include <subcmd/exec-cmd.h>
28#include "tests.h" 28#include "tests.h"
29 29
30#define ENV "PERF_TEST_ATTR" 30#define ENV "PERF_TEST_ATTR"
@@ -153,7 +153,7 @@ static int run_dir(const char *d, const char *perf)
153 return system(cmd); 153 return system(cmd);
154} 154}
155 155
156int test__attr(void) 156int test__attr(int subtest __maybe_unused)
157{ 157{
158 struct stat st; 158 struct stat st;
159 char path_perf[PATH_MAX]; 159 char path_perf[PATH_MAX];
@@ -164,13 +164,12 @@ int test__attr(void)
164 return run_dir("./tests", "./perf"); 164 return run_dir("./tests", "./perf");
165 165
166 /* Then installed path. */ 166 /* Then installed path. */
167 snprintf(path_dir, PATH_MAX, "%s/tests", perf_exec_path()); 167 snprintf(path_dir, PATH_MAX, "%s/tests", get_argv_exec_path());
168 snprintf(path_perf, PATH_MAX, "%s/perf", BINDIR); 168 snprintf(path_perf, PATH_MAX, "%s/perf", BINDIR);
169 169
170 if (!lstat(path_dir, &st) && 170 if (!lstat(path_dir, &st) &&
171 !lstat(path_perf, &st)) 171 !lstat(path_perf, &st))
172 return run_dir(path_dir, path_perf); 172 return run_dir(path_dir, path_perf);
173 173
174 fprintf(stderr, " (omitted)"); 174 return TEST_SKIP;
175 return 0;
176} 175}
diff --git a/tools/perf/tests/bp_signal.c b/tools/perf/tests/bp_signal.c
index a02b035fd5aa..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;
@@ -111,10 +165,10 @@ static long long bp_count(int fd)
111 return count; 165 return count;
112} 166}
113 167
114int test__bp_signal(void) 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(void)
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(void)
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(void)
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(void)
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/bp_signal_overflow.c b/tools/perf/tests/bp_signal_overflow.c
index e76537724491..89f92fa67cc4 100644
--- a/tools/perf/tests/bp_signal_overflow.c
+++ b/tools/perf/tests/bp_signal_overflow.c
@@ -58,7 +58,7 @@ static long long bp_count(int fd)
58#define EXECUTIONS 10000 58#define EXECUTIONS 10000
59#define THRESHOLD 100 59#define THRESHOLD 100
60 60
61int test__bp_signal_overflow(void) 61int test__bp_signal_overflow(int subtest __maybe_unused)
62{ 62{
63 struct perf_event_attr pe; 63 struct perf_event_attr pe;
64 struct sigaction sa; 64 struct sigaction sa;
diff --git a/tools/perf/tests/bpf-script-example.c b/tools/perf/tests/bpf-script-example.c
index 410a70b93b93..0ec9c2c03164 100644
--- a/tools/perf/tests/bpf-script-example.c
+++ b/tools/perf/tests/bpf-script-example.c
@@ -1,3 +1,7 @@
1/*
2 * bpf-script-example.c
3 * Test basic LLVM building
4 */
1#ifndef LINUX_VERSION_CODE 5#ifndef LINUX_VERSION_CODE
2# error Need LINUX_VERSION_CODE 6# error Need LINUX_VERSION_CODE
3# error Example: for 4.2 kernel, put 'clang-opt="-DLINUX_VERSION_CODE=0x40200" into llvm section of ~/.perfconfig' 7# error Example: for 4.2 kernel, put 'clang-opt="-DLINUX_VERSION_CODE=0x40200" into llvm section of ~/.perfconfig'
diff --git a/tools/perf/tests/bpf-script-test-kbuild.c b/tools/perf/tests/bpf-script-test-kbuild.c
new file mode 100644
index 000000000000..3626924740d8
--- /dev/null
+++ b/tools/perf/tests/bpf-script-test-kbuild.c
@@ -0,0 +1,21 @@
1/*
2 * bpf-script-test-kbuild.c
3 * Test include from kernel header
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 SEC(NAME) __attribute__((section(NAME), used))
10
11#include <uapi/linux/fs.h>
12#include <uapi/asm/ptrace.h>
13
14SEC("func=vfs_llseek")
15int bpf_func__vfs_llseek(void *ctx)
16{
17 return 0;
18}
19
20char _license[] SEC("license") = "GPL";
21int _version SEC("version") = LINUX_VERSION_CODE;
diff --git a/tools/perf/tests/bpf-script-test-prologue.c b/tools/perf/tests/bpf-script-test-prologue.c
new file mode 100644
index 000000000000..7230e62c70fc
--- /dev/null
+++ b/tools/perf/tests/bpf-script-test-prologue.c
@@ -0,0 +1,35 @@
1/*
2 * bpf-script-test-prologue.c
3 * Test BPF prologue
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 SEC(NAME) __attribute__((section(NAME), used))
10
11#include <uapi/linux/fs.h>
12
13#define FMODE_READ 0x1
14#define FMODE_WRITE 0x2
15
16static void (*bpf_trace_printk)(const char *fmt, int fmt_size, ...) =
17 (void *) 6;
18
19SEC("func=null_lseek file->f_mode offset orig")
20int bpf_func__null_lseek(void *ctx, int err, unsigned long f_mode,
21 unsigned long offset, unsigned long orig)
22{
23 if (err)
24 return 0;
25 if (f_mode & FMODE_WRITE)
26 return 0;
27 if (offset & 1)
28 return 0;
29 if (orig == SEEK_CUR)
30 return 0;
31 return 1;
32}
33
34char _license[] SEC("license") = "GPL";
35int _version SEC("version") = LINUX_VERSION_CODE;
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
new file mode 100644
index 000000000000..199501c71e27
--- /dev/null
+++ b/tools/perf/tests/bpf.c
@@ -0,0 +1,315 @@
1#include <stdio.h>
2#include <sys/epoll.h>
3#include <util/util.h>
4#include <util/bpf-loader.h>
5#include <util/evlist.h>
6#include <linux/bpf.h>
7#include <linux/filter.h>
8#include <bpf/bpf.h>
9#include "tests.h"
10#include "llvm.h"
11#include "debug.h"
12#define NR_ITERS 111
13
14#ifdef HAVE_LIBBPF_SUPPORT
15
16static int epoll_pwait_loop(void)
17{
18 int i;
19
20 /* Should fail NR_ITERS times */
21 for (i = 0; i < NR_ITERS; i++)
22 epoll_pwait(-(i + 1), NULL, 0, 0, NULL);
23 return 0;
24}
25
26#ifdef HAVE_BPF_PROLOGUE
27
28static int llseek_loop(void)
29{
30 int fds[2], i;
31
32 fds[0] = open("/dev/null", O_RDONLY);
33 fds[1] = open("/dev/null", O_RDWR);
34
35 if (fds[0] < 0 || fds[1] < 0)
36 return -1;
37
38 for (i = 0; i < NR_ITERS; i++) {
39 lseek(fds[i % 2], i, (i / 2) % 2 ? SEEK_CUR : SEEK_SET);
40 lseek(fds[(i + 1) % 2], i, (i / 2) % 2 ? SEEK_CUR : SEEK_SET);
41 }
42 close(fds[0]);
43 close(fds[1]);
44 return 0;
45}
46
47#endif
48
49static struct {
50 enum test_llvm__testcase prog_id;
51 const char *desc;
52 const char *name;
53 const char *msg_compile_fail;
54 const char *msg_load_fail;
55 int (*target_func)(void);
56 int expect_result;
57} bpf_testcase_table[] = {
58 {
59 LLVM_TESTCASE_BASE,
60 "Test basic BPF filtering",
61 "[basic_bpf_test]",
62 "fix 'perf test LLVM' first",
63 "load bpf object failed",
64 &epoll_pwait_loop,
65 (NR_ITERS + 1) / 2,
66 },
67#ifdef HAVE_BPF_PROLOGUE
68 {
69 LLVM_TESTCASE_BPF_PROLOGUE,
70 "Test BPF prologue generation",
71 "[bpf_prologue_test]",
72 "fix kbuild first",
73 "check your vmlinux setting?",
74 &llseek_loop,
75 (NR_ITERS + 1) / 4,
76 },
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 },
87};
88
89static int do_test(struct bpf_object *obj, int (*func)(void),
90 int expect)
91{
92 struct record_opts opts = {
93 .target = {
94 .uid = UINT_MAX,
95 .uses_mmap = true,
96 },
97 .freq = 0,
98 .mmap_pages = 256,
99 .default_interval = 1,
100 };
101
102 char pid[16];
103 char sbuf[STRERR_BUFSIZE];
104 struct perf_evlist *evlist;
105 int i, ret = TEST_FAIL, err = 0, count = 0;
106
107 struct parse_events_evlist parse_evlist;
108 struct parse_events_error parse_error;
109
110 bzero(&parse_error, sizeof(parse_error));
111 bzero(&parse_evlist, sizeof(parse_evlist));
112 parse_evlist.error = &parse_error;
113 INIT_LIST_HEAD(&parse_evlist.list);
114
115 err = parse_events_load_bpf_obj(&parse_evlist, &parse_evlist.list, obj, NULL);
116 if (err || list_empty(&parse_evlist.list)) {
117 pr_debug("Failed to add events selected by BPF\n");
118 return TEST_FAIL;
119 }
120
121 snprintf(pid, sizeof(pid), "%d", getpid());
122 pid[sizeof(pid) - 1] = '\0';
123 opts.target.tid = opts.target.pid = pid;
124
125 /* Instead of perf_evlist__new_default, don't add default events */
126 evlist = perf_evlist__new();
127 if (!evlist) {
128 pr_debug("No ehough memory to create evlist\n");
129 return TEST_FAIL;
130 }
131
132 err = perf_evlist__create_maps(evlist, &opts.target);
133 if (err < 0) {
134 pr_debug("Not enough memory to create thread/cpu maps\n");
135 goto out_delete_evlist;
136 }
137
138 perf_evlist__splice_list_tail(evlist, &parse_evlist.list);
139 evlist->nr_groups = parse_evlist.nr_groups;
140
141 perf_evlist__config(evlist, &opts);
142
143 err = perf_evlist__open(evlist);
144 if (err < 0) {
145 pr_debug("perf_evlist__open: %s\n",
146 strerror_r(errno, sbuf, sizeof(sbuf)));
147 goto out_delete_evlist;
148 }
149
150 err = perf_evlist__mmap(evlist, opts.mmap_pages, false);
151 if (err < 0) {
152 pr_debug("perf_evlist__mmap: %s\n",
153 strerror_r(errno, sbuf, sizeof(sbuf)));
154 goto out_delete_evlist;
155 }
156
157 perf_evlist__enable(evlist);
158 (*func)();
159 perf_evlist__disable(evlist);
160
161 for (i = 0; i < evlist->nr_mmaps; i++) {
162 union perf_event *event;
163
164 while ((event = perf_evlist__mmap_read(evlist, i)) != NULL) {
165 const u32 type = event->header.type;
166
167 if (type == PERF_RECORD_SAMPLE)
168 count ++;
169 }
170 }
171
172 if (count != expect) {
173 pr_debug("BPF filter result incorrect\n");
174 goto out_delete_evlist;
175 }
176
177 ret = TEST_OK;
178
179out_delete_evlist:
180 perf_evlist__delete(evlist);
181 return ret;
182}
183
184static struct bpf_object *
185prepare_bpf(void *obj_buf, size_t obj_buf_sz, const char *name)
186{
187 struct bpf_object *obj;
188
189 obj = bpf__prepare_load_buffer(obj_buf, obj_buf_sz, name);
190 if (IS_ERR(obj)) {
191 pr_debug("Compile BPF program failed.\n");
192 return NULL;
193 }
194 return obj;
195}
196
197static int __test__bpf(int idx)
198{
199 int ret;
200 void *obj_buf;
201 size_t obj_buf_sz;
202 struct bpf_object *obj;
203
204 ret = test_llvm__fetch_bpf_obj(&obj_buf, &obj_buf_sz,
205 bpf_testcase_table[idx].prog_id,
206 true, NULL);
207 if (ret != TEST_OK || !obj_buf || !obj_buf_sz) {
208 pr_debug("Unable to get BPF object, %s\n",
209 bpf_testcase_table[idx].msg_compile_fail);
210 if (idx == 0)
211 return TEST_SKIP;
212 else
213 return TEST_FAIL;
214 }
215
216 obj = prepare_bpf(obj_buf, obj_buf_sz,
217 bpf_testcase_table[idx].name);
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);
225 ret = TEST_FAIL;
226 goto out;
227 }
228
229 if (obj)
230 ret = do_test(obj,
231 bpf_testcase_table[idx].target_func,
232 bpf_testcase_table[idx].expect_result);
233out:
234 bpf__clear();
235 return ret;
236}
237
238int test__bpf_subtest_get_nr(void)
239{
240 return (int)ARRAY_SIZE(bpf_testcase_table);
241}
242
243const char *test__bpf_subtest_get_desc(int i)
244{
245 if (i < 0 || i >= (int)ARRAY_SIZE(bpf_testcase_table))
246 return NULL;
247 return bpf_testcase_table[i].desc;
248}
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
280int test__bpf(int i)
281{
282 int err;
283
284 if (i < 0 || i >= (int)ARRAY_SIZE(bpf_testcase_table))
285 return TEST_FAIL;
286
287 if (geteuid() != 0) {
288 pr_debug("Only root can run BPF test\n");
289 return TEST_SKIP;
290 }
291
292 if (check_env())
293 return TEST_SKIP;
294
295 err = __test__bpf(i);
296 return err;
297}
298
299#else
300int test__bpf_subtest_get_nr(void)
301{
302 return 0;
303}
304
305const char *test__bpf_subtest_get_desc(int i __maybe_unused)
306{
307 return NULL;
308}
309
310int test__bpf(int i __maybe_unused)
311{
312 pr_debug("Skip BPF test because BPF support is not compiled\n");
313 return TEST_SKIP;
314}
315#endif
diff --git a/tools/perf/tests/builtin-test.c b/tools/perf/tests/builtin-test.c
index 66f72d3d6677..f2b1dcac45d3 100644
--- a/tools/perf/tests/builtin-test.c
+++ b/tools/perf/tests/builtin-test.c
@@ -11,7 +11,7 @@
11#include "tests.h" 11#include "tests.h"
12#include "debug.h" 12#include "debug.h"
13#include "color.h" 13#include "color.h"
14#include "parse-options.h" 14#include <subcmd/parse-options.h>
15#include "symbol.h" 15#include "symbol.h"
16 16
17struct test __weak arch_tests[] = { 17struct test __weak arch_tests[] = {
@@ -160,12 +160,50 @@ static struct test generic_tests[] = {
160 { 160 {
161 .desc = "Test LLVM searching and compiling", 161 .desc = "Test LLVM searching and compiling",
162 .func = test__llvm, 162 .func = test__llvm,
163 .subtest = {
164 .skip_if_fail = true,
165 .get_nr = test__llvm_subtest_get_nr,
166 .get_desc = test__llvm_subtest_get_desc,
167 },
163 }, 168 },
164 { 169 {
165 .desc = "Test topology in session", 170 .desc = "Test topology in session",
166 .func = test_session_topology, 171 .func = test_session_topology,
167 }, 172 },
168 { 173 {
174 .desc = "Test BPF filter",
175 .func = test__bpf,
176 .subtest = {
177 .skip_if_fail = true,
178 .get_nr = test__bpf_subtest_get_nr,
179 .get_desc = test__bpf_subtest_get_desc,
180 },
181 },
182 {
183 .desc = "Test thread map synthesize",
184 .func = test__thread_map_synthesize,
185 },
186 {
187 .desc = "Test cpu map synthesize",
188 .func = test__cpu_map_synthesize,
189 },
190 {
191 .desc = "Test stat config synthesize",
192 .func = test__synthesize_stat_config,
193 },
194 {
195 .desc = "Test stat synthesize",
196 .func = test__synthesize_stat,
197 },
198 {
199 .desc = "Test stat round synthesize",
200 .func = test__synthesize_stat_round,
201 },
202 {
203 .desc = "Test attr update synthesize",
204 .func = test__event_update,
205 },
206 {
169 .func = NULL, 207 .func = NULL,
170 }, 208 },
171}; 209};
@@ -192,14 +230,14 @@ static bool perf_test__matches(struct test *test, int curr, int argc, const char
192 continue; 230 continue;
193 } 231 }
194 232
195 if (strstr(test->desc, argv[i])) 233 if (strcasestr(test->desc, argv[i]))
196 return true; 234 return true;
197 } 235 }
198 236
199 return false; 237 return false;
200} 238}
201 239
202static int run_test(struct test *test) 240static int run_test(struct test *test, int subtest)
203{ 241{
204 int status, err = -1, child = fork(); 242 int status, err = -1, child = fork();
205 char sbuf[STRERR_BUFSIZE]; 243 char sbuf[STRERR_BUFSIZE];
@@ -212,7 +250,22 @@ static int run_test(struct test *test)
212 250
213 if (!child) { 251 if (!child) {
214 pr_debug("test child forked, pid %d\n", getpid()); 252 pr_debug("test child forked, pid %d\n", getpid());
215 err = test->func(); 253 if (!verbose) {
254 int nullfd = open("/dev/null", O_WRONLY);
255 if (nullfd >= 0) {
256 close(STDERR_FILENO);
257 close(STDOUT_FILENO);
258
259 dup2(nullfd, STDOUT_FILENO);
260 dup2(STDOUT_FILENO, STDERR_FILENO);
261 close(nullfd);
262 }
263 } else {
264 signal(SIGSEGV, sighandler_dump_stack);
265 signal(SIGFPE, sighandler_dump_stack);
266 }
267
268 err = test->func(subtest);
216 exit(err); 269 exit(err);
217 } 270 }
218 271
@@ -233,6 +286,40 @@ static int run_test(struct test *test)
233 for (j = 0; j < ARRAY_SIZE(tests); j++) \ 286 for (j = 0; j < ARRAY_SIZE(tests); j++) \
234 for (t = &tests[j][0]; t->func; t++) 287 for (t = &tests[j][0]; t->func; t++)
235 288
289static int test_and_print(struct test *t, bool force_skip, int subtest)
290{
291 int err;
292
293 if (!force_skip) {
294 pr_debug("\n--- start ---\n");
295 err = run_test(t, subtest);
296 pr_debug("---- end ----\n");
297 } else {
298 pr_debug("\n--- force skipped ---\n");
299 err = TEST_SKIP;
300 }
301
302 if (!t->subtest.get_nr)
303 pr_debug("%s:", t->desc);
304 else
305 pr_debug("%s subtest %d:", t->desc, subtest);
306
307 switch (err) {
308 case TEST_OK:
309 pr_info(" Ok\n");
310 break;
311 case TEST_SKIP:
312 color_fprintf(stderr, PERF_COLOR_YELLOW, " Skip\n");
313 break;
314 case TEST_FAIL:
315 default:
316 color_fprintf(stderr, PERF_COLOR_RED, " FAILED!\n");
317 break;
318 }
319
320 return err;
321}
322
236static int __cmd_test(int argc, const char *argv[], struct intlist *skiplist) 323static int __cmd_test(int argc, const char *argv[], struct intlist *skiplist)
237{ 324{
238 struct test *t; 325 struct test *t;
@@ -260,21 +347,43 @@ static int __cmd_test(int argc, const char *argv[], struct intlist *skiplist)
260 continue; 347 continue;
261 } 348 }
262 349
263 pr_debug("\n--- start ---\n"); 350 if (!t->subtest.get_nr) {
264 err = run_test(t); 351 test_and_print(t, false, -1);
265 pr_debug("---- end ----\n%s:", t->desc); 352 } else {
266 353 int subn = t->subtest.get_nr();
267 switch (err) { 354 /*
268 case TEST_OK: 355 * minus 2 to align with normal testcases.
269 pr_info(" Ok\n"); 356 * For subtest we print additional '.x' in number.
270 break; 357 * for example:
271 case TEST_SKIP: 358 *
272 color_fprintf(stderr, PERF_COLOR_YELLOW, " Skip\n"); 359 * 35: Test LLVM searching and compiling :
273 break; 360 * 35.1: Basic BPF llvm compiling test : Ok
274 case TEST_FAIL: 361 */
275 default: 362 int subw = width > 2 ? width - 2 : width;
276 color_fprintf(stderr, PERF_COLOR_RED, " FAILED!\n"); 363 bool skip = false;
277 break; 364 int subi;
365
366 if (subn <= 0) {
367 color_fprintf(stderr, PERF_COLOR_YELLOW,
368 " Skip (not compiled in)\n");
369 continue;
370 }
371 pr_info("\n");
372
373 for (subi = 0; subi < subn; subi++) {
374 int len = strlen(t->subtest.get_desc(subi));
375
376 if (subw < len)
377 subw = len;
378 }
379
380 for (subi = 0; subi < subn; subi++) {
381 pr_info("%2d.%1d: %-*s:", i, subi + 1, subw,
382 t->subtest.get_desc(subi));
383 err = test_and_print(t, skip, subi);
384 if (err != TEST_OK && t->subtest.skip_if_fail)
385 skip = true;
386 }
278 } 387 }
279 } 388 }
280 389
diff --git a/tools/perf/tests/code-reading.c b/tools/perf/tests/code-reading.c
index 49b1959dda41..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}
@@ -433,14 +430,13 @@ enum {
433 430
434static int do_test_code_reading(bool try_kcore) 431static int do_test_code_reading(bool try_kcore)
435{ 432{
436 struct machines machines;
437 struct machine *machine; 433 struct machine *machine;
438 struct thread *thread; 434 struct thread *thread;
439 struct record_opts opts = { 435 struct record_opts opts = {
440 .mmap_pages = UINT_MAX, 436 .mmap_pages = UINT_MAX,
441 .user_freq = UINT_MAX, 437 .user_freq = UINT_MAX,
442 .user_interval = ULLONG_MAX, 438 .user_interval = ULLONG_MAX,
443 .freq = 4000, 439 .freq = 500,
444 .target = { 440 .target = {
445 .uses_mmap = true, 441 .uses_mmap = true,
446 }, 442 },
@@ -459,8 +455,7 @@ static int do_test_code_reading(bool try_kcore)
459 455
460 pid = getpid(); 456 pid = getpid();
461 457
462 machines__init(&machines); 458 machine = machine__new_host();
463 machine = &machines.host;
464 459
465 ret = machine__create_kernel_maps(machine); 460 ret = machine__create_kernel_maps(machine);
466 if (ret < 0) { 461 if (ret < 0) {
@@ -549,12 +544,25 @@ static int do_test_code_reading(bool try_kcore)
549 if (ret < 0) { 544 if (ret < 0) {
550 if (!excl_kernel) { 545 if (!excl_kernel) {
551 excl_kernel = true; 546 excl_kernel = true;
547 /*
548 * Both cpus and threads are now owned by evlist
549 * and will be freed by following perf_evlist__set_maps
550 * call. Getting refference to keep them alive.
551 */
552 cpu_map__get(cpus);
553 thread_map__get(threads);
552 perf_evlist__set_maps(evlist, NULL, NULL); 554 perf_evlist__set_maps(evlist, NULL, NULL);
553 perf_evlist__delete(evlist); 555 perf_evlist__delete(evlist);
554 evlist = NULL; 556 evlist = NULL;
555 continue; 557 continue;
556 } 558 }
557 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
558 goto out_put; 566 goto out_put;
559 } 567 }
560 break; 568 break;
@@ -594,14 +602,13 @@ out_err:
594 cpu_map__put(cpus); 602 cpu_map__put(cpus);
595 thread_map__put(threads); 603 thread_map__put(threads);
596 } 604 }
597 machines__destroy_kernel_maps(&machines);
598 machine__delete_threads(machine); 605 machine__delete_threads(machine);
599 machines__exit(&machines); 606 machine__delete(machine);
600 607
601 return err; 608 return err;
602} 609}
603 610
604int test__code_reading(void) 611int test__code_reading(int subtest __maybe_unused)
605{ 612{
606 int ret; 613 int ret;
607 614
@@ -613,16 +620,16 @@ int test__code_reading(void)
613 case TEST_CODE_READING_OK: 620 case TEST_CODE_READING_OK:
614 return 0; 621 return 0;
615 case TEST_CODE_READING_NO_VMLINUX: 622 case TEST_CODE_READING_NO_VMLINUX:
616 fprintf(stderr, " (no vmlinux)"); 623 pr_debug("no vmlinux\n");
617 return 0; 624 return 0;
618 case TEST_CODE_READING_NO_KCORE: 625 case TEST_CODE_READING_NO_KCORE:
619 fprintf(stderr, " (no kcore)"); 626 pr_debug("no kcore\n");
620 return 0; 627 return 0;
621 case TEST_CODE_READING_NO_ACCESS: 628 case TEST_CODE_READING_NO_ACCESS:
622 fprintf(stderr, " (no access)"); 629 pr_debug("no access\n");
623 return 0; 630 return 0;
624 case TEST_CODE_READING_NO_KERNEL_OBJ: 631 case TEST_CODE_READING_NO_KERNEL_OBJ:
625 fprintf(stderr, " (no kernel obj)"); 632 pr_debug("no kernel obj\n");
626 return 0; 633 return 0;
627 default: 634 default:
628 return -1; 635 return -1;
diff --git a/tools/perf/tests/cpumap.c b/tools/perf/tests/cpumap.c
new file mode 100644
index 000000000000..4cb6418a8ffc
--- /dev/null
+++ b/tools/perf/tests/cpumap.c
@@ -0,0 +1,88 @@
1#include "tests.h"
2#include "cpumap.h"
3
4static int process_event_mask(struct perf_tool *tool __maybe_unused,
5 union perf_event *event,
6 struct perf_sample *sample __maybe_unused,
7 struct machine *machine __maybe_unused)
8{
9 struct cpu_map_event *map_event = &event->cpu_map;
10 struct cpu_map_mask *mask;
11 struct cpu_map_data *data;
12 struct cpu_map *map;
13 int i;
14
15 data = &map_event->data;
16
17 TEST_ASSERT_VAL("wrong type", data->type == PERF_CPU_MAP__MASK);
18
19 mask = (struct cpu_map_mask *)data->data;
20
21 TEST_ASSERT_VAL("wrong nr", mask->nr == 1);
22
23 for (i = 0; i < 20; i++) {
24 TEST_ASSERT_VAL("wrong cpu", test_bit(i, mask->mask));
25 }
26
27 map = cpu_map__new_data(data);
28 TEST_ASSERT_VAL("wrong nr", map->nr == 20);
29
30 for (i = 0; i < 20; i++) {
31 TEST_ASSERT_VAL("wrong cpu", map->map[i] == i);
32 }
33
34 cpu_map__put(map);
35 return 0;
36}
37
38static int process_event_cpus(struct perf_tool *tool __maybe_unused,
39 union perf_event *event,
40 struct perf_sample *sample __maybe_unused,
41 struct machine *machine __maybe_unused)
42{
43 struct cpu_map_event *map_event = &event->cpu_map;
44 struct cpu_map_entries *cpus;
45 struct cpu_map_data *data;
46 struct cpu_map *map;
47
48 data = &map_event->data;
49
50 TEST_ASSERT_VAL("wrong type", data->type == PERF_CPU_MAP__CPUS);
51
52 cpus = (struct cpu_map_entries *)data->data;
53
54 TEST_ASSERT_VAL("wrong nr", cpus->nr == 2);
55 TEST_ASSERT_VAL("wrong cpu", cpus->cpu[0] == 1);
56 TEST_ASSERT_VAL("wrong cpu", cpus->cpu[1] == 256);
57
58 map = cpu_map__new_data(data);
59 TEST_ASSERT_VAL("wrong nr", map->nr == 2);
60 TEST_ASSERT_VAL("wrong cpu", map->map[0] == 1);
61 TEST_ASSERT_VAL("wrong cpu", map->map[1] == 256);
62 TEST_ASSERT_VAL("wrong refcnt", atomic_read(&map->refcnt) == 1);
63 cpu_map__put(map);
64 return 0;
65}
66
67
68int test__cpu_map_synthesize(int subtest __maybe_unused)
69{
70 struct cpu_map *cpus;
71
72 /* This one is better stores in mask. */
73 cpus = cpu_map__new("0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19");
74
75 TEST_ASSERT_VAL("failed to synthesize map",
76 !perf_event__synthesize_cpu_map(NULL, cpus, process_event_mask, NULL));
77
78 cpu_map__put(cpus);
79
80 /* This one is better stores in cpu values. */
81 cpus = cpu_map__new("1,256");
82
83 TEST_ASSERT_VAL("failed to synthesize map",
84 !perf_event__synthesize_cpu_map(NULL, cpus, process_event_cpus, NULL));
85
86 cpu_map__put(cpus);
87 return 0;
88}
diff --git a/tools/perf/tests/dso-data.c b/tools/perf/tests/dso-data.c
index a218aeaf56a0..dc673ff7c437 100644
--- a/tools/perf/tests/dso-data.c
+++ b/tools/perf/tests/dso-data.c
@@ -110,7 +110,7 @@ static int dso__data_fd(struct dso *dso, struct machine *machine)
110 return fd; 110 return fd;
111} 111}
112 112
113int test__dso_data(void) 113int test__dso_data(int subtest __maybe_unused)
114{ 114{
115 struct machine machine; 115 struct machine machine;
116 struct dso *dso; 116 struct dso *dso;
@@ -245,7 +245,7 @@ static int set_fd_limit(int n)
245 return setrlimit(RLIMIT_NOFILE, &rlim); 245 return setrlimit(RLIMIT_NOFILE, &rlim);
246} 246}
247 247
248int test__dso_data_cache(void) 248int test__dso_data_cache(int subtest __maybe_unused)
249{ 249{
250 struct machine machine; 250 struct machine machine;
251 long nr_end, nr = open_files_cnt(); 251 long nr_end, nr = open_files_cnt();
@@ -302,7 +302,7 @@ int test__dso_data_cache(void)
302 return 0; 302 return 0;
303} 303}
304 304
305int test__dso_data_reopen(void) 305int test__dso_data_reopen(int subtest __maybe_unused)
306{ 306{
307 struct machine machine; 307 struct machine machine;
308 long nr_end, nr = open_files_cnt(); 308 long nr_end, nr = open_files_cnt();
diff --git a/tools/perf/tests/dwarf-unwind.c b/tools/perf/tests/dwarf-unwind.c
index 07221793a3ac..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)
@@ -51,6 +51,12 @@ static int unwind_entry(struct unwind_entry *entry, void *arg)
51 "krava_1", 51 "krava_1",
52 "test__dwarf_unwind" 52 "test__dwarf_unwind"
53 }; 53 };
54 /*
55 * The funcs[MAX_STACK] array index, based on the
56 * callchain order setup.
57 */
58 int idx = callchain_param.order == ORDER_CALLER ?
59 MAX_STACK - *cnt - 1 : *cnt;
54 60
55 if (*cnt >= MAX_STACK) { 61 if (*cnt >= MAX_STACK) {
56 pr_debug("failed: crossed the max stack value %d\n", MAX_STACK); 62 pr_debug("failed: crossed the max stack value %d\n", MAX_STACK);
@@ -63,8 +69,10 @@ static int unwind_entry(struct unwind_entry *entry, void *arg)
63 return -1; 69 return -1;
64 } 70 }
65 71
66 pr_debug("got: %s 0x%" PRIx64 "\n", symbol, entry->ip); 72 (*cnt)++;
67 return strcmp((const char *) symbol, funcs[(*cnt)++]); 73 pr_debug("got: %s 0x%" PRIx64 ", expecting %s\n",
74 symbol, entry->ip, funcs[idx]);
75 return strcmp((const char *) symbol, funcs[idx]);
68} 76}
69 77
70__attribute__ ((noinline)) 78__attribute__ ((noinline))
@@ -105,8 +113,16 @@ static int compare(void *p1, void *p2)
105 /* Any possible value should be 'thread' */ 113 /* Any possible value should be 'thread' */
106 struct thread *thread = *(struct thread **)p1; 114 struct thread *thread = *(struct thread **)p1;
107 115
108 if (global_unwind_retval == -INT_MAX) 116 if (global_unwind_retval == -INT_MAX) {
117 /* Call unwinder twice for both callchain orders. */
118 callchain_param.order = ORDER_CALLER;
119
109 global_unwind_retval = unwind_thread(thread); 120 global_unwind_retval = unwind_thread(thread);
121 if (!global_unwind_retval) {
122 callchain_param.order = ORDER_CALLEE;
123 global_unwind_retval = unwind_thread(thread);
124 }
125 }
110 126
111 return p1 - p2; 127 return p1 - p2;
112} 128}
@@ -142,21 +158,23 @@ static int krava_1(struct thread *thread)
142 return krava_2(thread); 158 return krava_2(thread);
143} 159}
144 160
145int test__dwarf_unwind(void) 161int test__dwarf_unwind(int subtest __maybe_unused)
146{ 162{
147 struct machines machines;
148 struct machine *machine; 163 struct machine *machine;
149 struct thread *thread; 164 struct thread *thread;
150 int err = -1; 165 int err = -1;
151 166
152 machines__init(&machines); 167 machine = machine__new_host();
153
154 machine = machines__find(&machines, HOST_KERNEL_ID);
155 if (!machine) { 168 if (!machine) {
156 pr_err("Could not get machine\n"); 169 pr_err("Could not get machine\n");
157 return -1; 170 return -1;
158 } 171 }
159 172
173 if (machine__create_kernel_maps(machine)) {
174 pr_err("Failed to create kernel maps\n");
175 return -1;
176 }
177
160 callchain_param.record_mode = CALLCHAIN_DWARF; 178 callchain_param.record_mode = CALLCHAIN_DWARF;
161 179
162 if (init_live_machine(machine)) { 180 if (init_live_machine(machine)) {
@@ -178,7 +196,6 @@ int test__dwarf_unwind(void)
178 196
179 out: 197 out:
180 machine__delete_threads(machine); 198 machine__delete_threads(machine);
181 machine__exit(machine); 199 machine__delete(machine);
182 machines__exit(&machines);
183 return err; 200 return err;
184} 201}
diff --git a/tools/perf/tests/event_update.c b/tools/perf/tests/event_update.c
new file mode 100644
index 000000000000..012eab5d1df1
--- /dev/null
+++ b/tools/perf/tests/event_update.c
@@ -0,0 +1,117 @@
1#include <linux/compiler.h>
2#include "evlist.h"
3#include "evsel.h"
4#include "machine.h"
5#include "tests.h"
6#include "debug.h"
7
8static int process_event_unit(struct perf_tool *tool __maybe_unused,
9 union perf_event *event,
10 struct perf_sample *sample __maybe_unused,
11 struct machine *machine __maybe_unused)
12{
13 struct event_update_event *ev = (struct event_update_event *) event;
14
15 TEST_ASSERT_VAL("wrong id", ev->id == 123);
16 TEST_ASSERT_VAL("wrong id", ev->type == PERF_EVENT_UPDATE__UNIT);
17 TEST_ASSERT_VAL("wrong unit", !strcmp(ev->data, "KRAVA"));
18 return 0;
19}
20
21static int process_event_scale(struct perf_tool *tool __maybe_unused,
22 union perf_event *event,
23 struct perf_sample *sample __maybe_unused,
24 struct machine *machine __maybe_unused)
25{
26 struct event_update_event *ev = (struct event_update_event *) event;
27 struct event_update_event_scale *ev_data;
28
29 ev_data = (struct event_update_event_scale *) ev->data;
30
31 TEST_ASSERT_VAL("wrong id", ev->id == 123);
32 TEST_ASSERT_VAL("wrong id", ev->type == PERF_EVENT_UPDATE__SCALE);
33 TEST_ASSERT_VAL("wrong scale", ev_data->scale = 0.123);
34 return 0;
35}
36
37struct event_name {
38 struct perf_tool tool;
39 const char *name;
40};
41
42static int process_event_name(struct perf_tool *tool,
43 union perf_event *event,
44 struct perf_sample *sample __maybe_unused,
45 struct machine *machine __maybe_unused)
46{
47 struct event_name *tmp = container_of(tool, struct event_name, tool);
48 struct event_update_event *ev = (struct event_update_event*) event;
49
50 TEST_ASSERT_VAL("wrong id", ev->id == 123);
51 TEST_ASSERT_VAL("wrong id", ev->type == PERF_EVENT_UPDATE__NAME);
52 TEST_ASSERT_VAL("wrong name", !strcmp(ev->data, tmp->name));
53 return 0;
54}
55
56static int process_event_cpus(struct perf_tool *tool __maybe_unused,
57 union perf_event *event,
58 struct perf_sample *sample __maybe_unused,
59 struct machine *machine __maybe_unused)
60{
61 struct event_update_event *ev = (struct event_update_event*) event;
62 struct event_update_event_cpus *ev_data;
63 struct cpu_map *map;
64
65 ev_data = (struct event_update_event_cpus*) ev->data;
66
67 map = cpu_map__new_data(&ev_data->cpus);
68
69 TEST_ASSERT_VAL("wrong id", ev->id == 123);
70 TEST_ASSERT_VAL("wrong type", ev->type == PERF_EVENT_UPDATE__CPUS);
71 TEST_ASSERT_VAL("wrong cpus", map->nr == 3);
72 TEST_ASSERT_VAL("wrong cpus", map->map[0] == 1);
73 TEST_ASSERT_VAL("wrong cpus", map->map[1] == 2);
74 TEST_ASSERT_VAL("wrong cpus", map->map[2] == 3);
75 cpu_map__put(map);
76 return 0;
77}
78
79int test__event_update(int subtest __maybe_unused)
80{
81 struct perf_evlist *evlist;
82 struct perf_evsel *evsel;
83 struct event_name tmp;
84
85 evlist = perf_evlist__new_default();
86 TEST_ASSERT_VAL("failed to get evlist", evlist);
87
88 evsel = perf_evlist__first(evlist);
89
90 TEST_ASSERT_VAL("failed to allos ids",
91 !perf_evsel__alloc_id(evsel, 1, 1));
92
93 perf_evlist__id_add(evlist, evsel, 0, 0, 123);
94
95 evsel->unit = strdup("KRAVA");
96
97 TEST_ASSERT_VAL("failed to synthesize attr update unit",
98 !perf_event__synthesize_event_update_unit(NULL, evsel, process_event_unit));
99
100 evsel->scale = 0.123;
101
102 TEST_ASSERT_VAL("failed to synthesize attr update scale",
103 !perf_event__synthesize_event_update_scale(NULL, evsel, process_event_scale));
104
105 tmp.name = perf_evsel__name(evsel);
106
107 TEST_ASSERT_VAL("failed to synthesize attr update name",
108 !perf_event__synthesize_event_update_name(&tmp.tool, evsel, process_event_name));
109
110 evsel->own_cpus = cpu_map__new("1,2,3");
111
112 TEST_ASSERT_VAL("failed to synthesize attr update cpus",
113 !perf_event__synthesize_event_update_cpus(&tmp.tool, evsel, process_event_cpus));
114
115 cpu_map__put(evsel->own_cpus);
116 return 0;
117}
diff --git a/tools/perf/tests/evsel-roundtrip-name.c b/tools/perf/tests/evsel-roundtrip-name.c
index 3fa715987a5e..2de4a4f2c3ed 100644
--- a/tools/perf/tests/evsel-roundtrip-name.c
+++ b/tools/perf/tests/evsel-roundtrip-name.c
@@ -95,7 +95,7 @@ out_delete_evlist:
95#define perf_evsel__name_array_test(names) \ 95#define perf_evsel__name_array_test(names) \
96 __perf_evsel__name_array_test(names, ARRAY_SIZE(names)) 96 __perf_evsel__name_array_test(names, ARRAY_SIZE(names))
97 97
98int test__perf_evsel__roundtrip_name_test(void) 98int test__perf_evsel__roundtrip_name_test(int subtest __maybe_unused)
99{ 99{
100 int err = 0, ret = 0; 100 int err = 0, ret = 0;
101 101
@@ -103,7 +103,8 @@ int test__perf_evsel__roundtrip_name_test(void)
103 if (err) 103 if (err)
104 ret = err; 104 ret = err;
105 105
106 err = perf_evsel__name_array_test(perf_evsel__sw_names); 106 err = __perf_evsel__name_array_test(perf_evsel__sw_names,
107 PERF_COUNT_SW_DUMMY + 1);
107 if (err) 108 if (err)
108 ret = err; 109 ret = err;
109 110
diff --git a/tools/perf/tests/evsel-tp-sched.c b/tools/perf/tests/evsel-tp-sched.c
index 790e413d9a1f..1984b3bbfe15 100644
--- a/tools/perf/tests/evsel-tp-sched.c
+++ b/tools/perf/tests/evsel-tp-sched.c
@@ -32,7 +32,7 @@ static int perf_evsel__test_field(struct perf_evsel *evsel, const char *name,
32 return ret; 32 return ret;
33} 33}
34 34
35int test__perf_evsel__tp_sched_test(void) 35int test__perf_evsel__tp_sched_test(int subtest __maybe_unused)
36{ 36{
37 struct perf_evsel *evsel = perf_evsel__newtp("sched", "sched_switch"); 37 struct perf_evsel *evsel = perf_evsel__newtp("sched", "sched_switch");
38 int ret = 0; 38 int ret = 0;
diff --git a/tools/perf/tests/fdarray.c b/tools/perf/tests/fdarray.c
index d24b837951d4..c809463edbe5 100644
--- a/tools/perf/tests/fdarray.c
+++ b/tools/perf/tests/fdarray.c
@@ -25,7 +25,7 @@ static int fdarray__fprintf_prefix(struct fdarray *fda, const char *prefix, FILE
25 return printed + fdarray__fprintf(fda, fp); 25 return printed + fdarray__fprintf(fda, fp);
26} 26}
27 27
28int test__fdarray__filter(void) 28int test__fdarray__filter(int subtest __maybe_unused)
29{ 29{
30 int nr_fds, expected_fd[2], fd, err = TEST_FAIL; 30 int nr_fds, expected_fd[2], fd, err = TEST_FAIL;
31 struct fdarray *fda = fdarray__new(5, 5); 31 struct fdarray *fda = fdarray__new(5, 5);
@@ -103,7 +103,7 @@ out:
103 return err; 103 return err;
104} 104}
105 105
106int test__fdarray__add(void) 106int test__fdarray__add(int subtest __maybe_unused)
107{ 107{
108 int err = TEST_FAIL; 108 int err = TEST_FAIL;
109 struct fdarray *fda = fdarray__new(2, 2); 109 struct fdarray *fda = fdarray__new(2, 2);
diff --git a/tools/perf/tests/hists_common.c b/tools/perf/tests/hists_common.c
index ce80b274b097..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++) {
@@ -150,7 +152,6 @@ struct machine *setup_fake_machine(struct machines *machines)
150out: 152out:
151 pr_debug("Not enough memory for machine setup\n"); 153 pr_debug("Not enough memory for machine setup\n");
152 machine__delete_threads(machine); 154 machine__delete_threads(machine);
153 machine__delete(machine);
154 return NULL; 155 return NULL;
155} 156}
156 157
diff --git a/tools/perf/tests/hists_cumulate.c b/tools/perf/tests/hists_cumulate.c
index 7ed737019de7..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",
@@ -281,7 +276,7 @@ static int test1(struct perf_evsel *evsel, struct machine *machine)
281 symbol_conf.cumulate_callchain = false; 276 symbol_conf.cumulate_callchain = false;
282 perf_evsel__reset_sample_bit(evsel, CALLCHAIN); 277 perf_evsel__reset_sample_bit(evsel, CALLCHAIN);
283 278
284 setup_sorting(); 279 setup_sorting(NULL);
285 callchain_register_param(&callchain_param); 280 callchain_register_param(&callchain_param);
286 281
287 err = add_hist_entries(hists, machine); 282 err = add_hist_entries(hists, machine);
@@ -428,7 +423,7 @@ static int test2(struct perf_evsel *evsel, struct machine *machine)
428 symbol_conf.cumulate_callchain = false; 423 symbol_conf.cumulate_callchain = false;
429 perf_evsel__set_sample_bit(evsel, CALLCHAIN); 424 perf_evsel__set_sample_bit(evsel, CALLCHAIN);
430 425
431 setup_sorting(); 426 setup_sorting(NULL);
432 callchain_register_param(&callchain_param); 427 callchain_register_param(&callchain_param);
433 428
434 err = add_hist_entries(hists, machine); 429 err = add_hist_entries(hists, machine);
@@ -486,7 +481,7 @@ static int test3(struct perf_evsel *evsel, struct machine *machine)
486 symbol_conf.cumulate_callchain = true; 481 symbol_conf.cumulate_callchain = true;
487 perf_evsel__reset_sample_bit(evsel, CALLCHAIN); 482 perf_evsel__reset_sample_bit(evsel, CALLCHAIN);
488 483
489 setup_sorting(); 484 setup_sorting(NULL);
490 callchain_register_param(&callchain_param); 485 callchain_register_param(&callchain_param);
491 486
492 err = add_hist_entries(hists, machine); 487 err = add_hist_entries(hists, machine);
@@ -670,7 +665,7 @@ static int test4(struct perf_evsel *evsel, struct machine *machine)
670 symbol_conf.cumulate_callchain = true; 665 symbol_conf.cumulate_callchain = true;
671 perf_evsel__set_sample_bit(evsel, CALLCHAIN); 666 perf_evsel__set_sample_bit(evsel, CALLCHAIN);
672 667
673 setup_sorting(); 668 setup_sorting(NULL);
674 callchain_register_param(&callchain_param); 669 callchain_register_param(&callchain_param);
675 670
676 err = add_hist_entries(hists, machine); 671 err = add_hist_entries(hists, machine);
@@ -686,7 +681,7 @@ out:
686 return err; 681 return err;
687} 682}
688 683
689int test__hists_cumulate(void) 684int test__hists_cumulate(int subtest __maybe_unused)
690{ 685{
691 int err = TEST_FAIL; 686 int err = TEST_FAIL;
692 struct machines machines; 687 struct machines machines;
@@ -706,6 +701,7 @@ int test__hists_cumulate(void)
706 err = parse_events(evlist, "cpu-clock", NULL); 701 err = parse_events(evlist, "cpu-clock", NULL);
707 if (err) 702 if (err)
708 goto out; 703 goto out;
704 err = TEST_FAIL;
709 705
710 machines__init(&machines); 706 machines__init(&machines);
711 707
diff --git a/tools/perf/tests/hists_filter.c b/tools/perf/tests/hists_filter.c
index 818acf875dd0..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;
@@ -104,7 +99,7 @@ out:
104 return TEST_FAIL; 99 return TEST_FAIL;
105} 100}
106 101
107int test__hists_filter(void) 102int test__hists_filter(int subtest __maybe_unused)
108{ 103{
109 int err = TEST_FAIL; 104 int err = TEST_FAIL;
110 struct machines machines; 105 struct machines machines;
@@ -120,9 +115,10 @@ int test__hists_filter(void)
120 err = parse_events(evlist, "task-clock", NULL); 115 err = parse_events(evlist, "task-clock", NULL);
121 if (err) 116 if (err)
122 goto out; 117 goto out;
118 err = TEST_FAIL;
123 119
124 /* default sort order (comm,dso,sym) will be used */ 120 /* default sort order (comm,dso,sym) will be used */
125 if (setup_sorting() < 0) 121 if (setup_sorting(NULL) < 0)
126 goto out; 122 goto out;
127 123
128 machines__init(&machines); 124 machines__init(&machines);
@@ -144,7 +140,7 @@ int test__hists_filter(void)
144 struct hists *hists = evsel__hists(evsel); 140 struct hists *hists = evsel__hists(evsel);
145 141
146 hists__collapse_resort(hists, NULL); 142 hists__collapse_resort(hists, NULL);
147 hists__output_resort(hists, NULL); 143 perf_evsel__output_resort(evsel, NULL);
148 144
149 if (verbose > 2) { 145 if (verbose > 2) {
150 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 8c102b011424..358324e47805 100644
--- a/tools/perf/tests/hists_link.c
+++ b/tools/perf/tests/hists_link.c
@@ -64,7 +64,7 @@ static int add_hist_entries(struct perf_evlist *evlist, struct machine *machine)
64 struct perf_evsel *evsel; 64 struct perf_evsel *evsel;
65 struct addr_location al; 65 struct addr_location al;
66 struct hist_entry *he; 66 struct hist_entry *he;
67 struct perf_sample sample = { .period = 1, }; 67 struct perf_sample sample = { .period = 1, .weight = 1, };
68 size_t i = 0, k; 68 size_t i = 0, k;
69 69
70 /* 70 /*
@@ -76,21 +76,16 @@ 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,
93 NULL, NULL, 1, 1, 0, true); 88 NULL, NULL, &sample, true);
94 if (he == NULL) { 89 if (he == NULL) {
95 addr_location__put(&al); 90 addr_location__put(&al);
96 goto out; 91 goto out;
@@ -102,21 +97,14 @@ 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,
119 NULL, NULL, 1, 1, 0, true); 107 NULL, NULL, &sample, true);
120 if (he == NULL) { 108 if (he == NULL) {
121 addr_location__put(&al); 109 addr_location__put(&al);
122 goto out; 110 goto out;
@@ -274,7 +262,7 @@ static int validate_link(struct hists *leader, struct hists *other)
274 return __validate_link(leader, 0) || __validate_link(other, 1); 262 return __validate_link(leader, 0) || __validate_link(other, 1);
275} 263}
276 264
277int test__hists_link(void) 265int test__hists_link(int subtest __maybe_unused)
278{ 266{
279 int err = -1; 267 int err = -1;
280 struct hists *hists, *first_hists; 268 struct hists *hists, *first_hists;
@@ -293,8 +281,9 @@ int test__hists_link(void)
293 if (err) 281 if (err)
294 goto out; 282 goto out;
295 283
284 err = TEST_FAIL;
296 /* default sort order (comm,dso,sym) will be used */ 285 /* default sort order (comm,dso,sym) will be used */
297 if (setup_sorting() < 0) 286 if (setup_sorting(NULL) < 0)
298 goto out; 287 goto out;
299 288
300 machines__init(&machines); 289 machines__init(&machines);
diff --git a/tools/perf/tests/hists_output.c b/tools/perf/tests/hists_output.c
index adbebc852cc8..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,
@@ -134,7 +129,7 @@ static int test1(struct perf_evsel *evsel, struct machine *machine)
134 field_order = NULL; 129 field_order = NULL;
135 sort_order = NULL; /* equivalent to sort_order = "comm,dso,sym" */ 130 sort_order = NULL; /* equivalent to sort_order = "comm,dso,sym" */
136 131
137 setup_sorting(); 132 setup_sorting(NULL);
138 133
139 /* 134 /*
140 * expected output: 135 * expected output:
@@ -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);
@@ -236,7 +231,7 @@ static int test2(struct perf_evsel *evsel, struct machine *machine)
236 field_order = "overhead,cpu"; 231 field_order = "overhead,cpu";
237 sort_order = "pid"; 232 sort_order = "pid";
238 233
239 setup_sorting(); 234 setup_sorting(NULL);
240 235
241 /* 236 /*
242 * expected output: 237 * expected output:
@@ -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);
@@ -292,7 +287,7 @@ static int test3(struct perf_evsel *evsel, struct machine *machine)
292 field_order = "comm,overhead,dso"; 287 field_order = "comm,overhead,dso";
293 sort_order = NULL; 288 sort_order = NULL;
294 289
295 setup_sorting(); 290 setup_sorting(NULL);
296 291
297 /* 292 /*
298 * expected output: 293 * expected output:
@@ -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);
@@ -366,7 +361,7 @@ static int test4(struct perf_evsel *evsel, struct machine *machine)
366 field_order = "dso,sym,comm,overhead,dso"; 361 field_order = "dso,sym,comm,overhead,dso";
367 sort_order = "sym"; 362 sort_order = "sym";
368 363
369 setup_sorting(); 364 setup_sorting(NULL);
370 365
371 /* 366 /*
372 * expected output: 367 * expected output:
@@ -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);
@@ -468,7 +463,7 @@ static int test5(struct perf_evsel *evsel, struct machine *machine)
468 field_order = "cpu,pid,comm,dso,sym"; 463 field_order = "cpu,pid,comm,dso,sym";
469 sort_order = "dso,pid"; 464 sort_order = "dso,pid";
470 465
471 setup_sorting(); 466 setup_sorting(NULL);
472 467
473 /* 468 /*
474 * expected output: 469 * expected output:
@@ -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);
@@ -576,7 +571,7 @@ out:
576 return err; 571 return err;
577} 572}
578 573
579int test__hists_output(void) 574int test__hists_output(int subtest __maybe_unused)
580{ 575{
581 int err = TEST_FAIL; 576 int err = TEST_FAIL;
582 struct machines machines; 577 struct machines machines;
@@ -597,6 +592,7 @@ int test__hists_output(void)
597 err = parse_events(evlist, "cpu-clock", NULL); 592 err = parse_events(evlist, "cpu-clock", NULL);
598 if (err) 593 if (err)
599 goto out; 594 goto out;
595 err = TEST_FAIL;
600 596
601 machines__init(&machines); 597 machines__init(&machines);
602 598
diff --git a/tools/perf/tests/keep-tracking.c b/tools/perf/tests/keep-tracking.c
index 4d4b9837b630..ddb78fae064a 100644
--- a/tools/perf/tests/keep-tracking.c
+++ b/tools/perf/tests/keep-tracking.c
@@ -49,13 +49,12 @@ static int find_comm(struct perf_evlist *evlist, const char *comm)
49 * when an event is disabled but a dummy software event is not disabled. If the 49 * when an event is disabled but a dummy software event is not disabled. If the
50 * test passes %0 is returned, otherwise %-1 is returned. 50 * test passes %0 is returned, otherwise %-1 is returned.
51 */ 51 */
52int test__keep_tracking(void) 52int test__keep_tracking(int subtest __maybe_unused)
53{ 53{
54 struct record_opts opts = { 54 struct record_opts opts = {
55 .mmap_pages = UINT_MAX, 55 .mmap_pages = UINT_MAX,
56 .user_freq = UINT_MAX, 56 .user_freq = UINT_MAX,
57 .user_interval = ULLONG_MAX, 57 .user_interval = ULLONG_MAX,
58 .freq = 4000,
59 .target = { 58 .target = {
60 .uses_mmap = true, 59 .uses_mmap = true,
61 }, 60 },
@@ -90,8 +89,8 @@ int test__keep_tracking(void)
90 evsel->attr.enable_on_exec = 0; 89 evsel->attr.enable_on_exec = 0;
91 90
92 if (perf_evlist__open(evlist) < 0) { 91 if (perf_evlist__open(evlist) < 0) {
93 fprintf(stderr, " (not supported)"); 92 pr_debug("Unable to open dummy and cycles event\n");
94 err = 0; 93 err = TEST_SKIP;
95 goto out_err; 94 goto out_err;
96 } 95 }
97 96
@@ -124,7 +123,7 @@ int test__keep_tracking(void)
124 123
125 evsel = perf_evlist__last(evlist); 124 evsel = perf_evlist__last(evlist);
126 125
127 CHECK__(perf_evlist__disable_event(evlist, evsel)); 126 CHECK__(perf_evsel__disable(evsel));
128 127
129 comm = "Test COMM 2"; 128 comm = "Test COMM 2";
130 CHECK__(prctl(PR_SET_NAME, (unsigned long)comm, 0, 0, 0)); 129 CHECK__(prctl(PR_SET_NAME, (unsigned long)comm, 0, 0, 0));
diff --git a/tools/perf/tests/kmod-path.c b/tools/perf/tests/kmod-path.c
index 08c433b4bf4f..d2af78193153 100644
--- a/tools/perf/tests/kmod-path.c
+++ b/tools/perf/tests/kmod-path.c
@@ -49,7 +49,7 @@ static int test_is_kernel_module(const char *path, int cpumode, bool expect)
49#define M(path, c, e) \ 49#define M(path, c, e) \
50 TEST_ASSERT_VAL("failed", !test_is_kernel_module(path, c, e)) 50 TEST_ASSERT_VAL("failed", !test_is_kernel_module(path, c, e))
51 51
52int test__kmod_path__parse(void) 52int test__kmod_path__parse(int subtest __maybe_unused)
53{ 53{
54 /* path alloc_name alloc_ext kmod comp name ext */ 54 /* path alloc_name alloc_ext kmod comp name ext */
55 T("/xxxx/xxxx/x-x.ko", true , true , true, false, "[x_x]", NULL); 55 T("/xxxx/xxxx/x-x.ko", true , true , true, false, "[x_x]", NULL);
diff --git a/tools/perf/tests/llvm.c b/tools/perf/tests/llvm.c
index 52d55971f66f..cff564fb4b66 100644
--- a/tools/perf/tests/llvm.c
+++ b/tools/perf/tests/llvm.c
@@ -2,97 +2,169 @@
2#include <bpf/libbpf.h> 2#include <bpf/libbpf.h>
3#include <util/llvm-utils.h> 3#include <util/llvm-utils.h>
4#include <util/cache.h> 4#include <util/cache.h>
5#include "llvm.h"
5#include "tests.h" 6#include "tests.h"
6#include "debug.h" 7#include "debug.h"
7 8
8static int perf_config_cb(const char *var, const char *val,
9 void *arg __maybe_unused)
10{
11 return perf_default_config(var, val, arg);
12}
13
14/*
15 * Randomly give it a "version" section since we don't really load it
16 * into kernel
17 */
18static const char test_bpf_prog[] =
19 "__attribute__((section(\"do_fork\"), used)) "
20 "int fork(void *ctx) {return 0;} "
21 "char _license[] __attribute__((section(\"license\"), used)) = \"GPL\";"
22 "int _version __attribute__((section(\"version\"), used)) = 0x40100;";
23
24#ifdef HAVE_LIBBPF_SUPPORT 9#ifdef HAVE_LIBBPF_SUPPORT
25static 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)
26{ 11{
27 struct bpf_object *obj; 12 struct bpf_object *obj;
28 13
29 obj = bpf_object__open_buffer(obj_buf, obj_buf_sz, NULL); 14 obj = bpf_object__open_buffer(obj_buf, obj_buf_sz, NULL);
30 if (!obj) 15 if (IS_ERR(obj))
31 return -1; 16 return TEST_FAIL;
32 bpf_object__close(obj); 17 bpf_object__close(obj);
33 return 0; 18 return TEST_OK;
34} 19}
35#else 20#else
36static int test__bpf_parsing(void *obj_buf __maybe_unused, 21static int test__bpf_parsing(void *obj_buf __maybe_unused,
37 size_t obj_buf_sz __maybe_unused) 22 size_t obj_buf_sz __maybe_unused)
38{ 23{
39 fprintf(stderr, " (skip bpf parsing)"); 24 pr_debug("Skip bpf parsing\n");
40 return 0; 25 return TEST_OK;
41} 26}
42#endif 27#endif
43 28
44int test__llvm(void) 29static struct {
30 const char *source;
31 const char *desc;
32 bool should_load_fail;
33} bpf_source_table[__LLVM_TESTCASE_MAX] = {
34 [LLVM_TESTCASE_BASE] = {
35 .source = test_llvm__bpf_base_prog,
36 .desc = "Basic BPF llvm compiling test",
37 },
38 [LLVM_TESTCASE_KBUILD] = {
39 .source = test_llvm__bpf_test_kbuild_prog,
40 .desc = "Test kbuild searching",
41 },
42 [LLVM_TESTCASE_BPF_PROLOGUE] = {
43 .source = test_llvm__bpf_test_prologue_prog,
44 .desc = "Compile source for BPF prologue generation test",
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};
52
53int
54test_llvm__fetch_bpf_obj(void **p_obj_buf,
55 size_t *p_obj_buf_sz,
56 enum test_llvm__testcase idx,
57 bool force,
58 bool *should_load_fail)
45{ 59{
46 char *tmpl_new, *clang_opt_new; 60 const char *source;
47 void *obj_buf; 61 const char *desc;
48 size_t obj_buf_sz; 62 const char *tmpl_old, *clang_opt_old;
49 int err, old_verbose; 63 char *tmpl_new = NULL, *clang_opt_new = NULL;
64 int err, old_verbose, ret = TEST_FAIL;
65
66 if (idx >= __LLVM_TESTCASE_MAX)
67 return TEST_FAIL;
50 68
51 perf_config(perf_config_cb, NULL); 69 source = bpf_source_table[idx].source;
70 desc = bpf_source_table[idx].desc;
71 if (should_load_fail)
72 *should_load_fail = bpf_source_table[idx].should_load_fail;
52 73
53 /* 74 /*
54 * 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
55 * and clang is not found in $PATH, and this is not perf test -v 76 * and clang is not found in $PATH, and this is not perf test -v
56 */ 77 */
57 if (verbose == 0 && !llvm_param.user_set_param && llvm__search_clang()) { 78 if (!force && (verbose == 0 &&
58 fprintf(stderr, " (no clang, try 'perf test -v LLVM')"); 79 !llvm_param.user_set_param &&
80 llvm__search_clang())) {
81 pr_debug("No clang and no verbosive, skip this test\n");
59 return TEST_SKIP; 82 return TEST_SKIP;
60 } 83 }
61 84
62 old_verbose = verbose;
63 /* 85 /*
64 * llvm is verbosity when error. Suppress all error output if 86 * llvm is verbosity when error. Suppress all error output if
65 * not 'perf test -v'. 87 * not 'perf test -v'.
66 */ 88 */
89 old_verbose = verbose;
67 if (verbose == 0) 90 if (verbose == 0)
68 verbose = -1; 91 verbose = -1;
69 92
93 *p_obj_buf = NULL;
94 *p_obj_buf_sz = 0;
95
70 if (!llvm_param.clang_bpf_cmd_template) 96 if (!llvm_param.clang_bpf_cmd_template)
71 return -1; 97 goto out;
72 98
73 if (!llvm_param.clang_opt) 99 if (!llvm_param.clang_opt)
74 llvm_param.clang_opt = strdup(""); 100 llvm_param.clang_opt = strdup("");
75 101
76 err = asprintf(&tmpl_new, "echo '%s' | %s", test_bpf_prog, 102 err = asprintf(&tmpl_new, "echo '%s' | %s%s", source,
77 llvm_param.clang_bpf_cmd_template); 103 llvm_param.clang_bpf_cmd_template,
104 old_verbose ? "" : " 2>/dev/null");
78 if (err < 0) 105 if (err < 0)
79 return -1; 106 goto out;
80 err = asprintf(&clang_opt_new, "-xc %s", llvm_param.clang_opt); 107 err = asprintf(&clang_opt_new, "-xc %s", llvm_param.clang_opt);
81 if (err < 0) 108 if (err < 0)
82 return -1; 109 goto out;
83 110
111 tmpl_old = llvm_param.clang_bpf_cmd_template;
84 llvm_param.clang_bpf_cmd_template = tmpl_new; 112 llvm_param.clang_bpf_cmd_template = tmpl_new;
113 clang_opt_old = llvm_param.clang_opt;
85 llvm_param.clang_opt = clang_opt_new; 114 llvm_param.clang_opt = clang_opt_new;
86 err = llvm__compile_bpf("-", &obj_buf, &obj_buf_sz); 115
116 err = llvm__compile_bpf("-", p_obj_buf, p_obj_buf_sz);
117
118 llvm_param.clang_bpf_cmd_template = tmpl_old;
119 llvm_param.clang_opt = clang_opt_old;
87 120
88 verbose = old_verbose; 121 verbose = old_verbose;
89 if (err) { 122 if (err)
90 if (!verbose) 123 goto out;
91 fprintf(stderr, " (use -v to see error message)"); 124
92 return -1; 125 ret = TEST_OK;
93 } 126out:
127 free(tmpl_new);
128 free(clang_opt_new);
129 if (ret != TEST_OK)
130 pr_debug("Failed to compile test case: '%s'\n", desc);
131 return ret;
132}
94 133
95 err = test__bpf_parsing(obj_buf, obj_buf_sz); 134int test__llvm(int subtest)
135{
136 int ret;
137 void *obj_buf = NULL;
138 size_t obj_buf_sz = 0;
139 bool should_load_fail = false;
140
141 if ((subtest < 0) || (subtest >= __LLVM_TESTCASE_MAX))
142 return TEST_FAIL;
143
144 ret = test_llvm__fetch_bpf_obj(&obj_buf, &obj_buf_sz,
145 subtest, false, &should_load_fail);
146
147 if (ret == TEST_OK && !should_load_fail) {
148 ret = test__bpf_parsing(obj_buf, obj_buf_sz);
149 if (ret != TEST_OK) {
150 pr_debug("Failed to parse test case '%s'\n",
151 bpf_source_table[subtest].desc);
152 }
153 }
96 free(obj_buf); 154 free(obj_buf);
97 return err; 155
156 return ret;
157}
158
159int test__llvm_subtest_get_nr(void)
160{
161 return __LLVM_TESTCASE_MAX;
162}
163
164const char *test__llvm_subtest_get_desc(int subtest)
165{
166 if ((subtest < 0) || (subtest >= __LLVM_TESTCASE_MAX))
167 return NULL;
168
169 return bpf_source_table[subtest].desc;
98} 170}
diff --git a/tools/perf/tests/llvm.h b/tools/perf/tests/llvm.h
new file mode 100644
index 000000000000..0eaa604be99d
--- /dev/null
+++ b/tools/perf/tests/llvm.h
@@ -0,0 +1,23 @@
1#ifndef PERF_TEST_LLVM_H
2#define PERF_TEST_LLVM_H
3
4#include <stddef.h> /* for size_t */
5#include <stdbool.h> /* for bool */
6
7extern const char test_llvm__bpf_base_prog[];
8extern const char test_llvm__bpf_test_kbuild_prog[];
9extern const char test_llvm__bpf_test_prologue_prog[];
10extern const char test_llvm__bpf_test_relocation[];
11
12enum test_llvm__testcase {
13 LLVM_TESTCASE_BASE,
14 LLVM_TESTCASE_KBUILD,
15 LLVM_TESTCASE_BPF_PROLOGUE,
16 LLVM_TESTCASE_BPF_RELOCATION,
17 __LLVM_TESTCASE_MAX,
18};
19
20int test_llvm__fetch_bpf_obj(void **p_obj_buf, size_t *p_obj_buf_sz,
21 enum test_llvm__testcase index, bool force,
22 bool *should_load_fail);
23#endif
diff --git a/tools/perf/tests/make b/tools/perf/tests/make
index 2cbd0c6901e3..cac15d93aea6 100644
--- a/tools/perf/tests/make
+++ b/tools/perf/tests/make
@@ -1,9 +1,11 @@
1include ../scripts/Makefile.include
2
1ifndef MK 3ifndef MK
2ifeq ($(MAKECMDGOALS),) 4ifeq ($(MAKECMDGOALS),)
3# no target specified, trigger the whole suite 5# no target specified, trigger the whole suite
4all: 6all:
5 @echo "Testing Makefile"; $(MAKE) -sf tests/make MK=Makefile 7 @echo "Testing Makefile"; $(MAKE) -sf tests/make MK=Makefile
6 @echo "Testing Makefile.perf"; $(MAKE) -sf tests/make MK=Makefile.perf 8 @echo "Testing Makefile.perf"; $(MAKE) -sf tests/make MK=Makefile.perf SET_PARALLEL=1 SET_O=1
7else 9else
8# run only specific test over 'Makefile' 10# run only specific test over 'Makefile'
9%: 11%:
@@ -11,8 +13,41 @@ else
11endif 13endif
12else 14else
13PERF := . 15PERF := .
16PERF_O := $(PERF)
17O_OPT :=
18FULL_O := $(shell readlink -f $(PERF_O) || echo $(PERF_O))
19
20ifneq ($(O),)
21 FULL_O := $(shell readlink -f $(O) || echo $(O))
22 PERF_O := $(FULL_O)
23 ifeq ($(SET_O),1)
24 O_OPT := 'O=$(FULL_O)'
25 endif
26 K_O_OPT := 'O=$(FULL_O)'
27endif
28
29PARALLEL_OPT=
30ifeq ($(SET_PARALLEL),1)
31 cores := $(shell (getconf _NPROCESSORS_ONLN || egrep -c '^processor|^CPU[0-9]' /proc/cpuinfo) 2>/dev/null)
32 ifeq ($(cores),0)
33 cores := 1
34 endif
35 PARALLEL_OPT="-j$(cores)"
36endif
37
38# As per kernel Makefile, avoid funny character set dependencies
39unexport LC_ALL
40LC_COLLATE=C
41LC_NUMERIC=C
42export LC_COLLATE LC_NUMERIC
14 43
15include config/Makefile.arch 44ifeq ($(srctree),)
45srctree := $(patsubst %/,%,$(dir $(shell pwd)))
46srctree := $(patsubst %/,%,$(dir $(srctree)))
47#$(info Determined 'srctree' to be $(srctree))
48endif
49
50include $(srctree)/tools/scripts/Makefile.arch
16 51
17# FIXME looks like x86 is the only arch running tests ;-) 52# FIXME looks like x86 is the only arch running tests ;-)
18# we need some IS_(32/64) flag to make this generic 53# we need some IS_(32/64) flag to make this generic
@@ -45,6 +80,7 @@ make_no_libaudit := NO_LIBAUDIT=1
45make_no_libbionic := NO_LIBBIONIC=1 80make_no_libbionic := NO_LIBBIONIC=1
46make_no_auxtrace := NO_AUXTRACE=1 81make_no_auxtrace := NO_AUXTRACE=1
47make_no_libbpf := NO_LIBBPF=1 82make_no_libbpf := NO_LIBBPF=1
83make_no_libcrypto := NO_LIBCRYPTO=1
48make_tags := tags 84make_tags := tags
49make_cscope := cscope 85make_cscope := cscope
50make_help := help 86make_help := help
@@ -68,6 +104,7 @@ make_minimal := NO_LIBPERL=1 NO_LIBPYTHON=1 NO_NEWT=1 NO_GTK2=1
68make_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
69make_minimal += NO_LIBNUMA=1 NO_LIBAUDIT=1 NO_LIBBIONIC=1 105make_minimal += NO_LIBNUMA=1 NO_LIBAUDIT=1 NO_LIBBIONIC=1
70make_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
71 108
72# $(run) contains all available tests 109# $(run) contains all available tests
73run := make_pure 110run := make_pure
@@ -76,6 +113,9 @@ run := make_pure
76# disable features detection 113# disable features detection
77ifeq ($(MK),Makefile) 114ifeq ($(MK),Makefile)
78run += make_clean_all 115run += make_clean_all
116MAKE_F := $(MAKE)
117else
118MAKE_F := $(MAKE) -f $(MK)
79endif 119endif
80run += make_python_perf_so 120run += make_python_perf_so
81run += make_debug 121run += make_debug
@@ -142,11 +182,11 @@ test_make_doc := $(test_ok)
142test_make_help_O := $(test_ok) 182test_make_help_O := $(test_ok)
143test_make_doc_O := $(test_ok) 183test_make_doc_O := $(test_ok)
144 184
145test_make_python_perf_so := test -f $(PERF)/python/perf.so 185test_make_python_perf_so := test -f $(PERF_O)/python/perf.so
146 186
147test_make_perf_o := test -f $(PERF)/perf.o 187test_make_perf_o := test -f $(PERF_O)/perf.o
148test_make_util_map_o := test -f $(PERF)/util/map.o 188test_make_util_map_o := test -f $(PERF_O)/util/map.o
149test_make_util_pmu_bison_o := test -f $(PERF)/util/pmu-bison.o 189test_make_util_pmu_bison_o := test -f $(PERF_O)/util/pmu-bison.o
150 190
151define test_dest_files 191define test_dest_files
152 for file in $(1); do \ 192 for file in $(1); do \
@@ -213,7 +253,7 @@ test_make_perf_o_O := test -f $$TMP_O/perf.o
213test_make_util_map_o_O := test -f $$TMP_O/util/map.o 253test_make_util_map_o_O := test -f $$TMP_O/util/map.o
214test_make_util_pmu_bison_o_O := test -f $$TMP_O/util/pmu-bison.o 254test_make_util_pmu_bison_o_O := test -f $$TMP_O/util/pmu-bison.o
215 255
216test_default = test -x $(PERF)/perf 256test_default = test -x $(PERF_O)/perf
217test = $(if $(test_$1),$(test_$1),$(test_default)) 257test = $(if $(test_$1),$(test_$1),$(test_default))
218 258
219test_default_O = test -x $$TMP_O/perf 259test_default_O = test -x $$TMP_O/perf
@@ -221,6 +261,13 @@ test_O = $(if $(test_$1),$(test_$1),$(test_default_O))
221 261
222all: 262all:
223 263
264ifdef SHUF
265run := $(shell shuf -e $(run))
266run_O := $(shell shuf -e $(run_O))
267endif
268
269max_width := $(shell echo $(run_O) | sed 's/ /\n/g' | wc -L)
270
224ifdef DEBUG 271ifdef DEBUG
225d := $(info run $(run)) 272d := $(info run $(run))
226d := $(info run_O $(run_O)) 273d := $(info run_O $(run_O))
@@ -228,13 +275,13 @@ endif
228 275
229MAKEFLAGS := --no-print-directory 276MAKEFLAGS := --no-print-directory
230 277
231clean := @(cd $(PERF); make -s -f $(MK) clean >/dev/null) 278clean := @(cd $(PERF); $(MAKE_F) -s $(O_OPT) clean >/dev/null)
232 279
233$(run): 280$(run):
234 $(call clean) 281 $(call clean)
235 @TMP_DEST=$$(mktemp -d); \ 282 @TMP_DEST=$$(mktemp -d); \
236 cmd="cd $(PERF) && make -f $(MK) DESTDIR=$$TMP_DEST $($@)"; \ 283 cmd="cd $(PERF) && $(MAKE_F) $($@) $(PARALLEL_OPT) $(O_OPT) DESTDIR=$$TMP_DEST"; \
237 echo "- $@: $$cmd" && echo $$cmd > $@ && \ 284 printf "%*.*s: %s\n" $(max_width) $(max_width) "$@" "$$cmd" && echo $$cmd > $@ && \
238 ( eval $$cmd ) >> $@ 2>&1; \ 285 ( eval $$cmd ) >> $@ 2>&1; \
239 echo " test: $(call test,$@)" >> $@ 2>&1; \ 286 echo " test: $(call test,$@)" >> $@ 2>&1; \
240 $(call test,$@) && \ 287 $(call test,$@) && \
@@ -244,8 +291,8 @@ $(run_O):
244 $(call clean) 291 $(call clean)
245 @TMP_O=$$(mktemp -d); \ 292 @TMP_O=$$(mktemp -d); \
246 TMP_DEST=$$(mktemp -d); \ 293 TMP_DEST=$$(mktemp -d); \
247 cmd="cd $(PERF) && make -f $(MK) O=$$TMP_O DESTDIR=$$TMP_DEST $($(patsubst %_O,%,$@))"; \ 294 cmd="cd $(PERF) && $(MAKE_F) $($(patsubst %_O,%,$@)) $(PARALLEL_OPT) O=$$TMP_O DESTDIR=$$TMP_DEST"; \
248 echo "- $@: $$cmd" && echo $$cmd > $@ && \ 295 printf "%*.*s: %s\n" $(max_width) $(max_width) "$@" "$$cmd" && echo $$cmd > $@ && \
249 ( eval $$cmd ) >> $@ 2>&1 && \ 296 ( eval $$cmd ) >> $@ 2>&1 && \
250 echo " test: $(call test_O,$@)" >> $@ 2>&1; \ 297 echo " test: $(call test_O,$@)" >> $@ 2>&1; \
251 $(call test_O,$@) && \ 298 $(call test_O,$@) && \
@@ -254,25 +301,63 @@ $(run_O):
254tarpkg: 301tarpkg:
255 @cmd="$(PERF)/tests/perf-targz-src-pkg $(PERF)"; \ 302 @cmd="$(PERF)/tests/perf-targz-src-pkg $(PERF)"; \
256 echo "- $@: $$cmd" && echo $$cmd > $@ && \ 303 echo "- $@: $$cmd" && echo $$cmd > $@ && \
257 ( eval $$cmd ) >> $@ 2>&1 304 ( eval $$cmd ) >> $@ 2>&1 && \
305 rm -f $@
306
307KERNEL_O := ../..
308ifneq ($(O),)
309 KERNEL_O := $(O)
310endif
258 311
259make_kernelsrc: 312make_kernelsrc:
260 @echo "- make -C <kernelsrc> tools/perf" 313 @echo "- make -C <kernelsrc> $(PARALLEL_OPT) $(K_O_OPT) tools/perf"
261 $(call clean); \ 314 $(call clean); \
262 (make -C ../.. tools/perf) > $@ 2>&1 && \ 315 (make -C ../.. $(PARALLEL_OPT) $(K_O_OPT) tools/perf) > $@ 2>&1 && \
263 test -x perf && rm -f $@ || (cat $@ ; false) 316 test -x $(KERNEL_O)/tools/perf/perf && rm -f $@ || (cat $@ ; false)
264 317
265make_kernelsrc_tools: 318make_kernelsrc_tools:
266 @echo "- make -C <kernelsrc>/tools perf" 319 @echo "- make -C <kernelsrc>/tools $(PARALLEL_OPT) $(K_O_OPT) perf"
267 $(call clean); \ 320 $(call clean); \
268 (make -C ../../tools perf) > $@ 2>&1 && \ 321 (make -C ../../tools $(PARALLEL_OPT) $(K_O_OPT) perf) > $@ 2>&1 && \
269 test -x perf && rm -f $@ || (cat $@ ; false) 322 test -x $(KERNEL_O)/tools/perf/perf && rm -f $@ || (cat $@ ; false)
323
324FEATURES_DUMP_FILE := $(FULL_O)/BUILD_TEST_FEATURE_DUMP
325FEATURES_DUMP_FILE_STATIC := $(FULL_O)/BUILD_TEST_FEATURE_DUMP_STATIC
270 326
271all: $(run) $(run_O) tarpkg make_kernelsrc make_kernelsrc_tools 327all: $(run) $(run_O) tarpkg make_kernelsrc make_kernelsrc_tools
272 @echo OK 328 @echo OK
329 @rm -f $(FEATURES_DUMP_FILE) $(FEATURES_DUMP_FILE_STATIC)
273 330
274out: $(run_O) 331out: $(run_O)
275 @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
276 361
277.PHONY: all $(run) $(run_O) tarpkg clean 362.PHONY: all $(run) $(run_O) tarpkg clean make_kernelsrc make_kernelsrc_tools
278endif # ifndef MK 363endif # ifndef MK
diff --git a/tools/perf/tests/mmap-basic.c b/tools/perf/tests/mmap-basic.c
index 4495493c9431..359e98fcd94c 100644
--- a/tools/perf/tests/mmap-basic.c
+++ b/tools/perf/tests/mmap-basic.c
@@ -16,7 +16,7 @@
16 * Then it checks if the number of syscalls reported as perf events by 16 * Then it checks if the number of syscalls reported as perf events by
17 * the kernel corresponds to the number of syscalls made. 17 * the kernel corresponds to the number of syscalls made.
18 */ 18 */
19int test__basic_mmap(void) 19int test__basic_mmap(int subtest __maybe_unused)
20{ 20{
21 int err = -1; 21 int err = -1;
22 union perf_event *event; 22 union perf_event *event;
diff --git a/tools/perf/tests/mmap-thread-lookup.c b/tools/perf/tests/mmap-thread-lookup.c
index 145050e2e544..0c5ce44f723f 100644
--- a/tools/perf/tests/mmap-thread-lookup.c
+++ b/tools/perf/tests/mmap-thread-lookup.c
@@ -149,7 +149,6 @@ static int synth_process(struct machine *machine)
149 149
150static int mmap_events(synth_cb synth) 150static int mmap_events(synth_cb synth)
151{ 151{
152 struct machines machines;
153 struct machine *machine; 152 struct machine *machine;
154 int err, i; 153 int err, i;
155 154
@@ -162,8 +161,7 @@ static int mmap_events(synth_cb synth)
162 */ 161 */
163 TEST_ASSERT_VAL("failed to create threads", !threads_create()); 162 TEST_ASSERT_VAL("failed to create threads", !threads_create());
164 163
165 machines__init(&machines); 164 machine = machine__new_host();
166 machine = &machines.host;
167 165
168 dump_trace = verbose > 1 ? 1 : 0; 166 dump_trace = verbose > 1 ? 1 : 0;
169 167
@@ -203,7 +201,7 @@ static int mmap_events(synth_cb synth)
203 } 201 }
204 202
205 machine__delete_threads(machine); 203 machine__delete_threads(machine);
206 machines__exit(&machines); 204 machine__delete(machine);
207 return err; 205 return err;
208} 206}
209 207
@@ -221,7 +219,7 @@ static int mmap_events(synth_cb synth)
221 * 219 *
222 * by using all thread objects. 220 * by using all thread objects.
223 */ 221 */
224int test__mmap_thread_lookup(void) 222int test__mmap_thread_lookup(int subtest __maybe_unused)
225{ 223{
226 /* perf_event__synthesize_threads synthesize */ 224 /* perf_event__synthesize_threads synthesize */
227 TEST_ASSERT_VAL("failed with sythesizing all", 225 TEST_ASSERT_VAL("failed with sythesizing all",
diff --git a/tools/perf/tests/openat-syscall-all-cpus.c b/tools/perf/tests/openat-syscall-all-cpus.c
index 2006485a2859..53c2273e8859 100644
--- a/tools/perf/tests/openat-syscall-all-cpus.c
+++ b/tools/perf/tests/openat-syscall-all-cpus.c
@@ -7,7 +7,7 @@
7#include "debug.h" 7#include "debug.h"
8#include "stat.h" 8#include "stat.h"
9 9
10int test__openat_syscall_event_on_all_cpus(void) 10int test__openat_syscall_event_on_all_cpus(int subtest __maybe_unused)
11{ 11{
12 int err = -1, fd, cpu; 12 int err = -1, fd, cpu;
13 struct cpu_map *cpus; 13 struct cpu_map *cpus;
diff --git a/tools/perf/tests/openat-syscall-tp-fields.c b/tools/perf/tests/openat-syscall-tp-fields.c
index 5e811cd8f1c3..eb99a105f31c 100644
--- a/tools/perf/tests/openat-syscall-tp-fields.c
+++ b/tools/perf/tests/openat-syscall-tp-fields.c
@@ -6,7 +6,7 @@
6#include "tests.h" 6#include "tests.h"
7#include "debug.h" 7#include "debug.h"
8 8
9int test__syscall_openat_tp_fields(void) 9int test__syscall_openat_tp_fields(int subtest __maybe_unused)
10{ 10{
11 struct record_opts opts = { 11 struct record_opts opts = {
12 .target = { 12 .target = {
diff --git a/tools/perf/tests/openat-syscall.c b/tools/perf/tests/openat-syscall.c
index 033b54797b8a..1184f9ba6499 100644
--- a/tools/perf/tests/openat-syscall.c
+++ b/tools/perf/tests/openat-syscall.c
@@ -5,7 +5,7 @@
5#include "debug.h" 5#include "debug.h"
6#include "tests.h" 6#include "tests.h"
7 7
8int test__openat_syscall_event(void) 8int test__openat_syscall_event(int subtest __maybe_unused)
9{ 9{
10 int err = -1, fd; 10 int err = -1, fd;
11 struct perf_evsel *evsel; 11 struct perf_evsel *evsel;
diff --git a/tools/perf/tests/parse-events.c b/tools/perf/tests/parse-events.c
index 636d7b42d844..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}
@@ -1765,7 +1817,7 @@ static void debug_warn(const char *warn, va_list params)
1765 fprintf(stderr, " Warning: %s\n", msg); 1817 fprintf(stderr, " Warning: %s\n", msg);
1766} 1818}
1767 1819
1768int test__parse_events(void) 1820int test__parse_events(int subtest __maybe_unused)
1769{ 1821{
1770 int ret1, ret2 = 0; 1822 int ret1, ret2 = 0;
1771 1823
diff --git a/tools/perf/tests/parse-no-sample-id-all.c b/tools/perf/tests/parse-no-sample-id-all.c
index 2c63ea658541..294c76b01b41 100644
--- a/tools/perf/tests/parse-no-sample-id-all.c
+++ b/tools/perf/tests/parse-no-sample-id-all.c
@@ -67,7 +67,7 @@ struct test_attr_event {
67 * 67 *
68 * Return: %0 on success, %-1 if the test fails. 68 * Return: %0 on success, %-1 if the test fails.
69 */ 69 */
70int test__parse_no_sample_id_all(void) 70int test__parse_no_sample_id_all(int subtest __maybe_unused)
71{ 71{
72 int err; 72 int err;
73 73
diff --git a/tools/perf/tests/perf-record.c b/tools/perf/tests/perf-record.c
index 7a228a2a070b..1cc78cefe399 100644
--- a/tools/perf/tests/perf-record.c
+++ b/tools/perf/tests/perf-record.c
@@ -32,7 +32,7 @@ realloc:
32 return cpu; 32 return cpu;
33} 33}
34 34
35int test__PERF_RECORD(void) 35int test__PERF_RECORD(int subtest __maybe_unused)
36{ 36{
37 struct record_opts opts = { 37 struct record_opts opts = {
38 .target = { 38 .target = {
@@ -40,12 +40,11 @@ int test__PERF_RECORD(void)
40 .uses_mmap = true, 40 .uses_mmap = true,
41 }, 41 },
42 .no_buffering = true, 42 .no_buffering = true,
43 .freq = 10,
44 .mmap_pages = 256, 43 .mmap_pages = 256,
45 }; 44 };
46 cpu_set_t cpu_mask; 45 cpu_set_t cpu_mask;
47 size_t cpu_mask_size = sizeof(cpu_mask); 46 size_t cpu_mask_size = sizeof(cpu_mask);
48 struct perf_evlist *evlist = perf_evlist__new_default(); 47 struct perf_evlist *evlist = perf_evlist__new_dummy();
49 struct perf_evsel *evsel; 48 struct perf_evsel *evsel;
50 struct perf_sample sample; 49 struct perf_sample sample;
51 const char *cmd = "sleep"; 50 const char *cmd = "sleep";
@@ -61,6 +60,9 @@ int test__PERF_RECORD(void)
61 int total_events = 0, nr_events[PERF_RECORD_MAX] = { 0, }; 60 int total_events = 0, nr_events[PERF_RECORD_MAX] = { 0, };
62 char sbuf[STRERR_BUFSIZE]; 61 char sbuf[STRERR_BUFSIZE];
63 62
63 if (evlist == NULL) /* Fallback for kernels lacking PERF_COUNT_SW_DUMMY */
64 evlist = perf_evlist__new_default();
65
64 if (evlist == NULL || argv == NULL) { 66 if (evlist == NULL || argv == NULL) {
65 pr_debug("Not enough memory to create evlist\n"); 67 pr_debug("Not enough memory to create evlist\n");
66 goto out; 68 goto out;
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/pmu.c b/tools/perf/tests/pmu.c
index faa04e9d5d5f..1e2ba2602930 100644
--- a/tools/perf/tests/pmu.c
+++ b/tools/perf/tests/pmu.c
@@ -133,7 +133,7 @@ static struct list_head *test_terms_list(void)
133 return &terms; 133 return &terms;
134} 134}
135 135
136int test__pmu(void) 136int test__pmu(int subtest __maybe_unused)
137{ 137{
138 char *format = test_format_dir_get(); 138 char *format = test_format_dir_get();
139 LIST_HEAD(formats); 139 LIST_HEAD(formats);
diff --git a/tools/perf/tests/python-use.c b/tools/perf/tests/python-use.c
index 7760277c6def..7a52834ee0d0 100644
--- a/tools/perf/tests/python-use.c
+++ b/tools/perf/tests/python-use.c
@@ -4,11 +4,12 @@
4 4
5#include <stdio.h> 5#include <stdio.h>
6#include <stdlib.h> 6#include <stdlib.h>
7#include <linux/compiler.h>
7#include "tests.h" 8#include "tests.h"
8 9
9extern int verbose; 10extern int verbose;
10 11
11int test__python_use(void) 12int test__python_use(int subtest __maybe_unused)
12{ 13{
13 char *cmd; 14 char *cmd;
14 int ret; 15 int ret;
diff --git a/tools/perf/tests/sample-parsing.c b/tools/perf/tests/sample-parsing.c
index 30c02181e78b..5f23710b9fee 100644
--- a/tools/perf/tests/sample-parsing.c
+++ b/tools/perf/tests/sample-parsing.c
@@ -290,7 +290,7 @@ out_free:
290 * checks sample format bits separately and together. If the test passes %0 is 290 * checks sample format bits separately and together. If the test passes %0 is
291 * returned, otherwise %-1 is returned. 291 * returned, otherwise %-1 is returned.
292 */ 292 */
293int test__sample_parsing(void) 293int test__sample_parsing(int subtest __maybe_unused)
294{ 294{
295 const u64 rf[] = {4, 5, 6, 7, 12, 13, 14, 15}; 295 const u64 rf[] = {4, 5, 6, 7, 12, 13, 14, 15};
296 u64 sample_type; 296 u64 sample_type;
diff --git a/tools/perf/tests/stat.c b/tools/perf/tests/stat.c
new file mode 100644
index 000000000000..6a20ff2326bb
--- /dev/null
+++ b/tools/perf/tests/stat.c
@@ -0,0 +1,111 @@
1#include <linux/compiler.h>
2#include "event.h"
3#include "tests.h"
4#include "stat.h"
5#include "counts.h"
6#include "debug.h"
7
8static bool has_term(struct stat_config_event *config,
9 u64 tag, u64 val)
10{
11 unsigned i;
12
13 for (i = 0; i < config->nr; i++) {
14 if ((config->data[i].tag == tag) &&
15 (config->data[i].val == val))
16 return true;
17 }
18
19 return false;
20}
21
22static int process_stat_config_event(struct perf_tool *tool __maybe_unused,
23 union perf_event *event,
24 struct perf_sample *sample __maybe_unused,
25 struct machine *machine __maybe_unused)
26{
27 struct stat_config_event *config = &event->stat_config;
28 struct perf_stat_config stat_config;
29
30#define HAS(term, val) \
31 has_term(config, PERF_STAT_CONFIG_TERM__##term, val)
32
33 TEST_ASSERT_VAL("wrong nr", config->nr == PERF_STAT_CONFIG_TERM__MAX);
34 TEST_ASSERT_VAL("wrong aggr_mode", HAS(AGGR_MODE, AGGR_CORE));
35 TEST_ASSERT_VAL("wrong scale", HAS(SCALE, 1));
36 TEST_ASSERT_VAL("wrong interval", HAS(INTERVAL, 1));
37
38#undef HAS
39
40 perf_event__read_stat_config(&stat_config, config);
41
42 TEST_ASSERT_VAL("wrong aggr_mode", stat_config.aggr_mode == AGGR_CORE);
43 TEST_ASSERT_VAL("wrong scale", stat_config.scale == 1);
44 TEST_ASSERT_VAL("wrong interval", stat_config.interval == 1);
45 return 0;
46}
47
48int test__synthesize_stat_config(int subtest __maybe_unused)
49{
50 struct perf_stat_config stat_config = {
51 .aggr_mode = AGGR_CORE,
52 .scale = 1,
53 .interval = 1,
54 };
55
56 TEST_ASSERT_VAL("failed to synthesize stat_config",
57 !perf_event__synthesize_stat_config(NULL, &stat_config, process_stat_config_event, NULL));
58
59 return 0;
60}
61
62static int process_stat_event(struct perf_tool *tool __maybe_unused,
63 union perf_event *event,
64 struct perf_sample *sample __maybe_unused,
65 struct machine *machine __maybe_unused)
66{
67 struct stat_event *st = &event->stat;
68
69 TEST_ASSERT_VAL("wrong cpu", st->cpu == 1);
70 TEST_ASSERT_VAL("wrong thread", st->thread == 2);
71 TEST_ASSERT_VAL("wrong id", st->id == 3);
72 TEST_ASSERT_VAL("wrong val", st->val == 100);
73 TEST_ASSERT_VAL("wrong run", st->ena == 200);
74 TEST_ASSERT_VAL("wrong ena", st->run == 300);
75 return 0;
76}
77
78int test__synthesize_stat(int subtest __maybe_unused)
79{
80 struct perf_counts_values count;
81
82 count.val = 100;
83 count.ena = 200;
84 count.run = 300;
85
86 TEST_ASSERT_VAL("failed to synthesize stat_config",
87 !perf_event__synthesize_stat(NULL, 1, 2, 3, &count, process_stat_event, NULL));
88
89 return 0;
90}
91
92static int process_stat_round_event(struct perf_tool *tool __maybe_unused,
93 union perf_event *event,
94 struct perf_sample *sample __maybe_unused,
95 struct machine *machine __maybe_unused)
96{
97 struct stat_round_event *stat_round = &event->stat_round;
98
99 TEST_ASSERT_VAL("wrong time", stat_round->time == 0xdeadbeef);
100 TEST_ASSERT_VAL("wrong type", stat_round->type == PERF_STAT_ROUND_TYPE__INTERVAL);
101 return 0;
102}
103
104int test__synthesize_stat_round(int subtest __maybe_unused)
105{
106 TEST_ASSERT_VAL("failed to synthesize stat_config",
107 !perf_event__synthesize_stat_round(NULL, 0xdeadbeef, PERF_STAT_ROUND_TYPE__INTERVAL,
108 process_stat_round_event, NULL));
109
110 return 0;
111}
diff --git a/tools/perf/tests/sw-clock.c b/tools/perf/tests/sw-clock.c
index 5b83f56a3b6f..36e8ce1550e3 100644
--- a/tools/perf/tests/sw-clock.c
+++ b/tools/perf/tests/sw-clock.c
@@ -122,7 +122,7 @@ out_delete_evlist:
122 return err; 122 return err;
123} 123}
124 124
125int test__sw_clock_freq(void) 125int test__sw_clock_freq(int subtest __maybe_unused)
126{ 126{
127 int ret; 127 int ret;
128 128
diff --git a/tools/perf/tests/switch-tracking.c b/tools/perf/tests/switch-tracking.c
index e698742d4fec..ebd80168d51e 100644
--- a/tools/perf/tests/switch-tracking.c
+++ b/tools/perf/tests/switch-tracking.c
@@ -305,7 +305,7 @@ out_free_nodes:
305 * evsel->system_wide and evsel->tracking flags (respectively) with other events 305 * evsel->system_wide and evsel->tracking flags (respectively) with other events
306 * sometimes enabled or disabled. 306 * sometimes enabled or disabled.
307 */ 307 */
308int test__switch_tracking(void) 308int test__switch_tracking(int subtest __maybe_unused)
309{ 309{
310 const char *sched_switch = "sched:sched_switch"; 310 const char *sched_switch = "sched:sched_switch";
311 struct switch_tracking switch_tracking = { .tids = NULL, }; 311 struct switch_tracking switch_tracking = { .tids = NULL, };
@@ -366,7 +366,7 @@ int test__switch_tracking(void)
366 366
367 /* Third event */ 367 /* Third event */
368 if (!perf_evlist__can_select_event(evlist, sched_switch)) { 368 if (!perf_evlist__can_select_event(evlist, sched_switch)) {
369 fprintf(stderr, " (no sched_switch)"); 369 pr_debug("No sched_switch\n");
370 err = 0; 370 err = 0;
371 goto out; 371 goto out;
372 } 372 }
@@ -442,7 +442,7 @@ int test__switch_tracking(void)
442 } 442 }
443 443
444 if (perf_evlist__open(evlist) < 0) { 444 if (perf_evlist__open(evlist) < 0) {
445 fprintf(stderr, " (not supported)"); 445 pr_debug("Not supported\n");
446 err = 0; 446 err = 0;
447 goto out; 447 goto out;
448 } 448 }
@@ -455,7 +455,7 @@ int test__switch_tracking(void)
455 455
456 perf_evlist__enable(evlist); 456 perf_evlist__enable(evlist);
457 457
458 err = perf_evlist__disable_event(evlist, cpu_clocks_evsel); 458 err = perf_evsel__disable(cpu_clocks_evsel);
459 if (err) { 459 if (err) {
460 pr_debug("perf_evlist__disable_event failed!\n"); 460 pr_debug("perf_evlist__disable_event failed!\n");
461 goto out_err; 461 goto out_err;
@@ -474,7 +474,7 @@ int test__switch_tracking(void)
474 goto out_err; 474 goto out_err;
475 } 475 }
476 476
477 err = perf_evlist__disable_event(evlist, cycles_evsel); 477 err = perf_evsel__disable(cycles_evsel);
478 if (err) { 478 if (err) {
479 pr_debug("perf_evlist__disable_event failed!\n"); 479 pr_debug("perf_evlist__disable_event failed!\n");
480 goto out_err; 480 goto out_err;
@@ -500,7 +500,7 @@ int test__switch_tracking(void)
500 goto out_err; 500 goto out_err;
501 } 501 }
502 502
503 err = perf_evlist__enable_event(evlist, cycles_evsel); 503 err = perf_evsel__enable(cycles_evsel);
504 if (err) { 504 if (err) {
505 pr_debug("perf_evlist__disable_event failed!\n"); 505 pr_debug("perf_evlist__disable_event failed!\n");
506 goto out_err; 506 goto out_err;
diff --git a/tools/perf/tests/task-exit.c b/tools/perf/tests/task-exit.c
index add16385f13e..2dfff7ac8ef3 100644
--- a/tools/perf/tests/task-exit.c
+++ b/tools/perf/tests/task-exit.c
@@ -31,7 +31,7 @@ static void workload_exec_failed_signal(int signo __maybe_unused,
31 * if the number of exit event reported by the kernel is 1 or not 31 * if the number of exit event reported by the kernel is 1 or not
32 * in order to check the kernel returns correct number of event. 32 * in order to check the kernel returns correct number of event.
33 */ 33 */
34int test__task_exit(void) 34int test__task_exit(int subtest __maybe_unused)
35{ 35{
36 int err = -1; 36 int err = -1;
37 union perf_event *event; 37 union perf_event *event;
diff --git a/tools/perf/tests/tests.h b/tools/perf/tests/tests.h
index c80486969f83..82b2b5e6ba7c 100644
--- a/tools/perf/tests/tests.h
+++ b/tools/perf/tests/tests.h
@@ -1,6 +1,8 @@
1#ifndef TESTS_H 1#ifndef TESTS_H
2#define TESTS_H 2#define TESTS_H
3 3
4#include <stdbool.h>
5
4#define TEST_ASSERT_VAL(text, cond) \ 6#define TEST_ASSERT_VAL(text, cond) \
5do { \ 7do { \
6 if (!(cond)) { \ 8 if (!(cond)) { \
@@ -26,47 +28,63 @@ enum {
26 28
27struct test { 29struct test {
28 const char *desc; 30 const char *desc;
29 int (*func)(void); 31 int (*func)(int subtest);
32 struct {
33 bool skip_if_fail;
34 int (*get_nr)(void);
35 const char *(*get_desc)(int subtest);
36 } subtest;
30}; 37};
31 38
32/* Tests */ 39/* Tests */
33int test__vmlinux_matches_kallsyms(void); 40int test__vmlinux_matches_kallsyms(int subtest);
34int test__openat_syscall_event(void); 41int test__openat_syscall_event(int subtest);
35int test__openat_syscall_event_on_all_cpus(void); 42int test__openat_syscall_event_on_all_cpus(int subtest);
36int test__basic_mmap(void); 43int test__basic_mmap(int subtest);
37int test__PERF_RECORD(void); 44int test__PERF_RECORD(int subtest);
38int test__perf_evsel__roundtrip_name_test(void); 45int test__perf_evsel__roundtrip_name_test(int subtest);
39int test__perf_evsel__tp_sched_test(void); 46int test__perf_evsel__tp_sched_test(int subtest);
40int test__syscall_openat_tp_fields(void); 47int test__syscall_openat_tp_fields(int subtest);
41int test__pmu(void); 48int test__pmu(int subtest);
42int test__attr(void); 49int test__attr(int subtest);
43int test__dso_data(void); 50int test__dso_data(int subtest);
44int test__dso_data_cache(void); 51int test__dso_data_cache(int subtest);
45int test__dso_data_reopen(void); 52int test__dso_data_reopen(int subtest);
46int test__parse_events(void); 53int test__parse_events(int subtest);
47int test__hists_link(void); 54int test__hists_link(int subtest);
48int test__python_use(void); 55int test__python_use(int subtest);
49int test__bp_signal(void); 56int test__bp_signal(int subtest);
50int test__bp_signal_overflow(void); 57int test__bp_signal_overflow(int subtest);
51int test__task_exit(void); 58int test__task_exit(int subtest);
52int test__sw_clock_freq(void); 59int test__sw_clock_freq(int subtest);
53int test__code_reading(void); 60int test__code_reading(int subtest);
54int test__sample_parsing(void); 61int test__sample_parsing(int subtest);
55int test__keep_tracking(void); 62int test__keep_tracking(int subtest);
56int test__parse_no_sample_id_all(void); 63int test__parse_no_sample_id_all(int subtest);
57int test__dwarf_unwind(void); 64int test__dwarf_unwind(int subtest);
58int test__hists_filter(void); 65int test__hists_filter(int subtest);
59int test__mmap_thread_lookup(void); 66int test__mmap_thread_lookup(int subtest);
60int test__thread_mg_share(void); 67int test__thread_mg_share(int subtest);
61int test__hists_output(void); 68int test__hists_output(int subtest);
62int test__hists_cumulate(void); 69int test__hists_cumulate(int subtest);
63int test__switch_tracking(void); 70int test__switch_tracking(int subtest);
64int test__fdarray__filter(void); 71int test__fdarray__filter(int subtest);
65int test__fdarray__add(void); 72int test__fdarray__add(int subtest);
66int test__kmod_path__parse(void); 73int test__kmod_path__parse(int subtest);
67int test__thread_map(void); 74int test__thread_map(int subtest);
68int test__llvm(void); 75int test__llvm(int subtest);
69int test_session_topology(void); 76const char *test__llvm_subtest_get_desc(int subtest);
77int test__llvm_subtest_get_nr(void);
78int test__bpf(int subtest);
79const char *test__bpf_subtest_get_desc(int subtest);
80int test__bpf_subtest_get_nr(void);
81int test_session_topology(int subtest);
82int test__thread_map_synthesize(int subtest);
83int test__cpu_map_synthesize(int subtest);
84int test__synthesize_stat_config(int subtest);
85int test__synthesize_stat(int subtest);
86int test__synthesize_stat_round(int subtest);
87int test__event_update(int subtest);
70 88
71#if defined(__arm__) || defined(__aarch64__) 89#if defined(__arm__) || defined(__aarch64__)
72#ifdef HAVE_DWARF_UNWIND_SUPPORT 90#ifdef HAVE_DWARF_UNWIND_SUPPORT
diff --git a/tools/perf/tests/thread-map.c b/tools/perf/tests/thread-map.c
index 138a0e3431fa..fccde848fe9c 100644
--- a/tools/perf/tests/thread-map.c
+++ b/tools/perf/tests/thread-map.c
@@ -4,7 +4,7 @@
4#include "thread_map.h" 4#include "thread_map.h"
5#include "debug.h" 5#include "debug.h"
6 6
7int test__thread_map(void) 7int test__thread_map(int subtest __maybe_unused)
8{ 8{
9 struct thread_map *map; 9 struct thread_map *map;
10 10
@@ -40,3 +40,46 @@ int test__thread_map(void)
40 thread_map__put(map); 40 thread_map__put(map);
41 return 0; 41 return 0;
42} 42}
43
44static int process_event(struct perf_tool *tool __maybe_unused,
45 union perf_event *event,
46 struct perf_sample *sample __maybe_unused,
47 struct machine *machine __maybe_unused)
48{
49 struct thread_map_event *map = &event->thread_map;
50 struct thread_map *threads;
51
52 TEST_ASSERT_VAL("wrong nr", map->nr == 1);
53 TEST_ASSERT_VAL("wrong pid", map->entries[0].pid == (u64) getpid());
54 TEST_ASSERT_VAL("wrong comm", !strcmp(map->entries[0].comm, "perf"));
55
56 threads = thread_map__new_event(&event->thread_map);
57 TEST_ASSERT_VAL("failed to alloc map", threads);
58
59 TEST_ASSERT_VAL("wrong nr", threads->nr == 1);
60 TEST_ASSERT_VAL("wrong pid",
61 thread_map__pid(threads, 0) == getpid());
62 TEST_ASSERT_VAL("wrong comm",
63 thread_map__comm(threads, 0) &&
64 !strcmp(thread_map__comm(threads, 0), "perf"));
65 TEST_ASSERT_VAL("wrong refcnt",
66 atomic_read(&threads->refcnt) == 1);
67 thread_map__put(threads);
68 return 0;
69}
70
71int test__thread_map_synthesize(int subtest __maybe_unused)
72{
73 struct thread_map *threads;
74
75 /* test map on current pid */
76 threads = thread_map__new_by_pid(getpid());
77 TEST_ASSERT_VAL("failed to alloc map", threads);
78
79 thread_map__read_comms(threads);
80
81 TEST_ASSERT_VAL("failed to synthesize map",
82 !perf_event__synthesize_thread_map2(NULL, threads, process_event, NULL));
83
84 return 0;
85}
diff --git a/tools/perf/tests/thread-mg-share.c b/tools/perf/tests/thread-mg-share.c
index 01fabb19d746..188b63140fc8 100644
--- a/tools/perf/tests/thread-mg-share.c
+++ b/tools/perf/tests/thread-mg-share.c
@@ -4,7 +4,7 @@
4#include "map.h" 4#include "map.h"
5#include "debug.h" 5#include "debug.h"
6 6
7int test__thread_mg_share(void) 7int test__thread_mg_share(int subtest __maybe_unused)
8{ 8{
9 struct machines machines; 9 struct machines machines;
10 struct machine *machine; 10 struct machine *machine;
diff --git a/tools/perf/tests/topology.c b/tools/perf/tests/topology.c
index f5bb096c3bd9..98fe69ac553c 100644
--- a/tools/perf/tests/topology.c
+++ b/tools/perf/tests/topology.c
@@ -84,7 +84,7 @@ static int check_cpu_topology(char *path, struct cpu_map *map)
84 return 0; 84 return 0;
85} 85}
86 86
87int test_session_topology(void) 87int test_session_topology(int subtest __maybe_unused)
88{ 88{
89 char path[PATH_MAX]; 89 char path[PATH_MAX];
90 struct cpu_map *map; 90 struct cpu_map *map;
diff --git a/tools/perf/tests/vmlinux-kallsyms.c b/tools/perf/tests/vmlinux-kallsyms.c
index d677e018e504..630b0b409b97 100644
--- a/tools/perf/tests/vmlinux-kallsyms.c
+++ b/tools/perf/tests/vmlinux-kallsyms.c
@@ -18,7 +18,7 @@ static int vmlinux_matches_kallsyms_filter(struct map *map __maybe_unused,
18 18
19#define UM(x) kallsyms_map->unmap_ip(kallsyms_map, (x)) 19#define UM(x) kallsyms_map->unmap_ip(kallsyms_map, (x))
20 20
21int test__vmlinux_matches_kallsyms(void) 21int test__vmlinux_matches_kallsyms(int subtest __maybe_unused)
22{ 22{
23 int err = -1; 23 int err = -1;
24 struct rb_node *nd; 24 struct rb_node *nd;
@@ -110,7 +110,6 @@ int test__vmlinux_matches_kallsyms(void)
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 e9703c0829f1..af68a9d488bf 100644
--- a/tools/perf/ui/browser.c
+++ b/tools/perf/ui/browser.c
@@ -528,11 +528,11 @@ static struct ui_browser_colorset {
528 .colorset = HE_COLORSET_SELECTED, 528 .colorset = HE_COLORSET_SELECTED,
529 .name = "selected", 529 .name = "selected",
530 .fg = "black", 530 .fg = "black",
531 .bg = "lightgray", 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 d4d7cc27252f..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}
@@ -755,11 +755,11 @@ static int annotate_browser__run(struct annotate_browser *browser,
755 nd = browser->curr_hot; 755 nd = browser->curr_hot;
756 break; 756 break;
757 case K_UNTAB: 757 case K_UNTAB:
758 if (nd != NULL) 758 if (nd != NULL) {
759 nd = rb_next(nd); 759 nd = rb_next(nd);
760 if (nd == NULL) 760 if (nd == NULL)
761 nd = rb_first(&browser->entries); 761 nd = rb_first(&browser->entries);
762 else 762 } else
763 nd = browser->curr_hot; 763 nd = browser->curr_hot;
764 break; 764 break;
765 case K_F1: 765 case K_F1:
diff --git a/tools/perf/ui/browsers/hists.c b/tools/perf/ui/browsers/hists.c
index e5afb8936040..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;
@@ -178,12 +181,51 @@ static int callchain_node__count_rows_rb_tree(struct callchain_node *node)
178 return n; 181 return n;
179} 182}
180 183
184static int callchain_node__count_flat_rows(struct callchain_node *node)
185{
186 struct callchain_list *chain;
187 char folded_sign = 0;
188 int n = 0;
189
190 list_for_each_entry(chain, &node->parent_val, list) {
191 if (!folded_sign) {
192 /* only check first chain list entry */
193 folded_sign = callchain_list__folded(chain);
194 if (folded_sign == '+')
195 return 1;
196 }
197 n++;
198 }
199
200 list_for_each_entry(chain, &node->val, list) {
201 if (!folded_sign) {
202 /* node->parent_val list might be empty */
203 folded_sign = callchain_list__folded(chain);
204 if (folded_sign == '+')
205 return 1;
206 }
207 n++;
208 }
209
210 return n;
211}
212
213static int callchain_node__count_folded_rows(struct callchain_node *node __maybe_unused)
214{
215 return 1;
216}
217
181static int callchain_node__count_rows(struct callchain_node *node) 218static int callchain_node__count_rows(struct callchain_node *node)
182{ 219{
183 struct callchain_list *chain; 220 struct callchain_list *chain;
184 bool unfolded = false; 221 bool unfolded = false;
185 int n = 0; 222 int n = 0;
186 223
224 if (callchain_param.mode == CHAIN_FLAT)
225 return callchain_node__count_flat_rows(node);
226 else if (callchain_param.mode == CHAIN_FOLDED)
227 return callchain_node__count_folded_rows(node);
228
187 list_for_each_entry(chain, &node->val, list) { 229 list_for_each_entry(chain, &node->val, list) {
188 ++n; 230 ++n;
189 unfolded = chain->unfolded; 231 unfolded = chain->unfolded;
@@ -208,6 +250,38 @@ static int callchain__count_rows(struct rb_root *chain)
208 return n; 250 return n;
209} 251}
210 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
211static bool hist_entry__toggle_fold(struct hist_entry *he) 285static bool hist_entry__toggle_fold(struct hist_entry *he)
212{ 286{
213 if (!he) 287 if (!he)
@@ -279,16 +353,25 @@ static void callchain__init_have_children(struct rb_root *root)
279 for (nd = rb_first(root); nd; nd = rb_next(nd)) { 353 for (nd = rb_first(root); nd; nd = rb_next(nd)) {
280 struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node); 354 struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
281 callchain_node__init_have_children(node, has_sibling); 355 callchain_node__init_have_children(node, has_sibling);
356 if (callchain_param.mode == CHAIN_FLAT ||
357 callchain_param.mode == CHAIN_FOLDED)
358 callchain_node__make_parent_list(node);
282 } 359 }
283} 360}
284 361
285static void hist_entry__init_have_children(struct hist_entry *he) 362static void hist_entry__init_have_children(struct hist_entry *he)
286{ 363{
287 if (!he->init_have_children) { 364 if (he->init_have_children)
365 return;
366
367 if (he->leaf) {
288 he->has_children = !RB_EMPTY_ROOT(&he->sorted_chain); 368 he->has_children = !RB_EMPTY_ROOT(&he->sorted_chain);
289 callchain__init_have_children(&he->sorted_chain); 369 callchain__init_have_children(&he->sorted_chain);
290 he->init_have_children = true; 370 } else {
371 he->has_children = !RB_EMPTY_ROOT(&he->hroot_out);
291 } 372 }
373
374 he->init_have_children = true;
292} 375}
293 376
294static bool hist_browser__toggle_fold(struct hist_browser *browser) 377static bool hist_browser__toggle_fold(struct hist_browser *browser)
@@ -298,23 +381,58 @@ static bool hist_browser__toggle_fold(struct hist_browser *browser)
298 struct callchain_list *cl = container_of(ms, struct callchain_list, ms); 381 struct callchain_list *cl = container_of(ms, struct callchain_list, ms);
299 bool has_children; 382 bool has_children;
300 383
384 if (!he || !ms)
385 return false;
386
301 if (ms == &he->ms) 387 if (ms == &he->ms)
302 has_children = hist_entry__toggle_fold(he); 388 has_children = hist_entry__toggle_fold(he);
303 else 389 else
304 has_children = callchain_list__toggle_fold(cl); 390 has_children = callchain_list__toggle_fold(cl);
305 391
306 if (has_children) { 392 if (has_children) {
393 int child_rows = 0;
394
307 hist_entry__init_have_children(he); 395 hist_entry__init_have_children(he);
308 browser->b.nr_entries -= he->nr_rows; 396 browser->b.nr_entries -= he->nr_rows;
309 browser->nr_callchain_rows -= he->nr_rows;
310 397
311 if (he->unfolded) 398 if (he->leaf)
312 he->nr_rows = callchain__count_rows(&he->sorted_chain); 399 browser->nr_callchain_rows -= he->nr_rows;
313 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
314 he->nr_rows = 0; 427 he->nr_rows = 0;
428 }
315 429
316 browser->b.nr_entries += he->nr_rows; 430 browser->b.nr_entries += he->nr_rows;
317 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;
318 436
319 return true; 437 return true;
320 } 438 }
@@ -377,13 +495,38 @@ static int callchain__set_folding(struct rb_root *chain, bool unfold)
377 return n; 495 return n;
378} 496}
379 497
380static 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)
381{ 518{
382 hist_entry__init_have_children(he); 519 hist_entry__init_have_children(he);
383 he->unfolded = unfold ? he->has_children : false; 520 he->unfolded = unfold ? he->has_children : false;
384 521
385 if (he->has_children) { 522 if (he->has_children) {
386 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
387 he->nr_rows = unfold ? n : 0; 530 he->nr_rows = unfold ? n : 0;
388 } else 531 } else
389 he->nr_rows = 0; 532 he->nr_rows = 0;
@@ -393,19 +536,38 @@ static void
393__hist_browser__set_folding(struct hist_browser *browser, bool unfold) 536__hist_browser__set_folding(struct hist_browser *browser, bool unfold)
394{ 537{
395 struct rb_node *nd; 538 struct rb_node *nd;
396 struct hists *hists = browser->hists; 539 struct hist_entry *he;
540 double percent;
397 541
398 for (nd = rb_first(&hists->entries); 542 nd = rb_first(&browser->hists->entries);
399 (nd = hists__filter_entries(nd, browser->min_pcnt)) != NULL; 543 while (nd) {
400 nd = rb_next(nd)) { 544 he = rb_entry(nd, struct hist_entry, rb_node);
401 struct hist_entry *he = rb_entry(nd, struct hist_entry, rb_node); 545
402 hist_entry__set_folding(he, unfold); 546 /* set folding state even if it's currently folded */
403 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;
404 } 565 }
405} 566}
406 567
407static void hist_browser__set_folding(struct hist_browser *browser, bool unfold) 568static void hist_browser__set_folding(struct hist_browser *browser, bool unfold)
408{ 569{
570 browser->nr_hierarchy_entries = 0;
409 browser->nr_callchain_rows = 0; 571 browser->nr_callchain_rows = 0;
410 __hist_browser__set_folding(browser, unfold); 572 __hist_browser__set_folding(browser, unfold);
411 573
@@ -435,7 +597,7 @@ static int hist_browser__run(struct hist_browser *browser, const char *help)
435 597
436 hists__browser_title(browser->hists, hbt, title, sizeof(title)); 598 hists__browser_title(browser->hists, hbt, title, sizeof(title));
437 599
438 if (ui_browser__show(&browser->b, title, help) < 0) 600 if (ui_browser__show(&browser->b, title, "%s", help) < 0)
439 return -1; 601 return -1;
440 602
441 while (1) { 603 while (1) {
@@ -574,33 +736,105 @@ static bool hist_browser__check_dump_full(struct hist_browser *browser __maybe_u
574 736
575#define LEVEL_OFFSET_STEP 3 737#define LEVEL_OFFSET_STEP 3
576 738
577static int hist_browser__show_callchain(struct hist_browser *browser, 739static int hist_browser__show_callchain_list(struct hist_browser *browser,
578 struct rb_root *root, int level, 740 struct callchain_node *node,
579 unsigned short row, u64 total, 741 struct callchain_list *chain,
580 print_callchain_entry_fn print, 742 unsigned short row, u64 total,
581 struct callchain_print_arg *arg, 743 bool need_percent, int offset,
582 check_output_full_fn is_output_full) 744 print_callchain_entry_fn print,
745 struct callchain_print_arg *arg)
746{
747 char bf[1024], *alloc_str;
748 const char *str;
749
750 if (arg->row_offset != 0) {
751 arg->row_offset--;
752 return 0;
753 }
754
755 alloc_str = NULL;
756 str = callchain_list__sym_name(chain, bf, sizeof(bf),
757 browser->show_dso);
758
759 if (need_percent) {
760 char buf[64];
761
762 callchain_node__scnprintf_value(node, buf, sizeof(buf),
763 total);
764
765 if (asprintf(&alloc_str, "%s %s", buf, str) < 0)
766 str = "Not enough memory!";
767 else
768 str = alloc_str;
769 }
770
771 print(browser, chain, str, offset, row, arg);
772
773 free(alloc_str);
774 return 1;
775}
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
791static int hist_browser__show_callchain_flat(struct hist_browser *browser,
792 struct rb_root *root,
793 unsigned short row, u64 total,
794 u64 parent_total,
795 print_callchain_entry_fn print,
796 struct callchain_print_arg *arg,
797 check_output_full_fn is_output_full)
583{ 798{
584 struct rb_node *node; 799 struct rb_node *node;
585 int first_row = row, offset = level * LEVEL_OFFSET_STEP; 800 int first_row = row, offset = LEVEL_OFFSET_STEP;
586 u64 new_total;
587 bool need_percent; 801 bool need_percent;
588 802
589 node = rb_first(root); 803 node = rb_first(root);
590 need_percent = node && rb_next(node); 804 need_percent = check_percent_display(node, parent_total);
591 805
592 while (node) { 806 while (node) {
593 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);
594 struct rb_node *next = rb_next(node); 808 struct rb_node *next = rb_next(node);
595 u64 cumul = callchain_cumul_hits(child);
596 struct callchain_list *chain; 809 struct callchain_list *chain;
597 char folded_sign = ' '; 810 char folded_sign = ' ';
598 int first = true; 811 int first = true;
599 int extra_offset = 0; 812 int extra_offset = 0;
600 813
814 list_for_each_entry(chain, &child->parent_val, list) {
815 bool was_first = first;
816
817 if (first)
818 first = false;
819 else if (need_percent)
820 extra_offset = LEVEL_OFFSET_STEP;
821
822 folded_sign = callchain_list__folded(chain);
823
824 row += hist_browser__show_callchain_list(browser, child,
825 chain, row, total,
826 was_first && need_percent,
827 offset + extra_offset,
828 print, arg);
829
830 if (is_output_full(browser, row))
831 goto out;
832
833 if (folded_sign == '+')
834 goto next;
835 }
836
601 list_for_each_entry(chain, &child->val, list) { 837 list_for_each_entry(chain, &child->val, list) {
602 char bf[1024], *alloc_str;
603 const char *str;
604 bool was_first = first; 838 bool was_first = first;
605 839
606 if (first) 840 if (first)
@@ -609,31 +843,186 @@ static int hist_browser__show_callchain(struct hist_browser *browser,
609 extra_offset = LEVEL_OFFSET_STEP; 843 extra_offset = LEVEL_OFFSET_STEP;
610 844
611 folded_sign = callchain_list__folded(chain); 845 folded_sign = callchain_list__folded(chain);
612 if (arg->row_offset != 0) { 846
613 arg->row_offset--; 847 row += hist_browser__show_callchain_list(browser, child,
614 goto do_next; 848 chain, row, total,
849 was_first && need_percent,
850 offset + extra_offset,
851 print, arg);
852
853 if (is_output_full(browser, row))
854 goto out;
855
856 if (folded_sign == '+')
857 break;
858 }
859
860next:
861 if (is_output_full(browser, row))
862 break;
863 node = next;
864 }
865out:
866 return row - first_row;
867}
868
869static char *hist_browser__folded_callchain_str(struct hist_browser *browser,
870 struct callchain_list *chain,
871 char *value_str, char *old_str)
872{
873 char bf[1024];
874 const char *str;
875 char *new;
876
877 str = callchain_list__sym_name(chain, bf, sizeof(bf),
878 browser->show_dso);
879 if (old_str) {
880 if (asprintf(&new, "%s%s%s", old_str,
881 symbol_conf.field_sep ?: ";", str) < 0)
882 new = NULL;
883 } else {
884 if (value_str) {
885 if (asprintf(&new, "%s %s", value_str, str) < 0)
886 new = NULL;
887 } else {
888 if (asprintf(&new, "%s", str) < 0)
889 new = NULL;
890 }
891 }
892 return new;
893}
894
895static int hist_browser__show_callchain_folded(struct hist_browser *browser,
896 struct rb_root *root,
897 unsigned short row, u64 total,
898 u64 parent_total,
899 print_callchain_entry_fn print,
900 struct callchain_print_arg *arg,
901 check_output_full_fn is_output_full)
902{
903 struct rb_node *node;
904 int first_row = row, offset = LEVEL_OFFSET_STEP;
905 bool need_percent;
906
907 node = rb_first(root);
908 need_percent = check_percent_display(node, parent_total);
909
910 while (node) {
911 struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node);
912 struct rb_node *next = rb_next(node);
913 struct callchain_list *chain, *first_chain = NULL;
914 int first = true;
915 char *value_str = NULL, *value_str_alloc = NULL;
916 char *chain_str = NULL, *chain_str_alloc = NULL;
917
918 if (arg->row_offset != 0) {
919 arg->row_offset--;
920 goto next;
921 }
922
923 if (need_percent) {
924 char buf[64];
925
926 callchain_node__scnprintf_value(child, buf, sizeof(buf), total);
927 if (asprintf(&value_str, "%s", buf) < 0) {
928 value_str = (char *)"<...>";
929 goto do_print;
615 } 930 }
931 value_str_alloc = value_str;
932 }
616 933
617 alloc_str = NULL; 934 list_for_each_entry(chain, &child->parent_val, list) {
618 str = callchain_list__sym_name(chain, bf, sizeof(bf), 935 chain_str = hist_browser__folded_callchain_str(browser,
619 browser->show_dso); 936 chain, value_str, chain_str);
937 if (first) {
938 first = false;
939 first_chain = chain;
940 }
620 941
621 if (was_first && need_percent) { 942 if (chain_str == NULL) {
622 double percent = cumul * 100.0 / total; 943 chain_str = (char *)"Not enough memory!";
944 goto do_print;
945 }
623 946
624 if (asprintf(&alloc_str, "%2.2f%% %s", percent, str) < 0) 947 chain_str_alloc = chain_str;
625 str = "Not enough memory!"; 948 }
626 else 949
627 str = alloc_str; 950 list_for_each_entry(chain, &child->val, list) {
951 chain_str = hist_browser__folded_callchain_str(browser,
952 chain, value_str, chain_str);
953 if (first) {
954 first = false;
955 first_chain = chain;
628 } 956 }
629 957
630 print(browser, chain, str, offset + extra_offset, row, arg); 958 if (chain_str == NULL) {
959 chain_str = (char *)"Not enough memory!";
960 goto do_print;
961 }
962
963 chain_str_alloc = chain_str;
964 }
965
966do_print:
967 print(browser, first_chain, chain_str, offset, row++, arg);
968 free(value_str_alloc);
969 free(chain_str_alloc);
970
971next:
972 if (is_output_full(browser, row))
973 break;
974 node = next;
975 }
976
977 return row - first_row;
978}
979
980static int hist_browser__show_callchain_graph(struct hist_browser *browser,
981 struct rb_root *root, int level,
982 unsigned short row, u64 total,
983 u64 parent_total,
984 print_callchain_entry_fn print,
985 struct callchain_print_arg *arg,
986 check_output_full_fn is_output_full)
987{
988 struct rb_node *node;
989 int first_row = row, offset = level * LEVEL_OFFSET_STEP;
990 bool need_percent;
991 u64 percent_total = total;
992
993 if (callchain_param.mode == CHAIN_GRAPH_REL)
994 percent_total = parent_total;
631 995
632 free(alloc_str); 996 node = rb_first(root);
997 need_percent = check_percent_display(node, parent_total);
633 998
634 if (is_output_full(browser, ++row)) 999 while (node) {
1000 struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node);
1001 struct rb_node *next = rb_next(node);
1002 struct callchain_list *chain;
1003 char folded_sign = ' ';
1004 int first = true;
1005 int extra_offset = 0;
1006
1007 list_for_each_entry(chain, &child->val, list) {
1008 bool was_first = first;
1009
1010 if (first)
1011 first = false;
1012 else if (need_percent)
1013 extra_offset = LEVEL_OFFSET_STEP;
1014
1015 folded_sign = callchain_list__folded(chain);
1016
1017 row += hist_browser__show_callchain_list(browser, child,
1018 chain, row, percent_total,
1019 was_first && need_percent,
1020 offset + extra_offset,
1021 print, arg);
1022
1023 if (is_output_full(browser, row))
635 goto out; 1024 goto out;
636do_next: 1025
637 if (folded_sign == '+') 1026 if (folded_sign == '+')
638 break; 1027 break;
639 } 1028 }
@@ -641,13 +1030,9 @@ do_next:
641 if (folded_sign == '-') { 1030 if (folded_sign == '-') {
642 const int new_level = level + (extra_offset ? 2 : 1); 1031 const int new_level = level + (extra_offset ? 2 : 1);
643 1032
644 if (callchain_param.mode == CHAIN_GRAPH_REL) 1033 row += hist_browser__show_callchain_graph(browser, &child->rb_root,
645 new_total = child->children_hit; 1034 new_level, row, total,
646 else 1035 child->children_hit,
647 new_total = total;
648
649 row += hist_browser__show_callchain(browser, &child->rb_root,
650 new_level, row, new_total,
651 print, arg, is_output_full); 1036 print, arg, is_output_full);
652 } 1037 }
653 if (is_output_full(browser, row)) 1038 if (is_output_full(browser, row))
@@ -658,6 +1043,45 @@ out:
658 return row - first_row; 1043 return row - first_row;
659} 1044}
660 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
661struct hpp_arg { 1085struct hpp_arg {
662 struct ui_browser *b; 1086 struct ui_browser *b;
663 char folded_sign; 1087 char folded_sign;
@@ -754,7 +1178,6 @@ static int hist_browser__show_entry(struct hist_browser *browser,
754 struct hist_entry *entry, 1178 struct hist_entry *entry,
755 unsigned short row) 1179 unsigned short row)
756{ 1180{
757 char s[256];
758 int printed = 0; 1181 int printed = 0;
759 int width = browser->b.width; 1182 int width = browser->b.width;
760 char folded_sign = ' '; 1183 char folded_sign = ' ';
@@ -779,17 +1202,20 @@ static int hist_browser__show_entry(struct hist_browser *browser,
779 .folded_sign = folded_sign, 1202 .folded_sign = folded_sign,
780 .current_entry = current_entry, 1203 .current_entry = current_entry,
781 }; 1204 };
782 struct perf_hpp hpp = {
783 .buf = s,
784 .size = sizeof(s),
785 .ptr = &arg,
786 };
787 int column = 0; 1205 int column = 0;
788 1206
789 hist_browser__gotorc(browser, row, 0); 1207 hist_browser__gotorc(browser, row, 0);
790 1208
791 perf_hpp__for_each_format(fmt) { 1209 hists__for_each_format(browser->hists, fmt) {
792 if (perf_hpp__should_skip(fmt) || column++ < browser->b.horiz_scroll) 1210 char s[2048];
1211 struct perf_hpp hpp = {
1212 .buf = s,
1213 .size = sizeof(s),
1214 .ptr = &arg,
1215 };
1216
1217 if (perf_hpp__should_skip(fmt, entry->hists) ||
1218 column++ < browser->b.horiz_scroll)
793 continue; 1219 continue;
794 1220
795 if (current_entry && browser->b.navkeypressed) { 1221 if (current_entry && browser->b.navkeypressed) {
@@ -812,11 +1238,18 @@ static int hist_browser__show_entry(struct hist_browser *browser,
812 } 1238 }
813 1239
814 if (fmt->color) { 1240 if (fmt->color) {
815 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);
816 } else { 1248 } else {
817 width -= fmt->entry(fmt, &hpp, entry); 1249 hist_entry__snprintf_alignment(entry, &hpp, fmt, fmt->entry(fmt, &hpp, entry));
818 ui_browser__printf(&browser->b, "%s", s); 1250 ui_browser__printf(&browser->b, "%s", s);
819 } 1251 }
1252 width -= hpp.buf - s;
820 } 1253 }
821 1254
822 /* The scroll bar isn't being used */ 1255 /* The scroll bar isn't being used */
@@ -831,31 +1264,246 @@ static int hist_browser__show_entry(struct hist_browser *browser,
831 --row_offset; 1264 --row_offset;
832 1265
833 if (folded_sign == '-' && row != browser->b.rows) { 1266 if (folded_sign == '-' && row != browser->b.rows) {
834 u64 total = hists__total_period(entry->hists);
835 struct callchain_print_arg arg = { 1267 struct callchain_print_arg arg = {
836 .row_offset = row_offset, 1268 .row_offset = row_offset,
837 .is_current_entry = current_entry, 1269 .is_current_entry = current_entry,
838 }; 1270 };
839 1271
840 if (callchain_param.mode == CHAIN_GRAPH_REL) { 1272 printed += hist_browser__show_callchain(browser, entry, 1, row,
841 if (symbol_conf.cumulate_callchain)
842 total = entry->stat_acc->period;
843 else
844 total = entry->stat.period;
845 }
846
847 printed += hist_browser__show_callchain(browser,
848 &entry->sorted_chain, 1, row, total,
849 hist_browser__show_callchain_entry, &arg, 1273 hist_browser__show_callchain_entry, &arg,
850 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);
1342 } else {
1343 ui_browser__set_color(&browser->b,
1344 HE_COLORSET_NORMAL);
1345 }
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 }
851 1355
852 if (arg.is_current_entry) 1356 if (fmt->color) {
853 browser->he_selection = entry; 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);
1389 }
1390
1391 perf_hpp_list__for_each_format(entry->hpp_list, fmt) {
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);
854 } 1433 }
855 1434
856 return printed; 1435 return printed;
857} 1436}
858 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
859static int advance_hpp_check(struct perf_hpp *hpp, int inc) 1507static int advance_hpp_check(struct perf_hpp *hpp, int inc)
860{ 1508{
861 advance_hpp(hpp, inc); 1509 advance_hpp(hpp, inc);
@@ -879,8 +1527,8 @@ static int hists_browser__scnprintf_headers(struct hist_browser *browser, char *
879 return ret; 1527 return ret;
880 } 1528 }
881 1529
882 perf_hpp__for_each_format(fmt) { 1530 hists__for_each_format(browser->hists, fmt) {
883 if (perf_hpp__should_skip(fmt) || column++ < browser->b.horiz_scroll) 1531 if (perf_hpp__should_skip(fmt, hists) || column++ < browser->b.horiz_scroll)
884 continue; 1532 continue;
885 1533
886 ret = fmt->header(fmt, &dummy_hpp, hists_to_evsel(hists)); 1534 ret = fmt->header(fmt, &dummy_hpp, hists_to_evsel(hists));
@@ -895,11 +1543,96 @@ static int hists_browser__scnprintf_headers(struct hist_browser *browser, char *
895 return ret; 1543 return ret;
896} 1544}
897 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
898static void hist_browser__show_headers(struct hist_browser *browser) 1626static void hist_browser__show_headers(struct hist_browser *browser)
899{ 1627{
900 char headers[1024]; 1628 char headers[1024];
901 1629
902 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));
903 ui_browser__gotorc(&browser->b, 0, 0); 1636 ui_browser__gotorc(&browser->b, 0, 0);
904 ui_browser__set_color(&browser->b, HE_COLORSET_ROOT); 1637 ui_browser__set_color(&browser->b, HE_COLORSET_ROOT);
905 ui_browser__write_nstring(&browser->b, headers, browser->b.width + 1); 1638 ui_browser__write_nstring(&browser->b, headers, browser->b.width + 1);
@@ -928,19 +1661,37 @@ static unsigned int hist_browser__refresh(struct ui_browser *browser)
928 } 1661 }
929 1662
930 ui_browser__hists_init_top(browser); 1663 ui_browser__hists_init_top(browser);
1664 hb->he_selection = NULL;
1665 hb->selection = NULL;
931 1666
932 for (nd = browser->top; nd; nd = rb_next(nd)) { 1667 for (nd = browser->top; nd; nd = rb_hierarchy_next(nd)) {
933 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);
934 float percent; 1669 float percent;
935 1670
936 if (h->filtered) 1671 if (h->filtered) {
1672 /* let it move to sibling */
1673 h->unfolded = false;
937 continue; 1674 continue;
1675 }
938 1676
939 percent = hist_entry__get_percent_limit(h); 1677 percent = hist_entry__get_percent_limit(h);
940 if (percent < hb->min_pcnt) 1678 if (percent < hb->min_pcnt)
941 continue; 1679 continue;
942 1680
943 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
944 if (row == browser->rows) 1695 if (row == browser->rows)
945 break; 1696 break;
946 } 1697 }
@@ -958,7 +1709,14 @@ static struct rb_node *hists__filter_entries(struct rb_node *nd,
958 if (!h->filtered && percent >= min_pcnt) 1709 if (!h->filtered && percent >= min_pcnt)
959 return nd; 1710 return nd;
960 1711
961 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);
962 } 1720 }
963 1721
964 return NULL; 1722 return NULL;
@@ -974,7 +1732,7 @@ static struct rb_node *hists__filter_prev_entries(struct rb_node *nd,
974 if (!h->filtered && percent >= min_pcnt) 1732 if (!h->filtered && percent >= min_pcnt)
975 return nd; 1733 return nd;
976 1734
977 nd = rb_prev(nd); 1735 nd = rb_hierarchy_prev(nd);
978 } 1736 }
979 1737
980 return NULL; 1738 return NULL;
@@ -1004,8 +1762,8 @@ static void ui_browser__hists_seek(struct ui_browser *browser,
1004 nd = browser->top; 1762 nd = browser->top;
1005 goto do_offset; 1763 goto do_offset;
1006 case SEEK_END: 1764 case SEEK_END:
1007 nd = hists__filter_prev_entries(rb_last(browser->entries), 1765 nd = rb_hierarchy_last(rb_last(browser->entries));
1008 hb->min_pcnt); 1766 nd = hists__filter_prev_entries(nd, hb->min_pcnt);
1009 first = false; 1767 first = false;
1010 break; 1768 break;
1011 default: 1769 default:
@@ -1033,10 +1791,13 @@ static void ui_browser__hists_seek(struct ui_browser *browser,
1033 * and stop when we printed enough lines to fill the screen. 1791 * and stop when we printed enough lines to fill the screen.
1034 */ 1792 */
1035do_offset: 1793do_offset:
1794 if (!nd)
1795 return;
1796
1036 if (offset > 0) { 1797 if (offset > 0) {
1037 do { 1798 do {
1038 h = rb_entry(nd, struct hist_entry, rb_node); 1799 h = rb_entry(nd, struct hist_entry, rb_node);
1039 if (h->unfolded) { 1800 if (h->unfolded && h->leaf) {
1040 u16 remaining = h->nr_rows - h->row_offset; 1801 u16 remaining = h->nr_rows - h->row_offset;
1041 if (offset > remaining) { 1802 if (offset > remaining) {
1042 offset -= remaining; 1803 offset -= remaining;
@@ -1048,7 +1809,8 @@ do_offset:
1048 break; 1809 break;
1049 } 1810 }
1050 } 1811 }
1051 nd = hists__filter_entries(rb_next(nd), hb->min_pcnt); 1812 nd = hists__filter_entries(rb_hierarchy_next(nd),
1813 hb->min_pcnt);
1052 if (nd == NULL) 1814 if (nd == NULL)
1053 break; 1815 break;
1054 --offset; 1816 --offset;
@@ -1057,7 +1819,7 @@ do_offset:
1057 } else if (offset < 0) { 1819 } else if (offset < 0) {
1058 while (1) { 1820 while (1) {
1059 h = rb_entry(nd, struct hist_entry, rb_node); 1821 h = rb_entry(nd, struct hist_entry, rb_node);
1060 if (h->unfolded) { 1822 if (h->unfolded && h->leaf) {
1061 if (first) { 1823 if (first) {
1062 if (-offset > h->row_offset) { 1824 if (-offset > h->row_offset) {
1063 offset += h->row_offset; 1825 offset += h->row_offset;
@@ -1081,7 +1843,7 @@ do_offset:
1081 } 1843 }
1082 } 1844 }
1083 1845
1084 nd = hists__filter_prev_entries(rb_prev(nd), 1846 nd = hists__filter_prev_entries(rb_hierarchy_prev(nd),
1085 hb->min_pcnt); 1847 hb->min_pcnt);
1086 if (nd == NULL) 1848 if (nd == NULL)
1087 break; 1849 break;
@@ -1094,7 +1856,7 @@ do_offset:
1094 * row_offset at its last entry. 1856 * row_offset at its last entry.
1095 */ 1857 */
1096 h = rb_entry(nd, struct hist_entry, rb_node); 1858 h = rb_entry(nd, struct hist_entry, rb_node);
1097 if (h->unfolded) 1859 if (h->unfolded && h->leaf)
1098 h->row_offset = h->nr_rows; 1860 h->row_offset = h->nr_rows;
1099 break; 1861 break;
1100 } 1862 }
@@ -1108,17 +1870,14 @@ do_offset:
1108} 1870}
1109 1871
1110static int hist_browser__fprintf_callchain(struct hist_browser *browser, 1872static int hist_browser__fprintf_callchain(struct hist_browser *browser,
1111 struct hist_entry *he, FILE *fp) 1873 struct hist_entry *he, FILE *fp,
1874 int level)
1112{ 1875{
1113 u64 total = hists__total_period(he->hists);
1114 struct callchain_print_arg arg = { 1876 struct callchain_print_arg arg = {
1115 .fp = fp, 1877 .fp = fp,
1116 }; 1878 };
1117 1879
1118 if (symbol_conf.cumulate_callchain) 1880 hist_browser__show_callchain(browser, he, level, 0,
1119 total = he->stat_acc->period;
1120
1121 hist_browser__show_callchain(browser, &he->sorted_chain, 1, 0, total,
1122 hist_browser__fprintf_callchain_entry, &arg, 1881 hist_browser__fprintf_callchain_entry, &arg,
1123 hist_browser__check_dump_full); 1882 hist_browser__check_dump_full);
1124 return arg.printed; 1883 return arg.printed;
@@ -1144,8 +1903,8 @@ static int hist_browser__fprintf_entry(struct hist_browser *browser,
1144 if (symbol_conf.use_callchain) 1903 if (symbol_conf.use_callchain)
1145 printed += fprintf(fp, "%c ", folded_sign); 1904 printed += fprintf(fp, "%c ", folded_sign);
1146 1905
1147 perf_hpp__for_each_format(fmt) { 1906 hists__for_each_format(browser->hists, fmt) {
1148 if (perf_hpp__should_skip(fmt)) 1907 if (perf_hpp__should_skip(fmt, he->hists))
1149 continue; 1908 continue;
1150 1909
1151 if (!first) { 1910 if (!first) {
@@ -1155,12 +1914,71 @@ static int hist_browser__fprintf_entry(struct hist_browser *browser,
1155 first = false; 1914 first = false;
1156 1915
1157 ret = fmt->entry(fmt, &hpp, he); 1916 ret = fmt->entry(fmt, &hpp, he);
1917 ret = hist_entry__snprintf_alignment(he, &hpp, fmt, ret);
1158 advance_hpp(&hpp, ret); 1918 advance_hpp(&hpp, ret);
1159 } 1919 }
1160 printed += fprintf(fp, "%s\n", rtrim(s)); 1920 printed += fprintf(fp, "%s\n", s);
1161 1921
1162 if (folded_sign == '-') 1922 if (folded_sign == '-')
1163 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 }
1164 1982
1165 return printed; 1983 return printed;
1166} 1984}
@@ -1174,8 +1992,16 @@ static int hist_browser__fprintf(struct hist_browser *browser, FILE *fp)
1174 while (nd) { 1992 while (nd) {
1175 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);
1176 1994
1177 printed += hist_browser__fprintf_entry(browser, h, fp); 1995 if (symbol_conf.report_hierarchy) {
1178 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);
1179 } 2005 }
1180 2006
1181 return printed; 2007 return printed;
@@ -1310,11 +2136,18 @@ static int hists__browser_title(struct hists *hists,
1310 if (hists->uid_filter_str) 2136 if (hists->uid_filter_str)
1311 printed += snprintf(bf + printed, size - printed, 2137 printed += snprintf(bf + printed, size - printed,
1312 ", UID: %s", hists->uid_filter_str); 2138 ", UID: %s", hists->uid_filter_str);
1313 if (thread) 2139 if (thread) {
1314 printed += scnprintf(bf + printed, size - printed, 2140 if (sort__has_thread) {
2141 printed += scnprintf(bf + printed, size - printed,
1315 ", Thread: %s(%d)", 2142 ", Thread: %s(%d)",
1316 (thread->comm_set ? thread__comm_str(thread) : ""), 2143 (thread->comm_set ? thread__comm_str(thread) : ""),
1317 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 }
1318 if (dso) 2151 if (dso)
1319 printed += scnprintf(bf + printed, size - printed, 2152 printed += scnprintf(bf + printed, size - printed,
1320 ", DSO: %s", dso->short_name); 2153 ", DSO: %s", dso->short_name);
@@ -1430,7 +2263,6 @@ close_file_and_continue:
1430 2263
1431struct popup_action { 2264struct popup_action {
1432 struct thread *thread; 2265 struct thread *thread;
1433 struct dso *dso;
1434 struct map_symbol ms; 2266 struct map_symbol ms;
1435 int socket; 2267 int socket;
1436 2268
@@ -1490,15 +2322,24 @@ do_zoom_thread(struct hist_browser *browser, struct popup_action *act)
1490{ 2322{
1491 struct thread *thread = act->thread; 2323 struct thread *thread = act->thread;
1492 2324
2325 if ((!sort__has_thread && !sort__has_comm) || thread == NULL)
2326 return 0;
2327
1493 if (browser->hists->thread_filter) { 2328 if (browser->hists->thread_filter) {
1494 pstack__remove(browser->pstack, &browser->hists->thread_filter); 2329 pstack__remove(browser->pstack, &browser->hists->thread_filter);
1495 perf_hpp__set_elide(HISTC_THREAD, false); 2330 perf_hpp__set_elide(HISTC_THREAD, false);
1496 thread__zput(browser->hists->thread_filter); 2331 thread__zput(browser->hists->thread_filter);
1497 ui_helpline__pop(); 2332 ui_helpline__pop();
1498 } else { 2333 } else {
1499 ui_helpline__fpush("To zoom out press ESC or ENTER + \"Zoom out of %s(%d) thread\"", 2334 if (sort__has_thread) {
1500 thread->comm_set ? thread__comm_str(thread) : "", 2335 ui_helpline__fpush("To zoom out press ESC or ENTER + \"Zoom out of %s(%d) thread\"",
1501 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
1502 browser->hists->thread_filter = thread__get(thread); 2343 browser->hists->thread_filter = thread__get(thread);
1503 perf_hpp__set_elide(HISTC_THREAD, false); 2344 perf_hpp__set_elide(HISTC_THREAD, false);
1504 pstack__push(browser->pstack, &browser->hists->thread_filter); 2345 pstack__push(browser->pstack, &browser->hists->thread_filter);
@@ -1513,13 +2354,22 @@ static int
1513add_thread_opt(struct hist_browser *browser, struct popup_action *act, 2354add_thread_opt(struct hist_browser *browser, struct popup_action *act,
1514 char **optstr, struct thread *thread) 2355 char **optstr, struct thread *thread)
1515{ 2356{
1516 if (thread == NULL) 2357 int ret;
2358
2359 if ((!sort__has_thread && !sort__has_comm) || thread == NULL)
1517 return 0; 2360 return 0;
1518 2361
1519 if (asprintf(optstr, "Zoom %s %s(%d) thread", 2362 if (sort__has_thread) {
1520 browser->hists->thread_filter ? "out of" : "into", 2363 ret = asprintf(optstr, "Zoom %s %s(%d) thread",
1521 thread->comm_set ? thread__comm_str(thread) : "", 2364 browser->hists->thread_filter ? "out of" : "into",
1522 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)
1523 return 0; 2373 return 0;
1524 2374
1525 act->thread = thread; 2375 act->thread = thread;
@@ -1532,6 +2382,9 @@ do_zoom_dso(struct hist_browser *browser, struct popup_action *act)
1532{ 2382{
1533 struct map *map = act->ms.map; 2383 struct map *map = act->ms.map;
1534 2384
2385 if (!sort__has_dso || map == NULL)
2386 return 0;
2387
1535 if (browser->hists->dso_filter) { 2388 if (browser->hists->dso_filter) {
1536 pstack__remove(browser->pstack, &browser->hists->dso_filter); 2389 pstack__remove(browser->pstack, &browser->hists->dso_filter);
1537 perf_hpp__set_elide(HISTC_DSO, false); 2390 perf_hpp__set_elide(HISTC_DSO, false);
@@ -1556,7 +2409,7 @@ static int
1556add_dso_opt(struct hist_browser *browser, struct popup_action *act, 2409add_dso_opt(struct hist_browser *browser, struct popup_action *act,
1557 char **optstr, struct map *map) 2410 char **optstr, struct map *map)
1558{ 2411{
1559 if (map == NULL) 2412 if (!sort__has_dso || map == NULL)
1560 return 0; 2413 return 0;
1561 2414
1562 if (asprintf(optstr, "Zoom %s %s DSO", 2415 if (asprintf(optstr, "Zoom %s %s DSO",
@@ -1565,7 +2418,6 @@ add_dso_opt(struct hist_browser *browser, struct popup_action *act,
1565 return 0; 2418 return 0;
1566 2419
1567 act->ms.map = map; 2420 act->ms.map = map;
1568 act->dso = map->dso;
1569 act->fn = do_zoom_dso; 2421 act->fn = do_zoom_dso;
1570 return 1; 2422 return 1;
1571} 2423}
@@ -1582,7 +2434,7 @@ static int
1582add_map_opt(struct hist_browser *browser __maybe_unused, 2434add_map_opt(struct hist_browser *browser __maybe_unused,
1583 struct popup_action *act, char **optstr, struct map *map) 2435 struct popup_action *act, char **optstr, struct map *map)
1584{ 2436{
1585 if (map == NULL) 2437 if (!sort__has_dso || map == NULL)
1586 return 0; 2438 return 0;
1587 2439
1588 if (asprintf(optstr, "Browse map details") < 0) 2440 if (asprintf(optstr, "Browse map details") < 0)
@@ -1684,6 +2536,9 @@ add_exit_opt(struct hist_browser *browser __maybe_unused,
1684static int 2536static int
1685do_zoom_socket(struct hist_browser *browser, struct popup_action *act) 2537do_zoom_socket(struct hist_browser *browser, struct popup_action *act)
1686{ 2538{
2539 if (!sort__has_socket || act->socket < 0)
2540 return 0;
2541
1687 if (browser->hists->socket_filter > -1) { 2542 if (browser->hists->socket_filter > -1) {
1688 pstack__remove(browser->pstack, &browser->hists->socket_filter); 2543 pstack__remove(browser->pstack, &browser->hists->socket_filter);
1689 browser->hists->socket_filter = -1; 2544 browser->hists->socket_filter = -1;
@@ -1703,7 +2558,7 @@ static int
1703add_socket_opt(struct hist_browser *browser, struct popup_action *act, 2558add_socket_opt(struct hist_browser *browser, struct popup_action *act,
1704 char **optstr, int socket_id) 2559 char **optstr, int socket_id)
1705{ 2560{
1706 if (socket_id < 0) 2561 if (!sort__has_socket || socket_id < 0)
1707 return 0; 2562 return 0;
1708 2563
1709 if (asprintf(optstr, "Zoom %s Processor Socket %d", 2564 if (asprintf(optstr, "Zoom %s Processor Socket %d",
@@ -1721,17 +2576,60 @@ static void hist_browser__update_nr_entries(struct hist_browser *hb)
1721 u64 nr_entries = 0; 2576 u64 nr_entries = 0;
1722 struct rb_node *nd = rb_first(&hb->hists->entries); 2577 struct rb_node *nd = rb_first(&hb->hists->entries);
1723 2578
1724 if (hb->min_pcnt == 0) { 2579 if (hb->min_pcnt == 0 && !symbol_conf.report_hierarchy) {
1725 hb->nr_non_filtered_entries = hb->hists->nr_non_filtered_entries; 2580 hb->nr_non_filtered_entries = hb->hists->nr_non_filtered_entries;
1726 return; 2581 return;
1727 } 2582 }
1728 2583
1729 while ((nd = hists__filter_entries(nd, hb->min_pcnt)) != NULL) { 2584 while ((nd = hists__filter_entries(nd, hb->min_pcnt)) != NULL) {
1730 nr_entries++; 2585 nr_entries++;
1731 nd = rb_next(nd); 2586 nd = rb_hierarchy_next(nd);
1732 } 2587 }
1733 2588
1734 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 }
1735} 2633}
1736 2634
1737static 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,
@@ -1769,6 +2667,7 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
1769 "E Expand all callchains\n" \ 2667 "E Expand all callchains\n" \
1770 "F Toggle percentage of filtered entries\n" \ 2668 "F Toggle percentage of filtered entries\n" \
1771 "H Display column headers\n" \ 2669 "H Display column headers\n" \
2670 "L Change percent limit\n" \
1772 "m Display context menu\n" \ 2671 "m Display context menu\n" \
1773 "S Zoom into current Processor Socket\n" \ 2672 "S Zoom into current Processor Socket\n" \
1774 2673
@@ -1796,10 +2695,9 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
1796 SLang_reset_tty(); 2695 SLang_reset_tty();
1797 SLang_init_tty(0, 0, 0); 2696 SLang_init_tty(0, 0, 0);
1798 2697
1799 if (min_pcnt) { 2698 if (min_pcnt)
1800 browser->min_pcnt = min_pcnt; 2699 browser->min_pcnt = min_pcnt;
1801 hist_browser__update_nr_entries(browser); 2700 hist_browser__update_nr_entries(browser);
1802 }
1803 2701
1804 browser->pstack = pstack__new(3); 2702 browser->pstack = pstack__new(3);
1805 if (browser->pstack == NULL) 2703 if (browser->pstack == NULL)
@@ -1810,7 +2708,7 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
1810 memset(options, 0, sizeof(options)); 2708 memset(options, 0, sizeof(options));
1811 memset(actions, 0, sizeof(actions)); 2709 memset(actions, 0, sizeof(actions));
1812 2710
1813 perf_hpp__for_each_format(fmt) { 2711 hists__for_each_format(browser->hists, fmt) {
1814 perf_hpp__reset_width(fmt, hists); 2712 perf_hpp__reset_width(fmt, hists);
1815 /* 2713 /*
1816 * This is done just once, and activates the horizontal scrolling 2714 * This is done just once, and activates the horizontal scrolling
@@ -1827,7 +2725,6 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
1827 2725
1828 while (1) { 2726 while (1) {
1829 struct thread *thread = NULL; 2727 struct thread *thread = NULL;
1830 struct dso *dso = NULL;
1831 struct map *map = NULL; 2728 struct map *map = NULL;
1832 int choice = 0; 2729 int choice = 0;
1833 int socked_id = -1; 2730 int socked_id = -1;
@@ -1839,8 +2736,6 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
1839 if (browser->he_selection != NULL) { 2736 if (browser->he_selection != NULL) {
1840 thread = hist_browser__selected_thread(browser); 2737 thread = hist_browser__selected_thread(browser);
1841 map = browser->selection->map; 2738 map = browser->selection->map;
1842 if (map)
1843 dso = map->dso;
1844 socked_id = browser->he_selection->socket; 2739 socked_id = browser->he_selection->socket;
1845 } 2740 }
1846 switch (key) { 2741 switch (key) {
@@ -1874,7 +2769,7 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
1874 hist_browser__dump(browser); 2769 hist_browser__dump(browser);
1875 continue; 2770 continue;
1876 case 'd': 2771 case 'd':
1877 actions->dso = dso; 2772 actions->ms.map = map;
1878 do_zoom_dso(browser, actions); 2773 do_zoom_dso(browser, actions);
1879 continue; 2774 continue;
1880 case 'V': 2775 case 'V':
@@ -1928,6 +2823,24 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
1928 top->zero = !top->zero; 2823 top->zero = !top->zero;
1929 } 2824 }
1930 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;
1931 case K_F1: 2844 case K_F1:
1932 case 'h': 2845 case 'h':
1933 case '?': 2846 case '?':
@@ -1999,10 +2912,7 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
1999 continue; 2912 continue;
2000 } 2913 }
2001 2914
2002 if (!sort__has_sym) 2915 if (!sort__has_sym || browser->selection == NULL)
2003 goto add_exit_option;
2004
2005 if (browser->selection == NULL)
2006 goto skip_annotation; 2916 goto skip_annotation;
2007 2917
2008 if (sort__mode == SORT_MODE__BRANCH) { 2918 if (sort__mode == SORT_MODE__BRANCH) {
@@ -2042,11 +2952,16 @@ skip_annotation:
2042 &options[nr_options], 2952 &options[nr_options],
2043 socked_id); 2953 socked_id);
2044 /* perf script support */ 2954 /* perf script support */
2955 if (!is_report_browser(hbt))
2956 goto skip_scripting;
2957
2045 if (browser->he_selection) { 2958 if (browser->he_selection) {
2046 nr_options += add_script_opt(browser, 2959 if (sort__has_thread && thread) {
2047 &actions[nr_options], 2960 nr_options += add_script_opt(browser,
2048 &options[nr_options], 2961 &actions[nr_options],
2049 thread, NULL); 2962 &options[nr_options],
2963 thread, NULL);
2964 }
2050 /* 2965 /*
2051 * Note that browser->selection != NULL 2966 * Note that browser->selection != NULL
2052 * when browser->he_selection is not NULL, 2967 * when browser->he_selection is not NULL,
@@ -2056,16 +2971,18 @@ skip_annotation:
2056 * 2971 *
2057 * See hist_browser__show_entry. 2972 * See hist_browser__show_entry.
2058 */ 2973 */
2059 nr_options += add_script_opt(browser, 2974 if (sort__has_sym && browser->selection->sym) {
2060 &actions[nr_options], 2975 nr_options += add_script_opt(browser,
2061 &options[nr_options], 2976 &actions[nr_options],
2062 NULL, browser->selection->sym); 2977 &options[nr_options],
2978 NULL, browser->selection->sym);
2979 }
2063 } 2980 }
2064 nr_options += add_script_opt(browser, &actions[nr_options], 2981 nr_options += add_script_opt(browser, &actions[nr_options],
2065 &options[nr_options], NULL, NULL); 2982 &options[nr_options], NULL, NULL);
2066 nr_options += add_switch_opt(browser, &actions[nr_options], 2983 nr_options += add_switch_opt(browser, &actions[nr_options],
2067 &options[nr_options]); 2984 &options[nr_options]);
2068add_exit_option: 2985skip_scripting:
2069 nr_options += add_exit_opt(browser, &actions[nr_options], 2986 nr_options += add_exit_opt(browser, &actions[nr_options],
2070 &options[nr_options]); 2987 &options[nr_options]);
2071 2988
diff --git a/tools/perf/ui/gtk/hists.c b/tools/perf/ui/gtk/hists.c
index 4b3585eed1e8..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{ \
@@ -89,8 +89,8 @@ void perf_gtk__init_hpp(void)
89 perf_gtk__hpp_color_overhead_acc; 89 perf_gtk__hpp_color_overhead_acc;
90} 90}
91 91
92static void perf_gtk__add_callchain(struct rb_root *root, GtkTreeStore *store, 92static void perf_gtk__add_callchain_flat(struct rb_root *root, GtkTreeStore *store,
93 GtkTreeIter *parent, int col, u64 total) 93 GtkTreeIter *parent, int col, u64 total)
94{ 94{
95 struct rb_node *nd; 95 struct rb_node *nd;
96 bool has_single_node = (rb_first(root) == rb_last(root)); 96 bool has_single_node = (rb_first(root) == rb_last(root));
@@ -100,13 +100,132 @@ static void perf_gtk__add_callchain(struct rb_root *root, GtkTreeStore *store,
100 struct callchain_list *chain; 100 struct callchain_list *chain;
101 GtkTreeIter iter, new_parent; 101 GtkTreeIter iter, new_parent;
102 bool need_new_parent; 102 bool need_new_parent;
103 double percent;
104 u64 hits, child_total;
105 103
106 node = rb_entry(nd, struct callchain_node, rb_node); 104 node = rb_entry(nd, struct callchain_node, rb_node);
107 105
108 hits = callchain_cumul_hits(node); 106 new_parent = *parent;
109 percent = 100.0 * hits / total; 107 need_new_parent = !has_single_node;
108
109 callchain_node__make_parent_list(node);
110
111 list_for_each_entry(chain, &node->parent_val, list) {
112 char buf[128];
113
114 gtk_tree_store_append(store, &iter, &new_parent);
115
116 callchain_node__scnprintf_value(node, buf, sizeof(buf), total);
117 gtk_tree_store_set(store, &iter, 0, buf, -1);
118
119 callchain_list__sym_name(chain, buf, sizeof(buf), false);
120 gtk_tree_store_set(store, &iter, col, buf, -1);
121
122 if (need_new_parent) {
123 /*
124 * Only show the top-most symbol in a callchain
125 * if it's not the only callchain.
126 */
127 new_parent = iter;
128 need_new_parent = false;
129 }
130 }
131
132 list_for_each_entry(chain, &node->val, list) {
133 char buf[128];
134
135 gtk_tree_store_append(store, &iter, &new_parent);
136
137 callchain_node__scnprintf_value(node, buf, sizeof(buf), total);
138 gtk_tree_store_set(store, &iter, 0, buf, -1);
139
140 callchain_list__sym_name(chain, buf, sizeof(buf), false);
141 gtk_tree_store_set(store, &iter, col, buf, -1);
142
143 if (need_new_parent) {
144 /*
145 * Only show the top-most symbol in a callchain
146 * if it's not the only callchain.
147 */
148 new_parent = iter;
149 need_new_parent = false;
150 }
151 }
152 }
153}
154
155static void perf_gtk__add_callchain_folded(struct rb_root *root, GtkTreeStore *store,
156 GtkTreeIter *parent, int col, u64 total)
157{
158 struct rb_node *nd;
159
160 for (nd = rb_first(root); nd; nd = rb_next(nd)) {
161 struct callchain_node *node;
162 struct callchain_list *chain;
163 GtkTreeIter iter;
164 char buf[64];
165 char *str, *str_alloc = NULL;
166 bool first = true;
167
168 node = rb_entry(nd, struct callchain_node, rb_node);
169
170 callchain_node__make_parent_list(node);
171
172 list_for_each_entry(chain, &node->parent_val, list) {
173 char name[1024];
174
175 callchain_list__sym_name(chain, name, sizeof(name), false);
176
177 if (asprintf(&str, "%s%s%s",
178 first ? "" : str_alloc,
179 first ? "" : symbol_conf.field_sep ?: "; ",
180 name) < 0)
181 return;
182
183 first = false;
184 free(str_alloc);
185 str_alloc = str;
186 }
187
188 list_for_each_entry(chain, &node->val, list) {
189 char name[1024];
190
191 callchain_list__sym_name(chain, name, sizeof(name), false);
192
193 if (asprintf(&str, "%s%s%s",
194 first ? "" : str_alloc,
195 first ? "" : symbol_conf.field_sep ?: "; ",
196 name) < 0)
197 return;
198
199 first = false;
200 free(str_alloc);
201 str_alloc = str;
202 }
203
204 gtk_tree_store_append(store, &iter, parent);
205
206 callchain_node__scnprintf_value(node, buf, sizeof(buf), total);
207 gtk_tree_store_set(store, &iter, 0, buf, -1);
208
209 gtk_tree_store_set(store, &iter, col, str, -1);
210
211 free(str_alloc);
212 }
213}
214
215static void perf_gtk__add_callchain_graph(struct rb_root *root, GtkTreeStore *store,
216 GtkTreeIter *parent, int col, u64 total)
217{
218 struct rb_node *nd;
219 bool has_single_node = (rb_first(root) == rb_last(root));
220
221 for (nd = rb_first(root); nd; nd = rb_next(nd)) {
222 struct callchain_node *node;
223 struct callchain_list *chain;
224 GtkTreeIter iter, new_parent;
225 bool need_new_parent;
226 u64 child_total;
227
228 node = rb_entry(nd, struct callchain_node, rb_node);
110 229
111 new_parent = *parent; 230 new_parent = *parent;
112 need_new_parent = !has_single_node && (node->val_nr > 1); 231 need_new_parent = !has_single_node && (node->val_nr > 1);
@@ -116,7 +235,7 @@ static void perf_gtk__add_callchain(struct rb_root *root, GtkTreeStore *store,
116 235
117 gtk_tree_store_append(store, &iter, &new_parent); 236 gtk_tree_store_append(store, &iter, &new_parent);
118 237
119 scnprintf(buf, sizeof(buf), "%5.2f%%", percent); 238 callchain_node__scnprintf_value(node, buf, sizeof(buf), total);
120 gtk_tree_store_set(store, &iter, 0, buf, -1); 239 gtk_tree_store_set(store, &iter, 0, buf, -1);
121 240
122 callchain_list__sym_name(chain, buf, sizeof(buf), false); 241 callchain_list__sym_name(chain, buf, sizeof(buf), false);
@@ -138,11 +257,22 @@ static void perf_gtk__add_callchain(struct rb_root *root, GtkTreeStore *store,
138 child_total = total; 257 child_total = total;
139 258
140 /* Now 'iter' contains info of the last callchain_list */ 259 /* Now 'iter' contains info of the last callchain_list */
141 perf_gtk__add_callchain(&node->rb_root, store, &iter, col, 260 perf_gtk__add_callchain_graph(&node->rb_root, store, &iter, col,
142 child_total); 261 child_total);
143 } 262 }
144} 263}
145 264
265static void perf_gtk__add_callchain(struct rb_root *root, GtkTreeStore *store,
266 GtkTreeIter *parent, int col, u64 total)
267{
268 if (callchain_param.mode == CHAIN_FLAT)
269 perf_gtk__add_callchain_flat(root, store, parent, col, total);
270 else if (callchain_param.mode == CHAIN_FOLDED)
271 perf_gtk__add_callchain_folded(root, store, parent, col, total);
272 else
273 perf_gtk__add_callchain_graph(root, store, parent, col, total);
274}
275
146static void on_row_activated(GtkTreeView *view, GtkTreePath *path, 276static void on_row_activated(GtkTreeView *view, GtkTreePath *path,
147 GtkTreeViewColumn *col __maybe_unused, 277 GtkTreeViewColumn *col __maybe_unused,
148 gpointer user_data __maybe_unused) 278 gpointer user_data __maybe_unused)
@@ -176,7 +306,7 @@ static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists,
176 306
177 nr_cols = 0; 307 nr_cols = 0;
178 308
179 perf_hpp__for_each_format(fmt) 309 hists__for_each_format(hists, fmt)
180 col_types[nr_cols++] = G_TYPE_STRING; 310 col_types[nr_cols++] = G_TYPE_STRING;
181 311
182 store = gtk_tree_store_newv(nr_cols, col_types); 312 store = gtk_tree_store_newv(nr_cols, col_types);
@@ -187,8 +317,8 @@ static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists,
187 317
188 col_idx = 0; 318 col_idx = 0;
189 319
190 perf_hpp__for_each_format(fmt) { 320 hists__for_each_format(hists, fmt) {
191 if (perf_hpp__should_skip(fmt)) 321 if (perf_hpp__should_skip(fmt, hists))
192 continue; 322 continue;
193 323
194 /* 324 /*
@@ -237,8 +367,8 @@ static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists,
237 367
238 col_idx = 0; 368 col_idx = 0;
239 369
240 perf_hpp__for_each_format(fmt) { 370 hists__for_each_format(hists, fmt) {
241 if (perf_hpp__should_skip(fmt)) 371 if (perf_hpp__should_skip(fmt, h->hists))
242 continue; 372 continue;
243 373
244 if (fmt->color) 374 if (fmt->color)
@@ -266,6 +396,194 @@ static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists,
266 gtk_container_add(GTK_CONTAINER(window), view); 396 gtk_container_add(GTK_CONTAINER(window), view);
267} 397}
268 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
269int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist, 587int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist,
270 const char *help, 588 const char *help,
271 struct hist_browser_timer *hbt __maybe_unused, 589 struct hist_browser_timer *hbt __maybe_unused,
@@ -333,7 +651,10 @@ int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist,
333 GTK_POLICY_AUTOMATIC, 651 GTK_POLICY_AUTOMATIC,
334 GTK_POLICY_AUTOMATIC); 652 GTK_POLICY_AUTOMATIC);
335 653
336 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);
337 658
338 tab_label = gtk_label_new(evname); 659 tab_label = gtk_label_new(evname);
339 660
diff --git a/tools/perf/ui/hist.c b/tools/perf/ui/hist.c
index 5029ba2b55af..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
@@ -443,7 +464,6 @@ LIST_HEAD(perf_hpp__sort_list);
443 464
444void perf_hpp__init(void) 465void perf_hpp__init(void)
445{ 466{
446 struct list_head *list;
447 int i; 467 int i;
448 468
449 for (i = 0; i < PERF_HPP__MAX_INDEX; i++) { 469 for (i = 0; i < PERF_HPP__MAX_INDEX; i++) {
@@ -484,22 +504,18 @@ void perf_hpp__init(void)
484 504
485 if (symbol_conf.show_total_period) 505 if (symbol_conf.show_total_period)
486 hpp_dimension__add_output(PERF_HPP__PERIOD); 506 hpp_dimension__add_output(PERF_HPP__PERIOD);
507}
487 508
488 /* prepend overhead field for backward compatiblity. */ 509void perf_hpp_list__column_register(struct perf_hpp_list *list,
489 list = &perf_hpp__format[PERF_HPP__OVERHEAD].sort_list; 510 struct perf_hpp_fmt *format)
490 if (list_empty(list)) 511{
491 list_add(list, &perf_hpp__sort_list); 512 list_add_tail(&format->list, &list->fields);
492
493 if (symbol_conf.cumulate_callchain) {
494 list = &perf_hpp__format[PERF_HPP__OVERHEAD_ACC].sort_list;
495 if (list_empty(list))
496 list_add(list, &perf_hpp__sort_list);
497 }
498} 513}
499 514
500void perf_hpp__column_register(struct perf_hpp_fmt *format) 515void perf_hpp_list__register_sort_field(struct perf_hpp_list *list,
516 struct perf_hpp_fmt *format)
501{ 517{
502 list_add_tail(&format->list, &perf_hpp__list); 518 list_add_tail(&format->sort_list, &list->sorts);
503} 519}
504 520
505void perf_hpp__column_unregister(struct perf_hpp_fmt *format) 521void perf_hpp__column_unregister(struct perf_hpp_fmt *format)
@@ -507,53 +523,43 @@ void perf_hpp__column_unregister(struct perf_hpp_fmt *format)
507 list_del(&format->list); 523 list_del(&format->list);
508} 524}
509 525
510void perf_hpp__register_sort_field(struct perf_hpp_fmt *format) 526void perf_hpp__cancel_cumulate(void)
511{ 527{
512 list_add_tail(&format->sort_list, &perf_hpp__sort_list); 528 struct perf_hpp_fmt *fmt, *acc, *ovh, *tmp;
513}
514 529
515void perf_hpp__column_enable(unsigned col) 530 if (is_strict_order(field_order))
516{ 531 return;
517 BUG_ON(col >= PERF_HPP__MAX_INDEX);
518 perf_hpp__column_register(&perf_hpp__format[col]);
519}
520 532
521void perf_hpp__column_disable(unsigned col) 533 ovh = &perf_hpp__format[PERF_HPP__OVERHEAD];
522{ 534 acc = &perf_hpp__format[PERF_HPP__OVERHEAD_ACC];
523 BUG_ON(col >= PERF_HPP__MAX_INDEX); 535
524 perf_hpp__column_unregister(&perf_hpp__format[col]); 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 }
525} 545}
526 546
527void perf_hpp__cancel_cumulate(void) 547static bool fmt_equal(struct perf_hpp_fmt *a, struct perf_hpp_fmt *b)
528{ 548{
529 if (is_strict_order(field_order)) 549 return a->equal && a->equal(a, b);
530 return;
531
532 perf_hpp__column_disable(PERF_HPP__OVERHEAD_ACC);
533 perf_hpp__format[PERF_HPP__OVERHEAD].name = "Overhead";
534} 550}
535 551
536void perf_hpp__setup_output_field(void) 552void perf_hpp__setup_output_field(struct perf_hpp_list *list)
537{ 553{
538 struct perf_hpp_fmt *fmt; 554 struct perf_hpp_fmt *fmt;
539 555
540 /* append sort keys to output field */ 556 /* append sort keys to output field */
541 perf_hpp__for_each_sort_list(fmt) { 557 perf_hpp_list__for_each_sort_list(list, fmt) {
542 if (!list_empty(&fmt->list)) 558 struct perf_hpp_fmt *pos;
543 continue;
544 559
545 /* 560 perf_hpp_list__for_each_format(list, pos) {
546 * sort entry fields are dynamically created, 561 if (fmt_equal(fmt, pos))
547 * so they can share a same sort key even though 562 goto next;
548 * the list is empty.
549 */
550 if (perf_hpp__is_sort_entry(fmt)) {
551 struct perf_hpp_fmt *pos;
552
553 perf_hpp__for_each_format(pos) {
554 if (perf_hpp__same_sort_entry(pos, fmt))
555 goto next;
556 }
557 } 563 }
558 564
559 perf_hpp__column_register(fmt); 565 perf_hpp__column_register(fmt);
@@ -562,27 +568,17 @@ next:
562 } 568 }
563} 569}
564 570
565void perf_hpp__append_sort_keys(void) 571void perf_hpp__append_sort_keys(struct perf_hpp_list *list)
566{ 572{
567 struct perf_hpp_fmt *fmt; 573 struct perf_hpp_fmt *fmt;
568 574
569 /* append output fields to sort keys */ 575 /* append output fields to sort keys */
570 perf_hpp__for_each_format(fmt) { 576 perf_hpp_list__for_each_format(list, fmt) {
571 if (!list_empty(&fmt->sort_list)) 577 struct perf_hpp_fmt *pos;
572 continue;
573 578
574 /* 579 perf_hpp_list__for_each_sort_list(list, pos) {
575 * sort entry fields are dynamically created, 580 if (fmt_equal(fmt, pos))
576 * so they can share a same sort key even though 581 goto next;
577 * the list is empty.
578 */
579 if (perf_hpp__is_sort_entry(fmt)) {
580 struct perf_hpp_fmt *pos;
581
582 perf_hpp__for_each_sort_list(pos) {
583 if (perf_hpp__same_sort_entry(pos, fmt))
584 goto next;
585 }
586 } 582 }
587 583
588 perf_hpp__register_sort_field(fmt); 584 perf_hpp__register_sort_field(fmt);
@@ -591,20 +587,29 @@ next:
591 } 587 }
592} 588}
593 589
594void 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)
595{ 598{
596 struct perf_hpp_fmt *fmt, *tmp; 599 struct perf_hpp_fmt *fmt, *tmp;
597 600
598 /* reset output fields */ 601 /* reset output fields */
599 perf_hpp__for_each_format_safe(fmt, tmp) { 602 perf_hpp_list__for_each_format_safe(list, fmt, tmp) {
600 list_del_init(&fmt->list); 603 list_del_init(&fmt->list);
601 list_del_init(&fmt->sort_list); 604 list_del_init(&fmt->sort_list);
605 fmt_free(fmt);
602 } 606 }
603 607
604 /* reset sort keys */ 608 /* reset sort keys */
605 perf_hpp__for_each_sort_list_safe(fmt, tmp) { 609 perf_hpp_list__for_each_sort_list_safe(list, fmt, tmp) {
606 list_del_init(&fmt->list); 610 list_del_init(&fmt->list);
607 list_del_init(&fmt->sort_list); 611 list_del_init(&fmt->sort_list);
612 fmt_free(fmt);
608 } 613 }
609} 614}
610 615
@@ -618,8 +623,8 @@ unsigned int hists__sort_list_width(struct hists *hists)
618 bool first = true; 623 bool first = true;
619 struct perf_hpp dummy_hpp; 624 struct perf_hpp dummy_hpp;
620 625
621 perf_hpp__for_each_format(fmt) { 626 hists__for_each_format(hists, fmt) {
622 if (perf_hpp__should_skip(fmt)) 627 if (perf_hpp__should_skip(fmt, hists))
623 continue; 628 continue;
624 629
625 if (first) 630 if (first)
@@ -636,22 +641,39 @@ unsigned int hists__sort_list_width(struct hists *hists)
636 return ret; 641 return ret;
637} 642}
638 643
639void perf_hpp__reset_width(struct perf_hpp_fmt *fmt, struct hists *hists) 644unsigned int hists__overhead_width(struct hists *hists)
640{ 645{
641 int idx; 646 struct perf_hpp_fmt *fmt;
642 647 int ret = 0;
643 if (perf_hpp__is_sort_entry(fmt)) 648 bool first = true;
644 return perf_hpp__reset_sort_width(fmt, hists); 649 struct perf_hpp dummy_hpp;
645 650
646 for (idx = 0; idx < PERF_HPP__MAX_INDEX; idx++) { 651 hists__for_each_format(hists, fmt) {
647 if (fmt == &perf_hpp__format[idx]) 652 if (perf_hpp__is_sort_entry(fmt) || perf_hpp__is_dynamic_entry(fmt))
648 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));
649 } 661 }
650 662
651 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))
652 return; 672 return;
653 673
654 switch (idx) { 674 BUG_ON(fmt->idx >= PERF_HPP__MAX_INDEX);
675
676 switch (fmt->idx) {
655 case PERF_HPP__OVERHEAD: 677 case PERF_HPP__OVERHEAD:
656 case PERF_HPP__OVERHEAD_SYS: 678 case PERF_HPP__OVERHEAD_SYS:
657 case PERF_HPP__OVERHEAD_US: 679 case PERF_HPP__OVERHEAD_US:
@@ -679,7 +701,7 @@ void perf_hpp__set_user_width(const char *width_list_str)
679 struct perf_hpp_fmt *fmt; 701 struct perf_hpp_fmt *fmt;
680 const char *ptr = width_list_str; 702 const char *ptr = width_list_str;
681 703
682 perf_hpp__for_each_format(fmt) { 704 perf_hpp_list__for_each_format(&perf_hpp_list, fmt) {
683 char *p; 705 char *p;
684 706
685 int len = strtol(ptr, &p, 10); 707 int len = strtol(ptr, &p, 10);
@@ -691,3 +713,71 @@ void perf_hpp__set_user_width(const char *width_list_str)
691 break; 713 break;
692 } 714 }
693} 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 dfcbc90146ef..7aff5acf3265 100644
--- a/tools/perf/ui/stdio/hist.c
+++ b/tools/perf/ui/stdio/hist.c
@@ -34,10 +34,10 @@ static size_t ipchain__fprintf_graph_line(FILE *fp, int depth, int depth_mask,
34 return ret; 34 return ret;
35} 35}
36 36
37static size_t ipchain__fprintf_graph(FILE *fp, struct callchain_list *chain, 37static size_t ipchain__fprintf_graph(FILE *fp, struct callchain_node *node,
38 struct callchain_list *chain,
38 int depth, int depth_mask, int period, 39 int depth, int depth_mask, int period,
39 u64 total_samples, u64 hits, 40 u64 total_samples, int left_margin)
40 int left_margin)
41{ 41{
42 int i; 42 int i;
43 size_t ret = 0; 43 size_t ret = 0;
@@ -50,10 +50,9 @@ static size_t ipchain__fprintf_graph(FILE *fp, struct callchain_list *chain,
50 else 50 else
51 ret += fprintf(fp, " "); 51 ret += fprintf(fp, " ");
52 if (!period && i == depth - 1) { 52 if (!period && i == depth - 1) {
53 double percent; 53 ret += fprintf(fp, "--");
54 54 ret += callchain_node__fprintf_value(node, fp, total_samples);
55 percent = hits * 100.0 / total_samples; 55 ret += fprintf(fp, "--");
56 ret += percent_color_fprintf(fp, "--%2.2f%%-- ", percent);
57 } else 56 } else
58 ret += fprintf(fp, "%s", " "); 57 ret += fprintf(fp, "%s", " ");
59 } 58 }
@@ -82,13 +81,14 @@ static size_t __callchain__fprintf_graph(FILE *fp, struct rb_root *root,
82 int depth_mask, int left_margin) 81 int depth_mask, int left_margin)
83{ 82{
84 struct rb_node *node, *next; 83 struct rb_node *node, *next;
85 struct callchain_node *child; 84 struct callchain_node *child = NULL;
86 struct callchain_list *chain; 85 struct callchain_list *chain;
87 int new_depth_mask = depth_mask; 86 int new_depth_mask = depth_mask;
88 u64 remaining; 87 u64 remaining;
89 size_t ret = 0; 88 size_t ret = 0;
90 int i; 89 int i;
91 uint entries_printed = 0; 90 uint entries_printed = 0;
91 int cumul_count = 0;
92 92
93 remaining = total_samples; 93 remaining = total_samples;
94 94
@@ -100,6 +100,7 @@ static size_t __callchain__fprintf_graph(FILE *fp, struct rb_root *root,
100 child = rb_entry(node, struct callchain_node, rb_node); 100 child = rb_entry(node, struct callchain_node, rb_node);
101 cumul = callchain_cumul_hits(child); 101 cumul = callchain_cumul_hits(child);
102 remaining -= cumul; 102 remaining -= cumul;
103 cumul_count += callchain_cumul_counts(child);
103 104
104 /* 105 /*
105 * The depth mask manages the output of pipes that show 106 * The depth mask manages the output of pipes that show
@@ -120,10 +121,9 @@ static size_t __callchain__fprintf_graph(FILE *fp, struct rb_root *root,
120 left_margin); 121 left_margin);
121 i = 0; 122 i = 0;
122 list_for_each_entry(chain, &child->val, list) { 123 list_for_each_entry(chain, &child->val, list) {
123 ret += ipchain__fprintf_graph(fp, chain, depth, 124 ret += ipchain__fprintf_graph(fp, child, chain, depth,
124 new_depth_mask, i++, 125 new_depth_mask, i++,
125 total_samples, 126 total_samples,
126 cumul,
127 left_margin); 127 left_margin);
128 } 128 }
129 129
@@ -143,21 +143,50 @@ static size_t __callchain__fprintf_graph(FILE *fp, struct rb_root *root,
143 143
144 if (callchain_param.mode == CHAIN_GRAPH_REL && 144 if (callchain_param.mode == CHAIN_GRAPH_REL &&
145 remaining && remaining != total_samples) { 145 remaining && remaining != total_samples) {
146 struct callchain_node rem_node = {
147 .hit = remaining,
148 };
146 149
147 if (!rem_sq_bracket) 150 if (!rem_sq_bracket)
148 return ret; 151 return ret;
149 152
153 if (callchain_param.value == CCVAL_COUNT && child && child->parent) {
154 rem_node.count = child->parent->children_count - cumul_count;
155 if (rem_node.count <= 0)
156 return ret;
157 }
158
150 new_depth_mask &= ~(1 << (depth - 1)); 159 new_depth_mask &= ~(1 << (depth - 1));
151 ret += ipchain__fprintf_graph(fp, &rem_hits, depth, 160 ret += ipchain__fprintf_graph(fp, &rem_node, &rem_hits, depth,
152 new_depth_mask, 0, total_samples, 161 new_depth_mask, 0, total_samples,
153 remaining, left_margin); 162 left_margin);
154 } 163 }
155 164
156 return ret; 165 return ret;
157} 166}
158 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
159static size_t callchain__fprintf_graph(FILE *fp, struct rb_root *root, 187static size_t callchain__fprintf_graph(FILE *fp, struct rb_root *root,
160 u64 total_samples, int left_margin) 188 u64 total_samples, u64 parent_samples,
189 int left_margin)
161{ 190{
162 struct callchain_node *cnode; 191 struct callchain_node *cnode;
163 struct callchain_list *chain; 192 struct callchain_list *chain;
@@ -168,13 +197,8 @@ static size_t callchain__fprintf_graph(FILE *fp, struct rb_root *root,
168 int ret = 0; 197 int ret = 0;
169 char bf[1024]; 198 char bf[1024];
170 199
171 /*
172 * If have one single callchain root, don't bother printing
173 * its percentage (100 % in fractal mode and the same percentage
174 * than the hist in graph mode). This also avoid one level of column.
175 */
176 node = rb_first(root); 200 node = rb_first(root);
177 if (node && !rb_next(node)) { 201 if (node && !need_percent_display(node, parent_samples)) {
178 cnode = rb_entry(node, struct callchain_node, rb_node); 202 cnode = rb_entry(node, struct callchain_node, rb_node);
179 list_for_each_entry(chain, &cnode->val, list) { 203 list_for_each_entry(chain, &cnode->val, list) {
180 /* 204 /*
@@ -204,9 +228,15 @@ static size_t callchain__fprintf_graph(FILE *fp, struct rb_root *root,
204 root = &cnode->rb_root; 228 root = &cnode->rb_root;
205 } 229 }
206 230
231 if (callchain_param.mode == CHAIN_GRAPH_REL)
232 total_samples = parent_samples;
233
207 ret += __callchain__fprintf_graph(fp, root, total_samples, 234 ret += __callchain__fprintf_graph(fp, root, total_samples,
208 1, 1, left_margin); 235 1, 1, left_margin);
209 ret += fprintf(fp, "\n"); 236 if (ret) {
237 /* do not add a blank line if it printed nothing */
238 ret += fprintf(fp, "\n");
239 }
210 240
211 return ret; 241 return ret;
212} 242}
@@ -243,12 +273,11 @@ static size_t callchain__fprintf_flat(FILE *fp, struct rb_root *tree,
243 struct rb_node *rb_node = rb_first(tree); 273 struct rb_node *rb_node = rb_first(tree);
244 274
245 while (rb_node) { 275 while (rb_node) {
246 double percent;
247
248 chain = rb_entry(rb_node, struct callchain_node, rb_node); 276 chain = rb_entry(rb_node, struct callchain_node, rb_node);
249 percent = chain->hit * 100.0 / total_samples;
250 277
251 ret = percent_color_fprintf(fp, " %6.2f%%\n", percent); 278 ret += fprintf(fp, " ");
279 ret += callchain_node__fprintf_value(chain, fp, total_samples);
280 ret += fprintf(fp, "\n");
252 ret += __callchain__fprintf_flat(fp, chain, total_samples); 281 ret += __callchain__fprintf_flat(fp, chain, total_samples);
253 ret += fprintf(fp, "\n"); 282 ret += fprintf(fp, "\n");
254 if (++entries_printed == callchain_param.print_limit) 283 if (++entries_printed == callchain_param.print_limit)
@@ -260,24 +289,81 @@ static size_t callchain__fprintf_flat(FILE *fp, struct rb_root *tree,
260 return ret; 289 return ret;
261} 290}
262 291
292static size_t __callchain__fprintf_folded(FILE *fp, struct callchain_node *node)
293{
294 const char *sep = symbol_conf.field_sep ?: ";";
295 struct callchain_list *chain;
296 size_t ret = 0;
297 char bf[1024];
298 bool first;
299
300 if (!node)
301 return 0;
302
303 ret += __callchain__fprintf_folded(fp, node->parent);
304
305 first = (ret == 0);
306 list_for_each_entry(chain, &node->val, list) {
307 if (chain->ip >= PERF_CONTEXT_MAX)
308 continue;
309 ret += fprintf(fp, "%s%s", first ? "" : sep,
310 callchain_list__sym_name(chain,
311 bf, sizeof(bf), false));
312 first = false;
313 }
314
315 return ret;
316}
317
318static size_t callchain__fprintf_folded(FILE *fp, struct rb_root *tree,
319 u64 total_samples)
320{
321 size_t ret = 0;
322 u32 entries_printed = 0;
323 struct callchain_node *chain;
324 struct rb_node *rb_node = rb_first(tree);
325
326 while (rb_node) {
327
328 chain = rb_entry(rb_node, struct callchain_node, rb_node);
329
330 ret += callchain_node__fprintf_value(chain, fp, total_samples);
331 ret += fprintf(fp, " ");
332 ret += __callchain__fprintf_folded(fp, chain);
333 ret += fprintf(fp, "\n");
334 if (++entries_printed == callchain_param.print_limit)
335 break;
336
337 rb_node = rb_next(rb_node);
338 }
339
340 return ret;
341}
342
263static size_t hist_entry_callchain__fprintf(struct hist_entry *he, 343static size_t hist_entry_callchain__fprintf(struct hist_entry *he,
264 u64 total_samples, int left_margin, 344 u64 total_samples, int left_margin,
265 FILE *fp) 345 FILE *fp)
266{ 346{
347 u64 parent_samples = he->stat.period;
348
349 if (symbol_conf.cumulate_callchain)
350 parent_samples = he->stat_acc->period;
351
267 switch (callchain_param.mode) { 352 switch (callchain_param.mode) {
268 case CHAIN_GRAPH_REL: 353 case CHAIN_GRAPH_REL:
269 return callchain__fprintf_graph(fp, &he->sorted_chain, 354 return callchain__fprintf_graph(fp, &he->sorted_chain, total_samples,
270 symbol_conf.cumulate_callchain ? 355 parent_samples, left_margin);
271 he->stat_acc->period : he->stat.period,
272 left_margin);
273 break; 356 break;
274 case CHAIN_GRAPH_ABS: 357 case CHAIN_GRAPH_ABS:
275 return callchain__fprintf_graph(fp, &he->sorted_chain, total_samples, 358 return callchain__fprintf_graph(fp, &he->sorted_chain, total_samples,
276 left_margin); 359 parent_samples, left_margin);
277 break; 360 break;
278 case CHAIN_FLAT: 361 case CHAIN_FLAT:
279 return callchain__fprintf_flat(fp, &he->sorted_chain, total_samples); 362 return callchain__fprintf_flat(fp, &he->sorted_chain, total_samples);
280 break; 363 break;
364 case CHAIN_FOLDED:
365 return callchain__fprintf_folded(fp, &he->sorted_chain, total_samples);
366 break;
281 case CHAIN_NONE: 367 case CHAIN_NONE:
282 break; 368 break;
283 default: 369 default:
@@ -287,45 +373,66 @@ static size_t hist_entry_callchain__fprintf(struct hist_entry *he,
287 return 0; 373 return 0;
288} 374}
289 375
290static size_t hist_entry__callchain_fprintf(struct hist_entry *he, 376static int hist_entry__snprintf(struct hist_entry *he, struct perf_hpp *hpp)
291 struct hists *hists,
292 FILE *fp)
293{ 377{
294 int left_margin = 0; 378 const char *sep = symbol_conf.field_sep;
295 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;
296 383
297 if (field_order == NULL && (sort_order == NULL || 384 if (symbol_conf.exclude_other && !he->parent)
298 !prefixcmp(sort_order, "comm"))) { 385 return 0;
299 struct perf_hpp_fmt *fmt;
300 386
301 perf_hpp__for_each_format(fmt) { 387 hists__for_each_format(he->hists, fmt) {
302 if (!perf_hpp__is_sort_entry(fmt)) 388 if (perf_hpp__should_skip(fmt, he->hists))
303 continue; 389 continue;
304 390
305 /* must be 'comm' sort entry */ 391 /*
306 left_margin = fmt->width(fmt, NULL, hists_to_evsel(hists)); 392 * If there's no field_sep, we still need
307 left_margin -= thread__comm_len(he->thread); 393 * to display initial ' '.
308 break; 394 */
309 } 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);
310 } 408 }
311 return hist_entry_callchain__fprintf(he, total_period, left_margin, fp); 409
410 return hpp->buf - start;
312} 411}
313 412
314static 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)
315{ 417{
316 const char *sep = symbol_conf.field_sep; 418 const char *sep = symbol_conf.field_sep;
317 struct perf_hpp_fmt *fmt; 419 struct perf_hpp_fmt *fmt;
318 char *start = hpp->buf; 420 struct perf_hpp_list_node *fmt_node;
319 int ret; 421 char *buf = hpp->buf;
422 size_t size = hpp->size;
423 int ret, printed = 0;
320 bool first = true; 424 bool first = true;
321 425
322 if (symbol_conf.exclude_other && !he->parent) 426 if (symbol_conf.exclude_other && !he->parent)
323 return 0; 427 return 0;
324 428
325 perf_hpp__for_each_format(fmt) { 429 ret = scnprintf(hpp->buf, hpp->size, "%*s", he->depth * HIERARCHY_INDENT, "");
326 if (perf_hpp__should_skip(fmt)) 430 advance_hpp(hpp, ret);
327 continue;
328 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) {
329 /* 436 /*
330 * If there's no field_sep, we still need 437 * If there's no field_sep, we still need
331 * to display initial ' '. 438 * to display initial ' '.
@@ -341,10 +448,47 @@ static int hist_entry__snprintf(struct hist_entry *he, struct perf_hpp *hpp)
341 else 448 else
342 ret = fmt->entry(fmt, hpp, he); 449 ret = fmt->entry(fmt, hpp, he);
343 450
451 ret = hist_entry__snprintf_alignment(he, hpp, fmt, ret);
344 advance_hpp(hpp, ret); 452 advance_hpp(hpp, ret);
345 } 453 }
346 454
347 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;
348} 492}
349 493
350static int hist_entry__fprintf(struct hist_entry *he, size_t size, 494static int hist_entry__fprintf(struct hist_entry *he, size_t size,
@@ -356,24 +500,134 @@ static int hist_entry__fprintf(struct hist_entry *he, size_t size,
356 .buf = bf, 500 .buf = bf,
357 .size = size, 501 .size = size,
358 }; 502 };
503 u64 total_period = hists->stats.total_period;
359 504
360 if (size == 0 || size > bfsz) 505 if (size == 0 || size > bfsz)
361 size = hpp.size = bfsz; 506 size = hpp.size = bfsz;
362 507
508 if (symbol_conf.report_hierarchy)
509 return hist_entry__hierarchy_fprintf(he, &hpp, hists, fp);
510
363 hist_entry__snprintf(he, &hpp); 511 hist_entry__snprintf(he, &hpp);
364 512
365 ret = fprintf(fp, "%s\n", bf); 513 ret = fprintf(fp, "%s\n", bf);
366 514
367 if (symbol_conf.use_callchain) 515 if (symbol_conf.use_callchain)
368 ret += hist_entry__callchain_fprintf(he, hists, fp); 516 ret += hist_entry_callchain__fprintf(he, total_period, 0, fp);
369 517
370 return ret; 518 return ret;
371} 519}
372 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
373size_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,
374 int max_cols, float min_pcnt, FILE *fp) 627 int max_cols, float min_pcnt, FILE *fp)
375{ 628{
376 struct perf_hpp_fmt *fmt; 629 struct perf_hpp_fmt *fmt;
630 struct perf_hpp_list_node *fmt_node;
377 struct rb_node *nd; 631 struct rb_node *nd;
378 size_t ret = 0; 632 size_t ret = 0;
379 unsigned int width; 633 unsigned int width;
@@ -387,10 +641,11 @@ size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows,
387 bool first = true; 641 bool first = true;
388 size_t linesz; 642 size_t linesz;
389 char *line = NULL; 643 char *line = NULL;
644 unsigned indent;
390 645
391 init_rem_hits(); 646 init_rem_hits();
392 647
393 perf_hpp__for_each_format(fmt) 648 hists__for_each_format(hists, fmt)
394 perf_hpp__reset_width(fmt, hists); 649 perf_hpp__reset_width(fmt, hists);
395 650
396 if (symbol_conf.col_width_list_str) 651 if (symbol_conf.col_width_list_str)
@@ -401,8 +656,17 @@ size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows,
401 656
402 fprintf(fp, "# "); 657 fprintf(fp, "# ");
403 658
404 perf_hpp__for_each_format(fmt) { 659 if (symbol_conf.report_hierarchy) {
405 if (perf_hpp__should_skip(fmt)) 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) {
669 if (perf_hpp__should_skip(fmt, hists))
406 continue; 670 continue;
407 671
408 if (!first) 672 if (!first)
@@ -425,10 +689,10 @@ size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows,
425 689
426 fprintf(fp, "# "); 690 fprintf(fp, "# ");
427 691
428 perf_hpp__for_each_format(fmt) { 692 hists__for_each_format(hists, fmt) {
429 unsigned int i; 693 unsigned int i;
430 694
431 if (perf_hpp__should_skip(fmt)) 695 if (perf_hpp__should_skip(fmt, hists))
432 continue; 696 continue;
433 697
434 if (!first) 698 if (!first)
@@ -458,7 +722,9 @@ print_entries:
458 goto out; 722 goto out;
459 } 723 }
460 724
461 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)) {
462 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);
463 float percent; 729 float percent;
464 730
@@ -474,6 +740,20 @@ print_entries:
474 if (max_rows && ++nr_rows >= max_rows) 740 if (max_rows && ++nr_rows >= max_rows)
475 break; 741 break;
476 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
477 if (h->ms.map == NULL && verbose > 1) { 757 if (h->ms.map == NULL && verbose > 1) {
478 __map_groups__fprintf_maps(h->thread->mg, 758 __map_groups__fprintf_maps(h->thread->mg,
479 MAP__FUNCTION, fp); 759 MAP__FUNCTION, fp);
diff --git a/tools/perf/util/Build b/tools/perf/util/Build
index 591b3fe3ed49..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
@@ -6,24 +5,20 @@ libperf-y += config.o
6libperf-y += ctype.o 5libperf-y += ctype.o
7libperf-y += db-export.o 6libperf-y += db-export.o
8libperf-y += env.o 7libperf-y += env.o
9libperf-y += environment.o
10libperf-y += event.o 8libperf-y += event.o
11libperf-y += evlist.o 9libperf-y += evlist.o
12libperf-y += evsel.o 10libperf-y += evsel.o
13libperf-y += exec_cmd.o 11libperf-y += find_bit.o
14libperf-y += find_next_bit.o
15libperf-y += help.o
16libperf-y += kallsyms.o 12libperf-y += kallsyms.o
17libperf-y += levenshtein.o 13libperf-y += levenshtein.o
18libperf-y += llvm-utils.o 14libperf-y += llvm-utils.o
19libperf-y += parse-options.o
20libperf-y += parse-events.o 15libperf-y += parse-events.o
21libperf-y += perf_regs.o 16libperf-y += perf_regs.o
22libperf-y += path.o 17libperf-y += path.o
23libperf-y += rbtree.o 18libperf-y += rbtree.o
19libperf-y += libstring.o
24libperf-y += bitmap.o 20libperf-y += bitmap.o
25libperf-y += hweight.o 21libperf-y += hweight.o
26libperf-y += run-command.o
27libperf-y += quote.o 22libperf-y += quote.o
28libperf-y += strbuf.o 23libperf-y += strbuf.o
29libperf-y += string.o 24libperf-y += string.o
@@ -32,11 +27,9 @@ libperf-y += strfilter.o
32libperf-y += top.o 27libperf-y += top.o
33libperf-y += usage.o 28libperf-y += usage.o
34libperf-y += wrapper.o 29libperf-y += wrapper.o
35libperf-y += sigchain.o
36libperf-y += dso.o 30libperf-y += dso.o
37libperf-y += symbol.o 31libperf-y += symbol.o
38libperf-y += color.o 32libperf-y += color.o
39libperf-y += pager.o
40libperf-y += header.o 33libperf-y += header.o
41libperf-y += callchain.o 34libperf-y += callchain.o
42libperf-y += values.o 35libperf-y += values.o
@@ -86,8 +79,12 @@ libperf-$(CONFIG_AUXTRACE) += intel-pt.o
86libperf-$(CONFIG_AUXTRACE) += intel-bts.o 79libperf-$(CONFIG_AUXTRACE) += intel-bts.o
87libperf-y += parse-branch-options.o 80libperf-y += parse-branch-options.o
88libperf-y += parse-regs-options.o 81libperf-y += parse-regs-options.o
82libperf-y += term.o
83libperf-y += help-unknown-cmd.o
84libperf-y += mem-events.o
89 85
90libperf-$(CONFIG_LIBBPF) += bpf-loader.o 86libperf-$(CONFIG_LIBBPF) += bpf-loader.o
87libperf-$(CONFIG_BPF_PROLOGUE) += bpf-prologue.o
91libperf-$(CONFIG_LIBELF) += symbol-elf.o 88libperf-$(CONFIG_LIBELF) += symbol-elf.o
92libperf-$(CONFIG_LIBELF) += probe-file.o 89libperf-$(CONFIG_LIBELF) += probe-file.o
93libperf-$(CONFIG_LIBELF) += probe-event.o 90libperf-$(CONFIG_LIBELF) += probe-event.o
@@ -108,9 +105,17 @@ libperf-y += scripting-engines/
108 105
109libperf-$(CONFIG_ZLIB) += zlib.o 106libperf-$(CONFIG_ZLIB) += zlib.o
110libperf-$(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
111 115
112CFLAGS_config.o += -DETC_PERFCONFIG="BUILD_STR($(ETC_PERFCONFIG_SQ))" 116CFLAGS_config.o += -DETC_PERFCONFIG="BUILD_STR($(ETC_PERFCONFIG_SQ))"
113CFLAGS_exec_cmd.o += -DPERF_EXEC_PATH="BUILD_STR($(perfexecdir_SQ))" -DPREFIX="BUILD_STR($(prefix_SQ))" 117# avoid compiler warnings in 32-bit mode
118CFLAGS_genelf_debug.o += -Wno-packed
114 119
115$(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
116 $(call rule_mkdir) 121 $(call rule_mkdir)
@@ -136,8 +141,10 @@ CFLAGS_pmu-bison.o += -DYYENABLE_NLS=0 -DYYLTYPE_IS_TRIVIAL=0 -w
136$(OUTPUT)util/parse-events.o: $(OUTPUT)util/parse-events-flex.c $(OUTPUT)util/parse-events-bison.c 141$(OUTPUT)util/parse-events.o: $(OUTPUT)util/parse-events-flex.c $(OUTPUT)util/parse-events-bison.c
137$(OUTPUT)util/pmu.o: $(OUTPUT)util/pmu-flex.c $(OUTPUT)util/pmu-bison.c 142$(OUTPUT)util/pmu.o: $(OUTPUT)util/pmu-flex.c $(OUTPUT)util/pmu-bison.c
138 143
139CFLAGS_find_next_bit.o += -Wno-unused-parameter -DETC_PERFCONFIG="BUILD_STR($(ETC_PERFCONFIG_SQ))" 144CFLAGS_bitmap.o += -Wno-unused-parameter -DETC_PERFCONFIG="BUILD_STR($(ETC_PERFCONFIG_SQ))"
145CFLAGS_find_bit.o += -Wno-unused-parameter -DETC_PERFCONFIG="BUILD_STR($(ETC_PERFCONFIG_SQ))"
140CFLAGS_rbtree.o += -Wno-unused-parameter -DETC_PERFCONFIG="BUILD_STR($(ETC_PERFCONFIG_SQ))" 146CFLAGS_rbtree.o += -Wno-unused-parameter -DETC_PERFCONFIG="BUILD_STR($(ETC_PERFCONFIG_SQ))"
147CFLAGS_libstring.o += -Wno-unused-parameter -DETC_PERFCONFIG="BUILD_STR($(ETC_PERFCONFIG_SQ))"
141CFLAGS_hweight.o += -Wno-unused-parameter -DETC_PERFCONFIG="BUILD_STR($(ETC_PERFCONFIG_SQ))" 148CFLAGS_hweight.o += -Wno-unused-parameter -DETC_PERFCONFIG="BUILD_STR($(ETC_PERFCONFIG_SQ))"
142CFLAGS_parse-events.o += -Wno-redundant-decls 149CFLAGS_parse-events.o += -Wno-redundant-decls
143 150
@@ -145,7 +152,11 @@ $(OUTPUT)util/kallsyms.o: ../lib/symbol/kallsyms.c FORCE
145 $(call rule_mkdir) 152 $(call rule_mkdir)
146 $(call if_changed_dep,cc_o_c) 153 $(call if_changed_dep,cc_o_c)
147 154
148$(OUTPUT)util/find_next_bit.o: ../lib/util/find_next_bit.c FORCE 155$(OUTPUT)util/bitmap.o: ../lib/bitmap.c FORCE
156 $(call rule_mkdir)
157 $(call if_changed_dep,cc_o_c)
158
159$(OUTPUT)util/find_bit.o: ../lib/find_bit.c FORCE
149 $(call rule_mkdir) 160 $(call rule_mkdir)
150 $(call if_changed_dep,cc_o_c) 161 $(call if_changed_dep,cc_o_c)
151 162
@@ -153,6 +164,10 @@ $(OUTPUT)util/rbtree.o: ../lib/rbtree.c FORCE
153 $(call rule_mkdir) 164 $(call rule_mkdir)
154 $(call if_changed_dep,cc_o_c) 165 $(call if_changed_dep,cc_o_c)
155 166
167$(OUTPUT)util/libstring.o: ../lib/string.c FORCE
168 $(call rule_mkdir)
169 $(call if_changed_dep,cc_o_c)
170
156$(OUTPUT)util/hweight.o: ../lib/hweight.c FORCE 171$(OUTPUT)util/hweight.o: ../lib/hweight.c FORCE
157 $(call rule_mkdir) 172 $(call rule_mkdir)
158 $(call if_changed_dep,cc_o_c) 173 $(call if_changed_dep,cc_o_c)
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.c b/tools/perf/util/annotate.c
index 0fc8d7a2fea5..b795b6994144 100644
--- a/tools/perf/util/annotate.c
+++ b/tools/perf/util/annotate.c
@@ -65,6 +65,11 @@ static int call__parse(struct ins_operands *ops)
65 65
66 name++; 66 name++;
67 67
68#ifdef __arm__
69 if (strchr(name, '+'))
70 return -1;
71#endif
72
68 tok = strchr(name, '>'); 73 tok = strchr(name, '>');
69 if (tok == NULL) 74 if (tok == NULL)
70 return -1; 75 return -1;
@@ -246,7 +251,11 @@ static int mov__parse(struct ins_operands *ops)
246 return -1; 251 return -1;
247 252
248 target = ++s; 253 target = ++s;
254#ifdef __arm__
255 comment = strchr(s, ';');
256#else
249 comment = strchr(s, '#'); 257 comment = strchr(s, '#');
258#endif
250 259
251 if (comment != NULL) 260 if (comment != NULL)
252 s = comment - 1; 261 s = comment - 1;
@@ -354,6 +363,20 @@ static struct ins instructions[] = {
354 { .name = "addq", .ops = &mov_ops, }, 363 { .name = "addq", .ops = &mov_ops, },
355 { .name = "addw", .ops = &mov_ops, }, 364 { .name = "addw", .ops = &mov_ops, },
356 { .name = "and", .ops = &mov_ops, }, 365 { .name = "and", .ops = &mov_ops, },
366#ifdef __arm__
367 { .name = "b", .ops = &jump_ops, }, // might also be a call
368 { .name = "bcc", .ops = &jump_ops, },
369 { .name = "bcs", .ops = &jump_ops, },
370 { .name = "beq", .ops = &jump_ops, },
371 { .name = "bge", .ops = &jump_ops, },
372 { .name = "bgt", .ops = &jump_ops, },
373 { .name = "bhi", .ops = &jump_ops, },
374 { .name = "bl", .ops = &call_ops, },
375 { .name = "blt", .ops = &jump_ops, },
376 { .name = "bls", .ops = &jump_ops, },
377 { .name = "blx", .ops = &call_ops, },
378 { .name = "bne", .ops = &jump_ops, },
379#endif
357 { .name = "bts", .ops = &mov_ops, }, 380 { .name = "bts", .ops = &mov_ops, },
358 { .name = "call", .ops = &call_ops, }, 381 { .name = "call", .ops = &call_ops, },
359 { .name = "callq", .ops = &call_ops, }, 382 { .name = "callq", .ops = &call_ops, },
@@ -1084,6 +1107,7 @@ int symbol__annotate(struct symbol *sym, struct map *map, size_t privsize)
1084 struct kcore_extract kce; 1107 struct kcore_extract kce;
1085 bool delete_extract = false; 1108 bool delete_extract = false;
1086 int lineno = 0; 1109 int lineno = 0;
1110 int nline;
1087 1111
1088 if (filename) 1112 if (filename)
1089 symbol__join_symfs(symfs_filename, filename); 1113 symbol__join_symfs(symfs_filename, filename);
@@ -1179,6 +1203,9 @@ fallback:
1179 1203
1180 ret = decompress_to_file(m.ext, symfs_filename, fd); 1204 ret = decompress_to_file(m.ext, symfs_filename, fd);
1181 1205
1206 if (ret)
1207 pr_err("Cannot decompress %s %s\n", m.ext, symfs_filename);
1208
1182 free(m.ext); 1209 free(m.ext);
1183 close(fd); 1210 close(fd);
1184 1211
@@ -1204,13 +1231,25 @@ fallback:
1204 pr_debug("Executing: %s\n", command); 1231 pr_debug("Executing: %s\n", command);
1205 1232
1206 file = popen(command, "r"); 1233 file = popen(command, "r");
1207 if (!file) 1234 if (!file) {
1235 pr_err("Failure running %s\n", command);
1236 /*
1237 * If we were using debug info should retry with
1238 * original binary.
1239 */
1208 goto out_remove_tmp; 1240 goto out_remove_tmp;
1241 }
1209 1242
1210 while (!feof(file)) 1243 nline = 0;
1244 while (!feof(file)) {
1211 if (symbol__parse_objdump_line(sym, map, file, privsize, 1245 if (symbol__parse_objdump_line(sym, map, file, privsize,
1212 &lineno) < 0) 1246 &lineno) < 0)
1213 break; 1247 break;
1248 nline++;
1249 }
1250
1251 if (nline == 0)
1252 pr_err("No output from %s\n", command);
1214 1253
1215 /* 1254 /*
1216 * kallsyms does not have symbol sizes so there may a nop at the end. 1255 * kallsyms does not have symbol sizes so there may a nop at the end.
@@ -1604,6 +1643,7 @@ int symbol__tty_annotate(struct symbol *sym, struct map *map,
1604 len = symbol__size(sym); 1643 len = symbol__size(sym);
1605 1644
1606 if (print_lines) { 1645 if (print_lines) {
1646 srcline_full_filename = full_paths;
1607 symbol__get_source_line(sym, map, evsel, &source_line, len); 1647 symbol__get_source_line(sym, map, evsel, &source_line, len);
1608 print_summary(&source_line, dso->long_name); 1648 print_summary(&source_line, dso->long_name);
1609 } 1649 }
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 7f10430af39c..ec164fe70718 100644
--- a/tools/perf/util/auxtrace.c
+++ b/tools/perf/util/auxtrace.c
@@ -45,7 +45,7 @@
45#include "event.h" 45#include "event.h"
46#include "session.h" 46#include "session.h"
47#include "debug.h" 47#include "debug.h"
48#include "parse-options.h" 48#include <subcmd/parse-options.h>
49 49
50#include "intel-pt.h" 50#include "intel-pt.h"
51#include "intel-bts.h" 51#include "intel-bts.h"
@@ -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/bitmap.c b/tools/perf/util/bitmap.c
deleted file mode 100644
index 0a1adc1111fd..000000000000
--- a/tools/perf/util/bitmap.c
+++ /dev/null
@@ -1,31 +0,0 @@
1/*
2 * From lib/bitmap.c
3 * Helper functions for bitmap.h.
4 *
5 * This source code is licensed under the GNU General Public License,
6 * Version 2. See the file COPYING for more details.
7 */
8#include <linux/bitmap.h>
9
10int __bitmap_weight(const unsigned long *bitmap, int bits)
11{
12 int k, w = 0, lim = bits/BITS_PER_LONG;
13
14 for (k = 0; k < lim; k++)
15 w += hweight_long(bitmap[k]);
16
17 if (bits % BITS_PER_LONG)
18 w += hweight_long(bitmap[k] & BITMAP_LAST_WORD_MASK(bits));
19
20 return w;
21}
22
23void __bitmap_or(unsigned long *dst, const unsigned long *bitmap1,
24 const unsigned long *bitmap2, int bits)
25{
26 int k;
27 int nr = BITS_TO_LONGS(bits);
28
29 for (k = 0; k < nr; k++)
30 dst[k] = bitmap1[k] | bitmap2[k];
31}
diff --git a/tools/perf/util/bpf-loader.c b/tools/perf/util/bpf-loader.c
index ba6f7526b282..0967ce601931 100644
--- a/tools/perf/util/bpf-loader.c
+++ b/tools/perf/util/bpf-loader.c
@@ -5,13 +5,19 @@
5 * Copyright (C) 2015 Huawei Inc. 5 * Copyright (C) 2015 Huawei Inc.
6 */ 6 */
7 7
8#include <linux/bpf.h>
8#include <bpf/libbpf.h> 9#include <bpf/libbpf.h>
10#include <bpf/bpf.h>
9#include <linux/err.h> 11#include <linux/err.h>
12#include <linux/string.h>
10#include "perf.h" 13#include "perf.h"
11#include "debug.h" 14#include "debug.h"
12#include "bpf-loader.h" 15#include "bpf-loader.h"
16#include "bpf-prologue.h"
17#include "llvm-utils.h"
13#include "probe-event.h" 18#include "probe-event.h"
14#include "probe-finder.h" // for MAX_PROBES 19#include "probe-finder.h" // for MAX_PROBES
20#include "parse-events.h"
15#include "llvm-utils.h" 21#include "llvm-utils.h"
16 22
17#define DEFINE_PRINT_FN(name, level) \ 23#define DEFINE_PRINT_FN(name, level) \
@@ -26,18 +32,44 @@ static int libbpf_##name(const char *fmt, ...) \
26 return ret; \ 32 return ret; \
27} 33}
28 34
29DEFINE_PRINT_FN(warning, 0) 35DEFINE_PRINT_FN(warning, 1)
30DEFINE_PRINT_FN(info, 0) 36DEFINE_PRINT_FN(info, 1)
31DEFINE_PRINT_FN(debug, 1) 37DEFINE_PRINT_FN(debug, 1)
32 38
33struct bpf_prog_priv { 39struct bpf_prog_priv {
34 struct perf_probe_event pev; 40 struct perf_probe_event pev;
41 bool need_prologue;
42 struct bpf_insn *insns_buf;
43 int nr_types;
44 int *type_mapping;
35}; 45};
36 46
47static bool libbpf_initialized;
48
49struct bpf_object *
50bpf__prepare_load_buffer(void *obj_buf, size_t obj_buf_sz, const char *name)
51{
52 struct bpf_object *obj;
53
54 if (!libbpf_initialized) {
55 libbpf_set_print(libbpf_warning,
56 libbpf_info,
57 libbpf_debug);
58 libbpf_initialized = true;
59 }
60
61 obj = bpf_object__open_buffer(obj_buf, obj_buf_sz, name);
62 if (IS_ERR(obj)) {
63 pr_debug("bpf: failed to load buffer\n");
64 return ERR_PTR(-EINVAL);
65 }
66
67 return obj;
68}
69
37struct bpf_object *bpf__prepare_load(const char *filename, bool source) 70struct bpf_object *bpf__prepare_load(const char *filename, bool source)
38{ 71{
39 struct bpf_object *obj; 72 struct bpf_object *obj;
40 static bool libbpf_initialized;
41 73
42 if (!libbpf_initialized) { 74 if (!libbpf_initialized) {
43 libbpf_set_print(libbpf_warning, 75 libbpf_set_print(libbpf_warning,
@@ -53,15 +85,15 @@ struct bpf_object *bpf__prepare_load(const char *filename, bool source)
53 85
54 err = llvm__compile_bpf(filename, &obj_buf, &obj_buf_sz); 86 err = llvm__compile_bpf(filename, &obj_buf, &obj_buf_sz);
55 if (err) 87 if (err)
56 return ERR_PTR(err); 88 return ERR_PTR(-BPF_LOADER_ERRNO__COMPILE);
57 obj = bpf_object__open_buffer(obj_buf, obj_buf_sz, filename); 89 obj = bpf_object__open_buffer(obj_buf, obj_buf_sz, filename);
58 free(obj_buf); 90 free(obj_buf);
59 } else 91 } else
60 obj = bpf_object__open(filename); 92 obj = bpf_object__open(filename);
61 93
62 if (!obj) { 94 if (IS_ERR(obj)) {
63 pr_debug("bpf: failed to load %s\n", filename); 95 pr_debug("bpf: failed to load %s\n", filename);
64 return ERR_PTR(-EINVAL); 96 return obj;
65 } 97 }
66 98
67 return obj; 99 return obj;
@@ -78,16 +110,184 @@ void bpf__clear(void)
78} 110}
79 111
80static void 112static void
81bpf_prog_priv__clear(struct bpf_program *prog __maybe_unused, 113clear_prog_priv(struct bpf_program *prog __maybe_unused,
82 void *_priv) 114 void *_priv)
83{ 115{
84 struct bpf_prog_priv *priv = _priv; 116 struct bpf_prog_priv *priv = _priv;
85 117
86 cleanup_perf_probe_events(&priv->pev, 1); 118 cleanup_perf_probe_events(&priv->pev, 1);
119 zfree(&priv->insns_buf);
120 zfree(&priv->type_mapping);
87 free(priv); 121 free(priv);
88} 122}
89 123
90static int 124static int
125prog_config__exec(const char *value, struct perf_probe_event *pev)
126{
127 pev->uprobes = true;
128 pev->target = strdup(value);
129 if (!pev->target)
130 return -ENOMEM;
131 return 0;
132}
133
134static int
135prog_config__module(const char *value, struct perf_probe_event *pev)
136{
137 pev->uprobes = false;
138 pev->target = strdup(value);
139 if (!pev->target)
140 return -ENOMEM;
141 return 0;
142}
143
144static int
145prog_config__bool(const char *value, bool *pbool, bool invert)
146{
147 int err;
148 bool bool_value;
149
150 if (!pbool)
151 return -EINVAL;
152
153 err = strtobool(value, &bool_value);
154 if (err)
155 return err;
156
157 *pbool = invert ? !bool_value : bool_value;
158 return 0;
159}
160
161static int
162prog_config__inlines(const char *value,
163 struct perf_probe_event *pev __maybe_unused)
164{
165 return prog_config__bool(value, &probe_conf.no_inlines, true);
166}
167
168static int
169prog_config__force(const char *value,
170 struct perf_probe_event *pev __maybe_unused)
171{
172 return prog_config__bool(value, &probe_conf.force_add, false);
173}
174
175static struct {
176 const char *key;
177 const char *usage;
178 const char *desc;
179 int (*func)(const char *, struct perf_probe_event *);
180} bpf_prog_config_terms[] = {
181 {
182 .key = "exec",
183 .usage = "exec=<full path of file>",
184 .desc = "Set uprobe target",
185 .func = prog_config__exec,
186 },
187 {
188 .key = "module",
189 .usage = "module=<module name> ",
190 .desc = "Set kprobe module",
191 .func = prog_config__module,
192 },
193 {
194 .key = "inlines",
195 .usage = "inlines=[yes|no] ",
196 .desc = "Probe at inline symbol",
197 .func = prog_config__inlines,
198 },
199 {
200 .key = "force",
201 .usage = "force=[yes|no] ",
202 .desc = "Forcibly add events with existing name",
203 .func = prog_config__force,
204 },
205};
206
207static int
208do_prog_config(const char *key, const char *value,
209 struct perf_probe_event *pev)
210{
211 unsigned int i;
212
213 pr_debug("config bpf program: %s=%s\n", key, value);
214 for (i = 0; i < ARRAY_SIZE(bpf_prog_config_terms); i++)
215 if (strcmp(key, bpf_prog_config_terms[i].key) == 0)
216 return bpf_prog_config_terms[i].func(value, pev);
217
218 pr_debug("BPF: ERROR: invalid program config option: %s=%s\n",
219 key, value);
220
221 pr_debug("\nHint: Valid options are:\n");
222 for (i = 0; i < ARRAY_SIZE(bpf_prog_config_terms); i++)
223 pr_debug("\t%s:\t%s\n", bpf_prog_config_terms[i].usage,
224 bpf_prog_config_terms[i].desc);
225 pr_debug("\n");
226
227 return -BPF_LOADER_ERRNO__PROGCONF_TERM;
228}
229
230static const char *
231parse_prog_config_kvpair(const char *config_str, struct perf_probe_event *pev)
232{
233 char *text = strdup(config_str);
234 char *sep, *line;
235 const char *main_str = NULL;
236 int err = 0;
237
238 if (!text) {
239 pr_debug("No enough memory: dup config_str failed\n");
240 return ERR_PTR(-ENOMEM);
241 }
242
243 line = text;
244 while ((sep = strchr(line, ';'))) {
245 char *equ;
246
247 *sep = '\0';
248 equ = strchr(line, '=');
249 if (!equ) {
250 pr_warning("WARNING: invalid config in BPF object: %s\n",
251 line);
252 pr_warning("\tShould be 'key=value'.\n");
253 goto nextline;
254 }
255 *equ = '\0';
256
257 err = do_prog_config(line, equ + 1, pev);
258 if (err)
259 break;
260nextline:
261 line = sep + 1;
262 }
263
264 if (!err)
265 main_str = config_str + (line - text);
266 free(text);
267
268 return err ? ERR_PTR(err) : main_str;
269}
270
271static int
272parse_prog_config(const char *config_str, struct perf_probe_event *pev)
273{
274 int err;
275 const char *main_str = parse_prog_config_kvpair(config_str, pev);
276
277 if (IS_ERR(main_str))
278 return PTR_ERR(main_str);
279
280 err = parse_perf_probe_command(main_str, pev);
281 if (err < 0) {
282 pr_debug("bpf: '%s' is not a valid config string\n",
283 config_str);
284 /* parse failed, don't need clear pev. */
285 return -BPF_LOADER_ERRNO__CONFIG;
286 }
287 return 0;
288}
289
290static int
91config_bpf_program(struct bpf_program *prog) 291config_bpf_program(struct bpf_program *prog)
92{ 292{
93 struct perf_probe_event *pev = NULL; 293 struct perf_probe_event *pev = NULL;
@@ -95,10 +295,14 @@ config_bpf_program(struct bpf_program *prog)
95 const char *config_str; 295 const char *config_str;
96 int err; 296 int err;
97 297
298 /* Initialize per-program probing setting */
299 probe_conf.no_inlines = false;
300 probe_conf.force_add = false;
301
98 config_str = bpf_program__title(prog, false); 302 config_str = bpf_program__title(prog, false);
99 if (!config_str) { 303 if (IS_ERR(config_str)) {
100 pr_debug("bpf: unable to get title for program\n"); 304 pr_debug("bpf: unable to get title for program\n");
101 return -EINVAL; 305 return PTR_ERR(config_str);
102 } 306 }
103 307
104 priv = calloc(sizeof(*priv), 1); 308 priv = calloc(sizeof(*priv), 1);
@@ -109,18 +313,14 @@ config_bpf_program(struct bpf_program *prog)
109 pev = &priv->pev; 313 pev = &priv->pev;
110 314
111 pr_debug("bpf: config program '%s'\n", config_str); 315 pr_debug("bpf: config program '%s'\n", config_str);
112 err = parse_perf_probe_command(config_str, pev); 316 err = parse_prog_config(config_str, pev);
113 if (err < 0) { 317 if (err)
114 pr_debug("bpf: '%s' is not a valid config string\n",
115 config_str);
116 err = -EINVAL;
117 goto errout; 318 goto errout;
118 }
119 319
120 if (pev->group && strcmp(pev->group, PERF_BPF_PROBE_GROUP)) { 320 if (pev->group && strcmp(pev->group, PERF_BPF_PROBE_GROUP)) {
121 pr_debug("bpf: '%s': group for event is set and not '%s'.\n", 321 pr_debug("bpf: '%s': group for event is set and not '%s'.\n",
122 config_str, PERF_BPF_PROBE_GROUP); 322 config_str, PERF_BPF_PROBE_GROUP);
123 err = -EINVAL; 323 err = -BPF_LOADER_ERRNO__GROUP;
124 goto errout; 324 goto errout;
125 } else if (!pev->group) 325 } else if (!pev->group)
126 pev->group = strdup(PERF_BPF_PROBE_GROUP); 326 pev->group = strdup(PERF_BPF_PROBE_GROUP);
@@ -132,14 +332,14 @@ config_bpf_program(struct bpf_program *prog)
132 } 332 }
133 333
134 if (!pev->event) { 334 if (!pev->event) {
135 pr_debug("bpf: '%s': event name is missing\n", 335 pr_debug("bpf: '%s': event name is missing. Section name should be 'key=value'\n",
136 config_str); 336 config_str);
137 err = -EINVAL; 337 err = -BPF_LOADER_ERRNO__EVENTNAME;
138 goto errout; 338 goto errout;
139 } 339 }
140 pr_debug("bpf: config '%s' is ok\n", config_str); 340 pr_debug("bpf: config '%s' is ok\n", config_str);
141 341
142 err = bpf_program__set_private(prog, priv, bpf_prog_priv__clear); 342 err = bpf_program__set_private(prog, priv, clear_prog_priv);
143 if (err) { 343 if (err) {
144 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);
145 goto errout; 345 goto errout;
@@ -175,6 +375,220 @@ static int bpf__prepare_probe(void)
175 return err; 375 return err;
176} 376}
177 377
378static int
379preproc_gen_prologue(struct bpf_program *prog, int n,
380 struct bpf_insn *orig_insns, int orig_insns_cnt,
381 struct bpf_prog_prep_result *res)
382{
383 struct probe_trace_event *tev;
384 struct perf_probe_event *pev;
385 struct bpf_prog_priv *priv;
386 struct bpf_insn *buf;
387 size_t prologue_cnt = 0;
388 int i, err;
389
390 err = bpf_program__get_private(prog, (void **)&priv);
391 if (err || !priv)
392 goto errout;
393
394 pev = &priv->pev;
395
396 if (n < 0 || n >= priv->nr_types)
397 goto errout;
398
399 /* Find a tev belongs to that type */
400 for (i = 0; i < pev->ntevs; i++) {
401 if (priv->type_mapping[i] == n)
402 break;
403 }
404
405 if (i >= pev->ntevs) {
406 pr_debug("Internal error: prologue type %d not found\n", n);
407 return -BPF_LOADER_ERRNO__PROLOGUE;
408 }
409
410 tev = &pev->tevs[i];
411
412 buf = priv->insns_buf;
413 err = bpf__gen_prologue(tev->args, tev->nargs,
414 buf, &prologue_cnt,
415 BPF_MAXINSNS - orig_insns_cnt);
416 if (err) {
417 const char *title;
418
419 title = bpf_program__title(prog, false);
420 if (!title)
421 title = "[unknown]";
422
423 pr_debug("Failed to generate prologue for program %s\n",
424 title);
425 return err;
426 }
427
428 memcpy(&buf[prologue_cnt], orig_insns,
429 sizeof(struct bpf_insn) * orig_insns_cnt);
430
431 res->new_insn_ptr = buf;
432 res->new_insn_cnt = prologue_cnt + orig_insns_cnt;
433 res->pfd = NULL;
434 return 0;
435
436errout:
437 pr_debug("Internal error in preproc_gen_prologue\n");
438 return -BPF_LOADER_ERRNO__PROLOGUE;
439}
440
441/*
442 * compare_tev_args is reflexive, transitive and antisymmetric.
443 * I can proof it but this margin is too narrow to contain.
444 */
445static int compare_tev_args(const void *ptev1, const void *ptev2)
446{
447 int i, ret;
448 const struct probe_trace_event *tev1 =
449 *(const struct probe_trace_event **)ptev1;
450 const struct probe_trace_event *tev2 =
451 *(const struct probe_trace_event **)ptev2;
452
453 ret = tev2->nargs - tev1->nargs;
454 if (ret)
455 return ret;
456
457 for (i = 0; i < tev1->nargs; i++) {
458 struct probe_trace_arg *arg1, *arg2;
459 struct probe_trace_arg_ref *ref1, *ref2;
460
461 arg1 = &tev1->args[i];
462 arg2 = &tev2->args[i];
463
464 ret = strcmp(arg1->value, arg2->value);
465 if (ret)
466 return ret;
467
468 ref1 = arg1->ref;
469 ref2 = arg2->ref;
470
471 while (ref1 && ref2) {
472 ret = ref2->offset - ref1->offset;
473 if (ret)
474 return ret;
475
476 ref1 = ref1->next;
477 ref2 = ref2->next;
478 }
479
480 if (ref1 || ref2)
481 return ref2 ? 1 : -1;
482 }
483
484 return 0;
485}
486
487/*
488 * Assign a type number to each tevs in a pev.
489 * mapping is an array with same slots as tevs in that pev.
490 * nr_types will be set to number of types.
491 */
492static int map_prologue(struct perf_probe_event *pev, int *mapping,
493 int *nr_types)
494{
495 int i, type = 0;
496 struct probe_trace_event **ptevs;
497
498 size_t array_sz = sizeof(*ptevs) * pev->ntevs;
499
500 ptevs = malloc(array_sz);
501 if (!ptevs) {
502 pr_debug("No ehough memory: alloc ptevs failed\n");
503 return -ENOMEM;
504 }
505
506 pr_debug("In map_prologue, ntevs=%d\n", pev->ntevs);
507 for (i = 0; i < pev->ntevs; i++)
508 ptevs[i] = &pev->tevs[i];
509
510 qsort(ptevs, pev->ntevs, sizeof(*ptevs),
511 compare_tev_args);
512
513 for (i = 0; i < pev->ntevs; i++) {
514 int n;
515
516 n = ptevs[i] - pev->tevs;
517 if (i == 0) {
518 mapping[n] = type;
519 pr_debug("mapping[%d]=%d\n", n, type);
520 continue;
521 }
522
523 if (compare_tev_args(ptevs + i, ptevs + i - 1) == 0)
524 mapping[n] = type;
525 else
526 mapping[n] = ++type;
527
528 pr_debug("mapping[%d]=%d\n", n, mapping[n]);
529 }
530 free(ptevs);
531 *nr_types = type + 1;
532
533 return 0;
534}
535
536static int hook_load_preprocessor(struct bpf_program *prog)
537{
538 struct perf_probe_event *pev;
539 struct bpf_prog_priv *priv;
540 bool need_prologue = false;
541 int err, i;
542
543 err = bpf_program__get_private(prog, (void **)&priv);
544 if (err || !priv) {
545 pr_debug("Internal error when hook preprocessor\n");
546 return -BPF_LOADER_ERRNO__INTERNAL;
547 }
548
549 pev = &priv->pev;
550 for (i = 0; i < pev->ntevs; i++) {
551 struct probe_trace_event *tev = &pev->tevs[i];
552
553 if (tev->nargs > 0) {
554 need_prologue = true;
555 break;
556 }
557 }
558
559 /*
560 * Since all tevs don't have argument, we don't need generate
561 * prologue.
562 */
563 if (!need_prologue) {
564 priv->need_prologue = false;
565 return 0;
566 }
567
568 priv->need_prologue = true;
569 priv->insns_buf = malloc(sizeof(struct bpf_insn) * BPF_MAXINSNS);
570 if (!priv->insns_buf) {
571 pr_debug("No enough memory: alloc insns_buf failed\n");
572 return -ENOMEM;
573 }
574
575 priv->type_mapping = malloc(sizeof(int) * pev->ntevs);
576 if (!priv->type_mapping) {
577 pr_debug("No enough memory: alloc type_mapping failed\n");
578 return -ENOMEM;
579 }
580 memset(priv->type_mapping, -1,
581 sizeof(int) * pev->ntevs);
582
583 err = map_prologue(pev, priv->type_mapping, &priv->nr_types);
584 if (err)
585 return err;
586
587 err = bpf_program__set_prep(prog, priv->nr_types,
588 preproc_gen_prologue);
589 return err;
590}
591
178int bpf__probe(struct bpf_object *obj) 592int bpf__probe(struct bpf_object *obj)
179{ 593{
180 int err = 0; 594 int err = 0;
@@ -209,6 +623,18 @@ int bpf__probe(struct bpf_object *obj)
209 pr_debug("bpf_probe: failed to apply perf probe events"); 623 pr_debug("bpf_probe: failed to apply perf probe events");
210 goto out; 624 goto out;
211 } 625 }
626
627 /*
628 * After probing, let's consider prologue, which
629 * adds program fetcher to BPF programs.
630 *
631 * hook_load_preprocessorr() hooks pre-processor
632 * to bpf_program, let it generate prologue
633 * dynamically during loading.
634 */
635 err = hook_load_preprocessor(prog);
636 if (err)
637 goto out;
212 } 638 }
213out: 639out:
214 return err < 0 ? err : 0; 640 return err < 0 ? err : 0;
@@ -285,14 +711,21 @@ int bpf__foreach_tev(struct bpf_object *obj,
285 (void **)&priv); 711 (void **)&priv);
286 if (err || !priv) { 712 if (err || !priv) {
287 pr_debug("bpf: failed to get private field\n"); 713 pr_debug("bpf: failed to get private field\n");
288 return -EINVAL; 714 return -BPF_LOADER_ERRNO__INTERNAL;
289 } 715 }
290 716
291 pev = &priv->pev; 717 pev = &priv->pev;
292 for (i = 0; i < pev->ntevs; i++) { 718 for (i = 0; i < pev->ntevs; i++) {
293 tev = &pev->tevs[i]; 719 tev = &pev->tevs[i];
294 720
295 fd = bpf_program__fd(prog); 721 if (priv->need_prologue) {
722 int type = priv->type_mapping[i];
723
724 fd = bpf_program__nth_fd(prog, type);
725 } else {
726 fd = bpf_program__fd(prog);
727 }
728
296 if (fd < 0) { 729 if (fd < 0) {
297 pr_debug("bpf: failed to get file descriptor\n"); 730 pr_debug("bpf: failed to get file descriptor\n");
298 return fd; 731 return fd;
@@ -308,13 +741,751 @@ int bpf__foreach_tev(struct bpf_object *obj,
308 return 0; 741 return 0;
309} 742}
310 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
1420#define ERRNO_OFFSET(e) ((e) - __BPF_LOADER_ERRNO__START)
1421#define ERRCODE_OFFSET(c) ERRNO_OFFSET(BPF_LOADER_ERRNO__##c)
1422#define NR_ERRNO (__BPF_LOADER_ERRNO__END - __BPF_LOADER_ERRNO__START)
1423
1424static const char *bpf_loader_strerror_table[NR_ERRNO] = {
1425 [ERRCODE_OFFSET(CONFIG)] = "Invalid config string",
1426 [ERRCODE_OFFSET(GROUP)] = "Invalid group name",
1427 [ERRCODE_OFFSET(EVENTNAME)] = "No event name found in config string",
1428 [ERRCODE_OFFSET(INTERNAL)] = "BPF loader internal error",
1429 [ERRCODE_OFFSET(COMPILE)] = "Error when compiling BPF scriptlet",
1430 [ERRCODE_OFFSET(PROGCONF_TERM)] = "Invalid program config term in config string",
1431 [ERRCODE_OFFSET(PROLOGUE)] = "Failed to generate prologue",
1432 [ERRCODE_OFFSET(PROLOGUE2BIG)] = "Prologue too big for program",
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",
1448};
1449
1450static int
1451bpf_loader_strerror(int err, char *buf, size_t size)
1452{
1453 char sbuf[STRERR_BUFSIZE];
1454 const char *msg;
1455
1456 if (!buf || !size)
1457 return -1;
1458
1459 err = err > 0 ? err : -err;
1460
1461 if (err >= __LIBBPF_ERRNO__START)
1462 return libbpf_strerror(err, buf, size);
1463
1464 if (err >= __BPF_LOADER_ERRNO__START && err < __BPF_LOADER_ERRNO__END) {
1465 msg = bpf_loader_strerror_table[ERRNO_OFFSET(err)];
1466 snprintf(buf, size, "%s", msg);
1467 buf[size - 1] = '\0';
1468 return 0;
1469 }
1470
1471 if (err >= __BPF_LOADER_ERRNO__END)
1472 snprintf(buf, size, "Unknown bpf loader error %d", err);
1473 else
1474 snprintf(buf, size, "%s",
1475 strerror_r(err, sbuf, sizeof(sbuf)));
1476
1477 buf[size - 1] = '\0';
1478 return -1;
1479}
1480
311#define bpf__strerror_head(err, buf, size) \ 1481#define bpf__strerror_head(err, buf, size) \
312 char sbuf[STRERR_BUFSIZE], *emsg;\ 1482 char sbuf[STRERR_BUFSIZE], *emsg;\
313 if (!size)\ 1483 if (!size)\
314 return 0;\ 1484 return 0;\
315 if (err < 0)\ 1485 if (err < 0)\
316 err = -err;\ 1486 err = -err;\
317 emsg = strerror_r(err, sbuf, sizeof(sbuf));\ 1487 bpf_loader_strerror(err, sbuf, sizeof(sbuf));\
1488 emsg = sbuf;\
318 switch (err) {\ 1489 switch (err) {\
319 default:\ 1490 default:\
320 scnprintf(buf, size, "%s", emsg);\ 1491 scnprintf(buf, size, "%s", emsg);\
@@ -330,23 +1501,92 @@ int bpf__foreach_tev(struct bpf_object *obj,
330 }\ 1501 }\
331 buf[size - 1] = '\0'; 1502 buf[size - 1] = '\0';
332 1503
1504int bpf__strerror_prepare_load(const char *filename, bool source,
1505 int err, char *buf, size_t size)
1506{
1507 size_t n;
1508 int ret;
1509
1510 n = snprintf(buf, size, "Failed to load %s%s: ",
1511 filename, source ? " from source" : "");
1512 if (n >= size) {
1513 buf[size - 1] = '\0';
1514 return 0;
1515 }
1516 buf += n;
1517 size -= n;
1518
1519 ret = bpf_loader_strerror(err, buf, size);
1520 buf[size - 1] = '\0';
1521 return ret;
1522}
1523
333int bpf__strerror_probe(struct bpf_object *obj __maybe_unused, 1524int bpf__strerror_probe(struct bpf_object *obj __maybe_unused,
334 int err, char *buf, size_t size) 1525 int err, char *buf, size_t size)
335{ 1526{
336 bpf__strerror_head(err, buf, size); 1527 bpf__strerror_head(err, buf, size);
337 bpf__strerror_entry(EEXIST, "Probe point exist. Try use 'perf probe -d \"*\"'"); 1528 case BPF_LOADER_ERRNO__PROGCONF_TERM: {
338 bpf__strerror_entry(EPERM, "You need to be root, and /proc/sys/kernel/kptr_restrict should be 0\n"); 1529 scnprintf(buf, size, "%s (add -v to see detail)", emsg);
339 bpf__strerror_entry(ENOENT, "You need to check probing points in BPF file\n"); 1530 break;
1531 }
1532 bpf__strerror_entry(EEXIST, "Probe point exist. Try 'perf probe -d \"*\"' and set 'force=yes'");
1533 bpf__strerror_entry(EACCES, "You need to be root");
1534 bpf__strerror_entry(EPERM, "You need to be root, and /proc/sys/kernel/kptr_restrict should be 0");
1535 bpf__strerror_entry(ENOENT, "You need to check probing points in BPF file");
340 bpf__strerror_end(buf, size); 1536 bpf__strerror_end(buf, size);
341 return 0; 1537 return 0;
342} 1538}
343 1539
344int bpf__strerror_load(struct bpf_object *obj __maybe_unused, 1540int bpf__strerror_load(struct bpf_object *obj,
345 int err, char *buf, size_t size) 1541 int err, char *buf, size_t size)
346{ 1542{
347 bpf__strerror_head(err, buf, size); 1543 bpf__strerror_head(err, buf, size);
348 bpf__strerror_entry(EINVAL, "%s: Are you root and runing a CONFIG_BPF_SYSCALL kernel?", 1544 case LIBBPF_ERRNO__KVER: {
349 emsg) 1545 unsigned int obj_kver = bpf_object__get_kversion(obj);
1546 unsigned int real_kver;
1547
1548 if (fetch_kernel_version(&real_kver, NULL, 0)) {
1549 scnprintf(buf, size, "Unable to fetch kernel version");
1550 break;
1551 }
1552
1553 if (obj_kver != real_kver) {
1554 scnprintf(buf, size,
1555 "'version' ("KVER_FMT") doesn't match running kernel ("KVER_FMT")",
1556 KVER_PARAM(obj_kver),
1557 KVER_PARAM(real_kver));
1558 break;
1559 }
1560
1561 scnprintf(buf, size, "Failed to load program for unknown reason");
1562 break;
1563 }
1564 bpf__strerror_end(buf, size);
1565 return 0;
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");
350 bpf__strerror_end(buf, size); 1590 bpf__strerror_end(buf, size);
351 return 0; 1591 return 0;
352} 1592}
diff --git a/tools/perf/util/bpf-loader.h b/tools/perf/util/bpf-loader.h
index ccd8d7fd79d3..be4311944e3d 100644
--- a/tools/perf/util/bpf-loader.h
+++ b/tools/perf/util/bpf-loader.h
@@ -8,10 +8,42 @@
8#include <linux/compiler.h> 8#include <linux/compiler.h>
9#include <linux/err.h> 9#include <linux/err.h>
10#include <string.h> 10#include <string.h>
11#include <bpf/libbpf.h>
11#include "probe-event.h" 12#include "probe-event.h"
13#include "evlist.h"
12#include "debug.h" 14#include "debug.h"
13 15
16enum bpf_loader_errno {
17 __BPF_LOADER_ERRNO__START = __LIBBPF_ERRNO__START - 100,
18 /* Invalid config string */
19 BPF_LOADER_ERRNO__CONFIG = __BPF_LOADER_ERRNO__START,
20 BPF_LOADER_ERRNO__GROUP, /* Invalid group name */
21 BPF_LOADER_ERRNO__EVENTNAME, /* Event name is missing */
22 BPF_LOADER_ERRNO__INTERNAL, /* BPF loader internal error */
23 BPF_LOADER_ERRNO__COMPILE, /* Error when compiling BPF scriptlet */
24 BPF_LOADER_ERRNO__PROGCONF_TERM,/* Invalid program config term in config string */
25 BPF_LOADER_ERRNO__PROLOGUE, /* Failed to generate prologue */
26 BPF_LOADER_ERRNO__PROLOGUE2BIG, /* Prologue too big for program */
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 */
42 __BPF_LOADER_ERRNO__END,
43};
44
14struct bpf_object; 45struct bpf_object;
46struct parse_events_term;
15#define PERF_BPF_PROBE_GROUP "perf_bpf_probe" 47#define PERF_BPF_PROBE_GROUP "perf_bpf_probe"
16 48
17typedef int (*bpf_prog_iter_callback_t)(struct probe_trace_event *tev, 49typedef int (*bpf_prog_iter_callback_t)(struct probe_trace_event *tev,
@@ -19,6 +51,11 @@ typedef int (*bpf_prog_iter_callback_t)(struct probe_trace_event *tev,
19 51
20#ifdef HAVE_LIBBPF_SUPPORT 52#ifdef HAVE_LIBBPF_SUPPORT
21struct bpf_object *bpf__prepare_load(const char *filename, bool source); 53struct bpf_object *bpf__prepare_load(const char *filename, bool source);
54int bpf__strerror_prepare_load(const char *filename, bool source,
55 int err, char *buf, size_t size);
56
57struct bpf_object *bpf__prepare_load_buffer(void *obj_buf, size_t obj_buf_sz,
58 const char *name);
22 59
23void bpf__clear(void); 60void bpf__clear(void);
24 61
@@ -32,6 +69,16 @@ int bpf__strerror_load(struct bpf_object *obj, int err,
32 char *buf, size_t size); 69 char *buf, size_t size);
33int bpf__foreach_tev(struct bpf_object *obj, 70int bpf__foreach_tev(struct bpf_object *obj,
34 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);
35#else 82#else
36static inline struct bpf_object * 83static inline struct bpf_object *
37bpf__prepare_load(const char *filename __maybe_unused, 84bpf__prepare_load(const char *filename __maybe_unused,
@@ -41,6 +88,13 @@ bpf__prepare_load(const char *filename __maybe_unused,
41 return ERR_PTR(-ENOTSUP); 88 return ERR_PTR(-ENOTSUP);
42} 89}
43 90
91static inline struct bpf_object *
92bpf__prepare_load_buffer(void *obj_buf __maybe_unused,
93 size_t obj_buf_sz __maybe_unused)
94{
95 return ERR_PTR(-ENOTSUP);
96}
97
44static inline void bpf__clear(void) { } 98static inline void bpf__clear(void) { }
45 99
46static inline int bpf__probe(struct bpf_object *obj __maybe_unused) { return 0;} 100static inline int bpf__probe(struct bpf_object *obj __maybe_unused) { return 0;}
@@ -56,6 +110,21 @@ bpf__foreach_tev(struct bpf_object *obj __maybe_unused,
56} 110}
57 111
58static 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
59__bpf_strerror(char *buf, size_t size) 128__bpf_strerror(char *buf, size_t size)
60{ 129{
61 if (!size) 130 if (!size)
@@ -67,6 +136,15 @@ __bpf_strerror(char *buf, size_t size)
67 return 0; 136 return 0;
68} 137}
69 138
139static inline
140int bpf__strerror_prepare_load(const char *filename __maybe_unused,
141 bool source __maybe_unused,
142 int err __maybe_unused,
143 char *buf, size_t size)
144{
145 return __bpf_strerror(buf, size);
146}
147
70static inline int 148static inline int
71bpf__strerror_probe(struct bpf_object *obj __maybe_unused, 149bpf__strerror_probe(struct bpf_object *obj __maybe_unused,
72 int err __maybe_unused, 150 int err __maybe_unused,
@@ -81,5 +159,23 @@ static inline int bpf__strerror_load(struct bpf_object *obj __maybe_unused,
81{ 159{
82 return __bpf_strerror(buf, size); 160 return __bpf_strerror(buf, size);
83} 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}
84#endif 180#endif
85#endif 181#endif
diff --git a/tools/perf/util/bpf-prologue.c b/tools/perf/util/bpf-prologue.c
new file mode 100644
index 000000000000..6cdbee119ceb
--- /dev/null
+++ b/tools/perf/util/bpf-prologue.c
@@ -0,0 +1,455 @@
1/*
2 * bpf-prologue.c
3 *
4 * Copyright (C) 2015 He Kuang <hekuang@huawei.com>
5 * Copyright (C) 2015 Wang Nan <wangnan0@huawei.com>
6 * Copyright (C) 2015 Huawei Inc.
7 */
8
9#include <bpf/libbpf.h>
10#include "perf.h"
11#include "debug.h"
12#include "bpf-loader.h"
13#include "bpf-prologue.h"
14#include "probe-finder.h"
15#include <dwarf-regs.h>
16#include <linux/filter.h>
17
18#define BPF_REG_SIZE 8
19
20#define JMP_TO_ERROR_CODE -1
21#define JMP_TO_SUCCESS_CODE -2
22#define JMP_TO_USER_CODE -3
23
24struct bpf_insn_pos {
25 struct bpf_insn *begin;
26 struct bpf_insn *end;
27 struct bpf_insn *pos;
28};
29
30static inline int
31pos_get_cnt(struct bpf_insn_pos *pos)
32{
33 return pos->pos - pos->begin;
34}
35
36static int
37append_insn(struct bpf_insn new_insn, struct bpf_insn_pos *pos)
38{
39 if (!pos->pos)
40 return -BPF_LOADER_ERRNO__PROLOGUE2BIG;
41
42 if (pos->pos + 1 >= pos->end) {
43 pr_err("bpf prologue: prologue too long\n");
44 pos->pos = NULL;
45 return -BPF_LOADER_ERRNO__PROLOGUE2BIG;
46 }
47
48 *(pos->pos)++ = new_insn;
49 return 0;
50}
51
52static int
53check_pos(struct bpf_insn_pos *pos)
54{
55 if (!pos->pos || pos->pos >= pos->end)
56 return -BPF_LOADER_ERRNO__PROLOGUE2BIG;
57 return 0;
58}
59
60/* Give it a shorter name */
61#define ins(i, p) append_insn((i), (p))
62
63/*
64 * Give a register name (in 'reg'), generate instruction to
65 * load register into an eBPF register rd:
66 * 'ldd target_reg, offset(ctx_reg)', where:
67 * ctx_reg is pre initialized to pointer of 'struct pt_regs'.
68 */
69static int
70gen_ldx_reg_from_ctx(struct bpf_insn_pos *pos, int ctx_reg,
71 const char *reg, int target_reg)
72{
73 int offset = regs_query_register_offset(reg);
74
75 if (offset < 0) {
76 pr_err("bpf: prologue: failed to get register %s\n",
77 reg);
78 return offset;
79 }
80 ins(BPF_LDX_MEM(BPF_DW, target_reg, ctx_reg, offset), pos);
81
82 return check_pos(pos);
83}
84
85/*
86 * Generate a BPF_FUNC_probe_read function call.
87 *
88 * src_base_addr_reg is a register holding base address,
89 * dst_addr_reg is a register holding dest address (on stack),
90 * result is:
91 *
92 * *[dst_addr_reg] = *([src_base_addr_reg] + offset)
93 *
94 * Arguments of BPF_FUNC_probe_read:
95 * ARG1: ptr to stack (dest)
96 * ARG2: size (8)
97 * ARG3: unsafe ptr (src)
98 */
99static int
100gen_read_mem(struct bpf_insn_pos *pos,
101 int src_base_addr_reg,
102 int dst_addr_reg,
103 long offset)
104{
105 /* mov arg3, src_base_addr_reg */
106 if (src_base_addr_reg != BPF_REG_ARG3)
107 ins(BPF_MOV64_REG(BPF_REG_ARG3, src_base_addr_reg), pos);
108 /* add arg3, #offset */
109 if (offset)
110 ins(BPF_ALU64_IMM(BPF_ADD, BPF_REG_ARG3, offset), pos);
111
112 /* mov arg2, #reg_size */
113 ins(BPF_ALU64_IMM(BPF_MOV, BPF_REG_ARG2, BPF_REG_SIZE), pos);
114
115 /* mov arg1, dst_addr_reg */
116 if (dst_addr_reg != BPF_REG_ARG1)
117 ins(BPF_MOV64_REG(BPF_REG_ARG1, dst_addr_reg), pos);
118
119 /* Call probe_read */
120 ins(BPF_EMIT_CALL(BPF_FUNC_probe_read), pos);
121 /*
122 * Error processing: if read fail, goto error code,
123 * will be relocated. Target should be the start of
124 * error processing code.
125 */
126 ins(BPF_JMP_IMM(BPF_JNE, BPF_REG_0, 0, JMP_TO_ERROR_CODE),
127 pos);
128
129 return check_pos(pos);
130}
131
132/*
133 * Each arg should be bare register. Fetch and save them into argument
134 * registers (r3 - r5).
135 *
136 * BPF_REG_1 should have been initialized with pointer to
137 * 'struct pt_regs'.
138 */
139static int
140gen_prologue_fastpath(struct bpf_insn_pos *pos,
141 struct probe_trace_arg *args, int nargs)
142{
143 int i, err = 0;
144
145 for (i = 0; i < nargs; i++) {
146 err = gen_ldx_reg_from_ctx(pos, BPF_REG_1, args[i].value,
147 BPF_PROLOGUE_START_ARG_REG + i);
148 if (err)
149 goto errout;
150 }
151
152 return check_pos(pos);
153errout:
154 return err;
155}
156
157/*
158 * Slow path:
159 * At least one argument has the form of 'offset($rx)'.
160 *
161 * Following code first stores them into stack, then loads all of then
162 * to r2 - r5.
163 * Before final loading, the final result should be:
164 *
165 * low address
166 * BPF_REG_FP - 24 ARG3
167 * BPF_REG_FP - 16 ARG2
168 * BPF_REG_FP - 8 ARG1
169 * BPF_REG_FP
170 * high address
171 *
172 * For each argument (described as: offn(...off2(off1(reg)))),
173 * generates following code:
174 *
175 * r7 <- fp
176 * r7 <- r7 - stack_offset // Ideal code should initialize r7 using
177 * // fp before generating args. However,
178 * // eBPF won't regard r7 as stack pointer
179 * // if it is generated by minus 8 from
180 * // another stack pointer except fp.
181 * // This is why we have to set r7
182 * // to fp for each variable.
183 * r3 <- value of 'reg'-> generated using gen_ldx_reg_from_ctx()
184 * (r7) <- r3 // skip following instructions for bare reg
185 * r3 <- r3 + off1 . // skip if off1 == 0
186 * r2 <- 8 \
187 * r1 <- r7 |-> generated by gen_read_mem()
188 * call probe_read /
189 * jnei r0, 0, err ./
190 * r3 <- (r7)
191 * r3 <- r3 + off2 . // skip if off2 == 0
192 * r2 <- 8 \ // r2 may be broken by probe_read, so set again
193 * r1 <- r7 |-> generated by gen_read_mem()
194 * call probe_read /
195 * jnei r0, 0, err ./
196 * ...
197 */
198static int
199gen_prologue_slowpath(struct bpf_insn_pos *pos,
200 struct probe_trace_arg *args, int nargs)
201{
202 int err, i;
203
204 for (i = 0; i < nargs; i++) {
205 struct probe_trace_arg *arg = &args[i];
206 const char *reg = arg->value;
207 struct probe_trace_arg_ref *ref = NULL;
208 int stack_offset = (i + 1) * -8;
209
210 pr_debug("prologue: fetch arg %d, base reg is %s\n",
211 i, reg);
212
213 /* value of base register is stored into ARG3 */
214 err = gen_ldx_reg_from_ctx(pos, BPF_REG_CTX, reg,
215 BPF_REG_ARG3);
216 if (err) {
217 pr_err("prologue: failed to get offset of register %s\n",
218 reg);
219 goto errout;
220 }
221
222 /* Make r7 the stack pointer. */
223 ins(BPF_MOV64_REG(BPF_REG_7, BPF_REG_FP), pos);
224 /* r7 += -8 */
225 ins(BPF_ALU64_IMM(BPF_ADD, BPF_REG_7, stack_offset), pos);
226 /*
227 * Store r3 (base register) onto stack
228 * Ensure fp[offset] is set.
229 * fp is the only valid base register when storing
230 * into stack. We are not allowed to use r7 as base
231 * register here.
232 */
233 ins(BPF_STX_MEM(BPF_DW, BPF_REG_FP, BPF_REG_ARG3,
234 stack_offset), pos);
235
236 ref = arg->ref;
237 while (ref) {
238 pr_debug("prologue: arg %d: offset %ld\n",
239 i, ref->offset);
240 err = gen_read_mem(pos, BPF_REG_3, BPF_REG_7,
241 ref->offset);
242 if (err) {
243 pr_err("prologue: failed to generate probe_read function call\n");
244 goto errout;
245 }
246
247 ref = ref->next;
248 /*
249 * Load previous result into ARG3. Use
250 * BPF_REG_FP instead of r7 because verifier
251 * allows FP based addressing only.
252 */
253 if (ref)
254 ins(BPF_LDX_MEM(BPF_DW, BPF_REG_ARG3,
255 BPF_REG_FP, stack_offset), pos);
256 }
257 }
258
259 /* Final pass: read to registers */
260 for (i = 0; i < nargs; i++)
261 ins(BPF_LDX_MEM(BPF_DW, BPF_PROLOGUE_START_ARG_REG + i,
262 BPF_REG_FP, -BPF_REG_SIZE * (i + 1)), pos);
263
264 ins(BPF_JMP_IMM(BPF_JA, BPF_REG_0, 0, JMP_TO_SUCCESS_CODE), pos);
265
266 return check_pos(pos);
267errout:
268 return err;
269}
270
271static int
272prologue_relocate(struct bpf_insn_pos *pos, struct bpf_insn *error_code,
273 struct bpf_insn *success_code, struct bpf_insn *user_code)
274{
275 struct bpf_insn *insn;
276
277 if (check_pos(pos))
278 return -BPF_LOADER_ERRNO__PROLOGUE2BIG;
279
280 for (insn = pos->begin; insn < pos->pos; insn++) {
281 struct bpf_insn *target;
282 u8 class = BPF_CLASS(insn->code);
283 u8 opcode;
284
285 if (class != BPF_JMP)
286 continue;
287 opcode = BPF_OP(insn->code);
288 if (opcode == BPF_CALL)
289 continue;
290
291 switch (insn->off) {
292 case JMP_TO_ERROR_CODE:
293 target = error_code;
294 break;
295 case JMP_TO_SUCCESS_CODE:
296 target = success_code;
297 break;
298 case JMP_TO_USER_CODE:
299 target = user_code;
300 break;
301 default:
302 pr_err("bpf prologue: internal error: relocation failed\n");
303 return -BPF_LOADER_ERRNO__PROLOGUE;
304 }
305
306 insn->off = target - (insn + 1);
307 }
308 return 0;
309}
310
311int bpf__gen_prologue(struct probe_trace_arg *args, int nargs,
312 struct bpf_insn *new_prog, size_t *new_cnt,
313 size_t cnt_space)
314{
315 struct bpf_insn *success_code = NULL;
316 struct bpf_insn *error_code = NULL;
317 struct bpf_insn *user_code = NULL;
318 struct bpf_insn_pos pos;
319 bool fastpath = true;
320 int err = 0, i;
321
322 if (!new_prog || !new_cnt)
323 return -EINVAL;
324
325 if (cnt_space > BPF_MAXINSNS)
326 cnt_space = BPF_MAXINSNS;
327
328 pos.begin = new_prog;
329 pos.end = new_prog + cnt_space;
330 pos.pos = new_prog;
331
332 if (!nargs) {
333 ins(BPF_ALU64_IMM(BPF_MOV, BPF_PROLOGUE_FETCH_RESULT_REG, 0),
334 &pos);
335
336 if (check_pos(&pos))
337 goto errout;
338
339 *new_cnt = pos_get_cnt(&pos);
340 return 0;
341 }
342
343 if (nargs > BPF_PROLOGUE_MAX_ARGS) {
344 pr_warning("bpf: prologue: %d arguments are dropped\n",
345 nargs - BPF_PROLOGUE_MAX_ARGS);
346 nargs = BPF_PROLOGUE_MAX_ARGS;
347 }
348
349 /* First pass: validation */
350 for (i = 0; i < nargs; i++) {
351 struct probe_trace_arg_ref *ref = args[i].ref;
352
353 if (args[i].value[0] == '@') {
354 /* TODO: fetch global variable */
355 pr_err("bpf: prologue: global %s%+ld not support\n",
356 args[i].value, ref ? ref->offset : 0);
357 return -ENOTSUP;
358 }
359
360 while (ref) {
361 /* fastpath is true if all args has ref == NULL */
362 fastpath = false;
363
364 /*
365 * Instruction encodes immediate value using
366 * s32, ref->offset is long. On systems which
367 * can't fill long in s32, refuse to process if
368 * ref->offset too large (or small).
369 */
370#ifdef __LP64__
371#define OFFSET_MAX ((1LL << 31) - 1)
372#define OFFSET_MIN ((1LL << 31) * -1)
373 if (ref->offset > OFFSET_MAX ||
374 ref->offset < OFFSET_MIN) {
375 pr_err("bpf: prologue: offset out of bound: %ld\n",
376 ref->offset);
377 return -BPF_LOADER_ERRNO__PROLOGUEOOB;
378 }
379#endif
380 ref = ref->next;
381 }
382 }
383 pr_debug("prologue: pass validation\n");
384
385 if (fastpath) {
386 /* If all variables are registers... */
387 pr_debug("prologue: fast path\n");
388 err = gen_prologue_fastpath(&pos, args, nargs);
389 if (err)
390 goto errout;
391 } else {
392 pr_debug("prologue: slow path\n");
393
394 /* Initialization: move ctx to a callee saved register. */
395 ins(BPF_MOV64_REG(BPF_REG_CTX, BPF_REG_ARG1), &pos);
396
397 err = gen_prologue_slowpath(&pos, args, nargs);
398 if (err)
399 goto errout;
400 /*
401 * start of ERROR_CODE (only slow pass needs error code)
402 * mov r2 <- 1 // r2 is error number
403 * mov r3 <- 0 // r3, r4... should be touched or
404 * // verifier would complain
405 * mov r4 <- 0
406 * ...
407 * goto usercode
408 */
409 error_code = pos.pos;
410 ins(BPF_ALU64_IMM(BPF_MOV, BPF_PROLOGUE_FETCH_RESULT_REG, 1),
411 &pos);
412
413 for (i = 0; i < nargs; i++)
414 ins(BPF_ALU64_IMM(BPF_MOV,
415 BPF_PROLOGUE_START_ARG_REG + i,
416 0),
417 &pos);
418 ins(BPF_JMP_IMM(BPF_JA, BPF_REG_0, 0, JMP_TO_USER_CODE),
419 &pos);
420 }
421
422 /*
423 * start of SUCCESS_CODE:
424 * mov r2 <- 0
425 * goto usercode // skip
426 */
427 success_code = pos.pos;
428 ins(BPF_ALU64_IMM(BPF_MOV, BPF_PROLOGUE_FETCH_RESULT_REG, 0), &pos);
429
430 /*
431 * start of USER_CODE:
432 * Restore ctx to r1
433 */
434 user_code = pos.pos;
435 if (!fastpath) {
436 /*
437 * Only slow path needs restoring of ctx. In fast path,
438 * register are loaded directly from r1.
439 */
440 ins(BPF_MOV64_REG(BPF_REG_ARG1, BPF_REG_CTX), &pos);
441 err = prologue_relocate(&pos, error_code, success_code,
442 user_code);
443 if (err)
444 goto errout;
445 }
446
447 err = check_pos(&pos);
448 if (err)
449 goto errout;
450
451 *new_cnt = pos_get_cnt(&pos);
452 return 0;
453errout:
454 return err;
455}
diff --git a/tools/perf/util/bpf-prologue.h b/tools/perf/util/bpf-prologue.h
new file mode 100644
index 000000000000..d94cbea12899
--- /dev/null
+++ b/tools/perf/util/bpf-prologue.h
@@ -0,0 +1,34 @@
1/*
2 * Copyright (C) 2015, He Kuang <hekuang@huawei.com>
3 * Copyright (C) 2015, Huawei Inc.
4 */
5#ifndef __BPF_PROLOGUE_H
6#define __BPF_PROLOGUE_H
7
8#include <linux/compiler.h>
9#include <linux/filter.h>
10#include "probe-event.h"
11
12#define BPF_PROLOGUE_MAX_ARGS 3
13#define BPF_PROLOGUE_START_ARG_REG BPF_REG_3
14#define BPF_PROLOGUE_FETCH_RESULT_REG BPF_REG_2
15
16#ifdef HAVE_BPF_PROLOGUE
17int bpf__gen_prologue(struct probe_trace_arg *args, int nargs,
18 struct bpf_insn *new_prog, size_t *new_cnt,
19 size_t cnt_space);
20#else
21static inline int
22bpf__gen_prologue(struct probe_trace_arg *args __maybe_unused,
23 int nargs __maybe_unused,
24 struct bpf_insn *new_prog __maybe_unused,
25 size_t *new_cnt,
26 size_t cnt_space __maybe_unused)
27{
28 if (!new_cnt)
29 return -EINVAL;
30 *new_cnt = 0;
31 return -ENOTSUP;
32}
33#endif
34#endif /* __BPF_PROLOGUE_H */
diff --git a/tools/perf/util/build-id.c b/tools/perf/util/build-id.c
index d909459fb54c..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;
@@ -76,6 +75,7 @@ struct perf_tool build_id__mark_dso_hit_ops = {
76 .exit = perf_event__exit_del_thread, 75 .exit = perf_event__exit_del_thread,
77 .attr = perf_event__process_attr, 76 .attr = perf_event__process_attr,
78 .build_id = perf_event__process_build_id, 77 .build_id = perf_event__process_build_id,
78 .ordered_events = true,
79}; 79};
80 80
81int build_id__sprintf(const u8 *build_id, int len, char *bf) 81int build_id__sprintf(const u8 *build_id, int len, char *bf)
@@ -90,7 +90,7 @@ int build_id__sprintf(const u8 *build_id, int len, char *bf)
90 bid += 2; 90 bid += 2;
91 } 91 }
92 92
93 return raw - build_id; 93 return (bid - bf) + 1;
94} 94}
95 95
96int sysfs__sprintf_build_id(const char *root_dir, char *sbuild_id) 96int sysfs__sprintf_build_id(const char *root_dir, char *sbuild_id)
@@ -165,6 +165,50 @@ char *dso__build_id_filename(const struct dso *dso, char *bf, size_t size)
165 return build_id__filename(build_id_hex, bf, size); 165 return build_id__filename(build_id_hex, bf, size);
166} 166}
167 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
168#define dsos__for_each_with_build_id(pos, head) \ 212#define dsos__for_each_with_build_id(pos, head) \
169 list_for_each_entry(pos, head, node) \ 213 list_for_each_entry(pos, head, node) \
170 if (!pos->has_build_id) \ 214 if (!pos->has_build_id) \
@@ -210,6 +254,7 @@ static int machine__write_buildid_table(struct machine *machine, int fd)
210 dsos__for_each_with_build_id(pos, &machine->dsos.head) { 254 dsos__for_each_with_build_id(pos, &machine->dsos.head) {
211 const char *name; 255 const char *name;
212 size_t name_len; 256 size_t name_len;
257 bool in_kernel = false;
213 258
214 if (!pos->hit) 259 if (!pos->hit)
215 continue; 260 continue;
@@ -226,8 +271,11 @@ static int machine__write_buildid_table(struct machine *machine, int fd)
226 name_len = pos->long_name_len + 1; 271 name_len = pos->long_name_len + 1;
227 } 272 }
228 273
274 in_kernel = pos->kernel ||
275 is_kernel_module(name,
276 PERF_RECORD_MISC_CPUMODE_UNKNOWN);
229 err = write_buildid(name, name_len, pos->build_id, machine->pid, 277 err = write_buildid(name, name_len, pos->build_id, machine->pid,
230 pos->kernel ? kmisc : umisc, fd); 278 in_kernel ? kmisc : umisc, fd);
231 if (err) 279 if (err)
232 break; 280 break;
233 } 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 c861373aaed3..1f5a93c2c9a2 100644
--- a/tools/perf/util/cache.h
+++ b/tools/perf/util/cache.h
@@ -4,9 +4,12 @@
4#include <stdbool.h> 4#include <stdbool.h>
5#include "util.h" 5#include "util.h"
6#include "strbuf.h" 6#include "strbuf.h"
7#include <subcmd/pager.h>
7#include "../perf.h" 8#include "../perf.h"
8#include "../ui/ui.h" 9#include "../ui/ui.h"
9 10
11#include <linux/string.h>
12
10#define CMD_EXEC_PATH "--exec-path" 13#define CMD_EXEC_PATH "--exec-path"
11#define CMD_PERF_DIR "--perf-dir=" 14#define CMD_PERF_DIR "--perf-dir="
12#define CMD_WORK_TREE "--work-tree=" 15#define CMD_WORK_TREE "--work-tree="
@@ -18,20 +21,19 @@
18#define DEFAULT_PERF_DIR_ENVIRONMENT ".perf" 21#define DEFAULT_PERF_DIR_ENVIRONMENT ".perf"
19#define PERF_DEBUGFS_ENVIRONMENT "PERF_DEBUGFS_DIR" 22#define PERF_DEBUGFS_ENVIRONMENT "PERF_DEBUGFS_DIR"
20#define PERF_TRACEFS_ENVIRONMENT "PERF_TRACEFS_DIR" 23#define PERF_TRACEFS_ENVIRONMENT "PERF_TRACEFS_DIR"
24#define PERF_PAGER_ENVIRONMENT "PERF_PAGER"
21 25
22typedef int (*config_fn_t)(const char *, const char *, void *); 26extern const char *config_exclusive_filename;
23extern int perf_default_config(const char *, const char *, void *);
24extern int perf_config(config_fn_t fn, void *);
25extern int perf_config_int(const char *, const char *);
26extern u64 perf_config_u64(const char *, const char *);
27extern int perf_config_bool(const char *, const char *);
28extern int config_error_nonbool(const char *);
29extern const char *perf_config_dirname(const char *, const char *);
30 27
31/* pager.c */ 28typedef int (*config_fn_t)(const char *, const char *, void *);
32extern void setup_pager(void); 29int perf_default_config(const char *, const char *, void *);
33extern int pager_in_use(void); 30int perf_config(config_fn_t fn, void *);
34extern int pager_use_color; 31int perf_config_int(const char *, const char *);
32u64 perf_config_u64(const char *, const char *);
33int perf_config_bool(const char *, const char *);
34int config_error_nonbool(const char *);
35const char *perf_config_dirname(const char *, const char *);
36const char *perf_etc_perfconfig(void);
35 37
36char *alias_lookup(const char *alias); 38char *alias_lookup(const char *alias);
37int split_cmdline(char *cmdline, const char ***argv); 39int split_cmdline(char *cmdline, const char ***argv);
@@ -62,18 +64,9 @@ static inline int is_absolute_path(const char *path)
62 return path[0] == '/'; 64 return path[0] == '/';
63} 65}
64 66
65const char *make_nonrelative_path(const char *path);
66char *strip_path_suffix(const char *path, const char *suffix); 67char *strip_path_suffix(const char *path, const char *suffix);
67 68
68extern char *mkpath(const char *fmt, ...) __attribute__((format (printf, 1, 2))); 69char *mkpath(const char *fmt, ...) __attribute__((format (printf, 1, 2)));
69extern char *perf_path(const char *fmt, ...) __attribute__((format (printf, 1, 2))); 70char *perf_path(const char *fmt, ...) __attribute__((format (printf, 1, 2)));
70
71extern char *perf_pathdup(const char *fmt, ...)
72 __attribute__((format (printf, 1, 2)));
73
74#ifndef __UCLIBC__
75/* Matches the libc/libbsd function attribute so we declare this unconditionally: */
76extern size_t strlcpy(char *dest, const char *src, size_t size);
77#endif
78 71
79#endif /* __PERF_CACHE_H */ 72#endif /* __PERF_CACHE_H */
diff --git a/tools/perf/util/callchain.c b/tools/perf/util/callchain.c
index 735ad48e1858..24b4bd0d7754 100644
--- a/tools/perf/util/callchain.c
+++ b/tools/perf/util/callchain.c
@@ -44,6 +44,10 @@ static int parse_callchain_mode(const char *value)
44 callchain_param.mode = CHAIN_GRAPH_REL; 44 callchain_param.mode = CHAIN_GRAPH_REL;
45 return 0; 45 return 0;
46 } 46 }
47 if (!strncmp(value, "folded", strlen(value))) {
48 callchain_param.mode = CHAIN_FOLDED;
49 return 0;
50 }
47 return -1; 51 return -1;
48} 52}
49 53
@@ -79,6 +83,23 @@ static int parse_callchain_sort_key(const char *value)
79 return -1; 83 return -1;
80} 84}
81 85
86static int parse_callchain_value(const char *value)
87{
88 if (!strncmp(value, "percent", strlen(value))) {
89 callchain_param.value = CCVAL_PERCENT;
90 return 0;
91 }
92 if (!strncmp(value, "period", strlen(value))) {
93 callchain_param.value = CCVAL_PERIOD;
94 return 0;
95 }
96 if (!strncmp(value, "count", strlen(value))) {
97 callchain_param.value = CCVAL_COUNT;
98 return 0;
99 }
100 return -1;
101}
102
82static int 103static int
83__parse_callchain_report_opt(const char *arg, bool allow_record_opt) 104__parse_callchain_report_opt(const char *arg, bool allow_record_opt)
84{ 105{
@@ -102,7 +123,8 @@ __parse_callchain_report_opt(const char *arg, bool allow_record_opt)
102 123
103 if (!parse_callchain_mode(tok) || 124 if (!parse_callchain_mode(tok) ||
104 !parse_callchain_order(tok) || 125 !parse_callchain_order(tok) ||
105 !parse_callchain_sort_key(tok)) { 126 !parse_callchain_sort_key(tok) ||
127 !parse_callchain_value(tok)) {
106 /* parsing ok - move on to the next */ 128 /* parsing ok - move on to the next */
107 try_stack_size = false; 129 try_stack_size = false;
108 goto next; 130 goto next;
@@ -218,6 +240,7 @@ rb_insert_callchain(struct rb_root *root, struct callchain_node *chain,
218 240
219 switch (mode) { 241 switch (mode) {
220 case CHAIN_FLAT: 242 case CHAIN_FLAT:
243 case CHAIN_FOLDED:
221 if (rnode->hit < chain->hit) 244 if (rnode->hit < chain->hit)
222 p = &(*p)->rb_left; 245 p = &(*p)->rb_left;
223 else 246 else
@@ -267,6 +290,7 @@ static void
267sort_chain_flat(struct rb_root *rb_root, struct callchain_root *root, 290sort_chain_flat(struct rb_root *rb_root, struct callchain_root *root,
268 u64 min_hit, struct callchain_param *param __maybe_unused) 291 u64 min_hit, struct callchain_param *param __maybe_unused)
269{ 292{
293 *rb_root = RB_ROOT;
270 __sort_chain_flat(rb_root, &root->node, min_hit); 294 __sort_chain_flat(rb_root, &root->node, min_hit);
271} 295}
272 296
@@ -338,6 +362,7 @@ int callchain_register_param(struct callchain_param *param)
338 param->sort = sort_chain_graph_rel; 362 param->sort = sort_chain_graph_rel;
339 break; 363 break;
340 case CHAIN_FLAT: 364 case CHAIN_FLAT:
365 case CHAIN_FOLDED:
341 param->sort = sort_chain_flat; 366 param->sort = sort_chain_flat;
342 break; 367 break;
343 case CHAIN_NONE: 368 case CHAIN_NONE:
@@ -363,6 +388,7 @@ create_child(struct callchain_node *parent, bool inherit_children)
363 } 388 }
364 new->parent = parent; 389 new->parent = parent;
365 INIT_LIST_HEAD(&new->val); 390 INIT_LIST_HEAD(&new->val);
391 INIT_LIST_HEAD(&new->parent_val);
366 392
367 if (inherit_children) { 393 if (inherit_children) {
368 struct rb_node *n; 394 struct rb_node *n;
@@ -390,7 +416,7 @@ create_child(struct callchain_node *parent, bool inherit_children)
390/* 416/*
391 * Fill the node with callchain values 417 * Fill the node with callchain values
392 */ 418 */
393static void 419static int
394fill_node(struct callchain_node *node, struct callchain_cursor *cursor) 420fill_node(struct callchain_node *node, struct callchain_cursor *cursor)
395{ 421{
396 struct callchain_cursor_node *cursor_node; 422 struct callchain_cursor_node *cursor_node;
@@ -407,7 +433,7 @@ fill_node(struct callchain_node *node, struct callchain_cursor *cursor)
407 call = zalloc(sizeof(*call)); 433 call = zalloc(sizeof(*call));
408 if (!call) { 434 if (!call) {
409 perror("not enough memory for the code path tree"); 435 perror("not enough memory for the code path tree");
410 return; 436 return -1;
411 } 437 }
412 call->ip = cursor_node->ip; 438 call->ip = cursor_node->ip;
413 call->ms.sym = cursor_node->sym; 439 call->ms.sym = cursor_node->sym;
@@ -417,6 +443,7 @@ fill_node(struct callchain_node *node, struct callchain_cursor *cursor)
417 callchain_cursor_advance(cursor); 443 callchain_cursor_advance(cursor);
418 cursor_node = callchain_cursor_current(cursor); 444 cursor_node = callchain_cursor_current(cursor);
419 } 445 }
446 return 0;
420} 447}
421 448
422static struct callchain_node * 449static struct callchain_node *
@@ -427,23 +454,53 @@ add_child(struct callchain_node *parent,
427 struct callchain_node *new; 454 struct callchain_node *new;
428 455
429 new = create_child(parent, false); 456 new = create_child(parent, false);
430 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 }
431 470
432 new->children_hit = 0; 471 new->children_hit = 0;
433 new->hit = period; 472 new->hit = period;
473 new->children_count = 0;
474 new->count = 1;
434 return new; 475 return new;
435} 476}
436 477
437static s64 match_chain(struct callchain_cursor_node *node, 478enum match_result {
438 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)
439{ 487{
440 struct symbol *sym = node->sym; 488 struct symbol *sym = node->sym;
489 u64 left, right;
441 490
442 if (cnode->ms.sym && sym && 491 if (cnode->ms.sym && sym &&
443 callchain_param.key == CCKEY_FUNCTION) 492 callchain_param.key == CCKEY_FUNCTION) {
444 return cnode->ms.sym->start - sym->start; 493 left = cnode->ms.sym->start;
445 else 494 right = sym->start;
446 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;
447} 504}
448 505
449/* 506/*
@@ -451,7 +508,7 @@ static s64 match_chain(struct callchain_cursor_node *node,
451 * give a part of its callchain to the created child. 508 * give a part of its callchain to the created child.
452 * 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
453 */ 510 */
454static void 511static int
455split_add_child(struct callchain_node *parent, 512split_add_child(struct callchain_node *parent,
456 struct callchain_cursor *cursor, 513 struct callchain_cursor *cursor,
457 struct callchain_list *to_split, 514 struct callchain_list *to_split,
@@ -463,6 +520,8 @@ split_add_child(struct callchain_node *parent,
463 520
464 /* split */ 521 /* split */
465 new = create_child(parent, true); 522 new = create_child(parent, true);
523 if (new == NULL)
524 return -1;
466 525
467 /* split the callchain and move a part to the new child */ 526 /* split the callchain and move a part to the new child */
468 old_tail = parent->val.prev; 527 old_tail = parent->val.prev;
@@ -478,6 +537,9 @@ split_add_child(struct callchain_node *parent,
478 parent->children_hit = callchain_cumul_hits(new); 537 parent->children_hit = callchain_cumul_hits(new);
479 new->val_nr = parent->val_nr - idx_local; 538 new->val_nr = parent->val_nr - idx_local;
480 parent->val_nr = idx_local; 539 parent->val_nr = idx_local;
540 new->count = parent->count;
541 new->children_count = parent->children_count;
542 parent->children_count = callchain_cumul_counts(new);
481 543
482 /* create a new child for the new branch if any */ 544 /* create a new child for the new branch if any */
483 if (idx_total < cursor->nr) { 545 if (idx_total < cursor->nr) {
@@ -488,9 +550,13 @@ split_add_child(struct callchain_node *parent,
488 550
489 parent->hit = 0; 551 parent->hit = 0;
490 parent->children_hit += period; 552 parent->children_hit += period;
553 parent->count = 0;
554 parent->children_count += 1;
491 555
492 node = callchain_cursor_current(cursor); 556 node = callchain_cursor_current(cursor);
493 new = add_child(parent, cursor, period); 557 new = add_child(parent, cursor, period);
558 if (new == NULL)
559 return -1;
494 560
495 /* 561 /*
496 * This is second child since we moved parent's children 562 * This is second child since we moved parent's children
@@ -501,7 +567,7 @@ split_add_child(struct callchain_node *parent,
501 cnode = list_first_entry(&first->val, struct callchain_list, 567 cnode = list_first_entry(&first->val, struct callchain_list,
502 list); 568 list);
503 569
504 if (match_chain(node, cnode) < 0) 570 if (match_chain(node, cnode) == MATCH_LT)
505 pp = &p->rb_left; 571 pp = &p->rb_left;
506 else 572 else
507 pp = &p->rb_right; 573 pp = &p->rb_right;
@@ -510,15 +576,17 @@ split_add_child(struct callchain_node *parent,
510 rb_insert_color(&new->rb_node_in, &parent->rb_root_in); 576 rb_insert_color(&new->rb_node_in, &parent->rb_root_in);
511 } else { 577 } else {
512 parent->hit = period; 578 parent->hit = period;
579 parent->count = 1;
513 } 580 }
581 return 0;
514} 582}
515 583
516static int 584static enum match_result
517append_chain(struct callchain_node *root, 585append_chain(struct callchain_node *root,
518 struct callchain_cursor *cursor, 586 struct callchain_cursor *cursor,
519 u64 period); 587 u64 period);
520 588
521static void 589static int
522append_chain_children(struct callchain_node *root, 590append_chain_children(struct callchain_node *root,
523 struct callchain_cursor *cursor, 591 struct callchain_cursor *cursor,
524 u64 period) 592 u64 period)
@@ -530,35 +598,42 @@ append_chain_children(struct callchain_node *root,
530 598
531 node = callchain_cursor_current(cursor); 599 node = callchain_cursor_current(cursor);
532 if (!node) 600 if (!node)
533 return; 601 return -1;
534 602
535 /* lookup in childrens */ 603 /* lookup in childrens */
536 while (*p) { 604 while (*p) {
537 s64 ret; 605 enum match_result ret;
538 606
539 parent = *p; 607 parent = *p;
540 rnode = rb_entry(parent, struct callchain_node, rb_node_in); 608 rnode = rb_entry(parent, struct callchain_node, rb_node_in);
541 609
542 /* If at least first entry matches, rely to children */ 610 /* If at least first entry matches, rely to children */
543 ret = append_chain(rnode, cursor, period); 611 ret = append_chain(rnode, cursor, period);
544 if (ret == 0) 612 if (ret == MATCH_EQ)
545 goto inc_children_hit; 613 goto inc_children_hit;
614 if (ret == MATCH_ERROR)
615 return -1;
546 616
547 if (ret < 0) 617 if (ret == MATCH_LT)
548 p = &parent->rb_left; 618 p = &parent->rb_left;
549 else 619 else
550 p = &parent->rb_right; 620 p = &parent->rb_right;
551 } 621 }
552 /* nothing in children, add to the current node */ 622 /* nothing in children, add to the current node */
553 rnode = add_child(root, cursor, period); 623 rnode = add_child(root, cursor, period);
624 if (rnode == NULL)
625 return -1;
626
554 rb_link_node(&rnode->rb_node_in, parent, p); 627 rb_link_node(&rnode->rb_node_in, parent, p);
555 rb_insert_color(&rnode->rb_node_in, &root->rb_root_in); 628 rb_insert_color(&rnode->rb_node_in, &root->rb_root_in);
556 629
557inc_children_hit: 630inc_children_hit:
558 root->children_hit += period; 631 root->children_hit += period;
632 root->children_count++;
633 return 0;
559} 634}
560 635
561static int 636static enum match_result
562append_chain(struct callchain_node *root, 637append_chain(struct callchain_node *root,
563 struct callchain_cursor *cursor, 638 struct callchain_cursor *cursor,
564 u64 period) 639 u64 period)
@@ -567,7 +642,7 @@ append_chain(struct callchain_node *root,
567 u64 start = cursor->pos; 642 u64 start = cursor->pos;
568 bool found = false; 643 bool found = false;
569 u64 matches; 644 u64 matches;
570 int cmp = 0; 645 enum match_result cmp = MATCH_ERROR;
571 646
572 /* 647 /*
573 * Lookup in the current node 648 * Lookup in the current node
@@ -583,7 +658,7 @@ append_chain(struct callchain_node *root,
583 break; 658 break;
584 659
585 cmp = match_chain(node, cnode); 660 cmp = match_chain(node, cnode);
586 if (cmp) 661 if (cmp != MATCH_EQ)
587 break; 662 break;
588 663
589 found = true; 664 found = true;
@@ -593,7 +668,7 @@ append_chain(struct callchain_node *root,
593 668
594 /* matches not, relay no the parent */ 669 /* matches not, relay no the parent */
595 if (!found) { 670 if (!found) {
596 WARN_ONCE(!cmp, "Chain comparison error\n"); 671 WARN_ONCE(cmp == MATCH_ERROR, "Chain comparison error\n");
597 return cmp; 672 return cmp;
598 } 673 }
599 674
@@ -601,20 +676,25 @@ append_chain(struct callchain_node *root,
601 676
602 /* 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 */
603 if (matches < root->val_nr) { 678 if (matches < root->val_nr) {
604 split_add_child(root, cursor, cnode, start, matches, period); 679 if (split_add_child(root, cursor, cnode, start, matches,
605 return 0; 680 period) < 0)
681 return MATCH_ERROR;
682
683 return MATCH_EQ;
606 } 684 }
607 685
608 /* we match 100% of the path, increment the hit */ 686 /* we match 100% of the path, increment the hit */
609 if (matches == root->val_nr && cursor->pos == cursor->nr) { 687 if (matches == root->val_nr && cursor->pos == cursor->nr) {
610 root->hit += period; 688 root->hit += period;
611 return 0; 689 root->count++;
690 return MATCH_EQ;
612 } 691 }
613 692
614 /* We match the node and still have a part remaining */ 693 /* We match the node and still have a part remaining */
615 append_chain_children(root, cursor, period); 694 if (append_chain_children(root, cursor, period) < 0)
695 return MATCH_ERROR;
616 696
617 return 0; 697 return MATCH_EQ;
618} 698}
619 699
620int callchain_append(struct callchain_root *root, 700int callchain_append(struct callchain_root *root,
@@ -626,7 +706,8 @@ int callchain_append(struct callchain_root *root,
626 706
627 callchain_cursor_commit(cursor); 707 callchain_cursor_commit(cursor);
628 708
629 append_chain_children(&root->node, cursor, period); 709 if (append_chain_children(&root->node, cursor, period) < 0)
710 return -1;
630 711
631 if (cursor->nr > root->max_depth) 712 if (cursor->nr > root->max_depth)
632 root->max_depth = cursor->nr; 713 root->max_depth = cursor->nr;
@@ -654,7 +735,8 @@ merge_chain_branch(struct callchain_cursor *cursor,
654 735
655 if (src->hit) { 736 if (src->hit) {
656 callchain_cursor_commit(cursor); 737 callchain_cursor_commit(cursor);
657 append_chain_children(dst, cursor, src->hit); 738 if (append_chain_children(dst, cursor, src->hit) < 0)
739 return -1;
658 } 740 }
659 741
660 n = rb_first(&src->rb_root_in); 742 n = rb_first(&src->rb_root_in);
@@ -799,12 +881,72 @@ char *callchain_list__sym_name(struct callchain_list *cl,
799 return bf; 881 return bf;
800} 882}
801 883
884char *callchain_node__scnprintf_value(struct callchain_node *node,
885 char *bf, size_t bfsize, u64 total)
886{
887 double percent = 0.0;
888 u64 period = callchain_cumul_hits(node);
889 unsigned count = callchain_cumul_counts(node);
890
891 if (callchain_param.mode == CHAIN_FOLDED) {
892 period = node->hit;
893 count = node->count;
894 }
895
896 switch (callchain_param.value) {
897 case CCVAL_PERIOD:
898 scnprintf(bf, bfsize, "%"PRIu64, period);
899 break;
900 case CCVAL_COUNT:
901 scnprintf(bf, bfsize, "%u", count);
902 break;
903 case CCVAL_PERCENT:
904 default:
905 if (total)
906 percent = period * 100.0 / total;
907 scnprintf(bf, bfsize, "%.2f%%", percent);
908 break;
909 }
910 return bf;
911}
912
913int callchain_node__fprintf_value(struct callchain_node *node,
914 FILE *fp, u64 total)
915{
916 double percent = 0.0;
917 u64 period = callchain_cumul_hits(node);
918 unsigned count = callchain_cumul_counts(node);
919
920 if (callchain_param.mode == CHAIN_FOLDED) {
921 period = node->hit;
922 count = node->count;
923 }
924
925 switch (callchain_param.value) {
926 case CCVAL_PERIOD:
927 return fprintf(fp, "%"PRIu64, period);
928 case CCVAL_COUNT:
929 return fprintf(fp, "%u", count);
930 case CCVAL_PERCENT:
931 default:
932 if (total)
933 percent = period * 100.0 / total;
934 return percent_color_fprintf(fp, "%.2f%%", percent);
935 }
936 return 0;
937}
938
802static void free_callchain_node(struct callchain_node *node) 939static void free_callchain_node(struct callchain_node *node)
803{ 940{
804 struct callchain_list *list, *tmp; 941 struct callchain_list *list, *tmp;
805 struct callchain_node *child; 942 struct callchain_node *child;
806 struct rb_node *n; 943 struct rb_node *n;
807 944
945 list_for_each_entry_safe(list, tmp, &node->parent_val, list) {
946 list_del(&list->list);
947 free(list);
948 }
949
808 list_for_each_entry_safe(list, tmp, &node->val, list) { 950 list_for_each_entry_safe(list, tmp, &node->val, list) {
809 list_del(&list->list); 951 list_del(&list->list);
810 free(list); 952 free(list);
@@ -828,3 +970,69 @@ void free_callchain(struct callchain_root *root)
828 970
829 free_callchain_node(&root->node); 971 free_callchain_node(&root->node);
830} 972}
973
974static u64 decay_callchain_node(struct callchain_node *node)
975{
976 struct callchain_node *child;
977 struct rb_node *n;
978 u64 child_hits = 0;
979
980 n = rb_first(&node->rb_root_in);
981 while (n) {
982 child = container_of(n, struct callchain_node, rb_node_in);
983
984 child_hits += decay_callchain_node(child);
985 n = rb_next(n);
986 }
987
988 node->hit = (node->hit * 7) / 8;
989 node->children_hit = child_hits;
990
991 return node->hit;
992}
993
994void decay_callchain(struct callchain_root *root)
995{
996 if (!symbol_conf.use_callchain)
997 return;
998
999 decay_callchain_node(&root->node);
1000}
1001
1002int callchain_node__make_parent_list(struct callchain_node *node)
1003{
1004 struct callchain_node *parent = node->parent;
1005 struct callchain_list *chain, *new;
1006 LIST_HEAD(head);
1007
1008 while (parent) {
1009 list_for_each_entry_reverse(chain, &parent->val, list) {
1010 new = malloc(sizeof(*new));
1011 if (new == NULL)
1012 goto out;
1013 *new = *chain;
1014 new->has_children = false;
1015 list_add_tail(&new->list, &head);
1016 }
1017 parent = parent->parent;
1018 }
1019
1020 list_for_each_entry_safe_reverse(chain, new, &head, list)
1021 list_move_tail(&chain->list, &node->parent_val);
1022
1023 if (!list_empty(&node->parent_val)) {
1024 chain = list_first_entry(&node->parent_val, struct callchain_list, list);
1025 chain->has_children = rb_prev(&node->rb_node) || rb_next(&node->rb_node);
1026
1027 chain = list_first_entry(&node->val, struct callchain_list, list);
1028 chain->has_children = false;
1029 }
1030 return 0;
1031
1032out:
1033 list_for_each_entry_safe(chain, new, &head, list) {
1034 list_del(&chain->list);
1035 free(chain);
1036 }
1037 return -ENOMEM;
1038}
diff --git a/tools/perf/util/callchain.h b/tools/perf/util/callchain.h
index fce8161e54db..d2a9e694810c 100644
--- a/tools/perf/util/callchain.h
+++ b/tools/perf/util/callchain.h
@@ -24,12 +24,13 @@
24#define CALLCHAIN_RECORD_HELP CALLCHAIN_HELP RECORD_MODE_HELP RECORD_SIZE_HELP 24#define CALLCHAIN_RECORD_HELP CALLCHAIN_HELP RECORD_MODE_HELP RECORD_SIZE_HELP
25 25
26#define CALLCHAIN_REPORT_HELP \ 26#define CALLCHAIN_REPORT_HELP \
27 HELP_PAD "print_type:\tcall graph printing style (graph|flat|fractal|none)\n" \ 27 HELP_PAD "print_type:\tcall graph printing style (graph|flat|fractal|folded|none)\n" \
28 HELP_PAD "threshold:\tminimum call graph inclusion threshold (<percent>)\n" \ 28 HELP_PAD "threshold:\tminimum call graph inclusion threshold (<percent>)\n" \
29 HELP_PAD "print_limit:\tmaximum number of call graph entry (<number>)\n" \ 29 HELP_PAD "print_limit:\tmaximum number of call graph entry (<number>)\n" \
30 HELP_PAD "order:\t\tcall graph order (caller|callee)\n" \ 30 HELP_PAD "order:\t\tcall graph order (caller|callee)\n" \
31 HELP_PAD "sort_key:\tcall graph sort key (function|address)\n" \ 31 HELP_PAD "sort_key:\tcall graph sort key (function|address)\n" \
32 HELP_PAD "branch:\t\tinclude last branch info to call graph (branch)\n" 32 HELP_PAD "branch:\t\tinclude last branch info to call graph (branch)\n" \
33 HELP_PAD "value:\t\tcall graph value (percent|period|count)\n"
33 34
34enum perf_call_graph_mode { 35enum perf_call_graph_mode {
35 CALLCHAIN_NONE, 36 CALLCHAIN_NONE,
@@ -43,7 +44,8 @@ enum chain_mode {
43 CHAIN_NONE, 44 CHAIN_NONE,
44 CHAIN_FLAT, 45 CHAIN_FLAT,
45 CHAIN_GRAPH_ABS, 46 CHAIN_GRAPH_ABS,
46 CHAIN_GRAPH_REL 47 CHAIN_GRAPH_REL,
48 CHAIN_FOLDED,
47}; 49};
48 50
49enum chain_order { 51enum chain_order {
@@ -54,11 +56,14 @@ enum chain_order {
54struct callchain_node { 56struct callchain_node {
55 struct callchain_node *parent; 57 struct callchain_node *parent;
56 struct list_head val; 58 struct list_head val;
59 struct list_head parent_val;
57 struct rb_node rb_node_in; /* to insert nodes in an rbtree */ 60 struct rb_node rb_node_in; /* to insert nodes in an rbtree */
58 struct rb_node rb_node; /* to sort nodes in an output tree */ 61 struct rb_node rb_node; /* to sort nodes in an output tree */
59 struct rb_root rb_root_in; /* input tree of children */ 62 struct rb_root rb_root_in; /* input tree of children */
60 struct rb_root rb_root; /* sorted output tree of children */ 63 struct rb_root rb_root; /* sorted output tree of children */
61 unsigned int val_nr; 64 unsigned int val_nr;
65 unsigned int count;
66 unsigned int children_count;
62 u64 hit; 67 u64 hit;
63 u64 children_hit; 68 u64 children_hit;
64}; 69};
@@ -78,6 +83,12 @@ enum chain_key {
78 CCKEY_ADDRESS 83 CCKEY_ADDRESS
79}; 84};
80 85
86enum chain_value {
87 CCVAL_PERCENT,
88 CCVAL_PERIOD,
89 CCVAL_COUNT,
90};
91
81struct callchain_param { 92struct callchain_param {
82 bool enabled; 93 bool enabled;
83 enum perf_call_graph_mode record_mode; 94 enum perf_call_graph_mode record_mode;
@@ -90,6 +101,7 @@ struct callchain_param {
90 bool order_set; 101 bool order_set;
91 enum chain_key key; 102 enum chain_key key;
92 bool branch_callstack; 103 bool branch_callstack;
104 enum chain_value value;
93}; 105};
94 106
95extern struct callchain_param callchain_param; 107extern struct callchain_param callchain_param;
@@ -131,6 +143,7 @@ extern __thread struct callchain_cursor callchain_cursor;
131static inline void callchain_init(struct callchain_root *root) 143static inline void callchain_init(struct callchain_root *root)
132{ 144{
133 INIT_LIST_HEAD(&root->node.val); 145 INIT_LIST_HEAD(&root->node.val);
146 INIT_LIST_HEAD(&root->node.parent_val);
134 147
135 root->node.parent = NULL; 148 root->node.parent = NULL;
136 root->node.hit = 0; 149 root->node.hit = 0;
@@ -144,6 +157,11 @@ static inline u64 callchain_cumul_hits(struct callchain_node *node)
144 return node->hit + node->children_hit; 157 return node->hit + node->children_hit;
145} 158}
146 159
160static inline unsigned callchain_cumul_counts(struct callchain_node *node)
161{
162 return node->count + node->children_count;
163}
164
147int callchain_register_param(struct callchain_param *param); 165int callchain_register_param(struct callchain_param *param);
148int callchain_append(struct callchain_root *root, 166int callchain_append(struct callchain_root *root,
149 struct callchain_cursor *cursor, 167 struct callchain_cursor *cursor,
@@ -202,7 +220,7 @@ int fill_callchain_info(struct addr_location *al, struct callchain_cursor_node *
202 bool hide_unresolved); 220 bool hide_unresolved);
203 221
204extern const char record_callchain_help[]; 222extern const char record_callchain_help[];
205extern int parse_callchain_record(const char *arg, struct callchain_param *param); 223int parse_callchain_record(const char *arg, struct callchain_param *param);
206int parse_callchain_record_opt(const char *arg, struct callchain_param *param); 224int parse_callchain_record_opt(const char *arg, struct callchain_param *param);
207int parse_callchain_report_opt(const char *arg); 225int parse_callchain_report_opt(const char *arg);
208int parse_callchain_top_opt(const char *arg); 226int parse_callchain_top_opt(const char *arg);
@@ -218,7 +236,7 @@ static inline void callchain_cursor_snapshot(struct callchain_cursor *dest,
218} 236}
219 237
220#ifdef HAVE_SKIP_CALLCHAIN_IDX 238#ifdef HAVE_SKIP_CALLCHAIN_IDX
221extern int arch_skip_callchain_idx(struct thread *thread, struct ip_callchain *chain); 239int arch_skip_callchain_idx(struct thread *thread, struct ip_callchain *chain);
222#else 240#else
223static inline int arch_skip_callchain_idx(struct thread *thread __maybe_unused, 241static inline int arch_skip_callchain_idx(struct thread *thread __maybe_unused,
224 struct ip_callchain *chain __maybe_unused) 242 struct ip_callchain *chain __maybe_unused)
@@ -229,7 +247,13 @@ static inline int arch_skip_callchain_idx(struct thread *thread __maybe_unused,
229 247
230char *callchain_list__sym_name(struct callchain_list *cl, 248char *callchain_list__sym_name(struct callchain_list *cl,
231 char *bf, size_t bfsize, bool show_dso); 249 char *bf, size_t bfsize, bool show_dso);
250char *callchain_node__scnprintf_value(struct callchain_node *node,
251 char *bf, size_t bfsize, u64 total);
252int callchain_node__fprintf_value(struct callchain_node *node,
253 FILE *fp, u64 total);
232 254
233void free_callchain(struct callchain_root *root); 255void free_callchain(struct callchain_root *root);
256void decay_callchain(struct callchain_root *root);
257int callchain_node__make_parent_list(struct callchain_node *node);
234 258
235#endif /* __PERF_CALLCHAIN_H */ 259#endif /* __PERF_CALLCHAIN_H */
diff --git a/tools/perf/util/cgroup.c b/tools/perf/util/cgroup.c
index 32e12ecfe9c5..90aa1b46b2e5 100644
--- a/tools/perf/util/cgroup.c
+++ b/tools/perf/util/cgroup.c
@@ -1,6 +1,6 @@
1#include "util.h" 1#include "util.h"
2#include "../perf.h" 2#include "../perf.h"
3#include "parse-options.h" 3#include <subcmd/parse-options.h>
4#include "evsel.h" 4#include "evsel.h"
5#include "cgroup.h" 5#include "cgroup.h"
6#include "evlist.h" 6#include "evlist.h"
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 9b9565416f90..43e84aa27e4a 100644
--- a/tools/perf/util/color.c
+++ b/tools/perf/util/color.c
@@ -24,7 +24,7 @@ int perf_config_colorbool(const char *var, const char *value, int stdout_is_tty)
24 auto_color: 24 auto_color:
25 if (stdout_is_tty < 0) 25 if (stdout_is_tty < 0)
26 stdout_is_tty = isatty(1); 26 stdout_is_tty = isatty(1);
27 if (stdout_is_tty || (pager_in_use() && pager_use_color)) { 27 if (stdout_is_tty || pager_in_use()) {
28 char *term = getenv("TERM"); 28 char *term = getenv("TERM");
29 if (term && strcmp(term, "dumb")) 29 if (term && strcmp(term, "dumb"))
30 return 1; 30 return 1;
@@ -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 2e452ac1353d..4e727635476e 100644
--- a/tools/perf/util/config.c
+++ b/tools/perf/util/config.c
@@ -10,7 +10,7 @@
10 */ 10 */
11#include "util.h" 11#include "util.h"
12#include "cache.h" 12#include "cache.h"
13#include "exec_cmd.h" 13#include <subcmd/exec-cmd.h>
14#include "util/hist.h" /* perf_hist_config */ 14#include "util/hist.h" /* perf_hist_config */
15#include "util/llvm-utils.h" /* perf_llvm_config */ 15#include "util/llvm-utils.h" /* perf_llvm_config */
16 16
@@ -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 10af1e7524fb..9bcf2bed3a6d 100644
--- a/tools/perf/util/cpumap.c
+++ b/tools/perf/util/cpumap.c
@@ -5,8 +5,13 @@
5#include <assert.h> 5#include <assert.h>
6#include <stdio.h> 6#include <stdio.h>
7#include <stdlib.h> 7#include <stdlib.h>
8#include <linux/bitmap.h>
8#include "asm/bug.h" 9#include "asm/bug.h"
9 10
11static int max_cpu_num;
12static int max_node_num;
13static int *cpunode_map;
14
10static struct cpu_map *cpu_map__default_new(void) 15static struct cpu_map *cpu_map__default_new(void)
11{ 16{
12 struct cpu_map *cpus; 17 struct cpu_map *cpus;
@@ -179,6 +184,56 @@ out:
179 return cpus; 184 return cpus;
180} 185}
181 186
187static struct cpu_map *cpu_map__from_entries(struct cpu_map_entries *cpus)
188{
189 struct cpu_map *map;
190
191 map = cpu_map__empty_new(cpus->nr);
192 if (map) {
193 unsigned i;
194
195 for (i = 0; i < cpus->nr; i++) {
196 /*
197 * Special treatment for -1, which is not real cpu number,
198 * and we need to use (int) -1 to initialize map[i],
199 * otherwise it would become 65535.
200 */
201 if (cpus->cpu[i] == (u16) -1)
202 map->map[i] = -1;
203 else
204 map->map[i] = (int) cpus->cpu[i];
205 }
206 }
207
208 return map;
209}
210
211static struct cpu_map *cpu_map__from_mask(struct cpu_map_mask *mask)
212{
213 struct cpu_map *map;
214 int nr, nbits = mask->nr * mask->long_size * BITS_PER_BYTE;
215
216 nr = bitmap_weight(mask->mask, nbits);
217
218 map = cpu_map__empty_new(nr);
219 if (map) {
220 int cpu, i = 0;
221
222 for_each_set_bit(cpu, mask->mask, nbits)
223 map->map[i++] = cpu;
224 }
225 return map;
226
227}
228
229struct cpu_map *cpu_map__new_data(struct cpu_map_data *data)
230{
231 if (data->type == PERF_CPU_MAP__CPUS)
232 return cpu_map__from_entries((struct cpu_map_entries *)data->data);
233 else
234 return cpu_map__from_mask((struct cpu_map_mask *)data->data);
235}
236
182size_t cpu_map__fprintf(struct cpu_map *map, FILE *fp) 237size_t cpu_map__fprintf(struct cpu_map *map, FILE *fp)
183{ 238{
184 int i; 239 int i;
@@ -435,6 +490,32 @@ out:
435 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);
436} 491}
437 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
438static int init_cpunode_map(void) 519static int init_cpunode_map(void)
439{ 520{
440 int i; 521 int i;
diff --git a/tools/perf/util/cpumap.h b/tools/perf/util/cpumap.h
index 85f7772457fa..81a2562aaa2b 100644
--- a/tools/perf/util/cpumap.h
+++ b/tools/perf/util/cpumap.h
@@ -17,6 +17,7 @@ struct cpu_map {
17struct cpu_map *cpu_map__new(const char *cpu_list); 17struct cpu_map *cpu_map__new(const char *cpu_list);
18struct cpu_map *cpu_map__empty_new(int nr); 18struct cpu_map *cpu_map__empty_new(int nr);
19struct cpu_map *cpu_map__dummy_new(void); 19struct cpu_map *cpu_map__dummy_new(void);
20struct cpu_map *cpu_map__new_data(struct cpu_map_data *data);
20struct cpu_map *cpu_map__read(FILE *file); 21struct cpu_map *cpu_map__read(FILE *file);
21size_t cpu_map__fprintf(struct cpu_map *map, FILE *fp); 22size_t cpu_map__fprintf(struct cpu_map *map, FILE *fp);
22int cpu_map__get_socket_id(int cpu); 23int cpu_map__get_socket_id(int cpu);
@@ -56,37 +57,11 @@ static inline bool cpu_map__empty(const struct cpu_map *map)
56 return map ? map->map[0] == -1 : true; 57 return map ? map->map[0] == -1 : true;
57} 58}
58 59
59int max_cpu_num;
60int max_node_num;
61int *cpunode_map;
62
63int cpu__setup_cpunode_map(void); 60int cpu__setup_cpunode_map(void);
64 61
65static inline int cpu__max_node(void) 62int cpu__max_node(void);
66{ 63int cpu__max_cpu(void);
67 if (unlikely(!max_node_num)) 64int cpu__get_node(int cpu);
68 pr_debug("cpu_map not initialized\n");
69
70 return max_node_num;
71}
72
73static inline int cpu__max_cpu(void)
74{
75 if (unlikely(!max_cpu_num))
76 pr_debug("cpu_map not initialized\n");
77
78 return max_cpu_num;
79}
80
81static inline int cpu__get_node(int cpu)
82{
83 if (unlikely(cpunode_map == NULL)) {
84 pr_debug("cpu_map not initialized\n");
85 return -1;
86 }
87
88 return cpunode_map[cpu];
89}
90 65
91int 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,
92 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 5bfc1198ab46..bbf69d248ec5 100644
--- a/tools/perf/util/data-convert-bt.c
+++ b/tools/perf/util/data-convert-bt.c
@@ -63,6 +63,7 @@ struct ctf_writer {
63 struct bt_ctf_field_type *s32; 63 struct bt_ctf_field_type *s32;
64 struct bt_ctf_field_type *u32; 64 struct bt_ctf_field_type *u32;
65 struct bt_ctf_field_type *string; 65 struct bt_ctf_field_type *string;
66 struct bt_ctf_field_type *u32_hex;
66 struct bt_ctf_field_type *u64_hex; 67 struct bt_ctf_field_type *u64_hex;
67 }; 68 };
68 struct bt_ctf_field_type *array[6]; 69 struct bt_ctf_field_type *array[6];
@@ -351,6 +352,84 @@ static int add_tracepoint_values(struct ctf_writer *cw,
351 return ret; 352 return ret;
352} 353}
353 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
354static int add_generic_values(struct ctf_writer *cw, 433static int add_generic_values(struct ctf_writer *cw,
355 struct bt_ctf_event *event, 434 struct bt_ctf_event *event,
356 struct perf_evsel *evsel, 435 struct perf_evsel *evsel,
@@ -553,7 +632,7 @@ static bool is_flush_needed(struct ctf_stream *cs)
553} 632}
554 633
555static int process_sample_event(struct perf_tool *tool, 634static int process_sample_event(struct perf_tool *tool,
556 union perf_event *_event __maybe_unused, 635 union perf_event *_event,
557 struct perf_sample *sample, 636 struct perf_sample *sample,
558 struct perf_evsel *evsel, 637 struct perf_evsel *evsel,
559 struct machine *machine __maybe_unused) 638 struct machine *machine __maybe_unused)
@@ -596,6 +675,12 @@ static int process_sample_event(struct perf_tool *tool,
596 return -1; 675 return -1;
597 } 676 }
598 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
599 cs = ctf_stream(cw, get_sample_cpu(cw, sample, evsel)); 684 cs = ctf_stream(cw, get_sample_cpu(cw, sample, evsel));
600 if (cs) { 685 if (cs) {
601 if (is_flush_needed(cs)) 686 if (is_flush_needed(cs))
@@ -743,6 +828,25 @@ static int add_tracepoint_types(struct ctf_writer *cw,
743 return ret; 828 return ret;
744} 829}
745 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
746static 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,
747 struct bt_ctf_event_class *event_class) 851 struct bt_ctf_event_class *event_class)
748{ 852{
@@ -754,7 +858,8 @@ static int add_generic_types(struct ctf_writer *cw, struct perf_evsel *evsel,
754 * ctf event header 858 * ctf event header
755 * PERF_SAMPLE_READ - TODO 859 * PERF_SAMPLE_READ - TODO
756 * PERF_SAMPLE_CALLCHAIN - TODO 860 * PERF_SAMPLE_CALLCHAIN - TODO
757 * PERF_SAMPLE_RAW - tracepoint fields are handled separately 861 * PERF_SAMPLE_RAW - tracepoint fields and BPF output
862 * are handled separately
758 * PERF_SAMPLE_BRANCH_STACK - TODO 863 * PERF_SAMPLE_BRANCH_STACK - TODO
759 * PERF_SAMPLE_REGS_USER - TODO 864 * PERF_SAMPLE_REGS_USER - TODO
760 * PERF_SAMPLE_STACK_USER - TODO 865 * PERF_SAMPLE_STACK_USER - TODO
@@ -823,6 +928,12 @@ static int add_event(struct ctf_writer *cw, struct perf_evsel *evsel)
823 goto err; 928 goto err;
824 } 929 }
825 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
826 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);
827 if (ret) { 938 if (ret) {
828 pr("Failed to add event class into stream.\n"); 939 pr("Failed to add event class into stream.\n");
@@ -857,6 +968,23 @@ static int setup_events(struct ctf_writer *cw, struct perf_session *session)
857 return 0; 968 return 0;
858} 969}
859 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
860static int setup_streams(struct ctf_writer *cw, struct perf_session *session) 988static int setup_streams(struct ctf_writer *cw, struct perf_session *session)
861{ 989{
862 struct ctf_stream **stream; 990 struct ctf_stream **stream;
@@ -952,6 +1080,12 @@ static struct bt_ctf_field_type *create_int_type(int size, bool sign, bool hex)
952 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))
953 goto err; 1081 goto err;
954 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
955 pr2("Created type: INTEGER %d-bit %ssigned %s\n", 1089 pr2("Created type: INTEGER %d-bit %ssigned %s\n",
956 size, sign ? "un" : "", hex ? "hex" : ""); 1090 size, sign ? "un" : "", hex ? "hex" : "");
957 return type; 1091 return type;
@@ -982,6 +1116,7 @@ do { \
982 CREATE_INT_TYPE(cw->data.u64, 64, false, false); 1116 CREATE_INT_TYPE(cw->data.u64, 64, false, false);
983 CREATE_INT_TYPE(cw->data.s32, 32, true, false); 1117 CREATE_INT_TYPE(cw->data.s32, 32, true, false);
984 CREATE_INT_TYPE(cw->data.u32, 32, false, false); 1118 CREATE_INT_TYPE(cw->data.u32, 32, false, false);
1119 CREATE_INT_TYPE(cw->data.u32_hex, 32, false, true);
985 CREATE_INT_TYPE(cw->data.u64_hex, 64, false, true); 1120 CREATE_INT_TYPE(cw->data.u64_hex, 64, false, true);
986 1121
987 cw->data.string = bt_ctf_field_type_string_create(); 1122 cw->data.string = bt_ctf_field_type_string_create();
@@ -1098,7 +1233,7 @@ static int convert__config(const char *var, const char *value, void *cb)
1098 return 0; 1233 return 0;
1099 } 1234 }
1100 1235
1101 return perf_default_config(var, value, cb); 1236 return 0;
1102} 1237}
1103 1238
1104int bt_convert__perf2ctf(const char *input, const char *path, bool force) 1239int bt_convert__perf2ctf(const char *input, const char *path, bool force)
@@ -1169,6 +1304,7 @@ int bt_convert__perf2ctf(const char *input, const char *path, bool force)
1169 (double) c.events_size / 1024.0 / 1024.0, 1304 (double) c.events_size / 1024.0 / 1024.0,
1170 c.events_count); 1305 c.events_count);
1171 1306
1307 cleanup_events(session);
1172 perf_session__delete(session); 1308 perf_session__delete(session);
1173 ctf_writer__cleanup(cw); 1309 ctf_writer__cleanup(cw);
1174 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 7c0c08386a1d..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 }
@@ -933,6 +938,7 @@ static struct dso *__dso__findlink_by_longname(struct rb_root *root,
933 /* Add new node and rebalance tree */ 938 /* Add new node and rebalance tree */
934 rb_link_node(&dso->rb_node, parent, p); 939 rb_link_node(&dso->rb_node, parent, p);
935 rb_insert_color(&dso->rb_node, root); 940 rb_insert_color(&dso->rb_node, root);
941 dso->root = root;
936 } 942 }
937 return NULL; 943 return NULL;
938} 944}
@@ -945,15 +951,30 @@ static inline struct dso *__dso__find_by_longname(struct rb_root *root,
945 951
946void dso__set_long_name(struct dso *dso, const char *name, bool name_allocated) 952void dso__set_long_name(struct dso *dso, const char *name, bool name_allocated)
947{ 953{
954 struct rb_root *root = dso->root;
955
948 if (name == NULL) 956 if (name == NULL)
949 return; 957 return;
950 958
951 if (dso->long_name_allocated) 959 if (dso->long_name_allocated)
952 free((char *)dso->long_name); 960 free((char *)dso->long_name);
953 961
962 if (root) {
963 rb_erase(&dso->rb_node, root);
964 /*
965 * __dso__findlink_by_longname() isn't guaranteed to add it
966 * back, so a clean removal is required here.
967 */
968 RB_CLEAR_NODE(&dso->rb_node);
969 dso->root = NULL;
970 }
971
954 dso->long_name = name; 972 dso->long_name = name;
955 dso->long_name_len = strlen(name); 973 dso->long_name_len = strlen(name);
956 dso->long_name_allocated = name_allocated; 974 dso->long_name_allocated = name_allocated;
975
976 if (root)
977 __dso__findlink_by_longname(root, dso, NULL);
957} 978}
958 979
959void dso__set_short_name(struct dso *dso, const char *name, bool name_allocated) 980void dso__set_short_name(struct dso *dso, const char *name, bool name_allocated)
@@ -1046,6 +1067,7 @@ struct dso *dso__new(const char *name)
1046 dso->kernel = DSO_TYPE_USER; 1067 dso->kernel = DSO_TYPE_USER;
1047 dso->needs_swap = DSO_SWAP__UNSET; 1068 dso->needs_swap = DSO_SWAP__UNSET;
1048 RB_CLEAR_NODE(&dso->rb_node); 1069 RB_CLEAR_NODE(&dso->rb_node);
1070 dso->root = NULL;
1049 INIT_LIST_HEAD(&dso->node); 1071 INIT_LIST_HEAD(&dso->node);
1050 INIT_LIST_HEAD(&dso->data.open_entry); 1072 INIT_LIST_HEAD(&dso->data.open_entry);
1051 pthread_mutex_init(&dso->lock, NULL); 1073 pthread_mutex_init(&dso->lock, NULL);
@@ -1226,6 +1248,8 @@ struct dso *__dsos__addnew(struct dsos *dsos, const char *name)
1226 if (dso != NULL) { 1248 if (dso != NULL) {
1227 __dsos__add(dsos, dso); 1249 __dsos__add(dsos, dso);
1228 dso__set_basename(dso); 1250 dso__set_basename(dso);
1251 /* Put dso here because __dsos_add already got it */
1252 dso__put(dso);
1229 } 1253 }
1230 return dso; 1254 return dso;
1231} 1255}
diff --git a/tools/perf/util/dso.h b/tools/perf/util/dso.h
index fc8db9c764ac..0953280629cf 100644
--- a/tools/perf/util/dso.h
+++ b/tools/perf/util/dso.h
@@ -135,6 +135,7 @@ struct dso {
135 pthread_mutex_t lock; 135 pthread_mutex_t lock;
136 struct list_head node; 136 struct list_head node;
137 struct rb_node rb_node; /* rbtree node sorted by long name */ 137 struct rb_node rb_node; /* rbtree node sorted by long name */
138 struct rb_root *root; /* root of rbtree that rb_node is in */
138 struct rb_root symbols[MAP__NR_TYPES]; 139 struct rb_root symbols[MAP__NR_TYPES];
139 struct rb_root symbol_names[MAP__NR_TYPES]; 140 struct rb_root symbol_names[MAP__NR_TYPES];
140 struct { 141 struct {
@@ -161,6 +162,7 @@ struct dso {
161 u8 loaded; 162 u8 loaded;
162 u8 rel; 163 u8 rel;
163 u8 build_id[BUILD_ID_SIZE]; 164 u8 build_id[BUILD_ID_SIZE];
165 u64 text_offset;
164 const char *short_name; 166 const char *short_name;
165 const char *long_name; 167 const char *long_name;
166 u16 long_name_len; 168 u16 long_name_len;
@@ -300,7 +302,7 @@ int __kmod_path__parse(struct kmod_path *m, const char *path,
300 * TODO 302 * TODO
301*/ 303*/
302int dso__data_get_fd(struct dso *dso, struct machine *machine); 304int dso__data_get_fd(struct dso *dso, struct machine *machine);
303void dso__data_put_fd(struct dso *dso __maybe_unused); 305void dso__data_put_fd(struct dso *dso);
304void dso__data_close(struct dso *dso); 306void dso__data_close(struct dso *dso);
305 307
306off_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 6af4f7c36820..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,21 +21,16 @@ 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[])
25{ 31{
26 int i; 32 int i;
27 33
28 /*
29 * If env->cmdline_argv has already been set, do not override it. This allows
30 * a command to set the cmdline, parse args and then call another
31 * builtin function that implements a command -- e.g, cmd_kvm calling
32 * cmd_record.
33 */
34 if (env->cmdline_argv != NULL)
35 return 0;
36
37 /* do not include NULL termination */ 34 /* do not include NULL termination */
38 env->cmdline_argv = calloc(argc, sizeof(char *)); 35 env->cmdline_argv = calloc(argc, sizeof(char *));
39 if (env->cmdline_argv == NULL) 36 if (env->cmdline_argv == NULL)
@@ -84,3 +81,10 @@ int perf_env__read_cpu_topology_map(struct perf_env *env)
84 env->nr_cpus_avail = nr_cpus; 81 env->nr_cpus_avail = nr_cpus;
85 return 0; 82 return 0;
86} 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/environment.c b/tools/perf/util/environment.c
deleted file mode 100644
index 7405123692f1..000000000000
--- a/tools/perf/util/environment.c
+++ /dev/null
@@ -1,8 +0,0 @@
1/*
2 * We put all the perf config variables in this same object
3 * file, so that programs can link against the config parser
4 * without having to link against all the rest of perf.
5 */
6#include "cache.h"
7
8int pager_use_color = 1;
diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c
index 8b10621b415c..dad55d04ffdd 100644
--- a/tools/perf/util/event.c
+++ b/tools/perf/util/event.c
@@ -10,6 +10,8 @@
10#include "thread.h" 10#include "thread.h"
11#include "thread_map.h" 11#include "thread_map.h"
12#include "symbol/kallsyms.h" 12#include "symbol/kallsyms.h"
13#include "asm/bug.h"
14#include "stat.h"
13 15
14static const char *perf_event__names[] = { 16static const char *perf_event__names[] = {
15 [0] = "TOTAL", 17 [0] = "TOTAL",
@@ -37,6 +39,12 @@ static const char *perf_event__names[] = {
37 [PERF_RECORD_AUXTRACE_INFO] = "AUXTRACE_INFO", 39 [PERF_RECORD_AUXTRACE_INFO] = "AUXTRACE_INFO",
38 [PERF_RECORD_AUXTRACE] = "AUXTRACE", 40 [PERF_RECORD_AUXTRACE] = "AUXTRACE",
39 [PERF_RECORD_AUXTRACE_ERROR] = "AUXTRACE_ERROR", 41 [PERF_RECORD_AUXTRACE_ERROR] = "AUXTRACE_ERROR",
42 [PERF_RECORD_THREAD_MAP] = "THREAD_MAP",
43 [PERF_RECORD_CPU_MAP] = "CPU_MAP",
44 [PERF_RECORD_STAT_CONFIG] = "STAT_CONFIG",
45 [PERF_RECORD_STAT] = "STAT",
46 [PERF_RECORD_STAT_ROUND] = "STAT_ROUND",
47 [PERF_RECORD_EVENT_UPDATE] = "EVENT_UPDATE",
40}; 48};
41 49
42const char *perf_event__name(unsigned int id) 50const char *perf_event__name(unsigned int id)
@@ -48,13 +56,22 @@ const char *perf_event__name(unsigned int id)
48 return perf_event__names[id]; 56 return perf_event__names[id];
49} 57}
50 58
51static 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 = {
52 .pid = -1, 65 .pid = -1,
53 .tid = -1, 66 .tid = -1,
54 .time = -1, 67 .time = -1,
55 .stream_id = -1, 68 .stream_id = -1,
56 .cpu = -1, 69 .cpu = -1,
57 .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);
58}; 75};
59 76
60/* 77/*
@@ -178,7 +195,7 @@ pid_t perf_event__synthesize_comm(struct perf_tool *tool,
178 if (perf_event__prepare_comm(event, pid, machine, &tgid, &ppid) != 0) 195 if (perf_event__prepare_comm(event, pid, machine, &tgid, &ppid) != 0)
179 return -1; 196 return -1;
180 197
181 if (process(tool, event, &synth_sample, machine) != 0) 198 if (perf_tool__process_synth_event(tool, event, machine, process) != 0)
182 return -1; 199 return -1;
183 200
184 return tgid; 201 return tgid;
@@ -210,7 +227,7 @@ static int perf_event__synthesize_fork(struct perf_tool *tool,
210 227
211 event->fork.header.size = (sizeof(event->fork) + machine->id_hdr_size); 228 event->fork.header.size = (sizeof(event->fork) + machine->id_hdr_size);
212 229
213 if (process(tool, event, &synth_sample, machine) != 0) 230 if (perf_tool__process_synth_event(tool, event, machine, process) != 0)
214 return -1; 231 return -1;
215 232
216 return 0; 233 return 0;
@@ -274,7 +291,7 @@ int perf_event__synthesize_mmap_events(struct perf_tool *tool,
274 strcpy(execname, ""); 291 strcpy(execname, "");
275 292
276 /* 00400000-0040c000 r-xp 00000000 fd:01 41038 /bin/cat */ 293 /* 00400000-0040c000 r-xp 00000000 fd:01 41038 /bin/cat */
277 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",
278 &event->mmap2.start, &event->mmap2.len, prot, 295 &event->mmap2.start, &event->mmap2.len, prot,
279 &event->mmap2.pgoff, &event->mmap2.maj, 296 &event->mmap2.pgoff, &event->mmap2.maj,
280 &event->mmap2.min, 297 &event->mmap2.min,
@@ -336,7 +353,7 @@ out:
336 event->mmap2.pid = tgid; 353 event->mmap2.pid = tgid;
337 event->mmap2.tid = pid; 354 event->mmap2.tid = pid;
338 355
339 if (process(tool, event, &synth_sample, machine) != 0) { 356 if (perf_tool__process_synth_event(tool, event, machine, process) != 0) {
340 rc = -1; 357 rc = -1;
341 break; 358 break;
342 } 359 }
@@ -394,7 +411,7 @@ int perf_event__synthesize_modules(struct perf_tool *tool,
394 411
395 memcpy(event->mmap.filename, pos->dso->long_name, 412 memcpy(event->mmap.filename, pos->dso->long_name,
396 pos->dso->long_name_len + 1); 413 pos->dso->long_name_len + 1);
397 if (process(tool, event, &synth_sample, machine) != 0) { 414 if (perf_tool__process_synth_event(tool, event, machine, process) != 0) {
398 rc = -1; 415 rc = -1;
399 break; 416 break;
400 } 417 }
@@ -464,7 +481,7 @@ static int __event__synthesize_thread(union perf_event *comm_event,
464 /* 481 /*
465 * Send the prepared comm event 482 * Send the prepared comm event
466 */ 483 */
467 if (process(tool, comm_event, &synth_sample, machine) != 0) 484 if (perf_tool__process_synth_event(tool, comm_event, machine, process) != 0)
468 break; 485 break;
469 486
470 rc = 0; 487 rc = 0;
@@ -495,7 +512,7 @@ int perf_event__synthesize_thread_map(struct perf_tool *tool,
495 if (comm_event == NULL) 512 if (comm_event == NULL)
496 goto out; 513 goto out;
497 514
498 mmap_event = malloc(sizeof(mmap_event->mmap) + machine->id_hdr_size); 515 mmap_event = malloc(sizeof(mmap_event->mmap2) + machine->id_hdr_size);
499 if (mmap_event == NULL) 516 if (mmap_event == NULL)
500 goto out_free_comm; 517 goto out_free_comm;
501 518
@@ -569,7 +586,7 @@ int perf_event__synthesize_threads(struct perf_tool *tool,
569 if (comm_event == NULL) 586 if (comm_event == NULL)
570 goto out; 587 goto out;
571 588
572 mmap_event = malloc(sizeof(mmap_event->mmap) + machine->id_hdr_size); 589 mmap_event = malloc(sizeof(mmap_event->mmap2) + machine->id_hdr_size);
573 if (mmap_event == NULL) 590 if (mmap_event == NULL)
574 goto out_free_comm; 591 goto out_free_comm;
575 592
@@ -693,12 +710,280 @@ int perf_event__synthesize_kernel_mmap(struct perf_tool *tool,
693 event->mmap.len = map->end - event->mmap.start; 710 event->mmap.len = map->end - event->mmap.start;
694 event->mmap.pid = machine->pid; 711 event->mmap.pid = machine->pid;
695 712
696 err = process(tool, event, &synth_sample, machine); 713 err = perf_tool__process_synth_event(tool, event, machine, process);
697 free(event); 714 free(event);
698 715
699 return err; 716 return err;
700} 717}
701 718
719int perf_event__synthesize_thread_map2(struct perf_tool *tool,
720 struct thread_map *threads,
721 perf_event__handler_t process,
722 struct machine *machine)
723{
724 union perf_event *event;
725 int i, err, size;
726
727 size = sizeof(event->thread_map);
728 size += threads->nr * sizeof(event->thread_map.entries[0]);
729
730 event = zalloc(size);
731 if (!event)
732 return -ENOMEM;
733
734 event->header.type = PERF_RECORD_THREAD_MAP;
735 event->header.size = size;
736 event->thread_map.nr = threads->nr;
737
738 for (i = 0; i < threads->nr; i++) {
739 struct thread_map_event_entry *entry = &event->thread_map.entries[i];
740 char *comm = thread_map__comm(threads, i);
741
742 if (!comm)
743 comm = (char *) "";
744
745 entry->pid = thread_map__pid(threads, i);
746 strncpy((char *) &entry->comm, comm, sizeof(entry->comm));
747 }
748
749 err = process(tool, event, NULL, machine);
750
751 free(event);
752 return err;
753}
754
755static void synthesize_cpus(struct cpu_map_entries *cpus,
756 struct cpu_map *map)
757{
758 int i;
759
760 cpus->nr = map->nr;
761
762 for (i = 0; i < map->nr; i++)
763 cpus->cpu[i] = map->map[i];
764}
765
766static void synthesize_mask(struct cpu_map_mask *mask,
767 struct cpu_map *map, int max)
768{
769 int i;
770
771 mask->nr = BITS_TO_LONGS(max);
772 mask->long_size = sizeof(long);
773
774 for (i = 0; i < map->nr; i++)
775 set_bit(map->map[i], mask->mask);
776}
777
778static size_t cpus_size(struct cpu_map *map)
779{
780 return sizeof(struct cpu_map_entries) + map->nr * sizeof(u16);
781}
782
783static size_t mask_size(struct cpu_map *map, int *max)
784{
785 int i;
786
787 *max = 0;
788
789 for (i = 0; i < map->nr; i++) {
790 /* bit possition of the cpu is + 1 */
791 int bit = map->map[i] + 1;
792
793 if (bit > *max)
794 *max = bit;
795 }
796
797 return sizeof(struct cpu_map_mask) + BITS_TO_LONGS(*max) * sizeof(long);
798}
799
800void *cpu_map_data__alloc(struct cpu_map *map, size_t *size, u16 *type, int *max)
801{
802 size_t size_cpus, size_mask;
803 bool is_dummy = cpu_map__empty(map);
804
805 /*
806 * Both array and mask data have variable size based
807 * on the number of cpus and their actual values.
808 * The size of the 'struct cpu_map_data' is:
809 *
810 * array = size of 'struct cpu_map_entries' +
811 * number of cpus * sizeof(u64)
812 *
813 * mask = size of 'struct cpu_map_mask' +
814 * maximum cpu bit converted to size of longs
815 *
816 * and finaly + the size of 'struct cpu_map_data'.
817 */
818 size_cpus = cpus_size(map);
819 size_mask = mask_size(map, max);
820
821 if (is_dummy || (size_cpus < size_mask)) {
822 *size += size_cpus;
823 *type = PERF_CPU_MAP__CPUS;
824 } else {
825 *size += size_mask;
826 *type = PERF_CPU_MAP__MASK;
827 }
828
829 *size += sizeof(struct cpu_map_data);
830 return zalloc(*size);
831}
832
833void cpu_map_data__synthesize(struct cpu_map_data *data, struct cpu_map *map,
834 u16 type, int max)
835{
836 data->type = type;
837
838 switch (type) {
839 case PERF_CPU_MAP__CPUS:
840 synthesize_cpus((struct cpu_map_entries *) data->data, map);
841 break;
842 case PERF_CPU_MAP__MASK:
843 synthesize_mask((struct cpu_map_mask *) data->data, map, max);
844 default:
845 break;
846 };
847}
848
849static struct cpu_map_event* cpu_map_event__new(struct cpu_map *map)
850{
851 size_t size = sizeof(struct cpu_map_event);
852 struct cpu_map_event *event;
853 int max;
854 u16 type;
855
856 event = cpu_map_data__alloc(map, &size, &type, &max);
857 if (!event)
858 return NULL;
859
860 event->header.type = PERF_RECORD_CPU_MAP;
861 event->header.size = size;
862 event->data.type = type;
863
864 cpu_map_data__synthesize(&event->data, map, type, max);
865 return event;
866}
867
868int perf_event__synthesize_cpu_map(struct perf_tool *tool,
869 struct cpu_map *map,
870 perf_event__handler_t process,
871 struct machine *machine)
872{
873 struct cpu_map_event *event;
874 int err;
875
876 event = cpu_map_event__new(map);
877 if (!event)
878 return -ENOMEM;
879
880 err = process(tool, (union perf_event *) event, NULL, machine);
881
882 free(event);
883 return err;
884}
885
886int perf_event__synthesize_stat_config(struct perf_tool *tool,
887 struct perf_stat_config *config,
888 perf_event__handler_t process,
889 struct machine *machine)
890{
891 struct stat_config_event *event;
892 int size, i = 0, err;
893
894 size = sizeof(*event);
895 size += (PERF_STAT_CONFIG_TERM__MAX * sizeof(event->data[0]));
896
897 event = zalloc(size);
898 if (!event)
899 return -ENOMEM;
900
901 event->header.type = PERF_RECORD_STAT_CONFIG;
902 event->header.size = size;
903 event->nr = PERF_STAT_CONFIG_TERM__MAX;
904
905#define ADD(__term, __val) \
906 event->data[i].tag = PERF_STAT_CONFIG_TERM__##__term; \
907 event->data[i].val = __val; \
908 i++;
909
910 ADD(AGGR_MODE, config->aggr_mode)
911 ADD(INTERVAL, config->interval)
912 ADD(SCALE, config->scale)
913
914 WARN_ONCE(i != PERF_STAT_CONFIG_TERM__MAX,
915 "stat config terms unbalanced\n");
916#undef ADD
917
918 err = process(tool, (union perf_event *) event, NULL, machine);
919
920 free(event);
921 return err;
922}
923
924int perf_event__synthesize_stat(struct perf_tool *tool,
925 u32 cpu, u32 thread, u64 id,
926 struct perf_counts_values *count,
927 perf_event__handler_t process,
928 struct machine *machine)
929{
930 struct stat_event event;
931
932 event.header.type = PERF_RECORD_STAT;
933 event.header.size = sizeof(event);
934 event.header.misc = 0;
935
936 event.id = id;
937 event.cpu = cpu;
938 event.thread = thread;
939 event.val = count->val;
940 event.ena = count->ena;
941 event.run = count->run;
942
943 return process(tool, (union perf_event *) &event, NULL, machine);
944}
945
946int perf_event__synthesize_stat_round(struct perf_tool *tool,
947 u64 evtime, u64 type,
948 perf_event__handler_t process,
949 struct machine *machine)
950{
951 struct stat_round_event event;
952
953 event.header.type = PERF_RECORD_STAT_ROUND;
954 event.header.size = sizeof(event);
955 event.header.misc = 0;
956
957 event.time = evtime;
958 event.type = type;
959
960 return process(tool, (union perf_event *) &event, NULL, machine);
961}
962
963void perf_event__read_stat_config(struct perf_stat_config *config,
964 struct stat_config_event *event)
965{
966 unsigned i;
967
968 for (i = 0; i < event->nr; i++) {
969
970 switch (event->data[i].tag) {
971#define CASE(__term, __val) \
972 case PERF_STAT_CONFIG_TERM__##__term: \
973 config->__val = event->data[i].val; \
974 break;
975
976 CASE(AGGR_MODE, aggr_mode)
977 CASE(SCALE, scale)
978 CASE(INTERVAL, interval)
979#undef CASE
980 default:
981 pr_warning("unknown stat config term %" PRIu64 "\n",
982 event->data[i].tag);
983 }
984 }
985}
986
702size_t perf_event__fprintf_comm(union perf_event *event, FILE *fp) 987size_t perf_event__fprintf_comm(union perf_event *event, FILE *fp)
703{ 988{
704 const char *s; 989 const char *s;
@@ -783,6 +1068,38 @@ size_t perf_event__fprintf_mmap2(union perf_event *event, FILE *fp)
783 event->mmap2.filename); 1068 event->mmap2.filename);
784} 1069}
785 1070
1071size_t perf_event__fprintf_thread_map(union perf_event *event, FILE *fp)
1072{
1073 struct thread_map *threads = thread_map__new_event(&event->thread_map);
1074 size_t ret;
1075
1076 ret = fprintf(fp, " nr: ");
1077
1078 if (threads)
1079 ret += thread_map__fprintf(threads, fp);
1080 else
1081 ret += fprintf(fp, "failed to get threads from event\n");
1082
1083 thread_map__put(threads);
1084 return ret;
1085}
1086
1087size_t perf_event__fprintf_cpu_map(union perf_event *event, FILE *fp)
1088{
1089 struct cpu_map *cpus = cpu_map__new_data(&event->cpu_map.data);
1090 size_t ret;
1091
1092 ret = fprintf(fp, " nr: ");
1093
1094 if (cpus)
1095 ret += cpu_map__fprintf(cpus, fp);
1096 else
1097 ret += fprintf(fp, "failed to get cpumap from event\n");
1098
1099 cpu_map__put(cpus);
1100 return ret;
1101}
1102
786int perf_event__process_mmap(struct perf_tool *tool __maybe_unused, 1103int perf_event__process_mmap(struct perf_tool *tool __maybe_unused,
787 union perf_event *event, 1104 union perf_event *event,
788 struct perf_sample *sample, 1105 struct perf_sample *sample,
@@ -987,12 +1304,9 @@ void thread__find_addr_location(struct thread *thread,
987 * Callers need to drop the reference to al->thread, obtained in 1304 * Callers need to drop the reference to al->thread, obtained in
988 * machine__findnew_thread() 1305 * machine__findnew_thread()
989 */ 1306 */
990int perf_event__preprocess_sample(const union perf_event *event, 1307int machine__resolve(struct machine *machine, struct addr_location *al,
991 struct machine *machine, 1308 struct perf_sample *sample)
992 struct addr_location *al,
993 struct perf_sample *sample)
994{ 1309{
995 u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
996 struct thread *thread = machine__findnew_thread(machine, sample->pid, 1310 struct thread *thread = machine__findnew_thread(machine, sample->pid,
997 sample->tid); 1311 sample->tid);
998 1312
@@ -1007,11 +1321,11 @@ int perf_event__preprocess_sample(const union perf_event *event,
1007 * 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
1008 * it now. 1322 * it now.
1009 */ 1323 */
1010 if (cpumode == PERF_RECORD_MISC_KERNEL && 1324 if (sample->cpumode == PERF_RECORD_MISC_KERNEL &&
1011 machine__kernel_map(machine) == NULL) 1325 machine__kernel_map(machine) == NULL)
1012 machine__create_kernel_maps(machine); 1326 machine__create_kernel_maps(machine);
1013 1327
1014 thread__find_addr_map(thread, cpumode, MAP__FUNCTION, sample->ip, al); 1328 thread__find_addr_map(thread, sample->cpumode, MAP__FUNCTION, sample->ip, al);
1015 dump_printf(" ...... dso: %s\n", 1329 dump_printf(" ...... dso: %s\n",
1016 al->map ? al->map->dso->long_name : 1330 al->map ? al->map->dso->long_name :
1017 al->level == 'H' ? "[hypervisor]" : "<not found>"); 1331 al->level == 'H' ? "[hypervisor]" : "<not found>");
@@ -1087,16 +1401,12 @@ bool sample_addr_correlates_sym(struct perf_event_attr *attr)
1087 return false; 1401 return false;
1088} 1402}
1089 1403
1090void perf_event__preprocess_sample_addr(union perf_event *event, 1404void thread__resolve(struct thread *thread, struct addr_location *al,
1091 struct perf_sample *sample, 1405 struct perf_sample *sample)
1092 struct thread *thread,
1093 struct addr_location *al)
1094{ 1406{
1095 u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; 1407 thread__find_addr_map(thread, sample->cpumode, MAP__FUNCTION, sample->addr, al);
1096
1097 thread__find_addr_map(thread, cpumode, MAP__FUNCTION, sample->addr, al);
1098 if (!al->map) 1408 if (!al->map)
1099 thread__find_addr_map(thread, cpumode, MAP__VARIABLE, 1409 thread__find_addr_map(thread, sample->cpumode, MAP__VARIABLE,
1100 sample->addr, al); 1410 sample->addr, al);
1101 1411
1102 al->cpu = sample->cpu; 1412 al->cpu = sample->cpu;
diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h
index a0dbcbd4f6d8..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;
@@ -226,6 +227,12 @@ enum perf_user_event_type { /* above any possible kernel type */
226 PERF_RECORD_AUXTRACE_INFO = 70, 227 PERF_RECORD_AUXTRACE_INFO = 70,
227 PERF_RECORD_AUXTRACE = 71, 228 PERF_RECORD_AUXTRACE = 71,
228 PERF_RECORD_AUXTRACE_ERROR = 72, 229 PERF_RECORD_AUXTRACE_ERROR = 72,
230 PERF_RECORD_THREAD_MAP = 73,
231 PERF_RECORD_CPU_MAP = 74,
232 PERF_RECORD_STAT_CONFIG = 75,
233 PERF_RECORD_STAT = 76,
234 PERF_RECORD_STAT_ROUND = 77,
235 PERF_RECORD_EVENT_UPDATE = 78,
229 PERF_RECORD_HEADER_MAX 236 PERF_RECORD_HEADER_MAX
230}; 237};
231 238
@@ -270,12 +277,61 @@ struct events_stats {
270 u32 nr_proc_map_timeout; 277 u32 nr_proc_map_timeout;
271}; 278};
272 279
280enum {
281 PERF_CPU_MAP__CPUS = 0,
282 PERF_CPU_MAP__MASK = 1,
283};
284
285struct cpu_map_entries {
286 u16 nr;
287 u16 cpu[];
288};
289
290struct cpu_map_mask {
291 u16 nr;
292 u16 long_size;
293 unsigned long mask[];
294};
295
296struct cpu_map_data {
297 u16 type;
298 char data[];
299};
300
301struct cpu_map_event {
302 struct perf_event_header header;
303 struct cpu_map_data data;
304};
305
273struct attr_event { 306struct attr_event {
274 struct perf_event_header header; 307 struct perf_event_header header;
275 struct perf_event_attr attr; 308 struct perf_event_attr attr;
276 u64 id[]; 309 u64 id[];
277}; 310};
278 311
312enum {
313 PERF_EVENT_UPDATE__UNIT = 0,
314 PERF_EVENT_UPDATE__SCALE = 1,
315 PERF_EVENT_UPDATE__NAME = 2,
316 PERF_EVENT_UPDATE__CPUS = 3,
317};
318
319struct event_update_event_cpus {
320 struct cpu_map_data cpus;
321};
322
323struct event_update_event_scale {
324 double scale;
325};
326
327struct event_update_event {
328 struct perf_event_header header;
329 u64 type;
330 u64 id;
331
332 char data[];
333};
334
279#define MAX_EVENT_NAME 64 335#define MAX_EVENT_NAME 64
280 336
281struct perf_trace_event_type { 337struct perf_trace_event_type {
@@ -356,6 +412,63 @@ struct context_switch_event {
356 u32 next_prev_tid; 412 u32 next_prev_tid;
357}; 413};
358 414
415struct thread_map_event_entry {
416 u64 pid;
417 char comm[16];
418};
419
420struct thread_map_event {
421 struct perf_event_header header;
422 u64 nr;
423 struct thread_map_event_entry entries[];
424};
425
426enum {
427 PERF_STAT_CONFIG_TERM__AGGR_MODE = 0,
428 PERF_STAT_CONFIG_TERM__INTERVAL = 1,
429 PERF_STAT_CONFIG_TERM__SCALE = 2,
430 PERF_STAT_CONFIG_TERM__MAX = 3,
431};
432
433struct stat_config_event_entry {
434 u64 tag;
435 u64 val;
436};
437
438struct stat_config_event {
439 struct perf_event_header header;
440 u64 nr;
441 struct stat_config_event_entry data[];
442};
443
444struct stat_event {
445 struct perf_event_header header;
446
447 u64 id;
448 u32 cpu;
449 u32 thread;
450
451 union {
452 struct {
453 u64 val;
454 u64 ena;
455 u64 run;
456 };
457 u64 values[3];
458 };
459};
460
461enum {
462 PERF_STAT_ROUND_TYPE__INTERVAL = 0,
463 PERF_STAT_ROUND_TYPE__FINAL = 1,
464};
465
466struct stat_round_event {
467 struct perf_event_header header;
468 u64 type;
469 u64 time;
470};
471
359union perf_event { 472union perf_event {
360 struct perf_event_header header; 473 struct perf_event_header header;
361 struct mmap_event mmap; 474 struct mmap_event mmap;
@@ -368,6 +481,7 @@ union perf_event {
368 struct throttle_event throttle; 481 struct throttle_event throttle;
369 struct sample_event sample; 482 struct sample_event sample;
370 struct attr_event attr; 483 struct attr_event attr;
484 struct event_update_event event_update;
371 struct event_type_event event_type; 485 struct event_type_event event_type;
372 struct tracing_data_event tracing_data; 486 struct tracing_data_event tracing_data;
373 struct build_id_event build_id; 487 struct build_id_event build_id;
@@ -378,12 +492,20 @@ union perf_event {
378 struct aux_event aux; 492 struct aux_event aux;
379 struct itrace_start_event itrace_start; 493 struct itrace_start_event itrace_start;
380 struct context_switch_event context_switch; 494 struct context_switch_event context_switch;
495 struct thread_map_event thread_map;
496 struct cpu_map_event cpu_map;
497 struct stat_config_event stat_config;
498 struct stat_event stat;
499 struct stat_round_event stat_round;
381}; 500};
382 501
383void perf_event__print_totals(void); 502void perf_event__print_totals(void);
384 503
385struct perf_tool; 504struct perf_tool;
386struct thread_map; 505struct thread_map;
506struct cpu_map;
507struct perf_stat_config;
508struct perf_counts_values;
387 509
388typedef int (*perf_event__handler_t)(struct perf_tool *tool, 510typedef int (*perf_event__handler_t)(struct perf_tool *tool,
389 union perf_event *event, 511 union perf_event *event,
@@ -395,6 +517,14 @@ int perf_event__synthesize_thread_map(struct perf_tool *tool,
395 perf_event__handler_t process, 517 perf_event__handler_t process,
396 struct machine *machine, bool mmap_data, 518 struct machine *machine, bool mmap_data,
397 unsigned int proc_map_timeout); 519 unsigned int proc_map_timeout);
520int perf_event__synthesize_thread_map2(struct perf_tool *tool,
521 struct thread_map *threads,
522 perf_event__handler_t process,
523 struct machine *machine);
524int perf_event__synthesize_cpu_map(struct perf_tool *tool,
525 struct cpu_map *cpus,
526 perf_event__handler_t process,
527 struct machine *machine);
398int perf_event__synthesize_threads(struct perf_tool *tool, 528int perf_event__synthesize_threads(struct perf_tool *tool,
399 perf_event__handler_t process, 529 perf_event__handler_t process,
400 struct machine *machine, bool mmap_data, 530 struct machine *machine, bool mmap_data,
@@ -402,7 +532,21 @@ int perf_event__synthesize_threads(struct perf_tool *tool,
402int perf_event__synthesize_kernel_mmap(struct perf_tool *tool, 532int perf_event__synthesize_kernel_mmap(struct perf_tool *tool,
403 perf_event__handler_t process, 533 perf_event__handler_t process,
404 struct machine *machine); 534 struct machine *machine);
405 535int perf_event__synthesize_stat_config(struct perf_tool *tool,
536 struct perf_stat_config *config,
537 perf_event__handler_t process,
538 struct machine *machine);
539void perf_event__read_stat_config(struct perf_stat_config *config,
540 struct stat_config_event *event);
541int perf_event__synthesize_stat(struct perf_tool *tool,
542 u32 cpu, u32 thread, u64 id,
543 struct perf_counts_values *count,
544 perf_event__handler_t process,
545 struct machine *machine);
546int perf_event__synthesize_stat_round(struct perf_tool *tool,
547 u64 time, u64 type,
548 perf_event__handler_t process,
549 struct machine *machine);
406int perf_event__synthesize_modules(struct perf_tool *tool, 550int perf_event__synthesize_modules(struct perf_tool *tool,
407 perf_event__handler_t process, 551 perf_event__handler_t process,
408 struct machine *machine); 552 struct machine *machine);
@@ -454,10 +598,8 @@ int perf_event__process(struct perf_tool *tool,
454 598
455struct addr_location; 599struct addr_location;
456 600
457int perf_event__preprocess_sample(const union perf_event *event, 601int machine__resolve(struct machine *machine, struct addr_location *al,
458 struct machine *machine, 602 struct perf_sample *sample);
459 struct addr_location *al,
460 struct perf_sample *sample);
461 603
462void addr_location__put(struct addr_location *al); 604void addr_location__put(struct addr_location *al);
463 605
@@ -465,10 +607,8 @@ struct thread;
465 607
466bool is_bts_event(struct perf_event_attr *attr); 608bool is_bts_event(struct perf_event_attr *attr);
467bool sample_addr_correlates_sym(struct perf_event_attr *attr); 609bool sample_addr_correlates_sym(struct perf_event_attr *attr);
468void perf_event__preprocess_sample_addr(union perf_event *event, 610void thread__resolve(struct thread *thread, struct addr_location *al,
469 struct perf_sample *sample, 611 struct perf_sample *sample);
470 struct thread *thread,
471 struct addr_location *al);
472 612
473const char *perf_event__name(unsigned int id); 613const char *perf_event__name(unsigned int id);
474 614
@@ -499,9 +639,14 @@ size_t perf_event__fprintf_task(union perf_event *event, FILE *fp);
499size_t perf_event__fprintf_aux(union perf_event *event, FILE *fp); 639size_t perf_event__fprintf_aux(union perf_event *event, FILE *fp);
500size_t perf_event__fprintf_itrace_start(union perf_event *event, FILE *fp); 640size_t perf_event__fprintf_itrace_start(union perf_event *event, FILE *fp);
501size_t perf_event__fprintf_switch(union perf_event *event, FILE *fp); 641size_t perf_event__fprintf_switch(union perf_event *event, FILE *fp);
642size_t perf_event__fprintf_thread_map(union perf_event *event, FILE *fp);
643size_t perf_event__fprintf_cpu_map(union perf_event *event, FILE *fp);
502size_t perf_event__fprintf(union perf_event *event, FILE *fp); 644size_t perf_event__fprintf(union perf_event *event, FILE *fp);
503 645
504u64 kallsyms__get_function_start(const char *kallsyms_filename, 646u64 kallsyms__get_function_start(const char *kallsyms_filename,
505 const char *symbol_name); 647 const char *symbol_name);
506 648
649void *cpu_map_data__alloc(struct cpu_map *map, size_t *size, u16 *type, int *max);
650void cpu_map_data__synthesize(struct cpu_map_data *data, struct cpu_map *map,
651 u16 type, int max);
507#endif /* __PERF_RECORD_H */ 652#endif /* __PERF_RECORD_H */
diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c
index d1392194a9a9..86a03836a83f 100644
--- a/tools/perf/util/evlist.c
+++ b/tools/perf/util/evlist.c
@@ -18,7 +18,7 @@
18#include <unistd.h> 18#include <unistd.h>
19 19
20#include "parse-events.h" 20#include "parse-events.h"
21#include "parse-options.h" 21#include <subcmd/parse-options.h>
22 22
23#include <sys/mman.h> 23#include <sys/mman.h>
24 24
@@ -68,6 +68,18 @@ struct perf_evlist *perf_evlist__new_default(void)
68 return evlist; 68 return evlist;
69} 69}
70 70
71struct perf_evlist *perf_evlist__new_dummy(void)
72{
73 struct perf_evlist *evlist = perf_evlist__new();
74
75 if (evlist && perf_evlist__add_dummy(evlist)) {
76 perf_evlist__delete(evlist);
77 evlist = NULL;
78 }
79
80 return evlist;
81}
82
71/** 83/**
72 * perf_evlist__set_id_pos - set the positions of event ids. 84 * perf_evlist__set_id_pos - set the positions of event ids.
73 * @evlist: selected event list 85 * @evlist: selected event list
@@ -248,6 +260,22 @@ error:
248 return -ENOMEM; 260 return -ENOMEM;
249} 261}
250 262
263int perf_evlist__add_dummy(struct perf_evlist *evlist)
264{
265 struct perf_event_attr attr = {
266 .type = PERF_TYPE_SOFTWARE,
267 .config = PERF_COUNT_SW_DUMMY,
268 .size = sizeof(attr), /* to capture ABI version */
269 };
270 struct perf_evsel *evsel = perf_evsel__new(&attr);
271
272 if (evsel == NULL)
273 return -ENOMEM;
274
275 perf_evlist__add(evlist, evsel);
276 return 0;
277}
278
251static int perf_evlist__add_attrs(struct perf_evlist *evlist, 279static int perf_evlist__add_attrs(struct perf_evlist *evlist,
252 struct perf_event_attr *attrs, size_t nr_attrs) 280 struct perf_event_attr *attrs, size_t nr_attrs)
253{ 281{
@@ -336,20 +364,12 @@ static int perf_evlist__nr_threads(struct perf_evlist *evlist,
336 364
337void perf_evlist__disable(struct perf_evlist *evlist) 365void perf_evlist__disable(struct perf_evlist *evlist)
338{ 366{
339 int cpu, thread;
340 struct perf_evsel *pos; 367 struct perf_evsel *pos;
341 int nr_cpus = cpu_map__nr(evlist->cpus);
342 int nr_threads;
343 368
344 for (cpu = 0; cpu < nr_cpus; cpu++) { 369 evlist__for_each(evlist, pos) {
345 evlist__for_each(evlist, pos) { 370 if (!perf_evsel__is_group_leader(pos) || !pos->fd)
346 if (!perf_evsel__is_group_leader(pos) || !pos->fd) 371 continue;
347 continue; 372 perf_evsel__disable(pos);
348 nr_threads = perf_evlist__nr_threads(evlist, pos);
349 for (thread = 0; thread < nr_threads; thread++)
350 ioctl(FD(pos, cpu, thread),
351 PERF_EVENT_IOC_DISABLE, 0);
352 }
353 } 373 }
354 374
355 evlist->enabled = false; 375 evlist->enabled = false;
@@ -357,20 +377,12 @@ void perf_evlist__disable(struct perf_evlist *evlist)
357 377
358void perf_evlist__enable(struct perf_evlist *evlist) 378void perf_evlist__enable(struct perf_evlist *evlist)
359{ 379{
360 int cpu, thread;
361 struct perf_evsel *pos; 380 struct perf_evsel *pos;
362 int nr_cpus = cpu_map__nr(evlist->cpus);
363 int nr_threads;
364 381
365 for (cpu = 0; cpu < nr_cpus; cpu++) { 382 evlist__for_each(evlist, pos) {
366 evlist__for_each(evlist, pos) { 383 if (!perf_evsel__is_group_leader(pos) || !pos->fd)
367 if (!perf_evsel__is_group_leader(pos) || !pos->fd) 384 continue;
368 continue; 385 perf_evsel__enable(pos);
369 nr_threads = perf_evlist__nr_threads(evlist, pos);
370 for (thread = 0; thread < nr_threads; thread++)
371 ioctl(FD(pos, cpu, thread),
372 PERF_EVENT_IOC_ENABLE, 0);
373 }
374 } 386 }
375 387
376 evlist->enabled = true; 388 evlist->enabled = true;
@@ -381,48 +393,6 @@ void perf_evlist__toggle_enable(struct perf_evlist *evlist)
381 (evlist->enabled ? perf_evlist__disable : perf_evlist__enable)(evlist); 393 (evlist->enabled ? perf_evlist__disable : perf_evlist__enable)(evlist);
382} 394}
383 395
384int perf_evlist__disable_event(struct perf_evlist *evlist,
385 struct perf_evsel *evsel)
386{
387 int cpu, thread, err;
388 int nr_cpus = cpu_map__nr(evlist->cpus);
389 int nr_threads = perf_evlist__nr_threads(evlist, evsel);
390
391 if (!evsel->fd)
392 return 0;
393
394 for (cpu = 0; cpu < nr_cpus; cpu++) {
395 for (thread = 0; thread < nr_threads; thread++) {
396 err = ioctl(FD(evsel, cpu, thread),
397 PERF_EVENT_IOC_DISABLE, 0);
398 if (err)
399 return err;
400 }
401 }
402 return 0;
403}
404
405int perf_evlist__enable_event(struct perf_evlist *evlist,
406 struct perf_evsel *evsel)
407{
408 int cpu, thread, err;
409 int nr_cpus = cpu_map__nr(evlist->cpus);
410 int nr_threads = perf_evlist__nr_threads(evlist, evsel);
411
412 if (!evsel->fd)
413 return -EINVAL;
414
415 for (cpu = 0; cpu < nr_cpus; cpu++) {
416 for (thread = 0; thread < nr_threads; thread++) {
417 err = ioctl(FD(evsel, cpu, thread),
418 PERF_EVENT_IOC_ENABLE, 0);
419 if (err)
420 return err;
421 }
422 }
423 return 0;
424}
425
426static int perf_evlist__enable_event_cpu(struct perf_evlist *evlist, 396static int perf_evlist__enable_event_cpu(struct perf_evlist *evlist,
427 struct perf_evsel *evsel, int cpu) 397 struct perf_evsel *evsel, int cpu)
428{ 398{
@@ -550,9 +520,9 @@ void perf_evlist__id_add(struct perf_evlist *evlist, struct perf_evsel *evsel,
550 evsel->id[evsel->ids++] = id; 520 evsel->id[evsel->ids++] = id;
551} 521}
552 522
553static int perf_evlist__id_add_fd(struct perf_evlist *evlist, 523int perf_evlist__id_add_fd(struct perf_evlist *evlist,
554 struct perf_evsel *evsel, 524 struct perf_evsel *evsel,
555 int cpu, int thread, int fd) 525 int cpu, int thread, int fd)
556{ 526{
557 u64 read_data[4] = { 0, }; 527 u64 read_data[4] = { 0, };
558 int id_idx = 1; /* The first entry is the counter value */ 528 int id_idx = 1; /* The first entry is the counter value */
@@ -1211,12 +1181,12 @@ void perf_evlist__set_maps(struct perf_evlist *evlist, struct cpu_map *cpus,
1211 */ 1181 */
1212 if (cpus != evlist->cpus) { 1182 if (cpus != evlist->cpus) {
1213 cpu_map__put(evlist->cpus); 1183 cpu_map__put(evlist->cpus);
1214 evlist->cpus = cpus; 1184 evlist->cpus = cpu_map__get(cpus);
1215 } 1185 }
1216 1186
1217 if (threads != evlist->threads) { 1187 if (threads != evlist->threads) {
1218 thread_map__put(evlist->threads); 1188 thread_map__put(evlist->threads);
1219 evlist->threads = threads; 1189 evlist->threads = thread_map__get(threads);
1220 } 1190 }
1221 1191
1222 perf_evlist__propagate_maps(evlist); 1192 perf_evlist__propagate_maps(evlist);
@@ -1253,6 +1223,9 @@ int perf_evlist__set_filter(struct perf_evlist *evlist, const char *filter)
1253 int err = 0; 1223 int err = 0;
1254 1224
1255 evlist__for_each(evlist, evsel) { 1225 evlist__for_each(evlist, evsel) {
1226 if (evsel->attr.type != PERF_TYPE_TRACEPOINT)
1227 continue;
1228
1256 err = perf_evsel__set_filter(evsel, filter); 1229 err = perf_evsel__set_filter(evsel, filter);
1257 if (err) 1230 if (err)
1258 break; 1231 break;
@@ -1486,7 +1459,7 @@ int perf_evlist__open(struct perf_evlist *evlist)
1486 perf_evlist__update_id_pos(evlist); 1459 perf_evlist__update_id_pos(evlist);
1487 1460
1488 evlist__for_each(evlist, evsel) { 1461 evlist__for_each(evlist, evsel) {
1489 err = perf_evsel__open(evsel, evlist->cpus, evlist->threads); 1462 err = perf_evsel__open(evsel, evsel->cpus, evsel->threads);
1490 if (err < 0) 1463 if (err < 0)
1491 goto out_err; 1464 goto out_err;
1492 } 1465 }
@@ -1654,7 +1627,7 @@ size_t perf_evlist__fprintf(struct perf_evlist *evlist, FILE *fp)
1654 return printed + fprintf(fp, "\n"); 1627 return printed + fprintf(fp, "\n");
1655} 1628}
1656 1629
1657int perf_evlist__strerror_open(struct perf_evlist *evlist __maybe_unused, 1630int perf_evlist__strerror_open(struct perf_evlist *evlist,
1658 int err, char *buf, size_t size) 1631 int err, char *buf, size_t size)
1659{ 1632{
1660 int printed, value; 1633 int printed, value;
@@ -1682,7 +1655,25 @@ int perf_evlist__strerror_open(struct perf_evlist *evlist __maybe_unused,
1682 "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"
1683 "Hint:\tThe current value is %d.", value); 1656 "Hint:\tThe current value is %d.", value);
1684 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 }
1685 default: 1675 default:
1676out_default:
1686 scnprintf(buf, size, "%s", emsg); 1677 scnprintf(buf, size, "%s", emsg);
1687 break; 1678 break;
1688 } 1679 }
@@ -1753,3 +1744,19 @@ void perf_evlist__set_tracking_event(struct perf_evlist *evlist,
1753 1744
1754 tracking_evsel->tracking = true; 1745 tracking_evsel->tracking = true;
1755} 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 a459fe71b452..a0d15221db6e 100644
--- a/tools/perf/util/evlist.h
+++ b/tools/perf/util/evlist.h
@@ -67,6 +67,7 @@ struct perf_evsel_str_handler {
67 67
68struct perf_evlist *perf_evlist__new(void); 68struct perf_evlist *perf_evlist__new(void);
69struct perf_evlist *perf_evlist__new_default(void); 69struct perf_evlist *perf_evlist__new_default(void);
70struct perf_evlist *perf_evlist__new_dummy(void);
70void perf_evlist__init(struct perf_evlist *evlist, struct cpu_map *cpus, 71void perf_evlist__init(struct perf_evlist *evlist, struct cpu_map *cpus,
71 struct thread_map *threads); 72 struct thread_map *threads);
72void perf_evlist__exit(struct perf_evlist *evlist); 73void perf_evlist__exit(struct perf_evlist *evlist);
@@ -81,6 +82,8 @@ int __perf_evlist__add_default_attrs(struct perf_evlist *evlist,
81#define perf_evlist__add_default_attrs(evlist, array) \ 82#define perf_evlist__add_default_attrs(evlist, array) \
82 __perf_evlist__add_default_attrs(evlist, array, ARRAY_SIZE(array)) 83 __perf_evlist__add_default_attrs(evlist, array, ARRAY_SIZE(array))
83 84
85int perf_evlist__add_dummy(struct perf_evlist *evlist);
86
84int perf_evlist__add_newtp(struct perf_evlist *evlist, 87int perf_evlist__add_newtp(struct perf_evlist *evlist,
85 const char *sys, const char *name, void *handler); 88 const char *sys, const char *name, void *handler);
86 89
@@ -97,6 +100,9 @@ perf_evlist__find_tracepoint_by_name(struct perf_evlist *evlist,
97 100
98void perf_evlist__id_add(struct perf_evlist *evlist, struct perf_evsel *evsel, 101void perf_evlist__id_add(struct perf_evlist *evlist, struct perf_evsel *evsel,
99 int cpu, int thread, u64 id); 102 int cpu, int thread, u64 id);
103int perf_evlist__id_add_fd(struct perf_evlist *evlist,
104 struct perf_evsel *evsel,
105 int cpu, int thread, int fd);
100 106
101int perf_evlist__add_pollfd(struct perf_evlist *evlist, int fd); 107int perf_evlist__add_pollfd(struct perf_evlist *evlist, int fd);
102int perf_evlist__alloc_pollfd(struct perf_evlist *evlist); 108int perf_evlist__alloc_pollfd(struct perf_evlist *evlist);
@@ -149,10 +155,6 @@ void perf_evlist__disable(struct perf_evlist *evlist);
149void perf_evlist__enable(struct perf_evlist *evlist); 155void perf_evlist__enable(struct perf_evlist *evlist);
150void perf_evlist__toggle_enable(struct perf_evlist *evlist); 156void perf_evlist__toggle_enable(struct perf_evlist *evlist);
151 157
152int perf_evlist__disable_event(struct perf_evlist *evlist,
153 struct perf_evsel *evsel);
154int perf_evlist__enable_event(struct perf_evlist *evlist,
155 struct perf_evsel *evsel);
156int perf_evlist__enable_event_idx(struct perf_evlist *evlist, 158int perf_evlist__enable_event_idx(struct perf_evlist *evlist,
157 struct perf_evsel *evsel, int idx); 159 struct perf_evsel *evsel, int idx);
158 160
@@ -292,4 +294,7 @@ void perf_evlist__set_tracking_event(struct perf_evlist *evlist,
292 struct perf_evsel *tracking_evsel); 294 struct perf_evsel *tracking_evsel);
293 295
294void 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);
295#endif /* __PERF_EVLIST_H */ 300#endif /* __PERF_EVLIST_H */
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c
index 397fb4ed3c97..738ce226002b 100644
--- a/tools/perf/util/evsel.c
+++ b/tools/perf/util/evsel.c
@@ -36,6 +36,7 @@ static struct {
36 bool cloexec; 36 bool cloexec;
37 bool clockid; 37 bool clockid;
38 bool clockid_wrong; 38 bool clockid_wrong;
39 bool lbr_flags;
39} perf_missing_features; 40} perf_missing_features;
40 41
41static clockid_t clockid; 42static clockid_t clockid;
@@ -224,6 +225,11 @@ struct perf_evsel *perf_evsel__new_idx(struct perf_event_attr *attr, int idx)
224 if (evsel != NULL) 225 if (evsel != NULL)
225 perf_evsel__init(evsel, attr, idx); 226 perf_evsel__init(evsel, attr, idx);
226 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
227 return evsel; 233 return evsel;
228} 234}
229 235
@@ -574,7 +580,9 @@ perf_evsel__config_callgraph(struct perf_evsel *evsel,
574 } else { 580 } else {
575 perf_evsel__set_sample_bit(evsel, BRANCH_STACK); 581 perf_evsel__set_sample_bit(evsel, BRANCH_STACK);
576 attr->branch_sample_type = PERF_SAMPLE_BRANCH_USER | 582 attr->branch_sample_type = PERF_SAMPLE_BRANCH_USER |
577 PERF_SAMPLE_BRANCH_CALL_STACK; 583 PERF_SAMPLE_BRANCH_CALL_STACK |
584 PERF_SAMPLE_BRANCH_NO_CYCLES |
585 PERF_SAMPLE_BRANCH_NO_FLAGS;
578 } 586 }
579 } else 587 } else
580 pr_warning("Cannot use LBR callstack with branch stack. " 588 pr_warning("Cannot use LBR callstack with branch stack. "
@@ -895,6 +903,16 @@ void perf_evsel__config(struct perf_evsel *evsel, struct record_opts *opts)
895 if (evsel->precise_max) 903 if (evsel->precise_max)
896 perf_event_attr__set_max_precise_ip(attr); 904 perf_event_attr__set_max_precise_ip(attr);
897 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
898 /* 916 /*
899 * Apply event specific term settings, 917 * Apply event specific term settings,
900 * it overloads any global configuration. 918 * it overloads any global configuration.
@@ -981,13 +999,26 @@ int perf_evsel__append_filter(struct perf_evsel *evsel,
981 return -1; 999 return -1;
982} 1000}
983 1001
984int perf_evsel__enable(struct perf_evsel *evsel, int ncpus, int nthreads) 1002int perf_evsel__enable(struct perf_evsel *evsel)
985{ 1003{
1004 int nthreads = thread_map__nr(evsel->threads);
1005 int ncpus = cpu_map__nr(evsel->cpus);
1006
986 return perf_evsel__run_ioctl(evsel, ncpus, nthreads, 1007 return perf_evsel__run_ioctl(evsel, ncpus, nthreads,
987 PERF_EVENT_IOC_ENABLE, 1008 PERF_EVENT_IOC_ENABLE,
988 0); 1009 0);
989} 1010}
990 1011
1012int perf_evsel__disable(struct perf_evsel *evsel)
1013{
1014 int nthreads = thread_map__nr(evsel->threads);
1015 int ncpus = cpu_map__nr(evsel->cpus);
1016
1017 return perf_evsel__run_ioctl(evsel, ncpus, nthreads,
1018 PERF_EVENT_IOC_DISABLE,
1019 0);
1020}
1021
991int perf_evsel__alloc_id(struct perf_evsel *evsel, int ncpus, int nthreads) 1022int perf_evsel__alloc_id(struct perf_evsel *evsel, int ncpus, int nthreads)
992{ 1023{
993 if (ncpus == 0 || nthreads == 0) 1024 if (ncpus == 0 || nthreads == 0)
@@ -1192,6 +1223,7 @@ static void __p_sample_type(char *buf, size_t size, u64 value)
1192 bit_name(PERIOD), bit_name(STREAM_ID), bit_name(RAW), 1223 bit_name(PERIOD), bit_name(STREAM_ID), bit_name(RAW),
1193 bit_name(BRANCH_STACK), bit_name(REGS_USER), bit_name(STACK_USER), 1224 bit_name(BRANCH_STACK), bit_name(REGS_USER), bit_name(STACK_USER),
1194 bit_name(IDENTIFIER), bit_name(REGS_INTR), bit_name(DATA_SRC), 1225 bit_name(IDENTIFIER), bit_name(REGS_INTR), bit_name(DATA_SRC),
1226 bit_name(WEIGHT),
1195 { .name = NULL, } 1227 { .name = NULL, }
1196 }; 1228 };
1197#undef bit_name 1229#undef bit_name
@@ -1323,6 +1355,9 @@ fallback_missing_features:
1323 evsel->attr.mmap2 = 0; 1355 evsel->attr.mmap2 = 0;
1324 if (perf_missing_features.exclude_guest) 1356 if (perf_missing_features.exclude_guest)
1325 evsel->attr.exclude_guest = evsel->attr.exclude_host = 0; 1357 evsel->attr.exclude_guest = evsel->attr.exclude_host = 0;
1358 if (perf_missing_features.lbr_flags)
1359 evsel->attr.branch_sample_type &= ~(PERF_SAMPLE_BRANCH_NO_FLAGS |
1360 PERF_SAMPLE_BRANCH_NO_CYCLES);
1326retry_sample_id: 1361retry_sample_id:
1327 if (perf_missing_features.sample_id_all) 1362 if (perf_missing_features.sample_id_all)
1328 evsel->attr.sample_id_all = 0; 1363 evsel->attr.sample_id_all = 0;
@@ -1441,6 +1476,12 @@ try_fallback:
1441 } else if (!perf_missing_features.sample_id_all) { 1476 } else if (!perf_missing_features.sample_id_all) {
1442 perf_missing_features.sample_id_all = true; 1477 perf_missing_features.sample_id_all = true;
1443 goto retry_sample_id; 1478 goto retry_sample_id;
1479 } else if (!perf_missing_features.lbr_flags &&
1480 (evsel->attr.branch_sample_type &
1481 (PERF_SAMPLE_BRANCH_NO_CYCLES |
1482 PERF_SAMPLE_BRANCH_NO_FLAGS))) {
1483 perf_missing_features.lbr_flags = true;
1484 goto fallback_missing_features;
1444 } 1485 }
1445 1486
1446out_close: 1487out_close:
@@ -1602,6 +1643,7 @@ int perf_evsel__parse_sample(struct perf_evsel *evsel, union perf_event *event,
1602 data->stream_id = data->id = data->time = -1ULL; 1643 data->stream_id = data->id = data->time = -1ULL;
1603 data->period = evsel->attr.sample_period; 1644 data->period = evsel->attr.sample_period;
1604 data->weight = 0; 1645 data->weight = 0;
1646 data->cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
1605 1647
1606 if (event->header.type != PERF_RECORD_SAMPLE) { 1648 if (event->header.type != PERF_RECORD_SAMPLE) {
1607 if (!evsel->attr.sample_id_all) 1649 if (!evsel->attr.sample_id_all)
@@ -2272,6 +2314,29 @@ int perf_evsel__fprintf(struct perf_evsel *evsel,
2272 printed += comma_fprintf(fp, &first, " %s=%" PRIu64, 2314 printed += comma_fprintf(fp, &first, " %s=%" PRIu64,
2273 term, (u64)evsel->attr.sample_freq); 2315 term, (u64)evsel->attr.sample_freq);
2274 } 2316 }
2317
2318 if (details->trace_fields) {
2319 struct format_field *field;
2320
2321 if (evsel->attr.type != PERF_TYPE_TRACEPOINT) {
2322 printed += comma_fprintf(fp, &first, " (not a tracepoint)");
2323 goto out;
2324 }
2325
2326 field = evsel->tp_format->format.fields;
2327 if (field == NULL) {
2328 printed += comma_fprintf(fp, &first, " (no trace field)");
2329 goto out;
2330 }
2331
2332 printed += comma_fprintf(fp, &first, " trace_fields: %s", field->name);
2333
2334 field = field->next;
2335 while (field) {
2336 printed += comma_fprintf(fp, &first, "%s", field->name);
2337 field = field->next;
2338 }
2339 }
2275out: 2340out:
2276 fputc('\n', fp); 2341 fputc('\n', fp);
2277 return ++printed; 2342 return ++printed;
@@ -2313,12 +2378,15 @@ int perf_evsel__open_strerror(struct perf_evsel *evsel, struct target *target,
2313 case EPERM: 2378 case EPERM:
2314 case EACCES: 2379 case EACCES:
2315 return scnprintf(msg, size, 2380 return scnprintf(msg, size,
2316 "You may not have permission to collect %sstats.\n" 2381 "You may not have permission to collect %sstats.\n\n"
2317 "Consider tweaking /proc/sys/kernel/perf_event_paranoid:\n" 2382 "Consider tweaking /proc/sys/kernel/perf_event_paranoid,\n"
2318 " -1 - Not paranoid at all\n" 2383 "which controls use of the performance events system by\n"
2319 " 0 - Disallow raw tracepoint access for unpriv\n" 2384 "unprivileged users (without CAP_SYS_ADMIN).\n\n"
2320 " 1 - Disallow cpu events for unpriv\n" 2385 "The default value is 1:\n\n"
2321 " 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",
2322 target->system_wide ? "system-wide " : ""); 2390 target->system_wide ? "system-wide " : "");
2323 case ENOENT: 2391 case ENOENT:
2324 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 0e49bd742c63..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;
@@ -227,7 +225,8 @@ int perf_evsel__append_filter(struct perf_evsel *evsel,
227 const char *op, const char *filter); 225 const char *op, const char *filter);
228int perf_evsel__apply_filter(struct perf_evsel *evsel, int ncpus, int nthreads, 226int perf_evsel__apply_filter(struct perf_evsel *evsel, int ncpus, int nthreads,
229 const char *filter); 227 const char *filter);
230int perf_evsel__enable(struct perf_evsel *evsel, int ncpus, int nthreads); 228int perf_evsel__enable(struct perf_evsel *evsel);
229int perf_evsel__disable(struct perf_evsel *evsel);
231 230
232int perf_evsel__open_per_cpu(struct perf_evsel *evsel, 231int perf_evsel__open_per_cpu(struct perf_evsel *evsel,
233 struct cpu_map *cpus); 232 struct cpu_map *cpus);
@@ -363,11 +362,20 @@ static inline bool perf_evsel__is_function_event(struct perf_evsel *evsel)
363#undef FUNCTION_EVENT 362#undef FUNCTION_EVENT
364} 363}
365 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
366struct perf_attr_details { 373struct perf_attr_details {
367 bool freq; 374 bool freq;
368 bool verbose; 375 bool verbose;
369 bool event_group; 376 bool event_group;
370 bool force; 377 bool force;
378 bool trace_fields;
371}; 379};
372 380
373int perf_evsel__fprintf(struct perf_evsel *evsel, 381int perf_evsel__fprintf(struct perf_evsel *evsel,
diff --git a/tools/perf/util/exec_cmd.c b/tools/perf/util/exec_cmd.c
deleted file mode 100644
index 7adf4ad15d8f..000000000000
--- a/tools/perf/util/exec_cmd.c
+++ /dev/null
@@ -1,148 +0,0 @@
1#include "cache.h"
2#include "exec_cmd.h"
3#include "quote.h"
4
5#include <string.h>
6
7#define MAX_ARGS 32
8
9static const char *argv_exec_path;
10static const char *argv0_path;
11
12const char *system_path(const char *path)
13{
14 static const char *prefix = PREFIX;
15 struct strbuf d = STRBUF_INIT;
16
17 if (is_absolute_path(path))
18 return path;
19
20 strbuf_addf(&d, "%s/%s", prefix, path);
21 path = strbuf_detach(&d, NULL);
22 return path;
23}
24
25const char *perf_extract_argv0_path(const char *argv0)
26{
27 const char *slash;
28
29 if (!argv0 || !*argv0)
30 return NULL;
31 slash = argv0 + strlen(argv0);
32
33 while (argv0 <= slash && !is_dir_sep(*slash))
34 slash--;
35
36 if (slash >= argv0) {
37 argv0_path = strndup(argv0, slash - argv0);
38 return argv0_path ? slash + 1 : NULL;
39 }
40
41 return argv0;
42}
43
44void perf_set_argv_exec_path(const char *exec_path)
45{
46 argv_exec_path = exec_path;
47 /*
48 * Propagate this setting to external programs.
49 */
50 setenv(EXEC_PATH_ENVIRONMENT, exec_path, 1);
51}
52
53
54/* Returns the highest-priority, location to look for perf programs. */
55const char *perf_exec_path(void)
56{
57 const char *env;
58
59 if (argv_exec_path)
60 return argv_exec_path;
61
62 env = getenv(EXEC_PATH_ENVIRONMENT);
63 if (env && *env) {
64 return env;
65 }
66
67 return system_path(PERF_EXEC_PATH);
68}
69
70static void add_path(struct strbuf *out, const char *path)
71{
72 if (path && *path) {
73 if (is_absolute_path(path))
74 strbuf_addstr(out, path);
75 else
76 strbuf_addstr(out, make_nonrelative_path(path));
77
78 strbuf_addch(out, PATH_SEP);
79 }
80}
81
82void setup_path(void)
83{
84 const char *old_path = getenv("PATH");
85 struct strbuf new_path = STRBUF_INIT;
86
87 add_path(&new_path, perf_exec_path());
88 add_path(&new_path, argv0_path);
89
90 if (old_path)
91 strbuf_addstr(&new_path, old_path);
92 else
93 strbuf_addstr(&new_path, "/usr/local/bin:/usr/bin:/bin");
94
95 setenv("PATH", new_path.buf, 1);
96
97 strbuf_release(&new_path);
98}
99
100static const char **prepare_perf_cmd(const char **argv)
101{
102 int argc;
103 const char **nargv;
104
105 for (argc = 0; argv[argc]; argc++)
106 ; /* just counting */
107 nargv = malloc(sizeof(*nargv) * (argc + 2));
108
109 nargv[0] = "perf";
110 for (argc = 0; argv[argc]; argc++)
111 nargv[argc + 1] = argv[argc];
112 nargv[argc + 1] = NULL;
113 return nargv;
114}
115
116int execv_perf_cmd(const char **argv) {
117 const char **nargv = prepare_perf_cmd(argv);
118
119 /* execvp() can only ever return if it fails */
120 execvp("perf", (char **)nargv);
121
122 free(nargv);
123 return -1;
124}
125
126
127int execl_perf_cmd(const char *cmd,...)
128{
129 int argc;
130 const char *argv[MAX_ARGS + 1];
131 const char *arg;
132 va_list param;
133
134 va_start(param, cmd);
135 argv[0] = cmd;
136 argc = 1;
137 while (argc < MAX_ARGS) {
138 arg = argv[argc++] = va_arg(param, char *);
139 if (!arg)
140 break;
141 }
142 va_end(param);
143 if (MAX_ARGS <= argc)
144 return error("too many args to run %s", cmd);
145
146 argv[argc] = NULL;
147 return execv_perf_cmd(argv);
148}
diff --git a/tools/perf/util/exec_cmd.h b/tools/perf/util/exec_cmd.h
deleted file mode 100644
index bc4b915963f5..000000000000
--- a/tools/perf/util/exec_cmd.h
+++ /dev/null
@@ -1,12 +0,0 @@
1#ifndef __PERF_EXEC_CMD_H
2#define __PERF_EXEC_CMD_H
3
4extern void perf_set_argv_exec_path(const char *exec_path);
5extern const char *perf_extract_argv0_path(const char *path);
6extern const char *perf_exec_path(void);
7extern void setup_path(void);
8extern int execv_perf_cmd(const char **argv); /* NULL terminated */
9extern int execl_perf_cmd(const char *cmd, ...);
10extern const char *system_path(const char *path);
11
12#endif /* __PERF_EXEC_CMD_H */
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/generate-cmdlist.sh b/tools/perf/util/generate-cmdlist.sh
index 36a885d2cd22..0ac2037c970c 100755
--- a/tools/perf/util/generate-cmdlist.sh
+++ b/tools/perf/util/generate-cmdlist.sh
@@ -36,4 +36,19 @@ do
36 }' "Documentation/perf-$cmd.txt" 36 }' "Documentation/perf-$cmd.txt"
37done 37done
38echo "#endif /* HAVE_LIBELF_SUPPORT */" 38echo "#endif /* HAVE_LIBELF_SUPPORT */"
39
40echo "#ifdef HAVE_LIBAUDIT_SUPPORT"
41sed -n -e 's/^perf-\([^ ]*\)[ ].* audit*/\1/p' command-list.txt |
42sort |
43while read cmd
44do
45 sed -n '
46 /^NAME/,/perf-'"$cmd"'/H
47 ${
48 x
49 s/.*perf-'"$cmd"' - \(.*\)/ {"'"$cmd"'", "\1"},/
50 p
51 }' "Documentation/perf-$cmd.txt"
52done
53echo "#endif /* HAVE_LIBELF_SUPPORT */"
39echo "};" 54echo "};"
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
index 43838003c1a1..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"
@@ -724,7 +726,7 @@ static int write_numa_topology(int fd, struct perf_header *h __maybe_unused,
724done: 726done:
725 free(buf); 727 free(buf);
726 fclose(fp); 728 fclose(fp);
727 free(node_map); 729 cpu_map__put(node_map);
728 return ret; 730 return ret;
729} 731}
730 732
@@ -868,6 +870,206 @@ 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
1066static int write_stat(int fd __maybe_unused,
1067 struct perf_header *h __maybe_unused,
1068 struct perf_evlist *evlist __maybe_unused)
1069{
1070 return 0;
1071}
1072
871static void print_hostname(struct perf_header *ph, int fd __maybe_unused, 1073static void print_hostname(struct perf_header *ph, int fd __maybe_unused,
872 FILE *fp) 1074 FILE *fp)
873{ 1075{
@@ -1159,6 +1361,24 @@ static void print_auxtrace(struct perf_header *ph __maybe_unused,
1159 fprintf(fp, "# contains AUX area data (e.g. instruction trace)\n"); 1361 fprintf(fp, "# contains AUX area data (e.g. instruction trace)\n");
1160} 1362}
1161 1363
1364static void print_stat(struct perf_header *ph __maybe_unused,
1365 int fd __maybe_unused, FILE *fp)
1366{
1367 fprintf(fp, "# contains stat data\n");
1368}
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
1162static 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,
1163 FILE *fp) 1383 FILE *fp)
1164{ 1384{
@@ -1652,11 +1872,6 @@ static int process_cpu_topology(struct perf_file_section *section,
1652 if (ph->needs_swap) 1872 if (ph->needs_swap)
1653 nr = bswap_32(nr); 1873 nr = bswap_32(nr);
1654 1874
1655 if (nr > (u32)cpu_nr) {
1656 pr_debug("core_id number is too big."
1657 "You may need to upgrade the perf tool.\n");
1658 goto free_cpu;
1659 }
1660 ph->env.cpu[i].core_id = nr; 1875 ph->env.cpu[i].core_id = nr;
1661 1876
1662 ret = readn(fd, &nr, sizeof(nr)); 1877 ret = readn(fd, &nr, sizeof(nr));
@@ -1907,6 +2122,68 @@ static int process_auxtrace(struct perf_file_section *section,
1907 return err; 2122 return err;
1908} 2123}
1909 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
1910struct feature_ops { 2187struct feature_ops {
1911 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);
1912 void (*print)(struct perf_header *h, int fd, FILE *fp); 2189 void (*print)(struct perf_header *h, int fd, FILE *fp);
@@ -1948,6 +2225,8 @@ static const struct feature_ops feat_ops[HEADER_LAST_FEATURE] = {
1948 FEAT_OPP(HEADER_PMU_MAPPINGS, pmu_mappings), 2225 FEAT_OPP(HEADER_PMU_MAPPINGS, pmu_mappings),
1949 FEAT_OPP(HEADER_GROUP_DESC, group_desc), 2226 FEAT_OPP(HEADER_GROUP_DESC, group_desc),
1950 FEAT_OPP(HEADER_AUXTRACE, auxtrace), 2227 FEAT_OPP(HEADER_AUXTRACE, auxtrace),
2228 FEAT_OPA(HEADER_STAT, stat),
2229 FEAT_OPF(HEADER_CACHE, cache),
1951}; 2230};
1952 2231
1953struct header_print_data { 2232struct header_print_data {
@@ -2686,6 +2965,152 @@ int perf_event__synthesize_attr(struct perf_tool *tool,
2686 return err; 2965 return err;
2687} 2966}
2688 2967
2968static struct event_update_event *
2969event_update_event__new(size_t size, u64 type, u64 id)
2970{
2971 struct event_update_event *ev;
2972
2973 size += sizeof(*ev);
2974 size = PERF_ALIGN(size, sizeof(u64));
2975
2976 ev = zalloc(size);
2977 if (ev) {
2978 ev->header.type = PERF_RECORD_EVENT_UPDATE;
2979 ev->header.size = (u16)size;
2980 ev->type = type;
2981 ev->id = id;
2982 }
2983 return ev;
2984}
2985
2986int
2987perf_event__synthesize_event_update_unit(struct perf_tool *tool,
2988 struct perf_evsel *evsel,
2989 perf_event__handler_t process)
2990{
2991 struct event_update_event *ev;
2992 size_t size = strlen(evsel->unit);
2993 int err;
2994
2995 ev = event_update_event__new(size + 1, PERF_EVENT_UPDATE__UNIT, evsel->id[0]);
2996 if (ev == NULL)
2997 return -ENOMEM;
2998
2999 strncpy(ev->data, evsel->unit, size);
3000 err = process(tool, (union perf_event *)ev, NULL, NULL);
3001 free(ev);
3002 return err;
3003}
3004
3005int
3006perf_event__synthesize_event_update_scale(struct perf_tool *tool,
3007 struct perf_evsel *evsel,
3008 perf_event__handler_t process)
3009{
3010 struct event_update_event *ev;
3011 struct event_update_event_scale *ev_data;
3012 int err;
3013
3014 ev = event_update_event__new(sizeof(*ev_data), PERF_EVENT_UPDATE__SCALE, evsel->id[0]);
3015 if (ev == NULL)
3016 return -ENOMEM;
3017
3018 ev_data = (struct event_update_event_scale *) ev->data;
3019 ev_data->scale = evsel->scale;
3020 err = process(tool, (union perf_event*) ev, NULL, NULL);
3021 free(ev);
3022 return err;
3023}
3024
3025int
3026perf_event__synthesize_event_update_name(struct perf_tool *tool,
3027 struct perf_evsel *evsel,
3028 perf_event__handler_t process)
3029{
3030 struct event_update_event *ev;
3031 size_t len = strlen(evsel->name);
3032 int err;
3033
3034 ev = event_update_event__new(len + 1, PERF_EVENT_UPDATE__NAME, evsel->id[0]);
3035 if (ev == NULL)
3036 return -ENOMEM;
3037
3038 strncpy(ev->data, evsel->name, len);
3039 err = process(tool, (union perf_event*) ev, NULL, NULL);
3040 free(ev);
3041 return err;
3042}
3043
3044int
3045perf_event__synthesize_event_update_cpus(struct perf_tool *tool,
3046 struct perf_evsel *evsel,
3047 perf_event__handler_t process)
3048{
3049 size_t size = sizeof(struct event_update_event);
3050 struct event_update_event *ev;
3051 int max, err;
3052 u16 type;
3053
3054 if (!evsel->own_cpus)
3055 return 0;
3056
3057 ev = cpu_map_data__alloc(evsel->own_cpus, &size, &type, &max);
3058 if (!ev)
3059 return -ENOMEM;
3060
3061 ev->header.type = PERF_RECORD_EVENT_UPDATE;
3062 ev->header.size = (u16)size;
3063 ev->type = PERF_EVENT_UPDATE__CPUS;
3064 ev->id = evsel->id[0];
3065
3066 cpu_map_data__synthesize((struct cpu_map_data *) ev->data,
3067 evsel->own_cpus,
3068 type, max);
3069
3070 err = process(tool, (union perf_event*) ev, NULL, NULL);
3071 free(ev);
3072 return err;
3073}
3074
3075size_t perf_event__fprintf_event_update(union perf_event *event, FILE *fp)
3076{
3077 struct event_update_event *ev = &event->event_update;
3078 struct event_update_event_scale *ev_scale;
3079 struct event_update_event_cpus *ev_cpus;
3080 struct cpu_map *map;
3081 size_t ret;
3082
3083 ret = fprintf(fp, "\n... id: %" PRIu64 "\n", ev->id);
3084
3085 switch (ev->type) {
3086 case PERF_EVENT_UPDATE__SCALE:
3087 ev_scale = (struct event_update_event_scale *) ev->data;
3088 ret += fprintf(fp, "... scale: %f\n", ev_scale->scale);
3089 break;
3090 case PERF_EVENT_UPDATE__UNIT:
3091 ret += fprintf(fp, "... unit: %s\n", ev->data);
3092 break;
3093 case PERF_EVENT_UPDATE__NAME:
3094 ret += fprintf(fp, "... name: %s\n", ev->data);
3095 break;
3096 case PERF_EVENT_UPDATE__CPUS:
3097 ev_cpus = (struct event_update_event_cpus *) ev->data;
3098 ret += fprintf(fp, "... ");
3099
3100 map = cpu_map__new_data(&ev_cpus->cpus);
3101 if (map)
3102 ret += cpu_map__fprintf(map, fp);
3103 else
3104 ret += fprintf(fp, "failed to get cpus\n");
3105 break;
3106 default:
3107 ret += fprintf(fp, "... unknown type\n");
3108 break;
3109 }
3110
3111 return ret;
3112}
3113
2689int perf_event__synthesize_attrs(struct perf_tool *tool, 3114int perf_event__synthesize_attrs(struct perf_tool *tool,
2690 struct perf_session *session, 3115 struct perf_session *session,
2691 perf_event__handler_t process) 3116 perf_event__handler_t process)
@@ -2745,6 +3170,51 @@ int perf_event__process_attr(struct perf_tool *tool __maybe_unused,
2745 return 0; 3170 return 0;
2746} 3171}
2747 3172
3173int perf_event__process_event_update(struct perf_tool *tool __maybe_unused,
3174 union perf_event *event,
3175 struct perf_evlist **pevlist)
3176{
3177 struct event_update_event *ev = &event->event_update;
3178 struct event_update_event_scale *ev_scale;
3179 struct event_update_event_cpus *ev_cpus;
3180 struct perf_evlist *evlist;
3181 struct perf_evsel *evsel;
3182 struct cpu_map *map;
3183
3184 if (!pevlist || *pevlist == NULL)
3185 return -EINVAL;
3186
3187 evlist = *pevlist;
3188
3189 evsel = perf_evlist__id2evsel(evlist, ev->id);
3190 if (evsel == NULL)
3191 return -EINVAL;
3192
3193 switch (ev->type) {
3194 case PERF_EVENT_UPDATE__UNIT:
3195 evsel->unit = strdup(ev->data);
3196 break;
3197 case PERF_EVENT_UPDATE__NAME:
3198 evsel->name = strdup(ev->data);
3199 break;
3200 case PERF_EVENT_UPDATE__SCALE:
3201 ev_scale = (struct event_update_event_scale *) ev->data;
3202 evsel->scale = ev_scale->scale;
3203 case PERF_EVENT_UPDATE__CPUS:
3204 ev_cpus = (struct event_update_event_cpus *) ev->data;
3205
3206 map = cpu_map__new_data(&ev_cpus->cpus);
3207 if (map)
3208 evsel->own_cpus = map;
3209 else
3210 pr_err("failed to get event_update cpus\n");
3211 default:
3212 break;
3213 }
3214
3215 return 0;
3216}
3217
2748int perf_event__synthesize_tracing_data(struct perf_tool *tool, int fd, 3218int perf_event__synthesize_tracing_data(struct perf_tool *tool, int fd,
2749 struct perf_evlist *evlist, 3219 struct perf_evlist *evlist,
2750 perf_event__handler_t process) 3220 perf_event__handler_t process)
diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h
index 05f27cb6b7e3..d306ca118449 100644
--- a/tools/perf/util/header.h
+++ b/tools/perf/util/header.h
@@ -31,6 +31,8 @@ enum {
31 HEADER_PMU_MAPPINGS, 31 HEADER_PMU_MAPPINGS,
32 HEADER_GROUP_DESC, 32 HEADER_GROUP_DESC,
33 HEADER_AUXTRACE, 33 HEADER_AUXTRACE,
34 HEADER_STAT,
35 HEADER_CACHE,
34 HEADER_LAST_FEATURE, 36 HEADER_LAST_FEATURE,
35 HEADER_FEAT_BITS = 256, 37 HEADER_FEAT_BITS = 256,
36}; 38};
@@ -105,8 +107,24 @@ int perf_event__synthesize_attr(struct perf_tool *tool,
105int perf_event__synthesize_attrs(struct perf_tool *tool, 107int perf_event__synthesize_attrs(struct perf_tool *tool,
106 struct perf_session *session, 108 struct perf_session *session,
107 perf_event__handler_t process); 109 perf_event__handler_t process);
110int perf_event__synthesize_event_update_unit(struct perf_tool *tool,
111 struct perf_evsel *evsel,
112 perf_event__handler_t process);
113int perf_event__synthesize_event_update_scale(struct perf_tool *tool,
114 struct perf_evsel *evsel,
115 perf_event__handler_t process);
116int perf_event__synthesize_event_update_name(struct perf_tool *tool,
117 struct perf_evsel *evsel,
118 perf_event__handler_t process);
119int perf_event__synthesize_event_update_cpus(struct perf_tool *tool,
120 struct perf_evsel *evsel,
121 perf_event__handler_t process);
108int 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,
109 struct perf_evlist **pevlist); 123 struct perf_evlist **pevlist);
124int perf_event__process_event_update(struct perf_tool *tool,
125 union perf_event *event,
126 struct perf_evlist **pevlist);
127size_t perf_event__fprintf_event_update(union perf_event *event, FILE *fp);
110 128
111int perf_event__synthesize_tracing_data(struct perf_tool *tool, 129int perf_event__synthesize_tracing_data(struct perf_tool *tool,
112 int fd, struct perf_evlist *evlist, 130 int fd, struct perf_evlist *evlist,
diff --git a/tools/perf/util/help-unknown-cmd.c b/tools/perf/util/help-unknown-cmd.c
new file mode 100644
index 000000000000..43a98a4dc1e1
--- /dev/null
+++ b/tools/perf/util/help-unknown-cmd.c
@@ -0,0 +1,104 @@
1#include "cache.h"
2#include <subcmd/help.h>
3#include "../builtin.h"
4#include "levenshtein.h"
5
6static int autocorrect;
7static struct cmdnames aliases;
8
9static int perf_unknown_cmd_config(const char *var, const char *value,
10 void *cb __maybe_unused)
11{
12 if (!strcmp(var, "help.autocorrect"))
13 autocorrect = perf_config_int(var,value);
14 /* Also use aliases for command lookup */
15 if (!prefixcmp(var, "alias."))
16 add_cmdname(&aliases, var + 6, strlen(var + 6));
17
18 return 0;
19}
20
21static int levenshtein_compare(const void *p1, const void *p2)
22{
23 const struct cmdname *const *c1 = p1, *const *c2 = p2;
24 const char *s1 = (*c1)->name, *s2 = (*c2)->name;
25 int l1 = (*c1)->len;
26 int l2 = (*c2)->len;
27 return l1 != l2 ? l1 - l2 : strcmp(s1, s2);
28}
29
30static void add_cmd_list(struct cmdnames *cmds, struct cmdnames *old)
31{
32 unsigned int i;
33
34 ALLOC_GROW(cmds->names, cmds->cnt + old->cnt, cmds->alloc);
35
36 for (i = 0; i < old->cnt; i++)
37 cmds->names[cmds->cnt++] = old->names[i];
38 zfree(&old->names);
39 old->cnt = 0;
40}
41
42const char *help_unknown_cmd(const char *cmd)
43{
44 unsigned int i, n = 0, best_similarity = 0;
45 struct cmdnames main_cmds, other_cmds;
46
47 memset(&main_cmds, 0, sizeof(main_cmds));
48 memset(&other_cmds, 0, sizeof(main_cmds));
49 memset(&aliases, 0, sizeof(aliases));
50
51 perf_config(perf_unknown_cmd_config, NULL);
52
53 load_command_list("perf-", &main_cmds, &other_cmds);
54
55 add_cmd_list(&main_cmds, &aliases);
56 add_cmd_list(&main_cmds, &other_cmds);
57 qsort(main_cmds.names, main_cmds.cnt,
58 sizeof(main_cmds.names), cmdname_compare);
59 uniq(&main_cmds);
60
61 if (main_cmds.cnt) {
62 /* This reuses cmdname->len for similarity index */
63 for (i = 0; i < main_cmds.cnt; ++i)
64 main_cmds.names[i]->len =
65 levenshtein(cmd, main_cmds.names[i]->name, 0, 2, 1, 4);
66
67 qsort(main_cmds.names, main_cmds.cnt,
68 sizeof(*main_cmds.names), levenshtein_compare);
69
70 best_similarity = main_cmds.names[0]->len;
71 n = 1;
72 while (n < main_cmds.cnt && best_similarity == main_cmds.names[n]->len)
73 ++n;
74 }
75
76 if (autocorrect && n == 1) {
77 const char *assumed = main_cmds.names[0]->name;
78
79 main_cmds.names[0] = NULL;
80 clean_cmdnames(&main_cmds);
81 fprintf(stderr, "WARNING: You called a perf program named '%s', "
82 "which does not exist.\n"
83 "Continuing under the assumption that you meant '%s'\n",
84 cmd, assumed);
85 if (autocorrect > 0) {
86 fprintf(stderr, "in %0.1f seconds automatically...\n",
87 (float)autocorrect/10.0);
88 poll(NULL, 0, autocorrect * 100);
89 }
90 return assumed;
91 }
92
93 fprintf(stderr, "perf: '%s' is not a perf-command. See 'perf --help'.\n", cmd);
94
95 if (main_cmds.cnt && best_similarity < 6) {
96 fprintf(stderr, "\nDid you mean %s?\n",
97 n < 2 ? "this": "one of these");
98
99 for (i = 0; i < n; i++)
100 fprintf(stderr, "\t%s\n", main_cmds.names[i]->name);
101 }
102
103 exit(1);
104}
diff --git a/tools/perf/util/help-unknown-cmd.h b/tools/perf/util/help-unknown-cmd.h
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/tools/perf/util/help-unknown-cmd.h
diff --git a/tools/perf/util/help.c b/tools/perf/util/help.c
deleted file mode 100644
index 86c37c472263..000000000000
--- a/tools/perf/util/help.c
+++ /dev/null
@@ -1,339 +0,0 @@
1#include "cache.h"
2#include "../builtin.h"
3#include "exec_cmd.h"
4#include "levenshtein.h"
5#include "help.h"
6#include <termios.h>
7
8void add_cmdname(struct cmdnames *cmds, const char *name, size_t len)
9{
10 struct cmdname *ent = malloc(sizeof(*ent) + len + 1);
11
12 ent->len = len;
13 memcpy(ent->name, name, len);
14 ent->name[len] = 0;
15
16 ALLOC_GROW(cmds->names, cmds->cnt + 1, cmds->alloc);
17 cmds->names[cmds->cnt++] = ent;
18}
19
20static void clean_cmdnames(struct cmdnames *cmds)
21{
22 unsigned int i;
23
24 for (i = 0; i < cmds->cnt; ++i)
25 zfree(&cmds->names[i]);
26 zfree(&cmds->names);
27 cmds->cnt = 0;
28 cmds->alloc = 0;
29}
30
31static int cmdname_compare(const void *a_, const void *b_)
32{
33 struct cmdname *a = *(struct cmdname **)a_;
34 struct cmdname *b = *(struct cmdname **)b_;
35 return strcmp(a->name, b->name);
36}
37
38static void uniq(struct cmdnames *cmds)
39{
40 unsigned int i, j;
41
42 if (!cmds->cnt)
43 return;
44
45 for (i = j = 1; i < cmds->cnt; i++)
46 if (strcmp(cmds->names[i]->name, cmds->names[i-1]->name))
47 cmds->names[j++] = cmds->names[i];
48
49 cmds->cnt = j;
50}
51
52void exclude_cmds(struct cmdnames *cmds, struct cmdnames *excludes)
53{
54 size_t ci, cj, ei;
55 int cmp;
56
57 ci = cj = ei = 0;
58 while (ci < cmds->cnt && ei < excludes->cnt) {
59 cmp = strcmp(cmds->names[ci]->name, excludes->names[ei]->name);
60 if (cmp < 0)
61 cmds->names[cj++] = cmds->names[ci++];
62 else if (cmp == 0)
63 ci++, ei++;
64 else if (cmp > 0)
65 ei++;
66 }
67
68 while (ci < cmds->cnt)
69 cmds->names[cj++] = cmds->names[ci++];
70
71 cmds->cnt = cj;
72}
73
74static void pretty_print_string_list(struct cmdnames *cmds, int longest)
75{
76 int cols = 1, rows;
77 int space = longest + 1; /* min 1 SP between words */
78 struct winsize win;
79 int max_cols;
80 int i, j;
81
82 get_term_dimensions(&win);
83 max_cols = win.ws_col - 1; /* don't print *on* the edge */
84
85 if (space < max_cols)
86 cols = max_cols / space;
87 rows = (cmds->cnt + cols - 1) / cols;
88
89 for (i = 0; i < rows; i++) {
90 printf(" ");
91
92 for (j = 0; j < cols; j++) {
93 unsigned int n = j * rows + i;
94 unsigned int size = space;
95
96 if (n >= cmds->cnt)
97 break;
98 if (j == cols-1 || n + rows >= cmds->cnt)
99 size = 1;
100 printf("%-*s", size, cmds->names[n]->name);
101 }
102 putchar('\n');
103 }
104}
105
106static int is_executable(const char *name)
107{
108 struct stat st;
109
110 if (stat(name, &st) || /* stat, not lstat */
111 !S_ISREG(st.st_mode))
112 return 0;
113
114 return st.st_mode & S_IXUSR;
115}
116
117static void list_commands_in_dir(struct cmdnames *cmds,
118 const char *path,
119 const char *prefix)
120{
121 int prefix_len;
122 DIR *dir = opendir(path);
123 struct dirent *de;
124 struct strbuf buf = STRBUF_INIT;
125 int len;
126
127 if (!dir)
128 return;
129 if (!prefix)
130 prefix = "perf-";
131 prefix_len = strlen(prefix);
132
133 strbuf_addf(&buf, "%s/", path);
134 len = buf.len;
135
136 while ((de = readdir(dir)) != NULL) {
137 int entlen;
138
139 if (prefixcmp(de->d_name, prefix))
140 continue;
141
142 strbuf_setlen(&buf, len);
143 strbuf_addstr(&buf, de->d_name);
144 if (!is_executable(buf.buf))
145 continue;
146
147 entlen = strlen(de->d_name) - prefix_len;
148 if (has_extension(de->d_name, ".exe"))
149 entlen -= 4;
150
151 add_cmdname(cmds, de->d_name + prefix_len, entlen);
152 }
153 closedir(dir);
154 strbuf_release(&buf);
155}
156
157void load_command_list(const char *prefix,
158 struct cmdnames *main_cmds,
159 struct cmdnames *other_cmds)
160{
161 const char *env_path = getenv("PATH");
162 const char *exec_path = perf_exec_path();
163
164 if (exec_path) {
165 list_commands_in_dir(main_cmds, exec_path, prefix);
166 qsort(main_cmds->names, main_cmds->cnt,
167 sizeof(*main_cmds->names), cmdname_compare);
168 uniq(main_cmds);
169 }
170
171 if (env_path) {
172 char *paths, *path, *colon;
173 path = paths = strdup(env_path);
174 while (1) {
175 if ((colon = strchr(path, PATH_SEP)))
176 *colon = 0;
177 if (!exec_path || strcmp(path, exec_path))
178 list_commands_in_dir(other_cmds, path, prefix);
179
180 if (!colon)
181 break;
182 path = colon + 1;
183 }
184 free(paths);
185
186 qsort(other_cmds->names, other_cmds->cnt,
187 sizeof(*other_cmds->names), cmdname_compare);
188 uniq(other_cmds);
189 }
190 exclude_cmds(other_cmds, main_cmds);
191}
192
193void list_commands(const char *title, struct cmdnames *main_cmds,
194 struct cmdnames *other_cmds)
195{
196 unsigned int i, longest = 0;
197
198 for (i = 0; i < main_cmds->cnt; i++)
199 if (longest < main_cmds->names[i]->len)
200 longest = main_cmds->names[i]->len;
201 for (i = 0; i < other_cmds->cnt; i++)
202 if (longest < other_cmds->names[i]->len)
203 longest = other_cmds->names[i]->len;
204
205 if (main_cmds->cnt) {
206 const char *exec_path = perf_exec_path();
207 printf("available %s in '%s'\n", title, exec_path);
208 printf("----------------");
209 mput_char('-', strlen(title) + strlen(exec_path));
210 putchar('\n');
211 pretty_print_string_list(main_cmds, longest);
212 putchar('\n');
213 }
214
215 if (other_cmds->cnt) {
216 printf("%s available from elsewhere on your $PATH\n", title);
217 printf("---------------------------------------");
218 mput_char('-', strlen(title));
219 putchar('\n');
220 pretty_print_string_list(other_cmds, longest);
221 putchar('\n');
222 }
223}
224
225int is_in_cmdlist(struct cmdnames *c, const char *s)
226{
227 unsigned int i;
228
229 for (i = 0; i < c->cnt; i++)
230 if (!strcmp(s, c->names[i]->name))
231 return 1;
232 return 0;
233}
234
235static int autocorrect;
236static struct cmdnames aliases;
237
238static int perf_unknown_cmd_config(const char *var, const char *value, void *cb)
239{
240 if (!strcmp(var, "help.autocorrect"))
241 autocorrect = perf_config_int(var,value);
242 /* Also use aliases for command lookup */
243 if (!prefixcmp(var, "alias."))
244 add_cmdname(&aliases, var + 6, strlen(var + 6));
245
246 return perf_default_config(var, value, cb);
247}
248
249static int levenshtein_compare(const void *p1, const void *p2)
250{
251 const struct cmdname *const *c1 = p1, *const *c2 = p2;
252 const char *s1 = (*c1)->name, *s2 = (*c2)->name;
253 int l1 = (*c1)->len;
254 int l2 = (*c2)->len;
255 return l1 != l2 ? l1 - l2 : strcmp(s1, s2);
256}
257
258static void add_cmd_list(struct cmdnames *cmds, struct cmdnames *old)
259{
260 unsigned int i;
261
262 ALLOC_GROW(cmds->names, cmds->cnt + old->cnt, cmds->alloc);
263
264 for (i = 0; i < old->cnt; i++)
265 cmds->names[cmds->cnt++] = old->names[i];
266 zfree(&old->names);
267 old->cnt = 0;
268}
269
270const char *help_unknown_cmd(const char *cmd)
271{
272 unsigned int i, n = 0, best_similarity = 0;
273 struct cmdnames main_cmds, other_cmds;
274
275 memset(&main_cmds, 0, sizeof(main_cmds));
276 memset(&other_cmds, 0, sizeof(main_cmds));
277 memset(&aliases, 0, sizeof(aliases));
278
279 perf_config(perf_unknown_cmd_config, NULL);
280
281 load_command_list("perf-", &main_cmds, &other_cmds);
282
283 add_cmd_list(&main_cmds, &aliases);
284 add_cmd_list(&main_cmds, &other_cmds);
285 qsort(main_cmds.names, main_cmds.cnt,
286 sizeof(main_cmds.names), cmdname_compare);
287 uniq(&main_cmds);
288
289 if (main_cmds.cnt) {
290 /* This reuses cmdname->len for similarity index */
291 for (i = 0; i < main_cmds.cnt; ++i)
292 main_cmds.names[i]->len =
293 levenshtein(cmd, main_cmds.names[i]->name, 0, 2, 1, 4);
294
295 qsort(main_cmds.names, main_cmds.cnt,
296 sizeof(*main_cmds.names), levenshtein_compare);
297
298 best_similarity = main_cmds.names[0]->len;
299 n = 1;
300 while (n < main_cmds.cnt && best_similarity == main_cmds.names[n]->len)
301 ++n;
302 }
303
304 if (autocorrect && n == 1) {
305 const char *assumed = main_cmds.names[0]->name;
306
307 main_cmds.names[0] = NULL;
308 clean_cmdnames(&main_cmds);
309 fprintf(stderr, "WARNING: You called a perf program named '%s', "
310 "which does not exist.\n"
311 "Continuing under the assumption that you meant '%s'\n",
312 cmd, assumed);
313 if (autocorrect > 0) {
314 fprintf(stderr, "in %0.1f seconds automatically...\n",
315 (float)autocorrect/10.0);
316 poll(NULL, 0, autocorrect * 100);
317 }
318 return assumed;
319 }
320
321 fprintf(stderr, "perf: '%s' is not a perf-command. See 'perf --help'.\n", cmd);
322
323 if (main_cmds.cnt && best_similarity < 6) {
324 fprintf(stderr, "\nDid you mean %s?\n",
325 n < 2 ? "this": "one of these");
326
327 for (i = 0; i < n; i++)
328 fprintf(stderr, "\t%s\n", main_cmds.names[i]->name);
329 }
330
331 exit(1);
332}
333
334int cmd_version(int argc __maybe_unused, const char **argv __maybe_unused,
335 const char *prefix __maybe_unused)
336{
337 printf("perf version %s\n", perf_version_string);
338 return 0;
339}
diff --git a/tools/perf/util/help.h b/tools/perf/util/help.h
deleted file mode 100644
index 7f5c6dedd714..000000000000
--- a/tools/perf/util/help.h
+++ /dev/null
@@ -1,29 +0,0 @@
1#ifndef __PERF_HELP_H
2#define __PERF_HELP_H
3
4struct cmdnames {
5 size_t alloc;
6 size_t cnt;
7 struct cmdname {
8 size_t len; /* also used for similarity index in help.c */
9 char name[FLEX_ARRAY];
10 } **names;
11};
12
13static inline void mput_char(char c, unsigned int num)
14{
15 while(num--)
16 putchar(c);
17}
18
19void load_command_list(const char *prefix,
20 struct cmdnames *main_cmds,
21 struct cmdnames *other_cmds);
22void add_cmdname(struct cmdnames *cmds, const char *name, size_t len);
23/* Here we require that excludes is a sorted list. */
24void exclude_cmds(struct cmdnames *cmds, struct cmdnames *excludes);
25int is_in_cmdlist(struct cmdnames *c, const char *s);
26void list_commands(const char *title, struct cmdnames *main_cmds,
27 struct cmdnames *other_cmds);
28
29#endif /* __PERF_HELP_H */
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c
index 4fd37d6708cb..31c4641fe5ff 100644
--- a/tools/perf/util/hist.c
+++ b/tools/perf/util/hist.c
@@ -131,6 +131,8 @@ void hists__calc_col_len(struct hists *hists, struct hist_entry *h)
131 symlen = unresolved_col_width + 4 + 2; 131 symlen = unresolved_col_width + 4 + 2;
132 hists__new_col_len(hists, HISTC_MEM_DADDR_SYMBOL, 132 hists__new_col_len(hists, HISTC_MEM_DADDR_SYMBOL,
133 symlen); 133 symlen);
134 hists__new_col_len(hists, HISTC_MEM_DCACHELINE,
135 symlen);
134 } 136 }
135 137
136 if (h->mem_info->iaddr.sym) { 138 if (h->mem_info->iaddr.sym) {
@@ -177,6 +179,9 @@ void hists__calc_col_len(struct hists *hists, struct hist_entry *h)
177 if (h->transaction) 179 if (h->transaction)
178 hists__new_col_len(hists, HISTC_TRANSACTION, 180 hists__new_col_len(hists, HISTC_TRANSACTION,
179 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));
180} 185}
181 186
182void hists__output_recalc_col_len(struct hists *hists, int max_rows) 187void hists__output_recalc_col_len(struct hists *hists, int max_rows)
@@ -243,6 +248,8 @@ static void he_stat__decay(struct he_stat *he_stat)
243 /* XXX need decay for weight too? */ 248 /* XXX need decay for weight too? */
244} 249}
245 250
251static void hists__delete_entry(struct hists *hists, struct hist_entry *he);
252
246static bool hists__decay_entry(struct hists *hists, struct hist_entry *he) 253static bool hists__decay_entry(struct hists *hists, struct hist_entry *he)
247{ 254{
248 u64 prev_period = he->stat.period; 255 u64 prev_period = he->stat.period;
@@ -254,22 +261,49 @@ static bool hists__decay_entry(struct hists *hists, struct hist_entry *he)
254 he_stat__decay(&he->stat); 261 he_stat__decay(&he->stat);
255 if (symbol_conf.cumulate_callchain) 262 if (symbol_conf.cumulate_callchain)
256 he_stat__decay(he->stat_acc); 263 he_stat__decay(he->stat_acc);
264 decay_callchain(he->callchain);
257 265
258 diff = prev_period - he->stat.period; 266 diff = prev_period - he->stat.period;
259 267
260 hists->stats.total_period -= diff; 268 if (!he->depth) {
261 if (!he->filtered) 269 hists->stats.total_period -= diff;
262 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 }
263 285
264 return he->stat.period == 0; 286 return he->stat.period == 0;
265} 287}
266 288
267static void hists__delete_entry(struct hists *hists, struct hist_entry *he) 289static void hists__delete_entry(struct hists *hists, struct hist_entry *he)
268{ 290{
269 rb_erase(&he->rb_node, &hists->entries); 291 struct rb_root *root_in;
292 struct rb_root *root_out;
270 293
271 if (sort__need_collapse) 294 if (he->parent_he) {
272 rb_erase(&he->rb_node_in, &hists->entries_collapsed); 295 root_in = &he->parent_he->hroot_in;
296 root_out = &he->parent_he->hroot_out;
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);
273 307
274 --hists->nr_entries; 308 --hists->nr_entries;
275 if (!he->filtered) 309 if (!he->filtered)
@@ -367,8 +401,30 @@ static struct hist_entry *hist_entry__new(struct hist_entry *template,
367 if (symbol_conf.use_callchain) 401 if (symbol_conf.use_callchain)
368 callchain_init(he->callchain); 402 callchain_init(he->callchain);
369 403
404 if (he->raw_data) {
405 he->raw_data = memdup(he->raw_data, he->raw_size);
406
407 if (he->raw_data == NULL) {
408 map__put(he->ms.map);
409 if (he->branch_info) {
410 map__put(he->branch_info->from.map);
411 map__put(he->branch_info->to.map);
412 free(he->branch_info);
413 }
414 if (he->mem_info) {
415 map__put(he->mem_info->iaddr.map);
416 map__put(he->mem_info->daddr.map);
417 }
418 free(he->stat_acc);
419 free(he);
420 return NULL;
421 }
422 }
370 INIT_LIST_HEAD(&he->pairs.node); 423 INIT_LIST_HEAD(&he->pairs.node);
371 thread__get(he->thread); 424 thread__get(he->thread);
425
426 if (!symbol_conf.report_hierarchy)
427 he->leaf = true;
372 } 428 }
373 429
374 return he; 430 return he;
@@ -381,6 +437,16 @@ static u8 symbol__parent_filter(const struct symbol *parent)
381 return 0; 437 return 0;
382} 438}
383 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
384static struct hist_entry *hists__findnew_entry(struct hists *hists, 450static struct hist_entry *hists__findnew_entry(struct hists *hists,
385 struct hist_entry *entry, 451 struct hist_entry *entry,
386 struct addr_location *al, 452 struct addr_location *al,
@@ -408,8 +474,10 @@ static struct hist_entry *hists__findnew_entry(struct hists *hists,
408 cmp = hist_entry__cmp(he, entry); 474 cmp = hist_entry__cmp(he, entry);
409 475
410 if (!cmp) { 476 if (!cmp) {
411 if (sample_self) 477 if (sample_self) {
412 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 }
413 if (symbol_conf.cumulate_callchain) 481 if (symbol_conf.cumulate_callchain)
414 he_stat__add_period(he->stat_acc, period, weight); 482 he_stat__add_period(he->stat_acc, period, weight);
415 483
@@ -442,6 +510,8 @@ static struct hist_entry *hists__findnew_entry(struct hists *hists,
442 if (!he) 510 if (!he)
443 return NULL; 511 return NULL;
444 512
513 if (sample_self)
514 hist_entry__add_callchain_period(he, period);
445 hists->nr_entries++; 515 hists->nr_entries++;
446 516
447 rb_link_node(&he->rb_node_in, parent, p); 517 rb_link_node(&he->rb_node_in, parent, p);
@@ -459,7 +529,7 @@ struct hist_entry *__hists__add_entry(struct hists *hists,
459 struct symbol *sym_parent, 529 struct symbol *sym_parent,
460 struct branch_info *bi, 530 struct branch_info *bi,
461 struct mem_info *mi, 531 struct mem_info *mi,
462 u64 period, u64 weight, u64 transaction, 532 struct perf_sample *sample,
463 bool sample_self) 533 bool sample_self)
464{ 534{
465 struct hist_entry entry = { 535 struct hist_entry entry = {
@@ -476,15 +546,17 @@ struct hist_entry *__hists__add_entry(struct hists *hists,
476 .level = al->level, 546 .level = al->level,
477 .stat = { 547 .stat = {
478 .nr_events = 1, 548 .nr_events = 1,
479 .period = period, 549 .period = sample->period,
480 .weight = weight, 550 .weight = sample->weight,
481 }, 551 },
482 .parent = sym_parent, 552 .parent = sym_parent,
483 .filtered = symbol__parent_filter(sym_parent) | al->filtered, 553 .filtered = symbol__parent_filter(sym_parent) | al->filtered,
484 .hists = hists, 554 .hists = hists,
485 .branch_info = bi, 555 .branch_info = bi,
486 .mem_info = mi, 556 .mem_info = mi,
487 .transaction = transaction, 557 .transaction = sample->transaction,
558 .raw_data = sample->raw_data,
559 .raw_size = sample->raw_size,
488 }; 560 };
489 561
490 return hists__findnew_entry(hists, &entry, al, sample_self); 562 return hists__findnew_entry(hists, &entry, al, sample_self);
@@ -524,12 +596,13 @@ iter_add_single_mem_entry(struct hist_entry_iter *iter, struct addr_location *al
524 u64 cost; 596 u64 cost;
525 struct mem_info *mi = iter->priv; 597 struct mem_info *mi = iter->priv;
526 struct hists *hists = evsel__hists(iter->evsel); 598 struct hists *hists = evsel__hists(iter->evsel);
599 struct perf_sample *sample = iter->sample;
527 struct hist_entry *he; 600 struct hist_entry *he;
528 601
529 if (mi == NULL) 602 if (mi == NULL)
530 return -EINVAL; 603 return -EINVAL;
531 604
532 cost = iter->sample->weight; 605 cost = sample->weight;
533 if (!cost) 606 if (!cost)
534 cost = 1; 607 cost = 1;
535 608
@@ -540,8 +613,10 @@ iter_add_single_mem_entry(struct hist_entry_iter *iter, struct addr_location *al
540 * and this is indirectly achieved by passing period=weight here 613 * and this is indirectly achieved by passing period=weight here
541 * and the he_stat__add_period() function. 614 * and the he_stat__add_period() function.
542 */ 615 */
616 sample->period = cost;
617
543 he = __hists__add_entry(hists, al, iter->parent, NULL, mi, 618 he = __hists__add_entry(hists, al, iter->parent, NULL, mi,
544 cost, cost, 0, true); 619 sample, true);
545 if (!he) 620 if (!he)
546 return -ENOMEM; 621 return -ENOMEM;
547 622
@@ -595,7 +670,7 @@ iter_prepare_branch_entry(struct hist_entry_iter *iter, struct addr_location *al
595} 670}
596 671
597static int 672static int
598iter_add_single_branch_entry(struct hist_entry_iter *iter __maybe_unused, 673iter_add_single_branch_entry(struct hist_entry_iter *iter,
599 struct addr_location *al __maybe_unused) 674 struct addr_location *al __maybe_unused)
600{ 675{
601 /* to avoid calling callback function */ 676 /* to avoid calling callback function */
@@ -628,6 +703,7 @@ iter_add_next_branch_entry(struct hist_entry_iter *iter, struct addr_location *a
628 struct branch_info *bi; 703 struct branch_info *bi;
629 struct perf_evsel *evsel = iter->evsel; 704 struct perf_evsel *evsel = iter->evsel;
630 struct hists *hists = evsel__hists(evsel); 705 struct hists *hists = evsel__hists(evsel);
706 struct perf_sample *sample = iter->sample;
631 struct hist_entry *he = NULL; 707 struct hist_entry *he = NULL;
632 int i = iter->curr; 708 int i = iter->curr;
633 int err = 0; 709 int err = 0;
@@ -641,9 +717,11 @@ iter_add_next_branch_entry(struct hist_entry_iter *iter, struct addr_location *a
641 * The report shows the percentage of total branches captured 717 * The report shows the percentage of total branches captured
642 * and not events sampled. Thus we use a pseudo period of 1. 718 * and not events sampled. Thus we use a pseudo period of 1.
643 */ 719 */
720 sample->period = 1;
721 sample->weight = bi->flags.cycles ? bi->flags.cycles : 1;
722
644 he = __hists__add_entry(hists, al, iter->parent, &bi[i], NULL, 723 he = __hists__add_entry(hists, al, iter->parent, &bi[i], NULL,
645 1, bi->flags.cycles ? bi->flags.cycles : 1, 724 sample, true);
646 0, true);
647 if (he == NULL) 725 if (he == NULL)
648 return -ENOMEM; 726 return -ENOMEM;
649 727
@@ -680,8 +758,7 @@ iter_add_single_normal_entry(struct hist_entry_iter *iter, struct addr_location
680 struct hist_entry *he; 758 struct hist_entry *he;
681 759
682 he = __hists__add_entry(evsel__hists(evsel), al, iter->parent, NULL, NULL, 760 he = __hists__add_entry(evsel__hists(evsel), al, iter->parent, NULL, NULL,
683 sample->period, sample->weight, 761 sample, true);
684 sample->transaction, true);
685 if (he == NULL) 762 if (he == NULL)
686 return -ENOMEM; 763 return -ENOMEM;
687 764
@@ -742,8 +819,7 @@ iter_add_single_cumulative_entry(struct hist_entry_iter *iter,
742 int err = 0; 819 int err = 0;
743 820
744 he = __hists__add_entry(hists, al, iter->parent, NULL, NULL, 821 he = __hists__add_entry(hists, al, iter->parent, NULL, NULL,
745 sample->period, sample->weight, 822 sample, true);
746 sample->transaction, true);
747 if (he == NULL) 823 if (he == NULL)
748 return -ENOMEM; 824 return -ENOMEM;
749 825
@@ -795,6 +871,8 @@ iter_add_next_cumulative_entry(struct hist_entry_iter *iter,
795 .sym = al->sym, 871 .sym = al->sym,
796 }, 872 },
797 .parent = iter->parent, 873 .parent = iter->parent,
874 .raw_data = sample->raw_data,
875 .raw_size = sample->raw_size,
798 }; 876 };
799 int i; 877 int i;
800 struct callchain_cursor cursor; 878 struct callchain_cursor cursor;
@@ -816,8 +894,7 @@ iter_add_next_cumulative_entry(struct hist_entry_iter *iter,
816 } 894 }
817 895
818 he = __hists__add_entry(evsel__hists(evsel), al, iter->parent, NULL, NULL, 896 he = __hists__add_entry(evsel__hists(evsel), al, iter->parent, NULL, NULL,
819 sample->period, sample->weight, 897 sample, false);
820 sample->transaction, false);
821 if (he == NULL) 898 if (he == NULL)
822 return -ENOMEM; 899 return -ENOMEM;
823 900
@@ -920,11 +997,13 @@ out:
920int64_t 997int64_t
921hist_entry__cmp(struct hist_entry *left, struct hist_entry *right) 998hist_entry__cmp(struct hist_entry *left, struct hist_entry *right)
922{ 999{
1000 struct hists *hists = left->hists;
923 struct perf_hpp_fmt *fmt; 1001 struct perf_hpp_fmt *fmt;
924 int64_t cmp = 0; 1002 int64_t cmp = 0;
925 1003
926 perf_hpp__for_each_sort_list(fmt) { 1004 hists__for_each_sort_list(hists, fmt) {
927 if (perf_hpp__should_skip(fmt)) 1005 if (perf_hpp__is_dynamic_entry(fmt) &&
1006 !perf_hpp__defined_dynamic_entry(fmt, hists))
928 continue; 1007 continue;
929 1008
930 cmp = fmt->cmp(fmt, left, right); 1009 cmp = fmt->cmp(fmt, left, right);
@@ -938,11 +1017,13 @@ hist_entry__cmp(struct hist_entry *left, struct hist_entry *right)
938int64_t 1017int64_t
939hist_entry__collapse(struct hist_entry *left, struct hist_entry *right) 1018hist_entry__collapse(struct hist_entry *left, struct hist_entry *right)
940{ 1019{
1020 struct hists *hists = left->hists;
941 struct perf_hpp_fmt *fmt; 1021 struct perf_hpp_fmt *fmt;
942 int64_t cmp = 0; 1022 int64_t cmp = 0;
943 1023
944 perf_hpp__for_each_sort_list(fmt) { 1024 hists__for_each_sort_list(hists, fmt) {
945 if (perf_hpp__should_skip(fmt)) 1025 if (perf_hpp__is_dynamic_entry(fmt) &&
1026 !perf_hpp__defined_dynamic_entry(fmt, hists))
946 continue; 1027 continue;
947 1028
948 cmp = fmt->collapse(fmt, left, right); 1029 cmp = fmt->collapse(fmt, left, right);
@@ -975,22 +1056,256 @@ void hist_entry__delete(struct hist_entry *he)
975 if (he->srcfile && he->srcfile[0]) 1056 if (he->srcfile && he->srcfile[0])
976 free(he->srcfile); 1057 free(he->srcfile);
977 free_callchain(he->callchain); 1058 free_callchain(he->callchain);
1059 free(he->trace_output);
1060 free(he->raw_data);
978 free(he); 1061 free(he);
979} 1062}
980 1063
981/* 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/*
982 * collapse the histogram 1086 * collapse the histogram
983 */ 1087 */
984 1088
985static bool hists__collapse_insert_entry(struct hists *hists __maybe_unused, 1089static void hists__apply_filters(struct hists *hists, 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,
986 struct rb_root *root, 1253 struct rb_root *root,
987 struct hist_entry *he) 1254 struct hist_entry *he)
988{ 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)
1300{
989 struct rb_node **p = &root->rb_node; 1301 struct rb_node **p = &root->rb_node;
990 struct rb_node *parent = NULL; 1302 struct rb_node *parent = NULL;
991 struct hist_entry *iter; 1303 struct hist_entry *iter;
992 int64_t cmp; 1304 int64_t cmp;
993 1305
1306 if (symbol_conf.report_hierarchy)
1307 return hists__hierarchy_insert_entry(hists, root, he);
1308
994 while (*p != NULL) { 1309 while (*p != NULL) {
995 parent = *p; 1310 parent = *p;
996 iter = rb_entry(parent, struct hist_entry, rb_node_in); 1311 iter = rb_entry(parent, struct hist_entry, rb_node_in);
@@ -998,18 +1313,21 @@ static bool hists__collapse_insert_entry(struct hists *hists __maybe_unused,
998 cmp = hist_entry__collapse(iter, he); 1313 cmp = hist_entry__collapse(iter, he);
999 1314
1000 if (!cmp) { 1315 if (!cmp) {
1316 int ret = 0;
1317
1001 he_stat__add_stat(&iter->stat, &he->stat); 1318 he_stat__add_stat(&iter->stat, &he->stat);
1002 if (symbol_conf.cumulate_callchain) 1319 if (symbol_conf.cumulate_callchain)
1003 he_stat__add_stat(iter->stat_acc, he->stat_acc); 1320 he_stat__add_stat(iter->stat_acc, he->stat_acc);
1004 1321
1005 if (symbol_conf.use_callchain) { 1322 if (symbol_conf.use_callchain) {
1006 callchain_cursor_reset(&callchain_cursor); 1323 callchain_cursor_reset(&callchain_cursor);
1007 callchain_merge(&callchain_cursor, 1324 if (callchain_merge(&callchain_cursor,
1008 iter->callchain, 1325 iter->callchain,
1009 he->callchain); 1326 he->callchain) < 0)
1327 ret = -1;
1010 } 1328 }
1011 hist_entry__delete(he); 1329 hist_entry__delete(he);
1012 return false; 1330 return ret;
1013 } 1331 }
1014 1332
1015 if (cmp < 0) 1333 if (cmp < 0)
@@ -1021,10 +1339,10 @@ static bool hists__collapse_insert_entry(struct hists *hists __maybe_unused,
1021 1339
1022 rb_link_node(&he->rb_node_in, parent, p); 1340 rb_link_node(&he->rb_node_in, parent, p);
1023 rb_insert_color(&he->rb_node_in, root); 1341 rb_insert_color(&he->rb_node_in, root);
1024 return true; 1342 return 1;
1025} 1343}
1026 1344
1027static struct rb_root *hists__get_rotate_entries_in(struct hists *hists) 1345struct rb_root *hists__get_rotate_entries_in(struct hists *hists)
1028{ 1346{
1029 struct rb_root *root; 1347 struct rb_root *root;
1030 1348
@@ -1047,14 +1365,15 @@ static void hists__apply_filters(struct hists *hists, struct hist_entry *he)
1047 hists__filter_entry_by_socket(hists, he); 1365 hists__filter_entry_by_socket(hists, he);
1048} 1366}
1049 1367
1050void hists__collapse_resort(struct hists *hists, struct ui_progress *prog) 1368int hists__collapse_resort(struct hists *hists, struct ui_progress *prog)
1051{ 1369{
1052 struct rb_root *root; 1370 struct rb_root *root;
1053 struct rb_node *next; 1371 struct rb_node *next;
1054 struct hist_entry *n; 1372 struct hist_entry *n;
1373 int ret;
1055 1374
1056 if (!sort__need_collapse) 1375 if (!sort__need_collapse)
1057 return; 1376 return 0;
1058 1377
1059 hists->nr_entries = 0; 1378 hists->nr_entries = 0;
1060 1379
@@ -1069,7 +1388,11 @@ void hists__collapse_resort(struct hists *hists, struct ui_progress *prog)
1069 next = rb_next(&n->rb_node_in); 1388 next = rb_next(&n->rb_node_in);
1070 1389
1071 rb_erase(&n->rb_node_in, root); 1390 rb_erase(&n->rb_node_in, root);
1072 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) {
1073 /* 1396 /*
1074 * If it wasn't combined with one of the entries already 1397 * If it wasn't combined with one of the entries already
1075 * collapsed, we need to apply the filters that may have 1398 * collapsed, we need to apply the filters that may have
@@ -1080,15 +1403,17 @@ void hists__collapse_resort(struct hists *hists, struct ui_progress *prog)
1080 if (prog) 1403 if (prog)
1081 ui_progress__update(prog, 1); 1404 ui_progress__update(prog, 1);
1082 } 1405 }
1406 return 0;
1083} 1407}
1084 1408
1085static 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)
1086{ 1410{
1411 struct hists *hists = a->hists;
1087 struct perf_hpp_fmt *fmt; 1412 struct perf_hpp_fmt *fmt;
1088 int64_t cmp = 0; 1413 int64_t cmp = 0;
1089 1414
1090 perf_hpp__for_each_sort_list(fmt) { 1415 hists__for_each_sort_list(hists, fmt) {
1091 if (perf_hpp__should_skip(fmt)) 1416 if (perf_hpp__should_skip(fmt, a->hists))
1092 continue; 1417 continue;
1093 1418
1094 cmp = fmt->sort(fmt, a, b); 1419 cmp = fmt->sort(fmt, a, b);
@@ -1128,6 +1453,113 @@ void hists__inc_stats(struct hists *hists, struct hist_entry *h)
1128 hists->stats.total_period += h->stat.period; 1453 hists->stats.total_period += h->stat.period;
1129} 1454}
1130 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
1131static void __hists__insert_output_entry(struct rb_root *entries, 1563static void __hists__insert_output_entry(struct rb_root *entries,
1132 struct hist_entry *he, 1564 struct hist_entry *he,
1133 u64 min_callchain_hits, 1565 u64 min_callchain_hits,
@@ -1136,10 +1568,20 @@ static void __hists__insert_output_entry(struct rb_root *entries,
1136 struct rb_node **p = &entries->rb_node; 1568 struct rb_node **p = &entries->rb_node;
1137 struct rb_node *parent = NULL; 1569 struct rb_node *parent = NULL;
1138 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;
1139 1576
1140 if (use_callchain) 1577 if (symbol_conf.cumulate_callchain)
1578 total = he->stat_acc->period;
1579
1580 min_callchain_hits = total * (callchain_param.min_percent / 100);
1581 }
1141 callchain_param.sort(&he->sorted_chain, he->callchain, 1582 callchain_param.sort(&he->sorted_chain, he->callchain,
1142 min_callchain_hits, &callchain_param); 1583 min_callchain_hits, &callchain_param);
1584 }
1143 1585
1144 while (*p != NULL) { 1586 while (*p != NULL) {
1145 parent = *p; 1587 parent = *p;
@@ -1153,23 +1595,41 @@ static void __hists__insert_output_entry(struct rb_root *entries,
1153 1595
1154 rb_link_node(&he->rb_node, parent, p); 1596 rb_link_node(&he->rb_node, parent, p);
1155 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 }
1156} 1604}
1157 1605
1158void 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)
1159{ 1608{
1160 struct rb_root *root; 1609 struct rb_root *root;
1161 struct rb_node *next; 1610 struct rb_node *next;
1162 struct hist_entry *n; 1611 struct hist_entry *n;
1612 u64 callchain_total;
1163 u64 min_callchain_hits; 1613 u64 min_callchain_hits;
1164 struct perf_evsel *evsel = hists_to_evsel(hists);
1165 bool use_callchain;
1166 1614
1167 if (evsel && symbol_conf.use_callchain && !symbol_conf.show_ref_callgraph) 1615 callchain_total = hists->callchain_period;
1168 use_callchain = evsel->attr.sample_type & PERF_SAMPLE_CALLCHAIN; 1616 if (symbol_conf.filter_relative)
1169 else 1617 callchain_total = hists->callchain_non_filtered_period;
1170 use_callchain = symbol_conf.use_callchain;
1171 1618
1172 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 }
1173 1633
1174 if (sort__need_collapse) 1634 if (sort__need_collapse)
1175 root = &hists->entries_collapsed; 1635 root = &hists->entries_collapsed;
@@ -1179,9 +1639,6 @@ void hists__output_resort(struct hists *hists, struct ui_progress *prog)
1179 next = rb_first(root); 1639 next = rb_first(root);
1180 hists->entries = RB_ROOT; 1640 hists->entries = RB_ROOT;
1181 1641
1182 hists__reset_stats(hists);
1183 hists__reset_col_len(hists);
1184
1185 while (next) { 1642 while (next) {
1186 n = rb_entry(next, struct hist_entry, rb_node_in); 1643 n = rb_entry(next, struct hist_entry, rb_node_in);
1187 next = rb_next(&n->rb_node_in); 1644 next = rb_next(&n->rb_node_in);
@@ -1197,15 +1654,136 @@ void hists__output_resort(struct hists *hists, struct ui_progress *prog)
1197 } 1654 }
1198} 1655}
1199 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
1200static 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,
1201 enum hist_filter filter) 1756 enum hist_filter filter)
1202{ 1757{
1203 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
1204 if (h->filtered) 1781 if (h->filtered)
1205 return; 1782 return;
1206 1783
1207 /* force fold unfiltered entry for simplicity */ 1784 /* force fold unfiltered entry for simplicity */
1208 h->unfolded = false; 1785 h->unfolded = false;
1786 h->has_no_entry = false;
1209 h->row_offset = 0; 1787 h->row_offset = 0;
1210 h->nr_rows = 0; 1788 h->nr_rows = 0;
1211 1789
@@ -1228,28 +1806,6 @@ static bool hists__filter_entry_by_dso(struct hists *hists,
1228 return false; 1806 return false;
1229} 1807}
1230 1808
1231void hists__filter_by_dso(struct hists *hists)
1232{
1233 struct rb_node *nd;
1234
1235 hists->stats.nr_non_filtered_samples = 0;
1236
1237 hists__reset_filter_stats(hists);
1238 hists__reset_col_len(hists);
1239
1240 for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) {
1241 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
1242
1243 if (symbol_conf.exclude_other && !h->parent)
1244 continue;
1245
1246 if (hists__filter_entry_by_dso(hists, h))
1247 continue;
1248
1249 hists__remove_entry_filter(hists, h, HIST_FILTER__DSO);
1250 }
1251}
1252
1253static bool hists__filter_entry_by_thread(struct hists *hists, 1809static bool hists__filter_entry_by_thread(struct hists *hists,
1254 struct hist_entry *he) 1810 struct hist_entry *he)
1255{ 1811{
@@ -1262,25 +1818,6 @@ static bool hists__filter_entry_by_thread(struct hists *hists,
1262 return false; 1818 return false;
1263} 1819}
1264 1820
1265void hists__filter_by_thread(struct hists *hists)
1266{
1267 struct rb_node *nd;
1268
1269 hists->stats.nr_non_filtered_samples = 0;
1270
1271 hists__reset_filter_stats(hists);
1272 hists__reset_col_len(hists);
1273
1274 for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) {
1275 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
1276
1277 if (hists__filter_entry_by_thread(hists, h))
1278 continue;
1279
1280 hists__remove_entry_filter(hists, h, HIST_FILTER__THREAD);
1281 }
1282}
1283
1284static bool hists__filter_entry_by_symbol(struct hists *hists, 1821static bool hists__filter_entry_by_symbol(struct hists *hists,
1285 struct hist_entry *he) 1822 struct hist_entry *he)
1286{ 1823{
@@ -1294,7 +1831,21 @@ static bool hists__filter_entry_by_symbol(struct hists *hists,
1294 return false; 1831 return false;
1295} 1832}
1296 1833
1297void 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)
1298{ 1849{
1299 struct rb_node *nd; 1850 struct rb_node *nd;
1300 1851
@@ -1306,42 +1857,155 @@ void hists__filter_by_symbol(struct hists *hists)
1306 for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) { 1857 for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) {
1307 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);
1308 1859
1309 if (hists__filter_entry_by_symbol(hists, h)) 1860 if (filter(hists, h))
1310 continue; 1861 continue;
1311 1862
1312 hists__remove_entry_filter(hists, h, HIST_FILTER__SYMBOL); 1863 hists__remove_entry_filter(hists, h, type);
1313 } 1864 }
1314} 1865}
1315 1866
1316static bool hists__filter_entry_by_socket(struct hists *hists, 1867static void resort_filtered_entry(struct rb_root *root, struct hist_entry *he)
1317 struct hist_entry *he)
1318{ 1868{
1319 if ((hists->socket_filter > -1) && 1869 struct rb_node **p = &root->rb_node;
1320 (he->socket != hists->socket_filter)) { 1870 struct rb_node *parent = NULL;
1321 he->filtered |= (1 << HIST_FILTER__SOCKET); 1871 struct hist_entry *iter;
1322 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;
1323 } 1883 }
1324 1884
1325 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;
1326} 1902}
1327 1903
1328void hists__filter_by_socket(struct hists *hists) 1904static void hists__filter_hierarchy(struct hists *hists, int type, const void *arg)
1329{ 1905{
1330 struct rb_node *nd; 1906 struct rb_node *nd;
1907 struct rb_root new_root = RB_ROOT;
1331 1908
1332 hists->stats.nr_non_filtered_samples = 0; 1909 hists->stats.nr_non_filtered_samples = 0;
1333 1910
1334 hists__reset_filter_stats(hists); 1911 hists__reset_filter_stats(hists);
1335 hists__reset_col_len(hists); 1912 hists__reset_col_len(hists);
1336 1913
1337 for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) { 1914 nd = rb_first(&hists->entries);
1915 while (nd) {
1338 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;
1339 1918
1340 if (hists__filter_entry_by_socket(hists, h)) 1919 ret = hist_entry__filter(h, type, arg);
1341 continue; 1920
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);
1342 1964
1343 hists__remove_entry_filter(hists, h, HIST_FILTER__SOCKET); 1965 resort_filtered_entry(&new_root, h);
1344 } 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);
1345} 2009}
1346 2010
1347void events_stats__inc(struct events_stats *stats, u32 type) 2011void events_stats__inc(struct events_stats *stats, u32 type)
@@ -1559,10 +2223,8 @@ int perf_hist_config(const char *var, const char *value)
1559 return 0; 2223 return 0;
1560} 2224}
1561 2225
1562static int hists_evsel__init(struct perf_evsel *evsel) 2226int __hists__init(struct hists *hists, struct perf_hpp_list *hpp_list)
1563{ 2227{
1564 struct hists *hists = evsel__hists(evsel);
1565
1566 memset(hists, 0, sizeof(*hists)); 2228 memset(hists, 0, sizeof(*hists));
1567 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;
1568 hists->entries_in = &hists->entries_in_array[0]; 2230 hists->entries_in = &hists->entries_in_array[0];
@@ -1570,6 +2232,56 @@ static int hists_evsel__init(struct perf_evsel *evsel)
1570 hists->entries = RB_ROOT; 2232 hists->entries = RB_ROOT;
1571 pthread_mutex_init(&hists->lock, NULL); 2233 pthread_mutex_init(&hists->lock, NULL);
1572 hists->socket_filter = -1; 2234 hists->socket_filter = -1;
2235 hists->hpp_list = hpp_list;
2236 INIT_LIST_HEAD(&hists->hpp_formats);
2237 return 0;
2238}
2239
2240static void hists__delete_remaining_entries(struct rb_root *root)
2241{
2242 struct rb_node *node;
2243 struct hist_entry *he;
2244
2245 while (!RB_EMPTY_ROOT(root)) {
2246 node = rb_first(root);
2247 rb_erase(node, root);
2248
2249 he = rb_entry(node, struct hist_entry, rb_node_in);
2250 hist_entry__delete(he);
2251 }
2252}
2253
2254static void hists__delete_all_entries(struct hists *hists)
2255{
2256 hists__delete_entries(hists);
2257 hists__delete_remaining_entries(&hists->entries_in_array[0]);
2258 hists__delete_remaining_entries(&hists->entries_in_array[1]);
2259 hists__delete_remaining_entries(&hists->entries_collapsed);
2260}
2261
2262static void hists_evsel__exit(struct perf_evsel *evsel)
2263{
2264 struct hists *hists = evsel__hists(evsel);
2265 struct perf_hpp_fmt *fmt, *pos;
2266 struct perf_hpp_list_node *node, *tmp;
2267
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 }
2278}
2279
2280static int hists_evsel__init(struct perf_evsel *evsel)
2281{
2282 struct hists *hists = evsel__hists(evsel);
2283
2284 __hists__init(hists, &perf_hpp_list);
1573 return 0; 2285 return 0;
1574} 2286}
1575 2287
@@ -1581,9 +2293,16 @@ static int hists_evsel__init(struct perf_evsel *evsel)
1581int hists__init(void) 2293int hists__init(void)
1582{ 2294{
1583 int err = perf_evsel__object_config(sizeof(struct hists_evsel), 2295 int err = perf_evsel__object_config(sizeof(struct hists_evsel),
1584 hists_evsel__init, NULL); 2296 hists_evsel__init,
2297 hists_evsel__exit);
1585 if (err) 2298 if (err)
1586 fputs("FATAL ERROR: Couldn't setup hists class\n", stderr); 2299 fputs("FATAL ERROR: Couldn't setup hists class\n", stderr);
1587 2300
1588 return err; 2301 return err;
1589} 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 a48a2078d288..bec0cd660fbd 100644
--- a/tools/perf/util/hist.h
+++ b/tools/perf/util/hist.h
@@ -52,6 +52,7 @@ enum hist_column {
52 HISTC_MEM_IADDR_SYMBOL, 52 HISTC_MEM_IADDR_SYMBOL,
53 HISTC_TRANSACTION, 53 HISTC_TRANSACTION,
54 HISTC_CYCLES, 54 HISTC_CYCLES,
55 HISTC_TRACE,
55 HISTC_NR_COLS, /* Last entry */ 56 HISTC_NR_COLS, /* Last entry */
56}; 57};
57 58
@@ -65,6 +66,8 @@ struct hists {
65 struct rb_root entries_collapsed; 66 struct rb_root entries_collapsed;
66 u64 nr_entries; 67 u64 nr_entries;
67 u64 nr_non_filtered_entries; 68 u64 nr_non_filtered_entries;
69 u64 callchain_period;
70 u64 callchain_non_filtered_period;
68 struct thread *thread_filter; 71 struct thread *thread_filter;
69 const struct dso *dso_filter; 72 const struct dso *dso_filter;
70 const char *uid_filter_str; 73 const char *uid_filter_str;
@@ -74,6 +77,9 @@ struct hists {
74 u64 event_stream; 77 u64 event_stream;
75 u16 col_len[HISTC_NR_COLS]; 78 u16 col_len[HISTC_NR_COLS];
76 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;
77}; 83};
78 84
79struct hist_entry_iter; 85struct hist_entry_iter;
@@ -114,21 +120,27 @@ struct hist_entry *__hists__add_entry(struct hists *hists,
114 struct addr_location *al, 120 struct addr_location *al,
115 struct symbol *parent, 121 struct symbol *parent,
116 struct branch_info *bi, 122 struct branch_info *bi,
117 struct mem_info *mi, u64 period, 123 struct mem_info *mi,
118 u64 weight, u64 transaction, 124 struct perf_sample *sample,
119 bool sample_self); 125 bool sample_self);
120int 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,
121 int max_stack_depth, void *arg); 127 int max_stack_depth, void *arg);
122 128
129struct perf_hpp;
130struct perf_hpp_fmt;
131
123int64_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);
124int64_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);
125int hist_entry__transaction_len(void); 134int hist_entry__transaction_len(void);
126int 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,
127 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);
128void hist_entry__delete(struct hist_entry *he); 139void hist_entry__delete(struct hist_entry *he);
129 140
141void perf_evsel__output_resort(struct perf_evsel *evsel, struct ui_progress *prog);
130void hists__output_resort(struct hists *hists, struct ui_progress *prog); 142void hists__output_resort(struct hists *hists, struct ui_progress *prog);
131void hists__collapse_resort(struct hists *hists, struct ui_progress *prog); 143int hists__collapse_resort(struct hists *hists, struct ui_progress *prog);
132 144
133void 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);
134void hists__delete_entries(struct hists *hists); 146void hists__delete_entries(struct hists *hists);
@@ -184,6 +196,11 @@ static inline struct hists *evsel__hists(struct perf_evsel *evsel)
184} 196}
185 197
186int hists__init(void); 198int hists__init(void);
199int __hists__init(struct hists *hists, struct perf_hpp_list *hpp_list);
200
201struct rb_root *hists__get_rotate_entries_in(struct hists *hists);
202int hists__collapse_insert_entry(struct hists *hists,
203 struct rb_root *root, struct hist_entry *he);
187 204
188struct perf_hpp { 205struct perf_hpp {
189 char *buf; 206 char *buf;
@@ -208,28 +225,64 @@ struct perf_hpp_fmt {
208 struct hist_entry *a, struct hist_entry *b); 225 struct hist_entry *a, struct hist_entry *b);
209 int64_t (*sort)(struct perf_hpp_fmt *fmt, 226 int64_t (*sort)(struct perf_hpp_fmt *fmt,
210 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);
211 230
212 struct list_head list; 231 struct list_head list;
213 struct list_head sort_list; 232 struct list_head sort_list;
214 bool elide; 233 bool elide;
215 int len; 234 int len;
216 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;
243};
244
245extern struct perf_hpp_list perf_hpp_list;
246
247struct perf_hpp_list_node {
248 struct list_head list;
249 struct perf_hpp_list hpp;
250 int level;
251 bool skip;
217}; 252};
218 253
219extern struct list_head perf_hpp__list; 254void perf_hpp_list__column_register(struct perf_hpp_list *list,
220extern struct list_head perf_hpp__sort_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)
221 271
222#define perf_hpp__for_each_format(format) \ 272#define perf_hpp_list__for_each_format_safe(_list, format, tmp) \
223 list_for_each_entry(format, &perf_hpp__list, list) 273 list_for_each_entry_safe(format, tmp, &(_list)->fields, list)
224 274
225#define perf_hpp__for_each_format_safe(format, tmp) \ 275#define perf_hpp_list__for_each_sort_list(_list, format) \
226 list_for_each_entry_safe(format, tmp, &perf_hpp__list, list) 276 list_for_each_entry(format, &(_list)->sorts, sort_list)
227 277
228#define perf_hpp__for_each_sort_list(format) \ 278#define perf_hpp_list__for_each_sort_list_safe(_list, format, tmp) \
229 list_for_each_entry(format, &perf_hpp__sort_list, sort_list) 279 list_for_each_entry_safe(format, tmp, &(_list)->sorts, sort_list)
230 280
231#define perf_hpp__for_each_sort_list_safe(format, tmp) \ 281#define hists__for_each_format(hists, format) \
232 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)
233 286
234extern struct perf_hpp_fmt perf_hpp__format[]; 287extern struct perf_hpp_fmt perf_hpp__format[];
235 288
@@ -248,23 +301,41 @@ enum {
248}; 301};
249 302
250void perf_hpp__init(void); 303void perf_hpp__init(void);
251void perf_hpp__column_register(struct perf_hpp_fmt *format);
252void perf_hpp__column_unregister(struct perf_hpp_fmt *format); 304void perf_hpp__column_unregister(struct perf_hpp_fmt *format);
253void perf_hpp__column_enable(unsigned col);
254void perf_hpp__column_disable(unsigned col);
255void 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);
256 311
257void perf_hpp__register_sort_field(struct perf_hpp_fmt *format);
258void perf_hpp__setup_output_field(void);
259void perf_hpp__reset_output_field(void);
260void perf_hpp__append_sort_keys(void);
261 312
262bool perf_hpp__is_sort_entry(struct perf_hpp_fmt *format); 313bool perf_hpp__is_sort_entry(struct perf_hpp_fmt *format);
263bool perf_hpp__same_sort_entry(struct perf_hpp_fmt *a, struct perf_hpp_fmt *b); 314bool perf_hpp__is_dynamic_entry(struct perf_hpp_fmt *format);
264 315bool perf_hpp__defined_dynamic_entry(struct perf_hpp_fmt *fmt, struct hists *hists);
265static inline bool perf_hpp__should_skip(struct perf_hpp_fmt *format) 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);
327
328static inline bool perf_hpp__should_skip(struct perf_hpp_fmt *format,
329 struct hists *hists)
266{ 330{
267 return format->elide; 331 if (format->elide)
332 return true;
333
334 if (perf_hpp__is_dynamic_entry(format) &&
335 !perf_hpp__defined_dynamic_entry(format, hists))
336 return true;
337
338 return false;
268} 339}
269 340
270void perf_hpp__reset_width(struct perf_hpp_fmt *fmt, struct hists *hists); 341void perf_hpp__reset_width(struct perf_hpp_fmt *fmt, struct hists *hists);
@@ -356,13 +427,35 @@ static inline int script_browse(const char *script_opt __maybe_unused)
356#endif 427#endif
357 428
358unsigned 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);
359 431
360void hist__account_cycles(struct branch_stack *bs, struct addr_location *al, 432void hist__account_cycles(struct branch_stack *bs, struct addr_location *al,
361 struct perf_sample *sample, bool nonany_branch_mode); 433 struct perf_sample *sample, bool nonany_branch_mode);
362 434
363struct option; 435struct option;
364int parse_filter_percentage(const struct option *opt __maybe_unused, 436int parse_filter_percentage(const struct option *opt, const char *arg, int unset);
365 const char *arg, int unset __maybe_unused);
366int perf_hist_config(const char *var, const char *value); 437int perf_hist_config(const char *var, const char *value);
367 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
368#endif /* __PERF_HIST_H */ 461#endif /* __PERF_HIST_H */
diff --git a/tools/perf/util/include/linux/bitmap.h b/tools/perf/util/include/linux/bitmap.h
deleted file mode 100644
index 40bd21488032..000000000000
--- a/tools/perf/util/include/linux/bitmap.h
+++ /dev/null
@@ -1,66 +0,0 @@
1#ifndef _PERF_BITOPS_H
2#define _PERF_BITOPS_H
3
4#include <string.h>
5#include <linux/bitops.h>
6
7#define DECLARE_BITMAP(name,bits) \
8 unsigned long name[BITS_TO_LONGS(bits)]
9
10int __bitmap_weight(const unsigned long *bitmap, int bits);
11void __bitmap_or(unsigned long *dst, const unsigned long *bitmap1,
12 const unsigned long *bitmap2, int bits);
13
14#define BITMAP_LAST_WORD_MASK(nbits) \
15( \
16 ((nbits) % BITS_PER_LONG) ? \
17 (1UL<<((nbits) % BITS_PER_LONG))-1 : ~0UL \
18)
19
20#define small_const_nbits(nbits) \
21 (__builtin_constant_p(nbits) && (nbits) <= BITS_PER_LONG)
22
23static inline void bitmap_zero(unsigned long *dst, int nbits)
24{
25 if (small_const_nbits(nbits))
26 *dst = 0UL;
27 else {
28 int len = BITS_TO_LONGS(nbits) * sizeof(unsigned long);
29 memset(dst, 0, len);
30 }
31}
32
33static inline int bitmap_weight(const unsigned long *src, int nbits)
34{
35 if (small_const_nbits(nbits))
36 return hweight_long(*src & BITMAP_LAST_WORD_MASK(nbits));
37 return __bitmap_weight(src, nbits);
38}
39
40static inline void bitmap_or(unsigned long *dst, const unsigned long *src1,
41 const unsigned long *src2, int nbits)
42{
43 if (small_const_nbits(nbits))
44 *dst = *src1 | *src2;
45 else
46 __bitmap_or(dst, src1, src2, nbits);
47}
48
49/**
50 * test_and_set_bit - Set a bit and return its old value
51 * @nr: Bit to set
52 * @addr: Address to count from
53 */
54static inline int test_and_set_bit(int nr, unsigned long *addr)
55{
56 unsigned long mask = BIT_MASK(nr);
57 unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr);
58 unsigned long old;
59
60 old = *p;
61 *p = old | mask;
62
63 return (old & mask) != 0;
64}
65
66#endif /* _PERF_BITOPS_H */
diff --git a/tools/perf/util/include/linux/string.h b/tools/perf/util/include/linux/string.h
deleted file mode 100644
index 6f19c548ecc0..000000000000
--- a/tools/perf/util/include/linux/string.h
+++ /dev/null
@@ -1,3 +0,0 @@
1#include <string.h>
2
3void *memdup(const void *src, size_t len);
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 97f963a3dcb9..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;
@@ -1744,7 +1747,7 @@ static void intel_pt_free(struct perf_session *session)
1744 auxtrace_heap__free(&pt->heap); 1747 auxtrace_heap__free(&pt->heap);
1745 intel_pt_free_events(session); 1748 intel_pt_free_events(session);
1746 session->auxtrace = NULL; 1749 session->auxtrace = NULL;
1747 thread__delete(pt->unknown_thread); 1750 thread__put(pt->unknown_thread);
1748 free(pt); 1751 free(pt);
1749} 1752}
1750 1753
@@ -2068,6 +2071,15 @@ int intel_pt_process_auxtrace_info(union perf_event *event,
2068 err = -ENOMEM; 2071 err = -ENOMEM;
2069 goto err_free_queues; 2072 goto err_free_queues;
2070 } 2073 }
2074
2075 /*
2076 * Since this thread will not be kept in any rbtree not in a
2077 * list, initialize its list node so that at thread__put() the
2078 * current thread lifetime assuption is kept and we don't segfault
2079 * at list_del_init().
2080 */
2081 INIT_LIST_HEAD(&pt->unknown_thread->node);
2082
2071 err = thread__set_comm(pt->unknown_thread, "unknown", 0); 2083 err = thread__set_comm(pt->unknown_thread, "unknown", 0);
2072 if (err) 2084 if (err)
2073 goto err_delete_thread; 2085 goto err_delete_thread;
@@ -2153,7 +2165,7 @@ int intel_pt_process_auxtrace_info(union perf_event *event,
2153 return 0; 2165 return 0;
2154 2166
2155err_delete_thread: 2167err_delete_thread:
2156 thread__delete(pt->unknown_thread); 2168 thread__zput(pt->unknown_thread);
2157err_free_queues: 2169err_free_queues:
2158 intel_pt_log_disable(); 2170 intel_pt_log_disable();
2159 auxtrace_queues__free(&pt->queues); 2171 auxtrace_queues__free(&pt->queues);
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 4f6a4780bd5f..33071d6159bc 100644
--- a/tools/perf/util/llvm-utils.c
+++ b/tools/perf/util/llvm-utils.c
@@ -3,18 +3,19 @@
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 <sys/utsname.h> 8#include <stdlib.h>
8#include "util.h"
9#include "debug.h" 9#include "debug.h"
10#include "llvm-utils.h" 10#include "llvm-utils.h"
11#include "cache.h"
12 11
13#define CLANG_BPF_CMD_DEFAULT_TEMPLATE \ 12#define CLANG_BPF_CMD_DEFAULT_TEMPLATE \
14 "$CLANG_EXEC -D__KERNEL__ $CLANG_OPTIONS " \ 13 "$CLANG_EXEC -D__KERNEL__ -D__NR_CPUS__=$NR_CPUS "\
15 "$KERNEL_INC_OPTIONS -Wno-unused-value " \ 14 "-DLINUX_VERSION_CODE=$LINUX_VERSION_CODE " \
16 "-Wno-pointer-sign -working-directory " \ 15 "$CLANG_OPTIONS $KERNEL_INC_OPTIONS " \
17 "$WORKING_DIR -c \"$CLANG_SOURCE\" -target bpf -O2 -o -" 16 "-Wno-unused-value -Wno-pointer-sign " \
17 "-working-directory $WORKING_DIR " \
18 "-c \"$CLANG_SOURCE\" -target bpf -O2 -o -"
18 19
19struct llvm_param llvm_param = { 20struct llvm_param llvm_param = {
20 .clang_path = "clang", 21 .clang_path = "clang",
@@ -97,11 +98,12 @@ read_from_pipe(const char *cmd, void **p_buf, size_t *p_read_sz)
97 void *buf = NULL; 98 void *buf = NULL;
98 FILE *file = NULL; 99 FILE *file = NULL;
99 size_t read_sz = 0, buf_sz = 0; 100 size_t read_sz = 0, buf_sz = 0;
101 char serr[STRERR_BUFSIZE];
100 102
101 file = popen(cmd, "r"); 103 file = popen(cmd, "r");
102 if (!file) { 104 if (!file) {
103 pr_err("ERROR: unable to popen cmd: %s\n", 105 pr_err("ERROR: unable to popen cmd: %s\n",
104 strerror(errno)); 106 strerror_r(errno, serr, sizeof(serr)));
105 return -EINVAL; 107 return -EINVAL;
106 } 108 }
107 109
@@ -135,7 +137,7 @@ read_from_pipe(const char *cmd, void **p_buf, size_t *p_read_sz)
135 137
136 if (ferror(file)) { 138 if (ferror(file)) {
137 pr_err("ERROR: error occurred when reading from pipe: %s\n", 139 pr_err("ERROR: error occurred when reading from pipe: %s\n",
138 strerror(errno)); 140 strerror_r(errno, serr, sizeof(serr)));
139 err = -EIO; 141 err = -EIO;
140 goto errout; 142 goto errout;
141 } 143 }
@@ -214,18 +216,19 @@ static int detect_kbuild_dir(char **kbuild_dir)
214 const char *suffix_dir = ""; 216 const char *suffix_dir = "";
215 217
216 char *autoconf_path; 218 char *autoconf_path;
217 struct utsname utsname;
218 219
219 int err; 220 int err;
220 221
221 if (!test_dir) { 222 if (!test_dir) {
222 err = uname(&utsname); 223 /* _UTSNAME_LENGTH is 65 */
223 if (err) { 224 char release[128];
224 pr_warning("uname failed: %s\n", strerror(errno)); 225
226 err = fetch_kernel_version(NULL, release,
227 sizeof(release));
228 if (err)
225 return -EINVAL; 229 return -EINVAL;
226 }
227 230
228 test_dir = utsname.release; 231 test_dir = release;
229 prefix_dir = "/lib/modules/"; 232 prefix_dir = "/lib/modules/";
230 suffix_dir = "/build"; 233 suffix_dir = "/build";
231 } 234 }
@@ -326,13 +329,23 @@ get_kbuild_opts(char **kbuild_dir, char **kbuild_include_opts)
326int llvm__compile_bpf(const char *path, void **p_obj_buf, 329int llvm__compile_bpf(const char *path, void **p_obj_buf,
327 size_t *p_obj_buf_sz) 330 size_t *p_obj_buf_sz)
328{ 331{
329 int err; 332 size_t obj_buf_sz;
330 char clang_path[PATH_MAX]; 333 void *obj_buf = NULL;
334 int err, nr_cpus_avail;
335 unsigned int kernel_version;
336 char linux_version_code_str[64];
331 const char *clang_opt = llvm_param.clang_opt; 337 const char *clang_opt = llvm_param.clang_opt;
332 const char *template = llvm_param.clang_bpf_cmd_template; 338 char clang_path[PATH_MAX], abspath[PATH_MAX], nr_cpus_avail_str[64];
339 char serr[STRERR_BUFSIZE];
333 char *kbuild_dir = NULL, *kbuild_include_opts = NULL; 340 char *kbuild_dir = NULL, *kbuild_include_opts = NULL;
334 void *obj_buf = NULL; 341 const char *template = llvm_param.clang_bpf_cmd_template;
335 size_t obj_buf_sz; 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 }
336 349
337 if (!template) 350 if (!template)
338 template = CLANG_BPF_CMD_DEFAULT_TEMPLATE; 351 template = CLANG_BPF_CMD_DEFAULT_TEMPLATE;
@@ -354,6 +367,24 @@ int llvm__compile_bpf(const char *path, void **p_obj_buf,
354 */ 367 */
355 get_kbuild_opts(&kbuild_dir, &kbuild_include_opts); 368 get_kbuild_opts(&kbuild_dir, &kbuild_include_opts);
356 369
370 nr_cpus_avail = sysconf(_SC_NPROCESSORS_CONF);
371 if (nr_cpus_avail <= 0) {
372 pr_err(
373"WARNING:\tunable to get available CPUs in this system: %s\n"
374" \tUse 128 instead.\n", strerror_r(errno, serr, sizeof(serr)));
375 nr_cpus_avail = 128;
376 }
377 snprintf(nr_cpus_avail_str, sizeof(nr_cpus_avail_str), "%d",
378 nr_cpus_avail);
379
380 if (fetch_kernel_version(&kernel_version, NULL, 0))
381 kernel_version = 0;
382
383 snprintf(linux_version_code_str, sizeof(linux_version_code_str),
384 "0x%x", kernel_version);
385
386 force_set_env("NR_CPUS", nr_cpus_avail_str);
387 force_set_env("LINUX_VERSION_CODE", linux_version_code_str);
357 force_set_env("CLANG_EXEC", clang_path); 388 force_set_env("CLANG_EXEC", clang_path);
358 force_set_env("CLANG_OPTIONS", clang_opt); 389 force_set_env("CLANG_OPTIONS", clang_opt);
359 force_set_env("KERNEL_INC_OPTIONS", kbuild_include_opts); 390 force_set_env("KERNEL_INC_OPTIONS", kbuild_include_opts);
@@ -365,8 +396,7 @@ int llvm__compile_bpf(const char *path, void **p_obj_buf,
365 * stdin to be source file (testing). 396 * stdin to be source file (testing).
366 */ 397 */
367 force_set_env("CLANG_SOURCE", 398 force_set_env("CLANG_SOURCE",
368 (path[0] == '-') ? path : 399 (path[0] == '-') ? path : abspath);
369 make_nonrelative_path(path));
370 400
371 pr_debug("llvm compiling command template: %s\n", template); 401 pr_debug("llvm compiling command template: %s\n", template);
372 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 5ef90be2a249..80b9b6a87990 100644
--- a/tools/perf/util/machine.c
+++ b/tools/perf/util/machine.c
@@ -25,6 +25,7 @@ static void dsos__init(struct dsos *dsos)
25 25
26int machine__init(struct machine *machine, const char *root_dir, pid_t pid) 26int machine__init(struct machine *machine, const char *root_dir, pid_t pid)
27{ 27{
28 memset(machine, 0, sizeof(*machine));
28 map_groups__init(&machine->kmaps, machine); 29 map_groups__init(&machine->kmaps, machine);
29 RB_CLEAR_NODE(&machine->rb_node); 30 RB_CLEAR_NODE(&machine->rb_node);
30 dsos__init(&machine->dsos); 31 dsos__init(&machine->dsos);
@@ -44,6 +45,8 @@ int machine__init(struct machine *machine, const char *root_dir, pid_t pid)
44 machine->comm_exec = false; 45 machine->comm_exec = false;
45 machine->kernel_start = 0; 46 machine->kernel_start = 0;
46 47
48 memset(machine->vmlinux_maps, 0, sizeof(machine->vmlinux_maps));
49
47 machine->root_dir = strdup(root_dir); 50 machine->root_dir = strdup(root_dir);
48 if (machine->root_dir == NULL) 51 if (machine->root_dir == NULL)
49 return -ENOMEM; 52 return -ENOMEM;
@@ -91,6 +94,7 @@ static void dsos__purge(struct dsos *dsos)
91 94
92 list_for_each_entry_safe(pos, n, &dsos->head, node) { 95 list_for_each_entry_safe(pos, n, &dsos->head, node) {
93 RB_CLEAR_NODE(&pos->rb_node); 96 RB_CLEAR_NODE(&pos->rb_node);
97 pos->root = NULL;
94 list_del_init(&pos->node); 98 list_del_init(&pos->node);
95 dso__put(pos); 99 dso__put(pos);
96 } 100 }
@@ -121,6 +125,7 @@ void machine__delete_threads(struct machine *machine)
121 125
122void machine__exit(struct machine *machine) 126void machine__exit(struct machine *machine)
123{ 127{
128 machine__destroy_kernel_maps(machine);
124 map_groups__exit(&machine->kmaps); 129 map_groups__exit(&machine->kmaps);
125 dsos__exit(&machine->dsos); 130 dsos__exit(&machine->dsos);
126 machine__exit_vdso(machine); 131 machine__exit_vdso(machine);
@@ -347,13 +352,18 @@ static void machine__update_thread_pid(struct machine *machine,
347 } 352 }
348 353
349 th->mg = map_groups__get(leader->mg); 354 th->mg = map_groups__get(leader->mg);
350 355out_put:
356 thread__put(leader);
351 return; 357 return;
352
353out_err: 358out_err:
354 pr_err("Failed to join map groups for %d:%d\n", th->pid_, th->tid); 359 pr_err("Failed to join map groups for %d:%d\n", th->pid_, th->tid);
360 goto out_put;
355} 361}
356 362
363/*
364 * Caller must eventually drop thread->refcnt returned with a successfull
365 * lookup/new thread inserted.
366 */
357static struct thread *____machine__findnew_thread(struct machine *machine, 367static struct thread *____machine__findnew_thread(struct machine *machine,
358 pid_t pid, pid_t tid, 368 pid_t pid, pid_t tid,
359 bool create) 369 bool create)
@@ -371,7 +381,7 @@ static struct thread *____machine__findnew_thread(struct machine *machine,
371 if (th != NULL) { 381 if (th != NULL) {
372 if (th->tid == tid) { 382 if (th->tid == tid) {
373 machine__update_thread_pid(machine, th, pid); 383 machine__update_thread_pid(machine, th, pid);
374 return th; 384 return thread__get(th);
375 } 385 }
376 386
377 machine->last_match = NULL; 387 machine->last_match = NULL;
@@ -384,7 +394,7 @@ static struct thread *____machine__findnew_thread(struct machine *machine,
384 if (th->tid == tid) { 394 if (th->tid == tid) {
385 machine->last_match = th; 395 machine->last_match = th;
386 machine__update_thread_pid(machine, th, pid); 396 machine__update_thread_pid(machine, th, pid);
387 return th; 397 return thread__get(th);
388 } 398 }
389 399
390 if (tid < th->tid) 400 if (tid < th->tid)
@@ -412,7 +422,7 @@ static struct thread *____machine__findnew_thread(struct machine *machine,
412 if (thread__init_map_groups(th, machine)) { 422 if (thread__init_map_groups(th, machine)) {
413 rb_erase_init(&th->rb_node, &machine->threads); 423 rb_erase_init(&th->rb_node, &machine->threads);
414 RB_CLEAR_NODE(&th->rb_node); 424 RB_CLEAR_NODE(&th->rb_node);
415 thread__delete(th); 425 thread__put(th);
416 return NULL; 426 return NULL;
417 } 427 }
418 /* 428 /*
@@ -436,7 +446,7 @@ struct thread *machine__findnew_thread(struct machine *machine, pid_t pid,
436 struct thread *th; 446 struct thread *th;
437 447
438 pthread_rwlock_wrlock(&machine->threads_lock); 448 pthread_rwlock_wrlock(&machine->threads_lock);
439 th = thread__get(__machine__findnew_thread(machine, pid, tid)); 449 th = __machine__findnew_thread(machine, pid, tid);
440 pthread_rwlock_unlock(&machine->threads_lock); 450 pthread_rwlock_unlock(&machine->threads_lock);
441 return th; 451 return th;
442} 452}
@@ -446,7 +456,7 @@ struct thread *machine__find_thread(struct machine *machine, pid_t pid,
446{ 456{
447 struct thread *th; 457 struct thread *th;
448 pthread_rwlock_rdlock(&machine->threads_lock); 458 pthread_rwlock_rdlock(&machine->threads_lock);
449 th = thread__get(____machine__findnew_thread(machine, pid, tid, false)); 459 th = ____machine__findnew_thread(machine, pid, tid, false);
450 pthread_rwlock_unlock(&machine->threads_lock); 460 pthread_rwlock_unlock(&machine->threads_lock);
451 return th; 461 return th;
452} 462}
@@ -559,11 +569,29 @@ int machine__process_switch_event(struct machine *machine __maybe_unused,
559 return 0; 569 return 0;
560} 570}
561 571
572static void dso__adjust_kmod_long_name(struct dso *dso, const char *filename)
573{
574 const char *dup_filename;
575
576 if (!filename || !dso || !dso->long_name)
577 return;
578 if (dso->long_name[0] != '[')
579 return;
580 if (!strchr(filename, '/'))
581 return;
582
583 dup_filename = strdup(filename);
584 if (!dup_filename)
585 return;
586
587 dso__set_long_name(dso, dup_filename, true);
588}
589
562struct map *machine__findnew_module_map(struct machine *machine, u64 start, 590struct map *machine__findnew_module_map(struct machine *machine, u64 start,
563 const char *filename) 591 const char *filename)
564{ 592{
565 struct map *map = NULL; 593 struct map *map = NULL;
566 struct dso *dso; 594 struct dso *dso = NULL;
567 struct kmod_path m; 595 struct kmod_path m;
568 596
569 if (kmod_path__parse_name(&m, filename)) 597 if (kmod_path__parse_name(&m, filename))
@@ -571,8 +599,15 @@ struct map *machine__findnew_module_map(struct machine *machine, u64 start,
571 599
572 map = map_groups__find_by_name(&machine->kmaps, MAP__FUNCTION, 600 map = map_groups__find_by_name(&machine->kmaps, MAP__FUNCTION,
573 m.name); 601 m.name);
574 if (map) 602 if (map) {
603 /*
604 * If the map's dso is an offline module, give dso__load()
605 * a chance to find the file path of that module by fixing
606 * long_name.
607 */
608 dso__adjust_kmod_long_name(map->dso, filename);
575 goto out; 609 goto out;
610 }
576 611
577 dso = machine__findnew_module_dso(machine, &m, filename); 612 dso = machine__findnew_module_dso(machine, &m, filename);
578 if (dso == NULL) 613 if (dso == NULL)
@@ -584,7 +619,11 @@ struct map *machine__findnew_module_map(struct machine *machine, u64 start,
584 619
585 map_groups__insert(&machine->kmaps, map); 620 map_groups__insert(&machine->kmaps, map);
586 621
622 /* Put the map here because map_groups__insert alread got it */
623 map__put(map);
587out: 624out:
625 /* put the dso here, corresponding to machine__findnew_module_dso */
626 dso__put(dso);
588 free(m.name); 627 free(m.name);
589 return map; 628 return map;
590} 629}
@@ -739,6 +778,9 @@ int __machine__create_kernel_maps(struct machine *machine, struct dso *kernel)
739 enum map_type type; 778 enum map_type type;
740 u64 start = machine__get_running_kernel_start(machine, NULL); 779 u64 start = machine__get_running_kernel_start(machine, NULL);
741 780
781 /* In case of renewal the kernel map, destroy previous one */
782 machine__destroy_kernel_maps(machine);
783
742 for (type = 0; type < MAP__NR_TYPES; ++type) { 784 for (type = 0; type < MAP__NR_TYPES; ++type) {
743 struct kmap *kmap; 785 struct kmap *kmap;
744 struct map *map; 786 struct map *map;
@@ -787,6 +829,7 @@ void machine__destroy_kernel_maps(struct machine *machine)
787 kmap->ref_reloc_sym = NULL; 829 kmap->ref_reloc_sym = NULL;
788 } 830 }
789 831
832 map__put(machine->vmlinux_maps[type]);
790 machine->vmlinux_maps[type] = NULL; 833 machine->vmlinux_maps[type] = NULL;
791 } 834 }
792} 835}
@@ -1083,11 +1126,14 @@ int machine__create_kernel_maps(struct machine *machine)
1083 struct dso *kernel = machine__get_kernel(machine); 1126 struct dso *kernel = machine__get_kernel(machine);
1084 const char *name; 1127 const char *name;
1085 u64 addr = machine__get_running_kernel_start(machine, &name); 1128 u64 addr = machine__get_running_kernel_start(machine, &name);
1086 if (!addr) 1129 int ret;
1130
1131 if (!addr || kernel == NULL)
1087 return -1; 1132 return -1;
1088 1133
1089 if (kernel == NULL || 1134 ret = __machine__create_kernel_maps(machine, kernel);
1090 __machine__create_kernel_maps(machine, kernel) < 0) 1135 dso__put(kernel);
1136 if (ret < 0)
1091 return -1; 1137 return -1;
1092 1138
1093 if (symbol_conf.use_modules && machine__create_modules(machine) < 0) { 1139 if (symbol_conf.use_modules && machine__create_modules(machine) < 0) {
@@ -1255,9 +1301,8 @@ out_problem:
1255 1301
1256int machine__process_mmap2_event(struct machine *machine, 1302int machine__process_mmap2_event(struct machine *machine,
1257 union perf_event *event, 1303 union perf_event *event,
1258 struct perf_sample *sample __maybe_unused) 1304 struct perf_sample *sample)
1259{ 1305{
1260 u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
1261 struct thread *thread; 1306 struct thread *thread;
1262 struct map *map; 1307 struct map *map;
1263 enum map_type type; 1308 enum map_type type;
@@ -1266,8 +1311,8 @@ int machine__process_mmap2_event(struct machine *machine,
1266 if (dump_trace) 1311 if (dump_trace)
1267 perf_event__fprintf_mmap2(event, stdout); 1312 perf_event__fprintf_mmap2(event, stdout);
1268 1313
1269 if (cpumode == PERF_RECORD_MISC_GUEST_KERNEL || 1314 if (sample->cpumode == PERF_RECORD_MISC_GUEST_KERNEL ||
1270 cpumode == PERF_RECORD_MISC_KERNEL) { 1315 sample->cpumode == PERF_RECORD_MISC_KERNEL) {
1271 ret = machine__process_kernel_mmap_event(machine, event); 1316 ret = machine__process_kernel_mmap_event(machine, event);
1272 if (ret < 0) 1317 if (ret < 0)
1273 goto out_problem; 1318 goto out_problem;
@@ -1309,9 +1354,8 @@ out_problem:
1309} 1354}
1310 1355
1311int machine__process_mmap_event(struct machine *machine, union perf_event *event, 1356int machine__process_mmap_event(struct machine *machine, union perf_event *event,
1312 struct perf_sample *sample __maybe_unused) 1357 struct perf_sample *sample)
1313{ 1358{
1314 u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
1315 struct thread *thread; 1359 struct thread *thread;
1316 struct map *map; 1360 struct map *map;
1317 enum map_type type; 1361 enum map_type type;
@@ -1320,8 +1364,8 @@ int machine__process_mmap_event(struct machine *machine, union perf_event *event
1320 if (dump_trace) 1364 if (dump_trace)
1321 perf_event__fprintf_mmap(event, stdout); 1365 perf_event__fprintf_mmap(event, stdout);
1322 1366
1323 if (cpumode == PERF_RECORD_MISC_GUEST_KERNEL || 1367 if (sample->cpumode == PERF_RECORD_MISC_GUEST_KERNEL ||
1324 cpumode == PERF_RECORD_MISC_KERNEL) { 1368 sample->cpumode == PERF_RECORD_MISC_KERNEL) {
1325 ret = machine__process_kernel_mmap_event(machine, event); 1369 ret = machine__process_kernel_mmap_event(machine, event);
1326 if (ret < 0) 1370 if (ret < 0)
1327 goto out_problem; 1371 goto out_problem;
@@ -1608,6 +1652,8 @@ static int add_callchain_ip(struct thread *thread,
1608 } 1652 }
1609 } 1653 }
1610 1654
1655 if (symbol_conf.hide_unresolved && al.sym == NULL)
1656 return 0;
1611 return callchain_cursor_append(&callchain_cursor, al.addr, al.map, al.sym); 1657 return callchain_cursor_append(&callchain_cursor, al.addr, al.map, al.sym);
1612} 1658}
1613 1659
@@ -1862,6 +1908,9 @@ check_calls:
1862static int unwind_entry(struct unwind_entry *entry, void *arg) 1908static int unwind_entry(struct unwind_entry *entry, void *arg)
1863{ 1909{
1864 struct callchain_cursor *cursor = arg; 1910 struct callchain_cursor *cursor = arg;
1911
1912 if (symbol_conf.hide_unresolved && entry->sym == NULL)
1913 return 0;
1865 return callchain_cursor_append(cursor, entry->ip, 1914 return callchain_cursor_append(cursor, entry->ip,
1866 entry->map, entry->sym); 1915 entry->map, entry->sym);
1867} 1916}
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/map.c b/tools/perf/util/map.c
index 4e38c396a897..171b6d10a04b 100644
--- a/tools/perf/util/map.c
+++ b/tools/perf/util/map.c
@@ -26,8 +26,8 @@ const char *map_type__name[MAP__NR_TYPES] = {
26static inline int is_anon_memory(const char *filename) 26static inline int is_anon_memory(const char *filename)
27{ 27{
28 return !strcmp(filename, "//anon") || 28 return !strcmp(filename, "//anon") ||
29 !strcmp(filename, "/dev/zero (deleted)") || 29 !strncmp(filename, "/dev/zero", sizeof("/dev/zero") - 1) ||
30 !strcmp(filename, "/anon_hugepage (deleted)"); 30 !strncmp(filename, "/anon_hugepage", sizeof("/anon_hugepage") - 1);
31} 31}
32 32
33static inline int is_no_dso_memory(const char *filename) 33static inline int is_no_dso_memory(const char *filename)
@@ -644,6 +644,12 @@ size_t map_groups__fprintf(struct map_groups *mg, FILE *fp)
644 return printed; 644 return printed;
645} 645}
646 646
647static void __map_groups__insert(struct map_groups *mg, struct map *map)
648{
649 __maps__insert(&mg->maps[map->type], map);
650 map->groups = mg;
651}
652
647static int maps__fixup_overlappings(struct maps *maps, struct map *map, FILE *fp) 653static int maps__fixup_overlappings(struct maps *maps, struct map *map, FILE *fp)
648{ 654{
649 struct rb_root *root; 655 struct rb_root *root;
@@ -682,9 +688,10 @@ static int maps__fixup_overlappings(struct maps *maps, struct map *map, FILE *fp
682 } 688 }
683 689
684 before->end = map->start; 690 before->end = map->start;
685 __maps__insert(maps, before); 691 __map_groups__insert(pos->groups, before);
686 if (verbose >= 2) 692 if (verbose >= 2)
687 map__fprintf(before, fp); 693 map__fprintf(before, fp);
694 map__put(before);
688 } 695 }
689 696
690 if (map->end < pos->end) { 697 if (map->end < pos->end) {
@@ -696,9 +703,10 @@ static int maps__fixup_overlappings(struct maps *maps, struct map *map, FILE *fp
696 } 703 }
697 704
698 after->start = map->end; 705 after->start = map->end;
699 __maps__insert(maps, after); 706 __map_groups__insert(pos->groups, after);
700 if (verbose >= 2) 707 if (verbose >= 2)
701 map__fprintf(after, fp); 708 map__fprintf(after, fp);
709 map__put(after);
702 } 710 }
703put_map: 711put_map:
704 map__put(pos); 712 map__put(pos);
@@ -736,6 +744,7 @@ int map_groups__clone(struct map_groups *mg,
736 if (new == NULL) 744 if (new == NULL)
737 goto out_unlock; 745 goto out_unlock;
738 map_groups__insert(mg, new); 746 map_groups__insert(mg, new);
747 map__put(new);
739 } 748 }
740 749
741 err = 0; 750 err = 0;
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/pager.c b/tools/perf/util/pager.c
deleted file mode 100644
index 53ef006a951c..000000000000
--- a/tools/perf/util/pager.c
+++ /dev/null
@@ -1,95 +0,0 @@
1#include "cache.h"
2#include "run-command.h"
3#include "sigchain.h"
4
5/*
6 * This is split up from the rest of git so that we can do
7 * something different on Windows.
8 */
9
10static int spawned_pager;
11
12static void pager_preexec(void)
13{
14 /*
15 * Work around bug in "less" by not starting it until we
16 * have real input
17 */
18 fd_set in;
19
20 FD_ZERO(&in);
21 FD_SET(0, &in);
22 select(1, &in, NULL, &in, NULL);
23
24 setenv("LESS", "FRSX", 0);
25}
26
27static const char *pager_argv[] = { "sh", "-c", NULL, NULL };
28static struct child_process pager_process;
29
30static void wait_for_pager(void)
31{
32 fflush(stdout);
33 fflush(stderr);
34 /* signal EOF to pager */
35 close(1);
36 close(2);
37 finish_command(&pager_process);
38}
39
40static void wait_for_pager_signal(int signo)
41{
42 wait_for_pager();
43 sigchain_pop(signo);
44 raise(signo);
45}
46
47void setup_pager(void)
48{
49 const char *pager = getenv("PERF_PAGER");
50
51 if (!isatty(1))
52 return;
53 if (!pager)
54 pager = getenv("PAGER");
55 if (!(pager || access("/usr/bin/pager", X_OK)))
56 pager = "/usr/bin/pager";
57 if (!(pager || access("/usr/bin/less", X_OK)))
58 pager = "/usr/bin/less";
59 if (!pager)
60 pager = "cat";
61 if (!*pager || !strcmp(pager, "cat"))
62 return;
63
64 spawned_pager = 1; /* means we are emitting to terminal */
65
66 /* spawn the pager */
67 pager_argv[2] = pager;
68 pager_process.argv = pager_argv;
69 pager_process.in = -1;
70 pager_process.preexec_cb = pager_preexec;
71
72 if (start_command(&pager_process))
73 return;
74
75 /* original process continues, but writes to the pipe */
76 dup2(pager_process.in, 1);
77 if (isatty(2))
78 dup2(pager_process.in, 2);
79 close(pager_process.in);
80
81 /* this makes sure that the parent terminates after the pager */
82 sigchain_push_common(wait_for_pager_signal);
83 atexit(wait_for_pager);
84}
85
86int pager_in_use(void)
87{
88 const char *env;
89
90 if (spawned_pager)
91 return 1;
92
93 env = getenv("PERF_PAGER_IN_USE");
94 return env ? perf_config_bool("PERF_PAGER_IN_USE", env) : 0;
95}
diff --git a/tools/perf/util/parse-branch-options.c b/tools/perf/util/parse-branch-options.c
index 355eecf6bf59..afc088dd7d20 100644
--- a/tools/perf/util/parse-branch-options.c
+++ b/tools/perf/util/parse-branch-options.c
@@ -1,7 +1,7 @@
1#include "perf.h" 1#include "perf.h"
2#include "util/util.h" 2#include "util/util.h"
3#include "util/debug.h" 3#include "util/debug.h"
4#include "util/parse-options.h" 4#include <subcmd/parse-options.h>
5#include "util/parse-branch-options.h" 5#include "util/parse-branch-options.h"
6 6
7#define BRANCH_OPT(n, m) \ 7#define BRANCH_OPT(n, m) \
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index bee60583839a..4c19d5e79d8c 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -4,9 +4,9 @@
4#include "../perf.h" 4#include "../perf.h"
5#include "evlist.h" 5#include "evlist.h"
6#include "evsel.h" 6#include "evsel.h"
7#include "parse-options.h" 7#include <subcmd/parse-options.h>
8#include "parse-events.h" 8#include "parse-events.h"
9#include "exec_cmd.h" 9#include <subcmd/exec-cmd.h>
10#include "string.h" 10#include "string.h"
11#include "symbol.h" 11#include "symbol.h"
12#include "cache.h" 12#include "cache.h"
@@ -124,6 +124,10 @@ struct event_symbol event_symbols_sw[PERF_COUNT_SW_MAX] = {
124 .symbol = "dummy", 124 .symbol = "dummy",
125 .alias = "", 125 .alias = "",
126 }, 126 },
127 [PERF_COUNT_SW_BPF_OUTPUT] = {
128 .symbol = "bpf-output",
129 .alias = "",
130 },
127}; 131};
128 132
129#define __PERF_EVENT_FIELD(config, name) \ 133#define __PERF_EVENT_FIELD(config, name) \
@@ -275,7 +279,24 @@ const char *event_type(int type)
275 return "unknown"; 279 return "unknown";
276} 280}
277 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}
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;
278 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}
279 300
280static struct perf_evsel * 301static struct perf_evsel *
281__add_event(struct list_head *list, int *idx, 302__add_event(struct list_head *list, int *idx,
@@ -329,11 +350,25 @@ static int parse_aliases(char *str, const char *names[][PERF_EVSEL__MAX_ALIASES]
329 return -1; 350 return -1;
330} 351}
331 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
332int parse_events_add_cache(struct list_head *list, int *idx, 364int parse_events_add_cache(struct list_head *list, int *idx,
333 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)
334{ 368{
335 struct perf_event_attr attr; 369 struct perf_event_attr attr;
336 char name[MAX_NAME_LEN]; 370 LIST_HEAD(config_terms);
371 char name[MAX_NAME_LEN], *config_name;
337 int cache_type = -1, cache_op = -1, cache_result = -1; 372 int cache_type = -1, cache_op = -1, cache_result = -1;
338 char *op_result[2] = { op_result1, op_result2 }; 373 char *op_result[2] = { op_result1, op_result2 };
339 int i, n; 374 int i, n;
@@ -347,6 +382,7 @@ int parse_events_add_cache(struct list_head *list, int *idx,
347 if (cache_type == -1) 382 if (cache_type == -1)
348 return -EINVAL; 383 return -EINVAL;
349 384
385 config_name = get_config_name(head_config);
350 n = snprintf(name, MAX_NAME_LEN, "%s", type); 386 n = snprintf(name, MAX_NAME_LEN, "%s", type);
351 387
352 for (i = 0; (i < 2) && (op_result[i]); i++) { 388 for (i = 0; (i < 2) && (op_result[i]); i++) {
@@ -387,7 +423,16 @@ int parse_events_add_cache(struct list_head *list, int *idx,
387 memset(&attr, 0, sizeof(attr)); 423 memset(&attr, 0, sizeof(attr));
388 attr.config = cache_type | (cache_op << 8) | (cache_result << 16); 424 attr.config = cache_type | (cache_op << 8) | (cache_result << 16);
389 attr.type = PERF_TYPE_HW_CACHE; 425 attr.type = PERF_TYPE_HW_CACHE;
390 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);
391} 436}
392 437
393static void tracepoint_error(struct parse_events_error *e, int err, 438static void tracepoint_error(struct parse_events_error *e, int err,
@@ -395,6 +440,9 @@ static void tracepoint_error(struct parse_events_error *e, int err,
395{ 440{
396 char help[BUFSIZ]; 441 char help[BUFSIZ];
397 442
443 if (!e)
444 return;
445
398 /* 446 /*
399 * We get error directly from syscall errno ( > 0), 447 * We get error directly from syscall errno ( > 0),
400 * or from encoded pointer's error ( < 0). 448 * or from encoded pointer's error ( < 0).
@@ -533,6 +581,7 @@ static int add_tracepoint_multi_sys(struct list_head *list, int *idx,
533struct __add_bpf_event_param { 581struct __add_bpf_event_param {
534 struct parse_events_evlist *data; 582 struct parse_events_evlist *data;
535 struct list_head *list; 583 struct list_head *list;
584 struct list_head *head_config;
536}; 585};
537 586
538static int add_bpf_event(struct probe_trace_event *tev, int fd, 587static int add_bpf_event(struct probe_trace_event *tev, int fd,
@@ -549,7 +598,8 @@ static int add_bpf_event(struct probe_trace_event *tev, int fd,
549 tev->group, tev->event, fd); 598 tev->group, tev->event, fd);
550 599
551 err = parse_events_add_tracepoint(&new_evsels, &evlist->idx, tev->group, 600 err = parse_events_add_tracepoint(&new_evsels, &evlist->idx, tev->group,
552 tev->event, evlist->error, NULL); 601 tev->event, evlist->error,
602 param->head_config);
553 if (err) { 603 if (err) {
554 struct perf_evsel *evsel, *tmp; 604 struct perf_evsel *evsel, *tmp;
555 605
@@ -574,11 +624,12 @@ static int add_bpf_event(struct probe_trace_event *tev, int fd,
574 624
575int parse_events_load_bpf_obj(struct parse_events_evlist *data, 625int parse_events_load_bpf_obj(struct parse_events_evlist *data,
576 struct list_head *list, 626 struct list_head *list,
577 struct bpf_object *obj) 627 struct bpf_object *obj,
628 struct list_head *head_config)
578{ 629{
579 int err; 630 int err;
580 char errbuf[BUFSIZ]; 631 char errbuf[BUFSIZ];
581 struct __add_bpf_event_param param = {data, list}; 632 struct __add_bpf_event_param param = {data, list, head_config};
582 static bool registered_unprobe_atexit = false; 633 static bool registered_unprobe_atexit = false;
583 634
584 if (IS_ERR(obj) || !obj) { 635 if (IS_ERR(obj) || !obj) {
@@ -624,34 +675,128 @@ errout:
624 return err; 675 return err;
625} 676}
626 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
627int parse_events_load_bpf(struct parse_events_evlist *data, 755int parse_events_load_bpf(struct parse_events_evlist *data,
628 struct list_head *list, 756 struct list_head *list,
629 char *bpf_file_name, 757 char *bpf_file_name,
630 bool source) 758 bool source,
759 struct list_head *head_config)
631{ 760{
761 int err;
632 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);
633 767
634 obj = bpf__prepare_load(bpf_file_name, source); 768 obj = bpf__prepare_load(bpf_file_name, source);
635 if (IS_ERR(obj) || !obj) { 769 if (IS_ERR(obj)) {
636 char errbuf[BUFSIZ]; 770 char errbuf[BUFSIZ];
637 int err;
638 771
639 err = obj ? PTR_ERR(obj) : -EINVAL; 772 err = PTR_ERR(obj);
640 773
641 if (err == -ENOTSUP) 774 if (err == -ENOTSUP)
642 snprintf(errbuf, sizeof(errbuf), 775 snprintf(errbuf, sizeof(errbuf),
643 "BPF support is not compiled"); 776 "BPF support is not compiled");
644 else 777 else
645 snprintf(errbuf, sizeof(errbuf), 778 bpf__strerror_prepare_load(bpf_file_name,
646 "BPF object file '%s' is invalid", 779 source,
647 bpf_file_name); 780 -err, errbuf,
781 sizeof(errbuf));
648 782
649 data->error->help = strdup("(add -v to see detail)"); 783 data->error->help = strdup("(add -v to see detail)");
650 data->error->str = strdup(errbuf); 784 data->error->str = strdup(errbuf);
651 return err; 785 return err;
652 } 786 }
653 787
654 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;
655} 800}
656 801
657static int 802static int
@@ -738,9 +883,59 @@ static int check_type_val(struct parse_events_term *term,
738 return -EINVAL; 883 return -EINVAL;
739} 884}
740 885
741typedef int config_term_func_t(struct perf_event_attr *attr, 886/*
742 struct parse_events_term *term, 887 * Update according to parse-events.l
743 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}
744 939
745static int config_term_common(struct perf_event_attr *attr, 940static int config_term_common(struct perf_event_attr *attr,
746 struct parse_events_term *term, 941 struct parse_events_term *term,
@@ -807,6 +1002,17 @@ do { \
807 return -EINVAL; 1002 return -EINVAL;
808 } 1003 }
809 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;
810 return 0; 1016 return 0;
811#undef CHECK_TYPE_VAL 1017#undef CHECK_TYPE_VAL
812} 1018}
@@ -953,23 +1159,8 @@ int parse_events_add_numeric(struct parse_events_evlist *data,
953 return -ENOMEM; 1159 return -ENOMEM;
954 } 1160 }
955 1161
956 return add_event(list, &data->idx, &attr, NULL, &config_terms); 1162 return add_event(list, &data->idx, &attr,
957} 1163 get_config_name(head_config), &config_terms);
958
959static int parse_events__is_name_term(struct parse_events_term *term)
960{
961 return term->type_term == PARSE_EVENTS__TERM_TYPE_NAME;
962}
963
964static char *pmu_event_name(struct list_head *head_terms)
965{
966 struct parse_events_term *term;
967
968 list_for_each_entry(term, head_terms, list)
969 if (parse_events__is_name_term(term))
970 return term->val.str;
971
972 return NULL;
973} 1164}
974 1165
975int parse_events_add_pmu(struct parse_events_evlist *data, 1166int parse_events_add_pmu(struct parse_events_evlist *data,
@@ -1016,7 +1207,7 @@ int parse_events_add_pmu(struct parse_events_evlist *data,
1016 return -EINVAL; 1207 return -EINVAL;
1017 1208
1018 evsel = __add_event(list, &data->idx, &attr, 1209 evsel = __add_event(list, &data->idx, &attr,
1019 pmu_event_name(head_config), pmu->cpus, 1210 get_config_name(head_config), pmu->cpus,
1020 &config_terms); 1211 &config_terms);
1021 if (evsel) { 1212 if (evsel) {
1022 evsel->unit = info.unit; 1213 evsel->unit = info.unit;
@@ -1378,8 +1569,7 @@ int parse_events_terms(struct list_head *terms, const char *str)
1378 return 0; 1569 return 0;
1379 } 1570 }
1380 1571
1381 if (data.terms) 1572 parse_events_terms__delete(data.terms);
1382 parse_events__free_terms(data.terms);
1383 return ret; 1573 return ret;
1384} 1574}
1385 1575
@@ -1387,9 +1577,10 @@ int parse_events(struct perf_evlist *evlist, const char *str,
1387 struct parse_events_error *err) 1577 struct parse_events_error *err)
1388{ 1578{
1389 struct parse_events_evlist data = { 1579 struct parse_events_evlist data = {
1390 .list = LIST_HEAD_INIT(data.list), 1580 .list = LIST_HEAD_INIT(data.list),
1391 .idx = evlist->nr_entries, 1581 .idx = evlist->nr_entries,
1392 .error = err, 1582 .error = err,
1583 .evlist = evlist,
1393 }; 1584 };
1394 int ret; 1585 int ret;
1395 1586
@@ -1878,7 +2069,7 @@ restart:
1878 2069
1879 for (i = 0; i < max; i++, syms++) { 2070 for (i = 0; i < max; i++, syms++) {
1880 2071
1881 if (event_glob != NULL && 2072 if (event_glob != NULL && syms->symbol != NULL &&
1882 !(strglobmatch(syms->symbol, event_glob) || 2073 !(strglobmatch(syms->symbol, event_glob) ||
1883 (syms->alias && strglobmatch(syms->alias, event_glob)))) 2074 (syms->alias && strglobmatch(syms->alias, event_glob))))
1884 continue; 2075 continue;
@@ -2060,12 +2251,29 @@ int parse_events_term__clone(struct parse_events_term **new,
2060 term->err_term, term->err_val); 2251 term->err_term, term->err_val);
2061} 2252}
2062 2253
2063void parse_events__free_terms(struct list_head *terms) 2254void parse_events_terms__purge(struct list_head *terms)
2064{ 2255{
2065 struct parse_events_term *term, *h; 2256 struct parse_events_term *term, *h;
2066 2257
2067 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);
2068 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);
2069} 2277}
2070 2278
2071void parse_events_evlist_error(struct parse_events_evlist *data, 2279void parse_events_evlist_error(struct parse_events_evlist *data,
@@ -2080,6 +2288,33 @@ void parse_events_evlist_error(struct parse_events_evlist *data,
2080 WARN_ONCE(!err->str, "WARNING: failed to allocate error string"); 2288 WARN_ONCE(!err->str, "WARNING: failed to allocate error string");
2081} 2289}
2082 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
2083/* 2318/*
2084 * Return string contains valid config terms of an event. 2319 * Return string contains valid config terms of an event.
2085 * @additional_terms: For terms such as PMU sysfs terms. 2320 * @additional_terms: For terms such as PMU sysfs terms.
@@ -2087,17 +2322,18 @@ void parse_events_evlist_error(struct parse_events_evlist *data,
2087char *parse_events_formats_error_string(char *additional_terms) 2322char *parse_events_formats_error_string(char *additional_terms)
2088{ 2323{
2089 char *str; 2324 char *str;
2090 static const char *static_terms = "config,config1,config2,name," 2325 /* "branch_type" is the longest name */
2091 "period,freq,branch_type,time," 2326 char static_terms[__PARSE_EVENTS__TERM_TYPE_NR *
2092 "call-graph,stack-size\n"; 2327 (sizeof("branch_type") - 1)];
2093 2328
2329 config_terms_list(static_terms, sizeof(static_terms));
2094 /* valid terms */ 2330 /* valid terms */
2095 if (additional_terms) { 2331 if (additional_terms) {
2096 if (!asprintf(&str, "valid terms: %s,%s", 2332 if (asprintf(&str, "valid terms: %s,%s",
2097 additional_terms, static_terms)) 2333 additional_terms, static_terms) < 0)
2098 goto fail; 2334 goto fail;
2099 } else { 2335 } else {
2100 if (!asprintf(&str, "valid terms: %s", static_terms)) 2336 if (asprintf(&str, "valid terms: %s", static_terms) < 0)
2101 goto fail; 2337 goto fail;
2102 } 2338 }
2103 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/parse-options.c b/tools/perf/util/parse-options.c
deleted file mode 100644
index 9fca09296eb3..000000000000
--- a/tools/perf/util/parse-options.c
+++ /dev/null
@@ -1,867 +0,0 @@
1#include "util.h"
2#include "parse-options.h"
3#include "cache.h"
4#include "header.h"
5#include <linux/string.h>
6
7#define OPT_SHORT 1
8#define OPT_UNSET 2
9
10static struct strbuf error_buf = STRBUF_INIT;
11
12static int opterror(const struct option *opt, const char *reason, int flags)
13{
14 if (flags & OPT_SHORT)
15 return error("switch `%c' %s", opt->short_name, reason);
16 if (flags & OPT_UNSET)
17 return error("option `no-%s' %s", opt->long_name, reason);
18 return error("option `%s' %s", opt->long_name, reason);
19}
20
21static int get_arg(struct parse_opt_ctx_t *p, const struct option *opt,
22 int flags, const char **arg)
23{
24 if (p->opt) {
25 *arg = p->opt;
26 p->opt = NULL;
27 } else if ((opt->flags & PARSE_OPT_LASTARG_DEFAULT) && (p->argc == 1 ||
28 **(p->argv + 1) == '-')) {
29 *arg = (const char *)opt->defval;
30 } else if (p->argc > 1) {
31 p->argc--;
32 *arg = *++p->argv;
33 } else
34 return opterror(opt, "requires a value", flags);
35 return 0;
36}
37
38static int get_value(struct parse_opt_ctx_t *p,
39 const struct option *opt, int flags)
40{
41 const char *s, *arg = NULL;
42 const int unset = flags & OPT_UNSET;
43 int err;
44
45 if (unset && p->opt)
46 return opterror(opt, "takes no value", flags);
47 if (unset && (opt->flags & PARSE_OPT_NONEG))
48 return opterror(opt, "isn't available", flags);
49 if (opt->flags & PARSE_OPT_DISABLED)
50 return opterror(opt, "is not usable", flags);
51
52 if (opt->flags & PARSE_OPT_EXCLUSIVE) {
53 if (p->excl_opt && p->excl_opt != opt) {
54 char msg[128];
55
56 if (((flags & OPT_SHORT) && p->excl_opt->short_name) ||
57 p->excl_opt->long_name == NULL) {
58 scnprintf(msg, sizeof(msg), "cannot be used with switch `%c'",
59 p->excl_opt->short_name);
60 } else {
61 scnprintf(msg, sizeof(msg), "cannot be used with %s",
62 p->excl_opt->long_name);
63 }
64 opterror(opt, msg, flags);
65 return -3;
66 }
67 p->excl_opt = opt;
68 }
69 if (!(flags & OPT_SHORT) && p->opt) {
70 switch (opt->type) {
71 case OPTION_CALLBACK:
72 if (!(opt->flags & PARSE_OPT_NOARG))
73 break;
74 /* FALLTHROUGH */
75 case OPTION_BOOLEAN:
76 case OPTION_INCR:
77 case OPTION_BIT:
78 case OPTION_SET_UINT:
79 case OPTION_SET_PTR:
80 return opterror(opt, "takes no value", flags);
81 case OPTION_END:
82 case OPTION_ARGUMENT:
83 case OPTION_GROUP:
84 case OPTION_STRING:
85 case OPTION_INTEGER:
86 case OPTION_UINTEGER:
87 case OPTION_LONG:
88 case OPTION_U64:
89 default:
90 break;
91 }
92 }
93
94 switch (opt->type) {
95 case OPTION_BIT:
96 if (unset)
97 *(int *)opt->value &= ~opt->defval;
98 else
99 *(int *)opt->value |= opt->defval;
100 return 0;
101
102 case OPTION_BOOLEAN:
103 *(bool *)opt->value = unset ? false : true;
104 if (opt->set)
105 *(bool *)opt->set = true;
106 return 0;
107
108 case OPTION_INCR:
109 *(int *)opt->value = unset ? 0 : *(int *)opt->value + 1;
110 return 0;
111
112 case OPTION_SET_UINT:
113 *(unsigned int *)opt->value = unset ? 0 : opt->defval;
114 return 0;
115
116 case OPTION_SET_PTR:
117 *(void **)opt->value = unset ? NULL : (void *)opt->defval;
118 return 0;
119
120 case OPTION_STRING:
121 err = 0;
122 if (unset)
123 *(const char **)opt->value = NULL;
124 else if (opt->flags & PARSE_OPT_OPTARG && !p->opt)
125 *(const char **)opt->value = (const char *)opt->defval;
126 else
127 err = get_arg(p, opt, flags, (const char **)opt->value);
128
129 /* PARSE_OPT_NOEMPTY: Allow NULL but disallow empty string. */
130 if (opt->flags & PARSE_OPT_NOEMPTY) {
131 const char *val = *(const char **)opt->value;
132
133 if (!val)
134 return err;
135
136 /* Similar to unset if we are given an empty string. */
137 if (val[0] == '\0') {
138 *(const char **)opt->value = NULL;
139 return 0;
140 }
141 }
142
143 return err;
144
145 case OPTION_CALLBACK:
146 if (unset)
147 return (*opt->callback)(opt, NULL, 1) ? (-1) : 0;
148 if (opt->flags & PARSE_OPT_NOARG)
149 return (*opt->callback)(opt, NULL, 0) ? (-1) : 0;
150 if (opt->flags & PARSE_OPT_OPTARG && !p->opt)
151 return (*opt->callback)(opt, NULL, 0) ? (-1) : 0;
152 if (get_arg(p, opt, flags, &arg))
153 return -1;
154 return (*opt->callback)(opt, arg, 0) ? (-1) : 0;
155
156 case OPTION_INTEGER:
157 if (unset) {
158 *(int *)opt->value = 0;
159 return 0;
160 }
161 if (opt->flags & PARSE_OPT_OPTARG && !p->opt) {
162 *(int *)opt->value = opt->defval;
163 return 0;
164 }
165 if (get_arg(p, opt, flags, &arg))
166 return -1;
167 *(int *)opt->value = strtol(arg, (char **)&s, 10);
168 if (*s)
169 return opterror(opt, "expects a numerical value", flags);
170 return 0;
171
172 case OPTION_UINTEGER:
173 if (unset) {
174 *(unsigned int *)opt->value = 0;
175 return 0;
176 }
177 if (opt->flags & PARSE_OPT_OPTARG && !p->opt) {
178 *(unsigned int *)opt->value = opt->defval;
179 return 0;
180 }
181 if (get_arg(p, opt, flags, &arg))
182 return -1;
183 *(unsigned int *)opt->value = strtol(arg, (char **)&s, 10);
184 if (*s)
185 return opterror(opt, "expects a numerical value", flags);
186 return 0;
187
188 case OPTION_LONG:
189 if (unset) {
190 *(long *)opt->value = 0;
191 return 0;
192 }
193 if (opt->flags & PARSE_OPT_OPTARG && !p->opt) {
194 *(long *)opt->value = opt->defval;
195 return 0;
196 }
197 if (get_arg(p, opt, flags, &arg))
198 return -1;
199 *(long *)opt->value = strtol(arg, (char **)&s, 10);
200 if (*s)
201 return opterror(opt, "expects a numerical value", flags);
202 return 0;
203
204 case OPTION_U64:
205 if (unset) {
206 *(u64 *)opt->value = 0;
207 return 0;
208 }
209 if (opt->flags & PARSE_OPT_OPTARG && !p->opt) {
210 *(u64 *)opt->value = opt->defval;
211 return 0;
212 }
213 if (get_arg(p, opt, flags, &arg))
214 return -1;
215 *(u64 *)opt->value = strtoull(arg, (char **)&s, 10);
216 if (*s)
217 return opterror(opt, "expects a numerical value", flags);
218 return 0;
219
220 case OPTION_END:
221 case OPTION_ARGUMENT:
222 case OPTION_GROUP:
223 default:
224 die("should not happen, someone must be hit on the forehead");
225 }
226}
227
228static int parse_short_opt(struct parse_opt_ctx_t *p, const struct option *options)
229{
230 for (; options->type != OPTION_END; options++) {
231 if (options->short_name == *p->opt) {
232 p->opt = p->opt[1] ? p->opt + 1 : NULL;
233 return get_value(p, options, OPT_SHORT);
234 }
235 }
236 return -2;
237}
238
239static int parse_long_opt(struct parse_opt_ctx_t *p, const char *arg,
240 const struct option *options)
241{
242 const char *arg_end = strchr(arg, '=');
243 const struct option *abbrev_option = NULL, *ambiguous_option = NULL;
244 int abbrev_flags = 0, ambiguous_flags = 0;
245
246 if (!arg_end)
247 arg_end = arg + strlen(arg);
248
249 for (; options->type != OPTION_END; options++) {
250 const char *rest;
251 int flags = 0;
252
253 if (!options->long_name)
254 continue;
255
256 rest = skip_prefix(arg, options->long_name);
257 if (options->type == OPTION_ARGUMENT) {
258 if (!rest)
259 continue;
260 if (*rest == '=')
261 return opterror(options, "takes no value", flags);
262 if (*rest)
263 continue;
264 p->out[p->cpidx++] = arg - 2;
265 return 0;
266 }
267 if (!rest) {
268 if (!prefixcmp(options->long_name, "no-")) {
269 /*
270 * The long name itself starts with "no-", so
271 * accept the option without "no-" so that users
272 * do not have to enter "no-no-" to get the
273 * negation.
274 */
275 rest = skip_prefix(arg, options->long_name + 3);
276 if (rest) {
277 flags |= OPT_UNSET;
278 goto match;
279 }
280 /* Abbreviated case */
281 if (!prefixcmp(options->long_name + 3, arg)) {
282 flags |= OPT_UNSET;
283 goto is_abbreviated;
284 }
285 }
286 /* abbreviated? */
287 if (!strncmp(options->long_name, arg, arg_end - arg)) {
288is_abbreviated:
289 if (abbrev_option) {
290 /*
291 * If this is abbreviated, it is
292 * ambiguous. So when there is no
293 * exact match later, we need to
294 * error out.
295 */
296 ambiguous_option = abbrev_option;
297 ambiguous_flags = abbrev_flags;
298 }
299 if (!(flags & OPT_UNSET) && *arg_end)
300 p->opt = arg_end + 1;
301 abbrev_option = options;
302 abbrev_flags = flags;
303 continue;
304 }
305 /* negated and abbreviated very much? */
306 if (!prefixcmp("no-", arg)) {
307 flags |= OPT_UNSET;
308 goto is_abbreviated;
309 }
310 /* negated? */
311 if (strncmp(arg, "no-", 3))
312 continue;
313 flags |= OPT_UNSET;
314 rest = skip_prefix(arg + 3, options->long_name);
315 /* abbreviated and negated? */
316 if (!rest && !prefixcmp(options->long_name, arg + 3))
317 goto is_abbreviated;
318 if (!rest)
319 continue;
320 }
321match:
322 if (*rest) {
323 if (*rest != '=')
324 continue;
325 p->opt = rest + 1;
326 }
327 return get_value(p, options, flags);
328 }
329
330 if (ambiguous_option)
331 return error("Ambiguous option: %s "
332 "(could be --%s%s or --%s%s)",
333 arg,
334 (ambiguous_flags & OPT_UNSET) ? "no-" : "",
335 ambiguous_option->long_name,
336 (abbrev_flags & OPT_UNSET) ? "no-" : "",
337 abbrev_option->long_name);
338 if (abbrev_option)
339 return get_value(p, abbrev_option, abbrev_flags);
340 return -2;
341}
342
343static void check_typos(const char *arg, const struct option *options)
344{
345 if (strlen(arg) < 3)
346 return;
347
348 if (!prefixcmp(arg, "no-")) {
349 error ("did you mean `--%s` (with two dashes ?)", arg);
350 exit(129);
351 }
352
353 for (; options->type != OPTION_END; options++) {
354 if (!options->long_name)
355 continue;
356 if (!prefixcmp(options->long_name, arg)) {
357 error ("did you mean `--%s` (with two dashes ?)", arg);
358 exit(129);
359 }
360 }
361}
362
363void parse_options_start(struct parse_opt_ctx_t *ctx,
364 int argc, const char **argv, int flags)
365{
366 memset(ctx, 0, sizeof(*ctx));
367 ctx->argc = argc - 1;
368 ctx->argv = argv + 1;
369 ctx->out = argv;
370 ctx->cpidx = ((flags & PARSE_OPT_KEEP_ARGV0) != 0);
371 ctx->flags = flags;
372 if ((flags & PARSE_OPT_KEEP_UNKNOWN) &&
373 (flags & PARSE_OPT_STOP_AT_NON_OPTION))
374 die("STOP_AT_NON_OPTION and KEEP_UNKNOWN don't go together");
375}
376
377static int usage_with_options_internal(const char * const *,
378 const struct option *, int,
379 struct parse_opt_ctx_t *);
380
381int parse_options_step(struct parse_opt_ctx_t *ctx,
382 const struct option *options,
383 const char * const usagestr[])
384{
385 int internal_help = !(ctx->flags & PARSE_OPT_NO_INTERNAL_HELP);
386 int excl_short_opt = 1;
387 const char *arg;
388
389 /* we must reset ->opt, unknown short option leave it dangling */
390 ctx->opt = NULL;
391
392 for (; ctx->argc; ctx->argc--, ctx->argv++) {
393 arg = ctx->argv[0];
394 if (*arg != '-' || !arg[1]) {
395 if (ctx->flags & PARSE_OPT_STOP_AT_NON_OPTION)
396 break;
397 ctx->out[ctx->cpidx++] = ctx->argv[0];
398 continue;
399 }
400
401 if (arg[1] != '-') {
402 ctx->opt = ++arg;
403 if (internal_help && *ctx->opt == 'h') {
404 return usage_with_options_internal(usagestr, options, 0, ctx);
405 }
406 switch (parse_short_opt(ctx, options)) {
407 case -1:
408 return parse_options_usage(usagestr, options, arg, 1);
409 case -2:
410 goto unknown;
411 case -3:
412 goto exclusive;
413 default:
414 break;
415 }
416 if (ctx->opt)
417 check_typos(arg, options);
418 while (ctx->opt) {
419 if (internal_help && *ctx->opt == 'h')
420 return usage_with_options_internal(usagestr, options, 0, ctx);
421 arg = ctx->opt;
422 switch (parse_short_opt(ctx, options)) {
423 case -1:
424 return parse_options_usage(usagestr, options, arg, 1);
425 case -2:
426 /* fake a short option thing to hide the fact that we may have
427 * started to parse aggregated stuff
428 *
429 * This is leaky, too bad.
430 */
431 ctx->argv[0] = strdup(ctx->opt - 1);
432 *(char *)ctx->argv[0] = '-';
433 goto unknown;
434 case -3:
435 goto exclusive;
436 default:
437 break;
438 }
439 }
440 continue;
441 }
442
443 if (!arg[2]) { /* "--" */
444 if (!(ctx->flags & PARSE_OPT_KEEP_DASHDASH)) {
445 ctx->argc--;
446 ctx->argv++;
447 }
448 break;
449 }
450
451 arg += 2;
452 if (internal_help && !strcmp(arg, "help-all"))
453 return usage_with_options_internal(usagestr, options, 1, ctx);
454 if (internal_help && !strcmp(arg, "help"))
455 return usage_with_options_internal(usagestr, options, 0, ctx);
456 if (!strcmp(arg, "list-opts"))
457 return PARSE_OPT_LIST_OPTS;
458 if (!strcmp(arg, "list-cmds"))
459 return PARSE_OPT_LIST_SUBCMDS;
460 switch (parse_long_opt(ctx, arg, options)) {
461 case -1:
462 return parse_options_usage(usagestr, options, arg, 0);
463 case -2:
464 goto unknown;
465 case -3:
466 excl_short_opt = 0;
467 goto exclusive;
468 default:
469 break;
470 }
471 continue;
472unknown:
473 if (!(ctx->flags & PARSE_OPT_KEEP_UNKNOWN))
474 return PARSE_OPT_UNKNOWN;
475 ctx->out[ctx->cpidx++] = ctx->argv[0];
476 ctx->opt = NULL;
477 }
478 return PARSE_OPT_DONE;
479
480exclusive:
481 parse_options_usage(usagestr, options, arg, excl_short_opt);
482 if ((excl_short_opt && ctx->excl_opt->short_name) ||
483 ctx->excl_opt->long_name == NULL) {
484 char opt = ctx->excl_opt->short_name;
485 parse_options_usage(NULL, options, &opt, 1);
486 } else {
487 parse_options_usage(NULL, options, ctx->excl_opt->long_name, 0);
488 }
489 return PARSE_OPT_HELP;
490}
491
492int parse_options_end(struct parse_opt_ctx_t *ctx)
493{
494 memmove(ctx->out + ctx->cpidx, ctx->argv, ctx->argc * sizeof(*ctx->out));
495 ctx->out[ctx->cpidx + ctx->argc] = NULL;
496 return ctx->cpidx + ctx->argc;
497}
498
499int parse_options_subcommand(int argc, const char **argv, const struct option *options,
500 const char *const subcommands[], const char *usagestr[], int flags)
501{
502 struct parse_opt_ctx_t ctx;
503
504 perf_env__set_cmdline(&perf_env, argc, argv);
505
506 /* build usage string if it's not provided */
507 if (subcommands && !usagestr[0]) {
508 struct strbuf buf = STRBUF_INIT;
509
510 strbuf_addf(&buf, "perf %s [<options>] {", argv[0]);
511 for (int i = 0; subcommands[i]; i++) {
512 if (i)
513 strbuf_addstr(&buf, "|");
514 strbuf_addstr(&buf, subcommands[i]);
515 }
516 strbuf_addstr(&buf, "}");
517
518 usagestr[0] = strdup(buf.buf);
519 strbuf_release(&buf);
520 }
521
522 parse_options_start(&ctx, argc, argv, flags);
523 switch (parse_options_step(&ctx, options, usagestr)) {
524 case PARSE_OPT_HELP:
525 exit(129);
526 case PARSE_OPT_DONE:
527 break;
528 case PARSE_OPT_LIST_OPTS:
529 while (options->type != OPTION_END) {
530 if (options->long_name)
531 printf("--%s ", options->long_name);
532 options++;
533 }
534 putchar('\n');
535 exit(130);
536 case PARSE_OPT_LIST_SUBCMDS:
537 if (subcommands) {
538 for (int i = 0; subcommands[i]; i++)
539 printf("%s ", subcommands[i]);
540 }
541 putchar('\n');
542 exit(130);
543 default: /* PARSE_OPT_UNKNOWN */
544 if (ctx.argv[0][1] == '-') {
545 strbuf_addf(&error_buf, "unknown option `%s'",
546 ctx.argv[0] + 2);
547 } else {
548 strbuf_addf(&error_buf, "unknown switch `%c'",
549 *ctx.opt);
550 }
551 usage_with_options(usagestr, options);
552 }
553
554 return parse_options_end(&ctx);
555}
556
557int parse_options(int argc, const char **argv, const struct option *options,
558 const char * const usagestr[], int flags)
559{
560 return parse_options_subcommand(argc, argv, options, NULL,
561 (const char **) usagestr, flags);
562}
563
564#define USAGE_OPTS_WIDTH 24
565#define USAGE_GAP 2
566
567static void print_option_help(const struct option *opts, int full)
568{
569 size_t pos;
570 int pad;
571
572 if (opts->type == OPTION_GROUP) {
573 fputc('\n', stderr);
574 if (*opts->help)
575 fprintf(stderr, "%s\n", opts->help);
576 return;
577 }
578 if (!full && (opts->flags & PARSE_OPT_HIDDEN))
579 return;
580 if (opts->flags & PARSE_OPT_DISABLED)
581 return;
582
583 pos = fprintf(stderr, " ");
584 if (opts->short_name)
585 pos += fprintf(stderr, "-%c", opts->short_name);
586 else
587 pos += fprintf(stderr, " ");
588
589 if (opts->long_name && opts->short_name)
590 pos += fprintf(stderr, ", ");
591 if (opts->long_name)
592 pos += fprintf(stderr, "--%s", opts->long_name);
593
594 switch (opts->type) {
595 case OPTION_ARGUMENT:
596 break;
597 case OPTION_LONG:
598 case OPTION_U64:
599 case OPTION_INTEGER:
600 case OPTION_UINTEGER:
601 if (opts->flags & PARSE_OPT_OPTARG)
602 if (opts->long_name)
603 pos += fprintf(stderr, "[=<n>]");
604 else
605 pos += fprintf(stderr, "[<n>]");
606 else
607 pos += fprintf(stderr, " <n>");
608 break;
609 case OPTION_CALLBACK:
610 if (opts->flags & PARSE_OPT_NOARG)
611 break;
612 /* FALLTHROUGH */
613 case OPTION_STRING:
614 if (opts->argh) {
615 if (opts->flags & PARSE_OPT_OPTARG)
616 if (opts->long_name)
617 pos += fprintf(stderr, "[=<%s>]", opts->argh);
618 else
619 pos += fprintf(stderr, "[<%s>]", opts->argh);
620 else
621 pos += fprintf(stderr, " <%s>", opts->argh);
622 } else {
623 if (opts->flags & PARSE_OPT_OPTARG)
624 if (opts->long_name)
625 pos += fprintf(stderr, "[=...]");
626 else
627 pos += fprintf(stderr, "[...]");
628 else
629 pos += fprintf(stderr, " ...");
630 }
631 break;
632 default: /* OPTION_{BIT,BOOLEAN,SET_UINT,SET_PTR} */
633 case OPTION_END:
634 case OPTION_GROUP:
635 case OPTION_BIT:
636 case OPTION_BOOLEAN:
637 case OPTION_INCR:
638 case OPTION_SET_UINT:
639 case OPTION_SET_PTR:
640 break;
641 }
642
643 if (pos <= USAGE_OPTS_WIDTH)
644 pad = USAGE_OPTS_WIDTH - pos;
645 else {
646 fputc('\n', stderr);
647 pad = USAGE_OPTS_WIDTH;
648 }
649 fprintf(stderr, "%*s%s\n", pad + USAGE_GAP, "", opts->help);
650}
651
652static int option__cmp(const void *va, const void *vb)
653{
654 const struct option *a = va, *b = vb;
655 int sa = tolower(a->short_name), sb = tolower(b->short_name), ret;
656
657 if (sa == 0)
658 sa = 'z' + 1;
659 if (sb == 0)
660 sb = 'z' + 1;
661
662 ret = sa - sb;
663
664 if (ret == 0) {
665 const char *la = a->long_name ?: "",
666 *lb = b->long_name ?: "";
667 ret = strcmp(la, lb);
668 }
669
670 return ret;
671}
672
673static struct option *options__order(const struct option *opts)
674{
675 int nr_opts = 0;
676 const struct option *o = opts;
677 struct option *ordered;
678
679 for (o = opts; o->type != OPTION_END; o++)
680 ++nr_opts;
681
682 ordered = memdup(opts, sizeof(*o) * (nr_opts + 1));
683 if (ordered == NULL)
684 goto out;
685
686 qsort(ordered, nr_opts, sizeof(*o), option__cmp);
687out:
688 return ordered;
689}
690
691static bool option__in_argv(const struct option *opt, const struct parse_opt_ctx_t *ctx)
692{
693 int i;
694
695 for (i = 1; i < ctx->argc; ++i) {
696 const char *arg = ctx->argv[i];
697
698 if (arg[0] != '-') {
699 if (arg[1] == '\0') {
700 if (arg[0] == opt->short_name)
701 return true;
702 continue;
703 }
704
705 if (opt->long_name && strcmp(opt->long_name, arg) == 0)
706 return true;
707
708 if (opt->help && strcasestr(opt->help, arg) != NULL)
709 return true;
710
711 continue;
712 }
713
714 if (arg[1] == opt->short_name ||
715 (arg[1] == '-' && opt->long_name && strcmp(opt->long_name, arg + 2) == 0))
716 return true;
717 }
718
719 return false;
720}
721
722int usage_with_options_internal(const char * const *usagestr,
723 const struct option *opts, int full,
724 struct parse_opt_ctx_t *ctx)
725{
726 struct option *ordered;
727
728 if (!usagestr)
729 return PARSE_OPT_HELP;
730
731 setup_pager();
732
733 if (strbuf_avail(&error_buf)) {
734 fprintf(stderr, " Error: %s\n", error_buf.buf);
735 strbuf_release(&error_buf);
736 }
737
738 fprintf(stderr, "\n Usage: %s\n", *usagestr++);
739 while (*usagestr && **usagestr)
740 fprintf(stderr, " or: %s\n", *usagestr++);
741 while (*usagestr) {
742 fprintf(stderr, "%s%s\n",
743 **usagestr ? " " : "",
744 *usagestr);
745 usagestr++;
746 }
747
748 if (opts->type != OPTION_GROUP)
749 fputc('\n', stderr);
750
751 ordered = options__order(opts);
752 if (ordered)
753 opts = ordered;
754
755 for ( ; opts->type != OPTION_END; opts++) {
756 if (ctx && ctx->argc > 1 && !option__in_argv(opts, ctx))
757 continue;
758 print_option_help(opts, full);
759 }
760
761 fputc('\n', stderr);
762
763 free(ordered);
764
765 return PARSE_OPT_HELP;
766}
767
768void usage_with_options(const char * const *usagestr,
769 const struct option *opts)
770{
771 exit_browser(false);
772 usage_with_options_internal(usagestr, opts, 0, NULL);
773 exit(129);
774}
775
776void usage_with_options_msg(const char * const *usagestr,
777 const struct option *opts, const char *fmt, ...)
778{
779 va_list ap;
780
781 exit_browser(false);
782
783 va_start(ap, fmt);
784 strbuf_addv(&error_buf, fmt, ap);
785 va_end(ap);
786
787 usage_with_options_internal(usagestr, opts, 0, NULL);
788 exit(129);
789}
790
791int parse_options_usage(const char * const *usagestr,
792 const struct option *opts,
793 const char *optstr, bool short_opt)
794{
795 if (!usagestr)
796 goto opt;
797
798 fprintf(stderr, "\n Usage: %s\n", *usagestr++);
799 while (*usagestr && **usagestr)
800 fprintf(stderr, " or: %s\n", *usagestr++);
801 while (*usagestr) {
802 fprintf(stderr, "%s%s\n",
803 **usagestr ? " " : "",
804 *usagestr);
805 usagestr++;
806 }
807 fputc('\n', stderr);
808
809opt:
810 for ( ; opts->type != OPTION_END; opts++) {
811 if (short_opt) {
812 if (opts->short_name == *optstr) {
813 print_option_help(opts, 0);
814 break;
815 }
816 continue;
817 }
818
819 if (opts->long_name == NULL)
820 continue;
821
822 if (!prefixcmp(opts->long_name, optstr))
823 print_option_help(opts, 0);
824 if (!prefixcmp("no-", optstr) &&
825 !prefixcmp(opts->long_name, optstr + 3))
826 print_option_help(opts, 0);
827 }
828
829 return PARSE_OPT_HELP;
830}
831
832
833int parse_opt_verbosity_cb(const struct option *opt,
834 const char *arg __maybe_unused,
835 int unset)
836{
837 int *target = opt->value;
838
839 if (unset)
840 /* --no-quiet, --no-verbose */
841 *target = 0;
842 else if (opt->short_name == 'v') {
843 if (*target >= 0)
844 (*target)++;
845 else
846 *target = 1;
847 } else {
848 if (*target <= 0)
849 (*target)--;
850 else
851 *target = -1;
852 }
853 return 0;
854}
855
856void set_option_flag(struct option *opts, int shortopt, const char *longopt,
857 int flag)
858{
859 for (; opts->type != OPTION_END; opts++) {
860 if ((shortopt && opts->short_name == shortopt) ||
861 (opts->long_name && longopt &&
862 !strcmp(opts->long_name, longopt))) {
863 opts->flags |= flag;
864 break;
865 }
866 }
867}
diff --git a/tools/perf/util/parse-options.h b/tools/perf/util/parse-options.h
deleted file mode 100644
index a8e407bc251e..000000000000
--- a/tools/perf/util/parse-options.h
+++ /dev/null
@@ -1,229 +0,0 @@
1#ifndef __PERF_PARSE_OPTIONS_H
2#define __PERF_PARSE_OPTIONS_H
3
4#include <linux/kernel.h>
5#include <stdbool.h>
6
7enum parse_opt_type {
8 /* special types */
9 OPTION_END,
10 OPTION_ARGUMENT,
11 OPTION_GROUP,
12 /* options with no arguments */
13 OPTION_BIT,
14 OPTION_BOOLEAN,
15 OPTION_INCR,
16 OPTION_SET_UINT,
17 OPTION_SET_PTR,
18 /* options with arguments (usually) */
19 OPTION_STRING,
20 OPTION_INTEGER,
21 OPTION_LONG,
22 OPTION_CALLBACK,
23 OPTION_U64,
24 OPTION_UINTEGER,
25};
26
27enum parse_opt_flags {
28 PARSE_OPT_KEEP_DASHDASH = 1,
29 PARSE_OPT_STOP_AT_NON_OPTION = 2,
30 PARSE_OPT_KEEP_ARGV0 = 4,
31 PARSE_OPT_KEEP_UNKNOWN = 8,
32 PARSE_OPT_NO_INTERNAL_HELP = 16,
33};
34
35enum parse_opt_option_flags {
36 PARSE_OPT_OPTARG = 1,
37 PARSE_OPT_NOARG = 2,
38 PARSE_OPT_NONEG = 4,
39 PARSE_OPT_HIDDEN = 8,
40 PARSE_OPT_LASTARG_DEFAULT = 16,
41 PARSE_OPT_DISABLED = 32,
42 PARSE_OPT_EXCLUSIVE = 64,
43 PARSE_OPT_NOEMPTY = 128,
44};
45
46struct option;
47typedef int parse_opt_cb(const struct option *, const char *arg, int unset);
48
49/*
50 * `type`::
51 * holds the type of the option, you must have an OPTION_END last in your
52 * array.
53 *
54 * `short_name`::
55 * the character to use as a short option name, '\0' if none.
56 *
57 * `long_name`::
58 * the long option name, without the leading dashes, NULL if none.
59 *
60 * `value`::
61 * stores pointers to the values to be filled.
62 *
63 * `argh`::
64 * token to explain the kind of argument this option wants. Keep it
65 * homogenous across the repository.
66 *
67 * `help`::
68 * the short help associated to what the option does.
69 * Must never be NULL (except for OPTION_END).
70 * OPTION_GROUP uses this pointer to store the group header.
71 *
72 * `flags`::
73 * mask of parse_opt_option_flags.
74 * PARSE_OPT_OPTARG: says that the argument is optionnal (not for BOOLEANs)
75 * PARSE_OPT_NOARG: says that this option takes no argument, for CALLBACKs
76 * PARSE_OPT_NONEG: says that this option cannot be negated
77 * PARSE_OPT_HIDDEN this option is skipped in the default usage, showed in
78 * the long one.
79 *
80 * `callback`::
81 * pointer to the callback to use for OPTION_CALLBACK.
82 *
83 * `defval`::
84 * default value to fill (*->value) with for PARSE_OPT_OPTARG.
85 * OPTION_{BIT,SET_UINT,SET_PTR} store the {mask,integer,pointer} to put in
86 * the value when met.
87 * CALLBACKS can use it like they want.
88 *
89 * `set`::
90 * whether an option was set by the user
91 */
92struct option {
93 enum parse_opt_type type;
94 int short_name;
95 const char *long_name;
96 void *value;
97 const char *argh;
98 const char *help;
99
100 int flags;
101 parse_opt_cb *callback;
102 intptr_t defval;
103 bool *set;
104 void *data;
105};
106
107#define check_vtype(v, type) ( BUILD_BUG_ON_ZERO(!__builtin_types_compatible_p(typeof(v), type)) + v )
108
109#define OPT_END() { .type = OPTION_END }
110#define OPT_ARGUMENT(l, h) { .type = OPTION_ARGUMENT, .long_name = (l), .help = (h) }
111#define OPT_GROUP(h) { .type = OPTION_GROUP, .help = (h) }
112#define OPT_BIT(s, l, v, h, b) { .type = OPTION_BIT, .short_name = (s), .long_name = (l), .value = check_vtype(v, int *), .help = (h), .defval = (b) }
113#define OPT_BOOLEAN(s, l, v, h) { .type = OPTION_BOOLEAN, .short_name = (s), .long_name = (l), .value = check_vtype(v, bool *), .help = (h) }
114#define OPT_BOOLEAN_FLAG(s, l, v, h, f) { .type = OPTION_BOOLEAN, .short_name = (s), .long_name = (l), .value = check_vtype(v, bool *), .help = (h), .flags = (f) }
115#define OPT_BOOLEAN_SET(s, l, v, os, h) \
116 { .type = OPTION_BOOLEAN, .short_name = (s), .long_name = (l), \
117 .value = check_vtype(v, bool *), .help = (h), \
118 .set = check_vtype(os, bool *)}
119#define OPT_INCR(s, l, v, h) { .type = OPTION_INCR, .short_name = (s), .long_name = (l), .value = check_vtype(v, int *), .help = (h) }
120#define OPT_SET_UINT(s, l, v, h, i) { .type = OPTION_SET_UINT, .short_name = (s), .long_name = (l), .value = check_vtype(v, unsigned int *), .help = (h), .defval = (i) }
121#define OPT_SET_PTR(s, l, v, h, p) { .type = OPTION_SET_PTR, .short_name = (s), .long_name = (l), .value = (v), .help = (h), .defval = (p) }
122#define OPT_INTEGER(s, l, v, h) { .type = OPTION_INTEGER, .short_name = (s), .long_name = (l), .value = check_vtype(v, int *), .help = (h) }
123#define OPT_UINTEGER(s, l, v, h) { .type = OPTION_UINTEGER, .short_name = (s), .long_name = (l), .value = check_vtype(v, unsigned int *), .help = (h) }
124#define OPT_LONG(s, l, v, h) { .type = OPTION_LONG, .short_name = (s), .long_name = (l), .value = check_vtype(v, long *), .help = (h) }
125#define OPT_U64(s, l, v, h) { .type = OPTION_U64, .short_name = (s), .long_name = (l), .value = check_vtype(v, u64 *), .help = (h) }
126#define OPT_STRING(s, l, v, a, h) { .type = OPTION_STRING, .short_name = (s), .long_name = (l), .value = check_vtype(v, const char **), (a), .help = (h) }
127#define OPT_STRING_OPTARG(s, l, v, a, h, d) \
128 { .type = OPTION_STRING, .short_name = (s), .long_name = (l), \
129 .value = check_vtype(v, const char **), (a), .help = (h), \
130 .flags = PARSE_OPT_OPTARG, .defval = (intptr_t)(d) }
131#define OPT_STRING_NOEMPTY(s, l, v, a, h) { .type = OPTION_STRING, .short_name = (s), .long_name = (l), .value = check_vtype(v, const char **), (a), .help = (h), .flags = PARSE_OPT_NOEMPTY}
132#define OPT_DATE(s, l, v, h) \
133 { .type = OPTION_CALLBACK, .short_name = (s), .long_name = (l), .value = (v), .argh = "time", .help = (h), .callback = parse_opt_approxidate_cb }
134#define OPT_CALLBACK(s, l, v, a, h, f) \
135 { .type = OPTION_CALLBACK, .short_name = (s), .long_name = (l), .value = (v), (a), .help = (h), .callback = (f) }
136#define OPT_CALLBACK_NOOPT(s, l, v, a, h, f) \
137 { .type = OPTION_CALLBACK, .short_name = (s), .long_name = (l), .value = (v), (a), .help = (h), .callback = (f), .flags = PARSE_OPT_NOARG }
138#define OPT_CALLBACK_DEFAULT(s, l, v, a, h, f, d) \
139 { .type = OPTION_CALLBACK, .short_name = (s), .long_name = (l), .value = (v), (a), .help = (h), .callback = (f), .defval = (intptr_t)d, .flags = PARSE_OPT_LASTARG_DEFAULT }
140#define OPT_CALLBACK_DEFAULT_NOOPT(s, l, v, a, h, f, d) \
141 { .type = OPTION_CALLBACK, .short_name = (s), .long_name = (l),\
142 .value = (v), (a), .help = (h), .callback = (f), .defval = (intptr_t)d,\
143 .flags = PARSE_OPT_LASTARG_DEFAULT | PARSE_OPT_NOARG}
144#define OPT_CALLBACK_OPTARG(s, l, v, d, a, h, f) \
145 { .type = OPTION_CALLBACK, .short_name = (s), .long_name = (l), \
146 .value = (v), (a), .help = (h), .callback = (f), \
147 .flags = PARSE_OPT_OPTARG, .data = (d) }
148
149/* parse_options() will filter out the processed options and leave the
150 * non-option argments in argv[].
151 * Returns the number of arguments left in argv[].
152 */
153extern int parse_options(int argc, const char **argv,
154 const struct option *options,
155 const char * const usagestr[], int flags);
156
157extern int parse_options_subcommand(int argc, const char **argv,
158 const struct option *options,
159 const char *const subcommands[],
160 const char *usagestr[], int flags);
161
162extern NORETURN void usage_with_options(const char * const *usagestr,
163 const struct option *options);
164extern NORETURN __attribute__((format(printf,3,4)))
165void usage_with_options_msg(const char * const *usagestr,
166 const struct option *options,
167 const char *fmt, ...);
168
169/*----- incremantal advanced APIs -----*/
170
171enum {
172 PARSE_OPT_HELP = -1,
173 PARSE_OPT_DONE,
174 PARSE_OPT_LIST_OPTS,
175 PARSE_OPT_LIST_SUBCMDS,
176 PARSE_OPT_UNKNOWN,
177};
178
179/*
180 * It's okay for the caller to consume argv/argc in the usual way.
181 * Other fields of that structure are private to parse-options and should not
182 * be modified in any way.
183 */
184struct parse_opt_ctx_t {
185 const char **argv;
186 const char **out;
187 int argc, cpidx;
188 const char *opt;
189 const struct option *excl_opt;
190 int flags;
191};
192
193extern int parse_options_usage(const char * const *usagestr,
194 const struct option *opts,
195 const char *optstr,
196 bool short_opt);
197
198extern void parse_options_start(struct parse_opt_ctx_t *ctx,
199 int argc, const char **argv, int flags);
200
201extern int parse_options_step(struct parse_opt_ctx_t *ctx,
202 const struct option *options,
203 const char * const usagestr[]);
204
205extern int parse_options_end(struct parse_opt_ctx_t *ctx);
206
207
208/*----- some often used options -----*/
209extern int parse_opt_abbrev_cb(const struct option *, const char *, int);
210extern int parse_opt_approxidate_cb(const struct option *, const char *, int);
211extern int parse_opt_verbosity_cb(const struct option *, const char *, int);
212
213#define OPT__VERBOSE(var) OPT_BOOLEAN('v', "verbose", (var), "be verbose")
214#define OPT__QUIET(var) OPT_BOOLEAN('q', "quiet", (var), "be quiet")
215#define OPT__VERBOSITY(var) \
216 { OPTION_CALLBACK, 'v', "verbose", (var), NULL, "be more verbose", \
217 PARSE_OPT_NOARG, &parse_opt_verbosity_cb, 0 }, \
218 { OPTION_CALLBACK, 'q', "quiet", (var), NULL, "be more quiet", \
219 PARSE_OPT_NOARG, &parse_opt_verbosity_cb, 0 }
220#define OPT__DRY_RUN(var) OPT_BOOLEAN('n', "dry-run", (var), "dry run")
221#define OPT__ABBREV(var) \
222 { OPTION_CALLBACK, 0, "abbrev", (var), "n", \
223 "use <n> digits to display SHA-1s", \
224 PARSE_OPT_OPTARG, &parse_opt_abbrev_cb, 0 }
225
226extern const char *parse_options_fix_filename(const char *prefix, const char *file);
227
228void set_option_flag(struct option *opts, int sopt, const char *lopt, int flag);
229#endif /* __PERF_PARSE_OPTIONS_H */
diff --git a/tools/perf/util/parse-regs-options.c b/tools/perf/util/parse-regs-options.c
index 4f2c1c255d81..646ecf736aad 100644
--- a/tools/perf/util/parse-regs-options.c
+++ b/tools/perf/util/parse-regs-options.c
@@ -1,7 +1,7 @@
1#include "perf.h" 1#include "perf.h"
2#include "util/util.h" 2#include "util/util.h"
3#include "util/debug.h" 3#include "util/debug.h"
4#include "util/parse-options.h" 4#include <subcmd/parse-options.h>
5#include "util/parse-regs-options.h" 5#include "util/parse-regs-options.h"
6 6
7int 7int
diff --git a/tools/perf/util/path.c b/tools/perf/util/path.c
index 5d13cb45b317..3bf6bf82ff2d 100644
--- a/tools/perf/util/path.c
+++ b/tools/perf/util/path.c
@@ -22,24 +22,6 @@ static const char *get_perf_dir(void)
22 return "."; 22 return ".";
23} 23}
24 24
25/*
26 * If libc has strlcpy() then that version will override this
27 * implementation:
28 */
29size_t __weak strlcpy(char *dest, const char *src, size_t size)
30{
31 size_t ret = strlen(src);
32
33 if (size) {
34 size_t len = (ret >= size) ? size - 1 : ret;
35
36 memcpy(dest, src, len);
37 dest[len] = '\0';
38 }
39
40 return ret;
41}
42
43static char *get_pathname(void) 25static char *get_pathname(void)
44{ 26{
45 static char pathname_array[4][PATH_MAX]; 27 static char pathname_array[4][PATH_MAX];
@@ -59,36 +41,6 @@ static char *cleanup_path(char *path)
59 return path; 41 return path;
60} 42}
61 43
62static char *perf_vsnpath(char *buf, size_t n, const char *fmt, va_list args)
63{
64 const char *perf_dir = get_perf_dir();
65 size_t len;
66
67 len = strlen(perf_dir);
68 if (n < len + 1)
69 goto bad;
70 memcpy(buf, perf_dir, len);
71 if (len && !is_dir_sep(perf_dir[len-1]))
72 buf[len++] = '/';
73 len += vsnprintf(buf + len, n - len, fmt, args);
74 if (len >= n)
75 goto bad;
76 return cleanup_path(buf);
77bad:
78 strlcpy(buf, bad_path, n);
79 return buf;
80}
81
82char *perf_pathdup(const char *fmt, ...)
83{
84 char path[PATH_MAX];
85 va_list args;
86 va_start(args, fmt);
87 (void)perf_vsnpath(path, sizeof(path), fmt, args);
88 va_end(args);
89 return xstrdup(path);
90}
91
92char *mkpath(const char *fmt, ...) 44char *mkpath(const char *fmt, ...)
93{ 45{
94 va_list args; 46 va_list args;
diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c
index e4b173dec4b9..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
@@ -220,6 +233,7 @@ static int __perf_pmu__new_alias(struct list_head *list, char *dir, char *name,
220 alias->scale = 1.0; 233 alias->scale = 1.0;
221 alias->unit[0] = '\0'; 234 alias->unit[0] = '\0';
222 alias->per_pkg = false; 235 alias->per_pkg = false;
236 alias->snapshot = false;
223 237
224 ret = parse_events_terms(&alias->terms, val); 238 ret = parse_events_terms(&alias->terms, val);
225 if (ret) { 239 if (ret) {
@@ -283,13 +297,12 @@ static int pmu_aliases_parse(char *dir, struct list_head *head)
283{ 297{
284 struct dirent *evt_ent; 298 struct dirent *evt_ent;
285 DIR *event_dir; 299 DIR *event_dir;
286 int ret = 0;
287 300
288 event_dir = opendir(dir); 301 event_dir = opendir(dir);
289 if (!event_dir) 302 if (!event_dir)
290 return -EINVAL; 303 return -EINVAL;
291 304
292 while (!ret && (evt_ent = readdir(event_dir))) { 305 while ((evt_ent = readdir(event_dir))) {
293 char path[PATH_MAX]; 306 char path[PATH_MAX];
294 char *name = evt_ent->d_name; 307 char *name = evt_ent->d_name;
295 FILE *file; 308 FILE *file;
@@ -305,17 +318,19 @@ static int pmu_aliases_parse(char *dir, struct list_head *head)
305 318
306 snprintf(path, PATH_MAX, "%s/%s", dir, name); 319 snprintf(path, PATH_MAX, "%s/%s", dir, name);
307 320
308 ret = -EINVAL;
309 file = fopen(path, "r"); 321 file = fopen(path, "r");
310 if (!file) 322 if (!file) {
311 break; 323 pr_debug("Cannot open %s\n", path);
324 continue;
325 }
312 326
313 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);
314 fclose(file); 329 fclose(file);
315 } 330 }
316 331
317 closedir(event_dir); 332 closedir(event_dir);
318 return ret; 333 return 0;
319} 334}
320 335
321/* 336/*
@@ -353,7 +368,7 @@ static int pmu_alias_terms(struct perf_pmu_alias *alias,
353 list_for_each_entry(term, &alias->terms, list) { 368 list_for_each_entry(term, &alias->terms, list) {
354 ret = parse_events_term__clone(&cloned, term); 369 ret = parse_events_term__clone(&cloned, term);
355 if (ret) { 370 if (ret) {
356 parse_events__free_terms(&list); 371 parse_events_terms__purge(&list);
357 return ret; 372 return ret;
358 } 373 }
359 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 b51a8bfb40f9..8319fbb08636 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -1895,9 +1895,8 @@ static int find_perf_probe_point_from_map(struct probe_trace_point *tp,
1895 sym = map__find_symbol(map, addr, NULL); 1895 sym = map__find_symbol(map, addr, NULL);
1896 } else { 1896 } else {
1897 if (tp->symbol && !addr) { 1897 if (tp->symbol && !addr) {
1898 ret = kernel_get_symbol_address_by_name(tp->symbol, 1898 if (kernel_get_symbol_address_by_name(tp->symbol,
1899 &addr, true, false); 1899 &addr, true, false) < 0)
1900 if (ret < 0)
1901 goto out; 1900 goto out;
1902 } 1901 }
1903 if (addr) { 1902 if (addr) {
@@ -1905,6 +1904,7 @@ static int find_perf_probe_point_from_map(struct probe_trace_point *tp,
1905 sym = __find_kernel_function(addr, &map); 1904 sym = __find_kernel_function(addr, &map);
1906 } 1905 }
1907 } 1906 }
1907
1908 if (!sym) 1908 if (!sym)
1909 goto out; 1909 goto out;
1910 1910
@@ -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);
@@ -2326,8 +2326,11 @@ static int get_new_event_name(char *buf, size_t len, const char *base,
2326 goto out; 2326 goto out;
2327 2327
2328 if (!allow_suffix) { 2328 if (!allow_suffix) {
2329 pr_warning("Error: event \"%s\" already exists. " 2329 pr_warning("Error: event \"%s\" already exists.\n"
2330 "(Use -f to force duplicates.)\n", buf); 2330 " Hint: Remove existing event by 'perf probe -d'\n"
2331 " or force duplicates by 'perf probe -f'\n"
2332 " or set 'force=yes' in BPF source.\n",
2333 buf);
2331 ret = -EEXIST; 2334 ret = -EEXIST;
2332 goto out; 2335 goto out;
2333 } 2336 }
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-file.c b/tools/perf/util/probe-file.c
index 89dbeb92c68e..e3b3b92e4458 100644
--- a/tools/perf/util/probe-file.c
+++ b/tools/perf/util/probe-file.c
@@ -138,6 +138,9 @@ struct strlist *probe_file__get_rawlist(int fd)
138 char *p; 138 char *p;
139 struct strlist *sl; 139 struct strlist *sl;
140 140
141 if (fd < 0)
142 return NULL;
143
141 sl = strlist__new(NULL, NULL); 144 sl = strlist__new(NULL, NULL);
142 145
143 fp = fdopen(dup(fd), "r"); 146 fp = fdopen(dup(fd), "r");
@@ -271,6 +274,9 @@ int probe_file__get_events(int fd, struct strfilter *filter,
271 const char *p; 274 const char *p;
272 int ret = -ENOENT; 275 int ret = -ENOENT;
273 276
277 if (!plist)
278 return -EINVAL;
279
274 namelist = __probe_file__get_namelist(fd, true); 280 namelist = __probe_file__get_namelist(fd, true);
275 if (!namelist) 281 if (!namelist)
276 return -ENOENT; 282 return -ENOENT;
diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c
index bd8f03de5e40..b3bd0fba0237 100644
--- a/tools/perf/util/probe-finder.c
+++ b/tools/perf/util/probe-finder.c
@@ -654,6 +654,7 @@ static int convert_to_trace_point(Dwarf_Die *sp_die, Dwfl_Module *mod,
654static int call_probe_finder(Dwarf_Die *sc_die, struct probe_finder *pf) 654static int call_probe_finder(Dwarf_Die *sc_die, struct probe_finder *pf)
655{ 655{
656 Dwarf_Attribute fb_attr; 656 Dwarf_Attribute fb_attr;
657 Dwarf_Frame *frame = NULL;
657 size_t nops; 658 size_t nops;
658 int ret; 659 int ret;
659 660
@@ -685,12 +686,13 @@ static int call_probe_finder(Dwarf_Die *sc_die, struct probe_finder *pf)
685 pf->fb_ops = NULL; 686 pf->fb_ops = NULL;
686#if _ELFUTILS_PREREQ(0, 142) 687#if _ELFUTILS_PREREQ(0, 142)
687 } else if (nops == 1 && pf->fb_ops[0].atom == DW_OP_call_frame_cfa && 688 } else if (nops == 1 && pf->fb_ops[0].atom == DW_OP_call_frame_cfa &&
688 pf->cfi != NULL) { 689 (pf->cfi_eh != NULL || pf->cfi_dbg != NULL)) {
689 Dwarf_Frame *frame; 690 if ((dwarf_cfi_addrframe(pf->cfi_eh, pf->addr, &frame) != 0 &&
690 if (dwarf_cfi_addrframe(pf->cfi, pf->addr, &frame) != 0 || 691 (dwarf_cfi_addrframe(pf->cfi_dbg, pf->addr, &frame) != 0)) ||
691 dwarf_frame_cfa(frame, &pf->fb_ops, &nops) != 0) { 692 dwarf_frame_cfa(frame, &pf->fb_ops, &nops) != 0) {
692 pr_warning("Failed to get call frame on 0x%jx\n", 693 pr_warning("Failed to get call frame on 0x%jx\n",
693 (uintmax_t)pf->addr); 694 (uintmax_t)pf->addr);
695 free(frame);
694 return -ENOENT; 696 return -ENOENT;
695 } 697 }
696#endif 698#endif
@@ -699,7 +701,8 @@ static int call_probe_finder(Dwarf_Die *sc_die, struct probe_finder *pf)
699 /* Call finder's callback handler */ 701 /* Call finder's callback handler */
700 ret = pf->callback(sc_die, pf); 702 ret = pf->callback(sc_die, pf);
701 703
702 /* *pf->fb_ops will be cached in libdw. Don't free it. */ 704 /* Since *pf->fb_ops can be a part of frame. we should free it here. */
705 free(frame);
703 pf->fb_ops = NULL; 706 pf->fb_ops = NULL;
704 707
705 return ret; 708 return ret;
@@ -1013,8 +1016,7 @@ static int pubname_search_cb(Dwarf *dbg, Dwarf_Global *gl, void *data)
1013 return DWARF_CB_OK; 1016 return DWARF_CB_OK;
1014} 1017}
1015 1018
1016/* Find probe points from debuginfo */ 1019static int debuginfo__find_probe_location(struct debuginfo *dbg,
1017static int debuginfo__find_probes(struct debuginfo *dbg,
1018 struct probe_finder *pf) 1020 struct probe_finder *pf)
1019{ 1021{
1020 struct perf_probe_point *pp = &pf->pev->point; 1022 struct perf_probe_point *pp = &pf->pev->point;
@@ -1023,27 +1025,6 @@ static int debuginfo__find_probes(struct debuginfo *dbg,
1023 Dwarf_Die *diep; 1025 Dwarf_Die *diep;
1024 int ret = 0; 1026 int ret = 0;
1025 1027
1026#if _ELFUTILS_PREREQ(0, 142)
1027 Elf *elf;
1028 GElf_Ehdr ehdr;
1029 GElf_Shdr shdr;
1030
1031 /* Get the call frame information from this dwarf */
1032 elf = dwarf_getelf(dbg->dbg);
1033 if (elf == NULL)
1034 return -EINVAL;
1035
1036 if (gelf_getehdr(elf, &ehdr) == NULL)
1037 return -EINVAL;
1038
1039 if (elf_section_by_name(elf, &ehdr, &shdr, ".eh_frame", NULL) &&
1040 shdr.sh_type == SHT_PROGBITS) {
1041 pf->cfi = dwarf_getcfi_elf(elf);
1042 } else {
1043 pf->cfi = dwarf_getcfi(dbg->dbg);
1044 }
1045#endif
1046
1047 off = 0; 1028 off = 0;
1048 pf->lcache = intlist__new(NULL); 1029 pf->lcache = intlist__new(NULL);
1049 if (!pf->lcache) 1030 if (!pf->lcache)
@@ -1106,6 +1087,39 @@ found:
1106 return ret; 1087 return ret;
1107} 1088}
1108 1089
1090/* Find probe points from debuginfo */
1091static int debuginfo__find_probes(struct debuginfo *dbg,
1092 struct probe_finder *pf)
1093{
1094 int ret = 0;
1095
1096#if _ELFUTILS_PREREQ(0, 142)
1097 Elf *elf;
1098 GElf_Ehdr ehdr;
1099 GElf_Shdr shdr;
1100
1101 if (pf->cfi_eh || pf->cfi_dbg)
1102 return debuginfo__find_probe_location(dbg, pf);
1103
1104 /* Get the call frame information from this dwarf */
1105 elf = dwarf_getelf(dbg->dbg);
1106 if (elf == NULL)
1107 return -EINVAL;
1108
1109 if (gelf_getehdr(elf, &ehdr) == NULL)
1110 return -EINVAL;
1111
1112 if (elf_section_by_name(elf, &ehdr, &shdr, ".eh_frame", NULL) &&
1113 shdr.sh_type == SHT_PROGBITS)
1114 pf->cfi_eh = dwarf_getcfi_elf(elf);
1115
1116 pf->cfi_dbg = dwarf_getcfi(dbg->dbg);
1117#endif
1118
1119 ret = debuginfo__find_probe_location(dbg, pf);
1120 return ret;
1121}
1122
1109struct local_vars_finder { 1123struct local_vars_finder {
1110 struct probe_finder *pf; 1124 struct probe_finder *pf;
1111 struct perf_probe_arg *args; 1125 struct perf_probe_arg *args;
@@ -1183,7 +1197,7 @@ static int add_probe_trace_event(Dwarf_Die *sc_die, struct probe_finder *pf)
1183 container_of(pf, struct trace_event_finder, pf); 1197 container_of(pf, struct trace_event_finder, pf);
1184 struct perf_probe_point *pp = &pf->pev->point; 1198 struct perf_probe_point *pp = &pf->pev->point;
1185 struct probe_trace_event *tev; 1199 struct probe_trace_event *tev;
1186 struct perf_probe_arg *args; 1200 struct perf_probe_arg *args = NULL;
1187 int ret, i; 1201 int ret, i;
1188 1202
1189 /* Check number of tevs */ 1203 /* Check number of tevs */
@@ -1198,19 +1212,23 @@ static int add_probe_trace_event(Dwarf_Die *sc_die, struct probe_finder *pf)
1198 ret = convert_to_trace_point(&pf->sp_die, tf->mod, pf->addr, 1212 ret = convert_to_trace_point(&pf->sp_die, tf->mod, pf->addr,
1199 pp->retprobe, pp->function, &tev->point); 1213 pp->retprobe, pp->function, &tev->point);
1200 if (ret < 0) 1214 if (ret < 0)
1201 return ret; 1215 goto end;
1202 1216
1203 tev->point.realname = strdup(dwarf_diename(sc_die)); 1217 tev->point.realname = strdup(dwarf_diename(sc_die));
1204 if (!tev->point.realname) 1218 if (!tev->point.realname) {
1205 return -ENOMEM; 1219 ret = -ENOMEM;
1220 goto end;
1221 }
1206 1222
1207 pr_debug("Probe point found: %s+%lu\n", tev->point.symbol, 1223 pr_debug("Probe point found: %s+%lu\n", tev->point.symbol,
1208 tev->point.offset); 1224 tev->point.offset);
1209 1225
1210 /* Expand special probe argument if exist */ 1226 /* Expand special probe argument if exist */
1211 args = zalloc(sizeof(struct perf_probe_arg) * MAX_PROBE_ARGS); 1227 args = zalloc(sizeof(struct perf_probe_arg) * MAX_PROBE_ARGS);
1212 if (args == NULL) 1228 if (args == NULL) {
1213 return -ENOMEM; 1229 ret = -ENOMEM;
1230 goto end;
1231 }
1214 1232
1215 ret = expand_probe_args(sc_die, pf, args); 1233 ret = expand_probe_args(sc_die, pf, args);
1216 if (ret < 0) 1234 if (ret < 0)
@@ -1234,6 +1252,10 @@ static int add_probe_trace_event(Dwarf_Die *sc_die, struct probe_finder *pf)
1234 } 1252 }
1235 1253
1236end: 1254end:
1255 if (ret) {
1256 clear_probe_trace_event(tev);
1257 tf->ntevs--;
1258 }
1237 free(args); 1259 free(args);
1238 return ret; 1260 return ret;
1239} 1261}
@@ -1246,7 +1268,7 @@ int debuginfo__find_trace_events(struct debuginfo *dbg,
1246 struct trace_event_finder tf = { 1268 struct trace_event_finder tf = {
1247 .pf = {.pev = pev, .callback = add_probe_trace_event}, 1269 .pf = {.pev = pev, .callback = add_probe_trace_event},
1248 .max_tevs = probe_conf.max_probes, .mod = dbg->mod}; 1270 .max_tevs = probe_conf.max_probes, .mod = dbg->mod};
1249 int ret; 1271 int ret, i;
1250 1272
1251 /* Allocate result tevs array */ 1273 /* Allocate result tevs array */
1252 *tevs = zalloc(sizeof(struct probe_trace_event) * tf.max_tevs); 1274 *tevs = zalloc(sizeof(struct probe_trace_event) * tf.max_tevs);
@@ -1258,6 +1280,8 @@ int debuginfo__find_trace_events(struct debuginfo *dbg,
1258 1280
1259 ret = debuginfo__find_probes(dbg, &tf.pf); 1281 ret = debuginfo__find_probes(dbg, &tf.pf);
1260 if (ret < 0) { 1282 if (ret < 0) {
1283 for (i = 0; i < tf.ntevs; i++)
1284 clear_probe_trace_event(&tf.tevs[i]);
1261 zfree(tevs); 1285 zfree(tevs);
1262 return ret; 1286 return ret;
1263 } 1287 }
@@ -1290,18 +1314,18 @@ static int collect_variables_cb(Dwarf_Die *die_mem, void *data)
1290 if (probe_conf.show_location_range) { 1314 if (probe_conf.show_location_range) {
1291 if (!externs) { 1315 if (!externs) {
1292 if (ret) 1316 if (ret)
1293 strbuf_addf(&buf, "[INV]\t"); 1317 strbuf_add(&buf, "[INV]\t", 6);
1294 else 1318 else
1295 strbuf_addf(&buf, "[VAL]\t"); 1319 strbuf_add(&buf, "[VAL]\t", 6);
1296 } else 1320 } else
1297 strbuf_addf(&buf, "[EXT]\t"); 1321 strbuf_add(&buf, "[EXT]\t", 6);
1298 } 1322 }
1299 1323
1300 ret2 = die_get_varname(die_mem, &buf); 1324 ret2 = die_get_varname(die_mem, &buf);
1301 1325
1302 if (!ret2 && probe_conf.show_location_range && 1326 if (!ret2 && probe_conf.show_location_range &&
1303 !externs) { 1327 !externs) {
1304 strbuf_addf(&buf, "\t"); 1328 strbuf_addch(&buf, '\t');
1305 ret2 = die_get_var_range(&af->pf.sp_die, 1329 ret2 = die_get_var_range(&af->pf.sp_die,
1306 die_mem, &buf); 1330 die_mem, &buf);
1307 } 1331 }
diff --git a/tools/perf/util/probe-finder.h b/tools/perf/util/probe-finder.h
index bed82716e1b4..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,
@@ -76,7 +74,10 @@ struct probe_finder {
76 74
77 /* For variable searching */ 75 /* For variable searching */
78#if _ELFUTILS_PREREQ(0, 142) 76#if _ELFUTILS_PREREQ(0, 142)
79 Dwarf_CFI *cfi; /* Call Frame Information */ 77 /* Call Frame Information from .eh_frame */
78 Dwarf_CFI *cfi_eh;
79 /* Call Frame Information from .debug_frame */
80 Dwarf_CFI *cfi_dbg;
80#endif 81#endif
81 Dwarf_Op *fb_ops; /* Frame base attribute */ 82 Dwarf_Op *fb_ops; /* Frame base attribute */
82 struct perf_probe_arg *pvar; /* Current target variable */ 83 struct perf_probe_arg *pvar; /* Current target variable */
diff --git a/tools/perf/util/python-ext-sources b/tools/perf/util/python-ext-sources
index 51be28b1bca2..8162ba0e2e57 100644
--- a/tools/perf/util/python-ext-sources
+++ b/tools/perf/util/python-ext-sources
@@ -10,6 +10,8 @@ util/ctype.c
10util/evlist.c 10util/evlist.c
11util/evsel.c 11util/evsel.c
12util/cpumap.c 12util/cpumap.c
13../lib/bitmap.c
14../lib/find_bit.c
13../lib/hweight.c 15../lib/hweight.c
14util/thread_map.c 16util/thread_map.c
15util/util.c 17util/util.c
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/run-command.c b/tools/perf/util/run-command.c
deleted file mode 100644
index 34622b53e733..000000000000
--- a/tools/perf/util/run-command.c
+++ /dev/null
@@ -1,219 +0,0 @@
1#include "cache.h"
2#include "run-command.h"
3#include "exec_cmd.h"
4#include "debug.h"
5
6static inline void close_pair(int fd[2])
7{
8 close(fd[0]);
9 close(fd[1]);
10}
11
12static inline void dup_devnull(int to)
13{
14 int fd = open("/dev/null", O_RDWR);
15 dup2(fd, to);
16 close(fd);
17}
18
19int start_command(struct child_process *cmd)
20{
21 int need_in, need_out, need_err;
22 int fdin[2], fdout[2], fderr[2];
23 char sbuf[STRERR_BUFSIZE];
24
25 /*
26 * In case of errors we must keep the promise to close FDs
27 * that have been passed in via ->in and ->out.
28 */
29
30 need_in = !cmd->no_stdin && cmd->in < 0;
31 if (need_in) {
32 if (pipe(fdin) < 0) {
33 if (cmd->out > 0)
34 close(cmd->out);
35 return -ERR_RUN_COMMAND_PIPE;
36 }
37 cmd->in = fdin[1];
38 }
39
40 need_out = !cmd->no_stdout
41 && !cmd->stdout_to_stderr
42 && cmd->out < 0;
43 if (need_out) {
44 if (pipe(fdout) < 0) {
45 if (need_in)
46 close_pair(fdin);
47 else if (cmd->in)
48 close(cmd->in);
49 return -ERR_RUN_COMMAND_PIPE;
50 }
51 cmd->out = fdout[0];
52 }
53
54 need_err = !cmd->no_stderr && cmd->err < 0;
55 if (need_err) {
56 if (pipe(fderr) < 0) {
57 if (need_in)
58 close_pair(fdin);
59 else if (cmd->in)
60 close(cmd->in);
61 if (need_out)
62 close_pair(fdout);
63 else if (cmd->out)
64 close(cmd->out);
65 return -ERR_RUN_COMMAND_PIPE;
66 }
67 cmd->err = fderr[0];
68 }
69
70 fflush(NULL);
71 cmd->pid = fork();
72 if (!cmd->pid) {
73 if (cmd->no_stdin)
74 dup_devnull(0);
75 else if (need_in) {
76 dup2(fdin[0], 0);
77 close_pair(fdin);
78 } else if (cmd->in) {
79 dup2(cmd->in, 0);
80 close(cmd->in);
81 }
82
83 if (cmd->no_stderr)
84 dup_devnull(2);
85 else if (need_err) {
86 dup2(fderr[1], 2);
87 close_pair(fderr);
88 }
89
90 if (cmd->no_stdout)
91 dup_devnull(1);
92 else if (cmd->stdout_to_stderr)
93 dup2(2, 1);
94 else if (need_out) {
95 dup2(fdout[1], 1);
96 close_pair(fdout);
97 } else if (cmd->out > 1) {
98 dup2(cmd->out, 1);
99 close(cmd->out);
100 }
101
102 if (cmd->dir && chdir(cmd->dir))
103 die("exec %s: cd to %s failed (%s)", cmd->argv[0],
104 cmd->dir, strerror_r(errno, sbuf, sizeof(sbuf)));
105 if (cmd->env) {
106 for (; *cmd->env; cmd->env++) {
107 if (strchr(*cmd->env, '='))
108 putenv((char*)*cmd->env);
109 else
110 unsetenv(*cmd->env);
111 }
112 }
113 if (cmd->preexec_cb)
114 cmd->preexec_cb();
115 if (cmd->perf_cmd) {
116 execv_perf_cmd(cmd->argv);
117 } else {
118 execvp(cmd->argv[0], (char *const*) cmd->argv);
119 }
120 exit(127);
121 }
122
123 if (cmd->pid < 0) {
124 int err = errno;
125 if (need_in)
126 close_pair(fdin);
127 else if (cmd->in)
128 close(cmd->in);
129 if (need_out)
130 close_pair(fdout);
131 else if (cmd->out)
132 close(cmd->out);
133 if (need_err)
134 close_pair(fderr);
135 return err == ENOENT ?
136 -ERR_RUN_COMMAND_EXEC :
137 -ERR_RUN_COMMAND_FORK;
138 }
139
140 if (need_in)
141 close(fdin[0]);
142 else if (cmd->in)
143 close(cmd->in);
144
145 if (need_out)
146 close(fdout[1]);
147 else if (cmd->out)
148 close(cmd->out);
149
150 if (need_err)
151 close(fderr[1]);
152
153 return 0;
154}
155
156static int wait_or_whine(pid_t pid)
157{
158 char sbuf[STRERR_BUFSIZE];
159
160 for (;;) {
161 int status, code;
162 pid_t waiting = waitpid(pid, &status, 0);
163
164 if (waiting < 0) {
165 if (errno == EINTR)
166 continue;
167 error("waitpid failed (%s)",
168 strerror_r(errno, sbuf, sizeof(sbuf)));
169 return -ERR_RUN_COMMAND_WAITPID;
170 }
171 if (waiting != pid)
172 return -ERR_RUN_COMMAND_WAITPID_WRONG_PID;
173 if (WIFSIGNALED(status))
174 return -ERR_RUN_COMMAND_WAITPID_SIGNAL;
175
176 if (!WIFEXITED(status))
177 return -ERR_RUN_COMMAND_WAITPID_NOEXIT;
178 code = WEXITSTATUS(status);
179 switch (code) {
180 case 127:
181 return -ERR_RUN_COMMAND_EXEC;
182 case 0:
183 return 0;
184 default:
185 return -code;
186 }
187 }
188}
189
190int finish_command(struct child_process *cmd)
191{
192 return wait_or_whine(cmd->pid);
193}
194
195int run_command(struct child_process *cmd)
196{
197 int code = start_command(cmd);
198 if (code)
199 return code;
200 return finish_command(cmd);
201}
202
203static void prepare_run_command_v_opt(struct child_process *cmd,
204 const char **argv,
205 int opt)
206{
207 memset(cmd, 0, sizeof(*cmd));
208 cmd->argv = argv;
209 cmd->no_stdin = opt & RUN_COMMAND_NO_STDIN ? 1 : 0;
210 cmd->perf_cmd = opt & RUN_PERF_CMD ? 1 : 0;
211 cmd->stdout_to_stderr = opt & RUN_COMMAND_STDOUT_TO_STDERR ? 1 : 0;
212}
213
214int run_command_v_opt(const char **argv, int opt)
215{
216 struct child_process cmd;
217 prepare_run_command_v_opt(&cmd, argv, opt);
218 return run_command(&cmd);
219}
diff --git a/tools/perf/util/run-command.h b/tools/perf/util/run-command.h
deleted file mode 100644
index 1ef264d5069c..000000000000
--- a/tools/perf/util/run-command.h
+++ /dev/null
@@ -1,58 +0,0 @@
1#ifndef __PERF_RUN_COMMAND_H
2#define __PERF_RUN_COMMAND_H
3
4enum {
5 ERR_RUN_COMMAND_FORK = 10000,
6 ERR_RUN_COMMAND_EXEC,
7 ERR_RUN_COMMAND_PIPE,
8 ERR_RUN_COMMAND_WAITPID,
9 ERR_RUN_COMMAND_WAITPID_WRONG_PID,
10 ERR_RUN_COMMAND_WAITPID_SIGNAL,
11 ERR_RUN_COMMAND_WAITPID_NOEXIT,
12};
13#define IS_RUN_COMMAND_ERR(x) (-(x) >= ERR_RUN_COMMAND_FORK)
14
15struct child_process {
16 const char **argv;
17 pid_t pid;
18 /*
19 * Using .in, .out, .err:
20 * - Specify 0 for no redirections (child inherits stdin, stdout,
21 * stderr from parent).
22 * - Specify -1 to have a pipe allocated as follows:
23 * .in: returns the writable pipe end; parent writes to it,
24 * the readable pipe end becomes child's stdin
25 * .out, .err: returns the readable pipe end; parent reads from
26 * it, the writable pipe end becomes child's stdout/stderr
27 * The caller of start_command() must close the returned FDs
28 * after it has completed reading from/writing to it!
29 * - Specify > 0 to set a channel to a particular FD as follows:
30 * .in: a readable FD, becomes child's stdin
31 * .out: a writable FD, becomes child's stdout/stderr
32 * .err > 0 not supported
33 * The specified FD is closed by start_command(), even in case
34 * of errors!
35 */
36 int in;
37 int out;
38 int err;
39 const char *dir;
40 const char *const *env;
41 unsigned no_stdin:1;
42 unsigned no_stdout:1;
43 unsigned no_stderr:1;
44 unsigned perf_cmd:1; /* if this is to be perf sub-command */
45 unsigned stdout_to_stderr:1;
46 void (*preexec_cb)(void);
47};
48
49int start_command(struct child_process *);
50int finish_command(struct child_process *);
51int run_command(struct child_process *);
52
53#define RUN_COMMAND_NO_STDIN 1
54#define RUN_PERF_CMD 2 /*If this is to be perf sub-command */
55#define RUN_COMMAND_STDOUT_TO_STDERR 4
56int run_command_v_opt(const char **argv, int opt);
57
58#endif /* __PERF_RUN_COMMAND_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 a8e825fca42a..fbd05242b4e5 100644
--- a/tools/perf/util/scripting-engines/trace-event-python.c
+++ b/tools/perf/util/scripting-engines/trace-event-python.c
@@ -41,6 +41,9 @@
41#include "../thread-stack.h" 41#include "../thread-stack.h"
42#include "../trace-event.h" 42#include "../trace-event.h"
43#include "../machine.h" 43#include "../machine.h"
44#include "thread_map.h"
45#include "cpumap.h"
46#include "stat.h"
44 47
45PyMODINIT_FUNC initperf_trace_context(void); 48PyMODINIT_FUNC initperf_trace_context(void);
46 49
@@ -202,6 +205,9 @@ static void define_event_symbols(struct event_format *event,
202 const char *ev_name, 205 const char *ev_name,
203 struct print_arg *args) 206 struct print_arg *args)
204{ 207{
208 if (args == NULL)
209 return;
210
205 switch (args->type) { 211 switch (args->type) {
206 case PRINT_NULL: 212 case PRINT_NULL:
207 break; 213 break;
@@ -859,6 +865,104 @@ static void python_process_event(union perf_event *event,
859 } 865 }
860} 866}
861 867
868static void get_handler_name(char *str, size_t size,
869 struct perf_evsel *evsel)
870{
871 char *p = str;
872
873 scnprintf(str, size, "stat__%s", perf_evsel__name(evsel));
874
875 while ((p = strchr(p, ':'))) {
876 *p = '_';
877 p++;
878 }
879}
880
881static void
882process_stat(struct perf_evsel *counter, int cpu, int thread, u64 tstamp,
883 struct perf_counts_values *count)
884{
885 PyObject *handler, *t;
886 static char handler_name[256];
887 int n = 0;
888
889 t = PyTuple_New(MAX_FIELDS);
890 if (!t)
891 Py_FatalError("couldn't create Python tuple");
892
893 get_handler_name(handler_name, sizeof(handler_name),
894 counter);
895
896 handler = get_handler(handler_name);
897 if (!handler) {
898 pr_debug("can't find python handler %s\n", handler_name);
899 return;
900 }
901
902 PyTuple_SetItem(t, n++, PyInt_FromLong(cpu));
903 PyTuple_SetItem(t, n++, PyInt_FromLong(thread));
904
905 tuple_set_u64(t, n++, tstamp);
906 tuple_set_u64(t, n++, count->val);
907 tuple_set_u64(t, n++, count->ena);
908 tuple_set_u64(t, n++, count->run);
909
910 if (_PyTuple_Resize(&t, n) == -1)
911 Py_FatalError("error resizing Python tuple");
912
913 call_object(handler, t, handler_name);
914
915 Py_DECREF(t);
916}
917
918static void python_process_stat(struct perf_stat_config *config,
919 struct perf_evsel *counter, u64 tstamp)
920{
921 struct thread_map *threads = counter->threads;
922 struct cpu_map *cpus = counter->cpus;
923 int cpu, thread;
924
925 if (config->aggr_mode == AGGR_GLOBAL) {
926 process_stat(counter, -1, -1, tstamp,
927 &counter->counts->aggr);
928 return;
929 }
930
931 for (thread = 0; thread < threads->nr; thread++) {
932 for (cpu = 0; cpu < cpus->nr; cpu++) {
933 process_stat(counter, cpus->map[cpu],
934 thread_map__pid(threads, thread), tstamp,
935 perf_counts(counter->counts, cpu, thread));
936 }
937 }
938}
939
940static void python_process_stat_interval(u64 tstamp)
941{
942 PyObject *handler, *t;
943 static const char handler_name[] = "stat__interval";
944 int n = 0;
945
946 t = PyTuple_New(MAX_FIELDS);
947 if (!t)
948 Py_FatalError("couldn't create Python tuple");
949
950 handler = get_handler(handler_name);
951 if (!handler) {
952 pr_debug("can't find python handler %s\n", handler_name);
953 return;
954 }
955
956 tuple_set_u64(t, n++, tstamp);
957
958 if (_PyTuple_Resize(&t, n) == -1)
959 Py_FatalError("error resizing Python tuple");
960
961 call_object(handler, t, handler_name);
962
963 Py_DECREF(t);
964}
965
862static int run_start_sub(void) 966static int run_start_sub(void)
863{ 967{
864 main_module = PyImport_AddModule("__main__"); 968 main_module = PyImport_AddModule("__main__");
@@ -990,8 +1094,6 @@ static int python_start_script(const char *script, int argc, const char **argv)
990 goto error; 1094 goto error;
991 } 1095 }
992 1096
993 free(command_line);
994
995 set_table_handlers(tables); 1097 set_table_handlers(tables);
996 1098
997 if (tables->db_export_mode) { 1099 if (tables->db_export_mode) {
@@ -1000,6 +1102,8 @@ static int python_start_script(const char *script, int argc, const char **argv)
1000 goto error; 1102 goto error;
1001 } 1103 }
1002 1104
1105 free(command_line);
1106
1003 return err; 1107 return err;
1004error: 1108error:
1005 Py_Finalize(); 1109 Py_Finalize();
@@ -1201,10 +1305,12 @@ static int python_generate_script(struct pevent *pevent, const char *outfile)
1201} 1305}
1202 1306
1203struct scripting_ops python_scripting_ops = { 1307struct scripting_ops python_scripting_ops = {
1204 .name = "Python", 1308 .name = "Python",
1205 .start_script = python_start_script, 1309 .start_script = python_start_script,
1206 .flush_script = python_flush_script, 1310 .flush_script = python_flush_script,
1207 .stop_script = python_stop_script, 1311 .stop_script = python_stop_script,
1208 .process_event = python_process_event, 1312 .process_event = python_process_event,
1209 .generate_script = python_generate_script, 1313 .process_stat = python_process_stat,
1314 .process_stat_interval = python_process_stat_interval,
1315 .generate_script = python_generate_script,
1210}; 1316};
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
index 428149bc64d2..4abd85c6346d 100644
--- a/tools/perf/util/session.c
+++ b/tools/perf/util/session.c
@@ -17,6 +17,7 @@
17#include "asm/bug.h" 17#include "asm/bug.h"
18#include "auxtrace.h" 18#include "auxtrace.h"
19#include "thread-stack.h" 19#include "thread-stack.h"
20#include "stat.h"
20 21
21static int perf_session__deliver_event(struct perf_session *session, 22static int perf_session__deliver_event(struct perf_session *session,
22 union perf_event *event, 23 union perf_event *event,
@@ -29,25 +30,28 @@ static int perf_session__open(struct perf_session *session)
29 struct perf_data_file *file = session->file; 30 struct perf_data_file *file = session->file;
30 31
31 if (perf_session__read_header(session) < 0) { 32 if (perf_session__read_header(session) < 0) {
32 pr_err("incompatible file format (rerun with -v to learn more)"); 33 pr_err("incompatible file format (rerun with -v to learn more)\n");
33 return -1; 34 return -1;
34 } 35 }
35 36
36 if (perf_data_file__is_pipe(file)) 37 if (perf_data_file__is_pipe(file))
37 return 0; 38 return 0;
38 39
40 if (perf_header__has_feat(&session->header, HEADER_STAT))
41 return 0;
42
39 if (!perf_evlist__valid_sample_type(session->evlist)) { 43 if (!perf_evlist__valid_sample_type(session->evlist)) {
40 pr_err("non matching sample_type"); 44 pr_err("non matching sample_type\n");
41 return -1; 45 return -1;
42 } 46 }
43 47
44 if (!perf_evlist__valid_sample_id_all(session->evlist)) { 48 if (!perf_evlist__valid_sample_id_all(session->evlist)) {
45 pr_err("non matching sample_id_all"); 49 pr_err("non matching sample_id_all\n");
46 return -1; 50 return -1;
47 } 51 }
48 52
49 if (!perf_evlist__valid_read_format(session->evlist)) { 53 if (!perf_evlist__valid_read_format(session->evlist)) {
50 pr_err("non matching read_format"); 54 pr_err("non matching read_format\n");
51 return -1; 55 return -1;
52 } 56 }
53 57
@@ -205,6 +209,18 @@ static int process_event_synth_attr_stub(struct perf_tool *tool __maybe_unused,
205 return 0; 209 return 0;
206} 210}
207 211
212static int process_event_synth_event_update_stub(struct perf_tool *tool __maybe_unused,
213 union perf_event *event __maybe_unused,
214 struct perf_evlist **pevlist
215 __maybe_unused)
216{
217 if (dump_trace)
218 perf_event__fprintf_event_update(event, stdout);
219
220 dump_printf(": unhandled!\n");
221 return 0;
222}
223
208static int process_event_sample_stub(struct perf_tool *tool __maybe_unused, 224static int process_event_sample_stub(struct perf_tool *tool __maybe_unused,
209 union perf_event *event __maybe_unused, 225 union perf_event *event __maybe_unused,
210 struct perf_sample *sample __maybe_unused, 226 struct perf_sample *sample __maybe_unused,
@@ -224,14 +240,6 @@ static int process_event_stub(struct perf_tool *tool __maybe_unused,
224 return 0; 240 return 0;
225} 241}
226 242
227static int process_build_id_stub(struct perf_tool *tool __maybe_unused,
228 union perf_event *event __maybe_unused,
229 struct perf_session *session __maybe_unused)
230{
231 dump_printf(": unhandled!\n");
232 return 0;
233}
234
235static int process_finished_round_stub(struct perf_tool *tool __maybe_unused, 243static int process_finished_round_stub(struct perf_tool *tool __maybe_unused,
236 union perf_event *event __maybe_unused, 244 union perf_event *event __maybe_unused,
237 struct ordered_events *oe __maybe_unused) 245 struct ordered_events *oe __maybe_unused)
@@ -244,23 +252,6 @@ static int process_finished_round(struct perf_tool *tool,
244 union perf_event *event, 252 union perf_event *event,
245 struct ordered_events *oe); 253 struct ordered_events *oe);
246 254
247static int process_id_index_stub(struct perf_tool *tool __maybe_unused,
248 union perf_event *event __maybe_unused,
249 struct perf_session *perf_session
250 __maybe_unused)
251{
252 dump_printf(": unhandled!\n");
253 return 0;
254}
255
256static int process_event_auxtrace_info_stub(struct perf_tool *tool __maybe_unused,
257 union perf_event *event __maybe_unused,
258 struct perf_session *session __maybe_unused)
259{
260 dump_printf(": unhandled!\n");
261 return 0;
262}
263
264static int skipn(int fd, off_t n) 255static int skipn(int fd, off_t n)
265{ 256{
266 char buf[4096]; 257 char buf[4096];
@@ -287,11 +278,71 @@ static s64 process_event_auxtrace_stub(struct perf_tool *tool __maybe_unused,
287 return event->auxtrace.size; 278 return event->auxtrace.size;
288} 279}
289 280
281static int process_event_op2_stub(struct perf_tool *tool __maybe_unused,
282 union perf_event *event __maybe_unused,
283 struct perf_session *session __maybe_unused)
284{
285 dump_printf(": unhandled!\n");
286 return 0;
287}
288
289
290static 290static
291int process_event_auxtrace_error_stub(struct perf_tool *tool __maybe_unused, 291int process_event_thread_map_stub(struct perf_tool *tool __maybe_unused,
292 union perf_event *event __maybe_unused, 292 union perf_event *event __maybe_unused,
293 struct perf_session *session __maybe_unused) 293 struct perf_session *session __maybe_unused)
294{
295 if (dump_trace)
296 perf_event__fprintf_thread_map(event, stdout);
297
298 dump_printf(": unhandled!\n");
299 return 0;
300}
301
302static
303int process_event_cpu_map_stub(struct perf_tool *tool __maybe_unused,
304 union perf_event *event __maybe_unused,
305 struct perf_session *session __maybe_unused)
306{
307 if (dump_trace)
308 perf_event__fprintf_cpu_map(event, stdout);
309
310 dump_printf(": unhandled!\n");
311 return 0;
312}
313
314static
315int process_event_stat_config_stub(struct perf_tool *tool __maybe_unused,
316 union perf_event *event __maybe_unused,
317 struct perf_session *session __maybe_unused)
318{
319 if (dump_trace)
320 perf_event__fprintf_stat_config(event, stdout);
321
322 dump_printf(": unhandled!\n");
323 return 0;
324}
325
326static int process_stat_stub(struct perf_tool *tool __maybe_unused,
327 union perf_event *event __maybe_unused,
328 struct perf_session *perf_session
329 __maybe_unused)
294{ 330{
331 if (dump_trace)
332 perf_event__fprintf_stat(event, stdout);
333
334 dump_printf(": unhandled!\n");
335 return 0;
336}
337
338static int process_stat_round_stub(struct perf_tool *tool __maybe_unused,
339 union perf_event *event __maybe_unused,
340 struct perf_session *perf_session
341 __maybe_unused)
342{
343 if (dump_trace)
344 perf_event__fprintf_stat_round(event, stdout);
345
295 dump_printf(": unhandled!\n"); 346 dump_printf(": unhandled!\n");
296 return 0; 347 return 0;
297} 348}
@@ -328,10 +379,12 @@ void perf_tool__fill_defaults(struct perf_tool *tool)
328 tool->unthrottle = process_event_stub; 379 tool->unthrottle = process_event_stub;
329 if (tool->attr == NULL) 380 if (tool->attr == NULL)
330 tool->attr = process_event_synth_attr_stub; 381 tool->attr = process_event_synth_attr_stub;
382 if (tool->event_update == NULL)
383 tool->event_update = process_event_synth_event_update_stub;
331 if (tool->tracing_data == NULL) 384 if (tool->tracing_data == NULL)
332 tool->tracing_data = process_event_synth_tracing_data_stub; 385 tool->tracing_data = process_event_synth_tracing_data_stub;
333 if (tool->build_id == NULL) 386 if (tool->build_id == NULL)
334 tool->build_id = process_build_id_stub; 387 tool->build_id = process_event_op2_stub;
335 if (tool->finished_round == NULL) { 388 if (tool->finished_round == NULL) {
336 if (tool->ordered_events) 389 if (tool->ordered_events)
337 tool->finished_round = process_finished_round; 390 tool->finished_round = process_finished_round;
@@ -339,13 +392,23 @@ void perf_tool__fill_defaults(struct perf_tool *tool)
339 tool->finished_round = process_finished_round_stub; 392 tool->finished_round = process_finished_round_stub;
340 } 393 }
341 if (tool->id_index == NULL) 394 if (tool->id_index == NULL)
342 tool->id_index = process_id_index_stub; 395 tool->id_index = process_event_op2_stub;
343 if (tool->auxtrace_info == NULL) 396 if (tool->auxtrace_info == NULL)
344 tool->auxtrace_info = process_event_auxtrace_info_stub; 397 tool->auxtrace_info = process_event_op2_stub;
345 if (tool->auxtrace == NULL) 398 if (tool->auxtrace == NULL)
346 tool->auxtrace = process_event_auxtrace_stub; 399 tool->auxtrace = process_event_auxtrace_stub;
347 if (tool->auxtrace_error == NULL) 400 if (tool->auxtrace_error == NULL)
348 tool->auxtrace_error = process_event_auxtrace_error_stub; 401 tool->auxtrace_error = process_event_op2_stub;
402 if (tool->thread_map == NULL)
403 tool->thread_map = process_event_thread_map_stub;
404 if (tool->cpu_map == NULL)
405 tool->cpu_map = process_event_cpu_map_stub;
406 if (tool->stat_config == NULL)
407 tool->stat_config = process_event_stat_config_stub;
408 if (tool->stat == NULL)
409 tool->stat = process_stat_stub;
410 if (tool->stat_round == NULL)
411 tool->stat_round = process_stat_round_stub;
349} 412}
350 413
351static void swap_sample_id_all(union perf_event *event, void *data) 414static void swap_sample_id_all(union perf_event *event, void *data)
@@ -569,6 +632,13 @@ static void perf_event__hdr_attr_swap(union perf_event *event,
569 mem_bswap_64(event->attr.id, size); 632 mem_bswap_64(event->attr.id, size);
570} 633}
571 634
635static void perf_event__event_update_swap(union perf_event *event,
636 bool sample_id_all __maybe_unused)
637{
638 event->event_update.type = bswap_64(event->event_update.type);
639 event->event_update.id = bswap_64(event->event_update.id);
640}
641
572static void perf_event__event_type_swap(union perf_event *event, 642static void perf_event__event_type_swap(union perf_event *event,
573 bool sample_id_all __maybe_unused) 643 bool sample_id_all __maybe_unused)
574{ 644{
@@ -616,6 +686,81 @@ static void perf_event__auxtrace_error_swap(union perf_event *event,
616 event->auxtrace_error.ip = bswap_64(event->auxtrace_error.ip); 686 event->auxtrace_error.ip = bswap_64(event->auxtrace_error.ip);
617} 687}
618 688
689static void perf_event__thread_map_swap(union perf_event *event,
690 bool sample_id_all __maybe_unused)
691{
692 unsigned i;
693
694 event->thread_map.nr = bswap_64(event->thread_map.nr);
695
696 for (i = 0; i < event->thread_map.nr; i++)
697 event->thread_map.entries[i].pid = bswap_64(event->thread_map.entries[i].pid);
698}
699
700static void perf_event__cpu_map_swap(union perf_event *event,
701 bool sample_id_all __maybe_unused)
702{
703 struct cpu_map_data *data = &event->cpu_map.data;
704 struct cpu_map_entries *cpus;
705 struct cpu_map_mask *mask;
706 unsigned i;
707
708 data->type = bswap_64(data->type);
709
710 switch (data->type) {
711 case PERF_CPU_MAP__CPUS:
712 cpus = (struct cpu_map_entries *)data->data;
713
714 cpus->nr = bswap_16(cpus->nr);
715
716 for (i = 0; i < cpus->nr; i++)
717 cpus->cpu[i] = bswap_16(cpus->cpu[i]);
718 break;
719 case PERF_CPU_MAP__MASK:
720 mask = (struct cpu_map_mask *) data->data;
721
722 mask->nr = bswap_16(mask->nr);
723 mask->long_size = bswap_16(mask->long_size);
724
725 switch (mask->long_size) {
726 case 4: mem_bswap_32(&mask->mask, mask->nr); break;
727 case 8: mem_bswap_64(&mask->mask, mask->nr); break;
728 default:
729 pr_err("cpu_map swap: unsupported long size\n");
730 }
731 default:
732 break;
733 }
734}
735
736static void perf_event__stat_config_swap(union perf_event *event,
737 bool sample_id_all __maybe_unused)
738{
739 u64 size;
740
741 size = event->stat_config.nr * sizeof(event->stat_config.data[0]);
742 size += 1; /* nr item itself */
743 mem_bswap_64(&event->stat_config.nr, size);
744}
745
746static void perf_event__stat_swap(union perf_event *event,
747 bool sample_id_all __maybe_unused)
748{
749 event->stat.id = bswap_64(event->stat.id);
750 event->stat.thread = bswap_32(event->stat.thread);
751 event->stat.cpu = bswap_32(event->stat.cpu);
752 event->stat.val = bswap_64(event->stat.val);
753 event->stat.ena = bswap_64(event->stat.ena);
754 event->stat.run = bswap_64(event->stat.run);
755}
756
757static void perf_event__stat_round_swap(union perf_event *event,
758 bool sample_id_all __maybe_unused)
759{
760 event->stat_round.type = bswap_64(event->stat_round.type);
761 event->stat_round.time = bswap_64(event->stat_round.time);
762}
763
619typedef void (*perf_event__swap_op)(union perf_event *event, 764typedef void (*perf_event__swap_op)(union perf_event *event,
620 bool sample_id_all); 765 bool sample_id_all);
621 766
@@ -643,6 +788,12 @@ static perf_event__swap_op perf_event__swap_ops[] = {
643 [PERF_RECORD_AUXTRACE_INFO] = perf_event__auxtrace_info_swap, 788 [PERF_RECORD_AUXTRACE_INFO] = perf_event__auxtrace_info_swap,
644 [PERF_RECORD_AUXTRACE] = perf_event__auxtrace_swap, 789 [PERF_RECORD_AUXTRACE] = perf_event__auxtrace_swap,
645 [PERF_RECORD_AUXTRACE_ERROR] = perf_event__auxtrace_error_swap, 790 [PERF_RECORD_AUXTRACE_ERROR] = perf_event__auxtrace_error_swap,
791 [PERF_RECORD_THREAD_MAP] = perf_event__thread_map_swap,
792 [PERF_RECORD_CPU_MAP] = perf_event__cpu_map_swap,
793 [PERF_RECORD_STAT_CONFIG] = perf_event__stat_config_swap,
794 [PERF_RECORD_STAT] = perf_event__stat_swap,
795 [PERF_RECORD_STAT_ROUND] = perf_event__stat_round_swap,
796 [PERF_RECORD_EVENT_UPDATE] = perf_event__event_update_swap,
646 [PERF_RECORD_HEADER_MAX] = NULL, 797 [PERF_RECORD_HEADER_MAX] = NULL,
647}; 798};
648 799
@@ -956,12 +1107,11 @@ static struct machine *machines__find_for_cpumode(struct machines *machines,
956 union perf_event *event, 1107 union perf_event *event,
957 struct perf_sample *sample) 1108 struct perf_sample *sample)
958{ 1109{
959 const u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
960 struct machine *machine; 1110 struct machine *machine;
961 1111
962 if (perf_guest && 1112 if (perf_guest &&
963 ((cpumode == PERF_RECORD_MISC_GUEST_KERNEL) || 1113 ((sample->cpumode == PERF_RECORD_MISC_GUEST_KERNEL) ||
964 (cpumode == PERF_RECORD_MISC_GUEST_USER))) { 1114 (sample->cpumode == PERF_RECORD_MISC_GUEST_USER))) {
965 u32 pid; 1115 u32 pid;
966 1116
967 if (event->header.type == PERF_RECORD_MMAP 1117 if (event->header.type == PERF_RECORD_MMAP
@@ -972,7 +1122,7 @@ static struct machine *machines__find_for_cpumode(struct machines *machines,
972 1122
973 machine = machines__find(machines, pid); 1123 machine = machines__find(machines, pid);
974 if (!machine) 1124 if (!machine)
975 machine = machines__find(machines, DEFAULT_GUEST_KERNEL_ID); 1125 machine = machines__findnew(machines, DEFAULT_GUEST_KERNEL_ID);
976 return machine; 1126 return machine;
977 } 1127 }
978 1128
@@ -1154,6 +1304,8 @@ static s64 perf_session__process_user_event(struct perf_session *session,
1154 perf_session__set_comm_exec(session); 1304 perf_session__set_comm_exec(session);
1155 } 1305 }
1156 return err; 1306 return err;
1307 case PERF_RECORD_EVENT_UPDATE:
1308 return tool->event_update(tool, event, &session->evlist);
1157 case PERF_RECORD_HEADER_EVENT_TYPE: 1309 case PERF_RECORD_HEADER_EVENT_TYPE:
1158 /* 1310 /*
1159 * Depreceated, but we need to handle it for sake 1311 * Depreceated, but we need to handle it for sake
@@ -1179,6 +1331,16 @@ static s64 perf_session__process_user_event(struct perf_session *session,
1179 case PERF_RECORD_AUXTRACE_ERROR: 1331 case PERF_RECORD_AUXTRACE_ERROR:
1180 perf_session__auxtrace_error_inc(session, event); 1332 perf_session__auxtrace_error_inc(session, event);
1181 return tool->auxtrace_error(tool, event, session); 1333 return tool->auxtrace_error(tool, event, session);
1334 case PERF_RECORD_THREAD_MAP:
1335 return tool->thread_map(tool, event, session);
1336 case PERF_RECORD_CPU_MAP:
1337 return tool->cpu_map(tool, event, session);
1338 case PERF_RECORD_STAT_CONFIG:
1339 return tool->stat_config(tool, event, session);
1340 case PERF_RECORD_STAT:
1341 return tool->stat(tool, event, session);
1342 case PERF_RECORD_STAT_ROUND:
1343 return tool->stat_round(tool, event, session);
1182 default: 1344 default:
1183 return -EINVAL; 1345 return -EINVAL;
1184 } 1346 }
@@ -1311,17 +1473,20 @@ struct thread *perf_session__findnew(struct perf_session *session, pid_t pid)
1311 return machine__findnew_thread(&session->machines.host, -1, pid); 1473 return machine__findnew_thread(&session->machines.host, -1, pid);
1312} 1474}
1313 1475
1314struct thread *perf_session__register_idle_thread(struct perf_session *session) 1476int perf_session__register_idle_thread(struct perf_session *session)
1315{ 1477{
1316 struct thread *thread; 1478 struct thread *thread;
1479 int err = 0;
1317 1480
1318 thread = machine__findnew_thread(&session->machines.host, 0, 0); 1481 thread = machine__findnew_thread(&session->machines.host, 0, 0);
1319 if (thread == NULL || thread__set_comm(thread, "swapper", 0)) { 1482 if (thread == NULL || thread__set_comm(thread, "swapper", 0)) {
1320 pr_err("problem inserting idle task.\n"); 1483 pr_err("problem inserting idle task.\n");
1321 thread = NULL; 1484 err = -1;
1322 } 1485 }
1323 1486
1324 return thread; 1487 /* machine__findnew_thread() got the thread, so put it */
1488 thread__put(thread);
1489 return err;
1325} 1490}
1326 1491
1327static void perf_session__warn_about_errors(const struct perf_session *session) 1492static void perf_session__warn_about_errors(const struct perf_session *session)
@@ -1676,7 +1841,7 @@ int perf_session__process_events(struct perf_session *session)
1676 u64 size = perf_data_file__size(session->file); 1841 u64 size = perf_data_file__size(session->file);
1677 int err; 1842 int err;
1678 1843
1679 if (perf_session__register_idle_thread(session) == NULL) 1844 if (perf_session__register_idle_thread(session) < 0)
1680 return -ENOMEM; 1845 return -ENOMEM;
1681 1846
1682 if (!perf_data_file__is_pipe(session->file)) 1847 if (!perf_data_file__is_pipe(session->file))
diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h
index 3e900c0efc73..5f792e35d4c1 100644
--- a/tools/perf/util/session.h
+++ b/tools/perf/util/session.h
@@ -89,7 +89,7 @@ struct machine *perf_session__findnew_machine(struct perf_session *session, pid_
89} 89}
90 90
91struct thread *perf_session__findnew(struct perf_session *session, pid_t pid); 91struct thread *perf_session__findnew(struct perf_session *session, pid_t pid);
92struct thread *perf_session__register_idle_thread(struct perf_session *session); 92int perf_session__register_idle_thread(struct perf_session *session);
93 93
94size_t perf_session__fprintf(struct perf_session *session, FILE *fp); 94size_t perf_session__fprintf(struct perf_session *session, FILE *fp);
95 95
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/sigchain.c b/tools/perf/util/sigchain.c
deleted file mode 100644
index ba785e9b1841..000000000000
--- a/tools/perf/util/sigchain.c
+++ /dev/null
@@ -1,52 +0,0 @@
1#include "sigchain.h"
2#include "cache.h"
3
4#define SIGCHAIN_MAX_SIGNALS 32
5
6struct sigchain_signal {
7 sigchain_fun *old;
8 int n;
9 int alloc;
10};
11static struct sigchain_signal signals[SIGCHAIN_MAX_SIGNALS];
12
13static void check_signum(int sig)
14{
15 if (sig < 1 || sig >= SIGCHAIN_MAX_SIGNALS)
16 die("BUG: signal out of range: %d", sig);
17}
18
19static int sigchain_push(int sig, sigchain_fun f)
20{
21 struct sigchain_signal *s = signals + sig;
22 check_signum(sig);
23
24 ALLOC_GROW(s->old, s->n + 1, s->alloc);
25 s->old[s->n] = signal(sig, f);
26 if (s->old[s->n] == SIG_ERR)
27 return -1;
28 s->n++;
29 return 0;
30}
31
32int sigchain_pop(int sig)
33{
34 struct sigchain_signal *s = signals + sig;
35 check_signum(sig);
36 if (s->n < 1)
37 return 0;
38
39 if (signal(sig, s->old[s->n - 1]) == SIG_ERR)
40 return -1;
41 s->n--;
42 return 0;
43}
44
45void sigchain_push_common(sigchain_fun f)
46{
47 sigchain_push(SIGINT, f);
48 sigchain_push(SIGHUP, f);
49 sigchain_push(SIGTERM, f);
50 sigchain_push(SIGQUIT, f);
51 sigchain_push(SIGPIPE, f);
52}
diff --git a/tools/perf/util/sigchain.h b/tools/perf/util/sigchain.h
deleted file mode 100644
index 959d64eb5557..000000000000
--- a/tools/perf/util/sigchain.h
+++ /dev/null
@@ -1,10 +0,0 @@
1#ifndef __PERF_SIGCHAIN_H
2#define __PERF_SIGCHAIN_H
3
4typedef void (*sigchain_fun)(int);
5
6int sigchain_pop(int sig);
7
8void sigchain_push_common(sigchain_fun f);
9
10#endif /* __PERF_SIGCHAIN_H */
diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c
index 2d8ccd4d9e1b..47966a1618c7 100644
--- a/tools/perf/util/sort.c
+++ b/tools/perf/util/sort.c
@@ -4,6 +4,9 @@
4#include "comm.h" 4#include "comm.h"
5#include "symbol.h" 5#include "symbol.h"
6#include "evsel.h" 6#include "evsel.h"
7#include "evlist.h"
8#include <traceevent/event-parse.h>
9#include "mem-events.h"
7 10
8regex_t parent_regex; 11regex_t parent_regex;
9const char default_parent_pattern[] = "^sys_|^do_page_fault"; 12const char default_parent_pattern[] = "^sys_|^do_page_fault";
@@ -13,6 +16,7 @@ const char default_branch_sort_order[] = "comm,dso_from,symbol_from,symbol_to,cy
13const char default_mem_sort_order[] = "local_weight,mem,sym,dso,symbol_daddr,dso_daddr,snoop,tlb,locked"; 16const char default_mem_sort_order[] = "local_weight,mem,sym,dso,symbol_daddr,dso_daddr,snoop,tlb,locked";
14const char default_top_sort_order[] = "dso,symbol"; 17const char default_top_sort_order[] = "dso,symbol";
15const char default_diff_sort_order[] = "dso,symbol"; 18const char default_diff_sort_order[] = "dso,symbol";
19const char default_tracepoint_sort_order[] = "trace";
16const char *sort_order; 20const char *sort_order;
17const char *field_order; 21const char *field_order;
18regex_t ignore_callees_regex; 22regex_t ignore_callees_regex;
@@ -22,9 +26,19 @@ int sort__has_parent = 0;
22int sort__has_sym = 0; 26int sort__has_sym = 0;
23int sort__has_dso = 0; 27int sort__has_dso = 0;
24int sort__has_socket = 0; 28int sort__has_socket = 0;
29int sort__has_thread = 0;
30int sort__has_comm = 0;
25enum sort_mode sort__mode = SORT_MODE__NORMAL; 31enum sort_mode sort__mode = SORT_MODE__NORMAL;
26 32
27 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*/
28static int repsep_snprintf(char *bf, size_t size, const char *fmt, ...) 42static int repsep_snprintf(char *bf, size_t size, const char *fmt, ...)
29{ 43{
30 int n; 44 int n;
@@ -77,10 +91,21 @@ static int hist_entry__thread_snprintf(struct hist_entry *he, char *bf,
77 width, width, comm ?: ""); 91 width, width, comm ?: "");
78} 92}
79 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
80struct sort_entry sort_thread = { 104struct sort_entry sort_thread = {
81 .se_header = " Pid:Command", 105 .se_header = " Pid:Command",
82 .se_cmp = sort__thread_cmp, 106 .se_cmp = sort__thread_cmp,
83 .se_snprintf = hist_entry__thread_snprintf, 107 .se_snprintf = hist_entry__thread_snprintf,
108 .se_filter = hist_entry__thread_filter,
84 .se_width_idx = HISTC_THREAD, 109 .se_width_idx = HISTC_THREAD,
85}; 110};
86 111
@@ -118,6 +143,7 @@ struct sort_entry sort_comm = {
118 .se_collapse = sort__comm_collapse, 143 .se_collapse = sort__comm_collapse,
119 .se_sort = sort__comm_sort, 144 .se_sort = sort__comm_sort,
120 .se_snprintf = hist_entry__comm_snprintf, 145 .se_snprintf = hist_entry__comm_snprintf,
146 .se_filter = hist_entry__thread_filter,
121 .se_width_idx = HISTC_COMM, 147 .se_width_idx = HISTC_COMM,
122}; 148};
123 149
@@ -167,10 +193,21 @@ static int hist_entry__dso_snprintf(struct hist_entry *he, char *bf,
167 return _hist_entry__dso_snprintf(he->ms.map, bf, size, width); 193 return _hist_entry__dso_snprintf(he->ms.map, bf, size, width);
168} 194}
169 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
170struct sort_entry sort_dso = { 206struct sort_entry sort_dso = {
171 .se_header = "Shared Object", 207 .se_header = "Shared Object",
172 .se_cmp = sort__dso_cmp, 208 .se_cmp = sort__dso_cmp,
173 .se_snprintf = hist_entry__dso_snprintf, 209 .se_snprintf = hist_entry__dso_snprintf,
210 .se_filter = hist_entry__dso_filter,
174 .se_width_idx = HISTC_DSO, 211 .se_width_idx = HISTC_DSO,
175}; 212};
176 213
@@ -243,10 +280,8 @@ static int _hist_entry__sym_snprintf(struct map *map, struct symbol *sym,
243 ret += repsep_snprintf(bf + ret, size - ret, "%s", sym->name); 280 ret += repsep_snprintf(bf + ret, size - ret, "%s", sym->name);
244 ret += repsep_snprintf(bf + ret, size - ret, "+0x%llx", 281 ret += repsep_snprintf(bf + ret, size - ret, "+0x%llx",
245 ip - map->unmap_ip(map, sym->start)); 282 ip - map->unmap_ip(map, sym->start));
246 ret += repsep_snprintf(bf + ret, size - ret, "%-*s",
247 width - ret, "");
248 } else { 283 } else {
249 ret += repsep_snprintf(bf + ret, size - ret, "%-*s", 284 ret += repsep_snprintf(bf + ret, size - ret, "%.*s",
250 width - ret, 285 width - ret,
251 sym->name); 286 sym->name);
252 } 287 }
@@ -254,14 +289,9 @@ static int _hist_entry__sym_snprintf(struct map *map, struct symbol *sym,
254 size_t len = BITS_PER_LONG / 4; 289 size_t len = BITS_PER_LONG / 4;
255 ret += repsep_snprintf(bf + ret, size - ret, "%-#.*llx", 290 ret += repsep_snprintf(bf + ret, size - ret, "%-#.*llx",
256 len, ip); 291 len, ip);
257 ret += repsep_snprintf(bf + ret, size - ret, "%-*s",
258 width - ret, "");
259 } 292 }
260 293
261 if (ret > width) 294 return ret;
262 bf[width] = '\0';
263
264 return width;
265} 295}
266 296
267static int hist_entry__sym_snprintf(struct hist_entry *he, char *bf, 297static int hist_entry__sym_snprintf(struct hist_entry *he, char *bf,
@@ -271,46 +301,56 @@ static int hist_entry__sym_snprintf(struct hist_entry *he, char *bf,
271 he->level, bf, size, width); 301 he->level, bf, size, width);
272} 302}
273 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
274struct sort_entry sort_sym = { 314struct sort_entry sort_sym = {
275 .se_header = "Symbol", 315 .se_header = "Symbol",
276 .se_cmp = sort__sym_cmp, 316 .se_cmp = sort__sym_cmp,
277 .se_sort = sort__sym_sort, 317 .se_sort = sort__sym_sort,
278 .se_snprintf = hist_entry__sym_snprintf, 318 .se_snprintf = hist_entry__sym_snprintf,
319 .se_filter = hist_entry__sym_filter,
279 .se_width_idx = HISTC_SYMBOL, 320 .se_width_idx = HISTC_SYMBOL,
280}; 321};
281 322
282/* --sort srcline */ 323/* --sort srcline */
283 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
284static int64_t 336static int64_t
285sort__srcline_cmp(struct hist_entry *left, struct hist_entry *right) 337sort__srcline_cmp(struct hist_entry *left, struct hist_entry *right)
286{ 338{
287 if (!left->srcline) { 339 if (!left->srcline)
288 if (!left->ms.map) 340 left->srcline = hist_entry__get_srcline(left);
289 left->srcline = SRCLINE_UNKNOWN; 341 if (!right->srcline)
290 else { 342 right->srcline = hist_entry__get_srcline(right);
291 struct map *map = left->ms.map; 343
292 left->srcline = get_srcline(map->dso,
293 map__rip_2objdump(map, left->ip),
294 left->ms.sym, true);
295 }
296 }
297 if (!right->srcline) {
298 if (!right->ms.map)
299 right->srcline = SRCLINE_UNKNOWN;
300 else {
301 struct map *map = right->ms.map;
302 right->srcline = get_srcline(map->dso,
303 map__rip_2objdump(map, right->ip),
304 right->ms.sym, true);
305 }
306 }
307 return strcmp(right->srcline, left->srcline); 344 return strcmp(right->srcline, left->srcline);
308} 345}
309 346
310static int hist_entry__srcline_snprintf(struct hist_entry *he, char *bf, 347static int hist_entry__srcline_snprintf(struct hist_entry *he, char *bf,
311 size_t size, unsigned int width) 348 size_t size, unsigned int width)
312{ 349{
313 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);
314} 354}
315 355
316struct sort_entry sort_srcline = { 356struct sort_entry sort_srcline = {
@@ -324,11 +364,14 @@ struct sort_entry sort_srcline = {
324 364
325static char no_srcfile[1]; 365static char no_srcfile[1];
326 366
327static char *get_srcfile(struct hist_entry *e) 367static char *hist_entry__get_srcfile(struct hist_entry *e)
328{ 368{
329 char *sf, *p; 369 char *sf, *p;
330 struct map *map = e->ms.map; 370 struct map *map = e->ms.map;
331 371
372 if (!map)
373 return no_srcfile;
374
332 sf = __get_srcline(map->dso, map__rip_2objdump(map, e->ip), 375 sf = __get_srcline(map->dso, map__rip_2objdump(map, e->ip),
333 e->ms.sym, false, true); 376 e->ms.sym, false, true);
334 if (!strcmp(sf, SRCLINE_UNKNOWN)) 377 if (!strcmp(sf, SRCLINE_UNKNOWN))
@@ -345,25 +388,21 @@ static char *get_srcfile(struct hist_entry *e)
345static int64_t 388static int64_t
346sort__srcfile_cmp(struct hist_entry *left, struct hist_entry *right) 389sort__srcfile_cmp(struct hist_entry *left, struct hist_entry *right)
347{ 390{
348 if (!left->srcfile) { 391 if (!left->srcfile)
349 if (!left->ms.map) 392 left->srcfile = hist_entry__get_srcfile(left);
350 left->srcfile = no_srcfile; 393 if (!right->srcfile)
351 else 394 right->srcfile = hist_entry__get_srcfile(right);
352 left->srcfile = get_srcfile(left); 395
353 }
354 if (!right->srcfile) {
355 if (!right->ms.map)
356 right->srcfile = no_srcfile;
357 else
358 right->srcfile = get_srcfile(right);
359 }
360 return strcmp(right->srcfile, left->srcfile); 396 return strcmp(right->srcfile, left->srcfile);
361} 397}
362 398
363static int hist_entry__srcfile_snprintf(struct hist_entry *he, char *bf, 399static int hist_entry__srcfile_snprintf(struct hist_entry *he, char *bf,
364 size_t size, unsigned int width) 400 size_t size, unsigned int width)
365{ 401{
366 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);
367} 406}
368 407
369struct sort_entry sort_srcfile = { 408struct sort_entry sort_srcfile = {
@@ -436,13 +475,85 @@ static int hist_entry__socket_snprintf(struct hist_entry *he, char *bf,
436 return repsep_snprintf(bf, size, "%*.*d", width, width-3, he->socket); 475 return repsep_snprintf(bf, size, "%*.*d", width, width-3, he->socket);
437} 476}
438 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
439struct sort_entry sort_socket = { 488struct sort_entry sort_socket = {
440 .se_header = "Socket", 489 .se_header = "Socket",
441 .se_cmp = sort__socket_cmp, 490 .se_cmp = sort__socket_cmp,
442 .se_snprintf = hist_entry__socket_snprintf, 491 .se_snprintf = hist_entry__socket_snprintf,
492 .se_filter = hist_entry__socket_filter,
443 .se_width_idx = HISTC_SOCKET, 493 .se_width_idx = HISTC_SOCKET,
444}; 494};
445 495
496/* --sort trace */
497
498static char *get_trace_output(struct hist_entry *he)
499{
500 struct trace_seq seq;
501 struct perf_evsel *evsel;
502 struct pevent_record rec = {
503 .data = he->raw_data,
504 .size = he->raw_size,
505 };
506
507 evsel = hists_to_evsel(he->hists);
508
509 trace_seq_init(&seq);
510 if (symbol_conf.raw_trace) {
511 pevent_print_fields(&seq, he->raw_data, he->raw_size,
512 evsel->tp_format);
513 } else {
514 pevent_event_info(&seq, evsel->tp_format, &rec);
515 }
516 return seq.buffer;
517}
518
519static int64_t
520sort__trace_cmp(struct hist_entry *left, struct hist_entry *right)
521{
522 struct perf_evsel *evsel;
523
524 evsel = hists_to_evsel(left->hists);
525 if (evsel->attr.type != PERF_TYPE_TRACEPOINT)
526 return 0;
527
528 if (left->trace_output == NULL)
529 left->trace_output = get_trace_output(left);
530 if (right->trace_output == NULL)
531 right->trace_output = get_trace_output(right);
532
533 return strcmp(right->trace_output, left->trace_output);
534}
535
536static int hist_entry__trace_snprintf(struct hist_entry *he, char *bf,
537 size_t size, unsigned int width)
538{
539 struct perf_evsel *evsel;
540
541 evsel = hists_to_evsel(he->hists);
542 if (evsel->attr.type != PERF_TYPE_TRACEPOINT)
543 return scnprintf(bf, size, "%-.*s", width, "N/A");
544
545 if (he->trace_output == NULL)
546 he->trace_output = get_trace_output(he);
547 return repsep_snprintf(bf, size, "%-.*s", width, he->trace_output);
548}
549
550struct sort_entry sort_trace = {
551 .se_header = "Trace output",
552 .se_cmp = sort__trace_cmp,
553 .se_snprintf = hist_entry__trace_snprintf,
554 .se_width_idx = HISTC_TRACE,
555};
556
446/* sort keys for branch stacks */ 557/* sort keys for branch stacks */
447 558
448static int64_t 559static int64_t
@@ -465,6 +576,18 @@ static int hist_entry__dso_from_snprintf(struct hist_entry *he, char *bf,
465 return repsep_snprintf(bf, size, "%-*.*s", width, width, "N/A"); 576 return repsep_snprintf(bf, size, "%-*.*s", width, width, "N/A");
466} 577}
467 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
468static int64_t 591static int64_t
469sort__dso_to_cmp(struct hist_entry *left, struct hist_entry *right) 592sort__dso_to_cmp(struct hist_entry *left, struct hist_entry *right)
470{ 593{
@@ -485,6 +608,18 @@ static int hist_entry__dso_to_snprintf(struct hist_entry *he, char *bf,
485 return repsep_snprintf(bf, size, "%-*.*s", width, width, "N/A"); 608 return repsep_snprintf(bf, size, "%-*.*s", width, width, "N/A");
486} 609}
487 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
488static int64_t 623static int64_t
489sort__sym_from_cmp(struct hist_entry *left, struct hist_entry *right) 624sort__sym_from_cmp(struct hist_entry *left, struct hist_entry *right)
490{ 625{
@@ -546,10 +681,35 @@ static int hist_entry__sym_to_snprintf(struct hist_entry *he, char *bf,
546 return repsep_snprintf(bf, size, "%-*.*s", width, width, "N/A"); 681 return repsep_snprintf(bf, size, "%-*.*s", width, width, "N/A");
547} 682}
548 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
549struct sort_entry sort_dso_from = { 708struct sort_entry sort_dso_from = {
550 .se_header = "Source Shared Object", 709 .se_header = "Source Shared Object",
551 .se_cmp = sort__dso_from_cmp, 710 .se_cmp = sort__dso_from_cmp,
552 .se_snprintf = hist_entry__dso_from_snprintf, 711 .se_snprintf = hist_entry__dso_from_snprintf,
712 .se_filter = hist_entry__dso_from_filter,
553 .se_width_idx = HISTC_DSO_FROM, 713 .se_width_idx = HISTC_DSO_FROM,
554}; 714};
555 715
@@ -557,6 +717,7 @@ struct sort_entry sort_dso_to = {
557 .se_header = "Target Shared Object", 717 .se_header = "Target Shared Object",
558 .se_cmp = sort__dso_to_cmp, 718 .se_cmp = sort__dso_to_cmp,
559 .se_snprintf = hist_entry__dso_to_snprintf, 719 .se_snprintf = hist_entry__dso_to_snprintf,
720 .se_filter = hist_entry__dso_to_filter,
560 .se_width_idx = HISTC_DSO_TO, 721 .se_width_idx = HISTC_DSO_TO,
561}; 722};
562 723
@@ -564,6 +725,7 @@ struct sort_entry sort_sym_from = {
564 .se_header = "Source Symbol", 725 .se_header = "Source Symbol",
565 .se_cmp = sort__sym_from_cmp, 726 .se_cmp = sort__sym_from_cmp,
566 .se_snprintf = hist_entry__sym_from_snprintf, 727 .se_snprintf = hist_entry__sym_from_snprintf,
728 .se_filter = hist_entry__sym_from_filter,
567 .se_width_idx = HISTC_SYMBOL_FROM, 729 .se_width_idx = HISTC_SYMBOL_FROM,
568}; 730};
569 731
@@ -571,6 +733,7 @@ struct sort_entry sort_sym_to = {
571 .se_header = "Target Symbol", 733 .se_header = "Target Symbol",
572 .se_cmp = sort__sym_to_cmp, 734 .se_cmp = sort__sym_to_cmp,
573 .se_snprintf = hist_entry__sym_to_snprintf, 735 .se_snprintf = hist_entry__sym_to_snprintf,
736 .se_filter = hist_entry__sym_to_filter,
574 .se_width_idx = HISTC_SYMBOL_TO, 737 .se_width_idx = HISTC_SYMBOL_TO,
575}; 738};
576 739
@@ -730,20 +893,10 @@ sort__locked_cmp(struct hist_entry *left, struct hist_entry *right)
730static int hist_entry__locked_snprintf(struct hist_entry *he, char *bf, 893static int hist_entry__locked_snprintf(struct hist_entry *he, char *bf,
731 size_t size, unsigned int width) 894 size_t size, unsigned int width)
732{ 895{
733 const char *out; 896 char out[10];
734 u64 mask = PERF_MEM_LOCK_NA;
735 897
736 if (he->mem_info) 898 perf_mem__lck_scnprintf(out, sizeof(out), he->mem_info);
737 mask = he->mem_info->data_src.mem_lock; 899 return repsep_snprintf(bf, size, "%.*s", width, out);
738
739 if (mask & PERF_MEM_LOCK_NA)
740 out = "N/A";
741 else if (mask & PERF_MEM_LOCK_LOCKED)
742 out = "Yes";
743 else
744 out = "No";
745
746 return repsep_snprintf(bf, size, "%-*s", width, out);
747} 900}
748 901
749static int64_t 902static int64_t
@@ -765,54 +918,12 @@ sort__tlb_cmp(struct hist_entry *left, struct hist_entry *right)
765 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);
766} 919}
767 920
768static const char * const tlb_access[] = {
769 "N/A",
770 "HIT",
771 "MISS",
772 "L1",
773 "L2",
774 "Walker",
775 "Fault",
776};
777#define NUM_TLB_ACCESS (sizeof(tlb_access)/sizeof(const char *))
778
779static int hist_entry__tlb_snprintf(struct hist_entry *he, char *bf, 921static int hist_entry__tlb_snprintf(struct hist_entry *he, char *bf,
780 size_t size, unsigned int width) 922 size_t size, unsigned int width)
781{ 923{
782 char out[64]; 924 char out[64];
783 size_t sz = sizeof(out) - 1; /* -1 for null termination */
784 size_t l = 0, i;
785 u64 m = PERF_MEM_TLB_NA;
786 u64 hit, miss;
787
788 out[0] = '\0';
789
790 if (he->mem_info)
791 m = he->mem_info->data_src.mem_dtlb;
792
793 hit = m & PERF_MEM_TLB_HIT;
794 miss = m & PERF_MEM_TLB_MISS;
795
796 /* already taken care of */
797 m &= ~(PERF_MEM_TLB_HIT|PERF_MEM_TLB_MISS);
798
799 for (i = 0; m && i < NUM_TLB_ACCESS; i++, m >>= 1) {
800 if (!(m & 0x1))
801 continue;
802 if (l) {
803 strcat(out, " or ");
804 l += 4;
805 }
806 strncat(out, tlb_access[i], sz - l);
807 l += strlen(tlb_access[i]);
808 }
809 if (*out == '\0')
810 strcpy(out, "N/A");
811 if (hit)
812 strncat(out, " hit", sz - l);
813 if (miss)
814 strncat(out, " miss", sz - l);
815 925
926 perf_mem__tlb_scnprintf(out, sizeof(out), he->mem_info);
816 return repsep_snprintf(bf, size, "%-*s", width, out); 927 return repsep_snprintf(bf, size, "%-*s", width, out);
817} 928}
818 929
@@ -835,61 +946,12 @@ sort__lvl_cmp(struct hist_entry *left, struct hist_entry *right)
835 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);
836} 947}
837 948
838static const char * const mem_lvl[] = {
839 "N/A",
840 "HIT",
841 "MISS",
842 "L1",
843 "LFB",
844 "L2",
845 "L3",
846 "Local RAM",
847 "Remote RAM (1 hop)",
848 "Remote RAM (2 hops)",
849 "Remote Cache (1 hop)",
850 "Remote Cache (2 hops)",
851 "I/O",
852 "Uncached",
853};
854#define NUM_MEM_LVL (sizeof(mem_lvl)/sizeof(const char *))
855
856static int hist_entry__lvl_snprintf(struct hist_entry *he, char *bf, 949static int hist_entry__lvl_snprintf(struct hist_entry *he, char *bf,
857 size_t size, unsigned int width) 950 size_t size, unsigned int width)
858{ 951{
859 char out[64]; 952 char out[64];
860 size_t sz = sizeof(out) - 1; /* -1 for null termination */
861 size_t i, l = 0;
862 u64 m = PERF_MEM_LVL_NA;
863 u64 hit, miss;
864
865 if (he->mem_info)
866 m = he->mem_info->data_src.mem_lvl;
867
868 out[0] = '\0';
869
870 hit = m & PERF_MEM_LVL_HIT;
871 miss = m & PERF_MEM_LVL_MISS;
872
873 /* already taken care of */
874 m &= ~(PERF_MEM_LVL_HIT|PERF_MEM_LVL_MISS);
875
876 for (i = 0; m && i < NUM_MEM_LVL; i++, m >>= 1) {
877 if (!(m & 0x1))
878 continue;
879 if (l) {
880 strcat(out, " or ");
881 l += 4;
882 }
883 strncat(out, mem_lvl[i], sz - l);
884 l += strlen(mem_lvl[i]);
885 }
886 if (*out == '\0')
887 strcpy(out, "N/A");
888 if (hit)
889 strncat(out, " hit", sz - l);
890 if (miss)
891 strncat(out, " miss", sz - l);
892 953
954 perf_mem__lvl_scnprintf(out, sizeof(out), he->mem_info);
893 return repsep_snprintf(bf, size, "%-*s", width, out); 955 return repsep_snprintf(bf, size, "%-*s", width, out);
894} 956}
895 957
@@ -912,51 +974,15 @@ sort__snoop_cmp(struct hist_entry *left, struct hist_entry *right)
912 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);
913} 975}
914 976
915static const char * const snoop_access[] = {
916 "N/A",
917 "None",
918 "Miss",
919 "Hit",
920 "HitM",
921};
922#define NUM_SNOOP_ACCESS (sizeof(snoop_access)/sizeof(const char *))
923
924static int hist_entry__snoop_snprintf(struct hist_entry *he, char *bf, 977static int hist_entry__snoop_snprintf(struct hist_entry *he, char *bf,
925 size_t size, unsigned int width) 978 size_t size, unsigned int width)
926{ 979{
927 char out[64]; 980 char out[64];
928 size_t sz = sizeof(out) - 1; /* -1 for null termination */
929 size_t i, l = 0;
930 u64 m = PERF_MEM_SNOOP_NA;
931
932 out[0] = '\0';
933
934 if (he->mem_info)
935 m = he->mem_info->data_src.mem_snoop;
936
937 for (i = 0; m && i < NUM_SNOOP_ACCESS; i++, m >>= 1) {
938 if (!(m & 0x1))
939 continue;
940 if (l) {
941 strcat(out, " or ");
942 l += 4;
943 }
944 strncat(out, snoop_access[i], sz - l);
945 l += strlen(snoop_access[i]);
946 }
947
948 if (*out == '\0')
949 strcpy(out, "N/A");
950 981
982 perf_mem__snp_scnprintf(out, sizeof(out), he->mem_info);
951 return repsep_snprintf(bf, size, "%-*s", width, out); 983 return repsep_snprintf(bf, size, "%-*s", width, out);
952} 984}
953 985
954static inline u64 cl_address(u64 address)
955{
956 /* return the cacheline of the address */
957 return (address & ~(cacheline_size - 1));
958}
959
960static int64_t 986static int64_t
961sort__dcacheline_cmp(struct hist_entry *left, struct hist_entry *right) 987sort__dcacheline_cmp(struct hist_entry *left, struct hist_entry *right)
962{ 988{
@@ -1312,6 +1338,7 @@ static struct sort_dimension common_sort_dimensions[] = {
1312 DIM(SORT_LOCAL_WEIGHT, "local_weight", sort_local_weight), 1338 DIM(SORT_LOCAL_WEIGHT, "local_weight", sort_local_weight),
1313 DIM(SORT_GLOBAL_WEIGHT, "weight", sort_global_weight), 1339 DIM(SORT_GLOBAL_WEIGHT, "weight", sort_global_weight),
1314 DIM(SORT_TRANSACTION, "transaction", sort_transaction), 1340 DIM(SORT_TRANSACTION, "transaction", sort_transaction),
1341 DIM(SORT_TRACE, "trace", sort_trace),
1315}; 1342};
1316 1343
1317#undef DIM 1344#undef DIM
@@ -1372,20 +1399,6 @@ struct hpp_sort_entry {
1372 struct sort_entry *se; 1399 struct sort_entry *se;
1373}; 1400};
1374 1401
1375bool perf_hpp__same_sort_entry(struct perf_hpp_fmt *a, struct perf_hpp_fmt *b)
1376{
1377 struct hpp_sort_entry *hse_a;
1378 struct hpp_sort_entry *hse_b;
1379
1380 if (!perf_hpp__is_sort_entry(a) || !perf_hpp__is_sort_entry(b))
1381 return false;
1382
1383 hse_a = container_of(a, struct hpp_sort_entry, hpp);
1384 hse_b = container_of(b, struct hpp_sort_entry, hpp);
1385
1386 return hse_a->se == hse_b->se;
1387}
1388
1389void 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)
1390{ 1403{
1391 struct hpp_sort_entry *hse; 1404 struct hpp_sort_entry *hse;
@@ -1471,8 +1484,56 @@ static int64_t __sort__hpp_sort(struct perf_hpp_fmt *fmt,
1471 return sort_fn(a, b); 1484 return sort_fn(a, b);
1472} 1485}
1473 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
1474static struct hpp_sort_entry * 1535static struct hpp_sort_entry *
1475__sort_dimension__alloc_hpp(struct sort_dimension *sd) 1536__sort_dimension__alloc_hpp(struct sort_dimension *sd, int level)
1476{ 1537{
1477 struct hpp_sort_entry *hse; 1538 struct hpp_sort_entry *hse;
1478 1539
@@ -1492,49 +1553,613 @@ __sort_dimension__alloc_hpp(struct sort_dimension *sd)
1492 hse->hpp.cmp = __sort__hpp_cmp; 1553 hse->hpp.cmp = __sort__hpp_cmp;
1493 hse->hpp.collapse = __sort__hpp_collapse; 1554 hse->hpp.collapse = __sort__hpp_collapse;
1494 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;
1495 1558
1496 INIT_LIST_HEAD(&hse->hpp.list); 1559 INIT_LIST_HEAD(&hse->hpp.list);
1497 INIT_LIST_HEAD(&hse->hpp.sort_list); 1560 INIT_LIST_HEAD(&hse->hpp.sort_list);
1498 hse->hpp.elide = false; 1561 hse->hpp.elide = false;
1499 hse->hpp.len = 0; 1562 hse->hpp.len = 0;
1500 hse->hpp.user_len = 0; 1563 hse->hpp.user_len = 0;
1564 hse->hpp.level = level;
1501 1565
1502 return hse; 1566 return hse;
1503} 1567}
1504 1568
1505bool perf_hpp__is_sort_entry(struct perf_hpp_fmt *format) 1569static void hpp_free(struct perf_hpp_fmt *fmt)
1506{ 1570{
1507 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;
1508} 1618}
1509 1619
1510static 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)
1511{ 1623{
1512 struct hpp_sort_entry *hse = __sort_dimension__alloc_hpp(sd); 1624 struct hpp_sort_entry *hse = __sort_dimension__alloc_hpp(sd, level);
1513 1625
1514 if (hse == NULL) 1626 if (hse == NULL)
1515 return -1; 1627 return -1;
1516 1628
1517 perf_hpp__register_sort_field(&hse->hpp); 1629 perf_hpp_list__register_sort_field(list, &hse->hpp);
1518 return 0; 1630 return 0;
1519} 1631}
1520 1632
1521static 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)
1522{ 1635{
1523 struct hpp_sort_entry *hse = __sort_dimension__alloc_hpp(sd); 1636 struct hpp_sort_entry *hse = __sort_dimension__alloc_hpp(sd, 0);
1524 1637
1525 if (hse == NULL) 1638 if (hse == NULL)
1526 return -1; 1639 return -1;
1527 1640
1528 perf_hpp__column_register(&hse->hpp); 1641 perf_hpp_list__column_register(list, &hse->hpp);
1529 return 0; 1642 return 0;
1530} 1643}
1531 1644
1532static int __sort_dimension__add(struct sort_dimension *sd) 1645struct hpp_dynamic_entry {
1646 struct perf_hpp_fmt hpp;
1647 struct perf_evsel *evsel;
1648 struct format_field *field;
1649 unsigned dynamic_len;
1650 bool raw_trace;
1651};
1652
1653static int hde_width(struct hpp_dynamic_entry *hde)
1654{
1655 if (!hde->hpp.len) {
1656 int len = hde->dynamic_len;
1657 int namelen = strlen(hde->field->name);
1658 int fieldlen = hde->field->size;
1659
1660 if (namelen > len)
1661 len = namelen;
1662
1663 if (!(hde->field->flags & FIELD_IS_STRING)) {
1664 /* length for print hex numbers */
1665 fieldlen = hde->field->size * 2 + 2;
1666 }
1667 if (fieldlen > len)
1668 len = fieldlen;
1669
1670 hde->hpp.len = len;
1671 }
1672 return hde->hpp.len;
1673}
1674
1675static void update_dynamic_len(struct hpp_dynamic_entry *hde,
1676 struct hist_entry *he)
1677{
1678 char *str, *pos;
1679 struct format_field *field = hde->field;
1680 size_t namelen;
1681 bool last = false;
1682
1683 if (hde->raw_trace)
1684 return;
1685
1686 /* parse pretty print result and update max length */
1687 if (!he->trace_output)
1688 he->trace_output = get_trace_output(he);
1689
1690 namelen = strlen(field->name);
1691 str = he->trace_output;
1692
1693 while (str) {
1694 pos = strchr(str, ' ');
1695 if (pos == NULL) {
1696 last = true;
1697 pos = str + strlen(str);
1698 }
1699
1700 if (!strncmp(str, field->name, namelen)) {
1701 size_t len;
1702
1703 str += namelen + 1;
1704 len = pos - str;
1705
1706 if (len > hde->dynamic_len)
1707 hde->dynamic_len = len;
1708 break;
1709 }
1710
1711 if (last)
1712 str = NULL;
1713 else
1714 str = pos + 1;
1715 }
1716}
1717
1718static int __sort__hde_header(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
1719 struct perf_evsel *evsel __maybe_unused)
1720{
1721 struct hpp_dynamic_entry *hde;
1722 size_t len = fmt->user_len;
1723
1724 hde = container_of(fmt, struct hpp_dynamic_entry, hpp);
1725
1726 if (!len)
1727 len = hde_width(hde);
1728
1729 return scnprintf(hpp->buf, hpp->size, "%*.*s", len, len, hde->field->name);
1730}
1731
1732static int __sort__hde_width(struct perf_hpp_fmt *fmt,
1733 struct perf_hpp *hpp __maybe_unused,
1734 struct perf_evsel *evsel __maybe_unused)
1735{
1736 struct hpp_dynamic_entry *hde;
1737 size_t len = fmt->user_len;
1738
1739 hde = container_of(fmt, struct hpp_dynamic_entry, hpp);
1740
1741 if (!len)
1742 len = hde_width(hde);
1743
1744 return len;
1745}
1746
1747bool perf_hpp__defined_dynamic_entry(struct perf_hpp_fmt *fmt, struct hists *hists)
1748{
1749 struct hpp_dynamic_entry *hde;
1750
1751 hde = container_of(fmt, struct hpp_dynamic_entry, hpp);
1752
1753 return hists_to_evsel(hists) == hde->evsel;
1754}
1755
1756static int __sort__hde_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
1757 struct hist_entry *he)
1758{
1759 struct hpp_dynamic_entry *hde;
1760 size_t len = fmt->user_len;
1761 char *str, *pos;
1762 struct format_field *field;
1763 size_t namelen;
1764 bool last = false;
1765 int ret;
1766
1767 hde = container_of(fmt, struct hpp_dynamic_entry, hpp);
1768
1769 if (!len)
1770 len = hde_width(hde);
1771
1772 if (hde->raw_trace)
1773 goto raw_field;
1774
1775 if (!he->trace_output)
1776 he->trace_output = get_trace_output(he);
1777
1778 field = hde->field;
1779 namelen = strlen(field->name);
1780 str = he->trace_output;
1781
1782 while (str) {
1783 pos = strchr(str, ' ');
1784 if (pos == NULL) {
1785 last = true;
1786 pos = str + strlen(str);
1787 }
1788
1789 if (!strncmp(str, field->name, namelen)) {
1790 str += namelen + 1;
1791 str = strndup(str, pos - str);
1792
1793 if (str == NULL)
1794 return scnprintf(hpp->buf, hpp->size,
1795 "%*.*s", len, len, "ERROR");
1796 break;
1797 }
1798
1799 if (last)
1800 str = NULL;
1801 else
1802 str = pos + 1;
1803 }
1804
1805 if (str == NULL) {
1806 struct trace_seq seq;
1807raw_field:
1808 trace_seq_init(&seq);
1809 pevent_print_field(&seq, he->raw_data, hde->field);
1810 str = seq.buffer;
1811 }
1812
1813 ret = scnprintf(hpp->buf, hpp->size, "%*.*s", len, len, str);
1814 free(str);
1815 return ret;
1816}
1817
1818static int64_t __sort__hde_cmp(struct perf_hpp_fmt *fmt,
1819 struct hist_entry *a, struct hist_entry *b)
1820{
1821 struct hpp_dynamic_entry *hde;
1822 struct format_field *field;
1823 unsigned offset, size;
1824
1825 hde = container_of(fmt, struct hpp_dynamic_entry, hpp);
1826
1827 if (b == NULL) {
1828 update_dynamic_len(hde, a);
1829 return 0;
1830 }
1831
1832 field = hde->field;
1833 if (field->flags & FIELD_IS_DYNAMIC) {
1834 unsigned long long dyn;
1835
1836 pevent_read_number_field(field, a->raw_data, &dyn);
1837 offset = dyn & 0xffff;
1838 size = (dyn >> 16) & 0xffff;
1839
1840 /* record max width for output */
1841 if (size > hde->dynamic_len)
1842 hde->dynamic_len = size;
1843 } else {
1844 offset = field->offset;
1845 size = field->size;
1846 }
1847
1848 return memcmp(a->raw_data + offset, b->raw_data + offset, size);
1849}
1850
1851bool perf_hpp__is_dynamic_entry(struct perf_hpp_fmt *fmt)
1852{
1853 return fmt->cmp == __sort__hde_cmp;
1854}
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
1878static struct hpp_dynamic_entry *
1879__alloc_dynamic_entry(struct perf_evsel *evsel, struct format_field *field,
1880 int level)
1881{
1882 struct hpp_dynamic_entry *hde;
1883
1884 hde = malloc(sizeof(*hde));
1885 if (hde == NULL) {
1886 pr_debug("Memory allocation failed\n");
1887 return NULL;
1888 }
1889
1890 hde->evsel = evsel;
1891 hde->field = field;
1892 hde->dynamic_len = 0;
1893
1894 hde->hpp.name = field->name;
1895 hde->hpp.header = __sort__hde_header;
1896 hde->hpp.width = __sort__hde_width;
1897 hde->hpp.entry = __sort__hde_entry;
1898 hde->hpp.color = NULL;
1899
1900 hde->hpp.cmp = __sort__hde_cmp;
1901 hde->hpp.collapse = __sort__hde_cmp;
1902 hde->hpp.sort = __sort__hde_cmp;
1903 hde->hpp.equal = __sort__hde_equal;
1904 hde->hpp.free = hde_free;
1905
1906 INIT_LIST_HEAD(&hde->hpp.list);
1907 INIT_LIST_HEAD(&hde->hpp.sort_list);
1908 hde->hpp.elide = false;
1909 hde->hpp.len = 0;
1910 hde->hpp.user_len = 0;
1911 hde->hpp.level = level;
1912
1913 return hde;
1914}
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
1944static int parse_field_name(char *str, char **event, char **field, char **opt)
1945{
1946 char *event_name, *field_name, *opt_name;
1947
1948 event_name = str;
1949 field_name = strchr(str, '.');
1950
1951 if (field_name) {
1952 *field_name++ = '\0';
1953 } else {
1954 event_name = NULL;
1955 field_name = str;
1956 }
1957
1958 opt_name = strchr(field_name, '/');
1959 if (opt_name)
1960 *opt_name++ = '\0';
1961
1962 *event = event_name;
1963 *field = field_name;
1964 *opt = opt_name;
1965
1966 return 0;
1967}
1968
1969/* find match evsel using a given event name. The event name can be:
1970 * 1. '%' + event index (e.g. '%1' for first event)
1971 * 2. full event name (e.g. sched:sched_switch)
1972 * 3. partial event name (should not contain ':')
1973 */
1974static struct perf_evsel *find_evsel(struct perf_evlist *evlist, char *event_name)
1975{
1976 struct perf_evsel *evsel = NULL;
1977 struct perf_evsel *pos;
1978 bool full_name;
1979
1980 /* case 1 */
1981 if (event_name[0] == '%') {
1982 int nr = strtol(event_name+1, NULL, 0);
1983
1984 if (nr > evlist->nr_entries)
1985 return NULL;
1986
1987 evsel = perf_evlist__first(evlist);
1988 while (--nr > 0)
1989 evsel = perf_evsel__next(evsel);
1990
1991 return evsel;
1992 }
1993
1994 full_name = !!strchr(event_name, ':');
1995 evlist__for_each(evlist, pos) {
1996 /* case 2 */
1997 if (full_name && !strcmp(pos->name, event_name))
1998 return pos;
1999 /* case 3 */
2000 if (!full_name && strstr(pos->name, event_name)) {
2001 if (evsel) {
2002 pr_debug("'%s' event is ambiguous: it can be %s or %s\n",
2003 event_name, evsel->name, pos->name);
2004 return NULL;
2005 }
2006 evsel = pos;
2007 }
2008 }
2009
2010 return evsel;
2011}
2012
2013static int __dynamic_dimension__add(struct perf_evsel *evsel,
2014 struct format_field *field,
2015 bool raw_trace, int level)
2016{
2017 struct hpp_dynamic_entry *hde;
2018
2019 hde = __alloc_dynamic_entry(evsel, field, level);
2020 if (hde == NULL)
2021 return -ENOMEM;
2022
2023 hde->raw_trace = raw_trace;
2024
2025 perf_hpp__register_sort_field(&hde->hpp);
2026 return 0;
2027}
2028
2029static int add_evsel_fields(struct perf_evsel *evsel, bool raw_trace, int level)
2030{
2031 int ret;
2032 struct format_field *field;
2033
2034 field = evsel->tp_format->format.fields;
2035 while (field) {
2036 ret = __dynamic_dimension__add(evsel, field, raw_trace, level);
2037 if (ret < 0)
2038 return ret;
2039
2040 field = field->next;
2041 }
2042 return 0;
2043}
2044
2045static int add_all_dynamic_fields(struct perf_evlist *evlist, bool raw_trace,
2046 int level)
2047{
2048 int ret;
2049 struct perf_evsel *evsel;
2050
2051 evlist__for_each(evlist, evsel) {
2052 if (evsel->attr.type != PERF_TYPE_TRACEPOINT)
2053 continue;
2054
2055 ret = add_evsel_fields(evsel, raw_trace, level);
2056 if (ret < 0)
2057 return ret;
2058 }
2059 return 0;
2060}
2061
2062static int add_all_matching_fields(struct perf_evlist *evlist,
2063 char *field_name, bool raw_trace, int level)
2064{
2065 int ret = -ESRCH;
2066 struct perf_evsel *evsel;
2067 struct format_field *field;
2068
2069 evlist__for_each(evlist, evsel) {
2070 if (evsel->attr.type != PERF_TYPE_TRACEPOINT)
2071 continue;
2072
2073 field = pevent_find_any_field(evsel->tp_format, field_name);
2074 if (field == NULL)
2075 continue;
2076
2077 ret = __dynamic_dimension__add(evsel, field, raw_trace, level);
2078 if (ret < 0)
2079 break;
2080 }
2081 return ret;
2082}
2083
2084static int add_dynamic_entry(struct perf_evlist *evlist, const char *tok,
2085 int level)
2086{
2087 char *str, *event_name, *field_name, *opt_name;
2088 struct perf_evsel *evsel;
2089 struct format_field *field;
2090 bool raw_trace = symbol_conf.raw_trace;
2091 int ret = 0;
2092
2093 if (evlist == NULL)
2094 return -ENOENT;
2095
2096 str = strdup(tok);
2097 if (str == NULL)
2098 return -ENOMEM;
2099
2100 if (parse_field_name(str, &event_name, &field_name, &opt_name) < 0) {
2101 ret = -EINVAL;
2102 goto out;
2103 }
2104
2105 if (opt_name) {
2106 if (strcmp(opt_name, "raw")) {
2107 pr_debug("unsupported field option %s\n", opt_name);
2108 ret = -EINVAL;
2109 goto out;
2110 }
2111 raw_trace = true;
2112 }
2113
2114 if (!strcmp(field_name, "trace_fields")) {
2115 ret = add_all_dynamic_fields(evlist, raw_trace, level);
2116 goto out;
2117 }
2118
2119 if (event_name == NULL) {
2120 ret = add_all_matching_fields(evlist, field_name, raw_trace, level);
2121 goto out;
2122 }
2123
2124 evsel = find_evsel(evlist, event_name);
2125 if (evsel == NULL) {
2126 pr_debug("Cannot find event: %s\n", event_name);
2127 ret = -ENOENT;
2128 goto out;
2129 }
2130
2131 if (evsel->attr.type != PERF_TYPE_TRACEPOINT) {
2132 pr_debug("%s is not a tracepoint event\n", event_name);
2133 ret = -EINVAL;
2134 goto out;
2135 }
2136
2137 if (!strcmp(field_name, "*")) {
2138 ret = add_evsel_fields(evsel, raw_trace, level);
2139 } else {
2140 field = pevent_find_any_field(evsel->tp_format, field_name);
2141 if (field == NULL) {
2142 pr_debug("Cannot find event field for %s.%s\n",
2143 event_name, field_name);
2144 return -ENOENT;
2145 }
2146
2147 ret = __dynamic_dimension__add(evsel, field, raw_trace, level);
2148 }
2149
2150out:
2151 free(str);
2152 return ret;
2153}
2154
2155static int __sort_dimension__add(struct sort_dimension *sd,
2156 struct perf_hpp_list *list,
2157 int level)
1533{ 2158{
1534 if (sd->taken) 2159 if (sd->taken)
1535 return 0; 2160 return 0;
1536 2161
1537 if (__sort_dimension__add_hpp_sort(sd) < 0) 2162 if (__sort_dimension__add_hpp_sort(sd, list, level) < 0)
1538 return -1; 2163 return -1;
1539 2164
1540 if (sd->entry->se_collapse) 2165 if (sd->entry->se_collapse)
@@ -1545,45 +2170,63 @@ static int __sort_dimension__add(struct sort_dimension *sd)
1545 return 0; 2170 return 0;
1546} 2171}
1547 2172
1548static 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)
1549{ 2176{
1550 if (!hd->taken) { 2177 struct perf_hpp_fmt *fmt;
1551 hd->taken = 1;
1552 2178
1553 perf_hpp__register_sort_field(hd->fmt); 2179 if (hd->taken)
1554 } 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);
1555 return 0; 2188 return 0;
1556} 2189}
1557 2190
1558static 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)
1559{ 2193{
1560 if (sd->taken) 2194 if (sd->taken)
1561 return 0; 2195 return 0;
1562 2196
1563 if (__sort_dimension__add_hpp_output(sd) < 0) 2197 if (__sort_dimension__add_hpp_output(sd, list) < 0)
1564 return -1; 2198 return -1;
1565 2199
1566 sd->taken = 1; 2200 sd->taken = 1;
1567 return 0; 2201 return 0;
1568} 2202}
1569 2203
1570static 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)
1571{ 2206{
1572 if (!hd->taken) { 2207 struct perf_hpp_fmt *fmt;
1573 hd->taken = 1;
1574 2208
1575 perf_hpp__column_register(hd->fmt); 2209 if (hd->taken)
1576 } 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);
1577 return 0; 2218 return 0;
1578} 2219}
1579 2220
1580int hpp_dimension__add_output(unsigned col) 2221int hpp_dimension__add_output(unsigned col)
1581{ 2222{
1582 BUG_ON(col >= PERF_HPP__MAX_INDEX); 2223 BUG_ON(col >= PERF_HPP__MAX_INDEX);
1583 return __hpp_dimension__add_output(&hpp_sort_dimensions[col]); 2224 return __hpp_dimension__add_output(&perf_hpp_list, &hpp_sort_dimensions[col]);
1584} 2225}
1585 2226
1586int sort_dimension__add(const char *tok) 2227static int sort_dimension__add(struct perf_hpp_list *list, const char *tok,
2228 struct perf_evlist *evlist,
2229 int level)
1587{ 2230{
1588 unsigned int i; 2231 unsigned int i;
1589 2232
@@ -1618,9 +2261,13 @@ int sort_dimension__add(const char *tok)
1618 sort__has_dso = 1; 2261 sort__has_dso = 1;
1619 } else if (sd->entry == &sort_socket) { 2262 } else if (sd->entry == &sort_socket) {
1620 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;
1621 } 2268 }
1622 2269
1623 return __sort_dimension__add(sd); 2270 return __sort_dimension__add(sd, list, level);
1624 } 2271 }
1625 2272
1626 for (i = 0; i < ARRAY_SIZE(hpp_sort_dimensions); i++) { 2273 for (i = 0; i < ARRAY_SIZE(hpp_sort_dimensions); i++) {
@@ -1629,7 +2276,7 @@ int sort_dimension__add(const char *tok)
1629 if (strncasecmp(tok, hd->name, strlen(tok))) 2276 if (strncasecmp(tok, hd->name, strlen(tok)))
1630 continue; 2277 continue;
1631 2278
1632 return __hpp_dimension__add(hd); 2279 return __hpp_dimension__add(hd, list, level);
1633 } 2280 }
1634 2281
1635 for (i = 0; i < ARRAY_SIZE(bstack_sort_dimensions); i++) { 2282 for (i = 0; i < ARRAY_SIZE(bstack_sort_dimensions); i++) {
@@ -1644,7 +2291,7 @@ int sort_dimension__add(const char *tok)
1644 if (sd->entry == &sort_sym_from || sd->entry == &sort_sym_to) 2291 if (sd->entry == &sort_sym_from || sd->entry == &sort_sym_to)
1645 sort__has_sym = 1; 2292 sort__has_sym = 1;
1646 2293
1647 __sort_dimension__add(sd); 2294 __sort_dimension__add(sd, list, level);
1648 return 0; 2295 return 0;
1649 } 2296 }
1650 2297
@@ -1660,14 +2307,61 @@ int sort_dimension__add(const char *tok)
1660 if (sd->entry == &sort_mem_daddr_sym) 2307 if (sd->entry == &sort_mem_daddr_sym)
1661 sort__has_sym = 1; 2308 sort__has_sym = 1;
1662 2309
1663 __sort_dimension__add(sd); 2310 __sort_dimension__add(sd, list, level);
1664 return 0; 2311 return 0;
1665 } 2312 }
1666 2313
2314 if (!add_dynamic_entry(evlist, tok, level))
2315 return 0;
2316
1667 return -ESRCH; 2317 return -ESRCH;
1668} 2318}
1669 2319
1670static const char *get_default_sort_order(void) 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
2364static const char *get_default_sort_order(struct perf_evlist *evlist)
1671{ 2365{
1672 const char *default_sort_orders[] = { 2366 const char *default_sort_orders[] = {
1673 default_sort_order, 2367 default_sort_order,
@@ -1675,14 +2369,33 @@ static const char *get_default_sort_order(void)
1675 default_mem_sort_order, 2369 default_mem_sort_order,
1676 default_top_sort_order, 2370 default_top_sort_order,
1677 default_diff_sort_order, 2371 default_diff_sort_order,
2372 default_tracepoint_sort_order,
1678 }; 2373 };
2374 bool use_trace = true;
2375 struct perf_evsel *evsel;
1679 2376
1680 BUG_ON(sort__mode >= ARRAY_SIZE(default_sort_orders)); 2377 BUG_ON(sort__mode >= ARRAY_SIZE(default_sort_orders));
1681 2378
2379 if (evlist == NULL)
2380 goto out_no_evlist;
2381
2382 evlist__for_each(evlist, evsel) {
2383 if (evsel->attr.type != PERF_TYPE_TRACEPOINT) {
2384 use_trace = false;
2385 break;
2386 }
2387 }
2388
2389 if (use_trace) {
2390 sort__mode = SORT_MODE__TRACEPOINT;
2391 if (symbol_conf.raw_trace)
2392 return "trace_fields";
2393 }
2394out_no_evlist:
1682 return default_sort_orders[sort__mode]; 2395 return default_sort_orders[sort__mode];
1683} 2396}
1684 2397
1685static int setup_sort_order(void) 2398static int setup_sort_order(struct perf_evlist *evlist)
1686{ 2399{
1687 char *new_sort_order; 2400 char *new_sort_order;
1688 2401
@@ -1703,7 +2416,7 @@ static int setup_sort_order(void)
1703 * because it's checked over the rest of the code. 2416 * because it's checked over the rest of the code.
1704 */ 2417 */
1705 if (asprintf(&new_sort_order, "%s,%s", 2418 if (asprintf(&new_sort_order, "%s,%s",
1706 get_default_sort_order(), sort_order + 1) < 0) { 2419 get_default_sort_order(evlist), sort_order + 1) < 0) {
1707 error("Not enough memory to set up --sort"); 2420 error("Not enough memory to set up --sort");
1708 return -ENOMEM; 2421 return -ENOMEM;
1709 } 2422 }
@@ -1712,13 +2425,41 @@ static int setup_sort_order(void)
1712 return 0; 2425 return 0;
1713} 2426}
1714 2427
1715static int __setup_sorting(void) 2428/*
2429 * Adds 'pre,' prefix into 'str' is 'pre' is
2430 * not already part of 'str'.
2431 */
2432static char *prefix_if_not_in(const char *pre, char *str)
2433{
2434 char *n;
2435
2436 if (!str || strstr(str, pre))
2437 return str;
2438
2439 if (asprintf(&n, "%s,%s", pre, str) < 0)
2440 return NULL;
2441
2442 free(str);
2443 return n;
2444}
2445
2446static char *setup_overhead(char *keys)
2447{
2448 keys = prefix_if_not_in("overhead", keys);
2449
2450 if (symbol_conf.cumulate_callchain)
2451 keys = prefix_if_not_in("overhead_children", keys);
2452
2453 return keys;
2454}
2455
2456static int __setup_sorting(struct perf_evlist *evlist)
1716{ 2457{
1717 char *tmp, *tok, *str; 2458 char *str;
1718 const char *sort_keys; 2459 const char *sort_keys;
1719 int ret = 0; 2460 int ret = 0;
1720 2461
1721 ret = setup_sort_order(); 2462 ret = setup_sort_order(evlist);
1722 if (ret) 2463 if (ret)
1723 return ret; 2464 return ret;
1724 2465
@@ -1732,7 +2473,7 @@ static int __setup_sorting(void)
1732 return 0; 2473 return 0;
1733 } 2474 }
1734 2475
1735 sort_keys = get_default_sort_order(); 2476 sort_keys = get_default_sort_order(evlist);
1736 } 2477 }
1737 2478
1738 str = strdup(sort_keys); 2479 str = strdup(sort_keys);
@@ -1741,18 +2482,19 @@ static int __setup_sorting(void)
1741 return -ENOMEM; 2482 return -ENOMEM;
1742 } 2483 }
1743 2484
1744 for (tok = strtok_r(str, ", ", &tmp); 2485 /*
1745 tok; tok = strtok_r(NULL, ", ", &tmp)) { 2486 * Prepend overhead fields for backward compatibility.
1746 ret = sort_dimension__add(tok); 2487 */
1747 if (ret == -EINVAL) { 2488 if (!is_strict_order(field_order)) {
1748 error("Invalid --sort key: `%s'", tok); 2489 str = setup_overhead(str);
1749 break; 2490 if (str == NULL) {
1750 } else if (ret == -ESRCH) { 2491 error("Not enough memory to setup overhead keys");
1751 error("Unknown --sort key: `%s'", tok); 2492 return -ENOMEM;
1752 break;
1753 } 2493 }
1754 } 2494 }
1755 2495
2496 ret = setup_sort_list(&perf_hpp_list, str, evlist);
2497
1756 free(str); 2498 free(str);
1757 return ret; 2499 return ret;
1758} 2500}
@@ -1762,7 +2504,7 @@ void perf_hpp__set_elide(int idx, bool elide)
1762 struct perf_hpp_fmt *fmt; 2504 struct perf_hpp_fmt *fmt;
1763 struct hpp_sort_entry *hse; 2505 struct hpp_sort_entry *hse;
1764 2506
1765 perf_hpp__for_each_format(fmt) { 2507 perf_hpp_list__for_each_format(&perf_hpp_list, fmt) {
1766 if (!perf_hpp__is_sort_entry(fmt)) 2508 if (!perf_hpp__is_sort_entry(fmt))
1767 continue; 2509 continue;
1768 2510
@@ -1822,7 +2564,7 @@ void sort__setup_elide(FILE *output)
1822 struct perf_hpp_fmt *fmt; 2564 struct perf_hpp_fmt *fmt;
1823 struct hpp_sort_entry *hse; 2565 struct hpp_sort_entry *hse;
1824 2566
1825 perf_hpp__for_each_format(fmt) { 2567 perf_hpp_list__for_each_format(&perf_hpp_list, fmt) {
1826 if (!perf_hpp__is_sort_entry(fmt)) 2568 if (!perf_hpp__is_sort_entry(fmt))
1827 continue; 2569 continue;
1828 2570
@@ -1834,7 +2576,7 @@ void sort__setup_elide(FILE *output)
1834 * It makes no sense to elide all of sort entries. 2576 * It makes no sense to elide all of sort entries.
1835 * Just revert them to show up again. 2577 * Just revert them to show up again.
1836 */ 2578 */
1837 perf_hpp__for_each_format(fmt) { 2579 perf_hpp_list__for_each_format(&perf_hpp_list, fmt) {
1838 if (!perf_hpp__is_sort_entry(fmt)) 2580 if (!perf_hpp__is_sort_entry(fmt))
1839 continue; 2581 continue;
1840 2582
@@ -1842,7 +2584,7 @@ void sort__setup_elide(FILE *output)
1842 return; 2584 return;
1843 } 2585 }
1844 2586
1845 perf_hpp__for_each_format(fmt) { 2587 perf_hpp_list__for_each_format(&perf_hpp_list, fmt) {
1846 if (!perf_hpp__is_sort_entry(fmt)) 2588 if (!perf_hpp__is_sort_entry(fmt))
1847 continue; 2589 continue;
1848 2590
@@ -1850,7 +2592,7 @@ void sort__setup_elide(FILE *output)
1850 } 2592 }
1851} 2593}
1852 2594
1853static int output_field_add(char *tok) 2595static int output_field_add(struct perf_hpp_list *list, char *tok)
1854{ 2596{
1855 unsigned int i; 2597 unsigned int i;
1856 2598
@@ -1860,7 +2602,7 @@ static int output_field_add(char *tok)
1860 if (strncasecmp(tok, sd->name, strlen(tok))) 2602 if (strncasecmp(tok, sd->name, strlen(tok)))
1861 continue; 2603 continue;
1862 2604
1863 return __sort_dimension__add_output(sd); 2605 return __sort_dimension__add_output(list, sd);
1864 } 2606 }
1865 2607
1866 for (i = 0; i < ARRAY_SIZE(hpp_sort_dimensions); i++) { 2608 for (i = 0; i < ARRAY_SIZE(hpp_sort_dimensions); i++) {
@@ -1869,7 +2611,7 @@ static int output_field_add(char *tok)
1869 if (strncasecmp(tok, hd->name, strlen(tok))) 2611 if (strncasecmp(tok, hd->name, strlen(tok)))
1870 continue; 2612 continue;
1871 2613
1872 return __hpp_dimension__add_output(hd); 2614 return __hpp_dimension__add_output(list, hd);
1873 } 2615 }
1874 2616
1875 for (i = 0; i < ARRAY_SIZE(bstack_sort_dimensions); i++) { 2617 for (i = 0; i < ARRAY_SIZE(bstack_sort_dimensions); i++) {
@@ -1878,7 +2620,7 @@ static int output_field_add(char *tok)
1878 if (strncasecmp(tok, sd->name, strlen(tok))) 2620 if (strncasecmp(tok, sd->name, strlen(tok)))
1879 continue; 2621 continue;
1880 2622
1881 return __sort_dimension__add_output(sd); 2623 return __sort_dimension__add_output(list, sd);
1882 } 2624 }
1883 2625
1884 for (i = 0; i < ARRAY_SIZE(memory_sort_dimensions); i++) { 2626 for (i = 0; i < ARRAY_SIZE(memory_sort_dimensions); i++) {
@@ -1887,12 +2629,32 @@ static int output_field_add(char *tok)
1887 if (strncasecmp(tok, sd->name, strlen(tok))) 2629 if (strncasecmp(tok, sd->name, strlen(tok)))
1888 continue; 2630 continue;
1889 2631
1890 return __sort_dimension__add_output(sd); 2632 return __sort_dimension__add_output(list, sd);
1891 } 2633 }
1892 2634
1893 return -ESRCH; 2635 return -ESRCH;
1894} 2636}
1895 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
1896static void reset_dimensions(void) 2658static void reset_dimensions(void)
1897{ 2659{
1898 unsigned int i; 2660 unsigned int i;
@@ -1917,7 +2679,7 @@ bool is_strict_order(const char *order)
1917 2679
1918static int __setup_output_field(void) 2680static int __setup_output_field(void)
1919{ 2681{
1920 char *tmp, *tok, *str, *strp; 2682 char *str, *strp;
1921 int ret = -EINVAL; 2683 int ret = -EINVAL;
1922 2684
1923 if (field_order == NULL) 2685 if (field_order == NULL)
@@ -1937,33 +2699,23 @@ static int __setup_output_field(void)
1937 goto out; 2699 goto out;
1938 } 2700 }
1939 2701
1940 for (tok = strtok_r(strp, ", ", &tmp); 2702 ret = setup_output_list(&perf_hpp_list, strp);
1941 tok; tok = strtok_r(NULL, ", ", &tmp)) {
1942 ret = output_field_add(tok);
1943 if (ret == -EINVAL) {
1944 error("Invalid --fields key: `%s'", tok);
1945 break;
1946 } else if (ret == -ESRCH) {
1947 error("Unknown --fields key: `%s'", tok);
1948 break;
1949 }
1950 }
1951 2703
1952out: 2704out:
1953 free(str); 2705 free(str);
1954 return ret; 2706 return ret;
1955} 2707}
1956 2708
1957int setup_sorting(void) 2709int setup_sorting(struct perf_evlist *evlist)
1958{ 2710{
1959 int err; 2711 int err;
1960 2712
1961 err = __setup_sorting(); 2713 err = __setup_sorting(evlist);
1962 if (err < 0) 2714 if (err < 0)
1963 return err; 2715 return err;
1964 2716
1965 if (parent_pattern != default_parent_pattern) { 2717 if (parent_pattern != default_parent_pattern) {
1966 err = sort_dimension__add("parent"); 2718 err = sort_dimension__add(&perf_hpp_list, "parent", evlist, -1);
1967 if (err < 0) 2719 if (err < 0)
1968 return err; 2720 return err;
1969 } 2721 }
@@ -1981,9 +2733,13 @@ int setup_sorting(void)
1981 return err; 2733 return err;
1982 2734
1983 /* copy sort keys to output fields */ 2735 /* copy sort keys to output fields */
1984 perf_hpp__setup_output_field(); 2736 perf_hpp__setup_output_field(&perf_hpp_list);
1985 /* and then copy output fields to sort keys */ 2737 /* and then copy output fields to sort keys */
1986 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;
1987 2743
1988 return 0; 2744 return 0;
1989} 2745}
@@ -1999,5 +2755,5 @@ void reset_output_field(void)
1999 sort_order = NULL; 2755 sort_order = NULL;
2000 2756
2001 reset_dimensions(); 2757 reset_dimensions();
2002 perf_hpp__reset_output_field(); 2758 perf_hpp__reset_output_field(&perf_hpp_list);
2003} 2759}
diff --git a/tools/perf/util/sort.h b/tools/perf/util/sort.h
index 31228851e397..3f4e35998119 100644
--- a/tools/perf/util/sort.h
+++ b/tools/perf/util/sort.h
@@ -18,7 +18,7 @@
18#include "debug.h" 18#include "debug.h"
19#include "header.h" 19#include "header.h"
20 20
21#include "parse-options.h" 21#include <subcmd/parse-options.h>
22#include "parse-events.h" 22#include "parse-events.h"
23#include "hist.h" 23#include "hist.h"
24#include "thread.h" 24#include "thread.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,15 +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;
130 void *raw_data;
131 u32 raw_size;
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 };
125 struct callchain_root callchain[0]; /* must be last member */ 143 struct callchain_root callchain[0]; /* must be last member */
126}; 144};
127 145
@@ -157,6 +175,17 @@ static inline float hist_entry__get_percent_limit(struct hist_entry *he)
157 return period * 100.0 / total_period; 175 return period * 100.0 / total_period;
158} 176}
159 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}
160 189
161enum sort_mode { 190enum sort_mode {
162 SORT_MODE__NORMAL, 191 SORT_MODE__NORMAL,
@@ -164,6 +193,7 @@ enum sort_mode {
164 SORT_MODE__MEMORY, 193 SORT_MODE__MEMORY,
165 SORT_MODE__TOP, 194 SORT_MODE__TOP,
166 SORT_MODE__DIFF, 195 SORT_MODE__DIFF,
196 SORT_MODE__TRACEPOINT,
167}; 197};
168 198
169enum sort_type { 199enum sort_type {
@@ -180,6 +210,7 @@ enum sort_type {
180 SORT_LOCAL_WEIGHT, 210 SORT_LOCAL_WEIGHT,
181 SORT_GLOBAL_WEIGHT, 211 SORT_GLOBAL_WEIGHT,
182 SORT_TRANSACTION, 212 SORT_TRANSACTION,
213 SORT_TRACE,
183 214
184 /* branch stack specific sort keys */ 215 /* branch stack specific sort keys */
185 __SORT_BRANCH_STACK, 216 __SORT_BRANCH_STACK,
@@ -209,8 +240,6 @@ enum sort_type {
209 */ 240 */
210 241
211struct sort_entry { 242struct sort_entry {
212 struct list_head list;
213
214 const char *se_header; 243 const char *se_header;
215 244
216 int64_t (*se_cmp)(struct hist_entry *, struct hist_entry *); 245 int64_t (*se_cmp)(struct hist_entry *, struct hist_entry *);
@@ -218,16 +247,18 @@ struct sort_entry {
218 int64_t (*se_sort)(struct hist_entry *, struct hist_entry *); 247 int64_t (*se_sort)(struct hist_entry *, struct hist_entry *);
219 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,
220 unsigned int width); 249 unsigned int width);
250 int (*se_filter)(struct hist_entry *he, int type, const void *arg);
221 u8 se_width_idx; 251 u8 se_width_idx;
222}; 252};
223 253
224extern struct sort_entry sort_thread; 254extern struct sort_entry sort_thread;
225extern struct list_head hist_entry__sort_list; 255extern struct list_head hist_entry__sort_list;
226 256
227int setup_sorting(void); 257struct perf_evlist;
258struct pevent;
259int setup_sorting(struct perf_evlist *evlist);
228int setup_output_field(void); 260int setup_output_field(void);
229void reset_output_field(void); 261void reset_output_field(void);
230extern int sort_dimension__add(const char *);
231void sort__setup_elide(FILE *fp); 262void sort__setup_elide(FILE *fp);
232void perf_hpp__set_elide(int idx, bool elide); 263void perf_hpp__set_elide(int idx, bool elide);
233 264
diff --git a/tools/perf/util/stat-shadow.c b/tools/perf/util/stat-shadow.c
index 2a5d8d7698ae..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,114 +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);
447 } else if (perf_evsel__match(evsel, SOFTWARE, SW_TASK_CLOCK)) {
448 if ((ratio = avg_stats(&walltime_nsecs_stats)) != 0)
449 print_metric(ctxp, NULL, "%8.3f", "CPUs utilized",
450 avg / ratio);
451 else
452 print_metric(ctxp, NULL, NULL, "CPUs utilized", 0);
416 } else if (runtime_nsecs_stats[cpu].n != 0) { 453 } else if (runtime_nsecs_stats[cpu].n != 0) {
417 char unit = 'M'; 454 char unit = 'M';
455 char unit_buf[10];
418 456
419 total = avg_stats(&runtime_nsecs_stats[cpu]); 457 total = avg_stats(&runtime_nsecs_stats[cpu]);
420 458
@@ -424,9 +462,9 @@ void perf_stat__print_shadow_stats(FILE *out, struct perf_evsel *evsel,
424 ratio *= 1000; 462 ratio *= 1000;
425 unit = 'K'; 463 unit = 'K';
426 } 464 }
427 465 snprintf(unit_buf, sizeof(unit_buf), "%c/sec", unit);
428 fprintf(out, " # %8.3f %c/sec ", ratio, unit); 466 print_metric(ctxp, NULL, "%8.3f", unit_buf, ratio);
429 } else { 467 } else {
430 fprintf(out, " "); 468 print_metric(ctxp, NULL, NULL, NULL, 0);
431 } 469 }
432} 470}
diff --git a/tools/perf/util/stat.c b/tools/perf/util/stat.c
index 2d9d8306dbd3..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);
@@ -310,7 +310,16 @@ int perf_stat_process_counter(struct perf_stat_config *config,
310 int i, ret; 310 int i, ret;
311 311
312 aggr->val = aggr->ena = aggr->run = 0; 312 aggr->val = aggr->ena = aggr->run = 0;
313 init_stats(ps->res_stats); 313
314 /*
315 * We calculate counter's data every interval,
316 * and the display code shows ps->res_stats
317 * avg value. We need to zero the stats for
318 * interval mode, otherwise overall avg running
319 * averages will be shown for each interval.
320 */
321 if (config->interval)
322 init_stats(ps->res_stats);
314 323
315 if (counter->per_pkg) 324 if (counter->per_pkg)
316 zero_per_pkg(counter); 325 zero_per_pkg(counter);
@@ -341,3 +350,65 @@ int perf_stat_process_counter(struct perf_stat_config *config,
341 350
342 return 0; 351 return 0;
343} 352}
353
354int perf_event__process_stat_event(struct perf_tool *tool __maybe_unused,
355 union perf_event *event,
356 struct perf_session *session)
357{
358 struct perf_counts_values count;
359 struct stat_event *st = &event->stat;
360 struct perf_evsel *counter;
361
362 count.val = st->val;
363 count.ena = st->ena;
364 count.run = st->run;
365
366 counter = perf_evlist__id2evsel(session->evlist, st->id);
367 if (!counter) {
368 pr_err("Failed to resolve counter for stat event.\n");
369 return -EINVAL;
370 }
371
372 *perf_counts(counter->counts, st->cpu, st->thread) = count;
373 counter->supported = true;
374 return 0;
375}
376
377size_t perf_event__fprintf_stat(union perf_event *event, FILE *fp)
378{
379 struct stat_event *st = (struct stat_event *) event;
380 size_t ret;
381
382 ret = fprintf(fp, "\n... id %" PRIu64 ", cpu %d, thread %d\n",
383 st->id, st->cpu, st->thread);
384 ret += fprintf(fp, "... value %" PRIu64 ", enabled %" PRIu64 ", running %" PRIu64 "\n",
385 st->val, st->ena, st->run);
386
387 return ret;
388}
389
390size_t perf_event__fprintf_stat_round(union perf_event *event, FILE *fp)
391{
392 struct stat_round_event *rd = (struct stat_round_event *)event;
393 size_t ret;
394
395 ret = fprintf(fp, "\n... time %" PRIu64 ", type %s\n", rd->time,
396 rd->type == PERF_STAT_ROUND_TYPE__FINAL ? "FINAL" : "INTERVAL");
397
398 return ret;
399}
400
401size_t perf_event__fprintf_stat_config(union perf_event *event, FILE *fp)
402{
403 struct perf_stat_config sc;
404 size_t ret;
405
406 perf_event__read_stat_config(&sc, &event->stat_config);
407
408 ret = fprintf(fp, "\n");
409 ret += fprintf(fp, "... aggr_mode %d\n", sc.aggr_mode);
410 ret += fprintf(fp, "... scale %d\n", sc.scale);
411 ret += fprintf(fp, "... interval %u\n", sc.interval);
412
413 return ret;
414}
diff --git a/tools/perf/util/stat.h b/tools/perf/util/stat.h
index da1d11c4f8c1..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);
@@ -90,4 +92,14 @@ void perf_evlist__reset_stats(struct perf_evlist *evlist);
90 92
91int perf_stat_process_counter(struct perf_stat_config *config, 93int perf_stat_process_counter(struct perf_stat_config *config,
92 struct perf_evsel *counter); 94 struct perf_evsel *counter);
95struct perf_tool;
96union perf_event;
97struct perf_session;
98int perf_event__process_stat_event(struct perf_tool *tool,
99 union perf_event *event,
100 struct perf_session *session);
101
102size_t perf_event__fprintf_stat(union perf_event *event, FILE *fp);
103size_t perf_event__fprintf_stat_round(union perf_event *event, FILE *fp);
104size_t perf_event__fprintf_stat_config(union perf_event *event, FILE *fp);
93#endif 105#endif
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/string.c b/tools/perf/util/string.c
index fc8781de62db..7f7e072be746 100644
--- a/tools/perf/util/string.c
+++ b/tools/perf/util/string.c
@@ -342,22 +342,6 @@ char *rtrim(char *s)
342 return s; 342 return s;
343} 343}
344 344
345/**
346 * memdup - duplicate region of memory
347 * @src: memory region to duplicate
348 * @len: memory region length
349 */
350void *memdup(const void *src, size_t len)
351{
352 void *p;
353
354 p = malloc(len);
355 if (p)
356 memcpy(p, src, len);
357
358 return p;
359}
360
361char *asprintf_expr_inout_ints(const char *var, bool in, size_t nints, int *ints) 345char *asprintf_expr_inout_ints(const char *var, bool in, size_t nints, int *ints)
362{ 346{
363 /* 347 /*
diff --git a/tools/perf/util/strlist.c b/tools/perf/util/strlist.c
index bdf98f6f27bb..0d3dfcb919b4 100644
--- a/tools/perf/util/strlist.c
+++ b/tools/perf/util/strlist.c
@@ -126,6 +126,11 @@ static int strlist__parse_list_entry(struct strlist *slist, const char *s,
126 err = strlist__load(slist, subst); 126 err = strlist__load(slist, subst);
127 goto out; 127 goto out;
128 } 128 }
129
130 if (slist->file_only) {
131 err = -ENOENT;
132 goto out;
133 }
129 } 134 }
130 135
131 err = strlist__add(slist, s); 136 err = strlist__add(slist, s);
@@ -157,11 +162,13 @@ struct strlist *strlist__new(const char *list, const struct strlist_config *conf
157 162
158 if (slist != NULL) { 163 if (slist != NULL) {
159 bool dupstr = true; 164 bool dupstr = true;
165 bool file_only = false;
160 const char *dirname = NULL; 166 const char *dirname = NULL;
161 167
162 if (config) { 168 if (config) {
163 dupstr = !config->dont_dupstr; 169 dupstr = !config->dont_dupstr;
164 dirname = config->dirname; 170 dirname = config->dirname;
171 file_only = config->file_only;
165 } 172 }
166 173
167 rblist__init(&slist->rblist); 174 rblist__init(&slist->rblist);
@@ -170,6 +177,7 @@ struct strlist *strlist__new(const char *list, const struct strlist_config *conf
170 slist->rblist.node_delete = strlist__node_delete; 177 slist->rblist.node_delete = strlist__node_delete;
171 178
172 slist->dupstr = dupstr; 179 slist->dupstr = dupstr;
180 slist->file_only = file_only;
173 181
174 if (list && strlist__parse_list(slist, list, dirname) != 0) 182 if (list && strlist__parse_list(slist, list, dirname) != 0)
175 goto out_error; 183 goto out_error;
diff --git a/tools/perf/util/strlist.h b/tools/perf/util/strlist.h
index 297565aa7535..ca990029e243 100644
--- a/tools/perf/util/strlist.h
+++ b/tools/perf/util/strlist.h
@@ -13,11 +13,18 @@ struct str_node {
13 13
14struct strlist { 14struct strlist {
15 struct rblist rblist; 15 struct rblist rblist;
16 bool dupstr; 16 bool dupstr;
17 bool file_only;
17}; 18};
18 19
20/*
21 * @file_only: When dirname is present, only consider entries as filenames,
22 * that should not be added to the list if dirname/entry is not
23 * found
24 */
19struct strlist_config { 25struct strlist_config {
20 bool dont_dupstr; 26 bool dont_dupstr;
27 bool file_only;
21 const char *dirname; 28 const char *dirname;
22}; 29};
23 30
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 475d88d0a1c9..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 /*
@@ -1026,8 +1027,8 @@ int dso__load_sym(struct dso *dso, struct map *map,
1026 curr_dso->long_name_len = dso->long_name_len; 1027 curr_dso->long_name_len = dso->long_name_len;
1027 curr_map = map__new2(start, curr_dso, 1028 curr_map = map__new2(start, curr_dso,
1028 map->type); 1029 map->type);
1030 dso__put(curr_dso);
1029 if (curr_map == NULL) { 1031 if (curr_map == NULL) {
1030 dso__put(curr_dso);
1031 goto out_elf_end; 1032 goto out_elf_end;
1032 } 1033 }
1033 if (adjust_kernel_syms) { 1034 if (adjust_kernel_syms) {
@@ -1042,7 +1043,14 @@ int dso__load_sym(struct dso *dso, struct map *map,
1042 } 1043 }
1043 curr_dso->symtab_type = dso->symtab_type; 1044 curr_dso->symtab_type = dso->symtab_type;
1044 map_groups__insert(kmaps, curr_map); 1045 map_groups__insert(kmaps, curr_map);
1046 /*
1047 * Add it before we drop the referece to curr_map,
1048 * i.e. while we still are sure to have a reference
1049 * to this DSO via curr_map->dso.
1050 */
1045 dsos__add(&map->groups->machine->dsos, curr_dso); 1051 dsos__add(&map->groups->machine->dsos, curr_dso);
1052 /* kmaps already got it */
1053 map__put(curr_map);
1046 dso__set_loaded(curr_dso, map->type); 1054 dso__set_loaded(curr_dso, map->type);
1047 } else 1055 } else
1048 curr_dso = curr_map->dso; 1056 curr_dso = curr_map->dso;
@@ -1070,6 +1078,8 @@ new_symbol:
1070 demangle_flags = DMGL_PARAMS | DMGL_ANSI; 1078 demangle_flags = DMGL_PARAMS | DMGL_ANSI;
1071 1079
1072 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);
1073 if (demangled != NULL) 1083 if (demangled != NULL)
1074 elf_name = demangled; 1084 elf_name = demangled;
1075 } 1085 }
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
index b4cc7662677e..e7588dc91518 100644
--- a/tools/perf/util/symbol.c
+++ b/tools/perf/util/symbol.c
@@ -39,6 +39,7 @@ struct symbol_conf symbol_conf = {
39 .cumulate_callchain = true, 39 .cumulate_callchain = true,
40 .show_hist_headers = true, 40 .show_hist_headers = true,
41 .symfs = "", 41 .symfs = "",
42 .event_group = true,
42}; 43};
43 44
44static enum dso_binary_type binary_type_symtab[] = { 45static enum dso_binary_type binary_type_symtab[] = {
@@ -654,19 +655,24 @@ static int dso__split_kallsyms_for_kcore(struct dso *dso, struct map *map,
654 struct map_groups *kmaps = map__kmaps(map); 655 struct map_groups *kmaps = map__kmaps(map);
655 struct map *curr_map; 656 struct map *curr_map;
656 struct symbol *pos; 657 struct symbol *pos;
657 int count = 0, moved = 0; 658 int count = 0;
659 struct rb_root old_root = dso->symbols[map->type];
658 struct rb_root *root = &dso->symbols[map->type]; 660 struct rb_root *root = &dso->symbols[map->type];
659 struct rb_node *next = rb_first(root); 661 struct rb_node *next = rb_first(root);
660 662
661 if (!kmaps) 663 if (!kmaps)
662 return -1; 664 return -1;
663 665
666 *root = RB_ROOT;
667
664 while (next) { 668 while (next) {
665 char *module; 669 char *module;
666 670
667 pos = rb_entry(next, struct symbol, rb_node); 671 pos = rb_entry(next, struct symbol, rb_node);
668 next = rb_next(&pos->rb_node); 672 next = rb_next(&pos->rb_node);
669 673
674 rb_erase_init(&pos->rb_node, &old_root);
675
670 module = strchr(pos->name, '\t'); 676 module = strchr(pos->name, '\t');
671 if (module) 677 if (module)
672 *module = '\0'; 678 *module = '\0';
@@ -674,28 +680,21 @@ static int dso__split_kallsyms_for_kcore(struct dso *dso, struct map *map,
674 curr_map = map_groups__find(kmaps, map->type, pos->start); 680 curr_map = map_groups__find(kmaps, map->type, pos->start);
675 681
676 if (!curr_map || (filter && filter(curr_map, pos))) { 682 if (!curr_map || (filter && filter(curr_map, pos))) {
677 rb_erase_init(&pos->rb_node, root);
678 symbol__delete(pos); 683 symbol__delete(pos);
679 } else { 684 continue;
680 pos->start -= curr_map->start - curr_map->pgoff;
681 if (pos->end)
682 pos->end -= curr_map->start - curr_map->pgoff;
683 if (curr_map->dso != map->dso) {
684 rb_erase_init(&pos->rb_node, root);
685 symbols__insert(
686 &curr_map->dso->symbols[curr_map->type],
687 pos);
688 ++moved;
689 } else {
690 ++count;
691 }
692 } 685 }
686
687 pos->start -= curr_map->start - curr_map->pgoff;
688 if (pos->end)
689 pos->end -= curr_map->start - curr_map->pgoff;
690 symbols__insert(&curr_map->dso->symbols[curr_map->type], pos);
691 ++count;
693 } 692 }
694 693
695 /* Symbols have been adjusted */ 694 /* Symbols have been adjusted */
696 dso->adjust_symbols = 1; 695 dso->adjust_symbols = 1;
697 696
698 return count + moved; 697 return count;
699} 698}
700 699
701/* 700/*
@@ -1438,9 +1437,9 @@ int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter)
1438 if (lstat(dso->name, &st) < 0) 1437 if (lstat(dso->name, &st) < 0)
1439 goto out; 1438 goto out;
1440 1439
1441 if (st.st_uid && (st.st_uid != geteuid())) { 1440 if (!symbol_conf.force && st.st_uid && (st.st_uid != geteuid())) {
1442 pr_warning("File %s not owned by current user or root, " 1441 pr_warning("File %s not owned by current user or root, "
1443 "ignoring it.\n", dso->name); 1442 "ignoring it (use -f to override).\n", dso->name);
1444 goto out; 1443 goto out;
1445 } 1444 }
1446 1445
@@ -1467,7 +1466,8 @@ int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter)
1467 * Read the build id if possible. This is required for 1466 * Read the build id if possible. This is required for
1468 * DSO_BINARY_TYPE__BUILDID_DEBUGINFO to work 1467 * DSO_BINARY_TYPE__BUILDID_DEBUGINFO to work
1469 */ 1468 */
1470 if (filename__read_build_id(dso->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)
1471 dso__set_build_id(dso, build_id); 1471 dso__set_build_id(dso, build_id);
1472 1472
1473 /* 1473 /*
@@ -1488,6 +1488,9 @@ int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter)
1488 root_dir, name, PATH_MAX)) 1488 root_dir, name, PATH_MAX))
1489 continue; 1489 continue;
1490 1490
1491 if (!is_regular_file(name))
1492 continue;
1493
1491 /* Name is now the name of the next image to try */ 1494 /* Name is now the name of the next image to try */
1492 if (symsrc__init(ss, dso, name, symtab_type) < 0) 1495 if (symsrc__init(ss, dso, name, symtab_type) < 0)
1493 continue; 1496 continue;
@@ -1526,6 +1529,10 @@ int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter)
1526 if (!runtime_ss && syms_ss) 1529 if (!runtime_ss && syms_ss)
1527 runtime_ss = syms_ss; 1530 runtime_ss = syms_ss;
1528 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
1529 if (syms_ss) 1536 if (syms_ss)
1530 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);
1531 else 1538 else
@@ -1862,24 +1869,44 @@ static void vmlinux_path__exit(void)
1862 zfree(&vmlinux_path); 1869 zfree(&vmlinux_path);
1863} 1870}
1864 1871
1872static const char * const vmlinux_paths[] = {
1873 "vmlinux",
1874 "/boot/vmlinux"
1875};
1876
1877static const char * const vmlinux_paths_upd[] = {
1878 "/boot/vmlinux-%s",
1879 "/usr/lib/debug/boot/vmlinux-%s",
1880 "/lib/modules/%s/build/vmlinux",
1881 "/usr/lib/debug/lib/modules/%s/vmlinux",
1882 "/usr/lib/debug/boot/vmlinux-%s.debug"
1883};
1884
1885static int vmlinux_path__add(const char *new_entry)
1886{
1887 vmlinux_path[vmlinux_path__nr_entries] = strdup(new_entry);
1888 if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
1889 return -1;
1890 ++vmlinux_path__nr_entries;
1891
1892 return 0;
1893}
1894
1865static int vmlinux_path__init(struct perf_env *env) 1895static int vmlinux_path__init(struct perf_env *env)
1866{ 1896{
1867 struct utsname uts; 1897 struct utsname uts;
1868 char bf[PATH_MAX]; 1898 char bf[PATH_MAX];
1869 char *kernel_version; 1899 char *kernel_version;
1900 unsigned int i;
1870 1901
1871 vmlinux_path = malloc(sizeof(char *) * 6); 1902 vmlinux_path = malloc(sizeof(char *) * (ARRAY_SIZE(vmlinux_paths) +
1903 ARRAY_SIZE(vmlinux_paths_upd)));
1872 if (vmlinux_path == NULL) 1904 if (vmlinux_path == NULL)
1873 return -1; 1905 return -1;
1874 1906
1875 vmlinux_path[vmlinux_path__nr_entries] = strdup("vmlinux"); 1907 for (i = 0; i < ARRAY_SIZE(vmlinux_paths); i++)
1876 if (vmlinux_path[vmlinux_path__nr_entries] == NULL) 1908 if (vmlinux_path__add(vmlinux_paths[i]) < 0)
1877 goto out_fail; 1909 goto out_fail;
1878 ++vmlinux_path__nr_entries;
1879 vmlinux_path[vmlinux_path__nr_entries] = strdup("/boot/vmlinux");
1880 if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
1881 goto out_fail;
1882 ++vmlinux_path__nr_entries;
1883 1910
1884 /* only try kernel version if no symfs was given */ 1911 /* only try kernel version if no symfs was given */
1885 if (symbol_conf.symfs[0] != 0) 1912 if (symbol_conf.symfs[0] != 0)
@@ -1894,28 +1921,11 @@ static int vmlinux_path__init(struct perf_env *env)
1894 kernel_version = uts.release; 1921 kernel_version = uts.release;
1895 } 1922 }
1896 1923
1897 snprintf(bf, sizeof(bf), "/boot/vmlinux-%s", kernel_version); 1924 for (i = 0; i < ARRAY_SIZE(vmlinux_paths_upd); i++) {
1898 vmlinux_path[vmlinux_path__nr_entries] = strdup(bf); 1925 snprintf(bf, sizeof(bf), vmlinux_paths_upd[i], kernel_version);
1899 if (vmlinux_path[vmlinux_path__nr_entries] == NULL) 1926 if (vmlinux_path__add(bf) < 0)
1900 goto out_fail; 1927 goto out_fail;
1901 ++vmlinux_path__nr_entries; 1928 }
1902 snprintf(bf, sizeof(bf), "/usr/lib/debug/boot/vmlinux-%s",
1903 kernel_version);
1904 vmlinux_path[vmlinux_path__nr_entries] = strdup(bf);
1905 if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
1906 goto out_fail;
1907 ++vmlinux_path__nr_entries;
1908 snprintf(bf, sizeof(bf), "/lib/modules/%s/build/vmlinux", kernel_version);
1909 vmlinux_path[vmlinux_path__nr_entries] = strdup(bf);
1910 if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
1911 goto out_fail;
1912 ++vmlinux_path__nr_entries;
1913 snprintf(bf, sizeof(bf), "/usr/lib/debug/lib/modules/%s/vmlinux",
1914 kernel_version);
1915 vmlinux_path[vmlinux_path__nr_entries] = strdup(bf);
1916 if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
1917 goto out_fail;
1918 ++vmlinux_path__nr_entries;
1919 1929
1920 return 0; 1930 return 0;
1921 1931
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h
index 40073c60b83d..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
@@ -84,6 +84,7 @@ struct symbol_conf {
84 unsigned short priv_size; 84 unsigned short priv_size;
85 unsigned short nr_events; 85 unsigned short nr_events;
86 bool try_vmlinux_path, 86 bool try_vmlinux_path,
87 force,
87 ignore_vmlinux, 88 ignore_vmlinux,
88 ignore_vmlinux_buildid, 89 ignore_vmlinux_buildid,
89 show_kernel_path, 90 show_kernel_path,
@@ -107,7 +108,10 @@ struct symbol_conf {
107 show_hist_headers, 108 show_hist_headers,
108 branch_callstack, 109 branch_callstack,
109 has_filter, 110 has_filter,
110 show_ref_callgraph; 111 show_ref_callgraph,
112 hide_unresolved,
113 raw_trace,
114 report_hierarchy;
111 const char *vmlinux_name, 115 const char *vmlinux_name,
112 *kallsyms_name, 116 *kallsyms_name,
113 *source_prefix, 117 *source_prefix,
diff --git a/tools/perf/util/term.c b/tools/perf/util/term.c
new file mode 100644
index 000000000000..90b47d8aa19c
--- /dev/null
+++ b/tools/perf/util/term.c
@@ -0,0 +1,35 @@
1#include "util.h"
2
3void get_term_dimensions(struct winsize *ws)
4{
5 char *s = getenv("LINES");
6
7 if (s != NULL) {
8 ws->ws_row = atoi(s);
9 s = getenv("COLUMNS");
10 if (s != NULL) {
11 ws->ws_col = atoi(s);
12 if (ws->ws_row && ws->ws_col)
13 return;
14 }
15 }
16#ifdef TIOCGWINSZ
17 if (ioctl(1, TIOCGWINSZ, ws) == 0 &&
18 ws->ws_row && ws->ws_col)
19 return;
20#endif
21 ws->ws_row = 25;
22 ws->ws_col = 80;
23}
24
25void set_term_quiet_input(struct termios *old)
26{
27 struct termios tc;
28
29 tcgetattr(0, old);
30 tc = *old;
31 tc.c_lflag &= ~(ICANON | ECHO);
32 tc.c_cc[VMIN] = 0;
33 tc.c_cc[VTIME] = 0;
34 tcsetattr(0, TCSANOW, &tc);
35}
diff --git a/tools/perf/util/term.h b/tools/perf/util/term.h
new file mode 100644
index 000000000000..2c06a61846a1
--- /dev/null
+++ b/tools/perf/util/term.h
@@ -0,0 +1,10 @@
1#ifndef __PERF_TERM_H
2#define __PERF_TERM_H
3
4struct termios;
5struct winsize;
6
7void get_term_dimensions(struct winsize *ws);
8void set_term_quiet_input(struct termios *old);
9
10#endif /* __PERF_TERM_H */
diff --git a/tools/perf/util/thread.c b/tools/perf/util/thread.c
index 0a9ae8014729..dfd00c6dad6e 100644
--- a/tools/perf/util/thread.c
+++ b/tools/perf/util/thread.c
@@ -19,8 +19,10 @@ int thread__init_map_groups(struct thread *thread, struct machine *machine)
19 thread->mg = map_groups__new(machine); 19 thread->mg = map_groups__new(machine);
20 } else { 20 } else {
21 leader = __machine__findnew_thread(machine, pid, pid); 21 leader = __machine__findnew_thread(machine, pid, pid);
22 if (leader) 22 if (leader) {
23 thread->mg = map_groups__get(leader->mg); 23 thread->mg = map_groups__get(leader->mg);
24 thread__put(leader);
25 }
24 } 26 }
25 27
26 return thread->mg ? 0 : -1; 28 return thread->mg ? 0 : -1;
@@ -53,7 +55,7 @@ struct thread *thread__new(pid_t pid, pid_t tid)
53 goto err_thread; 55 goto err_thread;
54 56
55 list_add(&comm->list, &thread->comm_list); 57 list_add(&comm->list, &thread->comm_list);
56 atomic_set(&thread->refcnt, 0); 58 atomic_set(&thread->refcnt, 1);
57 RB_CLEAR_NODE(&thread->rb_node); 59 RB_CLEAR_NODE(&thread->rb_node);
58 } 60 }
59 61
@@ -95,6 +97,10 @@ struct thread *thread__get(struct thread *thread)
95void thread__put(struct thread *thread) 97void thread__put(struct thread *thread)
96{ 98{
97 if (thread && atomic_dec_and_test(&thread->refcnt)) { 99 if (thread && atomic_dec_and_test(&thread->refcnt)) {
100 /*
101 * Remove it from the dead_threads list, as last reference
102 * is gone.
103 */
98 list_del_init(&thread->node); 104 list_del_init(&thread->node);
99 thread__delete(thread); 105 thread__delete(thread);
100 } 106 }
diff --git a/tools/perf/util/thread_map.c b/tools/perf/util/thread_map.c
index 6ec3c5ca438f..08afc6909953 100644
--- a/tools/perf/util/thread_map.c
+++ b/tools/perf/util/thread_map.c
@@ -13,6 +13,7 @@
13#include "thread_map.h" 13#include "thread_map.h"
14#include "util.h" 14#include "util.h"
15#include "debug.h" 15#include "debug.h"
16#include "event.h"
16 17
17/* Skip "." and ".." directories */ 18/* Skip "." and ".." directories */
18static int filter(const struct dirent *dir) 19static int filter(const struct dirent *dir)
@@ -304,6 +305,7 @@ out:
304 305
305out_free_threads: 306out_free_threads:
306 zfree(&threads); 307 zfree(&threads);
308 strlist__delete(slist);
307 goto out; 309 goto out;
308} 310}
309 311
@@ -408,3 +410,29 @@ void thread_map__read_comms(struct thread_map *threads)
408 for (i = 0; i < threads->nr; ++i) 410 for (i = 0; i < threads->nr; ++i)
409 comm_init(threads, i); 411 comm_init(threads, i);
410} 412}
413
414static void thread_map__copy_event(struct thread_map *threads,
415 struct thread_map_event *event)
416{
417 unsigned i;
418
419 threads->nr = (int) event->nr;
420
421 for (i = 0; i < event->nr; i++) {
422 thread_map__set_pid(threads, i, (pid_t) event->entries[i].pid);
423 threads->map[i].comm = strndup(event->entries[i].comm, 16);
424 }
425
426 atomic_set(&threads->refcnt, 1);
427}
428
429struct thread_map *thread_map__new_event(struct thread_map_event *event)
430{
431 struct thread_map *threads;
432
433 threads = thread_map__alloc(event->nr);
434 if (threads)
435 thread_map__copy_event(threads, event);
436
437 return threads;
438}
diff --git a/tools/perf/util/thread_map.h b/tools/perf/util/thread_map.h
index af679d8a50f8..85e4c7c4fbde 100644
--- a/tools/perf/util/thread_map.h
+++ b/tools/perf/util/thread_map.h
@@ -16,11 +16,14 @@ struct thread_map {
16 struct thread_map_data map[]; 16 struct thread_map_data map[];
17}; 17};
18 18
19struct thread_map_event;
20
19struct thread_map *thread_map__new_dummy(void); 21struct thread_map *thread_map__new_dummy(void);
20struct thread_map *thread_map__new_by_pid(pid_t pid); 22struct thread_map *thread_map__new_by_pid(pid_t pid);
21struct thread_map *thread_map__new_by_tid(pid_t tid); 23struct thread_map *thread_map__new_by_tid(pid_t tid);
22struct thread_map *thread_map__new_by_uid(uid_t uid); 24struct thread_map *thread_map__new_by_uid(uid_t uid);
23struct thread_map *thread_map__new(pid_t pid, pid_t tid, uid_t uid); 25struct thread_map *thread_map__new(pid_t pid, pid_t tid, uid_t uid);
26struct thread_map *thread_map__new_event(struct thread_map_event *event);
24 27
25struct thread_map *thread_map__get(struct thread_map *map); 28struct thread_map *thread_map__get(struct thread_map *map);
26void thread_map__put(struct thread_map *map); 29void thread_map__put(struct thread_map *map);
diff --git a/tools/perf/util/tool.h b/tools/perf/util/tool.h
index cab8cc24831b..55de4cffcd4e 100644
--- a/tools/perf/util/tool.h
+++ b/tools/perf/util/tool.h
@@ -50,12 +50,18 @@ struct perf_tool {
50 throttle, 50 throttle,
51 unthrottle; 51 unthrottle;
52 event_attr_op attr; 52 event_attr_op attr;
53 event_attr_op event_update;
53 event_op2 tracing_data; 54 event_op2 tracing_data;
54 event_oe finished_round; 55 event_oe finished_round;
55 event_op2 build_id, 56 event_op2 build_id,
56 id_index, 57 id_index,
57 auxtrace_info, 58 auxtrace_info,
58 auxtrace_error; 59 auxtrace_error,
60 thread_map,
61 cpu_map,
62 stat_config,
63 stat,
64 stat_round;
59 event_op3 auxtrace; 65 event_op3 auxtrace;
60 bool ordered_events; 66 bool ordered_events;
61 bool ordering_requires_timestamps; 67 bool ordering_requires_timestamps;
diff --git a/tools/perf/util/trace-event-parse.c b/tools/perf/util/trace-event-parse.c
index 8ff7d620d942..33b52eaa39db 100644
--- a/tools/perf/util/trace-event-parse.c
+++ b/tools/perf/util/trace-event-parse.c
@@ -209,7 +209,7 @@ static const struct flag flags[] = {
209 { "NET_TX_SOFTIRQ", 2 }, 209 { "NET_TX_SOFTIRQ", 2 },
210 { "NET_RX_SOFTIRQ", 3 }, 210 { "NET_RX_SOFTIRQ", 3 },
211 { "BLOCK_SOFTIRQ", 4 }, 211 { "BLOCK_SOFTIRQ", 4 },
212 { "BLOCK_IOPOLL_SOFTIRQ", 5 }, 212 { "IRQ_POLL_SOFTIRQ", 5 },
213 { "TASKLET_SOFTIRQ", 6 }, 213 { "TASKLET_SOFTIRQ", 6 },
214 { "SCHED_SOFTIRQ", 7 }, 214 { "SCHED_SOFTIRQ", 7 },
215 { "HRTIMER_SOFTIRQ", 8 }, 215 { "HRTIMER_SOFTIRQ", 8 },
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/trace-event.h b/tools/perf/util/trace-event.h
index b85ee55cca0c..bce5b1dac268 100644
--- a/tools/perf/util/trace-event.h
+++ b/tools/perf/util/trace-event.h
@@ -65,6 +65,7 @@ int tracing_data_put(struct tracing_data *tdata);
65struct addr_location; 65struct addr_location;
66 66
67struct perf_session; 67struct perf_session;
68struct perf_stat_config;
68 69
69struct scripting_ops { 70struct scripting_ops {
70 const char *name; 71 const char *name;
@@ -75,6 +76,9 @@ struct scripting_ops {
75 struct perf_sample *sample, 76 struct perf_sample *sample,
76 struct perf_evsel *evsel, 77 struct perf_evsel *evsel,
77 struct addr_location *al); 78 struct addr_location *al);
79 void (*process_stat)(struct perf_stat_config *config,
80 struct perf_evsel *evsel, u64 tstamp);
81 void (*process_stat_interval)(u64 tstamp);
78 int (*generate_script) (struct pevent *pevent, const char *outfile); 82 int (*generate_script) (struct pevent *pevent, const char *outfile);
79}; 83};
80 84
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/unwind-libdw.c b/tools/perf/util/unwind-libdw.c
index 2dcfe9a7c8d0..cf5e250bc78e 100644
--- a/tools/perf/util/unwind-libdw.c
+++ b/tools/perf/util/unwind-libdw.c
@@ -11,6 +11,7 @@
11#include <linux/types.h> 11#include <linux/types.h>
12#include "event.h" 12#include "event.h"
13#include "perf_regs.h" 13#include "perf_regs.h"
14#include "callchain.h"
14 15
15static char *debuginfo_path; 16static char *debuginfo_path;
16 17
@@ -52,25 +53,28 @@ static int report_module(u64 ip, struct unwind_info *ui)
52 return __report_module(&al, ip, ui); 53 return __report_module(&al, ip, ui);
53} 54}
54 55
56/*
57 * Store all entries within entries array,
58 * we will process it after we finish unwind.
59 */
55static int entry(u64 ip, struct unwind_info *ui) 60static int entry(u64 ip, struct unwind_info *ui)
56 61
57{ 62{
58 struct unwind_entry e; 63 struct unwind_entry *e = &ui->entries[ui->idx++];
59 struct addr_location al; 64 struct addr_location al;
60 65
61 if (__report_module(&al, ip, ui)) 66 if (__report_module(&al, ip, ui))
62 return -1; 67 return -1;
63 68
64 e.ip = ip; 69 e->ip = ip;
65 e.map = al.map; 70 e->map = al.map;
66 e.sym = al.sym; 71 e->sym = al.sym;
67 72
68 pr_debug("unwind: %s:ip = 0x%" PRIx64 " (0x%" PRIx64 ")\n", 73 pr_debug("unwind: %s:ip = 0x%" PRIx64 " (0x%" PRIx64 ")\n",
69 al.sym ? al.sym->name : "''", 74 al.sym ? al.sym->name : "''",
70 ip, 75 ip,
71 al.map ? al.map->map_ip(al.map, ip) : (u64) 0); 76 al.map ? al.map->map_ip(al.map, ip) : (u64) 0);
72 77 return 0;
73 return ui->cb(&e, ui->arg);
74} 78}
75 79
76static pid_t next_thread(Dwfl *dwfl, void *arg, void **thread_argp) 80static pid_t next_thread(Dwfl *dwfl, void *arg, void **thread_argp)
@@ -92,6 +96,16 @@ static int access_dso_mem(struct unwind_info *ui, Dwarf_Addr addr,
92 thread__find_addr_map(ui->thread, PERF_RECORD_MISC_USER, 96 thread__find_addr_map(ui->thread, PERF_RECORD_MISC_USER,
93 MAP__FUNCTION, addr, &al); 97 MAP__FUNCTION, addr, &al);
94 if (!al.map) { 98 if (!al.map) {
99 /*
100 * We've seen cases (softice) where DWARF unwinder went
101 * through non executable mmaps, which we need to lookup
102 * in MAP__VARIABLE tree.
103 */
104 thread__find_addr_map(ui->thread, PERF_RECORD_MISC_USER,
105 MAP__VARIABLE, addr, &al);
106 }
107
108 if (!al.map) {
95 pr_debug("unwind: no map for %lx\n", (unsigned long)addr); 109 pr_debug("unwind: no map for %lx\n", (unsigned long)addr);
96 return -1; 110 return -1;
97 } 111 }
@@ -168,7 +182,7 @@ int unwind__get_entries(unwind_entry_cb_t cb, void *arg,
168 struct perf_sample *data, 182 struct perf_sample *data,
169 int max_stack) 183 int max_stack)
170{ 184{
171 struct unwind_info ui = { 185 struct unwind_info *ui, ui_buf = {
172 .sample = data, 186 .sample = data,
173 .thread = thread, 187 .thread = thread,
174 .machine = thread->mg->machine, 188 .machine = thread->mg->machine,
@@ -177,35 +191,54 @@ int unwind__get_entries(unwind_entry_cb_t cb, void *arg,
177 .max_stack = max_stack, 191 .max_stack = max_stack,
178 }; 192 };
179 Dwarf_Word ip; 193 Dwarf_Word ip;
180 int err = -EINVAL; 194 int err = -EINVAL, i;
181 195
182 if (!data->user_regs.regs) 196 if (!data->user_regs.regs)
183 return -EINVAL; 197 return -EINVAL;
184 198
185 ui.dwfl = dwfl_begin(&offline_callbacks); 199 ui = zalloc(sizeof(ui_buf) + sizeof(ui_buf.entries[0]) * max_stack);
186 if (!ui.dwfl) 200 if (!ui)
201 return -ENOMEM;
202
203 *ui = ui_buf;
204
205 ui->dwfl = dwfl_begin(&offline_callbacks);
206 if (!ui->dwfl)
187 goto out; 207 goto out;
188 208
189 err = perf_reg_value(&ip, &data->user_regs, PERF_REG_IP); 209 err = perf_reg_value(&ip, &data->user_regs, PERF_REG_IP);
190 if (err) 210 if (err)
191 goto out; 211 goto out;
192 212
193 err = report_module(ip, &ui); 213 err = report_module(ip, ui);
194 if (err) 214 if (err)
195 goto out; 215 goto out;
196 216
197 if (!dwfl_attach_state(ui.dwfl, EM_NONE, thread->tid, &callbacks, &ui)) 217 if (!dwfl_attach_state(ui->dwfl, EM_NONE, thread->tid, &callbacks, ui))
198 goto out; 218 goto out;
199 219
200 err = dwfl_getthread_frames(ui.dwfl, thread->tid, frame_callback, &ui); 220 err = dwfl_getthread_frames(ui->dwfl, thread->tid, frame_callback, ui);
201 221
202 if (err && !ui.max_stack) 222 if (err && !ui->max_stack)
203 err = 0; 223 err = 0;
204 224
225 /*
226 * Display what we got based on the order setup.
227 */
228 for (i = 0; i < ui->idx && !err; i++) {
229 int j = i;
230
231 if (callchain_param.order == ORDER_CALLER)
232 j = ui->idx - i - 1;
233
234 err = ui->entries[j].ip ? ui->cb(&ui->entries[j], ui->arg) : 0;
235 }
236
205 out: 237 out:
206 if (err) 238 if (err)
207 pr_debug("unwind: failed with '%s'\n", dwfl_errmsg(-1)); 239 pr_debug("unwind: failed with '%s'\n", dwfl_errmsg(-1));
208 240
209 dwfl_end(ui.dwfl); 241 dwfl_end(ui->dwfl);
242 free(ui);
210 return 0; 243 return 0;
211} 244}
diff --git a/tools/perf/util/unwind-libdw.h b/tools/perf/util/unwind-libdw.h
index 417a1426f3ad..58328669ed16 100644
--- a/tools/perf/util/unwind-libdw.h
+++ b/tools/perf/util/unwind-libdw.h
@@ -16,6 +16,8 @@ struct unwind_info {
16 unwind_entry_cb_t cb; 16 unwind_entry_cb_t cb;
17 void *arg; 17 void *arg;
18 int max_stack; 18 int max_stack;
19 int idx;
20 struct unwind_entry entries[];
19}; 21};
20 22
21#endif /* __PERF_UNWIND_LIBDW_H */ 23#endif /* __PERF_UNWIND_LIBDW_H */
diff --git a/tools/perf/util/unwind-libunwind.c b/tools/perf/util/unwind-libunwind.c
index c83832b555e5..ee7e372297e5 100644
--- a/tools/perf/util/unwind-libunwind.c
+++ b/tools/perf/util/unwind-libunwind.c
@@ -319,6 +319,15 @@ static struct map *find_map(unw_word_t ip, struct unwind_info *ui)
319 319
320 thread__find_addr_map(ui->thread, PERF_RECORD_MISC_USER, 320 thread__find_addr_map(ui->thread, PERF_RECORD_MISC_USER,
321 MAP__FUNCTION, ip, &al); 321 MAP__FUNCTION, ip, &al);
322 if (!al.map) {
323 /*
324 * We've seen cases (softice) where DWARF unwinder went
325 * through non executable mmaps, which we need to lookup
326 * in MAP__VARIABLE tree.
327 */
328 thread__find_addr_map(ui->thread, PERF_RECORD_MISC_USER,
329 MAP__VARIABLE, ip, &al);
330 }
322 return al.map; 331 return al.map;
323} 332}
324 333
@@ -416,20 +425,19 @@ get_proc_name(unw_addr_space_t __maybe_unused as,
416static int access_dso_mem(struct unwind_info *ui, unw_word_t addr, 425static int access_dso_mem(struct unwind_info *ui, unw_word_t addr,
417 unw_word_t *data) 426 unw_word_t *data)
418{ 427{
419 struct addr_location al; 428 struct map *map;
420 ssize_t size; 429 ssize_t size;
421 430
422 thread__find_addr_map(ui->thread, PERF_RECORD_MISC_USER, 431 map = find_map(addr, ui);
423 MAP__FUNCTION, addr, &al); 432 if (!map) {
424 if (!al.map) {
425 pr_debug("unwind: no map for %lx\n", (unsigned long)addr); 433 pr_debug("unwind: no map for %lx\n", (unsigned long)addr);
426 return -1; 434 return -1;
427 } 435 }
428 436
429 if (!al.map->dso) 437 if (!map->dso)
430 return -1; 438 return -1;
431 439
432 size = dso__data_read_addr(al.map->dso, al.map, ui->machine, 440 size = dso__data_read_addr(map->dso, map, ui->machine,
433 addr, (u8 *) data, sizeof(*data)); 441 addr, (u8 *) data, sizeof(*data));
434 442
435 return !(size == sizeof(*data)); 443 return !(size == sizeof(*data));
@@ -614,23 +622,48 @@ void unwind__finish_access(struct thread *thread)
614static int get_entries(struct unwind_info *ui, unwind_entry_cb_t cb, 622static int get_entries(struct unwind_info *ui, unwind_entry_cb_t cb,
615 void *arg, int max_stack) 623 void *arg, int max_stack)
616{ 624{
625 u64 val;
626 unw_word_t ips[max_stack];
617 unw_addr_space_t addr_space; 627 unw_addr_space_t addr_space;
618 unw_cursor_t c; 628 unw_cursor_t c;
619 int ret; 629 int ret, i = 0;
620
621 addr_space = thread__priv(ui->thread);
622 if (addr_space == NULL)
623 return -1;
624 630
625 ret = unw_init_remote(&c, addr_space, ui); 631 ret = perf_reg_value(&val, &ui->sample->user_regs, PERF_REG_IP);
626 if (ret) 632 if (ret)
627 display_error(ret); 633 return ret;
628 634
629 while (!ret && (unw_step(&c) > 0) && max_stack--) { 635 ips[i++] = (unw_word_t) val;
630 unw_word_t ip;
631 636
632 unw_get_reg(&c, UNW_REG_IP, &ip); 637 /*
633 ret = ip ? entry(ip, ui->thread, cb, arg) : 0; 638 * If we need more than one entry, do the DWARF
639 * unwind itself.
640 */
641 if (max_stack - 1 > 0) {
642 addr_space = thread__priv(ui->thread);
643 if (addr_space == NULL)
644 return -1;
645
646 ret = unw_init_remote(&c, addr_space, ui);
647 if (ret)
648 display_error(ret);
649
650 while (!ret && (unw_step(&c) > 0) && i < max_stack) {
651 unw_get_reg(&c, UNW_REG_IP, &ips[i]);
652 ++i;
653 }
654
655 max_stack = i;
656 }
657
658 /*
659 * Display what we got based on the order setup.
660 */
661 for (i = 0; i < max_stack && !ret; i++) {
662 int j = i;
663
664 if (callchain_param.order == ORDER_CALLER)
665 j = max_stack - i - 1;
666 ret = ips[j] ? entry(ips[j], ui->thread, cb, arg) : 0;
634 } 667 }
635 668
636 return ret; 669 return ret;
@@ -640,24 +673,17 @@ int unwind__get_entries(unwind_entry_cb_t cb, void *arg,
640 struct thread *thread, 673 struct thread *thread,
641 struct perf_sample *data, int max_stack) 674 struct perf_sample *data, int max_stack)
642{ 675{
643 u64 ip;
644 struct unwind_info ui = { 676 struct unwind_info ui = {
645 .sample = data, 677 .sample = data,
646 .thread = thread, 678 .thread = thread,
647 .machine = thread->mg->machine, 679 .machine = thread->mg->machine,
648 }; 680 };
649 int ret;
650 681
651 if (!data->user_regs.regs) 682 if (!data->user_regs.regs)
652 return -EINVAL; 683 return -EINVAL;
653 684
654 ret = perf_reg_value(&ip, &data->user_regs, PERF_REG_IP); 685 if (max_stack <= 0)
655 if (ret) 686 return -EINVAL;
656 return ret;
657
658 ret = entry(ip, thread, cb, arg);
659 if (ret)
660 return -ENOMEM;
661 687
662 return --max_stack > 0 ? get_entries(&ui, cb, arg, max_stack) : 0; 688 return get_entries(&ui, cb, arg, max_stack);
663} 689}
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 cd12c25e4ea4..b7766c577b01 100644
--- a/tools/perf/util/util.c
+++ b/tools/perf/util/util.c
@@ -3,6 +3,7 @@
3#include "debug.h" 3#include "debug.h"
4#include <api/fs/fs.h> 4#include <api/fs/fs.h>
5#include <sys/mman.h> 5#include <sys/mman.h>
6#include <sys/utsname.h>
6#ifdef HAVE_BACKTRACE_SUPPORT 7#ifdef HAVE_BACKTRACE_SUPPORT
7#include <execinfo.h> 8#include <execinfo.h>
8#endif 9#endif
@@ -13,14 +14,17 @@
13#include <limits.h> 14#include <limits.h>
14#include <byteswap.h> 15#include <byteswap.h>
15#include <linux/kernel.h> 16#include <linux/kernel.h>
17#include <linux/log2.h>
16#include <unistd.h> 18#include <unistd.h>
17#include "callchain.h" 19#include "callchain.h"
20#include "strlist.h"
18 21
19struct callchain_param callchain_param = { 22struct callchain_param callchain_param = {
20 .mode = CHAIN_GRAPH_ABS, 23 .mode = CHAIN_GRAPH_ABS,
21 .min_percent = 0.5, 24 .min_percent = 0.5,
22 .order = ORDER_CALLEE, 25 .order = ORDER_CALLEE,
23 .key = CCKEY_FUNCTION 26 .key = CCKEY_FUNCTION,
27 .value = CCVAL_PERCENT,
24}; 28};
25 29
26/* 30/*
@@ -350,41 +354,8 @@ void sighandler_dump_stack(int sig)
350{ 354{
351 psignal(sig, "perf"); 355 psignal(sig, "perf");
352 dump_stack(); 356 dump_stack();
353 exit(sig); 357 signal(sig, SIG_DFL);
354} 358 raise(sig);
355
356void get_term_dimensions(struct winsize *ws)
357{
358 char *s = getenv("LINES");
359
360 if (s != NULL) {
361 ws->ws_row = atoi(s);
362 s = getenv("COLUMNS");
363 if (s != NULL) {
364 ws->ws_col = atoi(s);
365 if (ws->ws_row && ws->ws_col)
366 return;
367 }
368 }
369#ifdef TIOCGWINSZ
370 if (ioctl(1, TIOCGWINSZ, ws) == 0 &&
371 ws->ws_row && ws->ws_col)
372 return;
373#endif
374 ws->ws_row = 25;
375 ws->ws_col = 80;
376}
377
378void set_term_quiet_input(struct termios *old)
379{
380 struct termios tc;
381
382 tcgetattr(0, old);
383 tc = *old;
384 tc.c_lflag &= ~(ICANON | ECHO);
385 tc.c_cc[VMIN] = 0;
386 tc.c_cc[VTIME] = 0;
387 tcsetattr(0, TCSANOW, &tc);
388} 359}
389 360
390int parse_nsec_time(const char *str, u64 *ptime) 361int parse_nsec_time(const char *str, u64 *ptime)
@@ -537,54 +508,6 @@ int parse_callchain_record(const char *arg, struct callchain_param *param)
537 return ret; 508 return ret;
538} 509}
539 510
540int filename__read_str(const char *filename, char **buf, size_t *sizep)
541{
542 size_t size = 0, alloc_size = 0;
543 void *bf = NULL, *nbf;
544 int fd, n, err = 0;
545 char sbuf[STRERR_BUFSIZE];
546
547 fd = open(filename, O_RDONLY);
548 if (fd < 0)
549 return -errno;
550
551 do {
552 if (size == alloc_size) {
553 alloc_size += BUFSIZ;
554 nbf = realloc(bf, alloc_size);
555 if (!nbf) {
556 err = -ENOMEM;
557 break;
558 }
559
560 bf = nbf;
561 }
562
563 n = read(fd, bf + size, alloc_size - size);
564 if (n < 0) {
565 if (size) {
566 pr_warning("read failed %d: %s\n", errno,
567 strerror_r(errno, sbuf, sizeof(sbuf)));
568 err = 0;
569 } else
570 err = -errno;
571
572 break;
573 }
574
575 size += n;
576 } while (n > 0);
577
578 if (!err) {
579 *sizep = size;
580 *buf = bf;
581 } else
582 free(bf);
583
584 close(fd);
585 return err;
586}
587
588const char *get_filename_for_perf_kvm(void) 511const char *get_filename_for_perf_kvm(void)
589{ 512{
590 const char *filename; 513 const char *filename;
@@ -665,3 +588,122 @@ bool find_process(const char *name)
665 closedir(dir); 588 closedir(dir);
666 return ret ? false : true; 589 return ret ? false : true;
667} 590}
591
592int
593fetch_kernel_version(unsigned int *puint, char *str,
594 size_t str_size)
595{
596 struct utsname utsname;
597 int version, patchlevel, sublevel, err;
598
599 if (uname(&utsname))
600 return -1;
601
602 if (str && str_size) {
603 strncpy(str, utsname.release, str_size);
604 str[str_size - 1] = '\0';
605 }
606
607 err = sscanf(utsname.release, "%d.%d.%d",
608 &version, &patchlevel, &sublevel);
609
610 if (err != 3) {
611 pr_debug("Unablt to get kernel version from uname '%s'\n",
612 utsname.release);
613 return -1;
614 }
615
616 if (puint)
617 *puint = (version << 16) + (patchlevel << 8) + sublevel;
618 return 0;
619}
620
621const char *perf_tip(const char *dirpath)
622{
623 struct strlist *tips;
624 struct str_node *node;
625 char *tip = NULL;
626 struct strlist_config conf = {
627 .dirname = dirpath,
628 .file_only = true,
629 };
630
631 tips = strlist__new("tips.txt", &conf);
632 if (tips == NULL)
633 return errno == ENOENT ? NULL : "Tip: get more memory! ;-p";
634
635 if (strlist__nr_entries(tips) == 0)
636 goto out;
637
638 node = strlist__entry(tips, random() % strlist__nr_entries(tips));
639 if (asprintf(&tip, "Tip: %s", node->s) < 0)
640 tip = (char *)"Tip: get more memory! ;-)";
641
642out:
643 strlist__delete(tips);
644
645 return tip;
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 4cfb913aa9e0..8298d607c738 100644
--- a/tools/perf/util/util.h
+++ b/tools/perf/util/util.h
@@ -53,6 +53,7 @@
53#include <stdlib.h> 53#include <stdlib.h>
54#include <stdarg.h> 54#include <stdarg.h>
55#include <string.h> 55#include <string.h>
56#include <term.h>
56#include <errno.h> 57#include <errno.h>
57#include <limits.h> 58#include <limits.h>
58#include <sys/param.h> 59#include <sys/param.h>
@@ -81,6 +82,8 @@
81 82
82extern const char *graph_line; 83extern const char *graph_line;
83extern const char *graph_dotted_line; 84extern const char *graph_dotted_line;
85extern const char *spaces;
86extern const char *dots;
84extern char buildid_dir[]; 87extern char buildid_dir[];
85 88
86/* On most systems <limits.h> would have given us this, but 89/* On most systems <limits.h> would have given us this, but
@@ -130,31 +133,15 @@ extern char buildid_dir[];
130#define PERF_GTK_DSO "libperf-gtk.so" 133#define PERF_GTK_DSO "libperf-gtk.so"
131 134
132/* General helper functions */ 135/* General helper functions */
133extern void usage(const char *err) NORETURN; 136void usage(const char *err) NORETURN;
134extern void die(const char *err, ...) NORETURN __attribute__((format (printf, 1, 2))); 137void die(const char *err, ...) NORETURN __attribute__((format (printf, 1, 2)));
135extern int error(const char *err, ...) __attribute__((format (printf, 1, 2))); 138int error(const char *err, ...) __attribute__((format (printf, 1, 2)));
136extern void warning(const char *err, ...) __attribute__((format (printf, 1, 2))); 139void warning(const char *err, ...) __attribute__((format (printf, 1, 2)));
137 140
138#include "../../../include/linux/stringify.h" 141void set_warning_routine(void (*routine)(const char *err, va_list params));
139 142
140#define DIE_IF(cnd) \ 143int prefixcmp(const char *str, const char *prefix);
141 do { if (cnd) \ 144void set_buildid_dir(const char *dir);
142 die(" at (" __FILE__ ":" __stringify(__LINE__) "): " \
143 __stringify(cnd) "\n"); \
144 } while (0)
145
146
147extern void set_die_routine(void (*routine)(const char *err, va_list params) NORETURN);
148extern void set_warning_routine(void (*routine)(const char *err, va_list params));
149
150extern int prefixcmp(const char *str, const char *prefix);
151extern void set_buildid_dir(const char *dir);
152
153static inline const char *skip_prefix(const char *str, const char *prefix)
154{
155 size_t len = strlen(prefix);
156 return strncmp(str, prefix, len) ? NULL : str + len;
157}
158 145
159#ifdef __GLIBC_PREREQ 146#ifdef __GLIBC_PREREQ
160#if __GLIBC_PREREQ(2, 1) 147#if __GLIBC_PREREQ(2, 1)
@@ -175,8 +162,7 @@ static inline char *gitstrchrnul(const char *s, int c)
175/* 162/*
176 * Wrappers: 163 * Wrappers:
177 */ 164 */
178extern char *xstrdup(const char *str); 165void *xrealloc(void *ptr, size_t size) __attribute__((weak));
179extern void *xrealloc(void *ptr, size_t size) __attribute__((weak));
180 166
181 167
182static inline void *zalloc(size_t size) 168static inline void *zalloc(size_t size)
@@ -186,14 +172,6 @@ static inline void *zalloc(size_t size)
186 172
187#define zfree(ptr) ({ free(*ptr); *ptr = NULL; }) 173#define zfree(ptr) ({ free(*ptr); *ptr = NULL; })
188 174
189static inline int has_extension(const char *filename, const char *ext)
190{
191 size_t len = strlen(filename);
192 size_t extlen = strlen(ext);
193
194 return len > extlen && !memcmp(filename + len - extlen, ext, extlen);
195}
196
197/* Sane ctype - no locale, and works with signed chars */ 175/* Sane ctype - no locale, and works with signed chars */
198#undef isascii 176#undef isascii
199#undef isspace 177#undef isspace
@@ -282,9 +260,6 @@ void sighandler_dump_stack(int sig);
282extern unsigned int page_size; 260extern unsigned int page_size;
283extern int cacheline_size; 261extern int cacheline_size;
284 262
285void get_term_dimensions(struct winsize *ws);
286void set_term_quiet_input(struct termios *old);
287
288struct parse_tag { 263struct parse_tag {
289 char tag; 264 char tag;
290 int mult; 265 int mult;
@@ -319,7 +294,6 @@ char *__get_srcline(struct dso *dso, u64 addr, struct symbol *sym,
319 bool show_sym, bool unwind_inlines); 294 bool show_sym, bool unwind_inlines);
320void free_srcline(char *srcline); 295void free_srcline(char *srcline);
321 296
322int filename__read_str(const char *filename, char **buf, size_t *sizep);
323int perf_event_paranoid(void); 297int perf_event_paranoid(void);
324 298
325void mem_bswap_64(void *src, int byte_size); 299void mem_bswap_64(void *src, int byte_size);
@@ -350,4 +324,36 @@ static inline char *asprintf_expr_not_in_ints(const char *var, size_t nints, int
350 324
351int get_stack_size(const char *str, unsigned long *_size); 325int get_stack_size(const char *str, unsigned long *_size);
352 326
327int fetch_kernel_version(unsigned int *puint,
328 char *str, size_t str_sz);
329#define KVER_VERSION(x) (((x) >> 16) & 0xff)
330#define KVER_PATCHLEVEL(x) (((x) >> 8) & 0xff)
331#define KVER_SUBLEVEL(x) ((x) & 0xff)
332#define KVER_FMT "%d.%d.%d"
333#define KVER_PARAM(x) KVER_VERSION(x), KVER_PATCHLEVEL(x), KVER_SUBLEVEL(x)
334
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);
355
356void print_binary(unsigned char *data, size_t len,
357 size_t bytes_per_line, print_binary_t printer,
358 void *extra);
353#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);