aboutsummaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
authorIngo Molnar <mingo@kernel.org>2016-03-21 05:47:40 -0400
committerIngo Molnar <mingo@kernel.org>2016-03-21 05:47:40 -0400
commit42e405f7b1d252c90a2468dd2140f47b8142b7a0 (patch)
treebaeda52d8726fe694d3344a0d0fda1dadc30a901 /tools
parente9532e69b8d1d1284e8ecf8d2586de34aec61244 (diff)
parent710d60cbf1b312a8075a2158cbfbbd9c66132dcc (diff)
Merge branch 'linus' into sched/urgent, to pick up dependencies
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Diffstat (limited to 'tools')
-rw-r--r--tools/build/Makefile.build2
-rw-r--r--tools/build/Makefile.feature31
-rw-r--r--tools/build/feature/Makefile4
-rw-r--r--tools/build/feature/test-all.c5
-rw-r--r--tools/build/feature/test-compile.c2
-rw-r--r--tools/build/feature/test-libcrypto.c17
-rw-r--r--tools/lib/api/Build1
-rw-r--r--tools/lib/api/Makefile1
-rw-r--r--tools/lib/api/debug-internal.h20
-rw-r--r--tools/lib/api/debug.c28
-rw-r--r--tools/lib/api/debug.h10
-rw-r--r--tools/lib/api/fs/fs.c64
-rw-r--r--tools/lib/api/fs/fs.h3
-rw-r--r--tools/lib/bpf/libbpf.c34
-rw-r--r--tools/lib/lockdep/Makefile2
-rw-r--r--tools/lib/lockdep/common.c5
-rw-r--r--tools/lib/lockdep/include/liblockdep/common.h1
-rw-r--r--tools/lib/lockdep/lockdep.c6
-rw-r--r--tools/lib/lockdep/preload.c2
-rw-r--r--tools/lib/lockdep/tests/AA.c8
-rw-r--r--tools/lib/lockdep/tests/ABA.c13
-rw-r--r--tools/lib/lockdep/tests/ABBA_2threads.c46
-rw-r--r--tools/lib/lockdep/uinclude/linux/compiler.h1
-rw-r--r--tools/lib/traceevent/event-parse.c156
-rw-r--r--tools/lib/traceevent/event-parse.h13
-rw-r--r--tools/perf/Documentation/perf-config.txt357
-rw-r--r--tools/perf/Documentation/perf-inject.txt7
-rw-r--r--tools/perf/Documentation/perf-record.txt6
-rw-r--r--tools/perf/Documentation/perf-report.txt40
-rw-r--r--tools/perf/Documentation/perf-stat.txt35
-rw-r--r--tools/perf/Documentation/perf-top.txt3
-rw-r--r--tools/perf/Documentation/perfconfig.example2
-rw-r--r--tools/perf/Documentation/tips.txt1
-rw-r--r--tools/perf/Makefile25
-rw-r--r--tools/perf/Makefile.perf16
-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/kvm-stat.c170
-rw-r--r--tools/perf/arch/s390/util/kvm-stat.c10
-rw-r--r--tools/perf/arch/x86/Makefile1
-rw-r--r--tools/perf/arch/x86/tests/rdpmc.c3
-rw-r--r--tools/perf/arch/x86/util/intel-bts.c4
-rw-r--r--tools/perf/arch/x86/util/intel-pt.c6
-rw-r--r--tools/perf/arch/x86/util/kvm-stat.c16
-rw-r--r--tools/perf/bench/mem-memcpy-x86-64-asm.S5
-rw-r--r--tools/perf/builtin-annotate.c2
-rw-r--r--tools/perf/builtin-buildid-cache.c14
-rw-r--r--tools/perf/builtin-config.c27
-rw-r--r--tools/perf/builtin-diff.c2
-rw-r--r--tools/perf/builtin-help.c5
-rw-r--r--tools/perf/builtin-inject.c105
-rw-r--r--tools/perf/builtin-kmem.c4
-rw-r--r--tools/perf/builtin-kvm.c38
-rw-r--r--tools/perf/builtin-mem.c84
-rw-r--r--tools/perf/builtin-record.c197
-rw-r--r--tools/perf/builtin-report.c58
-rw-r--r--tools/perf/builtin-script.c155
-rw-r--r--tools/perf/builtin-stat.c567
-rw-r--r--tools/perf/builtin-top.c43
-rw-r--r--tools/perf/builtin-trace.c54
-rw-r--r--tools/perf/config/Makefile119
-rw-r--r--tools/perf/jvmti/Makefile89
-rw-r--r--tools/perf/jvmti/jvmti_agent.c465
-rw-r--r--tools/perf/jvmti/jvmti_agent.h36
-rw-r--r--tools/perf/jvmti/libjvmti.c304
-rw-r--r--tools/perf/perf.c18
-rw-r--r--tools/perf/perf.h2
-rw-r--r--tools/perf/scripts/python/Perf-Trace-Util/lib/Perf/Trace/Util.py5
-rw-r--r--tools/perf/tests/.gitignore1
-rw-r--r--tools/perf/tests/Build9
-rw-r--r--tools/perf/tests/bp_signal.c140
-rw-r--r--tools/perf/tests/bpf-script-test-relocation.c50
-rw-r--r--tools/perf/tests/bpf.c65
-rw-r--r--tools/perf/tests/code-reading.c10
-rw-r--r--tools/perf/tests/hists_cumulate.c2
-rw-r--r--tools/perf/tests/hists_filter.c2
-rw-r--r--tools/perf/tests/hists_output.c10
-rw-r--r--tools/perf/tests/llvm.c25
-rw-r--r--tools/perf/tests/llvm.h5
-rw-r--r--tools/perf/tests/make50
-rw-r--r--tools/perf/tests/parse-events.c54
-rw-r--r--tools/perf/tests/vmlinux-kallsyms.c24
-rw-r--r--tools/perf/ui/browser.c4
-rw-r--r--tools/perf/ui/browser.h2
-rw-r--r--tools/perf/ui/browsers/annotate.c2
-rw-r--r--tools/perf/ui/browsers/hists.c885
-rw-r--r--tools/perf/ui/gtk/hists.c199
-rw-r--r--tools/perf/ui/hist.c262
-rw-r--r--tools/perf/ui/stdio/hist.c302
-rw-r--r--tools/perf/util/Build10
-rw-r--r--tools/perf/util/auxtrace.c7
-rw-r--r--tools/perf/util/auxtrace.h6
-rw-r--r--tools/perf/util/bpf-loader.c724
-rw-r--r--tools/perf/util/bpf-loader.h59
-rw-r--r--tools/perf/util/build-id.c50
-rw-r--r--tools/perf/util/build-id.h1
-rw-r--r--tools/perf/util/cache.h3
-rw-r--r--tools/perf/util/callchain.c102
-rw-r--r--tools/perf/util/color.c5
-rw-r--r--tools/perf/util/config.c4
-rw-r--r--tools/perf/util/cpumap.c30
-rw-r--r--tools/perf/util/cpumap.h32
-rw-r--r--tools/perf/util/ctype.c9
-rw-r--r--tools/perf/util/data-convert-bt.c138
-rw-r--r--tools/perf/util/debug.c111
-rw-r--r--tools/perf/util/debug.h1
-rw-r--r--tools/perf/util/demangle-java.c199
-rw-r--r--tools/perf/util/demangle-java.h10
-rw-r--r--tools/perf/util/dso.c5
-rw-r--r--tools/perf/util/env.c13
-rw-r--r--tools/perf/util/env.h15
-rw-r--r--tools/perf/util/event.c2
-rw-r--r--tools/perf/util/evlist.c43
-rw-r--r--tools/perf/util/evlist.h3
-rw-r--r--tools/perf/util/evsel.c30
-rw-r--r--tools/perf/util/evsel.h14
-rw-r--r--tools/perf/util/genelf.c449
-rw-r--r--tools/perf/util/genelf.h67
-rw-r--r--tools/perf/util/genelf_debug.c610
-rw-r--r--tools/perf/util/header.c270
-rw-r--r--tools/perf/util/header.h1
-rw-r--r--tools/perf/util/help-unknown-cmd.c5
-rw-r--r--tools/perf/util/hist.c841
-rw-r--r--tools/perf/util/hist.h120
-rw-r--r--tools/perf/util/jit.h15
-rw-r--r--tools/perf/util/jitdump.c697
-rw-r--r--tools/perf/util/jitdump.h124
-rw-r--r--tools/perf/util/kvm-stat.h8
-rw-r--r--tools/perf/util/machine.h10
-rw-r--r--tools/perf/util/mem-events.c255
-rw-r--r--tools/perf/util/mem-events.h35
-rw-r--r--tools/perf/util/parse-events.c314
-rw-r--r--tools/perf/util/parse-events.h28
-rw-r--r--tools/perf/util/parse-events.l19
-rw-r--r--tools/perf/util/parse-events.y184
-rw-r--r--tools/perf/util/pmu.c34
-rw-r--r--tools/perf/util/scripting-engines/trace-event-perl.c3
-rw-r--r--tools/perf/util/scripting-engines/trace-event-python.c7
-rw-r--r--tools/perf/util/session.c40
-rw-r--r--tools/perf/util/setup.py4
-rw-r--r--tools/perf/util/sort.c761
-rw-r--r--tools/perf/util/sort.h29
-rw-r--r--tools/perf/util/stat-shadow.c225
-rw-r--r--tools/perf/util/stat.c14
-rw-r--r--tools/perf/util/stat.h24
-rw-r--r--tools/perf/util/strbuf.c24
-rw-r--r--tools/perf/util/strbuf.h2
-rw-r--r--tools/perf/util/symbol-elf.c3
-rw-r--r--tools/perf/util/symbol.c10
-rw-r--r--tools/perf/util/symbol.h3
-rw-r--r--tools/perf/util/trace-event.c1
-rw-r--r--tools/perf/util/tsc.c2
-rw-r--r--tools/perf/util/util.c112
-rw-r--r--tools/perf/util/util.h25
-rw-r--r--tools/power/x86/turbostat/turbostat.c8
-rwxr-xr-xtools/testing/selftests/rcutorture/bin/parse-console.sh6
-rw-r--r--tools/testing/selftests/x86/Makefile17
-rw-r--r--tools/testing/selftests/x86/check_initial_reg_state.c109
-rw-r--r--tools/testing/selftests/x86/ptrace_syscall.c132
-rw-r--r--tools/testing/selftests/x86/sigreturn.c230
-rw-r--r--tools/testing/selftests/x86/syscall_nt.c57
165 files changed, 11725 insertions, 1675 deletions
diff --git a/tools/build/Makefile.build b/tools/build/Makefile.build
index 4a96473b180f..ee566e8bd1cf 100644
--- a/tools/build/Makefile.build
+++ b/tools/build/Makefile.build
@@ -85,7 +85,7 @@ $(OUTPUT)%.i: %.c FORCE
85 $(call rule_mkdir) 85 $(call rule_mkdir)
86 $(call if_changed_dep,cc_i_c) 86 $(call if_changed_dep,cc_i_c)
87 87
88$(OUTPUT)%.i: %.S FORCE 88$(OUTPUT)%.s: %.S FORCE
89 $(call rule_mkdir) 89 $(call rule_mkdir)
90 $(call if_changed_dep,cc_i_c) 90 $(call if_changed_dep,cc_i_c)
91 91
diff --git a/tools/build/Makefile.feature b/tools/build/Makefile.feature
index 02db3cdff20f..6b7707270aa3 100644
--- a/tools/build/Makefile.feature
+++ b/tools/build/Makefile.feature
@@ -27,7 +27,7 @@ endef
27# the rule that uses them - an example for that is the 'bionic' 27# the rule that uses them - an example for that is the 'bionic'
28# feature check. ] 28# feature check. ]
29# 29#
30FEATURE_TESTS ?= \ 30FEATURE_TESTS_BASIC := \
31 backtrace \ 31 backtrace \
32 dwarf \ 32 dwarf \
33 fortify-source \ 33 fortify-source \
@@ -46,6 +46,7 @@ FEATURE_TESTS ?= \
46 libpython \ 46 libpython \
47 libpython-version \ 47 libpython-version \
48 libslang \ 48 libslang \
49 libcrypto \
49 libunwind \ 50 libunwind \
50 pthread-attr-setaffinity-np \ 51 pthread-attr-setaffinity-np \
51 stackprotector-all \ 52 stackprotector-all \
@@ -56,6 +57,25 @@ FEATURE_TESTS ?= \
56 get_cpuid \ 57 get_cpuid \
57 bpf 58 bpf
58 59
60# FEATURE_TESTS_BASIC + FEATURE_TESTS_EXTRA is the complete list
61# of all feature tests
62FEATURE_TESTS_EXTRA := \
63 bionic \
64 compile-32 \
65 compile-x32 \
66 cplus-demangle \
67 hello \
68 libbabeltrace \
69 liberty \
70 liberty-z \
71 libunwind-debug-frame
72
73FEATURE_TESTS ?= $(FEATURE_TESTS_BASIC)
74
75ifeq ($(FEATURE_TESTS),all)
76 FEATURE_TESTS := $(FEATURE_TESTS_BASIC) $(FEATURE_TESTS_EXTRA)
77endif
78
59FEATURE_DISPLAY ?= \ 79FEATURE_DISPLAY ?= \
60 dwarf \ 80 dwarf \
61 glibc \ 81 glibc \
@@ -68,6 +88,7 @@ FEATURE_DISPLAY ?= \
68 libperl \ 88 libperl \
69 libpython \ 89 libpython \
70 libslang \ 90 libslang \
91 libcrypto \
71 libunwind \ 92 libunwind \
72 libdw-dwarf-unwind \ 93 libdw-dwarf-unwind \
73 zlib \ 94 zlib \
@@ -100,6 +121,14 @@ ifeq ($(feature-all), 1)
100 # test-all.c passed - just set all the core feature flags to 1: 121 # test-all.c passed - just set all the core feature flags to 1:
101 # 122 #
102 $(foreach feat,$(FEATURE_TESTS),$(call feature_set,$(feat))) 123 $(foreach feat,$(FEATURE_TESTS),$(call feature_set,$(feat)))
124 #
125 # test-all.c does not comprise these tests, so we need to
126 # for this case to get features proper values
127 #
128 $(call feature_check,compile-32)
129 $(call feature_check,compile-x32)
130 $(call feature_check,bionic)
131 $(call feature_check,libbabeltrace)
103else 132else
104 $(foreach feat,$(FEATURE_TESTS),$(call feature_check,$(feat))) 133 $(foreach feat,$(FEATURE_TESTS),$(call feature_check,$(feat)))
105endif 134endif
diff --git a/tools/build/feature/Makefile b/tools/build/feature/Makefile
index bf8f0352264d..c5f4c417428d 100644
--- a/tools/build/feature/Makefile
+++ b/tools/build/feature/Makefile
@@ -23,6 +23,7 @@ FILES= \
23 test-libpython.bin \ 23 test-libpython.bin \
24 test-libpython-version.bin \ 24 test-libpython-version.bin \
25 test-libslang.bin \ 25 test-libslang.bin \
26 test-libcrypto.bin \
26 test-libunwind.bin \ 27 test-libunwind.bin \
27 test-libunwind-debug-frame.bin \ 28 test-libunwind-debug-frame.bin \
28 test-pthread-attr-setaffinity-np.bin \ 29 test-pthread-attr-setaffinity-np.bin \
@@ -105,6 +106,9 @@ $(OUTPUT)test-libaudit.bin:
105$(OUTPUT)test-libslang.bin: 106$(OUTPUT)test-libslang.bin:
106 $(BUILD) -I/usr/include/slang -lslang 107 $(BUILD) -I/usr/include/slang -lslang
107 108
109$(OUTPUT)test-libcrypto.bin:
110 $(BUILD) -lcrypto
111
108$(OUTPUT)test-gtk2.bin: 112$(OUTPUT)test-gtk2.bin:
109 $(BUILD) $(shell $(PKG_CONFIG) --libs --cflags gtk+-2.0 2>/dev/null) 113 $(BUILD) $(shell $(PKG_CONFIG) --libs --cflags gtk+-2.0 2>/dev/null)
110 114
diff --git a/tools/build/feature/test-all.c b/tools/build/feature/test-all.c
index 81025cade45f..e499a36c1e4a 100644
--- a/tools/build/feature/test-all.c
+++ b/tools/build/feature/test-all.c
@@ -129,6 +129,10 @@
129# include "test-bpf.c" 129# include "test-bpf.c"
130#undef main 130#undef main
131 131
132#define main main_test_libcrypto
133# include "test-libcrypto.c"
134#undef main
135
132int main(int argc, char *argv[]) 136int main(int argc, char *argv[])
133{ 137{
134 main_test_libpython(); 138 main_test_libpython();
@@ -158,6 +162,7 @@ int main(int argc, char *argv[])
158 main_test_lzma(); 162 main_test_lzma();
159 main_test_get_cpuid(); 163 main_test_get_cpuid();
160 main_test_bpf(); 164 main_test_bpf();
165 main_test_libcrypto();
161 166
162 return 0; 167 return 0;
163} 168}
diff --git a/tools/build/feature/test-compile.c b/tools/build/feature/test-compile.c
index 31dbf45bf99c..c54e6551ae4c 100644
--- a/tools/build/feature/test-compile.c
+++ b/tools/build/feature/test-compile.c
@@ -1,4 +1,6 @@
1#include <stdio.h>
1int main(void) 2int main(void)
2{ 3{
4 printf("Hello World!\n");
3 return 0; 5 return 0;
4} 6}
diff --git a/tools/build/feature/test-libcrypto.c b/tools/build/feature/test-libcrypto.c
new file mode 100644
index 000000000000..bd79dc7f28d3
--- /dev/null
+++ b/tools/build/feature/test-libcrypto.c
@@ -0,0 +1,17 @@
1#include <openssl/sha.h>
2#include <openssl/md5.h>
3
4int main(void)
5{
6 MD5_CTX context;
7 unsigned char md[MD5_DIGEST_LENGTH + SHA_DIGEST_LENGTH];
8 unsigned char dat[] = "12345";
9
10 MD5_Init(&context);
11 MD5_Update(&context, &dat[0], sizeof(dat));
12 MD5_Final(&md[0], &context);
13
14 SHA1(&dat[0], sizeof(dat), &md[0]);
15
16 return 0;
17}
diff --git a/tools/lib/api/Build b/tools/lib/api/Build
index e8b8a23b9bf4..954c644f7ad9 100644
--- a/tools/lib/api/Build
+++ b/tools/lib/api/Build
@@ -1,3 +1,4 @@
1libapi-y += fd/ 1libapi-y += fd/
2libapi-y += fs/ 2libapi-y += fs/
3libapi-y += cpu.o 3libapi-y += cpu.o
4libapi-y += debug.o
diff --git a/tools/lib/api/Makefile b/tools/lib/api/Makefile
index d85904dc9b38..bbc82c614bee 100644
--- a/tools/lib/api/Makefile
+++ b/tools/lib/api/Makefile
@@ -18,6 +18,7 @@ LIBFILE = $(OUTPUT)libapi.a
18CFLAGS := $(EXTRA_WARNINGS) $(EXTRA_CFLAGS) 18CFLAGS := $(EXTRA_WARNINGS) $(EXTRA_CFLAGS)
19CFLAGS += -ggdb3 -Wall -Wextra -std=gnu99 -Werror -O6 -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=2 -fPIC 19CFLAGS += -ggdb3 -Wall -Wextra -std=gnu99 -Werror -O6 -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=2 -fPIC
20CFLAGS += -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 20CFLAGS += -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64
21CFLAGS += -I$(srctree)/tools/lib/api
21 22
22RM = rm -f 23RM = rm -f
23 24
diff --git a/tools/lib/api/debug-internal.h b/tools/lib/api/debug-internal.h
new file mode 100644
index 000000000000..188f7880eafe
--- /dev/null
+++ b/tools/lib/api/debug-internal.h
@@ -0,0 +1,20 @@
1#ifndef __API_DEBUG_INTERNAL_H__
2#define __API_DEBUG_INTERNAL_H__
3
4#include "debug.h"
5
6#define __pr(func, fmt, ...) \
7do { \
8 if ((func)) \
9 (func)("libapi: " fmt, ##__VA_ARGS__); \
10} while (0)
11
12extern libapi_print_fn_t __pr_warning;
13extern libapi_print_fn_t __pr_info;
14extern libapi_print_fn_t __pr_debug;
15
16#define pr_warning(fmt, ...) __pr(__pr_warning, fmt, ##__VA_ARGS__)
17#define pr_info(fmt, ...) __pr(__pr_info, fmt, ##__VA_ARGS__)
18#define pr_debug(fmt, ...) __pr(__pr_debug, fmt, ##__VA_ARGS__)
19
20#endif /* __API_DEBUG_INTERNAL_H__ */
diff --git a/tools/lib/api/debug.c b/tools/lib/api/debug.c
new file mode 100644
index 000000000000..5fa5cf500a1f
--- /dev/null
+++ b/tools/lib/api/debug.c
@@ -0,0 +1,28 @@
1#include <stdio.h>
2#include <stdarg.h>
3#include "debug.h"
4#include "debug-internal.h"
5
6static int __base_pr(const char *format, ...)
7{
8 va_list args;
9 int err;
10
11 va_start(args, format);
12 err = vfprintf(stderr, format, args);
13 va_end(args);
14 return err;
15}
16
17libapi_print_fn_t __pr_warning = __base_pr;
18libapi_print_fn_t __pr_info = __base_pr;
19libapi_print_fn_t __pr_debug;
20
21void libapi_set_print(libapi_print_fn_t warn,
22 libapi_print_fn_t info,
23 libapi_print_fn_t debug)
24{
25 __pr_warning = warn;
26 __pr_info = info;
27 __pr_debug = debug;
28}
diff --git a/tools/lib/api/debug.h b/tools/lib/api/debug.h
new file mode 100644
index 000000000000..a0872f68fc56
--- /dev/null
+++ b/tools/lib/api/debug.h
@@ -0,0 +1,10 @@
1#ifndef __API_DEBUG_H__
2#define __API_DEBUG_H__
3
4typedef int (*libapi_print_fn_t)(const char *, ...);
5
6void libapi_set_print(libapi_print_fn_t warn,
7 libapi_print_fn_t info,
8 libapi_print_fn_t debug);
9
10#endif /* __API_DEBUG_H__ */
diff --git a/tools/lib/api/fs/fs.c b/tools/lib/api/fs/fs.c
index 459599d1b6c4..ef78c22ff44d 100644
--- a/tools/lib/api/fs/fs.c
+++ b/tools/lib/api/fs/fs.c
@@ -13,6 +13,7 @@
13#include <sys/mount.h> 13#include <sys/mount.h>
14 14
15#include "fs.h" 15#include "fs.h"
16#include "debug-internal.h"
16 17
17#define _STR(x) #x 18#define _STR(x) #x
18#define STR(x) _STR(x) 19#define STR(x) _STR(x)
@@ -300,6 +301,56 @@ int filename__read_ull(const char *filename, unsigned long long *value)
300 return err; 301 return err;
301} 302}
302 303
304#define STRERR_BUFSIZE 128 /* For the buffer size of strerror_r */
305
306int filename__read_str(const char *filename, char **buf, size_t *sizep)
307{
308 size_t size = 0, alloc_size = 0;
309 void *bf = NULL, *nbf;
310 int fd, n, err = 0;
311 char sbuf[STRERR_BUFSIZE];
312
313 fd = open(filename, O_RDONLY);
314 if (fd < 0)
315 return -errno;
316
317 do {
318 if (size == alloc_size) {
319 alloc_size += BUFSIZ;
320 nbf = realloc(bf, alloc_size);
321 if (!nbf) {
322 err = -ENOMEM;
323 break;
324 }
325
326 bf = nbf;
327 }
328
329 n = read(fd, bf + size, alloc_size - size);
330 if (n < 0) {
331 if (size) {
332 pr_warning("read failed %d: %s\n", errno,
333 strerror_r(errno, sbuf, sizeof(sbuf)));
334 err = 0;
335 } else
336 err = -errno;
337
338 break;
339 }
340
341 size += n;
342 } while (n > 0);
343
344 if (!err) {
345 *sizep = size;
346 *buf = bf;
347 } else
348 free(bf);
349
350 close(fd);
351 return err;
352}
353
303int sysfs__read_ull(const char *entry, unsigned long long *value) 354int sysfs__read_ull(const char *entry, unsigned long long *value)
304{ 355{
305 char path[PATH_MAX]; 356 char path[PATH_MAX];
@@ -326,6 +377,19 @@ int sysfs__read_int(const char *entry, int *value)
326 return filename__read_int(path, value); 377 return filename__read_int(path, value);
327} 378}
328 379
380int sysfs__read_str(const char *entry, char **buf, size_t *sizep)
381{
382 char path[PATH_MAX];
383 const char *sysfs = sysfs__mountpoint();
384
385 if (!sysfs)
386 return -1;
387
388 snprintf(path, sizeof(path), "%s/%s", sysfs, entry);
389
390 return filename__read_str(path, buf, sizep);
391}
392
329int sysctl__read_int(const char *sysctl, int *value) 393int sysctl__read_int(const char *sysctl, int *value)
330{ 394{
331 char path[PATH_MAX]; 395 char path[PATH_MAX];
diff --git a/tools/lib/api/fs/fs.h b/tools/lib/api/fs/fs.h
index d024a7f682f6..9f6598098dc5 100644
--- a/tools/lib/api/fs/fs.h
+++ b/tools/lib/api/fs/fs.h
@@ -2,6 +2,7 @@
2#define __API_FS__ 2#define __API_FS__
3 3
4#include <stdbool.h> 4#include <stdbool.h>
5#include <unistd.h>
5 6
6/* 7/*
7 * On most systems <limits.h> would have given us this, but not on some systems 8 * On most systems <limits.h> would have given us this, but not on some systems
@@ -26,8 +27,10 @@ FS(tracefs)
26 27
27int filename__read_int(const char *filename, int *value); 28int filename__read_int(const char *filename, int *value);
28int filename__read_ull(const char *filename, unsigned long long *value); 29int filename__read_ull(const char *filename, unsigned long long *value);
30int filename__read_str(const char *filename, char **buf, size_t *sizep);
29 31
30int sysctl__read_int(const char *sysctl, int *value); 32int sysctl__read_int(const char *sysctl, int *value);
31int sysfs__read_int(const char *entry, int *value); 33int sysfs__read_int(const char *entry, int *value);
32int sysfs__read_ull(const char *entry, unsigned long long *value); 34int sysfs__read_ull(const char *entry, unsigned long long *value);
35int sysfs__read_str(const char *entry, char **buf, size_t *sizep);
33#endif /* __API_FS__ */ 36#endif /* __API_FS__ */
diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c
index 8334a5a9d5d7..7e543c3102d4 100644
--- a/tools/lib/bpf/libbpf.c
+++ b/tools/lib/bpf/libbpf.c
@@ -201,6 +201,7 @@ struct bpf_object {
201 Elf_Data *data; 201 Elf_Data *data;
202 } *reloc; 202 } *reloc;
203 int nr_reloc; 203 int nr_reloc;
204 int maps_shndx;
204 } efile; 205 } efile;
205 /* 206 /*
206 * All loaded bpf_object is linked in a list, which is 207 * All loaded bpf_object is linked in a list, which is
@@ -350,6 +351,7 @@ static struct bpf_object *bpf_object__new(const char *path,
350 */ 351 */
351 obj->efile.obj_buf = obj_buf; 352 obj->efile.obj_buf = obj_buf;
352 obj->efile.obj_buf_sz = obj_buf_sz; 353 obj->efile.obj_buf_sz = obj_buf_sz;
354 obj->efile.maps_shndx = -1;
353 355
354 obj->loaded = false; 356 obj->loaded = false;
355 357
@@ -529,12 +531,12 @@ bpf_object__init_maps(struct bpf_object *obj, void *data,
529} 531}
530 532
531static int 533static int
532bpf_object__init_maps_name(struct bpf_object *obj, int maps_shndx) 534bpf_object__init_maps_name(struct bpf_object *obj)
533{ 535{
534 int i; 536 int i;
535 Elf_Data *symbols = obj->efile.symbols; 537 Elf_Data *symbols = obj->efile.symbols;
536 538
537 if (!symbols || maps_shndx < 0) 539 if (!symbols || obj->efile.maps_shndx < 0)
538 return -EINVAL; 540 return -EINVAL;
539 541
540 for (i = 0; i < symbols->d_size / sizeof(GElf_Sym); i++) { 542 for (i = 0; i < symbols->d_size / sizeof(GElf_Sym); i++) {
@@ -544,7 +546,7 @@ bpf_object__init_maps_name(struct bpf_object *obj, int maps_shndx)
544 546
545 if (!gelf_getsym(symbols, i, &sym)) 547 if (!gelf_getsym(symbols, i, &sym))
546 continue; 548 continue;
547 if (sym.st_shndx != maps_shndx) 549 if (sym.st_shndx != obj->efile.maps_shndx)
548 continue; 550 continue;
549 551
550 map_name = elf_strptr(obj->efile.elf, 552 map_name = elf_strptr(obj->efile.elf,
@@ -572,7 +574,7 @@ static int bpf_object__elf_collect(struct bpf_object *obj)
572 Elf *elf = obj->efile.elf; 574 Elf *elf = obj->efile.elf;
573 GElf_Ehdr *ep = &obj->efile.ehdr; 575 GElf_Ehdr *ep = &obj->efile.ehdr;
574 Elf_Scn *scn = NULL; 576 Elf_Scn *scn = NULL;
575 int idx = 0, err = 0, maps_shndx = -1; 577 int idx = 0, err = 0;
576 578
577 /* Elf is corrupted/truncated, avoid calling elf_strptr. */ 579 /* Elf is corrupted/truncated, avoid calling elf_strptr. */
578 if (!elf_rawdata(elf_getscn(elf, ep->e_shstrndx), NULL)) { 580 if (!elf_rawdata(elf_getscn(elf, ep->e_shstrndx), NULL)) {
@@ -625,7 +627,7 @@ static int bpf_object__elf_collect(struct bpf_object *obj)
625 else if (strcmp(name, "maps") == 0) { 627 else if (strcmp(name, "maps") == 0) {
626 err = bpf_object__init_maps(obj, data->d_buf, 628 err = bpf_object__init_maps(obj, data->d_buf,
627 data->d_size); 629 data->d_size);
628 maps_shndx = idx; 630 obj->efile.maps_shndx = idx;
629 } else if (sh.sh_type == SHT_SYMTAB) { 631 } else if (sh.sh_type == SHT_SYMTAB) {
630 if (obj->efile.symbols) { 632 if (obj->efile.symbols) {
631 pr_warning("bpf: multiple SYMTAB in %s\n", 633 pr_warning("bpf: multiple SYMTAB in %s\n",
@@ -674,8 +676,8 @@ static int bpf_object__elf_collect(struct bpf_object *obj)
674 pr_warning("Corrupted ELF file: index of strtab invalid\n"); 676 pr_warning("Corrupted ELF file: index of strtab invalid\n");
675 return LIBBPF_ERRNO__FORMAT; 677 return LIBBPF_ERRNO__FORMAT;
676 } 678 }
677 if (maps_shndx >= 0) 679 if (obj->efile.maps_shndx >= 0)
678 err = bpf_object__init_maps_name(obj, maps_shndx); 680 err = bpf_object__init_maps_name(obj);
679out: 681out:
680 return err; 682 return err;
681} 683}
@@ -697,7 +699,8 @@ bpf_object__find_prog_by_idx(struct bpf_object *obj, int idx)
697static int 699static int
698bpf_program__collect_reloc(struct bpf_program *prog, 700bpf_program__collect_reloc(struct bpf_program *prog,
699 size_t nr_maps, GElf_Shdr *shdr, 701 size_t nr_maps, GElf_Shdr *shdr,
700 Elf_Data *data, Elf_Data *symbols) 702 Elf_Data *data, Elf_Data *symbols,
703 int maps_shndx)
701{ 704{
702 int i, nrels; 705 int i, nrels;
703 706
@@ -724,9 +727,6 @@ bpf_program__collect_reloc(struct bpf_program *prog,
724 return -LIBBPF_ERRNO__FORMAT; 727 return -LIBBPF_ERRNO__FORMAT;
725 } 728 }
726 729
727 insn_idx = rel.r_offset / sizeof(struct bpf_insn);
728 pr_debug("relocation: insn_idx=%u\n", insn_idx);
729
730 if (!gelf_getsym(symbols, 730 if (!gelf_getsym(symbols,
731 GELF_R_SYM(rel.r_info), 731 GELF_R_SYM(rel.r_info),
732 &sym)) { 732 &sym)) {
@@ -735,6 +735,15 @@ bpf_program__collect_reloc(struct bpf_program *prog,
735 return -LIBBPF_ERRNO__FORMAT; 735 return -LIBBPF_ERRNO__FORMAT;
736 } 736 }
737 737
738 if (sym.st_shndx != maps_shndx) {
739 pr_warning("Program '%s' contains non-map related relo data pointing to section %u\n",
740 prog->section_name, sym.st_shndx);
741 return -LIBBPF_ERRNO__RELOC;
742 }
743
744 insn_idx = rel.r_offset / sizeof(struct bpf_insn);
745 pr_debug("relocation: insn_idx=%u\n", insn_idx);
746
738 if (insns[insn_idx].code != (BPF_LD | BPF_IMM | BPF_DW)) { 747 if (insns[insn_idx].code != (BPF_LD | BPF_IMM | BPF_DW)) {
739 pr_warning("bpf: relocation: invalid relo for insns[%d].code 0x%x\n", 748 pr_warning("bpf: relocation: invalid relo for insns[%d].code 0x%x\n",
740 insn_idx, insns[insn_idx].code); 749 insn_idx, insns[insn_idx].code);
@@ -863,7 +872,8 @@ static int bpf_object__collect_reloc(struct bpf_object *obj)
863 872
864 err = bpf_program__collect_reloc(prog, nr_maps, 873 err = bpf_program__collect_reloc(prog, nr_maps,
865 shdr, data, 874 shdr, data,
866 obj->efile.symbols); 875 obj->efile.symbols,
876 obj->efile.maps_shndx);
867 if (err) 877 if (err)
868 return err; 878 return err;
869 } 879 }
diff --git a/tools/lib/lockdep/Makefile b/tools/lib/lockdep/Makefile
index 90d2baeb621a..1d57af56814b 100644
--- a/tools/lib/lockdep/Makefile
+++ b/tools/lib/lockdep/Makefile
@@ -100,7 +100,7 @@ include $(srctree)/tools/build/Makefile.include
100 100
101do_compile_shared_library = \ 101do_compile_shared_library = \
102 ($(print_shared_lib_compile) \ 102 ($(print_shared_lib_compile) \
103 $(CC) --shared $^ -o $@ -lpthread -ldl -Wl,-soname='"$@"';$(shell ln -s $@ liblockdep.so)) 103 $(CC) --shared $^ -o $@ -lpthread -ldl -Wl,-soname='"$@"';$(shell ln -sf $@ liblockdep.so))
104 104
105do_build_static_lib = \ 105do_build_static_lib = \
106 ($(print_static_lib_build) \ 106 ($(print_static_lib_build) \
diff --git a/tools/lib/lockdep/common.c b/tools/lib/lockdep/common.c
index 9be663340f0a..d1c89cc06f5f 100644
--- a/tools/lib/lockdep/common.c
+++ b/tools/lib/lockdep/common.c
@@ -11,11 +11,6 @@ static __thread struct task_struct current_obj;
11bool debug_locks = true; 11bool debug_locks = true;
12bool debug_locks_silent; 12bool debug_locks_silent;
13 13
14__attribute__((constructor)) static void liblockdep_init(void)
15{
16 lockdep_init();
17}
18
19__attribute__((destructor)) static void liblockdep_exit(void) 14__attribute__((destructor)) static void liblockdep_exit(void)
20{ 15{
21 debug_check_no_locks_held(); 16 debug_check_no_locks_held();
diff --git a/tools/lib/lockdep/include/liblockdep/common.h b/tools/lib/lockdep/include/liblockdep/common.h
index a60c14b9662a..6e66277ec437 100644
--- a/tools/lib/lockdep/include/liblockdep/common.h
+++ b/tools/lib/lockdep/include/liblockdep/common.h
@@ -44,7 +44,6 @@ void lock_acquire(struct lockdep_map *lock, unsigned int subclass,
44void lock_release(struct lockdep_map *lock, int nested, 44void lock_release(struct lockdep_map *lock, int nested,
45 unsigned long ip); 45 unsigned long ip);
46extern void debug_check_no_locks_freed(const void *from, unsigned long len); 46extern void debug_check_no_locks_freed(const void *from, unsigned long len);
47extern void lockdep_init(void);
48 47
49#define STATIC_LOCKDEP_MAP_INIT(_name, _key) \ 48#define STATIC_LOCKDEP_MAP_INIT(_name, _key) \
50 { .name = (_name), .key = (void *)(_key), } 49 { .name = (_name), .key = (void *)(_key), }
diff --git a/tools/lib/lockdep/lockdep.c b/tools/lib/lockdep/lockdep.c
index f42b7e9aa48f..a0a2e3a266af 100644
--- a/tools/lib/lockdep/lockdep.c
+++ b/tools/lib/lockdep/lockdep.c
@@ -1,2 +1,8 @@
1#include <linux/lockdep.h> 1#include <linux/lockdep.h>
2
3/* Trivial API wrappers, we don't (yet) have RCU in user-space: */
4#define hlist_for_each_entry_rcu hlist_for_each_entry
5#define hlist_add_head_rcu hlist_add_head
6#define hlist_del_rcu hlist_del
7
2#include "../../../kernel/locking/lockdep.c" 8#include "../../../kernel/locking/lockdep.c"
diff --git a/tools/lib/lockdep/preload.c b/tools/lib/lockdep/preload.c
index 21cdf869a01b..52844847569c 100644
--- a/tools/lib/lockdep/preload.c
+++ b/tools/lib/lockdep/preload.c
@@ -439,7 +439,5 @@ __attribute__((constructor)) static void init_preload(void)
439 ll_pthread_rwlock_unlock = dlsym(RTLD_NEXT, "pthread_rwlock_unlock"); 439 ll_pthread_rwlock_unlock = dlsym(RTLD_NEXT, "pthread_rwlock_unlock");
440#endif 440#endif
441 441
442 lockdep_init();
443
444 __init_state = done; 442 __init_state = done;
445} 443}
diff --git a/tools/lib/lockdep/tests/AA.c b/tools/lib/lockdep/tests/AA.c
index 0f782ff404ac..18211a5f354f 100644
--- a/tools/lib/lockdep/tests/AA.c
+++ b/tools/lib/lockdep/tests/AA.c
@@ -1,13 +1,13 @@
1#include <liblockdep/mutex.h> 1#include <liblockdep/mutex.h>
2 2
3void main(void) 3int main(void)
4{ 4{
5 pthread_mutex_t a, b; 5 pthread_mutex_t a;
6 6
7 pthread_mutex_init(&a, NULL); 7 pthread_mutex_init(&a, NULL);
8 pthread_mutex_init(&b, NULL);
9 8
10 pthread_mutex_lock(&a); 9 pthread_mutex_lock(&a);
11 pthread_mutex_lock(&b);
12 pthread_mutex_lock(&a); 10 pthread_mutex_lock(&a);
11
12 return 0;
13} 13}
diff --git a/tools/lib/lockdep/tests/ABA.c b/tools/lib/lockdep/tests/ABA.c
new file mode 100644
index 000000000000..0f782ff404ac
--- /dev/null
+++ b/tools/lib/lockdep/tests/ABA.c
@@ -0,0 +1,13 @@
1#include <liblockdep/mutex.h>
2
3void main(void)
4{
5 pthread_mutex_t a, b;
6
7 pthread_mutex_init(&a, NULL);
8 pthread_mutex_init(&b, NULL);
9
10 pthread_mutex_lock(&a);
11 pthread_mutex_lock(&b);
12 pthread_mutex_lock(&a);
13}
diff --git a/tools/lib/lockdep/tests/ABBA_2threads.c b/tools/lib/lockdep/tests/ABBA_2threads.c
new file mode 100644
index 000000000000..cd807d736361
--- /dev/null
+++ b/tools/lib/lockdep/tests/ABBA_2threads.c
@@ -0,0 +1,46 @@
1#include <stdio.h>
2#include <pthread.h>
3
4pthread_mutex_t a = PTHREAD_MUTEX_INITIALIZER;
5pthread_mutex_t b = PTHREAD_MUTEX_INITIALIZER;
6pthread_barrier_t bar;
7
8void *ba_lock(void *arg)
9{
10 int ret, i;
11
12 pthread_mutex_lock(&b);
13
14 if (pthread_barrier_wait(&bar) == PTHREAD_BARRIER_SERIAL_THREAD)
15 pthread_barrier_destroy(&bar);
16
17 pthread_mutex_lock(&a);
18
19 pthread_mutex_unlock(&a);
20 pthread_mutex_unlock(&b);
21}
22
23int main(void)
24{
25 pthread_t t;
26
27 pthread_barrier_init(&bar, NULL, 2);
28
29 if (pthread_create(&t, NULL, ba_lock, NULL)) {
30 fprintf(stderr, "pthread_create() failed\n");
31 return 1;
32 }
33 pthread_mutex_lock(&a);
34
35 if (pthread_barrier_wait(&bar) == PTHREAD_BARRIER_SERIAL_THREAD)
36 pthread_barrier_destroy(&bar);
37
38 pthread_mutex_lock(&b);
39
40 pthread_mutex_unlock(&b);
41 pthread_mutex_unlock(&a);
42
43 pthread_join(t, NULL);
44
45 return 0;
46}
diff --git a/tools/lib/lockdep/uinclude/linux/compiler.h b/tools/lib/lockdep/uinclude/linux/compiler.h
index 6386dc3182a0..fd3e56a83fc2 100644
--- a/tools/lib/lockdep/uinclude/linux/compiler.h
+++ b/tools/lib/lockdep/uinclude/linux/compiler.h
@@ -3,6 +3,7 @@
3 3
4#define __used __attribute__((__unused__)) 4#define __used __attribute__((__unused__))
5#define unlikely 5#define unlikely
6#define READ_ONCE(x) (x)
6#define WRITE_ONCE(x, val) x=(val) 7#define WRITE_ONCE(x, val) x=(val)
7#define RCU_INIT_POINTER(p, v) p=(v) 8#define RCU_INIT_POINTER(p, v) p=(v)
8 9
diff --git a/tools/lib/traceevent/event-parse.c b/tools/lib/traceevent/event-parse.c
index c3bd294a63d1..190cc886ab91 100644
--- a/tools/lib/traceevent/event-parse.c
+++ b/tools/lib/traceevent/event-parse.c
@@ -1951,6 +1951,7 @@ process_op(struct event_format *event, struct print_arg *arg, char **tok)
1951 strcmp(token, "*") == 0 || 1951 strcmp(token, "*") == 0 ||
1952 strcmp(token, "^") == 0 || 1952 strcmp(token, "^") == 0 ||
1953 strcmp(token, "/") == 0 || 1953 strcmp(token, "/") == 0 ||
1954 strcmp(token, "%") == 0 ||
1954 strcmp(token, "<") == 0 || 1955 strcmp(token, "<") == 0 ||
1955 strcmp(token, ">") == 0 || 1956 strcmp(token, ">") == 0 ||
1956 strcmp(token, "<=") == 0 || 1957 strcmp(token, "<=") == 0 ||
@@ -2397,6 +2398,12 @@ static int arg_num_eval(struct print_arg *arg, long long *val)
2397 break; 2398 break;
2398 *val = left + right; 2399 *val = left + right;
2399 break; 2400 break;
2401 case '~':
2402 ret = arg_num_eval(arg->op.right, &right);
2403 if (!ret)
2404 break;
2405 *val = ~right;
2406 break;
2400 default: 2407 default:
2401 do_warning("unknown op '%s'", arg->op.op); 2408 do_warning("unknown op '%s'", arg->op.op);
2402 ret = 0; 2409 ret = 0;
@@ -2634,6 +2641,7 @@ process_hex(struct event_format *event, struct print_arg *arg, char **tok)
2634 2641
2635free_field: 2642free_field:
2636 free_arg(arg->hex.field); 2643 free_arg(arg->hex.field);
2644 arg->hex.field = NULL;
2637out: 2645out:
2638 *tok = NULL; 2646 *tok = NULL;
2639 return EVENT_ERROR; 2647 return EVENT_ERROR;
@@ -2658,8 +2666,10 @@ process_int_array(struct event_format *event, struct print_arg *arg, char **tok)
2658 2666
2659free_size: 2667free_size:
2660 free_arg(arg->int_array.count); 2668 free_arg(arg->int_array.count);
2669 arg->int_array.count = NULL;
2661free_field: 2670free_field:
2662 free_arg(arg->int_array.field); 2671 free_arg(arg->int_array.field);
2672 arg->int_array.field = NULL;
2663out: 2673out:
2664 *tok = NULL; 2674 *tok = NULL;
2665 return EVENT_ERROR; 2675 return EVENT_ERROR;
@@ -3689,6 +3699,9 @@ eval_num_arg(void *data, int size, struct event_format *event, struct print_arg
3689 case '/': 3699 case '/':
3690 val = left / right; 3700 val = left / right;
3691 break; 3701 break;
3702 case '%':
3703 val = left % right;
3704 break;
3692 case '*': 3705 case '*':
3693 val = left * right; 3706 val = left * right;
3694 break; 3707 break;
@@ -4971,7 +4984,7 @@ static void pretty_print(struct trace_seq *s, void *data, int size, struct event
4971 break; 4984 break;
4972 } 4985 }
4973 } 4986 }
4974 if (pevent->long_size == 8 && ls && 4987 if (pevent->long_size == 8 && ls == 1 &&
4975 sizeof(long) != 8) { 4988 sizeof(long) != 8) {
4976 char *p; 4989 char *p;
4977 4990
@@ -5335,41 +5348,45 @@ static bool is_timestamp_in_us(char *trace_clock, bool use_trace_clock)
5335 return false; 5348 return false;
5336} 5349}
5337 5350
5338void pevent_print_event(struct pevent *pevent, struct trace_seq *s, 5351/**
5339 struct pevent_record *record, bool use_trace_clock) 5352 * pevent_find_event_by_record - return the event from a given record
5353 * @pevent: a handle to the pevent
5354 * @record: The record to get the event from
5355 *
5356 * Returns the associated event for a given record, or NULL if non is
5357 * is found.
5358 */
5359struct event_format *
5360pevent_find_event_by_record(struct pevent *pevent, struct pevent_record *record)
5340{ 5361{
5341 static const char *spaces = " "; /* 20 spaces */
5342 struct event_format *event;
5343 unsigned long secs;
5344 unsigned long usecs;
5345 unsigned long nsecs;
5346 const char *comm;
5347 void *data = record->data;
5348 int type; 5362 int type;
5349 int pid;
5350 int len;
5351 int p;
5352 bool use_usec_format;
5353
5354 use_usec_format = is_timestamp_in_us(pevent->trace_clock,
5355 use_trace_clock);
5356 if (use_usec_format) {
5357 secs = record->ts / NSECS_PER_SEC;
5358 nsecs = record->ts - secs * NSECS_PER_SEC;
5359 }
5360 5363
5361 if (record->size < 0) { 5364 if (record->size < 0) {
5362 do_warning("ug! negative record size %d", record->size); 5365 do_warning("ug! negative record size %d", record->size);
5363 return; 5366 return NULL;
5364 } 5367 }
5365 5368
5366 type = trace_parse_common_type(pevent, data); 5369 type = trace_parse_common_type(pevent, record->data);
5367 5370
5368 event = pevent_find_event(pevent, type); 5371 return pevent_find_event(pevent, type);
5369 if (!event) { 5372}
5370 do_warning("ug! no event found for type %d", type); 5373
5371 return; 5374/**
5372 } 5375 * pevent_print_event_task - Write the event task comm, pid and CPU
5376 * @pevent: a handle to the pevent
5377 * @s: the trace_seq to write to
5378 * @event: the handle to the record's event
5379 * @record: The record to get the event from
5380 *
5381 * Writes the tasks comm, pid and CPU to @s.
5382 */
5383void pevent_print_event_task(struct pevent *pevent, struct trace_seq *s,
5384 struct event_format *event,
5385 struct pevent_record *record)
5386{
5387 void *data = record->data;
5388 const char *comm;
5389 int pid;
5373 5390
5374 pid = parse_common_pid(pevent, data); 5391 pid = parse_common_pid(pevent, data);
5375 comm = find_cmdline(pevent, pid); 5392 comm = find_cmdline(pevent, pid);
@@ -5377,9 +5394,43 @@ void pevent_print_event(struct pevent *pevent, struct trace_seq *s,
5377 if (pevent->latency_format) { 5394 if (pevent->latency_format) {
5378 trace_seq_printf(s, "%8.8s-%-5d %3d", 5395 trace_seq_printf(s, "%8.8s-%-5d %3d",
5379 comm, pid, record->cpu); 5396 comm, pid, record->cpu);
5380 pevent_data_lat_fmt(pevent, s, record);
5381 } else 5397 } else
5382 trace_seq_printf(s, "%16s-%-5d [%03d]", comm, pid, record->cpu); 5398 trace_seq_printf(s, "%16s-%-5d [%03d]", comm, pid, record->cpu);
5399}
5400
5401/**
5402 * pevent_print_event_time - Write the event timestamp
5403 * @pevent: a handle to the pevent
5404 * @s: the trace_seq to write to
5405 * @event: the handle to the record's event
5406 * @record: The record to get the event from
5407 * @use_trace_clock: Set to parse according to the @pevent->trace_clock
5408 *
5409 * Writes the timestamp of the record into @s.
5410 */
5411void pevent_print_event_time(struct pevent *pevent, struct trace_seq *s,
5412 struct event_format *event,
5413 struct pevent_record *record,
5414 bool use_trace_clock)
5415{
5416 unsigned long secs;
5417 unsigned long usecs;
5418 unsigned long nsecs;
5419 int p;
5420 bool use_usec_format;
5421
5422 use_usec_format = is_timestamp_in_us(pevent->trace_clock,
5423 use_trace_clock);
5424 if (use_usec_format) {
5425 secs = record->ts / NSECS_PER_SEC;
5426 nsecs = record->ts - secs * NSECS_PER_SEC;
5427 }
5428
5429 if (pevent->latency_format) {
5430 trace_seq_printf(s, " %3d", record->cpu);
5431 pevent_data_lat_fmt(pevent, s, record);
5432 } else
5433 trace_seq_printf(s, " [%03d]", record->cpu);
5383 5434
5384 if (use_usec_format) { 5435 if (use_usec_format) {
5385 if (pevent->flags & PEVENT_NSEC_OUTPUT) { 5436 if (pevent->flags & PEVENT_NSEC_OUTPUT) {
@@ -5387,14 +5438,36 @@ void pevent_print_event(struct pevent *pevent, struct trace_seq *s,
5387 p = 9; 5438 p = 9;
5388 } else { 5439 } else {
5389 usecs = (nsecs + 500) / NSECS_PER_USEC; 5440 usecs = (nsecs + 500) / NSECS_PER_USEC;
5441 /* To avoid usecs larger than 1 sec */
5442 if (usecs >= 1000000) {
5443 usecs -= 1000000;
5444 secs++;
5445 }
5390 p = 6; 5446 p = 6;
5391 } 5447 }
5392 5448
5393 trace_seq_printf(s, " %5lu.%0*lu: %s: ", 5449 trace_seq_printf(s, " %5lu.%0*lu:", secs, p, usecs);
5394 secs, p, usecs, event->name);
5395 } else 5450 } else
5396 trace_seq_printf(s, " %12llu: %s: ", 5451 trace_seq_printf(s, " %12llu:", record->ts);
5397 record->ts, event->name); 5452}
5453
5454/**
5455 * pevent_print_event_data - Write the event data section
5456 * @pevent: a handle to the pevent
5457 * @s: the trace_seq to write to
5458 * @event: the handle to the record's event
5459 * @record: The record to get the event from
5460 *
5461 * Writes the parsing of the record's data to @s.
5462 */
5463void pevent_print_event_data(struct pevent *pevent, struct trace_seq *s,
5464 struct event_format *event,
5465 struct pevent_record *record)
5466{
5467 static const char *spaces = " "; /* 20 spaces */
5468 int len;
5469
5470 trace_seq_printf(s, " %s: ", event->name);
5398 5471
5399 /* Space out the event names evenly. */ 5472 /* Space out the event names evenly. */
5400 len = strlen(event->name); 5473 len = strlen(event->name);
@@ -5404,6 +5477,23 @@ void pevent_print_event(struct pevent *pevent, struct trace_seq *s,
5404 pevent_event_info(s, event, record); 5477 pevent_event_info(s, event, record);
5405} 5478}
5406 5479
5480void pevent_print_event(struct pevent *pevent, struct trace_seq *s,
5481 struct pevent_record *record, bool use_trace_clock)
5482{
5483 struct event_format *event;
5484
5485 event = pevent_find_event_by_record(pevent, record);
5486 if (!event) {
5487 do_warning("ug! no event found for type %d",
5488 trace_parse_common_type(pevent, record->data));
5489 return;
5490 }
5491
5492 pevent_print_event_task(pevent, s, event, record);
5493 pevent_print_event_time(pevent, s, event, record, use_trace_clock);
5494 pevent_print_event_data(pevent, s, event, record);
5495}
5496
5407static int events_id_cmp(const void *a, const void *b) 5497static int events_id_cmp(const void *a, const void *b)
5408{ 5498{
5409 struct event_format * const * ea = a; 5499 struct event_format * const * ea = a;
diff --git a/tools/lib/traceevent/event-parse.h b/tools/lib/traceevent/event-parse.h
index 706d9bc24066..9ffde377e89d 100644
--- a/tools/lib/traceevent/event-parse.h
+++ b/tools/lib/traceevent/event-parse.h
@@ -628,6 +628,16 @@ int pevent_register_print_string(struct pevent *pevent, const char *fmt,
628 unsigned long long addr); 628 unsigned long long addr);
629int pevent_pid_is_registered(struct pevent *pevent, int pid); 629int pevent_pid_is_registered(struct pevent *pevent, int pid);
630 630
631void pevent_print_event_task(struct pevent *pevent, struct trace_seq *s,
632 struct event_format *event,
633 struct pevent_record *record);
634void pevent_print_event_time(struct pevent *pevent, struct trace_seq *s,
635 struct event_format *event,
636 struct pevent_record *record,
637 bool use_trace_clock);
638void pevent_print_event_data(struct pevent *pevent, struct trace_seq *s,
639 struct event_format *event,
640 struct pevent_record *record);
631void pevent_print_event(struct pevent *pevent, struct trace_seq *s, 641void pevent_print_event(struct pevent *pevent, struct trace_seq *s,
632 struct pevent_record *record, bool use_trace_clock); 642 struct pevent_record *record, bool use_trace_clock);
633 643
@@ -694,6 +704,9 @@ struct event_format *pevent_find_event(struct pevent *pevent, int id);
694struct event_format * 704struct event_format *
695pevent_find_event_by_name(struct pevent *pevent, const char *sys, const char *name); 705pevent_find_event_by_name(struct pevent *pevent, const char *sys, const char *name);
696 706
707struct event_format *
708pevent_find_event_by_record(struct pevent *pevent, struct pevent_record *record);
709
697void pevent_data_lat_fmt(struct pevent *pevent, 710void pevent_data_lat_fmt(struct pevent *pevent,
698 struct trace_seq *s, struct pevent_record *record); 711 struct trace_seq *s, struct pevent_record *record);
699int pevent_data_type(struct pevent *pevent, struct pevent_record *rec); 712int pevent_data_type(struct pevent *pevent, struct pevent_record *rec);
diff --git a/tools/perf/Documentation/perf-config.txt b/tools/perf/Documentation/perf-config.txt
index b9ca1e304158..15949e2a7805 100644
--- a/tools/perf/Documentation/perf-config.txt
+++ b/tools/perf/Documentation/perf-config.txt
@@ -8,7 +8,7 @@ perf-config - Get and set variables in a configuration file.
8SYNOPSIS 8SYNOPSIS
9-------- 9--------
10[verse] 10[verse]
11'perf config' -l | --list 11'perf config' [<file-option>] -l | --list
12 12
13DESCRIPTION 13DESCRIPTION
14----------- 14-----------
@@ -21,6 +21,14 @@ OPTIONS
21--list:: 21--list::
22 Show current config variables, name and value, for all sections. 22 Show current config variables, name and value, for all sections.
23 23
24--user::
25 For writing and reading options: write to user
26 '$HOME/.perfconfig' file or read it.
27
28--system::
29 For writing and reading options: write to system-wide
30 '$(sysconfdir)/perfconfig' or read it.
31
24CONFIGURATION FILE 32CONFIGURATION FILE
25------------------ 33------------------
26 34
@@ -30,6 +38,10 @@ The '$HOME/.perfconfig' file is used to store a per-user configuration.
30The file '$(sysconfdir)/perfconfig' can be used to 38The file '$(sysconfdir)/perfconfig' can be used to
31store a system-wide default configuration. 39store a system-wide default configuration.
32 40
41When reading or writing, the values are read from the system and user
42configuration files by default, and options '--system' and '--user'
43can be used to tell the command to read from or write to only that location.
44
33Syntax 45Syntax
34~~~~~~ 46~~~~~~
35 47
@@ -62,7 +74,7 @@ Given a $HOME/.perfconfig like this:
62 medium = green, default 74 medium = green, default
63 normal = lightgray, default 75 normal = lightgray, default
64 selected = white, lightgray 76 selected = white, lightgray
65 code = blue, default 77 jump_arrows = blue, default
66 addr = magenta, default 78 addr = magenta, default
67 root = white, blue 79 root = white, blue
68 80
@@ -98,6 +110,347 @@ Given a $HOME/.perfconfig like this:
98 order = caller 110 order = caller
99 sort-key = function 111 sort-key = function
100 112
113Variables
114~~~~~~~~~
115
116colors.*::
117 The variables for customizing the colors used in the output for the
118 'report', 'top' and 'annotate' in the TUI. They should specify the
119 foreground and background colors, separated by a comma, for example:
120
121 medium = green, lightgray
122
123 If you want to use the color configured for you terminal, just leave it
124 as 'default', for example:
125
126 medium = default, lightgray
127
128 Available colors:
129 red, yellow, green, cyan, gray, black, blue,
130 white, default, magenta, lightgray
131
132 colors.top::
133 'top' means a overhead percentage which is more than 5%.
134 And values of this variable specify percentage colors.
135 Basic key values are foreground-color 'red' and
136 background-color 'default'.
137 colors.medium::
138 'medium' means a overhead percentage which has more than 0.5%.
139 Default values are 'green' and 'default'.
140 colors.normal::
141 'normal' means the rest of overhead percentages
142 except 'top', 'medium', 'selected'.
143 Default values are 'lightgray' and 'default'.
144 colors.selected::
145 This selects the colors for the current entry in a list of entries
146 from sub-commands (top, report, annotate).
147 Default values are 'black' and 'lightgray'.
148 colors.jump_arrows::
149 Colors for jump arrows on assembly code listings
150 such as 'jns', 'jmp', 'jane', etc.
151 Default values are 'blue', 'default'.
152 colors.addr::
153 This selects colors for addresses from 'annotate'.
154 Default values are 'magenta', 'default'.
155 colors.root::
156 Colors for headers in the output of a sub-commands (top, report).
157 Default values are 'white', 'blue'.
158
159tui.*, gtk.*::
160 Subcommands that can be configured here are 'top', 'report' and 'annotate'.
161 These values are booleans, for example:
162
163 [tui]
164 top = true
165
166 will make the TUI be the default for the 'top' subcommand. Those will be
167 available if the required libs were detected at tool build time.
168
169buildid.*::
170 buildid.dir::
171 Each executable and shared library in modern distributions comes with a
172 content based identifier that, if available, will be inserted in a
173 'perf.data' file header to, at analysis time find what is needed to do
174 symbol resolution, code annotation, etc.
175
176 The recording tools also stores a hard link or copy in a per-user
177 directory, $HOME/.debug/, of binaries, shared libraries, /proc/kallsyms
178 and /proc/kcore files to be used at analysis time.
179
180 The buildid.dir variable can be used to either change this directory
181 cache location, or to disable it altogether. If you want to disable it,
182 set buildid.dir to /dev/null. The default is $HOME/.debug
183
184annotate.*::
185 These options work only for TUI.
186 These are in control of addresses, jump function, source code
187 in lines of assembly code from a specific program.
188
189 annotate.hide_src_code::
190 If a program which is analyzed has source code,
191 this option lets 'annotate' print a list of assembly code with the source code.
192 For example, let's see a part of a program. There're four lines.
193 If this option is 'true', they can be printed
194 without source code from a program as below.
195
196 │ push %rbp
197 │ mov %rsp,%rbp
198 │ sub $0x10,%rsp
199 │ mov (%rdi),%rdx
200
201 But if this option is 'false', source code of the part
202 can be also printed as below. Default is 'false'.
203
204 │ struct rb_node *rb_next(const struct rb_node *node)
205 │ {
206 │ push %rbp
207 │ mov %rsp,%rbp
208 │ sub $0x10,%rsp
209 │ struct rb_node *parent;
210 │
211 │ if (RB_EMPTY_NODE(node))
212 │ mov (%rdi),%rdx
213 │ return n;
214
215 annotate.use_offset::
216 Basing on a first address of a loaded function, offset can be used.
217 Instead of using original addresses of assembly code,
218 addresses subtracted from a base address can be printed.
219 Let's illustrate an example.
220 If a base address is 0XFFFFFFFF81624d50 as below,
221
222 ffffffff81624d50 <load0>
223
224 an address on assembly code has a specific absolute address as below
225
226 ffffffff816250b8:│ mov 0x8(%r14),%rdi
227
228 but if use_offset is 'true', an address subtracted from a base address is printed.
229 Default is true. This option is only applied to TUI.
230
231 368:│ mov 0x8(%r14),%rdi
232
233 annotate.jump_arrows::
234 There can be jump instruction among assembly code.
235 Depending on a boolean value of jump_arrows,
236 arrows can be printed or not which represent
237 where do the instruction jump into as below.
238
239 │ ┌──jmp 1333
240 │ │ xchg %ax,%ax
241 │1330:│ mov %r15,%r10
242 │1333:└─→cmp %r15,%r14
243
244 If jump_arrow is 'false', the arrows isn't printed as below.
245 Default is 'false'.
246
247 │ ↓ jmp 1333
248 │ xchg %ax,%ax
249 │1330: mov %r15,%r10
250 │1333: cmp %r15,%r14
251
252 annotate.show_linenr::
253 When showing source code if this option is 'true',
254 line numbers are printed as below.
255
256 │1628 if (type & PERF_SAMPLE_IDENTIFIER) {
257 │ ↓ jne 508
258 │1628 data->id = *array;
259 │1629 array++;
260 │1630 }
261
262 However if this option is 'false', they aren't printed as below.
263 Default is 'false'.
264
265 │ if (type & PERF_SAMPLE_IDENTIFIER) {
266 │ ↓ jne 508
267 │ data->id = *array;
268 │ array++;
269 │ }
270
271 annotate.show_nr_jumps::
272 Let's see a part of assembly code.
273
274 │1382: movb $0x1,-0x270(%rbp)
275
276 If use this, the number of branches jumping to that address can be printed as below.
277 Default is 'false'.
278
279 │1 1382: movb $0x1,-0x270(%rbp)
280
281 annotate.show_total_period::
282 To compare two records on an instruction base, with this option
283 provided, display total number of samples that belong to a line
284 in assembly code. If this option is 'true', total periods are printed
285 instead of percent values as below.
286
287 302 │ mov %eax,%eax
288
289 But if this option is 'false', percent values for overhead are printed i.e.
290 Default is 'false'.
291
292 99.93 │ mov %eax,%eax
293
294hist.*::
295 hist.percentage::
296 This option control the way to calculate overhead of filtered entries -
297 that means the value of this option is effective only if there's a
298 filter (by comm, dso or symbol name). Suppose a following example:
299
300 Overhead Symbols
301 ........ .......
302 33.33% foo
303 33.33% bar
304 33.33% baz
305
306 This is an original overhead and we'll filter out the first 'foo'
307 entry. The value of 'relative' would increase the overhead of 'bar'
308 and 'baz' to 50.00% for each, while 'absolute' would show their
309 current overhead (33.33%).
310
311ui.*::
312 ui.show-headers::
313 This option controls display of column headers (like 'Overhead' and 'Symbol')
314 in 'report' and 'top'. If this option is false, they are hidden.
315 This option is only applied to TUI.
316
317call-graph.*::
318 When sub-commands 'top' and 'report' work with -g/—-children
319 there're options in control of call-graph.
320
321 call-graph.record-mode::
322 The record-mode can be 'fp' (frame pointer), 'dwarf' and 'lbr'.
323 The value of 'dwarf' is effective only if perf detect needed library
324 (libunwind or a recent version of libdw).
325 'lbr' only work for cpus that support it.
326
327 call-graph.dump-size::
328 The size of stack to dump in order to do post-unwinding. Default is 8192 (byte).
329 When using dwarf into record-mode, the default size will be used if omitted.
330
331 call-graph.print-type::
332 The print-types can be graph (graph absolute), fractal (graph relative),
333 flat and folded. This option controls a way to show overhead for each callchain
334 entry. Suppose a following example.
335
336 Overhead Symbols
337 ........ .......
338 40.00% foo
339 |
340 ---foo
341 |
342 |--50.00%--bar
343 | main
344 |
345 --50.00%--baz
346 main
347
348 This output is a 'fractal' format. The 'foo' came from 'bar' and 'baz' exactly
349 half and half so 'fractal' shows 50.00% for each
350 (meaning that it assumes 100% total overhead of 'foo').
351
352 The 'graph' uses absolute overhead value of 'foo' as total so each of
353 'bar' and 'baz' callchain will have 20.00% of overhead.
354 If 'flat' is used, single column and linear exposure of call chains.
355 'folded' mean call chains are displayed in a line, separated by semicolons.
356
357 call-graph.order::
358 This option controls print order of callchains. The default is
359 'callee' which means callee is printed at top and then followed by its
360 caller and so on. The 'caller' prints it in reverse order.
361
362 If this option is not set and report.children or top.children is
363 set to true (or the equivalent command line option is given),
364 the default value of this option is changed to 'caller' for the
365 execution of 'perf report' or 'perf top'. Other commands will
366 still default to 'callee'.
367
368 call-graph.sort-key::
369 The callchains are merged if they contain same information.
370 The sort-key option determines a way to compare the callchains.
371 A value of 'sort-key' can be 'function' or 'address'.
372 The default is 'function'.
373
374 call-graph.threshold::
375 When there're many callchains it'd print tons of lines. So perf omits
376 small callchains under a certain overhead (threshold) and this option
377 control the threshold. Default is 0.5 (%). The overhead is calculated
378 by value depends on call-graph.print-type.
379
380 call-graph.print-limit::
381 This is a maximum number of lines of callchain printed for a single
382 histogram entry. Default is 0 which means no limitation.
383
384report.*::
385 report.percent-limit::
386 This one is mostly the same as call-graph.threshold but works for
387 histogram entries. Entries having an overhead lower than this
388 percentage will not be printed. Default is '0'. If percent-limit
389 is '10', only entries which have more than 10% of overhead will be
390 printed.
391
392 report.queue-size::
393 This option sets up the maximum allocation size of the internal
394 event queue for ordering events. Default is 0, meaning no limit.
395
396 report.children::
397 'Children' means functions called from another function.
398 If this option is true, 'perf report' cumulates callchains of children
399 and show (accumulated) total overhead as well as 'Self' overhead.
400 Please refer to the 'perf report' manual. The default is 'true'.
401
402 report.group::
403 This option is to show event group information together.
404 Example output with this turned on, notice that there is one column
405 per event in the group, ref-cycles and cycles:
406
407 # group: {ref-cycles,cycles}
408 # ========
409 #
410 # Samples: 7K of event 'anon group { ref-cycles, cycles }'
411 # Event count (approx.): 6876107743
412 #
413 # Overhead Command Shared Object Symbol
414 # ................ ....... ................. ...................
415 #
416 99.84% 99.76% noploop noploop [.] main
417 0.07% 0.00% noploop ld-2.15.so [.] strcmp
418 0.03% 0.00% noploop [kernel.kallsyms] [k] timerqueue_del
419
420top.*::
421 top.children::
422 Same as 'report.children'. So if it is enabled, the output of 'top'
423 command will have 'Children' overhead column as well as 'Self' overhead
424 column by default.
425 The default is 'true'.
426
427man.*::
428 man.viewer::
429 This option can assign a tool to view manual pages when 'help'
430 subcommand was invoked. Supported tools are 'man', 'woman'
431 (with emacs client) and 'konqueror'. Default is 'man'.
432
433 New man viewer tool can be also added using 'man.<tool>.cmd'
434 or use different path using 'man.<tool>.path' config option.
435
436pager.*::
437 pager.<subcommand>::
438 When the subcommand is run on stdio, determine whether it uses
439 pager or not based on this value. Default is 'unspecified'.
440
441kmem.*::
442 kmem.default::
443 This option decides which allocator is to be analyzed if neither
444 '--slab' nor '--page' option is used. Default is 'slab'.
445
446record.*::
447 record.build-id::
448 This option can be 'cache', 'no-cache' or 'skip'.
449 'cache' is to post-process data and save/update the binaries into
450 the build-id cache (in ~/.debug). This is the default.
451 But if this option is 'no-cache', it will not update the build-id cache.
452 'skip' skips post-processing and does not update the cache.
453
101SEE ALSO 454SEE ALSO
102-------- 455--------
103linkperf:perf[1] 456linkperf:perf[1]
diff --git a/tools/perf/Documentation/perf-inject.txt b/tools/perf/Documentation/perf-inject.txt
index 0b1cedeef895..87b2588d1cbd 100644
--- a/tools/perf/Documentation/perf-inject.txt
+++ b/tools/perf/Documentation/perf-inject.txt
@@ -53,6 +53,13 @@ include::itrace.txt[]
53--strip:: 53--strip::
54 Use with --itrace to strip out non-synthesized events. 54 Use with --itrace to strip out non-synthesized events.
55 55
56-j::
57--jit::
58 Process jitdump files by injecting the mmap records corresponding to jitted
59 functions. This option also generates the ELF images for each jitted function
60 found in the jitdumps files captured in the input perf.data file. Use this option
61 if you are monitoring environment using JIT runtimes, such as Java, DART or V8.
62
56SEE ALSO 63SEE ALSO
57-------- 64--------
58linkperf:perf-record[1], linkperf:perf-report[1], linkperf:perf-archive[1] 65linkperf:perf-record[1], linkperf:perf-report[1], linkperf:perf-archive[1]
diff --git a/tools/perf/Documentation/perf-record.txt b/tools/perf/Documentation/perf-record.txt
index fbceb631387c..19aa17532a16 100644
--- a/tools/perf/Documentation/perf-record.txt
+++ b/tools/perf/Documentation/perf-record.txt
@@ -341,6 +341,12 @@ Specify vmlinux path which has debuginfo.
341--buildid-all:: 341--buildid-all::
342Record build-id of all DSOs regardless whether it's actually hit or not. 342Record build-id of all DSOs regardless whether it's actually hit or not.
343 343
344--all-kernel::
345Configure all used events to run in kernel space.
346
347--all-user::
348Configure all used events to run in user space.
349
344SEE ALSO 350SEE ALSO
345-------- 351--------
346linkperf:perf-stat[1], linkperf:perf-list[1] 352linkperf:perf-stat[1], linkperf:perf-list[1]
diff --git a/tools/perf/Documentation/perf-report.txt b/tools/perf/Documentation/perf-report.txt
index 8a301f6afb37..12113992ac9d 100644
--- a/tools/perf/Documentation/perf-report.txt
+++ b/tools/perf/Documentation/perf-report.txt
@@ -117,6 +117,22 @@ OPTIONS
117 And default sort keys are changed to comm, dso_from, symbol_from, dso_to 117 And default sort keys are changed to comm, dso_from, symbol_from, dso_to
118 and symbol_to, see '--branch-stack'. 118 and symbol_to, see '--branch-stack'.
119 119
120 If the --mem-mode option is used, the following sort keys are also available
121 (incompatible with --branch-stack):
122 symbol_daddr, dso_daddr, locked, tlb, mem, snoop, dcacheline.
123
124 - symbol_daddr: name of data symbol being executed on at the time of sample
125 - dso_daddr: name of library or module containing the data being executed
126 on at the time of the sample
127 - locked: whether the bus was locked at the time of the sample
128 - tlb: type of tlb access for the data at the time of the sample
129 - mem: type of memory access for the data at the time of the sample
130 - snoop: type of snoop (if any) for the data at the time of the sample
131 - dcacheline: the cacheline the data address is on at the time of the sample
132
133 And the default sort keys are changed to local_weight, mem, sym, dso,
134 symbol_daddr, dso_daddr, snoop, tlb, locked, see '--mem-mode'.
135
120 If the data file has tracepoint event(s), following (dynamic) sort keys 136 If the data file has tracepoint event(s), following (dynamic) sort keys
121 are also available: 137 are also available:
122 trace, trace_fields, [<event>.]<field>[/raw] 138 trace, trace_fields, [<event>.]<field>[/raw]
@@ -151,22 +167,6 @@ OPTIONS
151 By default, every sort keys not specified in -F will be appended 167 By default, every sort keys not specified in -F will be appended
152 automatically. 168 automatically.
153 169
154 If --mem-mode option is used, following sort keys are also available
155 (incompatible with --branch-stack):
156 symbol_daddr, dso_daddr, locked, tlb, mem, snoop, dcacheline.
157
158 - symbol_daddr: name of data symbol being executed on at the time of sample
159 - dso_daddr: name of library or module containing the data being executed
160 on at the time of sample
161 - locked: whether the bus was locked at the time of sample
162 - tlb: type of tlb access for the data at the time of sample
163 - mem: type of memory access for the data at the time of sample
164 - snoop: type of snoop (if any) for the data at the time of sample
165 - dcacheline: the cacheline the data address is on at the time of sample
166
167 And default sort keys are changed to local_weight, mem, sym, dso,
168 symbol_daddr, dso_daddr, snoop, tlb, locked, see '--mem-mode'.
169
170-p:: 170-p::
171--parent=<regex>:: 171--parent=<regex>::
172 A regex filter to identify parent. The parent is a caller of this 172 A regex filter to identify parent. The parent is a caller of this
@@ -351,7 +351,10 @@ OPTIONS
351 351
352--percent-limit:: 352--percent-limit::
353 Do not show entries which have an overhead under that percent. 353 Do not show entries which have an overhead under that percent.
354 (Default: 0). 354 (Default: 0). Note that this option also sets the percent limit (threshold)
355 of callchains. However the default value of callchain threshold is
356 different than the default value of hist entries. Please see the
357 --call-graph option for details.
355 358
356--percentage:: 359--percentage::
357 Determine how to display the overhead percentage of filtered entries. 360 Determine how to display the overhead percentage of filtered entries.
@@ -398,6 +401,9 @@ include::itrace.txt[]
398--raw-trace:: 401--raw-trace::
399 When displaying traceevent output, do not use print fmt or plugins. 402 When displaying traceevent output, do not use print fmt or plugins.
400 403
404--hierarchy::
405 Enable hierarchical output.
406
401include::callchain-overhead-calculation.txt[] 407include::callchain-overhead-calculation.txt[]
402 408
403SEE ALSO 409SEE ALSO
diff --git a/tools/perf/Documentation/perf-stat.txt b/tools/perf/Documentation/perf-stat.txt
index 52ef7a9d50aa..04f23b404bbc 100644
--- a/tools/perf/Documentation/perf-stat.txt
+++ b/tools/perf/Documentation/perf-stat.txt
@@ -69,6 +69,14 @@ report::
69--scale:: 69--scale::
70 scale/normalize counter values 70 scale/normalize counter values
71 71
72-d::
73--detailed::
74 print more detailed statistics, can be specified up to 3 times
75
76 -d: detailed events, L1 and LLC data cache
77 -d -d: more detailed events, dTLB and iTLB events
78 -d -d -d: very detailed events, adding prefetch events
79
72-r:: 80-r::
73--repeat=<n>:: 81--repeat=<n>::
74 repeat command and print average + stddev (max: 100). 0 means forever. 82 repeat command and print average + stddev (max: 100). 0 means forever.
@@ -139,6 +147,10 @@ Print count deltas every N milliseconds (minimum: 10ms)
139The overhead percentage could be high in some cases, for instance with small, sub 100ms intervals. Use with caution. 147The overhead percentage could be high in some cases, for instance with small, sub 100ms intervals. Use with caution.
140 example: 'perf stat -I 1000 -e cycles -a sleep 5' 148 example: 'perf stat -I 1000 -e cycles -a sleep 5'
141 149
150--metric-only::
151Only print computed metrics. Print them in a single line.
152Don't show any raw values. Not supported with --per-thread.
153
142--per-socket:: 154--per-socket::
143Aggregate counts per processor socket for system-wide mode measurements. This 155Aggregate counts per processor socket for system-wide mode measurements. This
144is a useful mode to detect imbalance between sockets. To enable this mode, 156is a useful mode to detect imbalance between sockets. To enable this mode,
@@ -211,6 +223,29 @@ $ perf stat -- make -j
211 223
212 Wall-clock time elapsed: 719.554352 msecs 224 Wall-clock time elapsed: 719.554352 msecs
213 225
226CSV FORMAT
227----------
228
229With -x, perf stat is able to output a not-quite-CSV format output
230Commas in the output are not put into "". To make it easy to parse
231it is recommended to use a different character like -x \;
232
233The fields are in this order:
234
235 - optional usec time stamp in fractions of second (with -I xxx)
236 - optional CPU, core, or socket identifier
237 - optional number of logical CPUs aggregated
238 - counter value
239 - unit of the counter value or empty
240 - event name
241 - run time of counter
242 - percentage of measurement time the counter was running
243 - optional variance if multiple values are collected with -r
244 - optional metric value
245 - optional unit of metric
246
247Additional metrics may be printed with all earlier fields being empty.
248
214SEE ALSO 249SEE ALSO
215-------- 250--------
216linkperf:perf-top[1], linkperf:perf-list[1] 251linkperf:perf-top[1], linkperf:perf-list[1]
diff --git a/tools/perf/Documentation/perf-top.txt b/tools/perf/Documentation/perf-top.txt
index b0e60e17db38..19f046f027cd 100644
--- a/tools/perf/Documentation/perf-top.txt
+++ b/tools/perf/Documentation/perf-top.txt
@@ -233,6 +233,9 @@ Default is to monitor all CPUS.
233--raw-trace:: 233--raw-trace::
234 When displaying traceevent output, do not use print fmt or plugins. 234 When displaying traceevent output, do not use print fmt or plugins.
235 235
236--hierarchy::
237 Enable hierarchy output.
238
236INTERACTIVE PROMPTING KEYS 239INTERACTIVE PROMPTING KEYS
237-------------------------- 240--------------------------
238 241
diff --git a/tools/perf/Documentation/perfconfig.example b/tools/perf/Documentation/perfconfig.example
index 767ea2436e1c..1d8d5bc4cd2d 100644
--- a/tools/perf/Documentation/perfconfig.example
+++ b/tools/perf/Documentation/perfconfig.example
@@ -5,7 +5,7 @@
5 medium = green, lightgray 5 medium = green, lightgray
6 normal = black, lightgray 6 normal = black, lightgray
7 selected = lightgray, magenta 7 selected = lightgray, magenta
8 code = blue, lightgray 8 jump_arrows = blue, lightgray
9 addr = magenta, lightgray 9 addr = magenta, lightgray
10 10
11[tui] 11[tui]
diff --git a/tools/perf/Documentation/tips.txt b/tools/perf/Documentation/tips.txt
index e0ce9573b79b..5950b5a24efd 100644
--- a/tools/perf/Documentation/tips.txt
+++ b/tools/perf/Documentation/tips.txt
@@ -27,3 +27,4 @@ Skip collecing build-id when recording: perf record -B
27To change sampling frequency to 100 Hz: perf record -F 100 27To change sampling frequency to 100 Hz: perf record -F 100
28See assembly instructions with percentage: perf annotate <symbol> 28See assembly instructions with percentage: perf annotate <symbol>
29If you prefer Intel style assembly, try: perf annotate -M intel 29If you prefer Intel style assembly, try: perf annotate -M intel
30For hierarchical output, try: perf report --hierarchy
diff --git a/tools/perf/Makefile b/tools/perf/Makefile
index dcd9a70c7193..32a64e619028 100644
--- a/tools/perf/Makefile
+++ b/tools/perf/Makefile
@@ -68,6 +68,20 @@ all tags TAGS:
68 $(print_msg) 68 $(print_msg)
69 $(make) 69 $(make)
70 70
71ifdef MAKECMDGOALS
72has_clean := 0
73ifneq ($(filter clean,$(MAKECMDGOALS)),)
74 has_clean := 1
75endif # clean
76
77ifeq ($(has_clean),1)
78 rest := $(filter-out clean,$(MAKECMDGOALS))
79 ifneq ($(rest),)
80$(rest): clean
81 endif # rest
82endif # has_clean
83endif # MAKECMDGOALS
84
71# 85#
72# The clean target is not really parallel, don't print the jobs info: 86# The clean target is not really parallel, don't print the jobs info:
73# 87#
@@ -75,10 +89,17 @@ clean:
75 $(make) 89 $(make)
76 90
77# 91#
78# The build-test target is not really parallel, don't print the jobs info: 92# The build-test target is not really parallel, don't print the jobs info,
93# it also uses only the tests/make targets that don't pollute the source
94# repository, i.e. that uses O= or builds the tarpkg outside the source
95# repo directories.
96#
97# For a full test, use:
98#
99# make -C tools/perf -f tests/make
79# 100#
80build-test: 101build-test:
81 @$(MAKE) SHUF=1 -f tests/make --no-print-directory 102 @$(MAKE) SHUF=1 -f tests/make REUSE_FEATURES_DUMP=1 MK=Makefile SET_PARALLEL=1 --no-print-directory tarpkg out
82 103
83# 104#
84# All other targets get passed through: 105# All other targets get passed through:
diff --git a/tools/perf/Makefile.perf b/tools/perf/Makefile.perf
index 5d34815c7ccb..4a4fad4182f5 100644
--- a/tools/perf/Makefile.perf
+++ b/tools/perf/Makefile.perf
@@ -58,6 +58,9 @@ include config/utilities.mak
58# 58#
59# Define NO_LIBBIONIC if you do not want bionic support 59# Define NO_LIBBIONIC if you do not want bionic support
60# 60#
61# Define NO_LIBCRYPTO if you do not want libcrypto (openssl) support
62# used for generating build-ids for ELFs generated by jitdump.
63#
61# Define NO_LIBDW_DWARF_UNWIND if you do not want libdw support 64# Define NO_LIBDW_DWARF_UNWIND if you do not want libdw support
62# for dwarf backtrace post unwind. 65# for dwarf backtrace post unwind.
63# 66#
@@ -136,6 +139,8 @@ $(call allow-override,CC,$(CROSS_COMPILE)gcc)
136$(call allow-override,AR,$(CROSS_COMPILE)ar) 139$(call allow-override,AR,$(CROSS_COMPILE)ar)
137$(call allow-override,LD,$(CROSS_COMPILE)ld) 140$(call allow-override,LD,$(CROSS_COMPILE)ld)
138 141
142LD += $(EXTRA_LDFLAGS)
143
139PKG_CONFIG = $(CROSS_COMPILE)pkg-config 144PKG_CONFIG = $(CROSS_COMPILE)pkg-config
140 145
141RM = rm -f 146RM = rm -f
@@ -165,7 +170,16 @@ ifeq ($(filter-out $(NON_CONFIG_TARGETS),$(MAKECMDGOALS)),)
165endif 170endif
166endif 171endif
167 172
173# Set FEATURE_TESTS to 'all' so all possible feature checkers are executed.
174# Without this setting the output feature dump file misses some features, for
175# example, liberty. Select all checkers so we won't get an incomplete feature
176# dump file.
168ifeq ($(config),1) 177ifeq ($(config),1)
178ifdef MAKECMDGOALS
179ifeq ($(filter feature-dump,$(MAKECMDGOALS)),feature-dump)
180FEATURE_TESTS := all
181endif
182endif
169include config/Makefile 183include config/Makefile
170endif 184endif
171 185
@@ -618,7 +632,7 @@ clean: $(LIBTRACEEVENT)-clean $(LIBAPI)-clean $(LIBBPF)-clean $(LIBSUBCMD)-clean
618 $(call QUIET_CLEAN, core-progs) $(RM) $(ALL_PROGRAMS) perf perf-read-vdso32 perf-read-vdsox32 632 $(call QUIET_CLEAN, core-progs) $(RM) $(ALL_PROGRAMS) perf perf-read-vdso32 perf-read-vdsox32
619 $(call QUIET_CLEAN, core-gen) $(RM) *.spec *.pyc *.pyo */*.pyc */*.pyo $(OUTPUT)common-cmds.h TAGS tags cscope* $(OUTPUT)PERF-VERSION-FILE $(OUTPUT)FEATURE-DUMP $(OUTPUT)util/*-bison* $(OUTPUT)util/*-flex* \ 633 $(call QUIET_CLEAN, core-gen) $(RM) *.spec *.pyc *.pyo */*.pyc */*.pyo $(OUTPUT)common-cmds.h TAGS tags cscope* $(OUTPUT)PERF-VERSION-FILE $(OUTPUT)FEATURE-DUMP $(OUTPUT)util/*-bison* $(OUTPUT)util/*-flex* \
620 $(OUTPUT)util/intel-pt-decoder/inat-tables.c $(OUTPUT)fixdep \ 634 $(OUTPUT)util/intel-pt-decoder/inat-tables.c $(OUTPUT)fixdep \
621 $(OUTPUT)tests/llvm-src-{base,kbuild,prologue}.c 635 $(OUTPUT)tests/llvm-src-{base,kbuild,prologue,relocation}.c
622 $(QUIET_SUBDIR0)Documentation $(QUIET_SUBDIR1) clean 636 $(QUIET_SUBDIR0)Documentation $(QUIET_SUBDIR1) clean
623 $(python-clean) 637 $(python-clean)
624 638
diff --git a/tools/perf/arch/arm/Makefile b/tools/perf/arch/arm/Makefile
index 7fbca175099e..18b13518d8d8 100644
--- a/tools/perf/arch/arm/Makefile
+++ b/tools/perf/arch/arm/Makefile
@@ -1,3 +1,4 @@
1ifndef NO_DWARF 1ifndef NO_DWARF
2PERF_HAVE_DWARF_REGS := 1 2PERF_HAVE_DWARF_REGS := 1
3endif 3endif
4PERF_HAVE_JITDUMP := 1
diff --git a/tools/perf/arch/arm64/Makefile b/tools/perf/arch/arm64/Makefile
index 7fbca175099e..18b13518d8d8 100644
--- a/tools/perf/arch/arm64/Makefile
+++ b/tools/perf/arch/arm64/Makefile
@@ -1,3 +1,4 @@
1ifndef NO_DWARF 1ifndef NO_DWARF
2PERF_HAVE_DWARF_REGS := 1 2PERF_HAVE_DWARF_REGS := 1
3endif 3endif
4PERF_HAVE_JITDUMP := 1
diff --git a/tools/perf/arch/powerpc/Makefile b/tools/perf/arch/powerpc/Makefile
index 7fbca175099e..56e05f126ad8 100644
--- a/tools/perf/arch/powerpc/Makefile
+++ b/tools/perf/arch/powerpc/Makefile
@@ -1,3 +1,6 @@
1ifndef NO_DWARF 1ifndef NO_DWARF
2PERF_HAVE_DWARF_REGS := 1 2PERF_HAVE_DWARF_REGS := 1
3endif 3endif
4
5HAVE_KVM_STAT_SUPPORT := 1
6PERF_HAVE_JITDUMP := 1
diff --git a/tools/perf/arch/powerpc/util/Build b/tools/perf/arch/powerpc/util/Build
index 7b8b0d1a1b62..c8fe2074d217 100644
--- a/tools/perf/arch/powerpc/util/Build
+++ b/tools/perf/arch/powerpc/util/Build
@@ -1,5 +1,6 @@
1libperf-y += header.o 1libperf-y += header.o
2libperf-y += sym-handling.o 2libperf-y += sym-handling.o
3libperf-y += kvm-stat.o
3 4
4libperf-$(CONFIG_DWARF) += dwarf-regs.o 5libperf-$(CONFIG_DWARF) += dwarf-regs.o
5libperf-$(CONFIG_DWARF) += skip-callchain-idx.o 6libperf-$(CONFIG_DWARF) += skip-callchain-idx.o
diff --git a/tools/perf/arch/powerpc/util/book3s_hcalls.h b/tools/perf/arch/powerpc/util/book3s_hcalls.h
new file mode 100644
index 000000000000..0dd6b7f2d44f
--- /dev/null
+++ b/tools/perf/arch/powerpc/util/book3s_hcalls.h
@@ -0,0 +1,123 @@
1#ifndef ARCH_PERF_BOOK3S_HV_HCALLS_H
2#define ARCH_PERF_BOOK3S_HV_HCALLS_H
3
4/*
5 * PowerPC HCALL codes : hcall code to name mapping
6 */
7#define kvm_trace_symbol_hcall \
8 {0x4, "H_REMOVE"}, \
9 {0x8, "H_ENTER"}, \
10 {0xc, "H_READ"}, \
11 {0x10, "H_CLEAR_MOD"}, \
12 {0x14, "H_CLEAR_REF"}, \
13 {0x18, "H_PROTECT"}, \
14 {0x1c, "H_GET_TCE"}, \
15 {0x20, "H_PUT_TCE"}, \
16 {0x24, "H_SET_SPRG0"}, \
17 {0x28, "H_SET_DABR"}, \
18 {0x2c, "H_PAGE_INIT"}, \
19 {0x30, "H_SET_ASR"}, \
20 {0x34, "H_ASR_ON"}, \
21 {0x38, "H_ASR_OFF"}, \
22 {0x3c, "H_LOGICAL_CI_LOAD"}, \
23 {0x40, "H_LOGICAL_CI_STORE"}, \
24 {0x44, "H_LOGICAL_CACHE_LOAD"}, \
25 {0x48, "H_LOGICAL_CACHE_STORE"}, \
26 {0x4c, "H_LOGICAL_ICBI"}, \
27 {0x50, "H_LOGICAL_DCBF"}, \
28 {0x54, "H_GET_TERM_CHAR"}, \
29 {0x58, "H_PUT_TERM_CHAR"}, \
30 {0x5c, "H_REAL_TO_LOGICAL"}, \
31 {0x60, "H_HYPERVISOR_DATA"}, \
32 {0x64, "H_EOI"}, \
33 {0x68, "H_CPPR"}, \
34 {0x6c, "H_IPI"}, \
35 {0x70, "H_IPOLL"}, \
36 {0x74, "H_XIRR"}, \
37 {0x78, "H_MIGRATE_DMA"}, \
38 {0x7c, "H_PERFMON"}, \
39 {0xdc, "H_REGISTER_VPA"}, \
40 {0xe0, "H_CEDE"}, \
41 {0xe4, "H_CONFER"}, \
42 {0xe8, "H_PROD"}, \
43 {0xec, "H_GET_PPP"}, \
44 {0xf0, "H_SET_PPP"}, \
45 {0xf4, "H_PURR"}, \
46 {0xf8, "H_PIC"}, \
47 {0xfc, "H_REG_CRQ"}, \
48 {0x100, "H_FREE_CRQ"}, \
49 {0x104, "H_VIO_SIGNAL"}, \
50 {0x108, "H_SEND_CRQ"}, \
51 {0x110, "H_COPY_RDMA"}, \
52 {0x114, "H_REGISTER_LOGICAL_LAN"}, \
53 {0x118, "H_FREE_LOGICAL_LAN"}, \
54 {0x11c, "H_ADD_LOGICAL_LAN_BUFFER"}, \
55 {0x120, "H_SEND_LOGICAL_LAN"}, \
56 {0x124, "H_BULK_REMOVE"}, \
57 {0x130, "H_MULTICAST_CTRL"}, \
58 {0x134, "H_SET_XDABR"}, \
59 {0x138, "H_STUFF_TCE"}, \
60 {0x13c, "H_PUT_TCE_INDIRECT"}, \
61 {0x14c, "H_CHANGE_LOGICAL_LAN_MAC"}, \
62 {0x150, "H_VTERM_PARTNER_INFO"}, \
63 {0x154, "H_REGISTER_VTERM"}, \
64 {0x158, "H_FREE_VTERM"}, \
65 {0x15c, "H_RESET_EVENTS"}, \
66 {0x160, "H_ALLOC_RESOURCE"}, \
67 {0x164, "H_FREE_RESOURCE"}, \
68 {0x168, "H_MODIFY_QP"}, \
69 {0x16c, "H_QUERY_QP"}, \
70 {0x170, "H_REREGISTER_PMR"}, \
71 {0x174, "H_REGISTER_SMR"}, \
72 {0x178, "H_QUERY_MR"}, \
73 {0x17c, "H_QUERY_MW"}, \
74 {0x180, "H_QUERY_HCA"}, \
75 {0x184, "H_QUERY_PORT"}, \
76 {0x188, "H_MODIFY_PORT"}, \
77 {0x18c, "H_DEFINE_AQP1"}, \
78 {0x190, "H_GET_TRACE_BUFFER"}, \
79 {0x194, "H_DEFINE_AQP0"}, \
80 {0x198, "H_RESIZE_MR"}, \
81 {0x19c, "H_ATTACH_MCQP"}, \
82 {0x1a0, "H_DETACH_MCQP"}, \
83 {0x1a4, "H_CREATE_RPT"}, \
84 {0x1a8, "H_REMOVE_RPT"}, \
85 {0x1ac, "H_REGISTER_RPAGES"}, \
86 {0x1b0, "H_DISABLE_AND_GETC"}, \
87 {0x1b4, "H_ERROR_DATA"}, \
88 {0x1b8, "H_GET_HCA_INFO"}, \
89 {0x1bc, "H_GET_PERF_COUNT"}, \
90 {0x1c0, "H_MANAGE_TRACE"}, \
91 {0x1d4, "H_FREE_LOGICAL_LAN_BUFFER"}, \
92 {0x1d8, "H_POLL_PENDING"}, \
93 {0x1e4, "H_QUERY_INT_STATE"}, \
94 {0x244, "H_ILLAN_ATTRIBUTES"}, \
95 {0x250, "H_MODIFY_HEA_QP"}, \
96 {0x254, "H_QUERY_HEA_QP"}, \
97 {0x258, "H_QUERY_HEA"}, \
98 {0x25c, "H_QUERY_HEA_PORT"}, \
99 {0x260, "H_MODIFY_HEA_PORT"}, \
100 {0x264, "H_REG_BCMC"}, \
101 {0x268, "H_DEREG_BCMC"}, \
102 {0x26c, "H_REGISTER_HEA_RPAGES"}, \
103 {0x270, "H_DISABLE_AND_GET_HEA"}, \
104 {0x274, "H_GET_HEA_INFO"}, \
105 {0x278, "H_ALLOC_HEA_RESOURCE"}, \
106 {0x284, "H_ADD_CONN"}, \
107 {0x288, "H_DEL_CONN"}, \
108 {0x298, "H_JOIN"}, \
109 {0x2a4, "H_VASI_STATE"}, \
110 {0x2b0, "H_ENABLE_CRQ"}, \
111 {0x2b8, "H_GET_EM_PARMS"}, \
112 {0x2d0, "H_SET_MPP"}, \
113 {0x2d4, "H_GET_MPP"}, \
114 {0x2ec, "H_HOME_NODE_ASSOCIATIVITY"}, \
115 {0x2f4, "H_BEST_ENERGY"}, \
116 {0x2fc, "H_XIRR_X"}, \
117 {0x300, "H_RANDOM"}, \
118 {0x304, "H_COP"}, \
119 {0x314, "H_GET_MPP_X"}, \
120 {0x31c, "H_SET_MODE"}, \
121 {0xf000, "H_RTAS"} \
122
123#endif
diff --git a/tools/perf/arch/powerpc/util/book3s_hv_exits.h b/tools/perf/arch/powerpc/util/book3s_hv_exits.h
new file mode 100644
index 000000000000..e68ba2da8970
--- /dev/null
+++ b/tools/perf/arch/powerpc/util/book3s_hv_exits.h
@@ -0,0 +1,33 @@
1#ifndef ARCH_PERF_BOOK3S_HV_EXITS_H
2#define ARCH_PERF_BOOK3S_HV_EXITS_H
3
4/*
5 * PowerPC Interrupt vectors : exit code to name mapping
6 */
7
8#define kvm_trace_symbol_exit \
9 {0x0, "RETURN_TO_HOST"}, \
10 {0x100, "SYSTEM_RESET"}, \
11 {0x200, "MACHINE_CHECK"}, \
12 {0x300, "DATA_STORAGE"}, \
13 {0x380, "DATA_SEGMENT"}, \
14 {0x400, "INST_STORAGE"}, \
15 {0x480, "INST_SEGMENT"}, \
16 {0x500, "EXTERNAL"}, \
17 {0x501, "EXTERNAL_LEVEL"}, \
18 {0x502, "EXTERNAL_HV"}, \
19 {0x600, "ALIGNMENT"}, \
20 {0x700, "PROGRAM"}, \
21 {0x800, "FP_UNAVAIL"}, \
22 {0x900, "DECREMENTER"}, \
23 {0x980, "HV_DECREMENTER"}, \
24 {0xc00, "SYSCALL"}, \
25 {0xd00, "TRACE"}, \
26 {0xe00, "H_DATA_STORAGE"}, \
27 {0xe20, "H_INST_STORAGE"}, \
28 {0xe40, "H_EMUL_ASSIST"}, \
29 {0xf00, "PERFMON"}, \
30 {0xf20, "ALTIVEC"}, \
31 {0xf40, "VSX"}
32
33#endif
diff --git a/tools/perf/arch/powerpc/util/kvm-stat.c b/tools/perf/arch/powerpc/util/kvm-stat.c
new file mode 100644
index 000000000000..74eee30398f8
--- /dev/null
+++ b/tools/perf/arch/powerpc/util/kvm-stat.c
@@ -0,0 +1,170 @@
1#include "util/kvm-stat.h"
2#include "util/parse-events.h"
3#include "util/debug.h"
4
5#include "book3s_hv_exits.h"
6#include "book3s_hcalls.h"
7
8#define NR_TPS 4
9
10const char *vcpu_id_str = "vcpu_id";
11const int decode_str_len = 40;
12const char *kvm_entry_trace = "kvm_hv:kvm_guest_enter";
13const char *kvm_exit_trace = "kvm_hv:kvm_guest_exit";
14
15define_exit_reasons_table(hv_exit_reasons, kvm_trace_symbol_exit);
16define_exit_reasons_table(hcall_reasons, kvm_trace_symbol_hcall);
17
18/* Tracepoints specific to ppc_book3s_hv */
19const char *ppc_book3s_hv_kvm_tp[] = {
20 "kvm_hv:kvm_guest_enter",
21 "kvm_hv:kvm_guest_exit",
22 "kvm_hv:kvm_hcall_enter",
23 "kvm_hv:kvm_hcall_exit",
24 NULL,
25};
26
27/* 1 extra placeholder for NULL */
28const char *kvm_events_tp[NR_TPS + 1];
29const char *kvm_exit_reason;
30
31static void hcall_event_get_key(struct perf_evsel *evsel,
32 struct perf_sample *sample,
33 struct event_key *key)
34{
35 key->info = 0;
36 key->key = perf_evsel__intval(evsel, sample, "req");
37}
38
39static const char *get_hcall_exit_reason(u64 exit_code)
40{
41 struct exit_reasons_table *tbl = hcall_reasons;
42
43 while (tbl->reason != NULL) {
44 if (tbl->exit_code == exit_code)
45 return tbl->reason;
46 tbl++;
47 }
48
49 pr_debug("Unknown hcall code: %lld\n",
50 (unsigned long long)exit_code);
51 return "UNKNOWN";
52}
53
54static bool hcall_event_end(struct perf_evsel *evsel,
55 struct perf_sample *sample __maybe_unused,
56 struct event_key *key __maybe_unused)
57{
58 return (!strcmp(evsel->name, kvm_events_tp[3]));
59}
60
61static bool hcall_event_begin(struct perf_evsel *evsel,
62 struct perf_sample *sample, struct event_key *key)
63{
64 if (!strcmp(evsel->name, kvm_events_tp[2])) {
65 hcall_event_get_key(evsel, sample, key);
66 return true;
67 }
68
69 return false;
70}
71static void hcall_event_decode_key(struct perf_kvm_stat *kvm __maybe_unused,
72 struct event_key *key,
73 char *decode)
74{
75 const char *hcall_reason = get_hcall_exit_reason(key->key);
76
77 scnprintf(decode, decode_str_len, "%s", hcall_reason);
78}
79
80static struct kvm_events_ops hcall_events = {
81 .is_begin_event = hcall_event_begin,
82 .is_end_event = hcall_event_end,
83 .decode_key = hcall_event_decode_key,
84 .name = "HCALL-EVENT",
85};
86
87static struct kvm_events_ops exit_events = {
88 .is_begin_event = exit_event_begin,
89 .is_end_event = exit_event_end,
90 .decode_key = exit_event_decode_key,
91 .name = "VM-EXIT"
92};
93
94struct kvm_reg_events_ops kvm_reg_events_ops[] = {
95 { .name = "vmexit", .ops = &exit_events },
96 { .name = "hcall", .ops = &hcall_events },
97 { NULL, NULL },
98};
99
100const char * const kvm_skip_events[] = {
101 NULL,
102};
103
104
105static int is_tracepoint_available(const char *str, struct perf_evlist *evlist)
106{
107 struct parse_events_error err;
108 int ret;
109
110 err.str = NULL;
111 ret = parse_events(evlist, str, &err);
112 if (err.str)
113 pr_err("%s : %s\n", str, err.str);
114 return ret;
115}
116
117static int ppc__setup_book3s_hv(struct perf_kvm_stat *kvm,
118 struct perf_evlist *evlist)
119{
120 const char **events_ptr;
121 int i, nr_tp = 0, err = -1;
122
123 /* Check for book3s_hv tracepoints */
124 for (events_ptr = ppc_book3s_hv_kvm_tp; *events_ptr; events_ptr++) {
125 err = is_tracepoint_available(*events_ptr, evlist);
126 if (err)
127 return -1;
128 nr_tp++;
129 }
130
131 for (i = 0; i < nr_tp; i++)
132 kvm_events_tp[i] = ppc_book3s_hv_kvm_tp[i];
133
134 kvm_events_tp[i] = NULL;
135 kvm_exit_reason = "trap";
136 kvm->exit_reasons = hv_exit_reasons;
137 kvm->exit_reasons_isa = "HV";
138
139 return 0;
140}
141
142/* Wrapper to setup kvm tracepoints */
143static int ppc__setup_kvm_tp(struct perf_kvm_stat *kvm)
144{
145 struct perf_evlist *evlist = perf_evlist__new();
146
147 if (evlist == NULL)
148 return -ENOMEM;
149
150 /* Right now, only supported on book3s_hv */
151 return ppc__setup_book3s_hv(kvm, evlist);
152}
153
154int setup_kvm_events_tp(struct perf_kvm_stat *kvm)
155{
156 return ppc__setup_kvm_tp(kvm);
157}
158
159int cpu_isa_init(struct perf_kvm_stat *kvm, const char *cpuid __maybe_unused)
160{
161 int ret;
162
163 ret = ppc__setup_kvm_tp(kvm);
164 if (ret) {
165 kvm->exit_reasons = NULL;
166 kvm->exit_reasons_isa = NULL;
167 }
168
169 return ret;
170}
diff --git a/tools/perf/arch/s390/util/kvm-stat.c b/tools/perf/arch/s390/util/kvm-stat.c
index a5dbc07ec9dc..ed57df2e6d68 100644
--- a/tools/perf/arch/s390/util/kvm-stat.c
+++ b/tools/perf/arch/s390/util/kvm-stat.c
@@ -10,7 +10,7 @@
10 */ 10 */
11 11
12#include "../../util/kvm-stat.h" 12#include "../../util/kvm-stat.h"
13#include <asm/kvm_perf.h> 13#include <asm/sie.h>
14 14
15define_exit_reasons_table(sie_exit_reasons, sie_intercept_code); 15define_exit_reasons_table(sie_exit_reasons, sie_intercept_code);
16define_exit_reasons_table(sie_icpt_insn_codes, icpt_insn_codes); 16define_exit_reasons_table(sie_icpt_insn_codes, icpt_insn_codes);
@@ -18,6 +18,12 @@ define_exit_reasons_table(sie_sigp_order_codes, sigp_order_codes);
18define_exit_reasons_table(sie_diagnose_codes, diagnose_codes); 18define_exit_reasons_table(sie_diagnose_codes, diagnose_codes);
19define_exit_reasons_table(sie_icpt_prog_codes, icpt_prog_codes); 19define_exit_reasons_table(sie_icpt_prog_codes, icpt_prog_codes);
20 20
21const char *vcpu_id_str = "id";
22const int decode_str_len = 40;
23const char *kvm_exit_reason = "icptcode";
24const char *kvm_entry_trace = "kvm:kvm_s390_sie_enter";
25const char *kvm_exit_trace = "kvm:kvm_s390_sie_exit";
26
21static void event_icpt_insn_get_key(struct perf_evsel *evsel, 27static void event_icpt_insn_get_key(struct perf_evsel *evsel,
22 struct perf_sample *sample, 28 struct perf_sample *sample,
23 struct event_key *key) 29 struct event_key *key)
@@ -73,7 +79,7 @@ static struct kvm_events_ops exit_events = {
73 .name = "VM-EXIT" 79 .name = "VM-EXIT"
74}; 80};
75 81
76const char * const kvm_events_tp[] = { 82const char *kvm_events_tp[] = {
77 "kvm:kvm_s390_sie_enter", 83 "kvm:kvm_s390_sie_enter",
78 "kvm:kvm_s390_sie_exit", 84 "kvm:kvm_s390_sie_exit",
79 "kvm:kvm_s390_intercept_instruction", 85 "kvm:kvm_s390_intercept_instruction",
diff --git a/tools/perf/arch/x86/Makefile b/tools/perf/arch/x86/Makefile
index 09ba923debe8..269af2143735 100644
--- a/tools/perf/arch/x86/Makefile
+++ b/tools/perf/arch/x86/Makefile
@@ -3,3 +3,4 @@ PERF_HAVE_DWARF_REGS := 1
3endif 3endif
4HAVE_KVM_STAT_SUPPORT := 1 4HAVE_KVM_STAT_SUPPORT := 1
5PERF_HAVE_ARCH_REGS_QUERY_REGISTER_OFFSET := 1 5PERF_HAVE_ARCH_REGS_QUERY_REGISTER_OFFSET := 1
6PERF_HAVE_JITDUMP := 1
diff --git a/tools/perf/arch/x86/tests/rdpmc.c b/tools/perf/arch/x86/tests/rdpmc.c
index 7bb0d13c235f..72193f19d6d7 100644
--- a/tools/perf/arch/x86/tests/rdpmc.c
+++ b/tools/perf/arch/x86/tests/rdpmc.c
@@ -59,7 +59,7 @@ static u64 mmap_read_self(void *addr)
59 u64 quot, rem; 59 u64 quot, rem;
60 60
61 quot = (cyc >> time_shift); 61 quot = (cyc >> time_shift);
62 rem = cyc & ((1 << time_shift) - 1); 62 rem = cyc & (((u64)1 << time_shift) - 1);
63 delta = time_offset + quot * time_mult + 63 delta = time_offset + quot * time_mult +
64 ((rem * time_mult) >> time_shift); 64 ((rem * time_mult) >> time_shift);
65 65
@@ -103,6 +103,7 @@ static int __test__rdpmc(void)
103 103
104 sigfillset(&sa.sa_mask); 104 sigfillset(&sa.sa_mask);
105 sa.sa_sigaction = segfault_handler; 105 sa.sa_sigaction = segfault_handler;
106 sa.sa_flags = 0;
106 sigaction(SIGSEGV, &sa, NULL); 107 sigaction(SIGSEGV, &sa, NULL);
107 108
108 fd = sys_perf_event_open(&attr, 0, -1, -1, 109 fd = sys_perf_event_open(&attr, 0, -1, -1,
diff --git a/tools/perf/arch/x86/util/intel-bts.c b/tools/perf/arch/x86/util/intel-bts.c
index 8d8150f1cf9b..d66f9ad4df2e 100644
--- a/tools/perf/arch/x86/util/intel-bts.c
+++ b/tools/perf/arch/x86/util/intel-bts.c
@@ -60,7 +60,9 @@ struct branch {
60 u64 misc; 60 u64 misc;
61}; 61};
62 62
63static size_t intel_bts_info_priv_size(struct auxtrace_record *itr __maybe_unused) 63static size_t
64intel_bts_info_priv_size(struct auxtrace_record *itr __maybe_unused,
65 struct perf_evlist *evlist __maybe_unused)
64{ 66{
65 return INTEL_BTS_AUXTRACE_PRIV_SIZE; 67 return INTEL_BTS_AUXTRACE_PRIV_SIZE;
66} 68}
diff --git a/tools/perf/arch/x86/util/intel-pt.c b/tools/perf/arch/x86/util/intel-pt.c
index f05daacc9e78..a3395179c9ee 100644
--- a/tools/perf/arch/x86/util/intel-pt.c
+++ b/tools/perf/arch/x86/util/intel-pt.c
@@ -89,7 +89,7 @@ static int intel_pt_parse_terms_with_default(struct list_head *formats,
89 89
90 *config = attr.config; 90 *config = attr.config;
91out_free: 91out_free:
92 parse_events__free_terms(terms); 92 parse_events_terms__delete(terms);
93 return err; 93 return err;
94} 94}
95 95
@@ -273,7 +273,9 @@ intel_pt_pmu_default_config(struct perf_pmu *intel_pt_pmu)
273 return attr; 273 return attr;
274} 274}
275 275
276static size_t intel_pt_info_priv_size(struct auxtrace_record *itr __maybe_unused) 276static size_t
277intel_pt_info_priv_size(struct auxtrace_record *itr __maybe_unused,
278 struct perf_evlist *evlist __maybe_unused)
277{ 279{
278 return INTEL_PT_AUXTRACE_PRIV_SIZE; 280 return INTEL_PT_AUXTRACE_PRIV_SIZE;
279} 281}
diff --git a/tools/perf/arch/x86/util/kvm-stat.c b/tools/perf/arch/x86/util/kvm-stat.c
index 14e4e668fad7..b63d4be655a2 100644
--- a/tools/perf/arch/x86/util/kvm-stat.c
+++ b/tools/perf/arch/x86/util/kvm-stat.c
@@ -1,5 +1,7 @@
1#include "../../util/kvm-stat.h" 1#include "../../util/kvm-stat.h"
2#include <asm/kvm_perf.h> 2#include <asm/svm.h>
3#include <asm/vmx.h>
4#include <asm/kvm.h>
3 5
4define_exit_reasons_table(vmx_exit_reasons, VMX_EXIT_REASONS); 6define_exit_reasons_table(vmx_exit_reasons, VMX_EXIT_REASONS);
5define_exit_reasons_table(svm_exit_reasons, SVM_EXIT_REASONS); 7define_exit_reasons_table(svm_exit_reasons, SVM_EXIT_REASONS);
@@ -11,6 +13,12 @@ static struct kvm_events_ops exit_events = {
11 .name = "VM-EXIT" 13 .name = "VM-EXIT"
12}; 14};
13 15
16const char *vcpu_id_str = "vcpu_id";
17const int decode_str_len = 20;
18const char *kvm_exit_reason = "exit_reason";
19const char *kvm_entry_trace = "kvm:kvm_entry";
20const char *kvm_exit_trace = "kvm:kvm_exit";
21
14/* 22/*
15 * For the mmio events, we treat: 23 * For the mmio events, we treat:
16 * the time of MMIO write: kvm_mmio(KVM_TRACE_MMIO_WRITE...) -> kvm_entry 24 * the time of MMIO write: kvm_mmio(KVM_TRACE_MMIO_WRITE...) -> kvm_entry
@@ -65,7 +73,7 @@ static void mmio_event_decode_key(struct perf_kvm_stat *kvm __maybe_unused,
65 struct event_key *key, 73 struct event_key *key,
66 char *decode) 74 char *decode)
67{ 75{
68 scnprintf(decode, DECODE_STR_LEN, "%#lx:%s", 76 scnprintf(decode, decode_str_len, "%#lx:%s",
69 (unsigned long)key->key, 77 (unsigned long)key->key,
70 key->info == KVM_TRACE_MMIO_WRITE ? "W" : "R"); 78 key->info == KVM_TRACE_MMIO_WRITE ? "W" : "R");
71} 79}
@@ -109,7 +117,7 @@ static void ioport_event_decode_key(struct perf_kvm_stat *kvm __maybe_unused,
109 struct event_key *key, 117 struct event_key *key,
110 char *decode) 118 char *decode)
111{ 119{
112 scnprintf(decode, DECODE_STR_LEN, "%#llx:%s", 120 scnprintf(decode, decode_str_len, "%#llx:%s",
113 (unsigned long long)key->key, 121 (unsigned long long)key->key,
114 key->info ? "POUT" : "PIN"); 122 key->info ? "POUT" : "PIN");
115} 123}
@@ -121,7 +129,7 @@ static struct kvm_events_ops ioport_events = {
121 .name = "IO Port Access" 129 .name = "IO Port Access"
122}; 130};
123 131
124const char * const kvm_events_tp[] = { 132const char *kvm_events_tp[] = {
125 "kvm:kvm_entry", 133 "kvm:kvm_entry",
126 "kvm:kvm_exit", 134 "kvm:kvm_exit",
127 "kvm:kvm_mmio", 135 "kvm:kvm_mmio",
diff --git a/tools/perf/bench/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/builtin-annotate.c b/tools/perf/builtin-annotate.c
index cc5c1267c738..cfe366375c4b 100644
--- a/tools/perf/builtin-annotate.c
+++ b/tools/perf/builtin-annotate.c
@@ -245,7 +245,7 @@ static int __cmd_annotate(struct perf_annotate *ann)
245 hists__collapse_resort(hists, NULL); 245 hists__collapse_resort(hists, NULL);
246 /* Don't sort callchain */ 246 /* Don't sort callchain */
247 perf_evsel__reset_sample_bit(pos, CALLCHAIN); 247 perf_evsel__reset_sample_bit(pos, CALLCHAIN);
248 hists__output_resort(hists, NULL); 248 perf_evsel__output_resort(pos, NULL);
249 249
250 if (symbol_conf.event_group && 250 if (symbol_conf.event_group &&
251 !perf_evsel__is_group_leader(pos)) 251 !perf_evsel__is_group_leader(pos))
diff --git a/tools/perf/builtin-buildid-cache.c b/tools/perf/builtin-buildid-cache.c
index d93bff7fc0e4..632efc6b79a0 100644
--- a/tools/perf/builtin-buildid-cache.c
+++ b/tools/perf/builtin-buildid-cache.c
@@ -38,19 +38,7 @@ static int build_id_cache__kcore_buildid(const char *proc_dir, char *sbuildid)
38 38
39static int build_id_cache__kcore_dir(char *dir, size_t sz) 39static int build_id_cache__kcore_dir(char *dir, size_t sz)
40{ 40{
41 struct timeval tv; 41 return fetch_current_timestamp(dir, sz);
42 struct tm tm;
43 char dt[32];
44
45 if (gettimeofday(&tv, NULL) || !localtime_r(&tv.tv_sec, &tm))
46 return -1;
47
48 if (!strftime(dt, sizeof(dt), "%Y%m%d%H%M%S", &tm))
49 return -1;
50
51 scnprintf(dir, sz, "%s%02u", dt, (unsigned)tv.tv_usec / 10000);
52
53 return 0;
54} 42}
55 43
56static bool same_kallsyms_reloc(const char *from_dir, char *to_dir) 44static bool same_kallsyms_reloc(const char *from_dir, char *to_dir)
diff --git a/tools/perf/builtin-config.c b/tools/perf/builtin-config.c
index f04e804a9fad..c42448ed5dfe 100644
--- a/tools/perf/builtin-config.c
+++ b/tools/perf/builtin-config.c
@@ -13,8 +13,10 @@
13#include "util/util.h" 13#include "util/util.h"
14#include "util/debug.h" 14#include "util/debug.h"
15 15
16static bool use_system_config, use_user_config;
17
16static const char * const config_usage[] = { 18static const char * const config_usage[] = {
17 "perf config [options]", 19 "perf config [<file-option>] [options]",
18 NULL 20 NULL
19}; 21};
20 22
@@ -25,6 +27,8 @@ enum actions {
25static struct option config_options[] = { 27static struct option config_options[] = {
26 OPT_SET_UINT('l', "list", &actions, 28 OPT_SET_UINT('l', "list", &actions,
27 "show current config variables", ACTION_LIST), 29 "show current config variables", ACTION_LIST),
30 OPT_BOOLEAN(0, "system", &use_system_config, "use system config file"),
31 OPT_BOOLEAN(0, "user", &use_user_config, "use user config file"),
28 OPT_END() 32 OPT_END()
29}; 33};
30 34
@@ -42,10 +46,23 @@ static int show_config(const char *key, const char *value,
42int cmd_config(int argc, const char **argv, const char *prefix __maybe_unused) 46int cmd_config(int argc, const char **argv, const char *prefix __maybe_unused)
43{ 47{
44 int ret = 0; 48 int ret = 0;
49 char *user_config = mkpath("%s/.perfconfig", getenv("HOME"));
45 50
46 argc = parse_options(argc, argv, config_options, config_usage, 51 argc = parse_options(argc, argv, config_options, config_usage,
47 PARSE_OPT_STOP_AT_NON_OPTION); 52 PARSE_OPT_STOP_AT_NON_OPTION);
48 53
54 if (use_system_config && use_user_config) {
55 pr_err("Error: only one config file at a time\n");
56 parse_options_usage(config_usage, config_options, "user", 0);
57 parse_options_usage(NULL, config_options, "system", 0);
58 return -1;
59 }
60
61 if (use_system_config)
62 config_exclusive_filename = perf_etc_perfconfig();
63 else if (use_user_config)
64 config_exclusive_filename = user_config;
65
49 switch (actions) { 66 switch (actions) {
50 case ACTION_LIST: 67 case ACTION_LIST:
51 if (argc) { 68 if (argc) {
@@ -53,9 +70,13 @@ int cmd_config(int argc, const char **argv, const char *prefix __maybe_unused)
53 parse_options_usage(config_usage, config_options, "l", 1); 70 parse_options_usage(config_usage, config_options, "l", 1);
54 } else { 71 } else {
55 ret = perf_config(show_config, NULL); 72 ret = perf_config(show_config, NULL);
56 if (ret < 0) 73 if (ret < 0) {
74 const char * config_filename = config_exclusive_filename;
75 if (!config_exclusive_filename)
76 config_filename = user_config;
57 pr_err("Nothing configured, " 77 pr_err("Nothing configured, "
58 "please check your ~/.perfconfig file\n"); 78 "please check your %s \n", config_filename);
79 }
59 } 80 }
60 break; 81 break;
61 default: 82 default:
diff --git a/tools/perf/builtin-diff.c b/tools/perf/builtin-diff.c
index 36ccc2b8827f..4d72359fd15a 100644
--- a/tools/perf/builtin-diff.c
+++ b/tools/perf/builtin-diff.c
@@ -1264,8 +1264,6 @@ int cmd_diff(int argc, const char **argv, const char *prefix __maybe_unused)
1264 if (ret < 0) 1264 if (ret < 0)
1265 return ret; 1265 return ret;
1266 1266
1267 perf_config(perf_default_config, NULL);
1268
1269 argc = parse_options(argc, argv, options, diff_usage, 0); 1267 argc = parse_options(argc, argv, options, diff_usage, 0);
1270 1268
1271 if (symbol__init(NULL) < 0) 1269 if (symbol__init(NULL) < 0)
diff --git a/tools/perf/builtin-help.c b/tools/perf/builtin-help.c
index 96c1a4cfbbbf..49d55e21b1b0 100644
--- a/tools/perf/builtin-help.c
+++ b/tools/perf/builtin-help.c
@@ -86,8 +86,7 @@ static int check_emacsclient_version(void)
86 return -1; 86 return -1;
87 } 87 }
88 88
89 strbuf_remove(&buffer, 0, strlen("emacsclient")); 89 version = atoi(buffer.buf + strlen("emacsclient"));
90 version = atoi(buffer.buf);
91 90
92 if (version < 22) { 91 if (version < 22) {
93 fprintf(stderr, 92 fprintf(stderr,
@@ -273,7 +272,7 @@ static int perf_help_config(const char *var, const char *value, void *cb)
273 if (!prefixcmp(var, "man.")) 272 if (!prefixcmp(var, "man."))
274 return add_man_viewer_info(var, value); 273 return add_man_viewer_info(var, value);
275 274
276 return perf_default_config(var, value, cb); 275 return 0;
277} 276}
278 277
279static struct cmdnames main_cmds, other_cmds; 278static struct cmdnames main_cmds, other_cmds;
diff --git a/tools/perf/builtin-inject.c b/tools/perf/builtin-inject.c
index 0022e02ed31a..7fa68663ed72 100644
--- a/tools/perf/builtin-inject.c
+++ b/tools/perf/builtin-inject.c
@@ -17,6 +17,7 @@
17#include "util/build-id.h" 17#include "util/build-id.h"
18#include "util/data.h" 18#include "util/data.h"
19#include "util/auxtrace.h" 19#include "util/auxtrace.h"
20#include "util/jit.h"
20 21
21#include <subcmd/parse-options.h> 22#include <subcmd/parse-options.h>
22 23
@@ -29,6 +30,7 @@ struct perf_inject {
29 bool sched_stat; 30 bool sched_stat;
30 bool have_auxtrace; 31 bool have_auxtrace;
31 bool strip; 32 bool strip;
33 bool jit_mode;
32 const char *input_name; 34 const char *input_name;
33 struct perf_data_file output; 35 struct perf_data_file output;
34 u64 bytes_written; 36 u64 bytes_written;
@@ -71,6 +73,15 @@ static int perf_event__repipe_oe_synth(struct perf_tool *tool,
71 return perf_event__repipe_synth(tool, event); 73 return perf_event__repipe_synth(tool, event);
72} 74}
73 75
76#ifdef HAVE_JITDUMP
77static int perf_event__drop_oe(struct perf_tool *tool __maybe_unused,
78 union perf_event *event __maybe_unused,
79 struct ordered_events *oe __maybe_unused)
80{
81 return 0;
82}
83#endif
84
74static int perf_event__repipe_op2_synth(struct perf_tool *tool, 85static int perf_event__repipe_op2_synth(struct perf_tool *tool,
75 union perf_event *event, 86 union perf_event *event,
76 struct perf_session *session 87 struct perf_session *session
@@ -234,6 +245,31 @@ static int perf_event__repipe_mmap(struct perf_tool *tool,
234 return err; 245 return err;
235} 246}
236 247
248#ifdef HAVE_JITDUMP
249static int perf_event__jit_repipe_mmap(struct perf_tool *tool,
250 union perf_event *event,
251 struct perf_sample *sample,
252 struct machine *machine)
253{
254 struct perf_inject *inject = container_of(tool, struct perf_inject, tool);
255 u64 n = 0;
256 int ret;
257
258 /*
259 * if jit marker, then inject jit mmaps and generate ELF images
260 */
261 ret = jit_process(inject->session, &inject->output, machine,
262 event->mmap.filename, sample->pid, &n);
263 if (ret < 0)
264 return ret;
265 if (ret) {
266 inject->bytes_written += n;
267 return 0;
268 }
269 return perf_event__repipe_mmap(tool, event, sample, machine);
270}
271#endif
272
237static int perf_event__repipe_mmap2(struct perf_tool *tool, 273static int perf_event__repipe_mmap2(struct perf_tool *tool,
238 union perf_event *event, 274 union perf_event *event,
239 struct perf_sample *sample, 275 struct perf_sample *sample,
@@ -247,6 +283,31 @@ static int perf_event__repipe_mmap2(struct perf_tool *tool,
247 return err; 283 return err;
248} 284}
249 285
286#ifdef HAVE_JITDUMP
287static int perf_event__jit_repipe_mmap2(struct perf_tool *tool,
288 union perf_event *event,
289 struct perf_sample *sample,
290 struct machine *machine)
291{
292 struct perf_inject *inject = container_of(tool, struct perf_inject, tool);
293 u64 n = 0;
294 int ret;
295
296 /*
297 * if jit marker, then inject jit mmaps and generate ELF images
298 */
299 ret = jit_process(inject->session, &inject->output, machine,
300 event->mmap2.filename, sample->pid, &n);
301 if (ret < 0)
302 return ret;
303 if (ret) {
304 inject->bytes_written += n;
305 return 0;
306 }
307 return perf_event__repipe_mmap2(tool, event, sample, machine);
308}
309#endif
310
250static int perf_event__repipe_fork(struct perf_tool *tool, 311static int perf_event__repipe_fork(struct perf_tool *tool,
251 union perf_event *event, 312 union perf_event *event,
252 struct perf_sample *sample, 313 struct perf_sample *sample,
@@ -626,12 +687,16 @@ static int __cmd_inject(struct perf_inject *inject)
626 ret = perf_session__process_events(session); 687 ret = perf_session__process_events(session);
627 688
628 if (!file_out->is_pipe) { 689 if (!file_out->is_pipe) {
629 if (inject->build_ids) { 690 if (inject->build_ids)
630 perf_header__set_feat(&session->header, 691 perf_header__set_feat(&session->header,
631 HEADER_BUILD_ID); 692 HEADER_BUILD_ID);
632 if (inject->have_auxtrace) 693 /*
633 dsos__hit_all(session); 694 * Keep all buildids when there is unprocessed AUX data because
634 } 695 * it is not known which ones the AUX trace hits.
696 */
697 if (perf_header__has_feat(&session->header, HEADER_BUILD_ID) &&
698 inject->have_auxtrace && !inject->itrace_synth_opts.set)
699 dsos__hit_all(session);
635 /* 700 /*
636 * The AUX areas have been removed and replaced with 701 * The AUX areas have been removed and replaced with
637 * synthesized hardware events, so clear the feature flag and 702 * synthesized hardware events, so clear the feature flag and
@@ -703,7 +768,7 @@ int cmd_inject(int argc, const char **argv, const char *prefix __maybe_unused)
703 }; 768 };
704 int ret; 769 int ret;
705 770
706 const struct option options[] = { 771 struct option options[] = {
707 OPT_BOOLEAN('b', "build-ids", &inject.build_ids, 772 OPT_BOOLEAN('b', "build-ids", &inject.build_ids,
708 "Inject build-ids into the output stream"), 773 "Inject build-ids into the output stream"),
709 OPT_STRING('i', "input", &inject.input_name, "file", 774 OPT_STRING('i', "input", &inject.input_name, "file",
@@ -713,6 +778,9 @@ int cmd_inject(int argc, const char **argv, const char *prefix __maybe_unused)
713 OPT_BOOLEAN('s', "sched-stat", &inject.sched_stat, 778 OPT_BOOLEAN('s', "sched-stat", &inject.sched_stat,
714 "Merge sched-stat and sched-switch for getting events " 779 "Merge sched-stat and sched-switch for getting events "
715 "where and how long tasks slept"), 780 "where and how long tasks slept"),
781#ifdef HAVE_JITDUMP
782 OPT_BOOLEAN('j', "jit", &inject.jit_mode, "merge jitdump files into perf.data file"),
783#endif
716 OPT_INCR('v', "verbose", &verbose, 784 OPT_INCR('v', "verbose", &verbose,
717 "be more verbose (show build ids, etc)"), 785 "be more verbose (show build ids, etc)"),
718 OPT_STRING(0, "kallsyms", &symbol_conf.kallsyms_name, "file", 786 OPT_STRING(0, "kallsyms", &symbol_conf.kallsyms_name, "file",
@@ -729,7 +797,9 @@ int cmd_inject(int argc, const char **argv, const char *prefix __maybe_unused)
729 "perf inject [<options>]", 797 "perf inject [<options>]",
730 NULL 798 NULL
731 }; 799 };
732 800#ifndef HAVE_JITDUMP
801 set_option_nobuild(options, 'j', "jit", "NO_LIBELF=1", true);
802#endif
733 argc = parse_options(argc, argv, options, inject_usage, 0); 803 argc = parse_options(argc, argv, options, inject_usage, 0);
734 804
735 /* 805 /*
@@ -755,6 +825,29 @@ int cmd_inject(int argc, const char **argv, const char *prefix __maybe_unused)
755 if (inject.session == NULL) 825 if (inject.session == NULL)
756 return -1; 826 return -1;
757 827
828 if (inject.build_ids) {
829 /*
830 * to make sure the mmap records are ordered correctly
831 * and so that the correct especially due to jitted code
832 * mmaps. We cannot generate the buildid hit list and
833 * inject the jit mmaps at the same time for now.
834 */
835 inject.tool.ordered_events = true;
836 inject.tool.ordering_requires_timestamps = true;
837 }
838#ifdef HAVE_JITDUMP
839 if (inject.jit_mode) {
840 inject.tool.mmap2 = perf_event__jit_repipe_mmap2;
841 inject.tool.mmap = perf_event__jit_repipe_mmap;
842 inject.tool.ordered_events = true;
843 inject.tool.ordering_requires_timestamps = true;
844 /*
845 * JIT MMAP injection injects all MMAP events in one go, so it
846 * does not obey finished_round semantics.
847 */
848 inject.tool.finished_round = perf_event__drop_oe;
849 }
850#endif
758 ret = symbol__init(&inject.session->header.env); 851 ret = symbol__init(&inject.session->header.env);
759 if (ret < 0) 852 if (ret < 0)
760 goto out_delete; 853 goto out_delete;
diff --git a/tools/perf/builtin-kmem.c b/tools/perf/builtin-kmem.c
index 118010553d0c..4d3340cce9a0 100644
--- a/tools/perf/builtin-kmem.c
+++ b/tools/perf/builtin-kmem.c
@@ -1834,7 +1834,7 @@ static int __cmd_record(int argc, const char **argv)
1834 return cmd_record(i, rec_argv, NULL); 1834 return cmd_record(i, rec_argv, NULL);
1835} 1835}
1836 1836
1837static int kmem_config(const char *var, const char *value, void *cb) 1837static int kmem_config(const char *var, const char *value, void *cb __maybe_unused)
1838{ 1838{
1839 if (!strcmp(var, "kmem.default")) { 1839 if (!strcmp(var, "kmem.default")) {
1840 if (!strcmp(value, "slab")) 1840 if (!strcmp(value, "slab"))
@@ -1847,7 +1847,7 @@ static int kmem_config(const char *var, const char *value, void *cb)
1847 return 0; 1847 return 0;
1848 } 1848 }
1849 1849
1850 return perf_default_config(var, value, cb); 1850 return 0;
1851} 1851}
1852 1852
1853int cmd_kmem(int argc, const char **argv, const char *prefix __maybe_unused) 1853int cmd_kmem(int argc, const char **argv, const char *prefix __maybe_unused)
diff --git a/tools/perf/builtin-kvm.c b/tools/perf/builtin-kvm.c
index 4418d9214872..bff666458b28 100644
--- a/tools/perf/builtin-kvm.c
+++ b/tools/perf/builtin-kvm.c
@@ -30,7 +30,6 @@
30#include <math.h> 30#include <math.h>
31 31
32#ifdef HAVE_KVM_STAT_SUPPORT 32#ifdef HAVE_KVM_STAT_SUPPORT
33#include <asm/kvm_perf.h>
34#include "util/kvm-stat.h" 33#include "util/kvm-stat.h"
35 34
36void exit_event_get_key(struct perf_evsel *evsel, 35void exit_event_get_key(struct perf_evsel *evsel,
@@ -38,12 +37,12 @@ void exit_event_get_key(struct perf_evsel *evsel,
38 struct event_key *key) 37 struct event_key *key)
39{ 38{
40 key->info = 0; 39 key->info = 0;
41 key->key = perf_evsel__intval(evsel, sample, KVM_EXIT_REASON); 40 key->key = perf_evsel__intval(evsel, sample, kvm_exit_reason);
42} 41}
43 42
44bool kvm_exit_event(struct perf_evsel *evsel) 43bool kvm_exit_event(struct perf_evsel *evsel)
45{ 44{
46 return !strcmp(evsel->name, KVM_EXIT_TRACE); 45 return !strcmp(evsel->name, kvm_exit_trace);
47} 46}
48 47
49bool exit_event_begin(struct perf_evsel *evsel, 48bool exit_event_begin(struct perf_evsel *evsel,
@@ -59,7 +58,7 @@ bool exit_event_begin(struct perf_evsel *evsel,
59 58
60bool kvm_entry_event(struct perf_evsel *evsel) 59bool kvm_entry_event(struct perf_evsel *evsel)
61{ 60{
62 return !strcmp(evsel->name, KVM_ENTRY_TRACE); 61 return !strcmp(evsel->name, kvm_entry_trace);
63} 62}
64 63
65bool exit_event_end(struct perf_evsel *evsel, 64bool exit_event_end(struct perf_evsel *evsel,
@@ -91,7 +90,7 @@ void exit_event_decode_key(struct perf_kvm_stat *kvm,
91 const char *exit_reason = get_exit_reason(kvm, key->exit_reasons, 90 const char *exit_reason = get_exit_reason(kvm, key->exit_reasons,
92 key->key); 91 key->key);
93 92
94 scnprintf(decode, DECODE_STR_LEN, "%s", exit_reason); 93 scnprintf(decode, decode_str_len, "%s", exit_reason);
95} 94}
96 95
97static bool register_kvm_events_ops(struct perf_kvm_stat *kvm) 96static bool register_kvm_events_ops(struct perf_kvm_stat *kvm)
@@ -357,7 +356,7 @@ static bool handle_end_event(struct perf_kvm_stat *kvm,
357 time_diff = sample->time - time_begin; 356 time_diff = sample->time - time_begin;
358 357
359 if (kvm->duration && time_diff > kvm->duration) { 358 if (kvm->duration && time_diff > kvm->duration) {
360 char decode[DECODE_STR_LEN]; 359 char decode[decode_str_len];
361 360
362 kvm->events_ops->decode_key(kvm, &event->key, decode); 361 kvm->events_ops->decode_key(kvm, &event->key, decode);
363 if (!skip_event(decode)) { 362 if (!skip_event(decode)) {
@@ -385,7 +384,8 @@ struct vcpu_event_record *per_vcpu_record(struct thread *thread,
385 return NULL; 384 return NULL;
386 } 385 }
387 386
388 vcpu_record->vcpu_id = perf_evsel__intval(evsel, sample, VCPU_ID); 387 vcpu_record->vcpu_id = perf_evsel__intval(evsel, sample,
388 vcpu_id_str);
389 thread__set_priv(thread, vcpu_record); 389 thread__set_priv(thread, vcpu_record);
390 } 390 }
391 391
@@ -574,7 +574,7 @@ static void show_timeofday(void)
574 574
575static void print_result(struct perf_kvm_stat *kvm) 575static void print_result(struct perf_kvm_stat *kvm)
576{ 576{
577 char decode[DECODE_STR_LEN]; 577 char decode[decode_str_len];
578 struct kvm_event *event; 578 struct kvm_event *event;
579 int vcpu = kvm->trace_vcpu; 579 int vcpu = kvm->trace_vcpu;
580 580
@@ -585,7 +585,7 @@ static void print_result(struct perf_kvm_stat *kvm)
585 585
586 pr_info("\n\n"); 586 pr_info("\n\n");
587 print_vcpu_info(kvm); 587 print_vcpu_info(kvm);
588 pr_info("%*s ", DECODE_STR_LEN, kvm->events_ops->name); 588 pr_info("%*s ", decode_str_len, kvm->events_ops->name);
589 pr_info("%10s ", "Samples"); 589 pr_info("%10s ", "Samples");
590 pr_info("%9s ", "Samples%"); 590 pr_info("%9s ", "Samples%");
591 591
@@ -604,7 +604,7 @@ static void print_result(struct perf_kvm_stat *kvm)
604 min = get_event_min(event, vcpu); 604 min = get_event_min(event, vcpu);
605 605
606 kvm->events_ops->decode_key(kvm, &event->key, decode); 606 kvm->events_ops->decode_key(kvm, &event->key, decode);
607 pr_info("%*s ", DECODE_STR_LEN, decode); 607 pr_info("%*s ", decode_str_len, decode);
608 pr_info("%10llu ", (unsigned long long)ecount); 608 pr_info("%10llu ", (unsigned long long)ecount);
609 pr_info("%8.2f%% ", (double)ecount / kvm->total_count * 100); 609 pr_info("%8.2f%% ", (double)ecount / kvm->total_count * 100);
610 pr_info("%8.2f%% ", (double)etime / kvm->total_time * 100); 610 pr_info("%8.2f%% ", (double)etime / kvm->total_time * 100);
@@ -1132,6 +1132,11 @@ exit:
1132 _p; \ 1132 _p; \
1133 }) 1133 })
1134 1134
1135int __weak setup_kvm_events_tp(struct perf_kvm_stat *kvm __maybe_unused)
1136{
1137 return 0;
1138}
1139
1135static int 1140static int
1136kvm_events_record(struct perf_kvm_stat *kvm, int argc, const char **argv) 1141kvm_events_record(struct perf_kvm_stat *kvm, int argc, const char **argv)
1137{ 1142{
@@ -1148,7 +1153,14 @@ kvm_events_record(struct perf_kvm_stat *kvm, int argc, const char **argv)
1148 NULL 1153 NULL
1149 }; 1154 };
1150 const char * const *events_tp; 1155 const char * const *events_tp;
1156 int ret;
1157
1151 events_tp_size = 0; 1158 events_tp_size = 0;
1159 ret = setup_kvm_events_tp(kvm);
1160 if (ret < 0) {
1161 pr_err("Unable to setup the kvm tracepoints\n");
1162 return ret;
1163 }
1152 1164
1153 for (events_tp = kvm_events_tp; *events_tp; events_tp++) 1165 for (events_tp = kvm_events_tp; *events_tp; events_tp++)
1154 events_tp_size++; 1166 events_tp_size++;
@@ -1377,6 +1389,12 @@ static int kvm_events_live(struct perf_kvm_stat *kvm,
1377 /* 1389 /*
1378 * generate the event list 1390 * generate the event list
1379 */ 1391 */
1392 err = setup_kvm_events_tp(kvm);
1393 if (err < 0) {
1394 pr_err("Unable to setup the kvm tracepoints\n");
1395 return err;
1396 }
1397
1380 kvm->evlist = kvm_live_event_list(); 1398 kvm->evlist = kvm_live_event_list();
1381 if (kvm->evlist == NULL) { 1399 if (kvm->evlist == NULL) {
1382 err = -1; 1400 err = -1;
diff --git a/tools/perf/builtin-mem.c b/tools/perf/builtin-mem.c
index 390170041696..88aeac9aa1da 100644
--- a/tools/perf/builtin-mem.c
+++ b/tools/perf/builtin-mem.c
@@ -6,6 +6,8 @@
6#include "util/tool.h" 6#include "util/tool.h"
7#include "util/session.h" 7#include "util/session.h"
8#include "util/data.h" 8#include "util/data.h"
9#include "util/mem-events.h"
10#include "util/debug.h"
9 11
10#define MEM_OPERATION_LOAD 0x1 12#define MEM_OPERATION_LOAD 0x1
11#define MEM_OPERATION_STORE 0x2 13#define MEM_OPERATION_STORE 0x2
@@ -21,11 +23,56 @@ struct perf_mem {
21 DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS); 23 DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS);
22}; 24};
23 25
26static int parse_record_events(const struct option *opt,
27 const char *str, int unset __maybe_unused)
28{
29 struct perf_mem *mem = *(struct perf_mem **)opt->value;
30 int j;
31
32 if (strcmp(str, "list")) {
33 if (!perf_mem_events__parse(str)) {
34 mem->operation = 0;
35 return 0;
36 }
37 exit(-1);
38 }
39
40 for (j = 0; j < PERF_MEM_EVENTS__MAX; j++) {
41 struct perf_mem_event *e = &perf_mem_events[j];
42
43 fprintf(stderr, "%-13s%-*s%s\n",
44 e->tag,
45 verbose ? 25 : 0,
46 verbose ? perf_mem_events__name(j) : "",
47 e->supported ? ": available" : "");
48 }
49 exit(0);
50}
51
52static const char * const __usage[] = {
53 "perf mem record [<options>] [<command>]",
54 "perf mem record [<options>] -- <command> [<options>]",
55 NULL
56};
57
58static const char * const *record_mem_usage = __usage;
59
24static int __cmd_record(int argc, const char **argv, struct perf_mem *mem) 60static int __cmd_record(int argc, const char **argv, struct perf_mem *mem)
25{ 61{
26 int rec_argc, i = 0, j; 62 int rec_argc, i = 0, j;
27 const char **rec_argv; 63 const char **rec_argv;
28 int ret; 64 int ret;
65 struct option options[] = {
66 OPT_CALLBACK('e', "event", &mem, "event",
67 "event selector. use 'perf mem record -e list' to list available events",
68 parse_record_events),
69 OPT_INCR('v', "verbose", &verbose,
70 "be more verbose (show counter open errors, etc)"),
71 OPT_END()
72 };
73
74 argc = parse_options(argc, argv, options, record_mem_usage,
75 PARSE_OPT_STOP_AT_NON_OPTION);
29 76
30 rec_argc = argc + 7; /* max number of arguments */ 77 rec_argc = argc + 7; /* max number of arguments */
31 rec_argv = calloc(rec_argc + 1, sizeof(char *)); 78 rec_argv = calloc(rec_argc + 1, sizeof(char *));
@@ -35,23 +82,40 @@ static int __cmd_record(int argc, const char **argv, struct perf_mem *mem)
35 rec_argv[i++] = "record"; 82 rec_argv[i++] = "record";
36 83
37 if (mem->operation & MEM_OPERATION_LOAD) 84 if (mem->operation & MEM_OPERATION_LOAD)
85 perf_mem_events[PERF_MEM_EVENTS__LOAD].record = true;
86
87 if (perf_mem_events[PERF_MEM_EVENTS__LOAD].record)
38 rec_argv[i++] = "-W"; 88 rec_argv[i++] = "-W";
39 89
40 rec_argv[i++] = "-d"; 90 rec_argv[i++] = "-d";
41 91
42 if (mem->operation & MEM_OPERATION_LOAD) { 92 for (j = 0; j < PERF_MEM_EVENTS__MAX; j++) {
43 rec_argv[i++] = "-e"; 93 if (!perf_mem_events[j].record)
44 rec_argv[i++] = "cpu/mem-loads/pp"; 94 continue;
45 } 95
96 if (!perf_mem_events[j].supported) {
97 pr_err("failed: event '%s' not supported\n",
98 perf_mem_events__name(j));
99 return -1;
100 }
46 101
47 if (mem->operation & MEM_OPERATION_STORE) {
48 rec_argv[i++] = "-e"; 102 rec_argv[i++] = "-e";
49 rec_argv[i++] = "cpu/mem-stores/pp"; 103 rec_argv[i++] = perf_mem_events__name(j);
50 } 104 };
51 105
52 for (j = 1; j < argc; j++, i++) 106 for (j = 0; j < argc; j++, i++)
53 rec_argv[i] = argv[j]; 107 rec_argv[i] = argv[j];
54 108
109 if (verbose > 0) {
110 pr_debug("calling: record ");
111
112 while (rec_argv[j]) {
113 pr_debug("%s ", rec_argv[j]);
114 j++;
115 }
116 pr_debug("\n");
117 }
118
55 ret = cmd_record(i, rec_argv, NULL); 119 ret = cmd_record(i, rec_argv, NULL);
56 free(rec_argv); 120 free(rec_argv);
57 return ret; 121 return ret;
@@ -298,6 +362,10 @@ int cmd_mem(int argc, const char **argv, const char *prefix __maybe_unused)
298 NULL 362 NULL
299 }; 363 };
300 364
365 if (perf_mem_events__init()) {
366 pr_err("failed: memory events not supported\n");
367 return -1;
368 }
301 369
302 argc = parse_options_subcommand(argc, argv, mem_options, mem_subcommands, 370 argc = parse_options_subcommand(argc, argv, mem_options, mem_subcommands,
303 mem_usage, PARSE_OPT_STOP_AT_NON_OPTION); 371 mem_usage, PARSE_OPT_STOP_AT_NON_OPTION);
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index 319712a4e02b..515510ecc76a 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -32,6 +32,8 @@
32#include "util/parse-branch-options.h" 32#include "util/parse-branch-options.h"
33#include "util/parse-regs-options.h" 33#include "util/parse-regs-options.h"
34#include "util/llvm-utils.h" 34#include "util/llvm-utils.h"
35#include "util/bpf-loader.h"
36#include "asm/bug.h"
35 37
36#include <unistd.h> 38#include <unistd.h>
37#include <sched.h> 39#include <sched.h>
@@ -49,7 +51,9 @@ struct record {
49 const char *progname; 51 const char *progname;
50 int realtime_prio; 52 int realtime_prio;
51 bool no_buildid; 53 bool no_buildid;
54 bool no_buildid_set;
52 bool no_buildid_cache; 55 bool no_buildid_cache;
56 bool no_buildid_cache_set;
53 bool buildid_all; 57 bool buildid_all;
54 unsigned long long samples; 58 unsigned long long samples;
55}; 59};
@@ -320,7 +324,10 @@ try_again:
320 } else { 324 } else {
321 pr_err("failed to mmap with %d (%s)\n", errno, 325 pr_err("failed to mmap with %d (%s)\n", errno,
322 strerror_r(errno, msg, sizeof(msg))); 326 strerror_r(errno, msg, sizeof(msg)));
323 rc = -errno; 327 if (errno)
328 rc = -errno;
329 else
330 rc = -EINVAL;
324 } 331 }
325 goto out; 332 goto out;
326 } 333 }
@@ -464,6 +471,29 @@ static void record__init_features(struct record *rec)
464 perf_header__clear_feat(&session->header, HEADER_STAT); 471 perf_header__clear_feat(&session->header, HEADER_STAT);
465} 472}
466 473
474static void
475record__finish_output(struct record *rec)
476{
477 struct perf_data_file *file = &rec->file;
478 int fd = perf_data_file__fd(file);
479
480 if (file->is_pipe)
481 return;
482
483 rec->session->header.data_size += rec->bytes_written;
484 file->size = lseek(perf_data_file__fd(file), 0, SEEK_CUR);
485
486 if (!rec->no_buildid) {
487 process_buildids(rec);
488
489 if (rec->buildid_all)
490 dsos__hit_all(rec->session);
491 }
492 perf_session__write_header(rec->session, rec->evlist, fd, true);
493
494 return;
495}
496
467static volatile int workload_exec_errno; 497static volatile int workload_exec_errno;
468 498
469/* 499/*
@@ -482,6 +512,74 @@ static void workload_exec_failed_signal(int signo __maybe_unused,
482 512
483static void snapshot_sig_handler(int sig); 513static void snapshot_sig_handler(int sig);
484 514
515static int record__synthesize(struct record *rec)
516{
517 struct perf_session *session = rec->session;
518 struct machine *machine = &session->machines.host;
519 struct perf_data_file *file = &rec->file;
520 struct record_opts *opts = &rec->opts;
521 struct perf_tool *tool = &rec->tool;
522 int fd = perf_data_file__fd(file);
523 int err = 0;
524
525 if (file->is_pipe) {
526 err = perf_event__synthesize_attrs(tool, session,
527 process_synthesized_event);
528 if (err < 0) {
529 pr_err("Couldn't synthesize attrs.\n");
530 goto out;
531 }
532
533 if (have_tracepoints(&rec->evlist->entries)) {
534 /*
535 * FIXME err <= 0 here actually means that
536 * there were no tracepoints so its not really
537 * an error, just that we don't need to
538 * synthesize anything. We really have to
539 * return this more properly and also
540 * propagate errors that now are calling die()
541 */
542 err = perf_event__synthesize_tracing_data(tool, fd, rec->evlist,
543 process_synthesized_event);
544 if (err <= 0) {
545 pr_err("Couldn't record tracing data.\n");
546 goto out;
547 }
548 rec->bytes_written += err;
549 }
550 }
551
552 if (rec->opts.full_auxtrace) {
553 err = perf_event__synthesize_auxtrace_info(rec->itr, tool,
554 session, process_synthesized_event);
555 if (err)
556 goto out;
557 }
558
559 err = perf_event__synthesize_kernel_mmap(tool, process_synthesized_event,
560 machine);
561 WARN_ONCE(err < 0, "Couldn't record kernel reference relocation symbol\n"
562 "Symbol resolution may be skewed if relocation was used (e.g. kexec).\n"
563 "Check /proc/kallsyms permission or run as root.\n");
564
565 err = perf_event__synthesize_modules(tool, process_synthesized_event,
566 machine);
567 WARN_ONCE(err < 0, "Couldn't record kernel module information.\n"
568 "Symbol resolution may be skewed if relocation was used (e.g. kexec).\n"
569 "Check /proc/modules permission or run as root.\n");
570
571 if (perf_guest) {
572 machines__process_guests(&session->machines,
573 perf_event__synthesize_guest_os, tool);
574 }
575
576 err = __machine__synthesize_threads(machine, tool, &opts->target, rec->evlist->threads,
577 process_synthesized_event, opts->sample_address,
578 opts->proc_map_timeout);
579out:
580 return err;
581}
582
485static int __cmd_record(struct record *rec, int argc, const char **argv) 583static int __cmd_record(struct record *rec, int argc, const char **argv)
486{ 584{
487 int err; 585 int err;
@@ -534,6 +632,16 @@ static int __cmd_record(struct record *rec, int argc, const char **argv)
534 goto out_child; 632 goto out_child;
535 } 633 }
536 634
635 err = bpf__apply_obj_config();
636 if (err) {
637 char errbuf[BUFSIZ];
638
639 bpf__strerror_apply_obj_config(err, errbuf, sizeof(errbuf));
640 pr_err("ERROR: Apply config to BPF failed: %s\n",
641 errbuf);
642 goto out_child;
643 }
644
537 /* 645 /*
538 * Normally perf_session__new would do this, but it doesn't have the 646 * Normally perf_session__new would do this, but it doesn't have the
539 * evlist. 647 * evlist.
@@ -566,63 +674,8 @@ static int __cmd_record(struct record *rec, int argc, const char **argv)
566 674
567 machine = &session->machines.host; 675 machine = &session->machines.host;
568 676
569 if (file->is_pipe) { 677 err = record__synthesize(rec);
570 err = perf_event__synthesize_attrs(tool, session,
571 process_synthesized_event);
572 if (err < 0) {
573 pr_err("Couldn't synthesize attrs.\n");
574 goto out_child;
575 }
576
577 if (have_tracepoints(&rec->evlist->entries)) {
578 /*
579 * FIXME err <= 0 here actually means that
580 * there were no tracepoints so its not really
581 * an error, just that we don't need to
582 * synthesize anything. We really have to
583 * return this more properly and also
584 * propagate errors that now are calling die()
585 */
586 err = perf_event__synthesize_tracing_data(tool, fd, rec->evlist,
587 process_synthesized_event);
588 if (err <= 0) {
589 pr_err("Couldn't record tracing data.\n");
590 goto out_child;
591 }
592 rec->bytes_written += err;
593 }
594 }
595
596 if (rec->opts.full_auxtrace) {
597 err = perf_event__synthesize_auxtrace_info(rec->itr, tool,
598 session, process_synthesized_event);
599 if (err)
600 goto out_delete_session;
601 }
602
603 err = perf_event__synthesize_kernel_mmap(tool, process_synthesized_event,
604 machine);
605 if (err < 0)
606 pr_err("Couldn't record kernel reference relocation symbol\n"
607 "Symbol resolution may be skewed if relocation was used (e.g. kexec).\n"
608 "Check /proc/kallsyms permission or run as root.\n");
609
610 err = perf_event__synthesize_modules(tool, process_synthesized_event,
611 machine);
612 if (err < 0) 678 if (err < 0)
613 pr_err("Couldn't record kernel module information.\n"
614 "Symbol resolution may be skewed if relocation was used (e.g. kexec).\n"
615 "Check /proc/modules permission or run as root.\n");
616
617 if (perf_guest) {
618 machines__process_guests(&session->machines,
619 perf_event__synthesize_guest_os, tool);
620 }
621
622 err = __machine__synthesize_threads(machine, tool, &opts->target, rec->evlist->threads,
623 process_synthesized_event, opts->sample_address,
624 opts->proc_map_timeout);
625 if (err != 0)
626 goto out_child; 679 goto out_child;
627 680
628 if (rec->realtime_prio) { 681 if (rec->realtime_prio) {
@@ -758,18 +811,8 @@ out_child:
758 /* this will be recalculated during process_buildids() */ 811 /* this will be recalculated during process_buildids() */
759 rec->samples = 0; 812 rec->samples = 0;
760 813
761 if (!err && !file->is_pipe) { 814 if (!err)
762 rec->session->header.data_size += rec->bytes_written; 815 record__finish_output(rec);
763 file->size = lseek(perf_data_file__fd(file), 0, SEEK_CUR);
764
765 if (!rec->no_buildid) {
766 process_buildids(rec);
767
768 if (rec->buildid_all)
769 dsos__hit_all(rec->session);
770 }
771 perf_session__write_header(rec->session, rec->evlist, fd, true);
772 }
773 816
774 if (!err && !quiet) { 817 if (!err && !quiet) {
775 char samples[128]; 818 char samples[128];
@@ -1097,10 +1140,12 @@ struct option __record_options[] = {
1097 OPT_BOOLEAN('P', "period", &record.opts.period, "Record the sample period"), 1140 OPT_BOOLEAN('P', "period", &record.opts.period, "Record the sample period"),
1098 OPT_BOOLEAN('n', "no-samples", &record.opts.no_samples, 1141 OPT_BOOLEAN('n', "no-samples", &record.opts.no_samples,
1099 "don't sample"), 1142 "don't sample"),
1100 OPT_BOOLEAN('N', "no-buildid-cache", &record.no_buildid_cache, 1143 OPT_BOOLEAN_SET('N', "no-buildid-cache", &record.no_buildid_cache,
1101 "do not update the buildid cache"), 1144 &record.no_buildid_cache_set,
1102 OPT_BOOLEAN('B', "no-buildid", &record.no_buildid, 1145 "do not update the buildid cache"),
1103 "do not collect buildids in perf.data"), 1146 OPT_BOOLEAN_SET('B', "no-buildid", &record.no_buildid,
1147 &record.no_buildid_set,
1148 "do not collect buildids in perf.data"),
1104 OPT_CALLBACK('G', "cgroup", &record.evlist, "name", 1149 OPT_CALLBACK('G', "cgroup", &record.evlist, "name",
1105 "monitor event in cgroup name only", 1150 "monitor event in cgroup name only",
1106 parse_cgroups), 1151 parse_cgroups),
@@ -1136,6 +1181,12 @@ struct option __record_options[] = {
1136 "per thread proc mmap processing timeout in ms"), 1181 "per thread proc mmap processing timeout in ms"),
1137 OPT_BOOLEAN(0, "switch-events", &record.opts.record_switch_events, 1182 OPT_BOOLEAN(0, "switch-events", &record.opts.record_switch_events,
1138 "Record context switch events"), 1183 "Record context switch events"),
1184 OPT_BOOLEAN_FLAG(0, "all-kernel", &record.opts.all_kernel,
1185 "Configure all used events to run in kernel space.",
1186 PARSE_OPT_EXCLUSIVE),
1187 OPT_BOOLEAN_FLAG(0, "all-user", &record.opts.all_user,
1188 "Configure all used events to run in user space.",
1189 PARSE_OPT_EXCLUSIVE),
1139 OPT_STRING(0, "clang-path", &llvm_param.clang_path, "clang path", 1190 OPT_STRING(0, "clang-path", &llvm_param.clang_path, "clang path",
1140 "clang binary to use for compiling BPF scriptlets"), 1191 "clang binary to use for compiling BPF scriptlets"),
1141 OPT_STRING(0, "clang-opt", &llvm_param.clang_opt, "clang options", 1192 OPT_STRING(0, "clang-opt", &llvm_param.clang_opt, "clang options",
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
index 2bf537f190a0..7eea49f9ed46 100644
--- a/tools/perf/builtin-report.c
+++ b/tools/perf/builtin-report.c
@@ -75,7 +75,10 @@ static int report__config(const char *var, const char *value, void *cb)
75 return 0; 75 return 0;
76 } 76 }
77 if (!strcmp(var, "report.percent-limit")) { 77 if (!strcmp(var, "report.percent-limit")) {
78 rep->min_percent = strtof(value, NULL); 78 double pcnt = strtof(value, NULL);
79
80 rep->min_percent = pcnt;
81 callchain_param.min_percent = pcnt;
79 return 0; 82 return 0;
80 } 83 }
81 if (!strcmp(var, "report.children")) { 84 if (!strcmp(var, "report.children")) {
@@ -87,7 +90,7 @@ static int report__config(const char *var, const char *value, void *cb)
87 return 0; 90 return 0;
88 } 91 }
89 92
90 return perf_default_config(var, value, cb); 93 return 0;
91} 94}
92 95
93static int hist_iter__report_callback(struct hist_entry_iter *iter, 96static int hist_iter__report_callback(struct hist_entry_iter *iter,
@@ -466,10 +469,11 @@ static int report__browse_hists(struct report *rep)
466 return ret; 469 return ret;
467} 470}
468 471
469static void report__collapse_hists(struct report *rep) 472static int report__collapse_hists(struct report *rep)
470{ 473{
471 struct ui_progress prog; 474 struct ui_progress prog;
472 struct perf_evsel *pos; 475 struct perf_evsel *pos;
476 int ret = 0;
473 477
474 ui_progress__init(&prog, rep->nr_entries, "Merging related events..."); 478 ui_progress__init(&prog, rep->nr_entries, "Merging related events...");
475 479
@@ -481,7 +485,9 @@ static void report__collapse_hists(struct report *rep)
481 485
482 hists->socket_filter = rep->socket_filter; 486 hists->socket_filter = rep->socket_filter;
483 487
484 hists__collapse_resort(hists, &prog); 488 ret = hists__collapse_resort(hists, &prog);
489 if (ret < 0)
490 break;
485 491
486 /* Non-group events are considered as leader */ 492 /* Non-group events are considered as leader */
487 if (symbol_conf.event_group && 493 if (symbol_conf.event_group &&
@@ -494,6 +500,7 @@ static void report__collapse_hists(struct report *rep)
494 } 500 }
495 501
496 ui_progress__finish(); 502 ui_progress__finish();
503 return ret;
497} 504}
498 505
499static void report__output_resort(struct report *rep) 506static void report__output_resort(struct report *rep)
@@ -504,7 +511,7 @@ static void report__output_resort(struct report *rep)
504 ui_progress__init(&prog, rep->nr_entries, "Sorting events for output..."); 511 ui_progress__init(&prog, rep->nr_entries, "Sorting events for output...");
505 512
506 evlist__for_each(rep->session->evlist, pos) 513 evlist__for_each(rep->session->evlist, pos)
507 hists__output_resort(evsel__hists(pos), &prog); 514 perf_evsel__output_resort(pos, &prog);
508 515
509 ui_progress__finish(); 516 ui_progress__finish();
510} 517}
@@ -561,7 +568,11 @@ static int __cmd_report(struct report *rep)
561 } 568 }
562 } 569 }
563 570
564 report__collapse_hists(rep); 571 ret = report__collapse_hists(rep);
572 if (ret) {
573 ui__error("failed to process hist entry\n");
574 return ret;
575 }
565 576
566 if (session_done()) 577 if (session_done())
567 return 0; 578 return 0;
@@ -633,8 +644,10 @@ parse_percent_limit(const struct option *opt, const char *str,
633 int unset __maybe_unused) 644 int unset __maybe_unused)
634{ 645{
635 struct report *rep = opt->value; 646 struct report *rep = opt->value;
647 double pcnt = strtof(str, NULL);
636 648
637 rep->min_percent = strtof(str, NULL); 649 rep->min_percent = pcnt;
650 callchain_param.min_percent = pcnt;
638 return 0; 651 return 0;
639} 652}
640 653
@@ -798,6 +811,8 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
798 "only show processor socket that match with this filter"), 811 "only show processor socket that match with this filter"),
799 OPT_BOOLEAN(0, "raw-trace", &symbol_conf.raw_trace, 812 OPT_BOOLEAN(0, "raw-trace", &symbol_conf.raw_trace,
800 "Show raw trace event output (do not use print fmt or plugins)"), 813 "Show raw trace event output (do not use print fmt or plugins)"),
814 OPT_BOOLEAN(0, "hierarchy", &symbol_conf.report_hierarchy,
815 "Show entries in a hierarchy"),
801 OPT_END() 816 OPT_END()
802 }; 817 };
803 struct perf_data_file file = { 818 struct perf_data_file file = {
@@ -907,13 +922,19 @@ repeat:
907 symbol_conf.cumulate_callchain = false; 922 symbol_conf.cumulate_callchain = false;
908 } 923 }
909 924
910 if (setup_sorting(session->evlist) < 0) { 925 if (symbol_conf.report_hierarchy) {
911 if (sort_order) 926 /* disable incompatible options */
912 parse_options_usage(report_usage, options, "s", 1); 927 symbol_conf.event_group = false;
913 if (field_order) 928 symbol_conf.cumulate_callchain = false;
914 parse_options_usage(sort_order ? NULL : report_usage, 929
915 options, "F", 1); 930 if (field_order) {
916 goto error; 931 pr_err("Error: --hierarchy and --fields options cannot be used together\n");
932 parse_options_usage(report_usage, options, "F", 1);
933 parse_options_usage(NULL, options, "hierarchy", 0);
934 goto error;
935 }
936
937 sort__need_collapse = true;
917 } 938 }
918 939
919 /* Force tty output for header output and per-thread stat. */ 940 /* Force tty output for header output and per-thread stat. */
@@ -925,6 +946,15 @@ repeat:
925 else 946 else
926 use_browser = 0; 947 use_browser = 0;
927 948
949 if (setup_sorting(session->evlist) < 0) {
950 if (sort_order)
951 parse_options_usage(report_usage, options, "s", 1);
952 if (field_order)
953 parse_options_usage(sort_order ? NULL : report_usage,
954 options, "F", 1);
955 goto error;
956 }
957
928 if (report.header || report.header_only) { 958 if (report.header || report.header_only) {
929 perf_session__fprintf_info(session, stdout, 959 perf_session__fprintf_info(session, stdout,
930 report.show_full_info); 960 report.show_full_info);
diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c
index c691214d820f..57f9a7e7f7d3 100644
--- a/tools/perf/builtin-script.c
+++ b/tools/perf/builtin-script.c
@@ -23,6 +23,7 @@
23#include "util/stat.h" 23#include "util/stat.h"
24#include <linux/bitmap.h> 24#include <linux/bitmap.h>
25#include "asm/bug.h" 25#include "asm/bug.h"
26#include "util/mem-events.h"
26 27
27static char const *script_name; 28static char const *script_name;
28static char const *generate_script_lang; 29static char const *generate_script_lang;
@@ -58,6 +59,9 @@ enum perf_output_field {
58 PERF_OUTPUT_IREGS = 1U << 14, 59 PERF_OUTPUT_IREGS = 1U << 14,
59 PERF_OUTPUT_BRSTACK = 1U << 15, 60 PERF_OUTPUT_BRSTACK = 1U << 15,
60 PERF_OUTPUT_BRSTACKSYM = 1U << 16, 61 PERF_OUTPUT_BRSTACKSYM = 1U << 16,
62 PERF_OUTPUT_DATA_SRC = 1U << 17,
63 PERF_OUTPUT_WEIGHT = 1U << 18,
64 PERF_OUTPUT_BPF_OUTPUT = 1U << 19,
61}; 65};
62 66
63struct output_option { 67struct output_option {
@@ -81,6 +85,9 @@ struct output_option {
81 {.str = "iregs", .field = PERF_OUTPUT_IREGS}, 85 {.str = "iregs", .field = PERF_OUTPUT_IREGS},
82 {.str = "brstack", .field = PERF_OUTPUT_BRSTACK}, 86 {.str = "brstack", .field = PERF_OUTPUT_BRSTACK},
83 {.str = "brstacksym", .field = PERF_OUTPUT_BRSTACKSYM}, 87 {.str = "brstacksym", .field = PERF_OUTPUT_BRSTACKSYM},
88 {.str = "data_src", .field = PERF_OUTPUT_DATA_SRC},
89 {.str = "weight", .field = PERF_OUTPUT_WEIGHT},
90 {.str = "bpf-output", .field = PERF_OUTPUT_BPF_OUTPUT},
84}; 91};
85 92
86/* default set to maintain compatibility with current format */ 93/* default set to maintain compatibility with current format */
@@ -101,7 +108,7 @@ static struct {
101 PERF_OUTPUT_SYM | PERF_OUTPUT_DSO | 108 PERF_OUTPUT_SYM | PERF_OUTPUT_DSO |
102 PERF_OUTPUT_PERIOD, 109 PERF_OUTPUT_PERIOD,
103 110
104 .invalid_fields = PERF_OUTPUT_TRACE, 111 .invalid_fields = PERF_OUTPUT_TRACE | PERF_OUTPUT_BPF_OUTPUT,
105 }, 112 },
106 113
107 [PERF_TYPE_SOFTWARE] = { 114 [PERF_TYPE_SOFTWARE] = {
@@ -111,7 +118,7 @@ static struct {
111 PERF_OUTPUT_CPU | PERF_OUTPUT_TIME | 118 PERF_OUTPUT_CPU | PERF_OUTPUT_TIME |
112 PERF_OUTPUT_EVNAME | PERF_OUTPUT_IP | 119 PERF_OUTPUT_EVNAME | PERF_OUTPUT_IP |
113 PERF_OUTPUT_SYM | PERF_OUTPUT_DSO | 120 PERF_OUTPUT_SYM | PERF_OUTPUT_DSO |
114 PERF_OUTPUT_PERIOD, 121 PERF_OUTPUT_PERIOD | PERF_OUTPUT_BPF_OUTPUT,
115 122
116 .invalid_fields = PERF_OUTPUT_TRACE, 123 .invalid_fields = PERF_OUTPUT_TRACE,
117 }, 124 },
@@ -121,7 +128,7 @@ static struct {
121 128
122 .fields = PERF_OUTPUT_COMM | PERF_OUTPUT_TID | 129 .fields = PERF_OUTPUT_COMM | PERF_OUTPUT_TID |
123 PERF_OUTPUT_CPU | PERF_OUTPUT_TIME | 130 PERF_OUTPUT_CPU | PERF_OUTPUT_TIME |
124 PERF_OUTPUT_EVNAME | PERF_OUTPUT_TRACE, 131 PERF_OUTPUT_EVNAME | PERF_OUTPUT_TRACE
125 }, 132 },
126 133
127 [PERF_TYPE_RAW] = { 134 [PERF_TYPE_RAW] = {
@@ -131,9 +138,10 @@ static struct {
131 PERF_OUTPUT_CPU | PERF_OUTPUT_TIME | 138 PERF_OUTPUT_CPU | PERF_OUTPUT_TIME |
132 PERF_OUTPUT_EVNAME | PERF_OUTPUT_IP | 139 PERF_OUTPUT_EVNAME | PERF_OUTPUT_IP |
133 PERF_OUTPUT_SYM | PERF_OUTPUT_DSO | 140 PERF_OUTPUT_SYM | PERF_OUTPUT_DSO |
134 PERF_OUTPUT_PERIOD, 141 PERF_OUTPUT_PERIOD | PERF_OUTPUT_ADDR |
142 PERF_OUTPUT_DATA_SRC | PERF_OUTPUT_WEIGHT,
135 143
136 .invalid_fields = PERF_OUTPUT_TRACE, 144 .invalid_fields = PERF_OUTPUT_TRACE | PERF_OUTPUT_BPF_OUTPUT,
137 }, 145 },
138 146
139 [PERF_TYPE_BREAKPOINT] = { 147 [PERF_TYPE_BREAKPOINT] = {
@@ -145,7 +153,7 @@ static struct {
145 PERF_OUTPUT_SYM | PERF_OUTPUT_DSO | 153 PERF_OUTPUT_SYM | PERF_OUTPUT_DSO |
146 PERF_OUTPUT_PERIOD, 154 PERF_OUTPUT_PERIOD,
147 155
148 .invalid_fields = PERF_OUTPUT_TRACE, 156 .invalid_fields = PERF_OUTPUT_TRACE | PERF_OUTPUT_BPF_OUTPUT,
149 }, 157 },
150}; 158};
151 159
@@ -242,6 +250,16 @@ static int perf_evsel__check_attr(struct perf_evsel *evsel,
242 PERF_OUTPUT_ADDR, allow_user_set)) 250 PERF_OUTPUT_ADDR, allow_user_set))
243 return -EINVAL; 251 return -EINVAL;
244 252
253 if (PRINT_FIELD(DATA_SRC) &&
254 perf_evsel__check_stype(evsel, PERF_SAMPLE_DATA_SRC, "DATA_SRC",
255 PERF_OUTPUT_DATA_SRC))
256 return -EINVAL;
257
258 if (PRINT_FIELD(WEIGHT) &&
259 perf_evsel__check_stype(evsel, PERF_SAMPLE_WEIGHT, "WEIGHT",
260 PERF_OUTPUT_WEIGHT))
261 return -EINVAL;
262
245 if (PRINT_FIELD(SYM) && !PRINT_FIELD(IP) && !PRINT_FIELD(ADDR)) { 263 if (PRINT_FIELD(SYM) && !PRINT_FIELD(IP) && !PRINT_FIELD(ADDR)) {
246 pr_err("Display of symbols requested but neither sample IP nor " 264 pr_err("Display of symbols requested but neither sample IP nor "
247 "sample address\nis selected. Hence, no addresses to convert " 265 "sample address\nis selected. Hence, no addresses to convert "
@@ -608,6 +626,84 @@ static void print_sample_flags(u32 flags)
608 printf(" %-4s ", str); 626 printf(" %-4s ", str);
609} 627}
610 628
629struct printer_data {
630 int line_no;
631 bool hit_nul;
632 bool is_printable;
633};
634
635static void
636print_sample_bpf_output_printer(enum binary_printer_ops op,
637 unsigned int val,
638 void *extra)
639{
640 unsigned char ch = (unsigned char)val;
641 struct printer_data *printer_data = extra;
642
643 switch (op) {
644 case BINARY_PRINT_DATA_BEGIN:
645 printf("\n");
646 break;
647 case BINARY_PRINT_LINE_BEGIN:
648 printf("%17s", !printer_data->line_no ? "BPF output:" :
649 " ");
650 break;
651 case BINARY_PRINT_ADDR:
652 printf(" %04x:", val);
653 break;
654 case BINARY_PRINT_NUM_DATA:
655 printf(" %02x", val);
656 break;
657 case BINARY_PRINT_NUM_PAD:
658 printf(" ");
659 break;
660 case BINARY_PRINT_SEP:
661 printf(" ");
662 break;
663 case BINARY_PRINT_CHAR_DATA:
664 if (printer_data->hit_nul && ch)
665 printer_data->is_printable = false;
666
667 if (!isprint(ch)) {
668 printf("%c", '.');
669
670 if (!printer_data->is_printable)
671 break;
672
673 if (ch == '\0')
674 printer_data->hit_nul = true;
675 else
676 printer_data->is_printable = false;
677 } else {
678 printf("%c", ch);
679 }
680 break;
681 case BINARY_PRINT_CHAR_PAD:
682 printf(" ");
683 break;
684 case BINARY_PRINT_LINE_END:
685 printf("\n");
686 printer_data->line_no++;
687 break;
688 case BINARY_PRINT_DATA_END:
689 default:
690 break;
691 }
692}
693
694static void print_sample_bpf_output(struct perf_sample *sample)
695{
696 unsigned int nr_bytes = sample->raw_size;
697 struct printer_data printer_data = {0, false, true};
698
699 print_binary(sample->raw_data, nr_bytes, 8,
700 print_sample_bpf_output_printer, &printer_data);
701
702 if (printer_data.is_printable && printer_data.hit_nul)
703 printf("%17s \"%s\"\n", "BPF string:",
704 (char *)(sample->raw_data));
705}
706
611struct perf_script { 707struct perf_script {
612 struct perf_tool tool; 708 struct perf_tool tool;
613 struct perf_session *session; 709 struct perf_session *session;
@@ -634,6 +730,23 @@ static int perf_evlist__max_name_len(struct perf_evlist *evlist)
634 return max; 730 return max;
635} 731}
636 732
733static size_t data_src__printf(u64 data_src)
734{
735 struct mem_info mi = { .data_src.val = data_src };
736 char decode[100];
737 char out[100];
738 static int maxlen;
739 int len;
740
741 perf_script__meminfo_scnprintf(decode, 100, &mi);
742
743 len = scnprintf(out, 100, "%16" PRIx64 " %s", data_src, decode);
744 if (maxlen < len)
745 maxlen = len;
746
747 return printf("%-*s", maxlen, out);
748}
749
637static void process_event(struct perf_script *script, union perf_event *event, 750static void process_event(struct perf_script *script, union perf_event *event,
638 struct perf_sample *sample, struct perf_evsel *evsel, 751 struct perf_sample *sample, struct perf_evsel *evsel,
639 struct addr_location *al) 752 struct addr_location *al)
@@ -673,6 +786,12 @@ static void process_event(struct perf_script *script, union perf_event *event,
673 if (PRINT_FIELD(ADDR)) 786 if (PRINT_FIELD(ADDR))
674 print_sample_addr(event, sample, thread, attr); 787 print_sample_addr(event, sample, thread, attr);
675 788
789 if (PRINT_FIELD(DATA_SRC))
790 data_src__printf(sample->data_src);
791
792 if (PRINT_FIELD(WEIGHT))
793 printf("%16" PRIu64, sample->weight);
794
676 if (PRINT_FIELD(IP)) { 795 if (PRINT_FIELD(IP)) {
677 if (!symbol_conf.use_callchain) 796 if (!symbol_conf.use_callchain)
678 printf(" "); 797 printf(" ");
@@ -692,6 +811,9 @@ static void process_event(struct perf_script *script, union perf_event *event,
692 else if (PRINT_FIELD(BRSTACKSYM)) 811 else if (PRINT_FIELD(BRSTACKSYM))
693 print_sample_brstacksym(event, sample, thread, attr); 812 print_sample_brstacksym(event, sample, thread, attr);
694 813
814 if (perf_evsel__is_bpf_output(evsel) && PRINT_FIELD(BPF_OUTPUT))
815 print_sample_bpf_output(sample);
816
695 printf("\n"); 817 printf("\n");
696} 818}
697 819
@@ -1090,23 +1212,6 @@ static struct script_spec *script_spec__find(const char *spec)
1090 return NULL; 1212 return NULL;
1091} 1213}
1092 1214
1093static struct script_spec *script_spec__findnew(const char *spec,
1094 struct scripting_ops *ops)
1095{
1096 struct script_spec *s = script_spec__find(spec);
1097
1098 if (s)
1099 return s;
1100
1101 s = script_spec__new(spec, ops);
1102 if (!s)
1103 return NULL;
1104
1105 script_spec__add(s);
1106
1107 return s;
1108}
1109
1110int script_spec_register(const char *spec, struct scripting_ops *ops) 1215int script_spec_register(const char *spec, struct scripting_ops *ops)
1111{ 1216{
1112 struct script_spec *s; 1217 struct script_spec *s;
@@ -1115,9 +1220,11 @@ int script_spec_register(const char *spec, struct scripting_ops *ops)
1115 if (s) 1220 if (s)
1116 return -1; 1221 return -1;
1117 1222
1118 s = script_spec__findnew(spec, ops); 1223 s = script_spec__new(spec, ops);
1119 if (!s) 1224 if (!s)
1120 return -1; 1225 return -1;
1226 else
1227 script_spec__add(s);
1121 1228
1122 return 0; 1229 return 0;
1123} 1230}
diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c
index 038e877081b6..1f19f2f999c8 100644
--- a/tools/perf/builtin-stat.c
+++ b/tools/perf/builtin-stat.c
@@ -122,6 +122,7 @@ static bool sync_run = false;
122static unsigned int initial_delay = 0; 122static unsigned int initial_delay = 0;
123static unsigned int unit_width = 4; /* strlen("unit") */ 123static unsigned int unit_width = 4; /* strlen("unit") */
124static bool forever = false; 124static bool forever = false;
125static bool metric_only = false;
125static struct timespec ref_time; 126static struct timespec ref_time;
126static struct cpu_map *aggr_map; 127static struct cpu_map *aggr_map;
127static aggr_get_id_t aggr_get_id; 128static aggr_get_id_t aggr_get_id;
@@ -735,6 +736,191 @@ static void aggr_printout(struct perf_evsel *evsel, int id, int nr)
735 } 736 }
736} 737}
737 738
739struct outstate {
740 FILE *fh;
741 bool newline;
742 const char *prefix;
743 int nfields;
744 int id, nr;
745 struct perf_evsel *evsel;
746};
747
748#define METRIC_LEN 35
749
750static void new_line_std(void *ctx)
751{
752 struct outstate *os = ctx;
753
754 os->newline = true;
755}
756
757static void do_new_line_std(struct outstate *os)
758{
759 fputc('\n', os->fh);
760 fputs(os->prefix, os->fh);
761 aggr_printout(os->evsel, os->id, os->nr);
762 if (stat_config.aggr_mode == AGGR_NONE)
763 fprintf(os->fh, " ");
764 fprintf(os->fh, " ");
765}
766
767static void print_metric_std(void *ctx, const char *color, const char *fmt,
768 const char *unit, double val)
769{
770 struct outstate *os = ctx;
771 FILE *out = os->fh;
772 int n;
773 bool newline = os->newline;
774
775 os->newline = false;
776
777 if (unit == NULL || fmt == NULL) {
778 fprintf(out, "%-*s", METRIC_LEN, "");
779 return;
780 }
781
782 if (newline)
783 do_new_line_std(os);
784
785 n = fprintf(out, " # ");
786 if (color)
787 n += color_fprintf(out, color, fmt, val);
788 else
789 n += fprintf(out, fmt, val);
790 fprintf(out, " %-*s", METRIC_LEN - n - 1, unit);
791}
792
793static void new_line_csv(void *ctx)
794{
795 struct outstate *os = ctx;
796 int i;
797
798 fputc('\n', os->fh);
799 if (os->prefix)
800 fprintf(os->fh, "%s%s", os->prefix, csv_sep);
801 aggr_printout(os->evsel, os->id, os->nr);
802 for (i = 0; i < os->nfields; i++)
803 fputs(csv_sep, os->fh);
804}
805
806static void print_metric_csv(void *ctx,
807 const char *color __maybe_unused,
808 const char *fmt, const char *unit, double val)
809{
810 struct outstate *os = ctx;
811 FILE *out = os->fh;
812 char buf[64], *vals, *ends;
813
814 if (unit == NULL || fmt == NULL) {
815 fprintf(out, "%s%s%s%s", csv_sep, csv_sep, csv_sep, csv_sep);
816 return;
817 }
818 snprintf(buf, sizeof(buf), fmt, val);
819 vals = buf;
820 while (isspace(*vals))
821 vals++;
822 ends = vals;
823 while (isdigit(*ends) || *ends == '.')
824 ends++;
825 *ends = 0;
826 while (isspace(*unit))
827 unit++;
828 fprintf(out, "%s%s%s%s", csv_sep, vals, csv_sep, unit);
829}
830
831#define METRIC_ONLY_LEN 20
832
833/* Filter out some columns that don't work well in metrics only mode */
834
835static bool valid_only_metric(const char *unit)
836{
837 if (!unit)
838 return false;
839 if (strstr(unit, "/sec") ||
840 strstr(unit, "hz") ||
841 strstr(unit, "Hz") ||
842 strstr(unit, "CPUs utilized"))
843 return false;
844 return true;
845}
846
847static const char *fixunit(char *buf, struct perf_evsel *evsel,
848 const char *unit)
849{
850 if (!strncmp(unit, "of all", 6)) {
851 snprintf(buf, 1024, "%s %s", perf_evsel__name(evsel),
852 unit);
853 return buf;
854 }
855 return unit;
856}
857
858static void print_metric_only(void *ctx, const char *color, const char *fmt,
859 const char *unit, double val)
860{
861 struct outstate *os = ctx;
862 FILE *out = os->fh;
863 int n;
864 char buf[1024];
865 unsigned mlen = METRIC_ONLY_LEN;
866
867 if (!valid_only_metric(unit))
868 return;
869 unit = fixunit(buf, os->evsel, unit);
870 if (color)
871 n = color_fprintf(out, color, fmt, val);
872 else
873 n = fprintf(out, fmt, val);
874 if (n > METRIC_ONLY_LEN)
875 n = METRIC_ONLY_LEN;
876 if (mlen < strlen(unit))
877 mlen = strlen(unit) + 1;
878 fprintf(out, "%*s", mlen - n, "");
879}
880
881static void print_metric_only_csv(void *ctx, const char *color __maybe_unused,
882 const char *fmt,
883 const char *unit, double val)
884{
885 struct outstate *os = ctx;
886 FILE *out = os->fh;
887 char buf[64], *vals, *ends;
888 char tbuf[1024];
889
890 if (!valid_only_metric(unit))
891 return;
892 unit = fixunit(tbuf, os->evsel, unit);
893 snprintf(buf, sizeof buf, fmt, val);
894 vals = buf;
895 while (isspace(*vals))
896 vals++;
897 ends = vals;
898 while (isdigit(*ends) || *ends == '.')
899 ends++;
900 *ends = 0;
901 fprintf(out, "%s%s", vals, csv_sep);
902}
903
904static void new_line_metric(void *ctx __maybe_unused)
905{
906}
907
908static void print_metric_header(void *ctx, const char *color __maybe_unused,
909 const char *fmt __maybe_unused,
910 const char *unit, double val __maybe_unused)
911{
912 struct outstate *os = ctx;
913 char tbuf[1024];
914
915 if (!valid_only_metric(unit))
916 return;
917 unit = fixunit(tbuf, os->evsel, unit);
918 if (csv_output)
919 fprintf(os->fh, "%s%s", unit, csv_sep);
920 else
921 fprintf(os->fh, "%-*s ", METRIC_ONLY_LEN, unit);
922}
923
738static void nsec_printout(int id, int nr, struct perf_evsel *evsel, double avg) 924static void nsec_printout(int id, int nr, struct perf_evsel *evsel, double avg)
739{ 925{
740 FILE *output = stat_config.output; 926 FILE *output = stat_config.output;
@@ -763,6 +949,28 @@ static void nsec_printout(int id, int nr, struct perf_evsel *evsel, double avg)
763 fprintf(output, "%s%s", csv_sep, evsel->cgrp->name); 949 fprintf(output, "%s%s", csv_sep, evsel->cgrp->name);
764} 950}
765 951
952static int first_shadow_cpu(struct perf_evsel *evsel, int id)
953{
954 int i;
955
956 if (!aggr_get_id)
957 return 0;
958
959 if (stat_config.aggr_mode == AGGR_NONE)
960 return id;
961
962 if (stat_config.aggr_mode == AGGR_GLOBAL)
963 return 0;
964
965 for (i = 0; i < perf_evsel__nr_cpus(evsel); i++) {
966 int cpu2 = perf_evsel__cpus(evsel)->map[i];
967
968 if (aggr_get_id(evsel_list->cpus, cpu2) == id)
969 return cpu2;
970 }
971 return 0;
972}
973
766static void abs_printout(int id, int nr, struct perf_evsel *evsel, double avg) 974static void abs_printout(int id, int nr, struct perf_evsel *evsel, double avg)
767{ 975{
768 FILE *output = stat_config.output; 976 FILE *output = stat_config.output;
@@ -793,22 +1001,124 @@ static void abs_printout(int id, int nr, struct perf_evsel *evsel, double avg)
793 fprintf(output, "%s%s", csv_sep, evsel->cgrp->name); 1001 fprintf(output, "%s%s", csv_sep, evsel->cgrp->name);
794} 1002}
795 1003
796static void printout(int id, int nr, struct perf_evsel *counter, double uval) 1004static void printout(int id, int nr, struct perf_evsel *counter, double uval,
1005 char *prefix, u64 run, u64 ena, double noise)
797{ 1006{
798 int cpu = cpu_map__id_to_cpu(id); 1007 struct perf_stat_output_ctx out;
1008 struct outstate os = {
1009 .fh = stat_config.output,
1010 .prefix = prefix ? prefix : "",
1011 .id = id,
1012 .nr = nr,
1013 .evsel = counter,
1014 };
1015 print_metric_t pm = print_metric_std;
1016 void (*nl)(void *);
799 1017
800 if (stat_config.aggr_mode == AGGR_GLOBAL) 1018 if (metric_only) {
801 cpu = 0; 1019 nl = new_line_metric;
1020 if (csv_output)
1021 pm = print_metric_only_csv;
1022 else
1023 pm = print_metric_only;
1024 } else
1025 nl = new_line_std;
1026
1027 if (csv_output && !metric_only) {
1028 static int aggr_fields[] = {
1029 [AGGR_GLOBAL] = 0,
1030 [AGGR_THREAD] = 1,
1031 [AGGR_NONE] = 1,
1032 [AGGR_SOCKET] = 2,
1033 [AGGR_CORE] = 2,
1034 };
1035
1036 pm = print_metric_csv;
1037 nl = new_line_csv;
1038 os.nfields = 3;
1039 os.nfields += aggr_fields[stat_config.aggr_mode];
1040 if (counter->cgrp)
1041 os.nfields++;
1042 }
1043 if (run == 0 || ena == 0 || counter->counts->scaled == -1) {
1044 if (metric_only) {
1045 pm(&os, NULL, "", "", 0);
1046 return;
1047 }
1048 aggr_printout(counter, id, nr);
1049
1050 fprintf(stat_config.output, "%*s%s",
1051 csv_output ? 0 : 18,
1052 counter->supported ? CNTR_NOT_COUNTED : CNTR_NOT_SUPPORTED,
1053 csv_sep);
1054
1055 fprintf(stat_config.output, "%-*s%s",
1056 csv_output ? 0 : unit_width,
1057 counter->unit, csv_sep);
1058
1059 fprintf(stat_config.output, "%*s",
1060 csv_output ? 0 : -25,
1061 perf_evsel__name(counter));
1062
1063 if (counter->cgrp)
1064 fprintf(stat_config.output, "%s%s",
1065 csv_sep, counter->cgrp->name);
802 1066
803 if (nsec_counter(counter)) 1067 if (!csv_output)
1068 pm(&os, NULL, NULL, "", 0);
1069 print_noise(counter, noise);
1070 print_running(run, ena);
1071 if (csv_output)
1072 pm(&os, NULL, NULL, "", 0);
1073 return;
1074 }
1075
1076 if (metric_only)
1077 /* nothing */;
1078 else if (nsec_counter(counter))
804 nsec_printout(id, nr, counter, uval); 1079 nsec_printout(id, nr, counter, uval);
805 else 1080 else
806 abs_printout(id, nr, counter, uval); 1081 abs_printout(id, nr, counter, uval);
807 1082
808 if (!csv_output && !stat_config.interval) 1083 out.print_metric = pm;
809 perf_stat__print_shadow_stats(stat_config.output, counter, 1084 out.new_line = nl;
810 uval, cpu, 1085 out.ctx = &os;
811 stat_config.aggr_mode); 1086
1087 if (csv_output && !metric_only) {
1088 print_noise(counter, noise);
1089 print_running(run, ena);
1090 }
1091
1092 perf_stat__print_shadow_stats(counter, uval,
1093 first_shadow_cpu(counter, id),
1094 &out);
1095 if (!csv_output && !metric_only) {
1096 print_noise(counter, noise);
1097 print_running(run, ena);
1098 }
1099}
1100
1101static void aggr_update_shadow(void)
1102{
1103 int cpu, s2, id, s;
1104 u64 val;
1105 struct perf_evsel *counter;
1106
1107 for (s = 0; s < aggr_map->nr; s++) {
1108 id = aggr_map->map[s];
1109 evlist__for_each(evsel_list, counter) {
1110 val = 0;
1111 for (cpu = 0; cpu < perf_evsel__nr_cpus(counter); cpu++) {
1112 s2 = aggr_get_id(evsel_list->cpus, cpu);
1113 if (s2 != id)
1114 continue;
1115 val += perf_counts(counter->counts, cpu, 0)->val;
1116 }
1117 val = val * counter->scale;
1118 perf_stat__update_shadow_stats(counter, &val,
1119 first_shadow_cpu(counter, id));
1120 }
1121 }
812} 1122}
813 1123
814static void print_aggr(char *prefix) 1124static void print_aggr(char *prefix)
@@ -818,12 +1128,23 @@ static void print_aggr(char *prefix)
818 int cpu, s, s2, id, nr; 1128 int cpu, s, s2, id, nr;
819 double uval; 1129 double uval;
820 u64 ena, run, val; 1130 u64 ena, run, val;
1131 bool first;
821 1132
822 if (!(aggr_map || aggr_get_id)) 1133 if (!(aggr_map || aggr_get_id))
823 return; 1134 return;
824 1135
1136 aggr_update_shadow();
1137
1138 /*
1139 * With metric_only everything is on a single line.
1140 * Without each counter has its own line.
1141 */
825 for (s = 0; s < aggr_map->nr; s++) { 1142 for (s = 0; s < aggr_map->nr; s++) {
1143 if (prefix && metric_only)
1144 fprintf(output, "%s", prefix);
1145
826 id = aggr_map->map[s]; 1146 id = aggr_map->map[s];
1147 first = true;
827 evlist__for_each(evsel_list, counter) { 1148 evlist__for_each(evsel_list, counter) {
828 val = ena = run = 0; 1149 val = ena = run = 0;
829 nr = 0; 1150 nr = 0;
@@ -836,41 +1157,20 @@ static void print_aggr(char *prefix)
836 run += perf_counts(counter->counts, cpu, 0)->run; 1157 run += perf_counts(counter->counts, cpu, 0)->run;
837 nr++; 1158 nr++;
838 } 1159 }
839 if (prefix) 1160 if (first && metric_only) {
840 fprintf(output, "%s", prefix); 1161 first = false;
841
842 if (run == 0 || ena == 0) {
843 aggr_printout(counter, id, nr); 1162 aggr_printout(counter, id, nr);
844
845 fprintf(output, "%*s%s",
846 csv_output ? 0 : 18,
847 counter->supported ? CNTR_NOT_COUNTED : CNTR_NOT_SUPPORTED,
848 csv_sep);
849
850 fprintf(output, "%-*s%s",
851 csv_output ? 0 : unit_width,
852 counter->unit, csv_sep);
853
854 fprintf(output, "%*s",
855 csv_output ? 0 : -25,
856 perf_evsel__name(counter));
857
858 if (counter->cgrp)
859 fprintf(output, "%s%s",
860 csv_sep, counter->cgrp->name);
861
862 print_running(run, ena);
863 fputc('\n', output);
864 continue;
865 } 1163 }
866 uval = val * counter->scale; 1164 if (prefix && !metric_only)
867 printout(id, nr, counter, uval); 1165 fprintf(output, "%s", prefix);
868 if (!csv_output)
869 print_noise(counter, 1.0);
870 1166
871 print_running(run, ena); 1167 uval = val * counter->scale;
872 fputc('\n', output); 1168 printout(id, nr, counter, uval, prefix, run, ena, 1.0);
1169 if (!metric_only)
1170 fputc('\n', output);
873 } 1171 }
1172 if (metric_only)
1173 fputc('\n', output);
874 } 1174 }
875} 1175}
876 1176
@@ -895,12 +1195,7 @@ static void print_aggr_thread(struct perf_evsel *counter, char *prefix)
895 fprintf(output, "%s", prefix); 1195 fprintf(output, "%s", prefix);
896 1196
897 uval = val * counter->scale; 1197 uval = val * counter->scale;
898 printout(thread, 0, counter, uval); 1198 printout(thread, 0, counter, uval, prefix, run, ena, 1.0);
899
900 if (!csv_output)
901 print_noise(counter, 1.0);
902
903 print_running(run, ena);
904 fputc('\n', output); 1199 fputc('\n', output);
905 } 1200 }
906} 1201}
@@ -914,43 +1209,19 @@ static void print_counter_aggr(struct perf_evsel *counter, char *prefix)
914 FILE *output = stat_config.output; 1209 FILE *output = stat_config.output;
915 struct perf_stat_evsel *ps = counter->priv; 1210 struct perf_stat_evsel *ps = counter->priv;
916 double avg = avg_stats(&ps->res_stats[0]); 1211 double avg = avg_stats(&ps->res_stats[0]);
917 int scaled = counter->counts->scaled;
918 double uval; 1212 double uval;
919 double avg_enabled, avg_running; 1213 double avg_enabled, avg_running;
920 1214
921 avg_enabled = avg_stats(&ps->res_stats[1]); 1215 avg_enabled = avg_stats(&ps->res_stats[1]);
922 avg_running = avg_stats(&ps->res_stats[2]); 1216 avg_running = avg_stats(&ps->res_stats[2]);
923 1217
924 if (prefix) 1218 if (prefix && !metric_only)
925 fprintf(output, "%s", prefix); 1219 fprintf(output, "%s", prefix);
926 1220
927 if (scaled == -1 || !counter->supported) {
928 fprintf(output, "%*s%s",
929 csv_output ? 0 : 18,
930 counter->supported ? CNTR_NOT_COUNTED : CNTR_NOT_SUPPORTED,
931 csv_sep);
932 fprintf(output, "%-*s%s",
933 csv_output ? 0 : unit_width,
934 counter->unit, csv_sep);
935 fprintf(output, "%*s",
936 csv_output ? 0 : -25,
937 perf_evsel__name(counter));
938
939 if (counter->cgrp)
940 fprintf(output, "%s%s", csv_sep, counter->cgrp->name);
941
942 print_running(avg_running, avg_enabled);
943 fputc('\n', output);
944 return;
945 }
946
947 uval = avg * counter->scale; 1221 uval = avg * counter->scale;
948 printout(-1, 0, counter, uval); 1222 printout(-1, 0, counter, uval, prefix, avg_running, avg_enabled, avg);
949 1223 if (!metric_only)
950 print_noise(counter, avg); 1224 fprintf(output, "\n");
951
952 print_running(avg_running, avg_enabled);
953 fprintf(output, "\n");
954} 1225}
955 1226
956/* 1227/*
@@ -972,39 +1243,78 @@ static void print_counter(struct perf_evsel *counter, char *prefix)
972 if (prefix) 1243 if (prefix)
973 fprintf(output, "%s", prefix); 1244 fprintf(output, "%s", prefix);
974 1245
975 if (run == 0 || ena == 0) { 1246 uval = val * counter->scale;
976 fprintf(output, "CPU%*d%s%*s%s", 1247 printout(cpu, 0, counter, uval, prefix, run, ena, 1.0);
977 csv_output ? 0 : -4,
978 perf_evsel__cpus(counter)->map[cpu], csv_sep,
979 csv_output ? 0 : 18,
980 counter->supported ? CNTR_NOT_COUNTED : CNTR_NOT_SUPPORTED,
981 csv_sep);
982 1248
983 fprintf(output, "%-*s%s", 1249 fputc('\n', output);
984 csv_output ? 0 : unit_width, 1250 }
985 counter->unit, csv_sep); 1251}
986 1252
987 fprintf(output, "%*s", 1253static void print_no_aggr_metric(char *prefix)
988 csv_output ? 0 : -25, 1254{
989 perf_evsel__name(counter)); 1255 int cpu;
1256 int nrcpus = 0;
1257 struct perf_evsel *counter;
1258 u64 ena, run, val;
1259 double uval;
990 1260
991 if (counter->cgrp) 1261 nrcpus = evsel_list->cpus->nr;
992 fprintf(output, "%s%s", 1262 for (cpu = 0; cpu < nrcpus; cpu++) {
993 csv_sep, counter->cgrp->name); 1263 bool first = true;
994 1264
995 print_running(run, ena); 1265 if (prefix)
996 fputc('\n', output); 1266 fputs(prefix, stat_config.output);
997 continue; 1267 evlist__for_each(evsel_list, counter) {
1268 if (first) {
1269 aggr_printout(counter, cpu, 0);
1270 first = false;
1271 }
1272 val = perf_counts(counter->counts, cpu, 0)->val;
1273 ena = perf_counts(counter->counts, cpu, 0)->ena;
1274 run = perf_counts(counter->counts, cpu, 0)->run;
1275
1276 uval = val * counter->scale;
1277 printout(cpu, 0, counter, uval, prefix, run, ena, 1.0);
998 } 1278 }
1279 fputc('\n', stat_config.output);
1280 }
1281}
999 1282
1000 uval = val * counter->scale; 1283static int aggr_header_lens[] = {
1001 printout(cpu, 0, counter, uval); 1284 [AGGR_CORE] = 18,
1002 if (!csv_output) 1285 [AGGR_SOCKET] = 12,
1003 print_noise(counter, 1.0); 1286 [AGGR_NONE] = 6,
1004 print_running(run, ena); 1287 [AGGR_THREAD] = 24,
1288 [AGGR_GLOBAL] = 0,
1289};
1005 1290
1006 fputc('\n', output); 1291static void print_metric_headers(char *prefix)
1292{
1293 struct perf_stat_output_ctx out;
1294 struct perf_evsel *counter;
1295 struct outstate os = {
1296 .fh = stat_config.output
1297 };
1298
1299 if (prefix)
1300 fprintf(stat_config.output, "%s", prefix);
1301
1302 if (!csv_output)
1303 fprintf(stat_config.output, "%*s",
1304 aggr_header_lens[stat_config.aggr_mode], "");
1305
1306 /* Print metrics headers only */
1307 evlist__for_each(evsel_list, counter) {
1308 os.evsel = counter;
1309 out.ctx = &os;
1310 out.print_metric = print_metric_header;
1311 out.new_line = new_line_metric;
1312 os.evsel = counter;
1313 perf_stat__print_shadow_stats(counter, 0,
1314 0,
1315 &out);
1007 } 1316 }
1317 fputc('\n', stat_config.output);
1008} 1318}
1009 1319
1010static void print_interval(char *prefix, struct timespec *ts) 1320static void print_interval(char *prefix, struct timespec *ts)
@@ -1014,7 +1324,7 @@ static void print_interval(char *prefix, struct timespec *ts)
1014 1324
1015 sprintf(prefix, "%6lu.%09lu%s", ts->tv_sec, ts->tv_nsec, csv_sep); 1325 sprintf(prefix, "%6lu.%09lu%s", ts->tv_sec, ts->tv_nsec, csv_sep);
1016 1326
1017 if (num_print_interval == 0 && !csv_output) { 1327 if (num_print_interval == 0 && !csv_output && !metric_only) {
1018 switch (stat_config.aggr_mode) { 1328 switch (stat_config.aggr_mode) {
1019 case AGGR_SOCKET: 1329 case AGGR_SOCKET:
1020 fprintf(output, "# time socket cpus counts %*s events\n", unit_width, "unit"); 1330 fprintf(output, "# time socket cpus counts %*s events\n", unit_width, "unit");
@@ -1101,6 +1411,17 @@ static void print_counters(struct timespec *ts, int argc, const char **argv)
1101 else 1411 else
1102 print_header(argc, argv); 1412 print_header(argc, argv);
1103 1413
1414 if (metric_only) {
1415 static int num_print_iv;
1416
1417 if (num_print_iv == 0)
1418 print_metric_headers(prefix);
1419 if (num_print_iv++ == 25)
1420 num_print_iv = 0;
1421 if (stat_config.aggr_mode == AGGR_GLOBAL && prefix)
1422 fprintf(stat_config.output, "%s", prefix);
1423 }
1424
1104 switch (stat_config.aggr_mode) { 1425 switch (stat_config.aggr_mode) {
1105 case AGGR_CORE: 1426 case AGGR_CORE:
1106 case AGGR_SOCKET: 1427 case AGGR_SOCKET:
@@ -1113,10 +1434,16 @@ static void print_counters(struct timespec *ts, int argc, const char **argv)
1113 case AGGR_GLOBAL: 1434 case AGGR_GLOBAL:
1114 evlist__for_each(evsel_list, counter) 1435 evlist__for_each(evsel_list, counter)
1115 print_counter_aggr(counter, prefix); 1436 print_counter_aggr(counter, prefix);
1437 if (metric_only)
1438 fputc('\n', stat_config.output);
1116 break; 1439 break;
1117 case AGGR_NONE: 1440 case AGGR_NONE:
1118 evlist__for_each(evsel_list, counter) 1441 if (metric_only)
1119 print_counter(counter, prefix); 1442 print_no_aggr_metric(prefix);
1443 else {
1444 evlist__for_each(evsel_list, counter)
1445 print_counter(counter, prefix);
1446 }
1120 break; 1447 break;
1121 case AGGR_UNSET: 1448 case AGGR_UNSET:
1122 default: 1449 default:
@@ -1237,6 +1564,8 @@ static const struct option stat_options[] = {
1237 "aggregate counts per thread", AGGR_THREAD), 1564 "aggregate counts per thread", AGGR_THREAD),
1238 OPT_UINTEGER('D', "delay", &initial_delay, 1565 OPT_UINTEGER('D', "delay", &initial_delay,
1239 "ms to wait before starting measurement after program start"), 1566 "ms to wait before starting measurement after program start"),
1567 OPT_BOOLEAN(0, "metric-only", &metric_only,
1568 "Only print computed metrics. No raw values"),
1240 OPT_END() 1569 OPT_END()
1241}; 1570};
1242 1571
@@ -1435,7 +1764,7 @@ static int perf_stat_init_aggr_mode_file(struct perf_stat *st)
1435 */ 1764 */
1436static int add_default_attributes(void) 1765static int add_default_attributes(void)
1437{ 1766{
1438 struct perf_event_attr default_attrs[] = { 1767 struct perf_event_attr default_attrs0[] = {
1439 1768
1440 { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_TASK_CLOCK }, 1769 { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_TASK_CLOCK },
1441 { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_CONTEXT_SWITCHES }, 1770 { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_CONTEXT_SWITCHES },
@@ -1443,8 +1772,14 @@ static int add_default_attributes(void)
1443 { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_PAGE_FAULTS }, 1772 { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_PAGE_FAULTS },
1444 1773
1445 { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_CPU_CYCLES }, 1774 { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_CPU_CYCLES },
1775};
1776 struct perf_event_attr frontend_attrs[] = {
1446 { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_STALLED_CYCLES_FRONTEND }, 1777 { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_STALLED_CYCLES_FRONTEND },
1778};
1779 struct perf_event_attr backend_attrs[] = {
1447 { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_STALLED_CYCLES_BACKEND }, 1780 { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_STALLED_CYCLES_BACKEND },
1781};
1782 struct perf_event_attr default_attrs1[] = {
1448 { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_INSTRUCTIONS }, 1783 { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_INSTRUCTIONS },
1449 { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_BRANCH_INSTRUCTIONS }, 1784 { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_BRANCH_INSTRUCTIONS },
1450 { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_BRANCH_MISSES }, 1785 { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_BRANCH_MISSES },
@@ -1561,7 +1896,19 @@ static int add_default_attributes(void)
1561 } 1896 }
1562 1897
1563 if (!evsel_list->nr_entries) { 1898 if (!evsel_list->nr_entries) {
1564 if (perf_evlist__add_default_attrs(evsel_list, default_attrs) < 0) 1899 if (perf_evlist__add_default_attrs(evsel_list, default_attrs0) < 0)
1900 return -1;
1901 if (pmu_have_event("cpu", "stalled-cycles-frontend")) {
1902 if (perf_evlist__add_default_attrs(evsel_list,
1903 frontend_attrs) < 0)
1904 return -1;
1905 }
1906 if (pmu_have_event("cpu", "stalled-cycles-backend")) {
1907 if (perf_evlist__add_default_attrs(evsel_list,
1908 backend_attrs) < 0)
1909 return -1;
1910 }
1911 if (perf_evlist__add_default_attrs(evsel_list, default_attrs1) < 0)
1565 return -1; 1912 return -1;
1566 } 1913 }
1567 1914
@@ -1825,9 +2172,11 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
1825 if (evsel_list == NULL) 2172 if (evsel_list == NULL)
1826 return -ENOMEM; 2173 return -ENOMEM;
1827 2174
2175 parse_events__shrink_config_terms();
1828 argc = parse_options_subcommand(argc, argv, stat_options, stat_subcommands, 2176 argc = parse_options_subcommand(argc, argv, stat_options, stat_subcommands,
1829 (const char **) stat_usage, 2177 (const char **) stat_usage,
1830 PARSE_OPT_STOP_AT_NON_OPTION); 2178 PARSE_OPT_STOP_AT_NON_OPTION);
2179 perf_stat__init_shadow_stats();
1831 2180
1832 if (csv_sep) { 2181 if (csv_sep) {
1833 csv_output = true; 2182 csv_output = true;
@@ -1858,6 +2207,16 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
1858 goto out; 2207 goto out;
1859 } 2208 }
1860 2209
2210 if (metric_only && stat_config.aggr_mode == AGGR_THREAD) {
2211 fprintf(stderr, "--metric-only is not supported with --per-thread\n");
2212 goto out;
2213 }
2214
2215 if (metric_only && run_count > 1) {
2216 fprintf(stderr, "--metric-only is not supported with -r\n");
2217 goto out;
2218 }
2219
1861 if (output_fd < 0) { 2220 if (output_fd < 0) {
1862 fprintf(stderr, "argument to --log-fd must be a > 0\n"); 2221 fprintf(stderr, "argument to --log-fd must be a > 0\n");
1863 parse_options_usage(stat_usage, stat_options, "log-fd", 0); 2222 parse_options_usage(stat_usage, stat_options, "log-fd", 0);
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c
index bf01cbb0ef23..94af190f6843 100644
--- a/tools/perf/builtin-top.c
+++ b/tools/perf/builtin-top.c
@@ -252,7 +252,8 @@ static void perf_top__print_sym_table(struct perf_top *top)
252 char bf[160]; 252 char bf[160];
253 int printed = 0; 253 int printed = 0;
254 const int win_width = top->winsize.ws_col - 1; 254 const int win_width = top->winsize.ws_col - 1;
255 struct hists *hists = evsel__hists(top->sym_evsel); 255 struct perf_evsel *evsel = top->sym_evsel;
256 struct hists *hists = evsel__hists(evsel);
256 257
257 puts(CONSOLE_CLEAR); 258 puts(CONSOLE_CLEAR);
258 259
@@ -288,7 +289,7 @@ static void perf_top__print_sym_table(struct perf_top *top)
288 } 289 }
289 290
290 hists__collapse_resort(hists, NULL); 291 hists__collapse_resort(hists, NULL);
291 hists__output_resort(hists, NULL); 292 perf_evsel__output_resort(evsel, NULL);
292 293
293 hists__output_recalc_col_len(hists, top->print_entries - printed); 294 hists__output_recalc_col_len(hists, top->print_entries - printed);
294 putchar('\n'); 295 putchar('\n');
@@ -540,6 +541,7 @@ static bool perf_top__handle_keypress(struct perf_top *top, int c)
540static void perf_top__sort_new_samples(void *arg) 541static void perf_top__sort_new_samples(void *arg)
541{ 542{
542 struct perf_top *t = arg; 543 struct perf_top *t = arg;
544 struct perf_evsel *evsel = t->sym_evsel;
543 struct hists *hists; 545 struct hists *hists;
544 546
545 perf_top__reset_sample_counters(t); 547 perf_top__reset_sample_counters(t);
@@ -547,7 +549,7 @@ static void perf_top__sort_new_samples(void *arg)
547 if (t->evlist->selected != NULL) 549 if (t->evlist->selected != NULL)
548 t->sym_evsel = t->evlist->selected; 550 t->sym_evsel = t->evlist->selected;
549 551
550 hists = evsel__hists(t->sym_evsel); 552 hists = evsel__hists(evsel);
551 553
552 if (t->evlist->enabled) { 554 if (t->evlist->enabled) {
553 if (t->zero) { 555 if (t->zero) {
@@ -559,7 +561,7 @@ static void perf_top__sort_new_samples(void *arg)
559 } 561 }
560 562
561 hists__collapse_resort(hists, NULL); 563 hists__collapse_resort(hists, NULL);
562 hists__output_resort(hists, NULL); 564 perf_evsel__output_resort(evsel, NULL);
563} 565}
564 566
565static void *display_thread_tui(void *arg) 567static void *display_thread_tui(void *arg)
@@ -1063,7 +1065,7 @@ parse_callchain_opt(const struct option *opt, const char *arg, int unset)
1063 return parse_callchain_top_opt(arg); 1065 return parse_callchain_top_opt(arg);
1064} 1066}
1065 1067
1066static int perf_top_config(const char *var, const char *value, void *cb) 1068static int perf_top_config(const char *var, const char *value, void *cb __maybe_unused)
1067{ 1069{
1068 if (!strcmp(var, "top.call-graph")) 1070 if (!strcmp(var, "top.call-graph"))
1069 var = "call-graph.record-mode"; /* fall-through */ 1071 var = "call-graph.record-mode"; /* fall-through */
@@ -1072,7 +1074,7 @@ static int perf_top_config(const char *var, const char *value, void *cb)
1072 return 0; 1074 return 0;
1073 } 1075 }
1074 1076
1075 return perf_default_config(var, value, cb); 1077 return 0;
1076} 1078}
1077 1079
1078static int 1080static int
@@ -1212,6 +1214,8 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused)
1212 parse_branch_stack), 1214 parse_branch_stack),
1213 OPT_BOOLEAN(0, "raw-trace", &symbol_conf.raw_trace, 1215 OPT_BOOLEAN(0, "raw-trace", &symbol_conf.raw_trace,
1214 "Show raw trace event output (do not use print fmt or plugins)"), 1216 "Show raw trace event output (do not use print fmt or plugins)"),
1217 OPT_BOOLEAN(0, "hierarchy", &symbol_conf.report_hierarchy,
1218 "Show entries in a hierarchy"),
1215 OPT_END() 1219 OPT_END()
1216 }; 1220 };
1217 const char * const top_usage[] = { 1221 const char * const top_usage[] = {
@@ -1239,10 +1243,30 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused)
1239 goto out_delete_evlist; 1243 goto out_delete_evlist;
1240 } 1244 }
1241 1245
1246 if (symbol_conf.report_hierarchy) {
1247 /* disable incompatible options */
1248 symbol_conf.event_group = false;
1249 symbol_conf.cumulate_callchain = false;
1250
1251 if (field_order) {
1252 pr_err("Error: --hierarchy and --fields options cannot be used together\n");
1253 parse_options_usage(top_usage, options, "fields", 0);
1254 parse_options_usage(NULL, options, "hierarchy", 0);
1255 goto out_delete_evlist;
1256 }
1257 }
1258
1242 sort__mode = SORT_MODE__TOP; 1259 sort__mode = SORT_MODE__TOP;
1243 /* display thread wants entries to be collapsed in a different tree */ 1260 /* display thread wants entries to be collapsed in a different tree */
1244 sort__need_collapse = 1; 1261 sort__need_collapse = 1;
1245 1262
1263 if (top.use_stdio)
1264 use_browser = 0;
1265 else if (top.use_tui)
1266 use_browser = 1;
1267
1268 setup_browser(false);
1269
1246 if (setup_sorting(top.evlist) < 0) { 1270 if (setup_sorting(top.evlist) < 0) {
1247 if (sort_order) 1271 if (sort_order)
1248 parse_options_usage(top_usage, options, "s", 1); 1272 parse_options_usage(top_usage, options, "s", 1);
@@ -1252,13 +1276,6 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused)
1252 goto out_delete_evlist; 1276 goto out_delete_evlist;
1253 } 1277 }
1254 1278
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); 1279 status = target__validate(target);
1263 if (status) { 1280 if (status) {
1264 target__strerror(target, status, errbuf, BUFSIZ); 1281 target__strerror(target, status, errbuf, BUFSIZ);
diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c
index 20916dd77aac..8dc98c598b1a 100644
--- a/tools/perf/builtin-trace.c
+++ b/tools/perf/builtin-trace.c
@@ -33,6 +33,7 @@
33#include "util/stat.h" 33#include "util/stat.h"
34#include "trace-event.h" 34#include "trace-event.h"
35#include "util/parse-events.h" 35#include "util/parse-events.h"
36#include "util/bpf-loader.h"
36 37
37#include <libaudit.h> 38#include <libaudit.h>
38#include <stdlib.h> 39#include <stdlib.h>
@@ -1724,8 +1725,12 @@ static int trace__read_syscall_info(struct trace *trace, int id)
1724 1725
1725 sc->args = sc->tp_format->format.fields; 1726 sc->args = sc->tp_format->format.fields;
1726 sc->nr_args = sc->tp_format->format.nr_fields; 1727 sc->nr_args = sc->tp_format->format.nr_fields;
1727 /* drop nr field - not relevant here; does not exist on older kernels */ 1728 /*
1728 if (sc->args && strcmp(sc->args->name, "nr") == 0) { 1729 * We need to check and discard the first variable '__syscall_nr'
1730 * or 'nr' that mean the syscall number. It is needless here.
1731 * So drop '__syscall_nr' or 'nr' field but does not exist on older kernels.
1732 */
1733 if (sc->args && (!strcmp(sc->args->name, "__syscall_nr") || !strcmp(sc->args->name, "nr"))) {
1729 sc->args = sc->args->next; 1734 sc->args = sc->args->next;
1730 --sc->nr_args; 1735 --sc->nr_args;
1731 } 1736 }
@@ -2177,6 +2182,37 @@ out_dump:
2177 return 0; 2182 return 0;
2178} 2183}
2179 2184
2185static void bpf_output__printer(enum binary_printer_ops op,
2186 unsigned int val, void *extra)
2187{
2188 FILE *output = extra;
2189 unsigned char ch = (unsigned char)val;
2190
2191 switch (op) {
2192 case BINARY_PRINT_CHAR_DATA:
2193 fprintf(output, "%c", isprint(ch) ? ch : '.');
2194 break;
2195 case BINARY_PRINT_DATA_BEGIN:
2196 case BINARY_PRINT_LINE_BEGIN:
2197 case BINARY_PRINT_ADDR:
2198 case BINARY_PRINT_NUM_DATA:
2199 case BINARY_PRINT_NUM_PAD:
2200 case BINARY_PRINT_SEP:
2201 case BINARY_PRINT_CHAR_PAD:
2202 case BINARY_PRINT_LINE_END:
2203 case BINARY_PRINT_DATA_END:
2204 default:
2205 break;
2206 }
2207}
2208
2209static void bpf_output__fprintf(struct trace *trace,
2210 struct perf_sample *sample)
2211{
2212 print_binary(sample->raw_data, sample->raw_size, 8,
2213 bpf_output__printer, trace->output);
2214}
2215
2180static int trace__event_handler(struct trace *trace, struct perf_evsel *evsel, 2216static int trace__event_handler(struct trace *trace, struct perf_evsel *evsel,
2181 union perf_event *event __maybe_unused, 2217 union perf_event *event __maybe_unused,
2182 struct perf_sample *sample) 2218 struct perf_sample *sample)
@@ -2189,7 +2225,9 @@ static int trace__event_handler(struct trace *trace, struct perf_evsel *evsel,
2189 2225
2190 fprintf(trace->output, "%s:", evsel->name); 2226 fprintf(trace->output, "%s:", evsel->name);
2191 2227
2192 if (evsel->tp_format) { 2228 if (perf_evsel__is_bpf_output(evsel)) {
2229 bpf_output__fprintf(trace, sample);
2230 } else if (evsel->tp_format) {
2193 event_format__fprintf(evsel->tp_format, sample->cpu, 2231 event_format__fprintf(evsel->tp_format, sample->cpu,
2194 sample->raw_data, sample->raw_size, 2232 sample->raw_data, sample->raw_size,
2195 trace->output); 2233 trace->output);
@@ -2586,6 +2624,16 @@ static int trace__run(struct trace *trace, int argc, const char **argv)
2586 if (err < 0) 2624 if (err < 0)
2587 goto out_error_open; 2625 goto out_error_open;
2588 2626
2627 err = bpf__apply_obj_config();
2628 if (err) {
2629 char errbuf[BUFSIZ];
2630
2631 bpf__strerror_apply_obj_config(err, errbuf, sizeof(errbuf));
2632 pr_err("ERROR: Apply config to BPF failed: %s\n",
2633 errbuf);
2634 goto out_error_open;
2635 }
2636
2589 /* 2637 /*
2590 * Better not use !target__has_task() here because we need to cover the 2638 * 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 2639 * case where no threads were specified in the command line, but a
diff --git a/tools/perf/config/Makefile b/tools/perf/config/Makefile
index 511141b102e8..eca6a912e8c2 100644
--- a/tools/perf/config/Makefile
+++ b/tools/perf/config/Makefile
@@ -61,50 +61,45 @@ endif
61 61
62ifeq ($(LIBUNWIND_LIBS),) 62ifeq ($(LIBUNWIND_LIBS),)
63 NO_LIBUNWIND := 1 63 NO_LIBUNWIND := 1
64else
65 #
66 # For linking with debug library, run like:
67 #
68 # make DEBUG=1 LIBUNWIND_DIR=/opt/libunwind/
69 #
70 ifdef LIBUNWIND_DIR
71 LIBUNWIND_CFLAGS = -I$(LIBUNWIND_DIR)/include
72 LIBUNWIND_LDFLAGS = -L$(LIBUNWIND_DIR)/lib
73 endif
74 LIBUNWIND_LDFLAGS += $(LIBUNWIND_LIBS)
75
76 # Set per-feature check compilation flags
77 FEATURE_CHECK_CFLAGS-libunwind = $(LIBUNWIND_CFLAGS)
78 FEATURE_CHECK_LDFLAGS-libunwind = $(LIBUNWIND_LDFLAGS)
79 FEATURE_CHECK_CFLAGS-libunwind-debug-frame = $(LIBUNWIND_CFLAGS)
80 FEATURE_CHECK_LDFLAGS-libunwind-debug-frame = $(LIBUNWIND_LDFLAGS)
81endif 64endif
65#
66# For linking with debug library, run like:
67#
68# make DEBUG=1 LIBUNWIND_DIR=/opt/libunwind/
69#
70ifdef LIBUNWIND_DIR
71 LIBUNWIND_CFLAGS = -I$(LIBUNWIND_DIR)/include
72 LIBUNWIND_LDFLAGS = -L$(LIBUNWIND_DIR)/lib
73endif
74LIBUNWIND_LDFLAGS += $(LIBUNWIND_LIBS)
75
76# Set per-feature check compilation flags
77FEATURE_CHECK_CFLAGS-libunwind = $(LIBUNWIND_CFLAGS)
78FEATURE_CHECK_LDFLAGS-libunwind = $(LIBUNWIND_LDFLAGS)
79FEATURE_CHECK_CFLAGS-libunwind-debug-frame = $(LIBUNWIND_CFLAGS)
80FEATURE_CHECK_LDFLAGS-libunwind-debug-frame = $(LIBUNWIND_LDFLAGS)
82 81
83ifeq ($(NO_PERF_REGS),0) 82ifeq ($(NO_PERF_REGS),0)
84 CFLAGS += -DHAVE_PERF_REGS_SUPPORT 83 CFLAGS += -DHAVE_PERF_REGS_SUPPORT
85endif 84endif
86 85
87ifndef NO_LIBELF 86# for linking with debug library, run like:
88 # for linking with debug library, run like: 87# make DEBUG=1 LIBDW_DIR=/opt/libdw/
89 # make DEBUG=1 LIBDW_DIR=/opt/libdw/ 88ifdef LIBDW_DIR
90 ifdef LIBDW_DIR 89 LIBDW_CFLAGS := -I$(LIBDW_DIR)/include
91 LIBDW_CFLAGS := -I$(LIBDW_DIR)/include 90 LIBDW_LDFLAGS := -L$(LIBDW_DIR)/lib
92 LIBDW_LDFLAGS := -L$(LIBDW_DIR)/lib
93 endif
94 FEATURE_CHECK_CFLAGS-libdw-dwarf-unwind := $(LIBDW_CFLAGS)
95 FEATURE_CHECK_LDFLAGS-libdw-dwarf-unwind := $(LIBDW_LDFLAGS) -ldw
96endif 91endif
92FEATURE_CHECK_CFLAGS-libdw-dwarf-unwind := $(LIBDW_CFLAGS)
93FEATURE_CHECK_LDFLAGS-libdw-dwarf-unwind := $(LIBDW_LDFLAGS) -ldw
97 94
98ifdef LIBBABELTRACE 95# for linking with debug library, run like:
99 # for linking with debug library, run like: 96# make DEBUG=1 LIBBABELTRACE_DIR=/opt/libbabeltrace/
100 # make DEBUG=1 LIBBABELTRACE_DIR=/opt/libbabeltrace/ 97ifdef LIBBABELTRACE_DIR
101 ifdef LIBBABELTRACE_DIR 98 LIBBABELTRACE_CFLAGS := -I$(LIBBABELTRACE_DIR)/include
102 LIBBABELTRACE_CFLAGS := -I$(LIBBABELTRACE_DIR)/include 99 LIBBABELTRACE_LDFLAGS := -L$(LIBBABELTRACE_DIR)/lib
103 LIBBABELTRACE_LDFLAGS := -L$(LIBBABELTRACE_DIR)/lib
104 endif
105 FEATURE_CHECK_CFLAGS-libbabeltrace := $(LIBBABELTRACE_CFLAGS)
106 FEATURE_CHECK_LDFLAGS-libbabeltrace := $(LIBBABELTRACE_LDFLAGS) -lbabeltrace-ctf
107endif 100endif
101FEATURE_CHECK_CFLAGS-libbabeltrace := $(LIBBABELTRACE_CFLAGS)
102FEATURE_CHECK_LDFLAGS-libbabeltrace := $(LIBBABELTRACE_LDFLAGS) -lbabeltrace-ctf
108 103
109FEATURE_CHECK_CFLAGS-bpf = -I. -I$(srctree)/tools/include -I$(srctree)/arch/$(ARCH)/include/uapi -I$(srctree)/include/uapi 104FEATURE_CHECK_CFLAGS-bpf = -I. -I$(srctree)/tools/include -I$(srctree)/arch/$(ARCH)/include/uapi -I$(srctree)/include/uapi
110# include ARCH specific config 105# include ARCH specific config
@@ -145,28 +140,26 @@ ifdef PARSER_DEBUG
145 $(call detected_var,PARSER_DEBUG_FLEX) 140 $(call detected_var,PARSER_DEBUG_FLEX)
146endif 141endif
147 142
148ifndef NO_LIBPYTHON 143# Try different combinations to accommodate systems that only have
149 # Try different combinations to accommodate systems that only have 144# python[2][-config] in weird combinations but always preferring
150 # python[2][-config] in weird combinations but always preferring 145# python2 and python2-config as per pep-0394. If we catch a
151 # python2 and python2-config as per pep-0394. If we catch a 146# python[-config] in version 3, the version check will kill it.
152 # python[-config] in version 3, the version check will kill it. 147PYTHON2 := $(if $(call get-executable,python2),python2,python)
153 PYTHON2 := $(if $(call get-executable,python2),python2,python) 148override PYTHON := $(call get-executable-or-default,PYTHON,$(PYTHON2))
154 override PYTHON := $(call get-executable-or-default,PYTHON,$(PYTHON2)) 149PYTHON2_CONFIG := \
155 PYTHON2_CONFIG := \ 150 $(if $(call get-executable,$(PYTHON)-config),$(PYTHON)-config,python-config)
156 $(if $(call get-executable,$(PYTHON)-config),$(PYTHON)-config,python-config) 151override PYTHON_CONFIG := \
157 override PYTHON_CONFIG := \ 152 $(call get-executable-or-default,PYTHON_CONFIG,$(PYTHON2_CONFIG))
158 $(call get-executable-or-default,PYTHON_CONFIG,$(PYTHON2_CONFIG))
159 153
160 PYTHON_CONFIG_SQ := $(call shell-sq,$(PYTHON_CONFIG)) 154PYTHON_CONFIG_SQ := $(call shell-sq,$(PYTHON_CONFIG))
161 155
162 PYTHON_EMBED_LDOPTS := $(shell $(PYTHON_CONFIG_SQ) --ldflags 2>/dev/null) 156PYTHON_EMBED_LDOPTS := $(shell $(PYTHON_CONFIG_SQ) --ldflags 2>/dev/null)
163 PYTHON_EMBED_CCOPTS := $(shell $(PYTHON_CONFIG_SQ) --cflags 2>/dev/null) 157PYTHON_EMBED_CCOPTS := $(shell $(PYTHON_CONFIG_SQ) --cflags 2>/dev/null)
164 158
165 FEATURE_CHECK_CFLAGS-libpython := $(PYTHON_EMBED_CCOPTS) 159FEATURE_CHECK_CFLAGS-libpython := $(PYTHON_EMBED_CCOPTS)
166 FEATURE_CHECK_LDFLAGS-libpython := $(PYTHON_EMBED_LDOPTS) 160FEATURE_CHECK_LDFLAGS-libpython := $(PYTHON_EMBED_LDOPTS)
167 FEATURE_CHECK_CFLAGS-libpython-version := $(PYTHON_EMBED_CCOPTS) 161FEATURE_CHECK_CFLAGS-libpython-version := $(PYTHON_EMBED_CCOPTS)
168 FEATURE_CHECK_LDFLAGS-libpython-version := $(PYTHON_EMBED_LDOPTS) 162FEATURE_CHECK_LDFLAGS-libpython-version := $(PYTHON_EMBED_LDOPTS)
169endif
170 163
171CFLAGS += -fno-omit-frame-pointer 164CFLAGS += -fno-omit-frame-pointer
172CFLAGS += -ggdb3 165CFLAGS += -ggdb3
@@ -335,6 +328,13 @@ ifndef NO_LIBELF
335 endif # NO_LIBBPF 328 endif # NO_LIBBPF
336endif # NO_LIBELF 329endif # NO_LIBELF
337 330
331ifdef PERF_HAVE_JITDUMP
332 ifndef NO_DWARF
333 $(call detected,CONFIG_JITDUMP)
334 CFLAGS += -DHAVE_JITDUMP
335 endif
336endif
337
338ifeq ($(ARCH),powerpc) 338ifeq ($(ARCH),powerpc)
339 ifndef NO_DWARF 339 ifndef NO_DWARF
340 CFLAGS += -DHAVE_SKIP_CALLCHAIN_IDX 340 CFLAGS += -DHAVE_SKIP_CALLCHAIN_IDX
@@ -411,6 +411,17 @@ ifndef NO_LIBAUDIT
411 endif 411 endif
412endif 412endif
413 413
414ifndef NO_LIBCRYPTO
415 ifneq ($(feature-libcrypto), 1)
416 msg := $(warning No libcrypto.h found, disables jitted code injection, please install libssl-devel or libssl-dev);
417 NO_LIBCRYPTO := 1
418 else
419 CFLAGS += -DHAVE_LIBCRYPTO_SUPPORT
420 EXTLIBS += -lcrypto
421 $(call detected,CONFIG_CRYPTO)
422 endif
423endif
424
414ifdef NO_NEWT 425ifdef NO_NEWT
415 NO_SLANG=1 426 NO_SLANG=1
416endif 427endif
diff --git a/tools/perf/jvmti/Makefile b/tools/perf/jvmti/Makefile
new file mode 100644
index 000000000000..5ce61a1bda9c
--- /dev/null
+++ b/tools/perf/jvmti/Makefile
@@ -0,0 +1,89 @@
1ARCH=$(shell uname -m)
2
3ifeq ($(ARCH), x86_64)
4JARCH=amd64
5endif
6ifeq ($(ARCH), armv7l)
7JARCH=armhf
8endif
9ifeq ($(ARCH), armv6l)
10JARCH=armhf
11endif
12ifeq ($(ARCH), aarch64)
13JARCH=aarch64
14endif
15ifeq ($(ARCH), ppc64)
16JARCH=powerpc
17endif
18ifeq ($(ARCH), ppc64le)
19JARCH=powerpc
20endif
21
22DESTDIR=/usr/local
23
24VERSION=1
25REVISION=0
26AGE=0
27
28LN=ln -sf
29RM=rm
30
31SLIBJVMTI=libjvmti.so.$(VERSION).$(REVISION).$(AGE)
32VLIBJVMTI=libjvmti.so.$(VERSION)
33SLDFLAGS=-shared -Wl,-soname -Wl,$(VLIBJVMTI)
34SOLIBEXT=so
35
36# The following works at least on fedora 23, you may need the next
37# line for other distros.
38ifneq (,$(wildcard /usr/sbin/update-java-alternatives))
39JDIR=$(shell /usr/sbin/update-java-alternatives -l | head -1 | cut -d ' ' -f 3)
40else
41 ifneq (,$(wildcard /usr/sbin/alternatives))
42 JDIR=$(shell alternatives --display java | tail -1 | cut -d' ' -f 5 | sed 's%/jre/bin/java.%%g')
43 endif
44endif
45ifndef JDIR
46$(error Could not find alternatives command, you need to set JDIR= to point to the root of your Java directory)
47else
48 ifeq (,$(wildcard $(JDIR)/include/jvmti.h))
49 $(error the openjdk development package appears to me missing, install and try again)
50 endif
51endif
52$(info Using Java from $(JDIR))
53# -lrt required in 32-bit mode for clock_gettime()
54LIBS=-lelf -lrt
55INCDIR=-I $(JDIR)/include -I $(JDIR)/include/linux
56
57TARGETS=$(SLIBJVMTI)
58
59SRCS=libjvmti.c jvmti_agent.c
60OBJS=$(SRCS:.c=.o)
61SOBJS=$(OBJS:.o=.lo)
62OPT=-O2 -g -Werror -Wall
63
64CFLAGS=$(INCDIR) $(OPT)
65
66all: $(TARGETS)
67
68.c.o:
69 $(CC) $(CFLAGS) -c $*.c
70.c.lo:
71 $(CC) -fPIC -DPIC $(CFLAGS) -c $*.c -o $*.lo
72
73$(OBJS) $(SOBJS): Makefile jvmti_agent.h ../util/jitdump.h
74
75$(SLIBJVMTI): $(SOBJS)
76 $(CC) $(CFLAGS) $(SLDFLAGS) -o $@ $(SOBJS) $(LIBS)
77 $(LN) $@ libjvmti.$(SOLIBEXT)
78
79clean:
80 $(RM) -f *.o *.so.* *.so *.lo
81
82install:
83 -mkdir -p $(DESTDIR)/lib
84 install -m 755 $(SLIBJVMTI) $(DESTDIR)/lib/
85 (cd $(DESTDIR)/lib; $(LN) $(SLIBJVMTI) $(VLIBJVMTI))
86 (cd $(DESTDIR)/lib; $(LN) $(SLIBJVMTI) libjvmti.$(SOLIBEXT))
87 ldconfig
88
89.SUFFIXES: .c .S .o .lo
diff --git a/tools/perf/jvmti/jvmti_agent.c b/tools/perf/jvmti/jvmti_agent.c
new file mode 100644
index 000000000000..6461e02ab940
--- /dev/null
+++ b/tools/perf/jvmti/jvmti_agent.c
@@ -0,0 +1,465 @@
1/*
2 * jvmti_agent.c: JVMTI agent interface
3 *
4 * Adapted from the Oprofile code in opagent.c:
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 *
19 * Copyright 2007 OProfile authors
20 * Jens Wilke
21 * Daniel Hansel
22 * Copyright IBM Corporation 2007
23 */
24#include <sys/types.h>
25#include <sys/stat.h> /* for mkdir() */
26#include <stdio.h>
27#include <errno.h>
28#include <string.h>
29#include <stdlib.h>
30#include <stdint.h>
31#include <limits.h>
32#include <fcntl.h>
33#include <unistd.h>
34#include <time.h>
35#include <sys/mman.h>
36#include <syscall.h> /* for gettid() */
37#include <err.h>
38
39#include "jvmti_agent.h"
40#include "../util/jitdump.h"
41
42#define JIT_LANG "java"
43
44static char jit_path[PATH_MAX];
45static void *marker_addr;
46
47/*
48 * padding buffer
49 */
50static const char pad_bytes[7];
51
52static inline pid_t gettid(void)
53{
54 return (pid_t)syscall(__NR_gettid);
55}
56
57static int get_e_machine(struct jitheader *hdr)
58{
59 ssize_t sret;
60 char id[16];
61 int fd, ret = -1;
62 int m = -1;
63 struct {
64 uint16_t e_type;
65 uint16_t e_machine;
66 } info;
67
68 fd = open("/proc/self/exe", O_RDONLY);
69 if (fd == -1)
70 return -1;
71
72 sret = read(fd, id, sizeof(id));
73 if (sret != sizeof(id))
74 goto error;
75
76 /* check ELF signature */
77 if (id[0] != 0x7f || id[1] != 'E' || id[2] != 'L' || id[3] != 'F')
78 goto error;
79
80 sret = read(fd, &info, sizeof(info));
81 if (sret != sizeof(info))
82 goto error;
83
84 m = info.e_machine;
85 if (m < 0)
86 m = 0; /* ELF EM_NONE */
87
88 hdr->elf_mach = m;
89 ret = 0;
90error:
91 close(fd);
92 return ret;
93}
94
95#define NSEC_PER_SEC 1000000000
96static int perf_clk_id = CLOCK_MONOTONIC;
97
98static inline uint64_t
99timespec_to_ns(const struct timespec *ts)
100{
101 return ((uint64_t) ts->tv_sec * NSEC_PER_SEC) + ts->tv_nsec;
102}
103
104static inline uint64_t
105perf_get_timestamp(void)
106{
107 struct timespec ts;
108 int ret;
109
110 ret = clock_gettime(perf_clk_id, &ts);
111 if (ret)
112 return 0;
113
114 return timespec_to_ns(&ts);
115}
116
117static int
118debug_cache_init(void)
119{
120 char str[32];
121 char *base, *p;
122 struct tm tm;
123 time_t t;
124 int ret;
125
126 time(&t);
127 localtime_r(&t, &tm);
128
129 base = getenv("JITDUMPDIR");
130 if (!base)
131 base = getenv("HOME");
132 if (!base)
133 base = ".";
134
135 strftime(str, sizeof(str), JIT_LANG"-jit-%Y%m%d", &tm);
136
137 snprintf(jit_path, PATH_MAX - 1, "%s/.debug/", base);
138
139 ret = mkdir(jit_path, 0755);
140 if (ret == -1) {
141 if (errno != EEXIST) {
142 warn("jvmti: cannot create jit cache dir %s", jit_path);
143 return -1;
144 }
145 }
146
147 snprintf(jit_path, PATH_MAX - 1, "%s/.debug/jit", base);
148 ret = mkdir(jit_path, 0755);
149 if (ret == -1) {
150 if (errno != EEXIST) {
151 warn("cannot create jit cache dir %s", jit_path);
152 return -1;
153 }
154 }
155
156 snprintf(jit_path, PATH_MAX - 1, "%s/.debug/jit/%s.XXXXXXXX", base, str);
157
158 p = mkdtemp(jit_path);
159 if (p != jit_path) {
160 warn("cannot create jit cache dir %s", jit_path);
161 return -1;
162 }
163
164 return 0;
165}
166
167static int
168perf_open_marker_file(int fd)
169{
170 long pgsz;
171
172 pgsz = sysconf(_SC_PAGESIZE);
173 if (pgsz == -1)
174 return -1;
175
176 /*
177 * we mmap the jitdump to create an MMAP RECORD in perf.data file.
178 * The mmap is captured either live (perf record running when we mmap)
179 * or in deferred mode, via /proc/PID/maps
180 * the MMAP record is used as a marker of a jitdump file for more meta
181 * data info about the jitted code. Perf report/annotate detect this
182 * special filename and process the jitdump file.
183 *
184 * mapping must be PROT_EXEC to ensure it is captured by perf record
185 * even when not using -d option
186 */
187 marker_addr = mmap(NULL, pgsz, PROT_READ|PROT_EXEC, MAP_PRIVATE, fd, 0);
188 return (marker_addr == MAP_FAILED) ? -1 : 0;
189}
190
191static void
192perf_close_marker_file(void)
193{
194 long pgsz;
195
196 if (!marker_addr)
197 return;
198
199 pgsz = sysconf(_SC_PAGESIZE);
200 if (pgsz == -1)
201 return;
202
203 munmap(marker_addr, pgsz);
204}
205
206void *jvmti_open(void)
207{
208 int pad_cnt;
209 char dump_path[PATH_MAX];
210 struct jitheader header;
211 int fd;
212 FILE *fp;
213
214 /*
215 * check if clockid is supported
216 */
217 if (!perf_get_timestamp())
218 warnx("jvmti: kernel does not support %d clock id", perf_clk_id);
219
220 memset(&header, 0, sizeof(header));
221
222 debug_cache_init();
223
224 /*
225 * jitdump file name
226 */
227 snprintf(dump_path, PATH_MAX, "%s/jit-%i.dump", jit_path, getpid());
228
229 fd = open(dump_path, O_CREAT|O_TRUNC|O_RDWR, 0666);
230 if (fd == -1)
231 return NULL;
232
233 /*
234 * create perf.data maker for the jitdump file
235 */
236 if (perf_open_marker_file(fd)) {
237 warnx("jvmti: failed to create marker file");
238 return NULL;
239 }
240
241 fp = fdopen(fd, "w+");
242 if (!fp) {
243 warn("jvmti: cannot create %s", dump_path);
244 close(fd);
245 goto error;
246 }
247
248 warnx("jvmti: jitdump in %s", dump_path);
249
250 if (get_e_machine(&header)) {
251 warn("get_e_machine failed\n");
252 goto error;
253 }
254
255 header.magic = JITHEADER_MAGIC;
256 header.version = JITHEADER_VERSION;
257 header.total_size = sizeof(header);
258 header.pid = getpid();
259
260 /* calculate amount of padding '\0' */
261 pad_cnt = PADDING_8ALIGNED(header.total_size);
262 header.total_size += pad_cnt;
263
264 header.timestamp = perf_get_timestamp();
265
266 if (!fwrite(&header, sizeof(header), 1, fp)) {
267 warn("jvmti: cannot write dumpfile header");
268 goto error;
269 }
270
271 /* write padding '\0' if necessary */
272 if (pad_cnt && !fwrite(pad_bytes, pad_cnt, 1, fp)) {
273 warn("jvmti: cannot write dumpfile header padding");
274 goto error;
275 }
276
277 return fp;
278error:
279 fclose(fp);
280 return NULL;
281}
282
283int
284jvmti_close(void *agent)
285{
286 struct jr_code_close rec;
287 FILE *fp = agent;
288
289 if (!fp) {
290 warnx("jvmti: incalid fd in close_agent");
291 return -1;
292 }
293
294 rec.p.id = JIT_CODE_CLOSE;
295 rec.p.total_size = sizeof(rec);
296
297 rec.p.timestamp = perf_get_timestamp();
298
299 if (!fwrite(&rec, sizeof(rec), 1, fp))
300 return -1;
301
302 fclose(fp);
303
304 fp = NULL;
305
306 perf_close_marker_file();
307
308 return 0;
309}
310
311int
312jvmti_write_code(void *agent, char const *sym,
313 uint64_t vma, void const *code, unsigned int const size)
314{
315 static int code_generation = 1;
316 struct jr_code_load rec;
317 size_t sym_len;
318 size_t padding_count;
319 FILE *fp = agent;
320 int ret = -1;
321
322 /* don't care about 0 length function, no samples */
323 if (size == 0)
324 return 0;
325
326 if (!fp) {
327 warnx("jvmti: invalid fd in write_native_code");
328 return -1;
329 }
330
331 sym_len = strlen(sym) + 1;
332
333 rec.p.id = JIT_CODE_LOAD;
334 rec.p.total_size = sizeof(rec) + sym_len;
335 padding_count = PADDING_8ALIGNED(rec.p.total_size);
336 rec.p. total_size += padding_count;
337 rec.p.timestamp = perf_get_timestamp();
338
339 rec.code_size = size;
340 rec.vma = vma;
341 rec.code_addr = vma;
342 rec.pid = getpid();
343 rec.tid = gettid();
344
345 if (code)
346 rec.p.total_size += size;
347
348 /*
349 * If JVM is multi-threaded, nultiple concurrent calls to agent
350 * may be possible, so protect file writes
351 */
352 flockfile(fp);
353
354 /*
355 * get code index inside lock to avoid race condition
356 */
357 rec.code_index = code_generation++;
358
359 ret = fwrite_unlocked(&rec, sizeof(rec), 1, fp);
360 fwrite_unlocked(sym, sym_len, 1, fp);
361
362 if (padding_count)
363 fwrite_unlocked(pad_bytes, padding_count, 1, fp);
364
365 if (code)
366 fwrite_unlocked(code, size, 1, fp);
367
368 funlockfile(fp);
369
370 ret = 0;
371
372 return ret;
373}
374
375int
376jvmti_write_debug_info(void *agent, uint64_t code, const char *file,
377 jvmti_line_info_t *li, int nr_lines)
378{
379 struct jr_code_debug_info rec;
380 size_t sret, len, size, flen;
381 size_t padding_count;
382 uint64_t addr;
383 const char *fn = file;
384 FILE *fp = agent;
385 int i;
386
387 /*
388 * no entry to write
389 */
390 if (!nr_lines)
391 return 0;
392
393 if (!fp) {
394 warnx("jvmti: invalid fd in write_debug_info");
395 return -1;
396 }
397
398 flen = strlen(file) + 1;
399
400 rec.p.id = JIT_CODE_DEBUG_INFO;
401 size = sizeof(rec);
402 rec.p.timestamp = perf_get_timestamp();
403 rec.code_addr = (uint64_t)(uintptr_t)code;
404 rec.nr_entry = nr_lines;
405
406 /*
407 * on disk source line info layout:
408 * uint64_t : addr
409 * int : line number
410 * int : column discriminator
411 * file[] : source file name
412 * padding : pad to multiple of 8 bytes
413 */
414 size += nr_lines * sizeof(struct debug_entry);
415 size += flen * nr_lines;
416 /*
417 * pad to 8 bytes
418 */
419 padding_count = PADDING_8ALIGNED(size);
420
421 rec.p.total_size = size + padding_count;
422
423 /*
424 * If JVM is multi-threaded, nultiple concurrent calls to agent
425 * may be possible, so protect file writes
426 */
427 flockfile(fp);
428
429 sret = fwrite_unlocked(&rec, sizeof(rec), 1, fp);
430 if (sret != 1)
431 goto error;
432
433 for (i = 0; i < nr_lines; i++) {
434
435 addr = (uint64_t)li[i].pc;
436 len = sizeof(addr);
437 sret = fwrite_unlocked(&addr, len, 1, fp);
438 if (sret != 1)
439 goto error;
440
441 len = sizeof(li[0].line_number);
442 sret = fwrite_unlocked(&li[i].line_number, len, 1, fp);
443 if (sret != 1)
444 goto error;
445
446 len = sizeof(li[0].discrim);
447 sret = fwrite_unlocked(&li[i].discrim, len, 1, fp);
448 if (sret != 1)
449 goto error;
450
451 sret = fwrite_unlocked(fn, flen, 1, fp);
452 if (sret != 1)
453 goto error;
454 }
455 if (padding_count)
456 sret = fwrite_unlocked(pad_bytes, padding_count, 1, fp);
457 if (sret != 1)
458 goto error;
459
460 funlockfile(fp);
461 return 0;
462error:
463 funlockfile(fp);
464 return -1;
465}
diff --git a/tools/perf/jvmti/jvmti_agent.h b/tools/perf/jvmti/jvmti_agent.h
new file mode 100644
index 000000000000..bedf5d0ba9ff
--- /dev/null
+++ b/tools/perf/jvmti/jvmti_agent.h
@@ -0,0 +1,36 @@
1#ifndef __JVMTI_AGENT_H__
2#define __JVMTI_AGENT_H__
3
4#include <sys/types.h>
5#include <stdint.h>
6#include <jvmti.h>
7
8#define __unused __attribute__((unused))
9
10#if defined(__cplusplus)
11extern "C" {
12#endif
13
14typedef struct {
15 unsigned long pc;
16 int line_number;
17 int discrim; /* discriminator -- 0 for now */
18} jvmti_line_info_t;
19
20void *jvmti_open(void);
21int jvmti_close(void *agent);
22int jvmti_write_code(void *agent, char const *symbol_name,
23 uint64_t vma, void const *code,
24 const unsigned int code_size);
25
26int jvmti_write_debug_info(void *agent,
27 uint64_t code,
28 const char *file,
29 jvmti_line_info_t *li,
30 int nr_lines);
31
32#if defined(__cplusplus)
33}
34
35#endif
36#endif /* __JVMTI_H__ */
diff --git a/tools/perf/jvmti/libjvmti.c b/tools/perf/jvmti/libjvmti.c
new file mode 100644
index 000000000000..ac12e4b91a92
--- /dev/null
+++ b/tools/perf/jvmti/libjvmti.c
@@ -0,0 +1,304 @@
1#include <sys/types.h>
2#include <stdio.h>
3#include <string.h>
4#include <stdlib.h>
5#include <err.h>
6#include <jvmti.h>
7#include <jvmticmlr.h>
8#include <limits.h>
9
10#include "jvmti_agent.h"
11
12static int has_line_numbers;
13void *jvmti_agent;
14
15static jvmtiError
16do_get_line_numbers(jvmtiEnv *jvmti, void *pc, jmethodID m, jint bci,
17 jvmti_line_info_t *tab, jint *nr)
18{
19 jint i, lines = 0;
20 jint nr_lines = 0;
21 jvmtiLineNumberEntry *loc_tab = NULL;
22 jvmtiError ret;
23
24 ret = (*jvmti)->GetLineNumberTable(jvmti, m, &nr_lines, &loc_tab);
25 if (ret != JVMTI_ERROR_NONE)
26 return ret;
27
28 for (i = 0; i < nr_lines; i++) {
29 if (loc_tab[i].start_location < bci) {
30 tab[lines].pc = (unsigned long)pc;
31 tab[lines].line_number = loc_tab[i].line_number;
32 tab[lines].discrim = 0; /* not yet used */
33 lines++;
34 } else {
35 break;
36 }
37 }
38 (*jvmti)->Deallocate(jvmti, (unsigned char *)loc_tab);
39 *nr = lines;
40 return JVMTI_ERROR_NONE;
41}
42
43static jvmtiError
44get_line_numbers(jvmtiEnv *jvmti, const void *compile_info, jvmti_line_info_t **tab, int *nr_lines)
45{
46 const jvmtiCompiledMethodLoadRecordHeader *hdr;
47 jvmtiCompiledMethodLoadInlineRecord *rec;
48 jvmtiLineNumberEntry *lne = NULL;
49 PCStackInfo *c;
50 jint nr, ret;
51 int nr_total = 0;
52 int i, lines_total = 0;
53
54 if (!(tab && nr_lines))
55 return JVMTI_ERROR_NULL_POINTER;
56
57 /*
58 * Phase 1 -- get the number of lines necessary
59 */
60 for (hdr = compile_info; hdr != NULL; hdr = hdr->next) {
61 if (hdr->kind == JVMTI_CMLR_INLINE_INFO) {
62 rec = (jvmtiCompiledMethodLoadInlineRecord *)hdr;
63 for (i = 0; i < rec->numpcs; i++) {
64 c = rec->pcinfo + i;
65 nr = 0;
66 /*
67 * unfortunately, need a tab to get the number of lines!
68 */
69 ret = (*jvmti)->GetLineNumberTable(jvmti, c->methods[0], &nr, &lne);
70 if (ret == JVMTI_ERROR_NONE) {
71 /* free what was allocated for nothing */
72 (*jvmti)->Deallocate(jvmti, (unsigned char *)lne);
73 nr_total += (int)nr;
74 }
75 }
76 }
77 }
78
79 if (nr_total == 0)
80 return JVMTI_ERROR_NOT_FOUND;
81
82 /*
83 * Phase 2 -- allocate big enough line table
84 */
85 *tab = malloc(nr_total * sizeof(**tab));
86 if (!*tab)
87 return JVMTI_ERROR_OUT_OF_MEMORY;
88
89 for (hdr = compile_info; hdr != NULL; hdr = hdr->next) {
90 if (hdr->kind == JVMTI_CMLR_INLINE_INFO) {
91 rec = (jvmtiCompiledMethodLoadInlineRecord *)hdr;
92 for (i = 0; i < rec->numpcs; i++) {
93 c = rec->pcinfo + i;
94 nr = 0;
95 ret = do_get_line_numbers(jvmti, c->pc,
96 c->methods[0],
97 c->bcis[0],
98 *tab + lines_total,
99 &nr);
100 if (ret == JVMTI_ERROR_NONE)
101 lines_total += nr;
102 }
103 }
104 }
105 *nr_lines = lines_total;
106 return JVMTI_ERROR_NONE;
107}
108
109static void JNICALL
110compiled_method_load_cb(jvmtiEnv *jvmti,
111 jmethodID method,
112 jint code_size,
113 void const *code_addr,
114 jint map_length,
115 jvmtiAddrLocationMap const *map,
116 const void *compile_info)
117{
118 jvmti_line_info_t *line_tab = NULL;
119 jclass decl_class;
120 char *class_sign = NULL;
121 char *func_name = NULL;
122 char *func_sign = NULL;
123 char *file_name= NULL;
124 char fn[PATH_MAX];
125 uint64_t addr = (uint64_t)(uintptr_t)code_addr;
126 jvmtiError ret;
127 int nr_lines = 0; /* in line_tab[] */
128 size_t len;
129
130 ret = (*jvmti)->GetMethodDeclaringClass(jvmti, method,
131 &decl_class);
132 if (ret != JVMTI_ERROR_NONE) {
133 warnx("jvmti: cannot get declaring class");
134 return;
135 }
136
137 if (has_line_numbers && map && map_length) {
138 ret = get_line_numbers(jvmti, compile_info, &line_tab, &nr_lines);
139 if (ret != JVMTI_ERROR_NONE) {
140 warnx("jvmti: cannot get line table for method");
141 nr_lines = 0;
142 }
143 }
144
145 ret = (*jvmti)->GetSourceFileName(jvmti, decl_class, &file_name);
146 if (ret != JVMTI_ERROR_NONE) {
147 warnx("jvmti: cannot get source filename ret=%d", ret);
148 goto error;
149 }
150
151 ret = (*jvmti)->GetClassSignature(jvmti, decl_class,
152 &class_sign, NULL);
153 if (ret != JVMTI_ERROR_NONE) {
154 warnx("jvmti: getclassignature failed");
155 goto error;
156 }
157
158 ret = (*jvmti)->GetMethodName(jvmti, method, &func_name,
159 &func_sign, NULL);
160 if (ret != JVMTI_ERROR_NONE) {
161 warnx("jvmti: failed getmethodname");
162 goto error;
163 }
164
165 /*
166 * Assume path name is class hierarchy, this is a common practice with Java programs
167 */
168 if (*class_sign == 'L') {
169 int j, i = 0;
170 char *p = strrchr(class_sign, '/');
171 if (p) {
172 /* drop the 'L' prefix and copy up to the final '/' */
173 for (i = 0; i < (p - class_sign); i++)
174 fn[i] = class_sign[i+1];
175 }
176 /*
177 * append file name, we use loops and not string ops to avoid modifying
178 * class_sign which is used later for the symbol name
179 */
180 for (j = 0; i < (PATH_MAX - 1) && file_name && j < strlen(file_name); j++, i++)
181 fn[i] = file_name[j];
182 fn[i] = '\0';
183 } else {
184 /* fallback case */
185 strcpy(fn, file_name);
186 }
187 /*
188 * write source line info record if we have it
189 */
190 if (jvmti_write_debug_info(jvmti_agent, addr, fn, line_tab, nr_lines))
191 warnx("jvmti: write_debug_info() failed");
192
193 len = strlen(func_name) + strlen(class_sign) + strlen(func_sign) + 2;
194 {
195 char str[len];
196 snprintf(str, len, "%s%s%s", class_sign, func_name, func_sign);
197
198 if (jvmti_write_code(jvmti_agent, str, addr, code_addr, code_size))
199 warnx("jvmti: write_code() failed");
200 }
201error:
202 (*jvmti)->Deallocate(jvmti, (unsigned char *)func_name);
203 (*jvmti)->Deallocate(jvmti, (unsigned char *)func_sign);
204 (*jvmti)->Deallocate(jvmti, (unsigned char *)class_sign);
205 (*jvmti)->Deallocate(jvmti, (unsigned char *)file_name);
206 free(line_tab);
207}
208
209static void JNICALL
210code_generated_cb(jvmtiEnv *jvmti,
211 char const *name,
212 void const *code_addr,
213 jint code_size)
214{
215 uint64_t addr = (uint64_t)(unsigned long)code_addr;
216 int ret;
217
218 ret = jvmti_write_code(jvmti_agent, name, addr, code_addr, code_size);
219 if (ret)
220 warnx("jvmti: write_code() failed for code_generated");
221}
222
223JNIEXPORT jint JNICALL
224Agent_OnLoad(JavaVM *jvm, char *options, void *reserved __unused)
225{
226 jvmtiEventCallbacks cb;
227 jvmtiCapabilities caps1;
228 jvmtiJlocationFormat format;
229 jvmtiEnv *jvmti = NULL;
230 jint ret;
231
232 jvmti_agent = jvmti_open();
233 if (!jvmti_agent) {
234 warnx("jvmti: open_agent failed");
235 return -1;
236 }
237
238 /*
239 * Request a JVMTI interface version 1 environment
240 */
241 ret = (*jvm)->GetEnv(jvm, (void *)&jvmti, JVMTI_VERSION_1);
242 if (ret != JNI_OK) {
243 warnx("jvmti: jvmti version 1 not supported");
244 return -1;
245 }
246
247 /*
248 * acquire method_load capability, we require it
249 * request line numbers (optional)
250 */
251 memset(&caps1, 0, sizeof(caps1));
252 caps1.can_generate_compiled_method_load_events = 1;
253
254 ret = (*jvmti)->AddCapabilities(jvmti, &caps1);
255 if (ret != JVMTI_ERROR_NONE) {
256 warnx("jvmti: acquire compiled_method capability failed");
257 return -1;
258 }
259 ret = (*jvmti)->GetJLocationFormat(jvmti, &format);
260 if (ret == JVMTI_ERROR_NONE && format == JVMTI_JLOCATION_JVMBCI) {
261 memset(&caps1, 0, sizeof(caps1));
262 caps1.can_get_line_numbers = 1;
263 caps1.can_get_source_file_name = 1;
264 ret = (*jvmti)->AddCapabilities(jvmti, &caps1);
265 if (ret == JVMTI_ERROR_NONE)
266 has_line_numbers = 1;
267 }
268
269 memset(&cb, 0, sizeof(cb));
270
271 cb.CompiledMethodLoad = compiled_method_load_cb;
272 cb.DynamicCodeGenerated = code_generated_cb;
273
274 ret = (*jvmti)->SetEventCallbacks(jvmti, &cb, sizeof(cb));
275 if (ret != JVMTI_ERROR_NONE) {
276 warnx("jvmti: cannot set event callbacks");
277 return -1;
278 }
279
280 ret = (*jvmti)->SetEventNotificationMode(jvmti, JVMTI_ENABLE,
281 JVMTI_EVENT_COMPILED_METHOD_LOAD, NULL);
282 if (ret != JVMTI_ERROR_NONE) {
283 warnx("jvmti: setnotification failed for method_load");
284 return -1;
285 }
286
287 ret = (*jvmti)->SetEventNotificationMode(jvmti, JVMTI_ENABLE,
288 JVMTI_EVENT_DYNAMIC_CODE_GENERATED, NULL);
289 if (ret != JVMTI_ERROR_NONE) {
290 warnx("jvmti: setnotification failed on code_generated");
291 return -1;
292 }
293 return 0;
294}
295
296JNIEXPORT void JNICALL
297Agent_OnUnload(JavaVM *jvm __unused)
298{
299 int ret;
300
301 ret = jvmti_close(jvmti_agent);
302 if (ret)
303 errx(1, "Error: op_close_agent()");
304}
diff --git a/tools/perf/perf.c b/tools/perf/perf.c
index a929618b8eb6..aaee0a782747 100644
--- a/tools/perf/perf.c
+++ b/tools/perf/perf.c
@@ -454,11 +454,12 @@ static void handle_internal_command(int argc, const char **argv)
454 454
455static void execv_dashed_external(const char **argv) 455static void execv_dashed_external(const char **argv)
456{ 456{
457 struct strbuf cmd = STRBUF_INIT; 457 char *cmd;
458 const char *tmp; 458 const char *tmp;
459 int status; 459 int status;
460 460
461 strbuf_addf(&cmd, "perf-%s", argv[0]); 461 if (asprintf(&cmd, "perf-%s", argv[0]) < 0)
462 goto do_die;
462 463
463 /* 464 /*
464 * argv[0] must be the perf command, but the argv array 465 * argv[0] must be the perf command, but the argv array
@@ -467,7 +468,7 @@ static void execv_dashed_external(const char **argv)
467 * restore it on error. 468 * restore it on error.
468 */ 469 */
469 tmp = argv[0]; 470 tmp = argv[0];
470 argv[0] = cmd.buf; 471 argv[0] = cmd;
471 472
472 /* 473 /*
473 * if we fail because the command is not found, it is 474 * if we fail because the command is not found, it is
@@ -475,15 +476,16 @@ static void execv_dashed_external(const char **argv)
475 */ 476 */
476 status = run_command_v_opt(argv, 0); 477 status = run_command_v_opt(argv, 0);
477 if (status != -ERR_RUN_COMMAND_EXEC) { 478 if (status != -ERR_RUN_COMMAND_EXEC) {
478 if (IS_RUN_COMMAND_ERR(status)) 479 if (IS_RUN_COMMAND_ERR(status)) {
480do_die:
479 die("unable to run '%s'", argv[0]); 481 die("unable to run '%s'", argv[0]);
482 }
480 exit(-status); 483 exit(-status);
481 } 484 }
482 errno = ENOENT; /* as if we called execvp */ 485 errno = ENOENT; /* as if we called execvp */
483 486
484 argv[0] = tmp; 487 argv[0] = tmp;
485 488 zfree(&cmd);
486 strbuf_release(&cmd);
487} 489}
488 490
489static int run_argv(int *argcp, const char ***argv) 491static int run_argv(int *argcp, const char ***argv)
@@ -546,6 +548,8 @@ int main(int argc, const char **argv)
546 548
547 srandom(time(NULL)); 549 srandom(time(NULL));
548 550
551 perf_config(perf_default_config, NULL);
552
549 /* get debugfs/tracefs mount point from /proc/mounts */ 553 /* get debugfs/tracefs mount point from /proc/mounts */
550 tracing_path_mount(); 554 tracing_path_mount();
551 555
@@ -613,6 +617,8 @@ int main(int argc, const char **argv)
613 */ 617 */
614 pthread__block_sigwinch(); 618 pthread__block_sigwinch();
615 619
620 perf_debug_setup();
621
616 while (1) { 622 while (1) {
617 static int done_help; 623 static int done_help;
618 int was_alias = run_argv(&argc, &argv); 624 int was_alias = run_argv(&argc, &argv);
diff --git a/tools/perf/perf.h b/tools/perf/perf.h
index 90129accffbe..5381a01c0610 100644
--- a/tools/perf/perf.h
+++ b/tools/perf/perf.h
@@ -58,6 +58,8 @@ struct record_opts {
58 bool full_auxtrace; 58 bool full_auxtrace;
59 bool auxtrace_snapshot_mode; 59 bool auxtrace_snapshot_mode;
60 bool record_switch_events; 60 bool record_switch_events;
61 bool all_kernel;
62 bool all_user;
61 unsigned int freq; 63 unsigned int freq;
62 unsigned int mmap_pages; 64 unsigned int mmap_pages;
63 unsigned int auxtrace_mmap_pages; 65 unsigned int auxtrace_mmap_pages;
diff --git a/tools/perf/scripts/python/Perf-Trace-Util/lib/Perf/Trace/Util.py b/tools/perf/scripts/python/Perf-Trace-Util/lib/Perf/Trace/Util.py
index 15c8400240fd..1d95009592eb 100644
--- a/tools/perf/scripts/python/Perf-Trace-Util/lib/Perf/Trace/Util.py
+++ b/tools/perf/scripts/python/Perf-Trace-Util/lib/Perf/Trace/Util.py
@@ -71,7 +71,10 @@ try:
71except: 71except:
72 if not audit_package_warned: 72 if not audit_package_warned:
73 audit_package_warned = True 73 audit_package_warned = True
74 print "Install the audit-libs-python package to get syscall names" 74 print "Install the audit-libs-python package to get syscall names.\n" \
75 "For example:\n # apt-get install python-audit (Ubuntu)" \
76 "\n # yum install audit-libs-python (Fedora)" \
77 "\n etc.\n"
75 78
76def syscall_name(id): 79def syscall_name(id):
77 try: 80 try:
diff --git a/tools/perf/tests/.gitignore b/tools/perf/tests/.gitignore
index bf016c439fbd..8cc30e731c73 100644
--- a/tools/perf/tests/.gitignore
+++ b/tools/perf/tests/.gitignore
@@ -1,3 +1,4 @@
1llvm-src-base.c 1llvm-src-base.c
2llvm-src-kbuild.c 2llvm-src-kbuild.c
3llvm-src-prologue.c 3llvm-src-prologue.c
4llvm-src-relocation.c
diff --git a/tools/perf/tests/Build b/tools/perf/tests/Build
index 614899b88b37..1ba628ed049a 100644
--- a/tools/perf/tests/Build
+++ b/tools/perf/tests/Build
@@ -31,7 +31,7 @@ perf-y += sample-parsing.o
31perf-y += parse-no-sample-id-all.o 31perf-y += parse-no-sample-id-all.o
32perf-y += kmod-path.o 32perf-y += kmod-path.o
33perf-y += thread-map.o 33perf-y += thread-map.o
34perf-y += llvm.o llvm-src-base.o llvm-src-kbuild.o llvm-src-prologue.o 34perf-y += llvm.o llvm-src-base.o llvm-src-kbuild.o llvm-src-prologue.o llvm-src-relocation.o
35perf-y += bpf.o 35perf-y += bpf.o
36perf-y += topology.o 36perf-y += topology.o
37perf-y += cpumap.o 37perf-y += cpumap.o
@@ -59,6 +59,13 @@ $(OUTPUT)tests/llvm-src-prologue.c: tests/bpf-script-test-prologue.c tests/Build
59 $(Q)sed -e 's/"/\\"/g' -e 's/\(.*\)/"\1\\n"/g' $< >> $@ 59 $(Q)sed -e 's/"/\\"/g' -e 's/\(.*\)/"\1\\n"/g' $< >> $@
60 $(Q)echo ';' >> $@ 60 $(Q)echo ';' >> $@
61 61
62$(OUTPUT)tests/llvm-src-relocation.c: tests/bpf-script-test-relocation.c tests/Build
63 $(call rule_mkdir)
64 $(Q)echo '#include <tests/llvm.h>' > $@
65 $(Q)echo 'const char test_llvm__bpf_test_relocation[] =' >> $@
66 $(Q)sed -e 's/"/\\"/g' -e 's/\(.*\)/"\1\\n"/g' $< >> $@
67 $(Q)echo ';' >> $@
68
62ifeq ($(ARCH),$(filter $(ARCH),x86 arm arm64)) 69ifeq ($(ARCH),$(filter $(ARCH),x86 arm arm64))
63perf-$(CONFIG_DWARF_UNWIND) += dwarf-unwind.o 70perf-$(CONFIG_DWARF_UNWIND) += dwarf-unwind.o
64endif 71endif
diff --git a/tools/perf/tests/bp_signal.c b/tools/perf/tests/bp_signal.c
index fb80c9eb6a95..e7664fe3bd33 100644
--- a/tools/perf/tests/bp_signal.c
+++ b/tools/perf/tests/bp_signal.c
@@ -29,14 +29,59 @@
29 29
30static int fd1; 30static int fd1;
31static int fd2; 31static int fd2;
32static int fd3;
32static int overflows; 33static int overflows;
34static int overflows_2;
35
36volatile long the_var;
37
38
39/*
40 * Use ASM to ensure watchpoint and breakpoint can be triggered
41 * at one instruction.
42 */
43#if defined (__x86_64__)
44extern void __test_function(volatile long *ptr);
45asm (
46 ".globl __test_function\n"
47 "__test_function:\n"
48 "incq (%rdi)\n"
49 "ret\n");
50#elif defined (__aarch64__)
51extern void __test_function(volatile long *ptr);
52asm (
53 ".globl __test_function\n"
54 "__test_function:\n"
55 "str x30, [x0]\n"
56 "ret\n");
57
58#else
59static void __test_function(volatile long *ptr)
60{
61 *ptr = 0x1234;
62}
63#endif
33 64
34__attribute__ ((noinline)) 65__attribute__ ((noinline))
35static int test_function(void) 66static int test_function(void)
36{ 67{
68 __test_function(&the_var);
69 the_var++;
37 return time(NULL); 70 return time(NULL);
38} 71}
39 72
73static void sig_handler_2(int signum __maybe_unused,
74 siginfo_t *oh __maybe_unused,
75 void *uc __maybe_unused)
76{
77 overflows_2++;
78 if (overflows_2 > 10) {
79 ioctl(fd1, PERF_EVENT_IOC_DISABLE, 0);
80 ioctl(fd2, PERF_EVENT_IOC_DISABLE, 0);
81 ioctl(fd3, PERF_EVENT_IOC_DISABLE, 0);
82 }
83}
84
40static void sig_handler(int signum __maybe_unused, 85static void sig_handler(int signum __maybe_unused,
41 siginfo_t *oh __maybe_unused, 86 siginfo_t *oh __maybe_unused,
42 void *uc __maybe_unused) 87 void *uc __maybe_unused)
@@ -54,10 +99,11 @@ static void sig_handler(int signum __maybe_unused,
54 */ 99 */
55 ioctl(fd1, PERF_EVENT_IOC_DISABLE, 0); 100 ioctl(fd1, PERF_EVENT_IOC_DISABLE, 0);
56 ioctl(fd2, PERF_EVENT_IOC_DISABLE, 0); 101 ioctl(fd2, PERF_EVENT_IOC_DISABLE, 0);
102 ioctl(fd3, PERF_EVENT_IOC_DISABLE, 0);
57 } 103 }
58} 104}
59 105
60static int bp_event(void *fn, int setup_signal) 106static int __event(bool is_x, void *addr, int sig)
61{ 107{
62 struct perf_event_attr pe; 108 struct perf_event_attr pe;
63 int fd; 109 int fd;
@@ -67,8 +113,8 @@ static int bp_event(void *fn, int setup_signal)
67 pe.size = sizeof(struct perf_event_attr); 113 pe.size = sizeof(struct perf_event_attr);
68 114
69 pe.config = 0; 115 pe.config = 0;
70 pe.bp_type = HW_BREAKPOINT_X; 116 pe.bp_type = is_x ? HW_BREAKPOINT_X : HW_BREAKPOINT_W;
71 pe.bp_addr = (unsigned long) fn; 117 pe.bp_addr = (unsigned long) addr;
72 pe.bp_len = sizeof(long); 118 pe.bp_len = sizeof(long);
73 119
74 pe.sample_period = 1; 120 pe.sample_period = 1;
@@ -86,17 +132,25 @@ static int bp_event(void *fn, int setup_signal)
86 return TEST_FAIL; 132 return TEST_FAIL;
87 } 133 }
88 134
89 if (setup_signal) { 135 fcntl(fd, F_SETFL, O_RDWR|O_NONBLOCK|O_ASYNC);
90 fcntl(fd, F_SETFL, O_RDWR|O_NONBLOCK|O_ASYNC); 136 fcntl(fd, F_SETSIG, sig);
91 fcntl(fd, F_SETSIG, SIGIO); 137 fcntl(fd, F_SETOWN, getpid());
92 fcntl(fd, F_SETOWN, getpid());
93 }
94 138
95 ioctl(fd, PERF_EVENT_IOC_RESET, 0); 139 ioctl(fd, PERF_EVENT_IOC_RESET, 0);
96 140
97 return fd; 141 return fd;
98} 142}
99 143
144static int bp_event(void *addr, int sig)
145{
146 return __event(true, addr, sig);
147}
148
149static int wp_event(void *addr, int sig)
150{
151 return __event(false, addr, sig);
152}
153
100static long long bp_count(int fd) 154static long long bp_count(int fd)
101{ 155{
102 long long count; 156 long long count;
@@ -114,7 +168,7 @@ static long long bp_count(int fd)
114int test__bp_signal(int subtest __maybe_unused) 168int test__bp_signal(int subtest __maybe_unused)
115{ 169{
116 struct sigaction sa; 170 struct sigaction sa;
117 long long count1, count2; 171 long long count1, count2, count3;
118 172
119 /* setup SIGIO signal handler */ 173 /* setup SIGIO signal handler */
120 memset(&sa, 0, sizeof(struct sigaction)); 174 memset(&sa, 0, sizeof(struct sigaction));
@@ -126,21 +180,52 @@ int test__bp_signal(int subtest __maybe_unused)
126 return TEST_FAIL; 180 return TEST_FAIL;
127 } 181 }
128 182
183 sa.sa_sigaction = (void *) sig_handler_2;
184 if (sigaction(SIGUSR1, &sa, NULL) < 0) {
185 pr_debug("failed setting up signal handler 2\n");
186 return TEST_FAIL;
187 }
188
129 /* 189 /*
130 * We create following events: 190 * We create following events:
131 * 191 *
132 * fd1 - breakpoint event on test_function with SIGIO 192 * fd1 - breakpoint event on __test_function with SIGIO
133 * signal configured. We should get signal 193 * signal configured. We should get signal
134 * notification each time the breakpoint is hit 194 * notification each time the breakpoint is hit
135 * 195 *
136 * fd2 - breakpoint event on sig_handler without SIGIO 196 * fd2 - breakpoint event on sig_handler with SIGUSR1
197 * configured. We should get SIGUSR1 each time when
198 * breakpoint is hit
199 *
200 * fd3 - watchpoint event on __test_function with SIGIO
137 * configured. 201 * configured.
138 * 202 *
139 * Following processing should happen: 203 * Following processing should happen:
140 * - execute test_function 204 * Exec: Action: Result:
141 * - fd1 event breakpoint hit -> count1 == 1 205 * incq (%rdi) - fd1 event breakpoint hit -> count1 == 1
142 * - SIGIO is delivered -> overflows == 1 206 * - SIGIO is delivered
143 * - fd2 event breakpoint hit -> count2 == 1 207 * sig_handler - fd2 event breakpoint hit -> count2 == 1
208 * - SIGUSR1 is delivered
209 * sig_handler_2 -> overflows_2 == 1 (nested signal)
210 * sys_rt_sigreturn - return from sig_handler_2
211 * overflows++ -> overflows = 1
212 * sys_rt_sigreturn - return from sig_handler
213 * incq (%rdi) - fd3 event watchpoint hit -> count3 == 1 (wp and bp in one insn)
214 * - SIGIO is delivered
215 * sig_handler - fd2 event breakpoint hit -> count2 == 2
216 * - SIGUSR1 is delivered
217 * sig_handler_2 -> overflows_2 == 2 (nested signal)
218 * sys_rt_sigreturn - return from sig_handler_2
219 * overflows++ -> overflows = 2
220 * sys_rt_sigreturn - return from sig_handler
221 * the_var++ - fd3 event watchpoint hit -> count3 == 2 (standalone watchpoint)
222 * - SIGIO is delivered
223 * sig_handler - fd2 event breakpoint hit -> count2 == 3
224 * - SIGUSR1 is delivered
225 * sig_handler_2 -> overflows_2 == 3 (nested signal)
226 * sys_rt_sigreturn - return from sig_handler_2
227 * overflows++ -> overflows == 3
228 * sys_rt_sigreturn - return from sig_handler
144 * 229 *
145 * The test case check following error conditions: 230 * The test case check following error conditions:
146 * - we get stuck in signal handler because of debug 231 * - we get stuck in signal handler because of debug
@@ -152,11 +237,13 @@ int test__bp_signal(int subtest __maybe_unused)
152 * 237 *
153 */ 238 */
154 239
155 fd1 = bp_event(test_function, 1); 240 fd1 = bp_event(__test_function, SIGIO);
156 fd2 = bp_event(sig_handler, 0); 241 fd2 = bp_event(sig_handler, SIGUSR1);
242 fd3 = wp_event((void *)&the_var, SIGIO);
157 243
158 ioctl(fd1, PERF_EVENT_IOC_ENABLE, 0); 244 ioctl(fd1, PERF_EVENT_IOC_ENABLE, 0);
159 ioctl(fd2, PERF_EVENT_IOC_ENABLE, 0); 245 ioctl(fd2, PERF_EVENT_IOC_ENABLE, 0);
246 ioctl(fd3, PERF_EVENT_IOC_ENABLE, 0);
160 247
161 /* 248 /*
162 * Kick off the test by trigering 'fd1' 249 * Kick off the test by trigering 'fd1'
@@ -166,15 +253,18 @@ int test__bp_signal(int subtest __maybe_unused)
166 253
167 ioctl(fd1, PERF_EVENT_IOC_DISABLE, 0); 254 ioctl(fd1, PERF_EVENT_IOC_DISABLE, 0);
168 ioctl(fd2, PERF_EVENT_IOC_DISABLE, 0); 255 ioctl(fd2, PERF_EVENT_IOC_DISABLE, 0);
256 ioctl(fd3, PERF_EVENT_IOC_DISABLE, 0);
169 257
170 count1 = bp_count(fd1); 258 count1 = bp_count(fd1);
171 count2 = bp_count(fd2); 259 count2 = bp_count(fd2);
260 count3 = bp_count(fd3);
172 261
173 close(fd1); 262 close(fd1);
174 close(fd2); 263 close(fd2);
264 close(fd3);
175 265
176 pr_debug("count1 %lld, count2 %lld, overflow %d\n", 266 pr_debug("count1 %lld, count2 %lld, count3 %lld, overflow %d, overflows_2 %d\n",
177 count1, count2, overflows); 267 count1, count2, count3, overflows, overflows_2);
178 268
179 if (count1 != 1) { 269 if (count1 != 1) {
180 if (count1 == 11) 270 if (count1 == 11)
@@ -183,12 +273,18 @@ int test__bp_signal(int subtest __maybe_unused)
183 pr_debug("failed: wrong count for bp1%lld\n", count1); 273 pr_debug("failed: wrong count for bp1%lld\n", count1);
184 } 274 }
185 275
186 if (overflows != 1) 276 if (overflows != 3)
187 pr_debug("failed: wrong overflow hit\n"); 277 pr_debug("failed: wrong overflow hit\n");
188 278
189 if (count2 != 1) 279 if (overflows_2 != 3)
280 pr_debug("failed: wrong overflow_2 hit\n");
281
282 if (count2 != 3)
190 pr_debug("failed: wrong count for bp2\n"); 283 pr_debug("failed: wrong count for bp2\n");
191 284
192 return count1 == 1 && overflows == 1 && count2 == 1 ? 285 if (count3 != 2)
286 pr_debug("failed: wrong count for bp3\n");
287
288 return count1 == 1 && overflows == 3 && count2 == 3 && overflows_2 == 3 && count3 == 2 ?
193 TEST_OK : TEST_FAIL; 289 TEST_OK : TEST_FAIL;
194} 290}
diff --git a/tools/perf/tests/bpf-script-test-relocation.c b/tools/perf/tests/bpf-script-test-relocation.c
new file mode 100644
index 000000000000..93af77421816
--- /dev/null
+++ b/tools/perf/tests/bpf-script-test-relocation.c
@@ -0,0 +1,50 @@
1/*
2 * bpf-script-test-relocation.c
3 * Test BPF loader checking relocation
4 */
5#ifndef LINUX_VERSION_CODE
6# error Need LINUX_VERSION_CODE
7# error Example: for 4.2 kernel, put 'clang-opt="-DLINUX_VERSION_CODE=0x40200" into llvm section of ~/.perfconfig'
8#endif
9#define BPF_ANY 0
10#define BPF_MAP_TYPE_ARRAY 2
11#define BPF_FUNC_map_lookup_elem 1
12#define BPF_FUNC_map_update_elem 2
13
14static void *(*bpf_map_lookup_elem)(void *map, void *key) =
15 (void *) BPF_FUNC_map_lookup_elem;
16static void *(*bpf_map_update_elem)(void *map, void *key, void *value, int flags) =
17 (void *) BPF_FUNC_map_update_elem;
18
19struct bpf_map_def {
20 unsigned int type;
21 unsigned int key_size;
22 unsigned int value_size;
23 unsigned int max_entries;
24};
25
26#define SEC(NAME) __attribute__((section(NAME), used))
27struct bpf_map_def SEC("maps") my_table = {
28 .type = BPF_MAP_TYPE_ARRAY,
29 .key_size = sizeof(int),
30 .value_size = sizeof(int),
31 .max_entries = 1,
32};
33
34int this_is_a_global_val;
35
36SEC("func=sys_write")
37int bpf_func__sys_write(void *ctx)
38{
39 int key = 0;
40 int value = 0;
41
42 /*
43 * Incorrect relocation. Should not allow this program be
44 * loaded into kernel.
45 */
46 bpf_map_update_elem(&this_is_a_global_val, &key, &value, 0);
47 return 0;
48}
49char _license[] SEC("license") = "GPL";
50int _version SEC("version") = LINUX_VERSION_CODE;
diff --git a/tools/perf/tests/bpf.c b/tools/perf/tests/bpf.c
index 33689a0cf821..199501c71e27 100644
--- a/tools/perf/tests/bpf.c
+++ b/tools/perf/tests/bpf.c
@@ -1,7 +1,11 @@
1#include <stdio.h> 1#include <stdio.h>
2#include <sys/epoll.h> 2#include <sys/epoll.h>
3#include <util/util.h>
3#include <util/bpf-loader.h> 4#include <util/bpf-loader.h>
4#include <util/evlist.h> 5#include <util/evlist.h>
6#include <linux/bpf.h>
7#include <linux/filter.h>
8#include <bpf/bpf.h>
5#include "tests.h" 9#include "tests.h"
6#include "llvm.h" 10#include "llvm.h"
7#include "debug.h" 11#include "debug.h"
@@ -71,6 +75,15 @@ static struct {
71 (NR_ITERS + 1) / 4, 75 (NR_ITERS + 1) / 4,
72 }, 76 },
73#endif 77#endif
78 {
79 LLVM_TESTCASE_BPF_RELOCATION,
80 "Test BPF relocation checker",
81 "[bpf_relocation_test]",
82 "fix 'perf test LLVM' first",
83 "libbpf error when dealing with relocation",
84 NULL,
85 0,
86 },
74}; 87};
75 88
76static int do_test(struct bpf_object *obj, int (*func)(void), 89static int do_test(struct bpf_object *obj, int (*func)(void),
@@ -99,7 +112,7 @@ static int do_test(struct bpf_object *obj, int (*func)(void),
99 parse_evlist.error = &parse_error; 112 parse_evlist.error = &parse_error;
100 INIT_LIST_HEAD(&parse_evlist.list); 113 INIT_LIST_HEAD(&parse_evlist.list);
101 114
102 err = parse_events_load_bpf_obj(&parse_evlist, &parse_evlist.list, obj); 115 err = parse_events_load_bpf_obj(&parse_evlist, &parse_evlist.list, obj, NULL);
103 if (err || list_empty(&parse_evlist.list)) { 116 if (err || list_empty(&parse_evlist.list)) {
104 pr_debug("Failed to add events selected by BPF\n"); 117 pr_debug("Failed to add events selected by BPF\n");
105 return TEST_FAIL; 118 return TEST_FAIL;
@@ -190,7 +203,7 @@ static int __test__bpf(int idx)
190 203
191 ret = test_llvm__fetch_bpf_obj(&obj_buf, &obj_buf_sz, 204 ret = test_llvm__fetch_bpf_obj(&obj_buf, &obj_buf_sz,
192 bpf_testcase_table[idx].prog_id, 205 bpf_testcase_table[idx].prog_id,
193 true); 206 true, NULL);
194 if (ret != TEST_OK || !obj_buf || !obj_buf_sz) { 207 if (ret != TEST_OK || !obj_buf || !obj_buf_sz) {
195 pr_debug("Unable to get BPF object, %s\n", 208 pr_debug("Unable to get BPF object, %s\n",
196 bpf_testcase_table[idx].msg_compile_fail); 209 bpf_testcase_table[idx].msg_compile_fail);
@@ -202,14 +215,21 @@ static int __test__bpf(int idx)
202 215
203 obj = prepare_bpf(obj_buf, obj_buf_sz, 216 obj = prepare_bpf(obj_buf, obj_buf_sz,
204 bpf_testcase_table[idx].name); 217 bpf_testcase_table[idx].name);
205 if (!obj) { 218 if ((!!bpf_testcase_table[idx].target_func) != (!!obj)) {
219 if (!obj)
220 pr_debug("Fail to load BPF object: %s\n",
221 bpf_testcase_table[idx].msg_load_fail);
222 else
223 pr_debug("Success unexpectedly: %s\n",
224 bpf_testcase_table[idx].msg_load_fail);
206 ret = TEST_FAIL; 225 ret = TEST_FAIL;
207 goto out; 226 goto out;
208 } 227 }
209 228
210 ret = do_test(obj, 229 if (obj)
211 bpf_testcase_table[idx].target_func, 230 ret = do_test(obj,
212 bpf_testcase_table[idx].expect_result); 231 bpf_testcase_table[idx].target_func,
232 bpf_testcase_table[idx].expect_result);
213out: 233out:
214 bpf__clear(); 234 bpf__clear();
215 return ret; 235 return ret;
@@ -227,6 +247,36 @@ const char *test__bpf_subtest_get_desc(int i)
227 return bpf_testcase_table[i].desc; 247 return bpf_testcase_table[i].desc;
228} 248}
229 249
250static int check_env(void)
251{
252 int err;
253 unsigned int kver_int;
254 char license[] = "GPL";
255
256 struct bpf_insn insns[] = {
257 BPF_MOV64_IMM(BPF_REG_0, 1),
258 BPF_EXIT_INSN(),
259 };
260
261 err = fetch_kernel_version(&kver_int, NULL, 0);
262 if (err) {
263 pr_debug("Unable to get kernel version\n");
264 return err;
265 }
266
267 err = bpf_load_program(BPF_PROG_TYPE_KPROBE, insns,
268 sizeof(insns) / sizeof(insns[0]),
269 license, kver_int, NULL, 0);
270 if (err < 0) {
271 pr_err("Missing basic BPF support, skip this test: %s\n",
272 strerror(errno));
273 return err;
274 }
275 close(err);
276
277 return 0;
278}
279
230int test__bpf(int i) 280int test__bpf(int i)
231{ 281{
232 int err; 282 int err;
@@ -239,6 +289,9 @@ int test__bpf(int i)
239 return TEST_SKIP; 289 return TEST_SKIP;
240 } 290 }
241 291
292 if (check_env())
293 return TEST_SKIP;
294
242 err = __test__bpf(i); 295 err = __test__bpf(i);
243 return err; 296 return err;
244} 297}
diff --git a/tools/perf/tests/code-reading.c b/tools/perf/tests/code-reading.c
index 313a48c6b2bc..afc9ad0a0515 100644
--- a/tools/perf/tests/code-reading.c
+++ b/tools/perf/tests/code-reading.c
@@ -439,7 +439,7 @@ static int do_test_code_reading(bool try_kcore)
439 .mmap_pages = UINT_MAX, 439 .mmap_pages = UINT_MAX,
440 .user_freq = UINT_MAX, 440 .user_freq = UINT_MAX,
441 .user_interval = ULLONG_MAX, 441 .user_interval = ULLONG_MAX,
442 .freq = 4000, 442 .freq = 500,
443 .target = { 443 .target = {
444 .uses_mmap = true, 444 .uses_mmap = true,
445 }, 445 },
@@ -559,7 +559,13 @@ static int do_test_code_reading(bool try_kcore)
559 evlist = NULL; 559 evlist = NULL;
560 continue; 560 continue;
561 } 561 }
562 pr_debug("perf_evlist__open failed\n"); 562
563 if (verbose) {
564 char errbuf[512];
565 perf_evlist__strerror_open(evlist, errno, errbuf, sizeof(errbuf));
566 pr_debug("perf_evlist__open() failed!\n%s\n", errbuf);
567 }
568
563 goto out_put; 569 goto out_put;
564 } 570 }
565 break; 571 break;
diff --git a/tools/perf/tests/hists_cumulate.c b/tools/perf/tests/hists_cumulate.c
index 5e6a86e50fb9..ecf136c385d5 100644
--- a/tools/perf/tests/hists_cumulate.c
+++ b/tools/perf/tests/hists_cumulate.c
@@ -191,7 +191,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. 191 * function since TEST_ASSERT_VAL() returns in case of failure.
192 */ 192 */
193 hists__collapse_resort(hists, NULL); 193 hists__collapse_resort(hists, NULL);
194 hists__output_resort(hists, NULL); 194 perf_evsel__output_resort(hists_to_evsel(hists), NULL);
195 195
196 if (verbose > 2) { 196 if (verbose > 2) {
197 pr_info("use callchain: %d, cumulate callchain: %d\n", 197 pr_info("use callchain: %d, cumulate callchain: %d\n",
diff --git a/tools/perf/tests/hists_filter.c b/tools/perf/tests/hists_filter.c
index 351a42463444..34b945a55d4d 100644
--- a/tools/perf/tests/hists_filter.c
+++ b/tools/perf/tests/hists_filter.c
@@ -145,7 +145,7 @@ int test__hists_filter(int subtest __maybe_unused)
145 struct hists *hists = evsel__hists(evsel); 145 struct hists *hists = evsel__hists(evsel);
146 146
147 hists__collapse_resort(hists, NULL); 147 hists__collapse_resort(hists, NULL);
148 hists__output_resort(hists, NULL); 148 perf_evsel__output_resort(evsel, NULL);
149 149
150 if (verbose > 2) { 150 if (verbose > 2) {
151 pr_info("Normal histogram\n"); 151 pr_info("Normal histogram\n");
diff --git a/tools/perf/tests/hists_output.c b/tools/perf/tests/hists_output.c
index b231265148d8..23cce67c7e48 100644
--- a/tools/perf/tests/hists_output.c
+++ b/tools/perf/tests/hists_output.c
@@ -156,7 +156,7 @@ static int test1(struct perf_evsel *evsel, struct machine *machine)
156 goto out; 156 goto out;
157 157
158 hists__collapse_resort(hists, NULL); 158 hists__collapse_resort(hists, NULL);
159 hists__output_resort(hists, NULL); 159 perf_evsel__output_resort(evsel, NULL);
160 160
161 if (verbose > 2) { 161 if (verbose > 2) {
162 pr_info("[fields = %s, sort = %s]\n", field_order, sort_order); 162 pr_info("[fields = %s, sort = %s]\n", field_order, sort_order);
@@ -256,7 +256,7 @@ static int test2(struct perf_evsel *evsel, struct machine *machine)
256 goto out; 256 goto out;
257 257
258 hists__collapse_resort(hists, NULL); 258 hists__collapse_resort(hists, NULL);
259 hists__output_resort(hists, NULL); 259 perf_evsel__output_resort(evsel, NULL);
260 260
261 if (verbose > 2) { 261 if (verbose > 2) {
262 pr_info("[fields = %s, sort = %s]\n", field_order, sort_order); 262 pr_info("[fields = %s, sort = %s]\n", field_order, sort_order);
@@ -310,7 +310,7 @@ static int test3(struct perf_evsel *evsel, struct machine *machine)
310 goto out; 310 goto out;
311 311
312 hists__collapse_resort(hists, NULL); 312 hists__collapse_resort(hists, NULL);
313 hists__output_resort(hists, NULL); 313 perf_evsel__output_resort(evsel, NULL);
314 314
315 if (verbose > 2) { 315 if (verbose > 2) {
316 pr_info("[fields = %s, sort = %s]\n", field_order, sort_order); 316 pr_info("[fields = %s, sort = %s]\n", field_order, sort_order);
@@ -388,7 +388,7 @@ static int test4(struct perf_evsel *evsel, struct machine *machine)
388 goto out; 388 goto out;
389 389
390 hists__collapse_resort(hists, NULL); 390 hists__collapse_resort(hists, NULL);
391 hists__output_resort(hists, NULL); 391 perf_evsel__output_resort(evsel, NULL);
392 392
393 if (verbose > 2) { 393 if (verbose > 2) {
394 pr_info("[fields = %s, sort = %s]\n", field_order, sort_order); 394 pr_info("[fields = %s, sort = %s]\n", field_order, sort_order);
@@ -491,7 +491,7 @@ static int test5(struct perf_evsel *evsel, struct machine *machine)
491 goto out; 491 goto out;
492 492
493 hists__collapse_resort(hists, NULL); 493 hists__collapse_resort(hists, NULL);
494 hists__output_resort(hists, NULL); 494 perf_evsel__output_resort(evsel, NULL);
495 495
496 if (verbose > 2) { 496 if (verbose > 2) {
497 pr_info("[fields = %s, sort = %s]\n", field_order, sort_order); 497 pr_info("[fields = %s, sort = %s]\n", field_order, sort_order);
diff --git a/tools/perf/tests/llvm.c b/tools/perf/tests/llvm.c
index 06f45c1d4256..cff564fb4b66 100644
--- a/tools/perf/tests/llvm.c
+++ b/tools/perf/tests/llvm.c
@@ -6,12 +6,6 @@
6#include "tests.h" 6#include "tests.h"
7#include "debug.h" 7#include "debug.h"
8 8
9static int perf_config_cb(const char *var, const char *val,
10 void *arg __maybe_unused)
11{
12 return perf_default_config(var, val, arg);
13}
14
15#ifdef HAVE_LIBBPF_SUPPORT 9#ifdef HAVE_LIBBPF_SUPPORT
16static int test__bpf_parsing(void *obj_buf, size_t obj_buf_sz) 10static int test__bpf_parsing(void *obj_buf, size_t obj_buf_sz)
17{ 11{
@@ -35,6 +29,7 @@ static int test__bpf_parsing(void *obj_buf __maybe_unused,
35static struct { 29static struct {
36 const char *source; 30 const char *source;
37 const char *desc; 31 const char *desc;
32 bool should_load_fail;
38} bpf_source_table[__LLVM_TESTCASE_MAX] = { 33} bpf_source_table[__LLVM_TESTCASE_MAX] = {
39 [LLVM_TESTCASE_BASE] = { 34 [LLVM_TESTCASE_BASE] = {
40 .source = test_llvm__bpf_base_prog, 35 .source = test_llvm__bpf_base_prog,
@@ -48,14 +43,19 @@ static struct {
48 .source = test_llvm__bpf_test_prologue_prog, 43 .source = test_llvm__bpf_test_prologue_prog,
49 .desc = "Compile source for BPF prologue generation test", 44 .desc = "Compile source for BPF prologue generation test",
50 }, 45 },
46 [LLVM_TESTCASE_BPF_RELOCATION] = {
47 .source = test_llvm__bpf_test_relocation,
48 .desc = "Compile source for BPF relocation test",
49 .should_load_fail = true,
50 },
51}; 51};
52 52
53
54int 53int
55test_llvm__fetch_bpf_obj(void **p_obj_buf, 54test_llvm__fetch_bpf_obj(void **p_obj_buf,
56 size_t *p_obj_buf_sz, 55 size_t *p_obj_buf_sz,
57 enum test_llvm__testcase idx, 56 enum test_llvm__testcase idx,
58 bool force) 57 bool force,
58 bool *should_load_fail)
59{ 59{
60 const char *source; 60 const char *source;
61 const char *desc; 61 const char *desc;
@@ -68,8 +68,8 @@ test_llvm__fetch_bpf_obj(void **p_obj_buf,
68 68
69 source = bpf_source_table[idx].source; 69 source = bpf_source_table[idx].source;
70 desc = bpf_source_table[idx].desc; 70 desc = bpf_source_table[idx].desc;
71 71 if (should_load_fail)
72 perf_config(perf_config_cb, NULL); 72 *should_load_fail = bpf_source_table[idx].should_load_fail;
73 73
74 /* 74 /*
75 * Skip this test if user's .perfconfig doesn't set [llvm] section 75 * Skip this test if user's .perfconfig doesn't set [llvm] section
@@ -136,14 +136,15 @@ int test__llvm(int subtest)
136 int ret; 136 int ret;
137 void *obj_buf = NULL; 137 void *obj_buf = NULL;
138 size_t obj_buf_sz = 0; 138 size_t obj_buf_sz = 0;
139 bool should_load_fail = false;
139 140
140 if ((subtest < 0) || (subtest >= __LLVM_TESTCASE_MAX)) 141 if ((subtest < 0) || (subtest >= __LLVM_TESTCASE_MAX))
141 return TEST_FAIL; 142 return TEST_FAIL;
142 143
143 ret = test_llvm__fetch_bpf_obj(&obj_buf, &obj_buf_sz, 144 ret = test_llvm__fetch_bpf_obj(&obj_buf, &obj_buf_sz,
144 subtest, false); 145 subtest, false, &should_load_fail);
145 146
146 if (ret == TEST_OK) { 147 if (ret == TEST_OK && !should_load_fail) {
147 ret = test__bpf_parsing(obj_buf, obj_buf_sz); 148 ret = test__bpf_parsing(obj_buf, obj_buf_sz);
148 if (ret != TEST_OK) { 149 if (ret != TEST_OK) {
149 pr_debug("Failed to parse test case '%s'\n", 150 pr_debug("Failed to parse test case '%s'\n",
diff --git a/tools/perf/tests/llvm.h b/tools/perf/tests/llvm.h
index 5150b4d6ef50..0eaa604be99d 100644
--- a/tools/perf/tests/llvm.h
+++ b/tools/perf/tests/llvm.h
@@ -7,14 +7,17 @@
7extern const char test_llvm__bpf_base_prog[]; 7extern const char test_llvm__bpf_base_prog[];
8extern const char test_llvm__bpf_test_kbuild_prog[]; 8extern const char test_llvm__bpf_test_kbuild_prog[];
9extern const char test_llvm__bpf_test_prologue_prog[]; 9extern const char test_llvm__bpf_test_prologue_prog[];
10extern const char test_llvm__bpf_test_relocation[];
10 11
11enum test_llvm__testcase { 12enum test_llvm__testcase {
12 LLVM_TESTCASE_BASE, 13 LLVM_TESTCASE_BASE,
13 LLVM_TESTCASE_KBUILD, 14 LLVM_TESTCASE_KBUILD,
14 LLVM_TESTCASE_BPF_PROLOGUE, 15 LLVM_TESTCASE_BPF_PROLOGUE,
16 LLVM_TESTCASE_BPF_RELOCATION,
15 __LLVM_TESTCASE_MAX, 17 __LLVM_TESTCASE_MAX,
16}; 18};
17 19
18int test_llvm__fetch_bpf_obj(void **p_obj_buf, size_t *p_obj_buf_sz, 20int test_llvm__fetch_bpf_obj(void **p_obj_buf, size_t *p_obj_buf_sz,
19 enum test_llvm__testcase index, bool force); 21 enum test_llvm__testcase index, bool force,
22 bool *should_load_fail);
20#endif 23#endif
diff --git a/tools/perf/tests/make b/tools/perf/tests/make
index f918015512af..cac15d93aea6 100644
--- a/tools/perf/tests/make
+++ b/tools/perf/tests/make
@@ -15,6 +15,7 @@ else
15PERF := . 15PERF := .
16PERF_O := $(PERF) 16PERF_O := $(PERF)
17O_OPT := 17O_OPT :=
18FULL_O := $(shell readlink -f $(PERF_O) || echo $(PERF_O))
18 19
19ifneq ($(O),) 20ifneq ($(O),)
20 FULL_O := $(shell readlink -f $(O) || echo $(O)) 21 FULL_O := $(shell readlink -f $(O) || echo $(O))
@@ -79,6 +80,7 @@ make_no_libaudit := NO_LIBAUDIT=1
79make_no_libbionic := NO_LIBBIONIC=1 80make_no_libbionic := NO_LIBBIONIC=1
80make_no_auxtrace := NO_AUXTRACE=1 81make_no_auxtrace := NO_AUXTRACE=1
81make_no_libbpf := NO_LIBBPF=1 82make_no_libbpf := NO_LIBBPF=1
83make_no_libcrypto := NO_LIBCRYPTO=1
82make_tags := tags 84make_tags := tags
83make_cscope := cscope 85make_cscope := cscope
84make_help := help 86make_help := help
@@ -102,6 +104,7 @@ make_minimal := NO_LIBPERL=1 NO_LIBPYTHON=1 NO_NEWT=1 NO_GTK2=1
102make_minimal += NO_DEMANGLE=1 NO_LIBELF=1 NO_LIBUNWIND=1 NO_BACKTRACE=1 104make_minimal += NO_DEMANGLE=1 NO_LIBELF=1 NO_LIBUNWIND=1 NO_BACKTRACE=1
103make_minimal += NO_LIBNUMA=1 NO_LIBAUDIT=1 NO_LIBBIONIC=1 105make_minimal += NO_LIBNUMA=1 NO_LIBAUDIT=1 NO_LIBBIONIC=1
104make_minimal += NO_LIBDW_DWARF_UNWIND=1 NO_AUXTRACE=1 NO_LIBBPF=1 106make_minimal += NO_LIBDW_DWARF_UNWIND=1 NO_AUXTRACE=1 NO_LIBBPF=1
107make_minimal += NO_LIBCRYPTO=1
105 108
106# $(run) contains all available tests 109# $(run) contains all available tests
107run := make_pure 110run := make_pure
@@ -110,6 +113,9 @@ run := make_pure
110# disable features detection 113# disable features detection
111ifeq ($(MK),Makefile) 114ifeq ($(MK),Makefile)
112run += make_clean_all 115run += make_clean_all
116MAKE_F := $(MAKE)
117else
118MAKE_F := $(MAKE) -f $(MK)
113endif 119endif
114run += make_python_perf_so 120run += make_python_perf_so
115run += make_debug 121run += make_debug
@@ -260,6 +266,8 @@ run := $(shell shuf -e $(run))
260run_O := $(shell shuf -e $(run_O)) 266run_O := $(shell shuf -e $(run_O))
261endif 267endif
262 268
269max_width := $(shell echo $(run_O) | sed 's/ /\n/g' | wc -L)
270
263ifdef DEBUG 271ifdef DEBUG
264d := $(info run $(run)) 272d := $(info run $(run))
265d := $(info run_O $(run_O)) 273d := $(info run_O $(run_O))
@@ -267,13 +275,13 @@ endif
267 275
268MAKEFLAGS := --no-print-directory 276MAKEFLAGS := --no-print-directory
269 277
270clean := @(cd $(PERF); make -s -f $(MK) $(O_OPT) clean >/dev/null) 278clean := @(cd $(PERF); $(MAKE_F) -s $(O_OPT) clean >/dev/null)
271 279
272$(run): 280$(run):
273 $(call clean) 281 $(call clean)
274 @TMP_DEST=$$(mktemp -d); \ 282 @TMP_DEST=$$(mktemp -d); \
275 cmd="cd $(PERF) && make -f $(MK) $(PARALLEL_OPT) $(O_OPT) DESTDIR=$$TMP_DEST $($@)"; \ 283 cmd="cd $(PERF) && $(MAKE_F) $($@) $(PARALLEL_OPT) $(O_OPT) DESTDIR=$$TMP_DEST"; \
276 echo "- $@: $$cmd" && echo $$cmd > $@ && \ 284 printf "%*.*s: %s\n" $(max_width) $(max_width) "$@" "$$cmd" && echo $$cmd > $@ && \
277 ( eval $$cmd ) >> $@ 2>&1; \ 285 ( eval $$cmd ) >> $@ 2>&1; \
278 echo " test: $(call test,$@)" >> $@ 2>&1; \ 286 echo " test: $(call test,$@)" >> $@ 2>&1; \
279 $(call test,$@) && \ 287 $(call test,$@) && \
@@ -283,8 +291,8 @@ $(run_O):
283 $(call clean) 291 $(call clean)
284 @TMP_O=$$(mktemp -d); \ 292 @TMP_O=$$(mktemp -d); \
285 TMP_DEST=$$(mktemp -d); \ 293 TMP_DEST=$$(mktemp -d); \
286 cmd="cd $(PERF) && make -f $(MK) $(PARALLEL_OPT) O=$$TMP_O DESTDIR=$$TMP_DEST $($(patsubst %_O,%,$@))"; \ 294 cmd="cd $(PERF) && $(MAKE_F) $($(patsubst %_O,%,$@)) $(PARALLEL_OPT) O=$$TMP_O DESTDIR=$$TMP_DEST"; \
287 echo "- $@: $$cmd" && echo $$cmd > $@ && \ 295 printf "%*.*s: %s\n" $(max_width) $(max_width) "$@" "$$cmd" && echo $$cmd > $@ && \
288 ( eval $$cmd ) >> $@ 2>&1 && \ 296 ( eval $$cmd ) >> $@ 2>&1 && \
289 echo " test: $(call test_O,$@)" >> $@ 2>&1; \ 297 echo " test: $(call test_O,$@)" >> $@ 2>&1; \
290 $(call test_O,$@) && \ 298 $(call test_O,$@) && \
@@ -313,11 +321,43 @@ make_kernelsrc_tools:
313 (make -C ../../tools $(PARALLEL_OPT) $(K_O_OPT) perf) > $@ 2>&1 && \ 321 (make -C ../../tools $(PARALLEL_OPT) $(K_O_OPT) perf) > $@ 2>&1 && \
314 test -x $(KERNEL_O)/tools/perf/perf && rm -f $@ || (cat $@ ; false) 322 test -x $(KERNEL_O)/tools/perf/perf && rm -f $@ || (cat $@ ; false)
315 323
324FEATURES_DUMP_FILE := $(FULL_O)/BUILD_TEST_FEATURE_DUMP
325FEATURES_DUMP_FILE_STATIC := $(FULL_O)/BUILD_TEST_FEATURE_DUMP_STATIC
326
316all: $(run) $(run_O) tarpkg make_kernelsrc make_kernelsrc_tools 327all: $(run) $(run_O) tarpkg make_kernelsrc make_kernelsrc_tools
317 @echo OK 328 @echo OK
329 @rm -f $(FEATURES_DUMP_FILE) $(FEATURES_DUMP_FILE_STATIC)
318 330
319out: $(run_O) 331out: $(run_O)
320 @echo OK 332 @echo OK
333 @rm -f $(FEATURES_DUMP_FILE) $(FEATURES_DUMP_FILE_STATIC)
334
335ifeq ($(REUSE_FEATURES_DUMP),1)
336$(FEATURES_DUMP_FILE):
337 $(call clean)
338 @cmd="cd $(PERF) && make FEATURE_DUMP_COPY=$@ $(O_OPT) feature-dump"; \
339 echo "- $@: $$cmd" && echo $$cmd && \
340 ( eval $$cmd ) > /dev/null 2>&1
341
342$(FEATURES_DUMP_FILE_STATIC):
343 $(call clean)
344 @cmd="cd $(PERF) && make FEATURE_DUMP_COPY=$@ $(O_OPT) LDFLAGS='-static' feature-dump"; \
345 echo "- $@: $$cmd" && echo $$cmd && \
346 ( eval $$cmd ) > /dev/null 2>&1
347
348# Add feature dump dependency for run/run_O targets
349$(foreach t,$(run) $(run_O),$(eval \
350 $(t): $(if $(findstring make_static,$(t)),\
351 $(FEATURES_DUMP_FILE_STATIC),\
352 $(FEATURES_DUMP_FILE))))
353
354# Append 'FEATURES_DUMP=' option to all test cases. For example:
355# make_no_libbpf: NO_LIBBPF=1 --> NO_LIBBPF=1 FEATURES_DUMP=/a/b/BUILD_TEST_FEATURE_DUMP
356# make_static: LDFLAGS=-static --> LDFLAGS=-static FEATURES_DUMP=/a/b/BUILD_TEST_FEATURE_DUMP_STATIC
357$(foreach t,$(run),$(if $(findstring make_static,$(t)),\
358 $(eval $(t) := $($(t)) FEATURES_DUMP=$(FEATURES_DUMP_FILE_STATIC)),\
359 $(eval $(t) := $($(t)) FEATURES_DUMP=$(FEATURES_DUMP_FILE))))
360endif
321 361
322.PHONY: all $(run) $(run_O) tarpkg clean make_kernelsrc make_kernelsrc_tools 362.PHONY: all $(run) $(run_O) tarpkg clean make_kernelsrc make_kernelsrc_tools
323endif # ifndef MK 363endif # ifndef MK
diff --git a/tools/perf/tests/parse-events.c b/tools/perf/tests/parse-events.c
index abe8849d1d70..7865f68dc0d8 100644
--- a/tools/perf/tests/parse-events.c
+++ b/tools/perf/tests/parse-events.c
@@ -1271,6 +1271,38 @@ static int test__checkevent_precise_max_modifier(struct perf_evlist *evlist)
1271 return 0; 1271 return 0;
1272} 1272}
1273 1273
1274static int test__checkevent_config_symbol(struct perf_evlist *evlist)
1275{
1276 struct perf_evsel *evsel = perf_evlist__first(evlist);
1277
1278 TEST_ASSERT_VAL("wrong name setting", strcmp(evsel->name, "insn") == 0);
1279 return 0;
1280}
1281
1282static int test__checkevent_config_raw(struct perf_evlist *evlist)
1283{
1284 struct perf_evsel *evsel = perf_evlist__first(evlist);
1285
1286 TEST_ASSERT_VAL("wrong name setting", strcmp(evsel->name, "rawpmu") == 0);
1287 return 0;
1288}
1289
1290static int test__checkevent_config_num(struct perf_evlist *evlist)
1291{
1292 struct perf_evsel *evsel = perf_evlist__first(evlist);
1293
1294 TEST_ASSERT_VAL("wrong name setting", strcmp(evsel->name, "numpmu") == 0);
1295 return 0;
1296}
1297
1298static int test__checkevent_config_cache(struct perf_evlist *evlist)
1299{
1300 struct perf_evsel *evsel = perf_evlist__first(evlist);
1301
1302 TEST_ASSERT_VAL("wrong name setting", strcmp(evsel->name, "cachepmu") == 0);
1303 return 0;
1304}
1305
1274static int count_tracepoints(void) 1306static int count_tracepoints(void)
1275{ 1307{
1276 struct dirent *events_ent; 1308 struct dirent *events_ent;
@@ -1579,6 +1611,26 @@ static struct evlist_test test__events[] = {
1579 .check = test__checkevent_precise_max_modifier, 1611 .check = test__checkevent_precise_max_modifier,
1580 .id = 47, 1612 .id = 47,
1581 }, 1613 },
1614 {
1615 .name = "instructions/name=insn/",
1616 .check = test__checkevent_config_symbol,
1617 .id = 48,
1618 },
1619 {
1620 .name = "r1234/name=rawpmu/",
1621 .check = test__checkevent_config_raw,
1622 .id = 49,
1623 },
1624 {
1625 .name = "4:0x6530160/name=numpmu/",
1626 .check = test__checkevent_config_num,
1627 .id = 50,
1628 },
1629 {
1630 .name = "L1-dcache-misses/name=cachepmu/",
1631 .check = test__checkevent_config_cache,
1632 .id = 51,
1633 },
1582}; 1634};
1583 1635
1584static struct evlist_test test__events_pmu[] = { 1636static struct evlist_test test__events_pmu[] = {
@@ -1666,7 +1718,7 @@ static int test_term(struct terms_test *t)
1666 } 1718 }
1667 1719
1668 ret = t->check(&terms); 1720 ret = t->check(&terms);
1669 parse_events__free_terms(&terms); 1721 parse_events_terms__purge(&terms);
1670 1722
1671 return ret; 1723 return ret;
1672} 1724}
diff --git a/tools/perf/tests/vmlinux-kallsyms.c b/tools/perf/tests/vmlinux-kallsyms.c
index f0bfc9e8fd9f..630b0b409b97 100644
--- a/tools/perf/tests/vmlinux-kallsyms.c
+++ b/tools/perf/tests/vmlinux-kallsyms.c
@@ -110,7 +110,6 @@ int test__vmlinux_matches_kallsyms(int subtest __maybe_unused)
110 */ 110 */
111 for (nd = rb_first(&vmlinux_map->dso->symbols[type]); nd; nd = rb_next(nd)) { 111 for (nd = rb_first(&vmlinux_map->dso->symbols[type]); nd; nd = rb_next(nd)) {
112 struct symbol *pair, *first_pair; 112 struct symbol *pair, *first_pair;
113 bool backwards = true;
114 113
115 sym = rb_entry(nd, struct symbol, rb_node); 114 sym = rb_entry(nd, struct symbol, rb_node);
116 115
@@ -151,27 +150,14 @@ next_pair:
151 continue; 150 continue;
152 151
153 } else { 152 } else {
154 struct rb_node *nnd; 153 pair = machine__find_kernel_symbol_by_name(&kallsyms, type, sym->name, NULL, NULL);
155detour: 154 if (pair) {
156 nnd = backwards ? rb_prev(&pair->rb_node) : 155 if (UM(pair->start) == mem_start)
157 rb_next(&pair->rb_node);
158 if (nnd) {
159 struct symbol *next = rb_entry(nnd, struct symbol, rb_node);
160
161 if (UM(next->start) == mem_start) {
162 pair = next;
163 goto next_pair; 156 goto next_pair;
164 }
165 }
166 157
167 if (backwards) { 158 pr_debug("%#" PRIx64 ": diff name v: %s k: %s\n",
168 backwards = false; 159 mem_start, sym->name, pair->name);
169 pair = first_pair;
170 goto detour;
171 } 160 }
172
173 pr_debug("%#" PRIx64 ": diff name v: %s k: %s\n",
174 mem_start, sym->name, pair->name);
175 } 161 }
176 } else 162 } else
177 pr_debug("%#" PRIx64 ": %s not on kallsyms\n", 163 pr_debug("%#" PRIx64 ": %s not on kallsyms\n",
diff --git a/tools/perf/ui/browser.c b/tools/perf/ui/browser.c
index d37202121689..af68a9d488bf 100644
--- a/tools/perf/ui/browser.c
+++ b/tools/perf/ui/browser.c
@@ -531,8 +531,8 @@ static struct ui_browser_colorset {
531 .bg = "yellow", 531 .bg = "yellow",
532 }, 532 },
533 { 533 {
534 .colorset = HE_COLORSET_CODE, 534 .colorset = HE_COLORSET_JUMP_ARROWS,
535 .name = "code", 535 .name = "jump_arrows",
536 .fg = "blue", 536 .fg = "blue",
537 .bg = "default", 537 .bg = "default",
538 }, 538 },
diff --git a/tools/perf/ui/browser.h b/tools/perf/ui/browser.h
index 01781de59532..be3b70eb5fca 100644
--- a/tools/perf/ui/browser.h
+++ b/tools/perf/ui/browser.h
@@ -7,7 +7,7 @@
7#define HE_COLORSET_MEDIUM 51 7#define HE_COLORSET_MEDIUM 51
8#define HE_COLORSET_NORMAL 52 8#define HE_COLORSET_NORMAL 52
9#define HE_COLORSET_SELECTED 53 9#define HE_COLORSET_SELECTED 53
10#define HE_COLORSET_CODE 54 10#define HE_COLORSET_JUMP_ARROWS 54
11#define HE_COLORSET_ADDR 55 11#define HE_COLORSET_ADDR 55
12#define HE_COLORSET_ROOT 56 12#define HE_COLORSET_ROOT 56
13 13
diff --git a/tools/perf/ui/browsers/annotate.c b/tools/perf/ui/browsers/annotate.c
index 718bd46d47fa..4fc208e82c6f 100644
--- a/tools/perf/ui/browsers/annotate.c
+++ b/tools/perf/ui/browsers/annotate.c
@@ -284,7 +284,7 @@ static void annotate_browser__draw_current_jump(struct ui_browser *browser)
284 to = (u64)btarget->idx; 284 to = (u64)btarget->idx;
285 } 285 }
286 286
287 ui_browser__set_color(browser, HE_COLORSET_CODE); 287 ui_browser__set_color(browser, HE_COLORSET_JUMP_ARROWS);
288 __ui_browser__line_arrow(browser, pcnt_width + 2 + ab->addr_width, 288 __ui_browser__line_arrow(browser, pcnt_width + 2 + ab->addr_width,
289 from, to); 289 from, to);
290} 290}
diff --git a/tools/perf/ui/browsers/hists.c b/tools/perf/ui/browsers/hists.c
index 08c09ad755d2..4b9816555946 100644
--- a/tools/perf/ui/browsers/hists.c
+++ b/tools/perf/ui/browsers/hists.c
@@ -32,6 +32,7 @@ struct hist_browser {
32 bool show_headers; 32 bool show_headers;
33 float min_pcnt; 33 float min_pcnt;
34 u64 nr_non_filtered_entries; 34 u64 nr_non_filtered_entries;
35 u64 nr_hierarchy_entries;
35 u64 nr_callchain_rows; 36 u64 nr_callchain_rows;
36}; 37};
37 38
@@ -58,11 +59,11 @@ static int hist_browser__get_folding(struct hist_browser *browser)
58 59
59 for (nd = rb_first(&hists->entries); 60 for (nd = rb_first(&hists->entries);
60 (nd = hists__filter_entries(nd, browser->min_pcnt)) != NULL; 61 (nd = hists__filter_entries(nd, browser->min_pcnt)) != NULL;
61 nd = rb_next(nd)) { 62 nd = rb_hierarchy_next(nd)) {
62 struct hist_entry *he = 63 struct hist_entry *he =
63 rb_entry(nd, struct hist_entry, rb_node); 64 rb_entry(nd, struct hist_entry, rb_node);
64 65
65 if (he->unfolded) 66 if (he->leaf && he->unfolded)
66 unfolded_rows += he->nr_rows; 67 unfolded_rows += he->nr_rows;
67 } 68 }
68 return unfolded_rows; 69 return unfolded_rows;
@@ -72,7 +73,9 @@ static u32 hist_browser__nr_entries(struct hist_browser *hb)
72{ 73{
73 u32 nr_entries; 74 u32 nr_entries;
74 75
75 if (hist_browser__has_filter(hb)) 76 if (symbol_conf.report_hierarchy)
77 nr_entries = hb->nr_hierarchy_entries;
78 else if (hist_browser__has_filter(hb))
76 nr_entries = hb->nr_non_filtered_entries; 79 nr_entries = hb->nr_non_filtered_entries;
77 else 80 else
78 nr_entries = hb->hists->nr_entries; 81 nr_entries = hb->hists->nr_entries;
@@ -247,6 +250,38 @@ static int callchain__count_rows(struct rb_root *chain)
247 return n; 250 return n;
248} 251}
249 252
253static int hierarchy_count_rows(struct hist_browser *hb, struct hist_entry *he,
254 bool include_children)
255{
256 int count = 0;
257 struct rb_node *node;
258 struct hist_entry *child;
259
260 if (he->leaf)
261 return callchain__count_rows(&he->sorted_chain);
262
263 if (he->has_no_entry)
264 return 1;
265
266 node = rb_first(&he->hroot_out);
267 while (node) {
268 float percent;
269
270 child = rb_entry(node, struct hist_entry, rb_node);
271 percent = hist_entry__get_percent_limit(child);
272
273 if (!child->filtered && percent >= hb->min_pcnt) {
274 count++;
275
276 if (include_children && child->unfolded)
277 count += hierarchy_count_rows(hb, child, true);
278 }
279
280 node = rb_next(node);
281 }
282 return count;
283}
284
250static bool hist_entry__toggle_fold(struct hist_entry *he) 285static bool hist_entry__toggle_fold(struct hist_entry *he)
251{ 286{
252 if (!he) 287 if (!he)
@@ -326,11 +361,17 @@ static void callchain__init_have_children(struct rb_root *root)
326 361
327static void hist_entry__init_have_children(struct hist_entry *he) 362static void hist_entry__init_have_children(struct hist_entry *he)
328{ 363{
329 if (!he->init_have_children) { 364 if (he->init_have_children)
365 return;
366
367 if (he->leaf) {
330 he->has_children = !RB_EMPTY_ROOT(&he->sorted_chain); 368 he->has_children = !RB_EMPTY_ROOT(&he->sorted_chain);
331 callchain__init_have_children(&he->sorted_chain); 369 callchain__init_have_children(&he->sorted_chain);
332 he->init_have_children = true; 370 } else {
371 he->has_children = !RB_EMPTY_ROOT(&he->hroot_out);
333 } 372 }
373
374 he->init_have_children = true;
334} 375}
335 376
336static bool hist_browser__toggle_fold(struct hist_browser *browser) 377static bool hist_browser__toggle_fold(struct hist_browser *browser)
@@ -349,17 +390,49 @@ static bool hist_browser__toggle_fold(struct hist_browser *browser)
349 has_children = callchain_list__toggle_fold(cl); 390 has_children = callchain_list__toggle_fold(cl);
350 391
351 if (has_children) { 392 if (has_children) {
393 int child_rows = 0;
394
352 hist_entry__init_have_children(he); 395 hist_entry__init_have_children(he);
353 browser->b.nr_entries -= he->nr_rows; 396 browser->b.nr_entries -= he->nr_rows;
354 browser->nr_callchain_rows -= he->nr_rows;
355 397
356 if (he->unfolded) 398 if (he->leaf)
357 he->nr_rows = callchain__count_rows(&he->sorted_chain); 399 browser->nr_callchain_rows -= he->nr_rows;
358 else 400 else
401 browser->nr_hierarchy_entries -= he->nr_rows;
402
403 if (symbol_conf.report_hierarchy)
404 child_rows = hierarchy_count_rows(browser, he, true);
405
406 if (he->unfolded) {
407 if (he->leaf)
408 he->nr_rows = callchain__count_rows(&he->sorted_chain);
409 else
410 he->nr_rows = hierarchy_count_rows(browser, he, false);
411
412 /* account grand children */
413 if (symbol_conf.report_hierarchy)
414 browser->b.nr_entries += child_rows - he->nr_rows;
415
416 if (!he->leaf && he->nr_rows == 0) {
417 he->has_no_entry = true;
418 he->nr_rows = 1;
419 }
420 } else {
421 if (symbol_conf.report_hierarchy)
422 browser->b.nr_entries -= child_rows - he->nr_rows;
423
424 if (he->has_no_entry)
425 he->has_no_entry = false;
426
359 he->nr_rows = 0; 427 he->nr_rows = 0;
428 }
360 429
361 browser->b.nr_entries += he->nr_rows; 430 browser->b.nr_entries += he->nr_rows;
362 browser->nr_callchain_rows += he->nr_rows; 431
432 if (he->leaf)
433 browser->nr_callchain_rows += he->nr_rows;
434 else
435 browser->nr_hierarchy_entries += he->nr_rows;
363 436
364 return true; 437 return true;
365 } 438 }
@@ -422,13 +495,38 @@ static int callchain__set_folding(struct rb_root *chain, bool unfold)
422 return n; 495 return n;
423} 496}
424 497
425static void hist_entry__set_folding(struct hist_entry *he, bool unfold) 498static int hierarchy_set_folding(struct hist_browser *hb, struct hist_entry *he,
499 bool unfold __maybe_unused)
500{
501 float percent;
502 struct rb_node *nd;
503 struct hist_entry *child;
504 int n = 0;
505
506 for (nd = rb_first(&he->hroot_out); nd; nd = rb_next(nd)) {
507 child = rb_entry(nd, struct hist_entry, rb_node);
508 percent = hist_entry__get_percent_limit(child);
509 if (!child->filtered && percent >= hb->min_pcnt)
510 n++;
511 }
512
513 return n;
514}
515
516static void hist_entry__set_folding(struct hist_entry *he,
517 struct hist_browser *hb, bool unfold)
426{ 518{
427 hist_entry__init_have_children(he); 519 hist_entry__init_have_children(he);
428 he->unfolded = unfold ? he->has_children : false; 520 he->unfolded = unfold ? he->has_children : false;
429 521
430 if (he->has_children) { 522 if (he->has_children) {
431 int n = callchain__set_folding(&he->sorted_chain, unfold); 523 int n;
524
525 if (he->leaf)
526 n = callchain__set_folding(&he->sorted_chain, unfold);
527 else
528 n = hierarchy_set_folding(hb, he, unfold);
529
432 he->nr_rows = unfold ? n : 0; 530 he->nr_rows = unfold ? n : 0;
433 } else 531 } else
434 he->nr_rows = 0; 532 he->nr_rows = 0;
@@ -438,19 +536,38 @@ static void
438__hist_browser__set_folding(struct hist_browser *browser, bool unfold) 536__hist_browser__set_folding(struct hist_browser *browser, bool unfold)
439{ 537{
440 struct rb_node *nd; 538 struct rb_node *nd;
441 struct hists *hists = browser->hists; 539 struct hist_entry *he;
540 double percent;
442 541
443 for (nd = rb_first(&hists->entries); 542 nd = rb_first(&browser->hists->entries);
444 (nd = hists__filter_entries(nd, browser->min_pcnt)) != NULL; 543 while (nd) {
445 nd = rb_next(nd)) { 544 he = rb_entry(nd, struct hist_entry, rb_node);
446 struct hist_entry *he = rb_entry(nd, struct hist_entry, rb_node); 545
447 hist_entry__set_folding(he, unfold); 546 /* set folding state even if it's currently folded */
448 browser->nr_callchain_rows += he->nr_rows; 547 nd = __rb_hierarchy_next(nd, HMD_FORCE_CHILD);
548
549 hist_entry__set_folding(he, browser, unfold);
550
551 percent = hist_entry__get_percent_limit(he);
552 if (he->filtered || percent < browser->min_pcnt)
553 continue;
554
555 if (!he->depth || unfold)
556 browser->nr_hierarchy_entries++;
557 if (he->leaf)
558 browser->nr_callchain_rows += he->nr_rows;
559 else if (unfold && !hist_entry__has_hierarchy_children(he, browser->min_pcnt)) {
560 browser->nr_hierarchy_entries++;
561 he->has_no_entry = true;
562 he->nr_rows = 1;
563 } else
564 he->has_no_entry = false;
449 } 565 }
450} 566}
451 567
452static void hist_browser__set_folding(struct hist_browser *browser, bool unfold) 568static void hist_browser__set_folding(struct hist_browser *browser, bool unfold)
453{ 569{
570 browser->nr_hierarchy_entries = 0;
454 browser->nr_callchain_rows = 0; 571 browser->nr_callchain_rows = 0;
455 __hist_browser__set_folding(browser, unfold); 572 __hist_browser__set_folding(browser, unfold);
456 573
@@ -657,9 +774,24 @@ static int hist_browser__show_callchain_list(struct hist_browser *browser,
657 return 1; 774 return 1;
658} 775}
659 776
777static bool check_percent_display(struct rb_node *node, u64 parent_total)
778{
779 struct callchain_node *child;
780
781 if (node == NULL)
782 return false;
783
784 if (rb_next(node))
785 return true;
786
787 child = rb_entry(node, struct callchain_node, rb_node);
788 return callchain_cumul_hits(child) != parent_total;
789}
790
660static int hist_browser__show_callchain_flat(struct hist_browser *browser, 791static int hist_browser__show_callchain_flat(struct hist_browser *browser,
661 struct rb_root *root, 792 struct rb_root *root,
662 unsigned short row, u64 total, 793 unsigned short row, u64 total,
794 u64 parent_total,
663 print_callchain_entry_fn print, 795 print_callchain_entry_fn print,
664 struct callchain_print_arg *arg, 796 struct callchain_print_arg *arg,
665 check_output_full_fn is_output_full) 797 check_output_full_fn is_output_full)
@@ -669,7 +801,7 @@ static int hist_browser__show_callchain_flat(struct hist_browser *browser,
669 bool need_percent; 801 bool need_percent;
670 802
671 node = rb_first(root); 803 node = rb_first(root);
672 need_percent = node && rb_next(node); 804 need_percent = check_percent_display(node, parent_total);
673 805
674 while (node) { 806 while (node) {
675 struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node); 807 struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node);
@@ -763,6 +895,7 @@ static char *hist_browser__folded_callchain_str(struct hist_browser *browser,
763static int hist_browser__show_callchain_folded(struct hist_browser *browser, 895static int hist_browser__show_callchain_folded(struct hist_browser *browser,
764 struct rb_root *root, 896 struct rb_root *root,
765 unsigned short row, u64 total, 897 unsigned short row, u64 total,
898 u64 parent_total,
766 print_callchain_entry_fn print, 899 print_callchain_entry_fn print,
767 struct callchain_print_arg *arg, 900 struct callchain_print_arg *arg,
768 check_output_full_fn is_output_full) 901 check_output_full_fn is_output_full)
@@ -772,7 +905,7 @@ static int hist_browser__show_callchain_folded(struct hist_browser *browser,
772 bool need_percent; 905 bool need_percent;
773 906
774 node = rb_first(root); 907 node = rb_first(root);
775 need_percent = node && rb_next(node); 908 need_percent = check_percent_display(node, parent_total);
776 909
777 while (node) { 910 while (node) {
778 struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node); 911 struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node);
@@ -844,20 +977,24 @@ next:
844 return row - first_row; 977 return row - first_row;
845} 978}
846 979
847static int hist_browser__show_callchain(struct hist_browser *browser, 980static int hist_browser__show_callchain_graph(struct hist_browser *browser,
848 struct rb_root *root, int level, 981 struct rb_root *root, int level,
849 unsigned short row, u64 total, 982 unsigned short row, u64 total,
983 u64 parent_total,
850 print_callchain_entry_fn print, 984 print_callchain_entry_fn print,
851 struct callchain_print_arg *arg, 985 struct callchain_print_arg *arg,
852 check_output_full_fn is_output_full) 986 check_output_full_fn is_output_full)
853{ 987{
854 struct rb_node *node; 988 struct rb_node *node;
855 int first_row = row, offset = level * LEVEL_OFFSET_STEP; 989 int first_row = row, offset = level * LEVEL_OFFSET_STEP;
856 u64 new_total;
857 bool need_percent; 990 bool need_percent;
991 u64 percent_total = total;
992
993 if (callchain_param.mode == CHAIN_GRAPH_REL)
994 percent_total = parent_total;
858 995
859 node = rb_first(root); 996 node = rb_first(root);
860 need_percent = node && rb_next(node); 997 need_percent = check_percent_display(node, parent_total);
861 998
862 while (node) { 999 while (node) {
863 struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node); 1000 struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node);
@@ -878,7 +1015,7 @@ static int hist_browser__show_callchain(struct hist_browser *browser,
878 folded_sign = callchain_list__folded(chain); 1015 folded_sign = callchain_list__folded(chain);
879 1016
880 row += hist_browser__show_callchain_list(browser, child, 1017 row += hist_browser__show_callchain_list(browser, child,
881 chain, row, total, 1018 chain, row, percent_total,
882 was_first && need_percent, 1019 was_first && need_percent,
883 offset + extra_offset, 1020 offset + extra_offset,
884 print, arg); 1021 print, arg);
@@ -893,13 +1030,9 @@ static int hist_browser__show_callchain(struct hist_browser *browser,
893 if (folded_sign == '-') { 1030 if (folded_sign == '-') {
894 const int new_level = level + (extra_offset ? 2 : 1); 1031 const int new_level = level + (extra_offset ? 2 : 1);
895 1032
896 if (callchain_param.mode == CHAIN_GRAPH_REL) 1033 row += hist_browser__show_callchain_graph(browser, &child->rb_root,
897 new_total = child->children_hit; 1034 new_level, row, total,
898 else 1035 child->children_hit,
899 new_total = total;
900
901 row += hist_browser__show_callchain(browser, &child->rb_root,
902 new_level, row, new_total,
903 print, arg, is_output_full); 1036 print, arg, is_output_full);
904 } 1037 }
905 if (is_output_full(browser, row)) 1038 if (is_output_full(browser, row))
@@ -910,6 +1043,45 @@ out:
910 return row - first_row; 1043 return row - first_row;
911} 1044}
912 1045
1046static int hist_browser__show_callchain(struct hist_browser *browser,
1047 struct hist_entry *entry, int level,
1048 unsigned short row,
1049 print_callchain_entry_fn print,
1050 struct callchain_print_arg *arg,
1051 check_output_full_fn is_output_full)
1052{
1053 u64 total = hists__total_period(entry->hists);
1054 u64 parent_total;
1055 int printed;
1056
1057 if (symbol_conf.cumulate_callchain)
1058 parent_total = entry->stat_acc->period;
1059 else
1060 parent_total = entry->stat.period;
1061
1062 if (callchain_param.mode == CHAIN_FLAT) {
1063 printed = hist_browser__show_callchain_flat(browser,
1064 &entry->sorted_chain, row,
1065 total, parent_total, print, arg,
1066 is_output_full);
1067 } else if (callchain_param.mode == CHAIN_FOLDED) {
1068 printed = hist_browser__show_callchain_folded(browser,
1069 &entry->sorted_chain, row,
1070 total, parent_total, print, arg,
1071 is_output_full);
1072 } else {
1073 printed = hist_browser__show_callchain_graph(browser,
1074 &entry->sorted_chain, level, row,
1075 total, parent_total, print, arg,
1076 is_output_full);
1077 }
1078
1079 if (arg->is_current_entry)
1080 browser->he_selection = entry;
1081
1082 return printed;
1083}
1084
913struct hpp_arg { 1085struct hpp_arg {
914 struct ui_browser *b; 1086 struct ui_browser *b;
915 char folded_sign; 1087 char folded_sign;
@@ -1006,7 +1178,6 @@ static int hist_browser__show_entry(struct hist_browser *browser,
1006 struct hist_entry *entry, 1178 struct hist_entry *entry,
1007 unsigned short row) 1179 unsigned short row)
1008{ 1180{
1009 char s[256];
1010 int printed = 0; 1181 int printed = 0;
1011 int width = browser->b.width; 1182 int width = browser->b.width;
1012 char folded_sign = ' '; 1183 char folded_sign = ' ';
@@ -1031,16 +1202,18 @@ static int hist_browser__show_entry(struct hist_browser *browser,
1031 .folded_sign = folded_sign, 1202 .folded_sign = folded_sign,
1032 .current_entry = current_entry, 1203 .current_entry = current_entry,
1033 }; 1204 };
1034 struct perf_hpp hpp = {
1035 .buf = s,
1036 .size = sizeof(s),
1037 .ptr = &arg,
1038 };
1039 int column = 0; 1205 int column = 0;
1040 1206
1041 hist_browser__gotorc(browser, row, 0); 1207 hist_browser__gotorc(browser, row, 0);
1042 1208
1043 perf_hpp__for_each_format(fmt) { 1209 hists__for_each_format(browser->hists, fmt) {
1210 char s[2048];
1211 struct perf_hpp hpp = {
1212 .buf = s,
1213 .size = sizeof(s),
1214 .ptr = &arg,
1215 };
1216
1044 if (perf_hpp__should_skip(fmt, entry->hists) || 1217 if (perf_hpp__should_skip(fmt, entry->hists) ||
1045 column++ < browser->b.horiz_scroll) 1218 column++ < browser->b.horiz_scroll)
1046 continue; 1219 continue;
@@ -1065,11 +1238,18 @@ static int hist_browser__show_entry(struct hist_browser *browser,
1065 } 1238 }
1066 1239
1067 if (fmt->color) { 1240 if (fmt->color) {
1068 width -= fmt->color(fmt, &hpp, entry); 1241 int ret = fmt->color(fmt, &hpp, entry);
1242 hist_entry__snprintf_alignment(entry, &hpp, fmt, ret);
1243 /*
1244 * fmt->color() already used ui_browser to
1245 * print the non alignment bits, skip it (+ret):
1246 */
1247 ui_browser__printf(&browser->b, "%s", s + ret);
1069 } else { 1248 } else {
1070 width -= fmt->entry(fmt, &hpp, entry); 1249 hist_entry__snprintf_alignment(entry, &hpp, fmt, fmt->entry(fmt, &hpp, entry));
1071 ui_browser__printf(&browser->b, "%s", s); 1250 ui_browser__printf(&browser->b, "%s", s);
1072 } 1251 }
1252 width -= hpp.buf - s;
1073 } 1253 }
1074 1254
1075 /* The scroll bar isn't being used */ 1255 /* The scroll bar isn't being used */
@@ -1084,43 +1264,246 @@ static int hist_browser__show_entry(struct hist_browser *browser,
1084 --row_offset; 1264 --row_offset;
1085 1265
1086 if (folded_sign == '-' && row != browser->b.rows) { 1266 if (folded_sign == '-' && row != browser->b.rows) {
1087 u64 total = hists__total_period(entry->hists);
1088 struct callchain_print_arg arg = { 1267 struct callchain_print_arg arg = {
1089 .row_offset = row_offset, 1268 .row_offset = row_offset,
1090 .is_current_entry = current_entry, 1269 .is_current_entry = current_entry,
1091 }; 1270 };
1092 1271
1093 if (callchain_param.mode == CHAIN_GRAPH_REL) { 1272 printed += hist_browser__show_callchain(browser, entry, 1, row,
1094 if (symbol_conf.cumulate_callchain)
1095 total = entry->stat_acc->period;
1096 else
1097 total = entry->stat.period;
1098 }
1099
1100 if (callchain_param.mode == CHAIN_FLAT) {
1101 printed += hist_browser__show_callchain_flat(browser,
1102 &entry->sorted_chain, row, total,
1103 hist_browser__show_callchain_entry, &arg,
1104 hist_browser__check_output_full);
1105 } else if (callchain_param.mode == CHAIN_FOLDED) {
1106 printed += hist_browser__show_callchain_folded(browser,
1107 &entry->sorted_chain, row, total,
1108 hist_browser__show_callchain_entry, &arg, 1273 hist_browser__show_callchain_entry, &arg,
1109 hist_browser__check_output_full); 1274 hist_browser__check_output_full);
1275 }
1276
1277 return printed;
1278}
1279
1280static int hist_browser__show_hierarchy_entry(struct hist_browser *browser,
1281 struct hist_entry *entry,
1282 unsigned short row,
1283 int level)
1284{
1285 int printed = 0;
1286 int width = browser->b.width;
1287 char folded_sign = ' ';
1288 bool current_entry = ui_browser__is_current_entry(&browser->b, row);
1289 off_t row_offset = entry->row_offset;
1290 bool first = true;
1291 struct perf_hpp_fmt *fmt;
1292 struct perf_hpp_list_node *fmt_node;
1293 struct hpp_arg arg = {
1294 .b = &browser->b,
1295 .current_entry = current_entry,
1296 };
1297 int column = 0;
1298 int hierarchy_indent = (entry->hists->nr_hpp_node - 2) * HIERARCHY_INDENT;
1299
1300 if (current_entry) {
1301 browser->he_selection = entry;
1302 browser->selection = &entry->ms;
1303 }
1304
1305 hist_entry__init_have_children(entry);
1306 folded_sign = hist_entry__folded(entry);
1307 arg.folded_sign = folded_sign;
1308
1309 if (entry->leaf && row_offset) {
1310 row_offset--;
1311 goto show_callchain;
1312 }
1313
1314 hist_browser__gotorc(browser, row, 0);
1315
1316 if (current_entry && browser->b.navkeypressed)
1317 ui_browser__set_color(&browser->b, HE_COLORSET_SELECTED);
1318 else
1319 ui_browser__set_color(&browser->b, HE_COLORSET_NORMAL);
1320
1321 ui_browser__write_nstring(&browser->b, "", level * HIERARCHY_INDENT);
1322 width -= level * HIERARCHY_INDENT;
1323
1324 /* the first hpp_list_node is for overhead columns */
1325 fmt_node = list_first_entry(&entry->hists->hpp_formats,
1326 struct perf_hpp_list_node, list);
1327 perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) {
1328 char s[2048];
1329 struct perf_hpp hpp = {
1330 .buf = s,
1331 .size = sizeof(s),
1332 .ptr = &arg,
1333 };
1334
1335 if (perf_hpp__should_skip(fmt, entry->hists) ||
1336 column++ < browser->b.horiz_scroll)
1337 continue;
1338
1339 if (current_entry && browser->b.navkeypressed) {
1340 ui_browser__set_color(&browser->b,
1341 HE_COLORSET_SELECTED);
1110 } else { 1342 } else {
1111 printed += hist_browser__show_callchain(browser, 1343 ui_browser__set_color(&browser->b,
1112 &entry->sorted_chain, 1, row, total, 1344 HE_COLORSET_NORMAL);
1113 hist_browser__show_callchain_entry, &arg, 1345 }
1114 hist_browser__check_output_full); 1346
1347 if (first) {
1348 ui_browser__printf(&browser->b, "%c", folded_sign);
1349 width--;
1350 first = false;
1351 } else {
1352 ui_browser__printf(&browser->b, " ");
1353 width -= 2;
1354 }
1355
1356 if (fmt->color) {
1357 int ret = fmt->color(fmt, &hpp, entry);
1358 hist_entry__snprintf_alignment(entry, &hpp, fmt, ret);
1359 /*
1360 * fmt->color() already used ui_browser to
1361 * print the non alignment bits, skip it (+ret):
1362 */
1363 ui_browser__printf(&browser->b, "%s", s + ret);
1364 } else {
1365 int ret = fmt->entry(fmt, &hpp, entry);
1366 hist_entry__snprintf_alignment(entry, &hpp, fmt, ret);
1367 ui_browser__printf(&browser->b, "%s", s);
1368 }
1369 width -= hpp.buf - s;
1370 }
1371
1372 ui_browser__write_nstring(&browser->b, "", hierarchy_indent);
1373 width -= hierarchy_indent;
1374
1375 if (column >= browser->b.horiz_scroll) {
1376 char s[2048];
1377 struct perf_hpp hpp = {
1378 .buf = s,
1379 .size = sizeof(s),
1380 .ptr = &arg,
1381 };
1382
1383 if (current_entry && browser->b.navkeypressed) {
1384 ui_browser__set_color(&browser->b,
1385 HE_COLORSET_SELECTED);
1386 } else {
1387 ui_browser__set_color(&browser->b,
1388 HE_COLORSET_NORMAL);
1115 } 1389 }
1116 1390
1117 if (arg.is_current_entry) 1391 perf_hpp_list__for_each_format(entry->hpp_list, fmt) {
1118 browser->he_selection = entry; 1392 ui_browser__write_nstring(&browser->b, "", 2);
1393 width -= 2;
1394
1395 /*
1396 * No need to call hist_entry__snprintf_alignment()
1397 * since this fmt is always the last column in the
1398 * hierarchy mode.
1399 */
1400 if (fmt->color) {
1401 width -= fmt->color(fmt, &hpp, entry);
1402 } else {
1403 int i = 0;
1404
1405 width -= fmt->entry(fmt, &hpp, entry);
1406 ui_browser__printf(&browser->b, "%s", ltrim(s));
1407
1408 while (isspace(s[i++]))
1409 width++;
1410 }
1411 }
1412 }
1413
1414 /* The scroll bar isn't being used */
1415 if (!browser->b.navkeypressed)
1416 width += 1;
1417
1418 ui_browser__write_nstring(&browser->b, "", width);
1419
1420 ++row;
1421 ++printed;
1422
1423show_callchain:
1424 if (entry->leaf && folded_sign == '-' && row != browser->b.rows) {
1425 struct callchain_print_arg carg = {
1426 .row_offset = row_offset,
1427 };
1428
1429 printed += hist_browser__show_callchain(browser, entry,
1430 level + 1, row,
1431 hist_browser__show_callchain_entry, &carg,
1432 hist_browser__check_output_full);
1119 } 1433 }
1120 1434
1121 return printed; 1435 return printed;
1122} 1436}
1123 1437
1438static int hist_browser__show_no_entry(struct hist_browser *browser,
1439 unsigned short row, int level)
1440{
1441 int width = browser->b.width;
1442 bool current_entry = ui_browser__is_current_entry(&browser->b, row);
1443 bool first = true;
1444 int column = 0;
1445 int ret;
1446 struct perf_hpp_fmt *fmt;
1447 struct perf_hpp_list_node *fmt_node;
1448 int indent = browser->hists->nr_hpp_node - 2;
1449
1450 if (current_entry) {
1451 browser->he_selection = NULL;
1452 browser->selection = NULL;
1453 }
1454
1455 hist_browser__gotorc(browser, row, 0);
1456
1457 if (current_entry && browser->b.navkeypressed)
1458 ui_browser__set_color(&browser->b, HE_COLORSET_SELECTED);
1459 else
1460 ui_browser__set_color(&browser->b, HE_COLORSET_NORMAL);
1461
1462 ui_browser__write_nstring(&browser->b, "", level * HIERARCHY_INDENT);
1463 width -= level * HIERARCHY_INDENT;
1464
1465 /* the first hpp_list_node is for overhead columns */
1466 fmt_node = list_first_entry(&browser->hists->hpp_formats,
1467 struct perf_hpp_list_node, list);
1468 perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) {
1469 if (perf_hpp__should_skip(fmt, browser->hists) ||
1470 column++ < browser->b.horiz_scroll)
1471 continue;
1472
1473 ret = fmt->width(fmt, NULL, hists_to_evsel(browser->hists));
1474
1475 if (first) {
1476 /* for folded sign */
1477 first = false;
1478 ret++;
1479 } else {
1480 /* space between columns */
1481 ret += 2;
1482 }
1483
1484 ui_browser__write_nstring(&browser->b, "", ret);
1485 width -= ret;
1486 }
1487
1488 ui_browser__write_nstring(&browser->b, "", indent * HIERARCHY_INDENT);
1489 width -= indent * HIERARCHY_INDENT;
1490
1491 if (column >= browser->b.horiz_scroll) {
1492 char buf[32];
1493
1494 ret = snprintf(buf, sizeof(buf), "no entry >= %.2f%%", browser->min_pcnt);
1495 ui_browser__printf(&browser->b, " %s", buf);
1496 width -= ret + 2;
1497 }
1498
1499 /* The scroll bar isn't being used */
1500 if (!browser->b.navkeypressed)
1501 width += 1;
1502
1503 ui_browser__write_nstring(&browser->b, "", width);
1504 return 1;
1505}
1506
1124static int advance_hpp_check(struct perf_hpp *hpp, int inc) 1507static int advance_hpp_check(struct perf_hpp *hpp, int inc)
1125{ 1508{
1126 advance_hpp(hpp, inc); 1509 advance_hpp(hpp, inc);
@@ -1144,7 +1527,7 @@ static int hists_browser__scnprintf_headers(struct hist_browser *browser, char *
1144 return ret; 1527 return ret;
1145 } 1528 }
1146 1529
1147 perf_hpp__for_each_format(fmt) { 1530 hists__for_each_format(browser->hists, fmt) {
1148 if (perf_hpp__should_skip(fmt, hists) || column++ < browser->b.horiz_scroll) 1531 if (perf_hpp__should_skip(fmt, hists) || column++ < browser->b.horiz_scroll)
1149 continue; 1532 continue;
1150 1533
@@ -1160,11 +1543,96 @@ static int hists_browser__scnprintf_headers(struct hist_browser *browser, char *
1160 return ret; 1543 return ret;
1161} 1544}
1162 1545
1546static int hists_browser__scnprintf_hierarchy_headers(struct hist_browser *browser, char *buf, size_t size)
1547{
1548 struct hists *hists = browser->hists;
1549 struct perf_hpp dummy_hpp = {
1550 .buf = buf,
1551 .size = size,
1552 };
1553 struct perf_hpp_fmt *fmt;
1554 struct perf_hpp_list_node *fmt_node;
1555 size_t ret = 0;
1556 int column = 0;
1557 int indent = hists->nr_hpp_node - 2;
1558 bool first_node, first_col;
1559
1560 ret = scnprintf(buf, size, " ");
1561 if (advance_hpp_check(&dummy_hpp, ret))
1562 return ret;
1563
1564 /* the first hpp_list_node is for overhead columns */
1565 fmt_node = list_first_entry(&hists->hpp_formats,
1566 struct perf_hpp_list_node, list);
1567 perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) {
1568 if (column++ < browser->b.horiz_scroll)
1569 continue;
1570
1571 ret = fmt->header(fmt, &dummy_hpp, hists_to_evsel(hists));
1572 if (advance_hpp_check(&dummy_hpp, ret))
1573 break;
1574
1575 ret = scnprintf(dummy_hpp.buf, dummy_hpp.size, " ");
1576 if (advance_hpp_check(&dummy_hpp, ret))
1577 break;
1578 }
1579
1580 ret = scnprintf(dummy_hpp.buf, dummy_hpp.size, "%*s",
1581 indent * HIERARCHY_INDENT, "");
1582 if (advance_hpp_check(&dummy_hpp, ret))
1583 return ret;
1584
1585 first_node = true;
1586 list_for_each_entry_continue(fmt_node, &hists->hpp_formats, list) {
1587 if (!first_node) {
1588 ret = scnprintf(dummy_hpp.buf, dummy_hpp.size, " / ");
1589 if (advance_hpp_check(&dummy_hpp, ret))
1590 break;
1591 }
1592 first_node = false;
1593
1594 first_col = true;
1595 perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) {
1596 char *start;
1597
1598 if (perf_hpp__should_skip(fmt, hists))
1599 continue;
1600
1601 if (!first_col) {
1602 ret = scnprintf(dummy_hpp.buf, dummy_hpp.size, "+");
1603 if (advance_hpp_check(&dummy_hpp, ret))
1604 break;
1605 }
1606 first_col = false;
1607
1608 ret = fmt->header(fmt, &dummy_hpp, hists_to_evsel(hists));
1609 dummy_hpp.buf[ret] = '\0';
1610 rtrim(dummy_hpp.buf);
1611
1612 start = ltrim(dummy_hpp.buf);
1613 ret = strlen(start);
1614
1615 if (start != dummy_hpp.buf)
1616 memmove(dummy_hpp.buf, start, ret + 1);
1617
1618 if (advance_hpp_check(&dummy_hpp, ret))
1619 break;
1620 }
1621 }
1622
1623 return ret;
1624}
1625
1163static void hist_browser__show_headers(struct hist_browser *browser) 1626static void hist_browser__show_headers(struct hist_browser *browser)
1164{ 1627{
1165 char headers[1024]; 1628 char headers[1024];
1166 1629
1167 hists_browser__scnprintf_headers(browser, headers, sizeof(headers)); 1630 if (symbol_conf.report_hierarchy)
1631 hists_browser__scnprintf_hierarchy_headers(browser, headers,
1632 sizeof(headers));
1633 else
1634 hists_browser__scnprintf_headers(browser, headers,
1635 sizeof(headers));
1168 ui_browser__gotorc(&browser->b, 0, 0); 1636 ui_browser__gotorc(&browser->b, 0, 0);
1169 ui_browser__set_color(&browser->b, HE_COLORSET_ROOT); 1637 ui_browser__set_color(&browser->b, HE_COLORSET_ROOT);
1170 ui_browser__write_nstring(&browser->b, headers, browser->b.width + 1); 1638 ui_browser__write_nstring(&browser->b, headers, browser->b.width + 1);
@@ -1196,18 +1664,34 @@ static unsigned int hist_browser__refresh(struct ui_browser *browser)
1196 hb->he_selection = NULL; 1664 hb->he_selection = NULL;
1197 hb->selection = NULL; 1665 hb->selection = NULL;
1198 1666
1199 for (nd = browser->top; nd; nd = rb_next(nd)) { 1667 for (nd = browser->top; nd; nd = rb_hierarchy_next(nd)) {
1200 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); 1668 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
1201 float percent; 1669 float percent;
1202 1670
1203 if (h->filtered) 1671 if (h->filtered) {
1672 /* let it move to sibling */
1673 h->unfolded = false;
1204 continue; 1674 continue;
1675 }
1205 1676
1206 percent = hist_entry__get_percent_limit(h); 1677 percent = hist_entry__get_percent_limit(h);
1207 if (percent < hb->min_pcnt) 1678 if (percent < hb->min_pcnt)
1208 continue; 1679 continue;
1209 1680
1210 row += hist_browser__show_entry(hb, h, row); 1681 if (symbol_conf.report_hierarchy) {
1682 row += hist_browser__show_hierarchy_entry(hb, h, row,
1683 h->depth);
1684 if (row == browser->rows)
1685 break;
1686
1687 if (h->has_no_entry) {
1688 hist_browser__show_no_entry(hb, row, h->depth + 1);
1689 row++;
1690 }
1691 } else {
1692 row += hist_browser__show_entry(hb, h, row);
1693 }
1694
1211 if (row == browser->rows) 1695 if (row == browser->rows)
1212 break; 1696 break;
1213 } 1697 }
@@ -1225,7 +1709,14 @@ static struct rb_node *hists__filter_entries(struct rb_node *nd,
1225 if (!h->filtered && percent >= min_pcnt) 1709 if (!h->filtered && percent >= min_pcnt)
1226 return nd; 1710 return nd;
1227 1711
1228 nd = rb_next(nd); 1712 /*
1713 * If it's filtered, its all children also were filtered.
1714 * So move to sibling node.
1715 */
1716 if (rb_next(nd))
1717 nd = rb_next(nd);
1718 else
1719 nd = rb_hierarchy_next(nd);
1229 } 1720 }
1230 1721
1231 return NULL; 1722 return NULL;
@@ -1241,7 +1732,7 @@ static struct rb_node *hists__filter_prev_entries(struct rb_node *nd,
1241 if (!h->filtered && percent >= min_pcnt) 1732 if (!h->filtered && percent >= min_pcnt)
1242 return nd; 1733 return nd;
1243 1734
1244 nd = rb_prev(nd); 1735 nd = rb_hierarchy_prev(nd);
1245 } 1736 }
1246 1737
1247 return NULL; 1738 return NULL;
@@ -1271,8 +1762,8 @@ static void ui_browser__hists_seek(struct ui_browser *browser,
1271 nd = browser->top; 1762 nd = browser->top;
1272 goto do_offset; 1763 goto do_offset;
1273 case SEEK_END: 1764 case SEEK_END:
1274 nd = hists__filter_prev_entries(rb_last(browser->entries), 1765 nd = rb_hierarchy_last(rb_last(browser->entries));
1275 hb->min_pcnt); 1766 nd = hists__filter_prev_entries(nd, hb->min_pcnt);
1276 first = false; 1767 first = false;
1277 break; 1768 break;
1278 default: 1769 default:
@@ -1306,7 +1797,7 @@ do_offset:
1306 if (offset > 0) { 1797 if (offset > 0) {
1307 do { 1798 do {
1308 h = rb_entry(nd, struct hist_entry, rb_node); 1799 h = rb_entry(nd, struct hist_entry, rb_node);
1309 if (h->unfolded) { 1800 if (h->unfolded && h->leaf) {
1310 u16 remaining = h->nr_rows - h->row_offset; 1801 u16 remaining = h->nr_rows - h->row_offset;
1311 if (offset > remaining) { 1802 if (offset > remaining) {
1312 offset -= remaining; 1803 offset -= remaining;
@@ -1318,7 +1809,8 @@ do_offset:
1318 break; 1809 break;
1319 } 1810 }
1320 } 1811 }
1321 nd = hists__filter_entries(rb_next(nd), hb->min_pcnt); 1812 nd = hists__filter_entries(rb_hierarchy_next(nd),
1813 hb->min_pcnt);
1322 if (nd == NULL) 1814 if (nd == NULL)
1323 break; 1815 break;
1324 --offset; 1816 --offset;
@@ -1327,7 +1819,7 @@ do_offset:
1327 } else if (offset < 0) { 1819 } else if (offset < 0) {
1328 while (1) { 1820 while (1) {
1329 h = rb_entry(nd, struct hist_entry, rb_node); 1821 h = rb_entry(nd, struct hist_entry, rb_node);
1330 if (h->unfolded) { 1822 if (h->unfolded && h->leaf) {
1331 if (first) { 1823 if (first) {
1332 if (-offset > h->row_offset) { 1824 if (-offset > h->row_offset) {
1333 offset += h->row_offset; 1825 offset += h->row_offset;
@@ -1351,7 +1843,7 @@ do_offset:
1351 } 1843 }
1352 } 1844 }
1353 1845
1354 nd = hists__filter_prev_entries(rb_prev(nd), 1846 nd = hists__filter_prev_entries(rb_hierarchy_prev(nd),
1355 hb->min_pcnt); 1847 hb->min_pcnt);
1356 if (nd == NULL) 1848 if (nd == NULL)
1357 break; 1849 break;
@@ -1364,7 +1856,7 @@ do_offset:
1364 * row_offset at its last entry. 1856 * row_offset at its last entry.
1365 */ 1857 */
1366 h = rb_entry(nd, struct hist_entry, rb_node); 1858 h = rb_entry(nd, struct hist_entry, rb_node);
1367 if (h->unfolded) 1859 if (h->unfolded && h->leaf)
1368 h->row_offset = h->nr_rows; 1860 h->row_offset = h->nr_rows;
1369 break; 1861 break;
1370 } 1862 }
@@ -1378,17 +1870,14 @@ do_offset:
1378} 1870}
1379 1871
1380static int hist_browser__fprintf_callchain(struct hist_browser *browser, 1872static int hist_browser__fprintf_callchain(struct hist_browser *browser,
1381 struct hist_entry *he, FILE *fp) 1873 struct hist_entry *he, FILE *fp,
1874 int level)
1382{ 1875{
1383 u64 total = hists__total_period(he->hists);
1384 struct callchain_print_arg arg = { 1876 struct callchain_print_arg arg = {
1385 .fp = fp, 1877 .fp = fp,
1386 }; 1878 };
1387 1879
1388 if (symbol_conf.cumulate_callchain) 1880 hist_browser__show_callchain(browser, he, level, 0,
1389 total = he->stat_acc->period;
1390
1391 hist_browser__show_callchain(browser, &he->sorted_chain, 1, 0, total,
1392 hist_browser__fprintf_callchain_entry, &arg, 1881 hist_browser__fprintf_callchain_entry, &arg,
1393 hist_browser__check_dump_full); 1882 hist_browser__check_dump_full);
1394 return arg.printed; 1883 return arg.printed;
@@ -1414,7 +1903,7 @@ static int hist_browser__fprintf_entry(struct hist_browser *browser,
1414 if (symbol_conf.use_callchain) 1903 if (symbol_conf.use_callchain)
1415 printed += fprintf(fp, "%c ", folded_sign); 1904 printed += fprintf(fp, "%c ", folded_sign);
1416 1905
1417 perf_hpp__for_each_format(fmt) { 1906 hists__for_each_format(browser->hists, fmt) {
1418 if (perf_hpp__should_skip(fmt, he->hists)) 1907 if (perf_hpp__should_skip(fmt, he->hists))
1419 continue; 1908 continue;
1420 1909
@@ -1425,12 +1914,71 @@ static int hist_browser__fprintf_entry(struct hist_browser *browser,
1425 first = false; 1914 first = false;
1426 1915
1427 ret = fmt->entry(fmt, &hpp, he); 1916 ret = fmt->entry(fmt, &hpp, he);
1917 ret = hist_entry__snprintf_alignment(he, &hpp, fmt, ret);
1428 advance_hpp(&hpp, ret); 1918 advance_hpp(&hpp, ret);
1429 } 1919 }
1430 printed += fprintf(fp, "%s\n", rtrim(s)); 1920 printed += fprintf(fp, "%s\n", s);
1431 1921
1432 if (folded_sign == '-') 1922 if (folded_sign == '-')
1433 printed += hist_browser__fprintf_callchain(browser, he, fp); 1923 printed += hist_browser__fprintf_callchain(browser, he, fp, 1);
1924
1925 return printed;
1926}
1927
1928
1929static int hist_browser__fprintf_hierarchy_entry(struct hist_browser *browser,
1930 struct hist_entry *he,
1931 FILE *fp, int level)
1932{
1933 char s[8192];
1934 int printed = 0;
1935 char folded_sign = ' ';
1936 struct perf_hpp hpp = {
1937 .buf = s,
1938 .size = sizeof(s),
1939 };
1940 struct perf_hpp_fmt *fmt;
1941 struct perf_hpp_list_node *fmt_node;
1942 bool first = true;
1943 int ret;
1944 int hierarchy_indent = (he->hists->nr_hpp_node - 2) * HIERARCHY_INDENT;
1945
1946 printed = fprintf(fp, "%*s", level * HIERARCHY_INDENT, "");
1947
1948 folded_sign = hist_entry__folded(he);
1949 printed += fprintf(fp, "%c", folded_sign);
1950
1951 /* the first hpp_list_node is for overhead columns */
1952 fmt_node = list_first_entry(&he->hists->hpp_formats,
1953 struct perf_hpp_list_node, list);
1954 perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) {
1955 if (!first) {
1956 ret = scnprintf(hpp.buf, hpp.size, " ");
1957 advance_hpp(&hpp, ret);
1958 } else
1959 first = false;
1960
1961 ret = fmt->entry(fmt, &hpp, he);
1962 advance_hpp(&hpp, ret);
1963 }
1964
1965 ret = scnprintf(hpp.buf, hpp.size, "%*s", hierarchy_indent, "");
1966 advance_hpp(&hpp, ret);
1967
1968 perf_hpp_list__for_each_format(he->hpp_list, fmt) {
1969 ret = scnprintf(hpp.buf, hpp.size, " ");
1970 advance_hpp(&hpp, ret);
1971
1972 ret = fmt->entry(fmt, &hpp, he);
1973 advance_hpp(&hpp, ret);
1974 }
1975
1976 printed += fprintf(fp, "%s\n", rtrim(s));
1977
1978 if (he->leaf && folded_sign == '-') {
1979 printed += hist_browser__fprintf_callchain(browser, he, fp,
1980 he->depth + 1);
1981 }
1434 1982
1435 return printed; 1983 return printed;
1436} 1984}
@@ -1444,8 +1992,16 @@ static int hist_browser__fprintf(struct hist_browser *browser, FILE *fp)
1444 while (nd) { 1992 while (nd) {
1445 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); 1993 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
1446 1994
1447 printed += hist_browser__fprintf_entry(browser, h, fp); 1995 if (symbol_conf.report_hierarchy) {
1448 nd = hists__filter_entries(rb_next(nd), browser->min_pcnt); 1996 printed += hist_browser__fprintf_hierarchy_entry(browser,
1997 h, fp,
1998 h->depth);
1999 } else {
2000 printed += hist_browser__fprintf_entry(browser, h, fp);
2001 }
2002
2003 nd = hists__filter_entries(rb_hierarchy_next(nd),
2004 browser->min_pcnt);
1449 } 2005 }
1450 2006
1451 return printed; 2007 return printed;
@@ -1580,11 +2136,18 @@ static int hists__browser_title(struct hists *hists,
1580 if (hists->uid_filter_str) 2136 if (hists->uid_filter_str)
1581 printed += snprintf(bf + printed, size - printed, 2137 printed += snprintf(bf + printed, size - printed,
1582 ", UID: %s", hists->uid_filter_str); 2138 ", UID: %s", hists->uid_filter_str);
1583 if (thread) 2139 if (thread) {
1584 printed += scnprintf(bf + printed, size - printed, 2140 if (sort__has_thread) {
2141 printed += scnprintf(bf + printed, size - printed,
1585 ", Thread: %s(%d)", 2142 ", Thread: %s(%d)",
1586 (thread->comm_set ? thread__comm_str(thread) : ""), 2143 (thread->comm_set ? thread__comm_str(thread) : ""),
1587 thread->tid); 2144 thread->tid);
2145 } else {
2146 printed += scnprintf(bf + printed, size - printed,
2147 ", Thread: %s",
2148 (thread->comm_set ? thread__comm_str(thread) : ""));
2149 }
2150 }
1588 if (dso) 2151 if (dso)
1589 printed += scnprintf(bf + printed, size - printed, 2152 printed += scnprintf(bf + printed, size - printed,
1590 ", DSO: %s", dso->short_name); 2153 ", DSO: %s", dso->short_name);
@@ -1759,15 +2322,24 @@ do_zoom_thread(struct hist_browser *browser, struct popup_action *act)
1759{ 2322{
1760 struct thread *thread = act->thread; 2323 struct thread *thread = act->thread;
1761 2324
2325 if ((!sort__has_thread && !sort__has_comm) || thread == NULL)
2326 return 0;
2327
1762 if (browser->hists->thread_filter) { 2328 if (browser->hists->thread_filter) {
1763 pstack__remove(browser->pstack, &browser->hists->thread_filter); 2329 pstack__remove(browser->pstack, &browser->hists->thread_filter);
1764 perf_hpp__set_elide(HISTC_THREAD, false); 2330 perf_hpp__set_elide(HISTC_THREAD, false);
1765 thread__zput(browser->hists->thread_filter); 2331 thread__zput(browser->hists->thread_filter);
1766 ui_helpline__pop(); 2332 ui_helpline__pop();
1767 } else { 2333 } else {
1768 ui_helpline__fpush("To zoom out press ESC or ENTER + \"Zoom out of %s(%d) thread\"", 2334 if (sort__has_thread) {
1769 thread->comm_set ? thread__comm_str(thread) : "", 2335 ui_helpline__fpush("To zoom out press ESC or ENTER + \"Zoom out of %s(%d) thread\"",
1770 thread->tid); 2336 thread->comm_set ? thread__comm_str(thread) : "",
2337 thread->tid);
2338 } else {
2339 ui_helpline__fpush("To zoom out press ESC or ENTER + \"Zoom out of %s thread\"",
2340 thread->comm_set ? thread__comm_str(thread) : "");
2341 }
2342
1771 browser->hists->thread_filter = thread__get(thread); 2343 browser->hists->thread_filter = thread__get(thread);
1772 perf_hpp__set_elide(HISTC_THREAD, false); 2344 perf_hpp__set_elide(HISTC_THREAD, false);
1773 pstack__push(browser->pstack, &browser->hists->thread_filter); 2345 pstack__push(browser->pstack, &browser->hists->thread_filter);
@@ -1782,13 +2354,22 @@ static int
1782add_thread_opt(struct hist_browser *browser, struct popup_action *act, 2354add_thread_opt(struct hist_browser *browser, struct popup_action *act,
1783 char **optstr, struct thread *thread) 2355 char **optstr, struct thread *thread)
1784{ 2356{
1785 if (thread == NULL) 2357 int ret;
2358
2359 if ((!sort__has_thread && !sort__has_comm) || thread == NULL)
1786 return 0; 2360 return 0;
1787 2361
1788 if (asprintf(optstr, "Zoom %s %s(%d) thread", 2362 if (sort__has_thread) {
1789 browser->hists->thread_filter ? "out of" : "into", 2363 ret = asprintf(optstr, "Zoom %s %s(%d) thread",
1790 thread->comm_set ? thread__comm_str(thread) : "", 2364 browser->hists->thread_filter ? "out of" : "into",
1791 thread->tid) < 0) 2365 thread->comm_set ? thread__comm_str(thread) : "",
2366 thread->tid);
2367 } else {
2368 ret = asprintf(optstr, "Zoom %s %s thread",
2369 browser->hists->thread_filter ? "out of" : "into",
2370 thread->comm_set ? thread__comm_str(thread) : "");
2371 }
2372 if (ret < 0)
1792 return 0; 2373 return 0;
1793 2374
1794 act->thread = thread; 2375 act->thread = thread;
@@ -1801,6 +2382,9 @@ do_zoom_dso(struct hist_browser *browser, struct popup_action *act)
1801{ 2382{
1802 struct map *map = act->ms.map; 2383 struct map *map = act->ms.map;
1803 2384
2385 if (!sort__has_dso || map == NULL)
2386 return 0;
2387
1804 if (browser->hists->dso_filter) { 2388 if (browser->hists->dso_filter) {
1805 pstack__remove(browser->pstack, &browser->hists->dso_filter); 2389 pstack__remove(browser->pstack, &browser->hists->dso_filter);
1806 perf_hpp__set_elide(HISTC_DSO, false); 2390 perf_hpp__set_elide(HISTC_DSO, false);
@@ -1825,7 +2409,7 @@ static int
1825add_dso_opt(struct hist_browser *browser, struct popup_action *act, 2409add_dso_opt(struct hist_browser *browser, struct popup_action *act,
1826 char **optstr, struct map *map) 2410 char **optstr, struct map *map)
1827{ 2411{
1828 if (map == NULL) 2412 if (!sort__has_dso || map == NULL)
1829 return 0; 2413 return 0;
1830 2414
1831 if (asprintf(optstr, "Zoom %s %s DSO", 2415 if (asprintf(optstr, "Zoom %s %s DSO",
@@ -1850,7 +2434,7 @@ static int
1850add_map_opt(struct hist_browser *browser __maybe_unused, 2434add_map_opt(struct hist_browser *browser __maybe_unused,
1851 struct popup_action *act, char **optstr, struct map *map) 2435 struct popup_action *act, char **optstr, struct map *map)
1852{ 2436{
1853 if (map == NULL) 2437 if (!sort__has_dso || map == NULL)
1854 return 0; 2438 return 0;
1855 2439
1856 if (asprintf(optstr, "Browse map details") < 0) 2440 if (asprintf(optstr, "Browse map details") < 0)
@@ -1952,6 +2536,9 @@ add_exit_opt(struct hist_browser *browser __maybe_unused,
1952static int 2536static int
1953do_zoom_socket(struct hist_browser *browser, struct popup_action *act) 2537do_zoom_socket(struct hist_browser *browser, struct popup_action *act)
1954{ 2538{
2539 if (!sort__has_socket || act->socket < 0)
2540 return 0;
2541
1955 if (browser->hists->socket_filter > -1) { 2542 if (browser->hists->socket_filter > -1) {
1956 pstack__remove(browser->pstack, &browser->hists->socket_filter); 2543 pstack__remove(browser->pstack, &browser->hists->socket_filter);
1957 browser->hists->socket_filter = -1; 2544 browser->hists->socket_filter = -1;
@@ -1971,7 +2558,7 @@ static int
1971add_socket_opt(struct hist_browser *browser, struct popup_action *act, 2558add_socket_opt(struct hist_browser *browser, struct popup_action *act,
1972 char **optstr, int socket_id) 2559 char **optstr, int socket_id)
1973{ 2560{
1974 if (socket_id < 0) 2561 if (!sort__has_socket || socket_id < 0)
1975 return 0; 2562 return 0;
1976 2563
1977 if (asprintf(optstr, "Zoom %s Processor Socket %d", 2564 if (asprintf(optstr, "Zoom %s Processor Socket %d",
@@ -1989,17 +2576,60 @@ static void hist_browser__update_nr_entries(struct hist_browser *hb)
1989 u64 nr_entries = 0; 2576 u64 nr_entries = 0;
1990 struct rb_node *nd = rb_first(&hb->hists->entries); 2577 struct rb_node *nd = rb_first(&hb->hists->entries);
1991 2578
1992 if (hb->min_pcnt == 0) { 2579 if (hb->min_pcnt == 0 && !symbol_conf.report_hierarchy) {
1993 hb->nr_non_filtered_entries = hb->hists->nr_non_filtered_entries; 2580 hb->nr_non_filtered_entries = hb->hists->nr_non_filtered_entries;
1994 return; 2581 return;
1995 } 2582 }
1996 2583
1997 while ((nd = hists__filter_entries(nd, hb->min_pcnt)) != NULL) { 2584 while ((nd = hists__filter_entries(nd, hb->min_pcnt)) != NULL) {
1998 nr_entries++; 2585 nr_entries++;
1999 nd = rb_next(nd); 2586 nd = rb_hierarchy_next(nd);
2000 } 2587 }
2001 2588
2002 hb->nr_non_filtered_entries = nr_entries; 2589 hb->nr_non_filtered_entries = nr_entries;
2590 hb->nr_hierarchy_entries = nr_entries;
2591}
2592
2593static void hist_browser__update_percent_limit(struct hist_browser *hb,
2594 double percent)
2595{
2596 struct hist_entry *he;
2597 struct rb_node *nd = rb_first(&hb->hists->entries);
2598 u64 total = hists__total_period(hb->hists);
2599 u64 min_callchain_hits = total * (percent / 100);
2600
2601 hb->min_pcnt = callchain_param.min_percent = percent;
2602
2603 while ((nd = hists__filter_entries(nd, hb->min_pcnt)) != NULL) {
2604 he = rb_entry(nd, struct hist_entry, rb_node);
2605
2606 if (he->has_no_entry) {
2607 he->has_no_entry = false;
2608 he->nr_rows = 0;
2609 }
2610
2611 if (!he->leaf || !symbol_conf.use_callchain)
2612 goto next;
2613
2614 if (callchain_param.mode == CHAIN_GRAPH_REL) {
2615 total = he->stat.period;
2616
2617 if (symbol_conf.cumulate_callchain)
2618 total = he->stat_acc->period;
2619
2620 min_callchain_hits = total * (percent / 100);
2621 }
2622
2623 callchain_param.sort(&he->sorted_chain, he->callchain,
2624 min_callchain_hits, &callchain_param);
2625
2626next:
2627 nd = __rb_hierarchy_next(nd, HMD_FORCE_CHILD);
2628
2629 /* force to re-evaluate folding state of callchains */
2630 he->init_have_children = false;
2631 hist_entry__set_folding(he, hb, false);
2632 }
2003} 2633}
2004 2634
2005static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events, 2635static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
@@ -2037,6 +2667,7 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
2037 "E Expand all callchains\n" \ 2667 "E Expand all callchains\n" \
2038 "F Toggle percentage of filtered entries\n" \ 2668 "F Toggle percentage of filtered entries\n" \
2039 "H Display column headers\n" \ 2669 "H Display column headers\n" \
2670 "L Change percent limit\n" \
2040 "m Display context menu\n" \ 2671 "m Display context menu\n" \
2041 "S Zoom into current Processor Socket\n" \ 2672 "S Zoom into current Processor Socket\n" \
2042 2673
@@ -2077,7 +2708,7 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
2077 memset(options, 0, sizeof(options)); 2708 memset(options, 0, sizeof(options));
2078 memset(actions, 0, sizeof(actions)); 2709 memset(actions, 0, sizeof(actions));
2079 2710
2080 perf_hpp__for_each_format(fmt) { 2711 hists__for_each_format(browser->hists, fmt) {
2081 perf_hpp__reset_width(fmt, hists); 2712 perf_hpp__reset_width(fmt, hists);
2082 /* 2713 /*
2083 * This is done just once, and activates the horizontal scrolling 2714 * This is done just once, and activates the horizontal scrolling
@@ -2192,6 +2823,24 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
2192 top->zero = !top->zero; 2823 top->zero = !top->zero;
2193 } 2824 }
2194 continue; 2825 continue;
2826 case 'L':
2827 if (ui_browser__input_window("Percent Limit",
2828 "Please enter the value you want to hide entries under that percent.",
2829 buf, "ENTER: OK, ESC: Cancel",
2830 delay_secs * 2) == K_ENTER) {
2831 char *end;
2832 double new_percent = strtod(buf, &end);
2833
2834 if (new_percent < 0 || new_percent > 100) {
2835 ui_browser__warning(&browser->b, delay_secs * 2,
2836 "Invalid percent: %.2f", new_percent);
2837 continue;
2838 }
2839
2840 hist_browser__update_percent_limit(browser, new_percent);
2841 hist_browser__reset(browser);
2842 }
2843 continue;
2195 case K_F1: 2844 case K_F1:
2196 case 'h': 2845 case 'h':
2197 case '?': 2846 case '?':
@@ -2263,10 +2912,7 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
2263 continue; 2912 continue;
2264 } 2913 }
2265 2914
2266 if (!sort__has_sym) 2915 if (!sort__has_sym || browser->selection == NULL)
2267 goto add_exit_option;
2268
2269 if (browser->selection == NULL)
2270 goto skip_annotation; 2916 goto skip_annotation;
2271 2917
2272 if (sort__mode == SORT_MODE__BRANCH) { 2918 if (sort__mode == SORT_MODE__BRANCH) {
@@ -2306,11 +2952,16 @@ skip_annotation:
2306 &options[nr_options], 2952 &options[nr_options],
2307 socked_id); 2953 socked_id);
2308 /* perf script support */ 2954 /* perf script support */
2955 if (!is_report_browser(hbt))
2956 goto skip_scripting;
2957
2309 if (browser->he_selection) { 2958 if (browser->he_selection) {
2310 nr_options += add_script_opt(browser, 2959 if (sort__has_thread && thread) {
2311 &actions[nr_options], 2960 nr_options += add_script_opt(browser,
2312 &options[nr_options], 2961 &actions[nr_options],
2313 thread, NULL); 2962 &options[nr_options],
2963 thread, NULL);
2964 }
2314 /* 2965 /*
2315 * Note that browser->selection != NULL 2966 * Note that browser->selection != NULL
2316 * when browser->he_selection is not NULL, 2967 * when browser->he_selection is not NULL,
@@ -2320,16 +2971,18 @@ skip_annotation:
2320 * 2971 *
2321 * See hist_browser__show_entry. 2972 * See hist_browser__show_entry.
2322 */ 2973 */
2323 nr_options += add_script_opt(browser, 2974 if (sort__has_sym && browser->selection->sym) {
2324 &actions[nr_options], 2975 nr_options += add_script_opt(browser,
2325 &options[nr_options], 2976 &actions[nr_options],
2326 NULL, browser->selection->sym); 2977 &options[nr_options],
2978 NULL, browser->selection->sym);
2979 }
2327 } 2980 }
2328 nr_options += add_script_opt(browser, &actions[nr_options], 2981 nr_options += add_script_opt(browser, &actions[nr_options],
2329 &options[nr_options], NULL, NULL); 2982 &options[nr_options], NULL, NULL);
2330 nr_options += add_switch_opt(browser, &actions[nr_options], 2983 nr_options += add_switch_opt(browser, &actions[nr_options],
2331 &options[nr_options]); 2984 &options[nr_options]);
2332add_exit_option: 2985skip_scripting:
2333 nr_options += add_exit_opt(browser, &actions[nr_options], 2986 nr_options += add_exit_opt(browser, &actions[nr_options],
2334 &options[nr_options]); 2987 &options[nr_options]);
2335 2988
diff --git a/tools/perf/ui/gtk/hists.c b/tools/perf/ui/gtk/hists.c
index 0f8dcfdfb10f..bd9bf7e343b1 100644
--- a/tools/perf/ui/gtk/hists.c
+++ b/tools/perf/ui/gtk/hists.c
@@ -306,7 +306,7 @@ static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists,
306 306
307 nr_cols = 0; 307 nr_cols = 0;
308 308
309 perf_hpp__for_each_format(fmt) 309 hists__for_each_format(hists, fmt)
310 col_types[nr_cols++] = G_TYPE_STRING; 310 col_types[nr_cols++] = G_TYPE_STRING;
311 311
312 store = gtk_tree_store_newv(nr_cols, col_types); 312 store = gtk_tree_store_newv(nr_cols, col_types);
@@ -317,7 +317,7 @@ static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists,
317 317
318 col_idx = 0; 318 col_idx = 0;
319 319
320 perf_hpp__for_each_format(fmt) { 320 hists__for_each_format(hists, fmt) {
321 if (perf_hpp__should_skip(fmt, hists)) 321 if (perf_hpp__should_skip(fmt, hists))
322 continue; 322 continue;
323 323
@@ -367,7 +367,7 @@ static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists,
367 367
368 col_idx = 0; 368 col_idx = 0;
369 369
370 perf_hpp__for_each_format(fmt) { 370 hists__for_each_format(hists, fmt) {
371 if (perf_hpp__should_skip(fmt, h->hists)) 371 if (perf_hpp__should_skip(fmt, h->hists))
372 continue; 372 continue;
373 373
@@ -396,6 +396,194 @@ static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists,
396 gtk_container_add(GTK_CONTAINER(window), view); 396 gtk_container_add(GTK_CONTAINER(window), view);
397} 397}
398 398
399static void perf_gtk__add_hierarchy_entries(struct hists *hists,
400 struct rb_root *root,
401 GtkTreeStore *store,
402 GtkTreeIter *parent,
403 struct perf_hpp *hpp,
404 float min_pcnt)
405{
406 int col_idx = 0;
407 struct rb_node *node;
408 struct hist_entry *he;
409 struct perf_hpp_fmt *fmt;
410 struct perf_hpp_list_node *fmt_node;
411 u64 total = hists__total_period(hists);
412 int size;
413
414 for (node = rb_first(root); node; node = rb_next(node)) {
415 GtkTreeIter iter;
416 float percent;
417 char *bf;
418
419 he = rb_entry(node, struct hist_entry, rb_node);
420 if (he->filtered)
421 continue;
422
423 percent = hist_entry__get_percent_limit(he);
424 if (percent < min_pcnt)
425 continue;
426
427 gtk_tree_store_append(store, &iter, parent);
428
429 col_idx = 0;
430
431 /* the first hpp_list_node is for overhead columns */
432 fmt_node = list_first_entry(&hists->hpp_formats,
433 struct perf_hpp_list_node, list);
434 perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) {
435 if (fmt->color)
436 fmt->color(fmt, hpp, he);
437 else
438 fmt->entry(fmt, hpp, he);
439
440 gtk_tree_store_set(store, &iter, col_idx++, hpp->buf, -1);
441 }
442
443 bf = hpp->buf;
444 size = hpp->size;
445 perf_hpp_list__for_each_format(he->hpp_list, fmt) {
446 int ret;
447
448 if (fmt->color)
449 ret = fmt->color(fmt, hpp, he);
450 else
451 ret = fmt->entry(fmt, hpp, he);
452
453 snprintf(hpp->buf + ret, hpp->size - ret, " ");
454 advance_hpp(hpp, ret + 2);
455 }
456
457 gtk_tree_store_set(store, &iter, col_idx, ltrim(rtrim(bf)), -1);
458
459 if (!he->leaf) {
460 hpp->buf = bf;
461 hpp->size = size;
462
463 perf_gtk__add_hierarchy_entries(hists, &he->hroot_out,
464 store, &iter, hpp,
465 min_pcnt);
466
467 if (!hist_entry__has_hierarchy_children(he, min_pcnt)) {
468 char buf[32];
469 GtkTreeIter child;
470
471 snprintf(buf, sizeof(buf), "no entry >= %.2f%%",
472 min_pcnt);
473
474 gtk_tree_store_append(store, &child, &iter);
475 gtk_tree_store_set(store, &child, col_idx, buf, -1);
476 }
477 }
478
479 if (symbol_conf.use_callchain && he->leaf) {
480 if (callchain_param.mode == CHAIN_GRAPH_REL)
481 total = symbol_conf.cumulate_callchain ?
482 he->stat_acc->period : he->stat.period;
483
484 perf_gtk__add_callchain(&he->sorted_chain, store, &iter,
485 col_idx, total);
486 }
487 }
488
489}
490
491static void perf_gtk__show_hierarchy(GtkWidget *window, struct hists *hists,
492 float min_pcnt)
493{
494 struct perf_hpp_fmt *fmt;
495 struct perf_hpp_list_node *fmt_node;
496 GType col_types[MAX_COLUMNS];
497 GtkCellRenderer *renderer;
498 GtkTreeStore *store;
499 GtkWidget *view;
500 int col_idx;
501 int nr_cols = 0;
502 char s[512];
503 char buf[512];
504 bool first_node, first_col;
505 struct perf_hpp hpp = {
506 .buf = s,
507 .size = sizeof(s),
508 };
509
510 hists__for_each_format(hists, fmt) {
511 if (perf_hpp__is_sort_entry(fmt) ||
512 perf_hpp__is_dynamic_entry(fmt))
513 break;
514
515 col_types[nr_cols++] = G_TYPE_STRING;
516 }
517 col_types[nr_cols++] = G_TYPE_STRING;
518
519 store = gtk_tree_store_newv(nr_cols, col_types);
520 view = gtk_tree_view_new();
521 renderer = gtk_cell_renderer_text_new();
522
523 col_idx = 0;
524
525 /* the first hpp_list_node is for overhead columns */
526 fmt_node = list_first_entry(&hists->hpp_formats,
527 struct perf_hpp_list_node, list);
528 perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) {
529 gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view),
530 -1, fmt->name,
531 renderer, "markup",
532 col_idx++, NULL);
533 }
534
535 /* construct merged column header since sort keys share single column */
536 buf[0] = '\0';
537 first_node = true;
538 list_for_each_entry_continue(fmt_node, &hists->hpp_formats, list) {
539 if (!first_node)
540 strcat(buf, " / ");
541 first_node = false;
542
543 first_col = true;
544 perf_hpp_list__for_each_format(&fmt_node->hpp ,fmt) {
545 if (perf_hpp__should_skip(fmt, hists))
546 continue;
547
548 if (!first_col)
549 strcat(buf, "+");
550 first_col = false;
551
552 fmt->header(fmt, &hpp, hists_to_evsel(hists));
553 strcat(buf, ltrim(rtrim(hpp.buf)));
554 }
555 }
556
557 gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view),
558 -1, buf,
559 renderer, "markup",
560 col_idx++, NULL);
561
562 for (col_idx = 0; col_idx < nr_cols; col_idx++) {
563 GtkTreeViewColumn *column;
564
565 column = gtk_tree_view_get_column(GTK_TREE_VIEW(view), col_idx);
566 gtk_tree_view_column_set_resizable(column, TRUE);
567
568 if (col_idx == 0) {
569 gtk_tree_view_set_expander_column(GTK_TREE_VIEW(view),
570 column);
571 }
572 }
573
574 gtk_tree_view_set_model(GTK_TREE_VIEW(view), GTK_TREE_MODEL(store));
575 g_object_unref(GTK_TREE_MODEL(store));
576
577 perf_gtk__add_hierarchy_entries(hists, &hists->entries, store,
578 NULL, &hpp, min_pcnt);
579
580 gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(view), TRUE);
581
582 g_signal_connect(view, "row-activated",
583 G_CALLBACK(on_row_activated), NULL);
584 gtk_container_add(GTK_CONTAINER(window), view);
585}
586
399int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist, 587int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist,
400 const char *help, 588 const char *help,
401 struct hist_browser_timer *hbt __maybe_unused, 589 struct hist_browser_timer *hbt __maybe_unused,
@@ -463,7 +651,10 @@ int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist,
463 GTK_POLICY_AUTOMATIC, 651 GTK_POLICY_AUTOMATIC,
464 GTK_POLICY_AUTOMATIC); 652 GTK_POLICY_AUTOMATIC);
465 653
466 perf_gtk__show_hists(scrolled_window, hists, min_pcnt); 654 if (symbol_conf.report_hierarchy)
655 perf_gtk__show_hierarchy(scrolled_window, hists, min_pcnt);
656 else
657 perf_gtk__show_hists(scrolled_window, hists, min_pcnt);
467 658
468 tab_label = gtk_label_new(evname); 659 tab_label = gtk_label_new(evname);
469 660
diff --git a/tools/perf/ui/hist.c b/tools/perf/ui/hist.c
index bf2a66e254ea..3baeaa6e71b5 100644
--- a/tools/perf/ui/hist.c
+++ b/tools/perf/ui/hist.c
@@ -5,6 +5,7 @@
5#include "../util/util.h" 5#include "../util/util.h"
6#include "../util/sort.h" 6#include "../util/sort.h"
7#include "../util/evsel.h" 7#include "../util/evsel.h"
8#include "../util/evlist.h"
8 9
9/* hist period print (hpp) functions */ 10/* hist period print (hpp) functions */
10 11
@@ -371,7 +372,20 @@ static int64_t hpp__nop_cmp(struct perf_hpp_fmt *fmt __maybe_unused,
371 return 0; 372 return 0;
372} 373}
373 374
374#define HPP__COLOR_PRINT_FNS(_name, _fn) \ 375static bool perf_hpp__is_hpp_entry(struct perf_hpp_fmt *a)
376{
377 return a->header == hpp__header_fn;
378}
379
380static bool hpp__equal(struct perf_hpp_fmt *a, struct perf_hpp_fmt *b)
381{
382 if (!perf_hpp__is_hpp_entry(a) || !perf_hpp__is_hpp_entry(b))
383 return false;
384
385 return a->idx == b->idx;
386}
387
388#define HPP__COLOR_PRINT_FNS(_name, _fn, _idx) \
375 { \ 389 { \
376 .name = _name, \ 390 .name = _name, \
377 .header = hpp__header_fn, \ 391 .header = hpp__header_fn, \
@@ -381,9 +395,11 @@ static int64_t hpp__nop_cmp(struct perf_hpp_fmt *fmt __maybe_unused,
381 .cmp = hpp__nop_cmp, \ 395 .cmp = hpp__nop_cmp, \
382 .collapse = hpp__nop_cmp, \ 396 .collapse = hpp__nop_cmp, \
383 .sort = hpp__sort_ ## _fn, \ 397 .sort = hpp__sort_ ## _fn, \
398 .idx = PERF_HPP__ ## _idx, \
399 .equal = hpp__equal, \
384 } 400 }
385 401
386#define HPP__COLOR_ACC_PRINT_FNS(_name, _fn) \ 402#define HPP__COLOR_ACC_PRINT_FNS(_name, _fn, _idx) \
387 { \ 403 { \
388 .name = _name, \ 404 .name = _name, \
389 .header = hpp__header_fn, \ 405 .header = hpp__header_fn, \
@@ -393,9 +409,11 @@ static int64_t hpp__nop_cmp(struct perf_hpp_fmt *fmt __maybe_unused,
393 .cmp = hpp__nop_cmp, \ 409 .cmp = hpp__nop_cmp, \
394 .collapse = hpp__nop_cmp, \ 410 .collapse = hpp__nop_cmp, \
395 .sort = hpp__sort_ ## _fn, \ 411 .sort = hpp__sort_ ## _fn, \
412 .idx = PERF_HPP__ ## _idx, \
413 .equal = hpp__equal, \
396 } 414 }
397 415
398#define HPP__PRINT_FNS(_name, _fn) \ 416#define HPP__PRINT_FNS(_name, _fn, _idx) \
399 { \ 417 { \
400 .name = _name, \ 418 .name = _name, \
401 .header = hpp__header_fn, \ 419 .header = hpp__header_fn, \
@@ -404,22 +422,25 @@ static int64_t hpp__nop_cmp(struct perf_hpp_fmt *fmt __maybe_unused,
404 .cmp = hpp__nop_cmp, \ 422 .cmp = hpp__nop_cmp, \
405 .collapse = hpp__nop_cmp, \ 423 .collapse = hpp__nop_cmp, \
406 .sort = hpp__sort_ ## _fn, \ 424 .sort = hpp__sort_ ## _fn, \
425 .idx = PERF_HPP__ ## _idx, \
426 .equal = hpp__equal, \
407 } 427 }
408 428
409struct perf_hpp_fmt perf_hpp__format[] = { 429struct perf_hpp_fmt perf_hpp__format[] = {
410 HPP__COLOR_PRINT_FNS("Overhead", overhead), 430 HPP__COLOR_PRINT_FNS("Overhead", overhead, OVERHEAD),
411 HPP__COLOR_PRINT_FNS("sys", overhead_sys), 431 HPP__COLOR_PRINT_FNS("sys", overhead_sys, OVERHEAD_SYS),
412 HPP__COLOR_PRINT_FNS("usr", overhead_us), 432 HPP__COLOR_PRINT_FNS("usr", overhead_us, OVERHEAD_US),
413 HPP__COLOR_PRINT_FNS("guest sys", overhead_guest_sys), 433 HPP__COLOR_PRINT_FNS("guest sys", overhead_guest_sys, OVERHEAD_GUEST_SYS),
414 HPP__COLOR_PRINT_FNS("guest usr", overhead_guest_us), 434 HPP__COLOR_PRINT_FNS("guest usr", overhead_guest_us, OVERHEAD_GUEST_US),
415 HPP__COLOR_ACC_PRINT_FNS("Children", overhead_acc), 435 HPP__COLOR_ACC_PRINT_FNS("Children", overhead_acc, OVERHEAD_ACC),
416 HPP__PRINT_FNS("Samples", samples), 436 HPP__PRINT_FNS("Samples", samples, SAMPLES),
417 HPP__PRINT_FNS("Period", period) 437 HPP__PRINT_FNS("Period", period, PERIOD)
418}; 438};
419 439
420LIST_HEAD(perf_hpp__list); 440struct perf_hpp_list perf_hpp_list = {
421LIST_HEAD(perf_hpp__sort_list); 441 .fields = LIST_HEAD_INIT(perf_hpp_list.fields),
422 442 .sorts = LIST_HEAD_INIT(perf_hpp_list.sorts),
443};
423 444
424#undef HPP__COLOR_PRINT_FNS 445#undef HPP__COLOR_PRINT_FNS
425#undef HPP__COLOR_ACC_PRINT_FNS 446#undef HPP__COLOR_ACC_PRINT_FNS
@@ -485,63 +506,60 @@ void perf_hpp__init(void)
485 hpp_dimension__add_output(PERF_HPP__PERIOD); 506 hpp_dimension__add_output(PERF_HPP__PERIOD);
486} 507}
487 508
488void perf_hpp__column_register(struct perf_hpp_fmt *format) 509void perf_hpp_list__column_register(struct perf_hpp_list *list,
510 struct perf_hpp_fmt *format)
489{ 511{
490 list_add_tail(&format->list, &perf_hpp__list); 512 list_add_tail(&format->list, &list->fields);
491} 513}
492 514
493void perf_hpp__column_unregister(struct perf_hpp_fmt *format) 515void perf_hpp_list__register_sort_field(struct perf_hpp_list *list,
516 struct perf_hpp_fmt *format)
494{ 517{
495 list_del(&format->list); 518 list_add_tail(&format->sort_list, &list->sorts);
496} 519}
497 520
498void perf_hpp__register_sort_field(struct perf_hpp_fmt *format) 521void perf_hpp__column_unregister(struct perf_hpp_fmt *format)
499{
500 list_add_tail(&format->sort_list, &perf_hpp__sort_list);
501}
502
503void perf_hpp__column_enable(unsigned col)
504{
505 BUG_ON(col >= PERF_HPP__MAX_INDEX);
506 perf_hpp__column_register(&perf_hpp__format[col]);
507}
508
509void perf_hpp__column_disable(unsigned col)
510{ 522{
511 BUG_ON(col >= PERF_HPP__MAX_INDEX); 523 list_del(&format->list);
512 perf_hpp__column_unregister(&perf_hpp__format[col]);
513} 524}
514 525
515void perf_hpp__cancel_cumulate(void) 526void perf_hpp__cancel_cumulate(void)
516{ 527{
528 struct perf_hpp_fmt *fmt, *acc, *ovh, *tmp;
529
517 if (is_strict_order(field_order)) 530 if (is_strict_order(field_order))
518 return; 531 return;
519 532
520 perf_hpp__column_disable(PERF_HPP__OVERHEAD_ACC); 533 ovh = &perf_hpp__format[PERF_HPP__OVERHEAD];
521 perf_hpp__format[PERF_HPP__OVERHEAD].name = "Overhead"; 534 acc = &perf_hpp__format[PERF_HPP__OVERHEAD_ACC];
535
536 perf_hpp_list__for_each_format_safe(&perf_hpp_list, fmt, tmp) {
537 if (acc->equal(acc, fmt)) {
538 perf_hpp__column_unregister(fmt);
539 continue;
540 }
541
542 if (ovh->equal(ovh, fmt))
543 fmt->name = "Overhead";
544 }
522} 545}
523 546
524void perf_hpp__setup_output_field(void) 547static bool fmt_equal(struct perf_hpp_fmt *a, struct perf_hpp_fmt *b)
548{
549 return a->equal && a->equal(a, b);
550}
551
552void perf_hpp__setup_output_field(struct perf_hpp_list *list)
525{ 553{
526 struct perf_hpp_fmt *fmt; 554 struct perf_hpp_fmt *fmt;
527 555
528 /* append sort keys to output field */ 556 /* append sort keys to output field */
529 perf_hpp__for_each_sort_list(fmt) { 557 perf_hpp_list__for_each_sort_list(list, fmt) {
530 if (!list_empty(&fmt->list)) 558 struct perf_hpp_fmt *pos;
531 continue;
532
533 /*
534 * sort entry fields are dynamically created,
535 * so they can share a same sort key even though
536 * the list is empty.
537 */
538 if (perf_hpp__is_sort_entry(fmt)) {
539 struct perf_hpp_fmt *pos;
540 559
541 perf_hpp__for_each_format(pos) { 560 perf_hpp_list__for_each_format(list, pos) {
542 if (perf_hpp__same_sort_entry(pos, fmt)) 561 if (fmt_equal(fmt, pos))
543 goto next; 562 goto next;
544 }
545 } 563 }
546 564
547 perf_hpp__column_register(fmt); 565 perf_hpp__column_register(fmt);
@@ -550,27 +568,17 @@ next:
550 } 568 }
551} 569}
552 570
553void perf_hpp__append_sort_keys(void) 571void perf_hpp__append_sort_keys(struct perf_hpp_list *list)
554{ 572{
555 struct perf_hpp_fmt *fmt; 573 struct perf_hpp_fmt *fmt;
556 574
557 /* append output fields to sort keys */ 575 /* append output fields to sort keys */
558 perf_hpp__for_each_format(fmt) { 576 perf_hpp_list__for_each_format(list, fmt) {
559 if (!list_empty(&fmt->sort_list)) 577 struct perf_hpp_fmt *pos;
560 continue;
561
562 /*
563 * sort entry fields are dynamically created,
564 * so they can share a same sort key even though
565 * the list is empty.
566 */
567 if (perf_hpp__is_sort_entry(fmt)) {
568 struct perf_hpp_fmt *pos;
569 578
570 perf_hpp__for_each_sort_list(pos) { 579 perf_hpp_list__for_each_sort_list(list, pos) {
571 if (perf_hpp__same_sort_entry(pos, fmt)) 580 if (fmt_equal(fmt, pos))
572 goto next; 581 goto next;
573 }
574 } 582 }
575 583
576 perf_hpp__register_sort_field(fmt); 584 perf_hpp__register_sort_field(fmt);
@@ -579,20 +587,29 @@ next:
579 } 587 }
580} 588}
581 589
582void perf_hpp__reset_output_field(void) 590
591static void fmt_free(struct perf_hpp_fmt *fmt)
592{
593 if (fmt->free)
594 fmt->free(fmt);
595}
596
597void perf_hpp__reset_output_field(struct perf_hpp_list *list)
583{ 598{
584 struct perf_hpp_fmt *fmt, *tmp; 599 struct perf_hpp_fmt *fmt, *tmp;
585 600
586 /* reset output fields */ 601 /* reset output fields */
587 perf_hpp__for_each_format_safe(fmt, tmp) { 602 perf_hpp_list__for_each_format_safe(list, fmt, tmp) {
588 list_del_init(&fmt->list); 603 list_del_init(&fmt->list);
589 list_del_init(&fmt->sort_list); 604 list_del_init(&fmt->sort_list);
605 fmt_free(fmt);
590 } 606 }
591 607
592 /* reset sort keys */ 608 /* reset sort keys */
593 perf_hpp__for_each_sort_list_safe(fmt, tmp) { 609 perf_hpp_list__for_each_sort_list_safe(list, fmt, tmp) {
594 list_del_init(&fmt->list); 610 list_del_init(&fmt->list);
595 list_del_init(&fmt->sort_list); 611 list_del_init(&fmt->sort_list);
612 fmt_free(fmt);
596 } 613 }
597} 614}
598 615
@@ -606,7 +623,7 @@ unsigned int hists__sort_list_width(struct hists *hists)
606 bool first = true; 623 bool first = true;
607 struct perf_hpp dummy_hpp; 624 struct perf_hpp dummy_hpp;
608 625
609 perf_hpp__for_each_format(fmt) { 626 hists__for_each_format(hists, fmt) {
610 if (perf_hpp__should_skip(fmt, hists)) 627 if (perf_hpp__should_skip(fmt, hists))
611 continue; 628 continue;
612 629
@@ -624,22 +641,39 @@ unsigned int hists__sort_list_width(struct hists *hists)
624 return ret; 641 return ret;
625} 642}
626 643
627void perf_hpp__reset_width(struct perf_hpp_fmt *fmt, struct hists *hists) 644unsigned int hists__overhead_width(struct hists *hists)
628{ 645{
629 int idx; 646 struct perf_hpp_fmt *fmt;
630 647 int ret = 0;
631 if (perf_hpp__is_sort_entry(fmt)) 648 bool first = true;
632 return perf_hpp__reset_sort_width(fmt, hists); 649 struct perf_hpp dummy_hpp;
633 650
634 for (idx = 0; idx < PERF_HPP__MAX_INDEX; idx++) { 651 hists__for_each_format(hists, fmt) {
635 if (fmt == &perf_hpp__format[idx]) 652 if (perf_hpp__is_sort_entry(fmt) || perf_hpp__is_dynamic_entry(fmt))
636 break; 653 break;
654
655 if (first)
656 first = false;
657 else
658 ret += 2;
659
660 ret += fmt->width(fmt, &dummy_hpp, hists_to_evsel(hists));
637 } 661 }
638 662
639 if (idx == PERF_HPP__MAX_INDEX) 663 return ret;
664}
665
666void perf_hpp__reset_width(struct perf_hpp_fmt *fmt, struct hists *hists)
667{
668 if (perf_hpp__is_sort_entry(fmt))
669 return perf_hpp__reset_sort_width(fmt, hists);
670
671 if (perf_hpp__is_dynamic_entry(fmt))
640 return; 672 return;
641 673
642 switch (idx) { 674 BUG_ON(fmt->idx >= PERF_HPP__MAX_INDEX);
675
676 switch (fmt->idx) {
643 case PERF_HPP__OVERHEAD: 677 case PERF_HPP__OVERHEAD:
644 case PERF_HPP__OVERHEAD_SYS: 678 case PERF_HPP__OVERHEAD_SYS:
645 case PERF_HPP__OVERHEAD_US: 679 case PERF_HPP__OVERHEAD_US:
@@ -667,7 +701,7 @@ void perf_hpp__set_user_width(const char *width_list_str)
667 struct perf_hpp_fmt *fmt; 701 struct perf_hpp_fmt *fmt;
668 const char *ptr = width_list_str; 702 const char *ptr = width_list_str;
669 703
670 perf_hpp__for_each_format(fmt) { 704 perf_hpp_list__for_each_format(&perf_hpp_list, fmt) {
671 char *p; 705 char *p;
672 706
673 int len = strtol(ptr, &p, 10); 707 int len = strtol(ptr, &p, 10);
@@ -679,3 +713,71 @@ void perf_hpp__set_user_width(const char *width_list_str)
679 break; 713 break;
680 } 714 }
681} 715}
716
717static int add_hierarchy_fmt(struct hists *hists, struct perf_hpp_fmt *fmt)
718{
719 struct perf_hpp_list_node *node = NULL;
720 struct perf_hpp_fmt *fmt_copy;
721 bool found = false;
722 bool skip = perf_hpp__should_skip(fmt, hists);
723
724 list_for_each_entry(node, &hists->hpp_formats, list) {
725 if (node->level == fmt->level) {
726 found = true;
727 break;
728 }
729 }
730
731 if (!found) {
732 node = malloc(sizeof(*node));
733 if (node == NULL)
734 return -1;
735
736 node->skip = skip;
737 node->level = fmt->level;
738 perf_hpp_list__init(&node->hpp);
739
740 hists->nr_hpp_node++;
741 list_add_tail(&node->list, &hists->hpp_formats);
742 }
743
744 fmt_copy = perf_hpp_fmt__dup(fmt);
745 if (fmt_copy == NULL)
746 return -1;
747
748 if (!skip)
749 node->skip = false;
750
751 list_add_tail(&fmt_copy->list, &node->hpp.fields);
752 list_add_tail(&fmt_copy->sort_list, &node->hpp.sorts);
753
754 return 0;
755}
756
757int perf_hpp__setup_hists_formats(struct perf_hpp_list *list,
758 struct perf_evlist *evlist)
759{
760 struct perf_evsel *evsel;
761 struct perf_hpp_fmt *fmt;
762 struct hists *hists;
763 int ret;
764
765 if (!symbol_conf.report_hierarchy)
766 return 0;
767
768 evlist__for_each(evlist, evsel) {
769 hists = evsel__hists(evsel);
770
771 perf_hpp_list__for_each_sort_list(list, fmt) {
772 if (perf_hpp__is_dynamic_entry(fmt) &&
773 !perf_hpp__defined_dynamic_entry(fmt, hists))
774 continue;
775
776 ret = add_hierarchy_fmt(hists, fmt);
777 if (ret < 0)
778 return ret;
779 }
780 }
781
782 return 0;
783}
diff --git a/tools/perf/ui/stdio/hist.c b/tools/perf/ui/stdio/hist.c
index 387110d50b00..7aff5acf3265 100644
--- a/tools/perf/ui/stdio/hist.c
+++ b/tools/perf/ui/stdio/hist.c
@@ -165,8 +165,28 @@ static size_t __callchain__fprintf_graph(FILE *fp, struct rb_root *root,
165 return ret; 165 return ret;
166} 166}
167 167
168/*
169 * If have one single callchain root, don't bother printing
170 * its percentage (100 % in fractal mode and the same percentage
171 * than the hist in graph mode). This also avoid one level of column.
172 *
173 * However when percent-limit applied, it's possible that single callchain
174 * node have different (non-100% in fractal mode) percentage.
175 */
176static bool need_percent_display(struct rb_node *node, u64 parent_samples)
177{
178 struct callchain_node *cnode;
179
180 if (rb_next(node))
181 return true;
182
183 cnode = rb_entry(node, struct callchain_node, rb_node);
184 return callchain_cumul_hits(cnode) != parent_samples;
185}
186
168static size_t callchain__fprintf_graph(FILE *fp, struct rb_root *root, 187static size_t callchain__fprintf_graph(FILE *fp, struct rb_root *root,
169 u64 total_samples, int left_margin) 188 u64 total_samples, u64 parent_samples,
189 int left_margin)
170{ 190{
171 struct callchain_node *cnode; 191 struct callchain_node *cnode;
172 struct callchain_list *chain; 192 struct callchain_list *chain;
@@ -177,13 +197,8 @@ static size_t callchain__fprintf_graph(FILE *fp, struct rb_root *root,
177 int ret = 0; 197 int ret = 0;
178 char bf[1024]; 198 char bf[1024];
179 199
180 /*
181 * If have one single callchain root, don't bother printing
182 * its percentage (100 % in fractal mode and the same percentage
183 * than the hist in graph mode). This also avoid one level of column.
184 */
185 node = rb_first(root); 200 node = rb_first(root);
186 if (node && !rb_next(node)) { 201 if (node && !need_percent_display(node, parent_samples)) {
187 cnode = rb_entry(node, struct callchain_node, rb_node); 202 cnode = rb_entry(node, struct callchain_node, rb_node);
188 list_for_each_entry(chain, &cnode->val, list) { 203 list_for_each_entry(chain, &cnode->val, list) {
189 /* 204 /*
@@ -213,9 +228,15 @@ static size_t callchain__fprintf_graph(FILE *fp, struct rb_root *root,
213 root = &cnode->rb_root; 228 root = &cnode->rb_root;
214 } 229 }
215 230
231 if (callchain_param.mode == CHAIN_GRAPH_REL)
232 total_samples = parent_samples;
233
216 ret += __callchain__fprintf_graph(fp, root, total_samples, 234 ret += __callchain__fprintf_graph(fp, root, total_samples,
217 1, 1, left_margin); 235 1, 1, left_margin);
218 ret += fprintf(fp, "\n"); 236 if (ret) {
237 /* do not add a blank line if it printed nothing */
238 ret += fprintf(fp, "\n");
239 }
219 240
220 return ret; 241 return ret;
221} 242}
@@ -323,16 +344,19 @@ static size_t hist_entry_callchain__fprintf(struct hist_entry *he,
323 u64 total_samples, int left_margin, 344 u64 total_samples, int left_margin,
324 FILE *fp) 345 FILE *fp)
325{ 346{
347 u64 parent_samples = he->stat.period;
348
349 if (symbol_conf.cumulate_callchain)
350 parent_samples = he->stat_acc->period;
351
326 switch (callchain_param.mode) { 352 switch (callchain_param.mode) {
327 case CHAIN_GRAPH_REL: 353 case CHAIN_GRAPH_REL:
328 return callchain__fprintf_graph(fp, &he->sorted_chain, 354 return callchain__fprintf_graph(fp, &he->sorted_chain, total_samples,
329 symbol_conf.cumulate_callchain ? 355 parent_samples, left_margin);
330 he->stat_acc->period : he->stat.period,
331 left_margin);
332 break; 356 break;
333 case CHAIN_GRAPH_ABS: 357 case CHAIN_GRAPH_ABS:
334 return callchain__fprintf_graph(fp, &he->sorted_chain, total_samples, 358 return callchain__fprintf_graph(fp, &he->sorted_chain, total_samples,
335 left_margin); 359 parent_samples, left_margin);
336 break; 360 break;
337 case CHAIN_FLAT: 361 case CHAIN_FLAT:
338 return callchain__fprintf_flat(fp, &he->sorted_chain, total_samples); 362 return callchain__fprintf_flat(fp, &he->sorted_chain, total_samples);
@@ -349,45 +373,66 @@ static size_t hist_entry_callchain__fprintf(struct hist_entry *he,
349 return 0; 373 return 0;
350} 374}
351 375
352static size_t hist_entry__callchain_fprintf(struct hist_entry *he, 376static int hist_entry__snprintf(struct hist_entry *he, struct perf_hpp *hpp)
353 struct hists *hists,
354 FILE *fp)
355{ 377{
356 int left_margin = 0; 378 const char *sep = symbol_conf.field_sep;
357 u64 total_period = hists->stats.total_period; 379 struct perf_hpp_fmt *fmt;
380 char *start = hpp->buf;
381 int ret;
382 bool first = true;
358 383
359 if (field_order == NULL && (sort_order == NULL || 384 if (symbol_conf.exclude_other && !he->parent)
360 !prefixcmp(sort_order, "comm"))) { 385 return 0;
361 struct perf_hpp_fmt *fmt;
362 386
363 perf_hpp__for_each_format(fmt) { 387 hists__for_each_format(he->hists, fmt) {
364 if (!perf_hpp__is_sort_entry(fmt)) 388 if (perf_hpp__should_skip(fmt, he->hists))
365 continue; 389 continue;
366 390
367 /* must be 'comm' sort entry */ 391 /*
368 left_margin = fmt->width(fmt, NULL, hists_to_evsel(hists)); 392 * If there's no field_sep, we still need
369 left_margin -= thread__comm_len(he->thread); 393 * to display initial ' '.
370 break; 394 */
371 } 395 if (!sep || !first) {
396 ret = scnprintf(hpp->buf, hpp->size, "%s", sep ?: " ");
397 advance_hpp(hpp, ret);
398 } else
399 first = false;
400
401 if (perf_hpp__use_color() && fmt->color)
402 ret = fmt->color(fmt, hpp, he);
403 else
404 ret = fmt->entry(fmt, hpp, he);
405
406 ret = hist_entry__snprintf_alignment(he, hpp, fmt, ret);
407 advance_hpp(hpp, ret);
372 } 408 }
373 return hist_entry_callchain__fprintf(he, total_period, left_margin, fp); 409
410 return hpp->buf - start;
374} 411}
375 412
376static int hist_entry__snprintf(struct hist_entry *he, struct perf_hpp *hpp) 413static int hist_entry__hierarchy_fprintf(struct hist_entry *he,
414 struct perf_hpp *hpp,
415 struct hists *hists,
416 FILE *fp)
377{ 417{
378 const char *sep = symbol_conf.field_sep; 418 const char *sep = symbol_conf.field_sep;
379 struct perf_hpp_fmt *fmt; 419 struct perf_hpp_fmt *fmt;
380 char *start = hpp->buf; 420 struct perf_hpp_list_node *fmt_node;
381 int ret; 421 char *buf = hpp->buf;
422 size_t size = hpp->size;
423 int ret, printed = 0;
382 bool first = true; 424 bool first = true;
383 425
384 if (symbol_conf.exclude_other && !he->parent) 426 if (symbol_conf.exclude_other && !he->parent)
385 return 0; 427 return 0;
386 428
387 perf_hpp__for_each_format(fmt) { 429 ret = scnprintf(hpp->buf, hpp->size, "%*s", he->depth * HIERARCHY_INDENT, "");
388 if (perf_hpp__should_skip(fmt, he->hists)) 430 advance_hpp(hpp, ret);
389 continue;
390 431
432 /* the first hpp_list_node is for overhead columns */
433 fmt_node = list_first_entry(&hists->hpp_formats,
434 struct perf_hpp_list_node, list);
435 perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) {
391 /* 436 /*
392 * If there's no field_sep, we still need 437 * If there's no field_sep, we still need
393 * to display initial ' '. 438 * to display initial ' '.
@@ -403,10 +448,47 @@ static int hist_entry__snprintf(struct hist_entry *he, struct perf_hpp *hpp)
403 else 448 else
404 ret = fmt->entry(fmt, hpp, he); 449 ret = fmt->entry(fmt, hpp, he);
405 450
451 ret = hist_entry__snprintf_alignment(he, hpp, fmt, ret);
406 advance_hpp(hpp, ret); 452 advance_hpp(hpp, ret);
407 } 453 }
408 454
409 return hpp->buf - start; 455 if (!sep)
456 ret = scnprintf(hpp->buf, hpp->size, "%*s",
457 (hists->nr_hpp_node - 2) * HIERARCHY_INDENT, "");
458 advance_hpp(hpp, ret);
459
460 printed += fprintf(fp, "%s", buf);
461
462 perf_hpp_list__for_each_format(he->hpp_list, fmt) {
463 hpp->buf = buf;
464 hpp->size = size;
465
466 /*
467 * No need to call hist_entry__snprintf_alignment() since this
468 * fmt is always the last column in the hierarchy mode.
469 */
470 if (perf_hpp__use_color() && fmt->color)
471 fmt->color(fmt, hpp, he);
472 else
473 fmt->entry(fmt, hpp, he);
474
475 /*
476 * dynamic entries are right-aligned but we want left-aligned
477 * in the hierarchy mode
478 */
479 printed += fprintf(fp, "%s%s", sep ?: " ", ltrim(buf));
480 }
481 printed += putc('\n', fp);
482
483 if (symbol_conf.use_callchain && he->leaf) {
484 u64 total = hists__total_period(hists);
485
486 printed += hist_entry_callchain__fprintf(he, total, 0, fp);
487 goto out;
488 }
489
490out:
491 return printed;
410} 492}
411 493
412static int hist_entry__fprintf(struct hist_entry *he, size_t size, 494static int hist_entry__fprintf(struct hist_entry *he, size_t size,
@@ -418,24 +500,134 @@ static int hist_entry__fprintf(struct hist_entry *he, size_t size,
418 .buf = bf, 500 .buf = bf,
419 .size = size, 501 .size = size,
420 }; 502 };
503 u64 total_period = hists->stats.total_period;
421 504
422 if (size == 0 || size > bfsz) 505 if (size == 0 || size > bfsz)
423 size = hpp.size = bfsz; 506 size = hpp.size = bfsz;
424 507
508 if (symbol_conf.report_hierarchy)
509 return hist_entry__hierarchy_fprintf(he, &hpp, hists, fp);
510
425 hist_entry__snprintf(he, &hpp); 511 hist_entry__snprintf(he, &hpp);
426 512
427 ret = fprintf(fp, "%s\n", bf); 513 ret = fprintf(fp, "%s\n", bf);
428 514
429 if (symbol_conf.use_callchain) 515 if (symbol_conf.use_callchain)
430 ret += hist_entry__callchain_fprintf(he, hists, fp); 516 ret += hist_entry_callchain__fprintf(he, total_period, 0, fp);
431 517
432 return ret; 518 return ret;
433} 519}
434 520
521static int print_hierarchy_indent(const char *sep, int indent,
522 const char *line, FILE *fp)
523{
524 if (sep != NULL || indent < 2)
525 return 0;
526
527 return fprintf(fp, "%-.*s", (indent - 2) * HIERARCHY_INDENT, line);
528}
529
530static int print_hierarchy_header(struct hists *hists, struct perf_hpp *hpp,
531 const char *sep, FILE *fp)
532{
533 bool first_node, first_col;
534 int indent;
535 int depth;
536 unsigned width = 0;
537 unsigned header_width = 0;
538 struct perf_hpp_fmt *fmt;
539 struct perf_hpp_list_node *fmt_node;
540
541 indent = hists->nr_hpp_node;
542
543 /* preserve max indent depth for column headers */
544 print_hierarchy_indent(sep, indent, spaces, fp);
545
546 /* the first hpp_list_node is for overhead columns */
547 fmt_node = list_first_entry(&hists->hpp_formats,
548 struct perf_hpp_list_node, list);
549
550 perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) {
551 fmt->header(fmt, hpp, hists_to_evsel(hists));
552 fprintf(fp, "%s%s", hpp->buf, sep ?: " ");
553 }
554
555 /* combine sort headers with ' / ' */
556 first_node = true;
557 list_for_each_entry_continue(fmt_node, &hists->hpp_formats, list) {
558 if (!first_node)
559 header_width += fprintf(fp, " / ");
560 first_node = false;
561
562 first_col = true;
563 perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) {
564 if (perf_hpp__should_skip(fmt, hists))
565 continue;
566
567 if (!first_col)
568 header_width += fprintf(fp, "+");
569 first_col = false;
570
571 fmt->header(fmt, hpp, hists_to_evsel(hists));
572 rtrim(hpp->buf);
573
574 header_width += fprintf(fp, "%s", ltrim(hpp->buf));
575 }
576 }
577
578 fprintf(fp, "\n# ");
579
580 /* preserve max indent depth for initial dots */
581 print_hierarchy_indent(sep, indent, dots, fp);
582
583 /* the first hpp_list_node is for overhead columns */
584 fmt_node = list_first_entry(&hists->hpp_formats,
585 struct perf_hpp_list_node, list);
586
587 first_col = true;
588 perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) {
589 if (!first_col)
590 fprintf(fp, "%s", sep ?: "..");
591 first_col = false;
592
593 width = fmt->width(fmt, hpp, hists_to_evsel(hists));
594 fprintf(fp, "%.*s", width, dots);
595 }
596
597 depth = 0;
598 list_for_each_entry_continue(fmt_node, &hists->hpp_formats, list) {
599 first_col = true;
600 width = depth * HIERARCHY_INDENT;
601
602 perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) {
603 if (perf_hpp__should_skip(fmt, hists))
604 continue;
605
606 if (!first_col)
607 width++; /* for '+' sign between column header */
608 first_col = false;
609
610 width += fmt->width(fmt, hpp, hists_to_evsel(hists));
611 }
612
613 if (width > header_width)
614 header_width = width;
615
616 depth++;
617 }
618
619 fprintf(fp, "%s%-.*s", sep ?: " ", header_width, dots);
620
621 fprintf(fp, "\n#\n");
622
623 return 2;
624}
625
435size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows, 626size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows,
436 int max_cols, float min_pcnt, FILE *fp) 627 int max_cols, float min_pcnt, FILE *fp)
437{ 628{
438 struct perf_hpp_fmt *fmt; 629 struct perf_hpp_fmt *fmt;
630 struct perf_hpp_list_node *fmt_node;
439 struct rb_node *nd; 631 struct rb_node *nd;
440 size_t ret = 0; 632 size_t ret = 0;
441 unsigned int width; 633 unsigned int width;
@@ -449,10 +641,11 @@ size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows,
449 bool first = true; 641 bool first = true;
450 size_t linesz; 642 size_t linesz;
451 char *line = NULL; 643 char *line = NULL;
644 unsigned indent;
452 645
453 init_rem_hits(); 646 init_rem_hits();
454 647
455 perf_hpp__for_each_format(fmt) 648 hists__for_each_format(hists, fmt)
456 perf_hpp__reset_width(fmt, hists); 649 perf_hpp__reset_width(fmt, hists);
457 650
458 if (symbol_conf.col_width_list_str) 651 if (symbol_conf.col_width_list_str)
@@ -463,7 +656,16 @@ size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows,
463 656
464 fprintf(fp, "# "); 657 fprintf(fp, "# ");
465 658
466 perf_hpp__for_each_format(fmt) { 659 if (symbol_conf.report_hierarchy) {
660 list_for_each_entry(fmt_node, &hists->hpp_formats, list) {
661 perf_hpp_list__for_each_format(&fmt_node->hpp, fmt)
662 perf_hpp__reset_width(fmt, hists);
663 }
664 nr_rows += print_hierarchy_header(hists, &dummy_hpp, sep, fp);
665 goto print_entries;
666 }
667
668 hists__for_each_format(hists, fmt) {
467 if (perf_hpp__should_skip(fmt, hists)) 669 if (perf_hpp__should_skip(fmt, hists))
468 continue; 670 continue;
469 671
@@ -487,7 +689,7 @@ size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows,
487 689
488 fprintf(fp, "# "); 690 fprintf(fp, "# ");
489 691
490 perf_hpp__for_each_format(fmt) { 692 hists__for_each_format(hists, fmt) {
491 unsigned int i; 693 unsigned int i;
492 694
493 if (perf_hpp__should_skip(fmt, hists)) 695 if (perf_hpp__should_skip(fmt, hists))
@@ -520,7 +722,9 @@ print_entries:
520 goto out; 722 goto out;
521 } 723 }
522 724
523 for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) { 725 indent = hists__overhead_width(hists) + 4;
726
727 for (nd = rb_first(&hists->entries); nd; nd = __rb_hierarchy_next(nd, HMD_FORCE_CHILD)) {
524 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); 728 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
525 float percent; 729 float percent;
526 730
@@ -536,6 +740,20 @@ print_entries:
536 if (max_rows && ++nr_rows >= max_rows) 740 if (max_rows && ++nr_rows >= max_rows)
537 break; 741 break;
538 742
743 /*
744 * If all children are filtered out or percent-limited,
745 * display "no entry >= x.xx%" message.
746 */
747 if (!h->leaf && !hist_entry__has_hierarchy_children(h, min_pcnt)) {
748 int depth = hists->nr_hpp_node + h->depth + 1;
749
750 print_hierarchy_indent(sep, depth, spaces, fp);
751 fprintf(fp, "%*sno entry >= %.2f%%\n", indent, "", min_pcnt);
752
753 if (max_rows && ++nr_rows >= max_rows)
754 break;
755 }
756
539 if (h->ms.map == NULL && verbose > 1) { 757 if (h->ms.map == NULL && verbose > 1) {
540 __map_groups__fprintf_maps(h->thread->mg, 758 __map_groups__fprintf_maps(h->thread->mg,
541 MAP__FUNCTION, fp); 759 MAP__FUNCTION, fp);
diff --git a/tools/perf/util/Build b/tools/perf/util/Build
index 5eec53a3f4ac..eea25e2424e9 100644
--- a/tools/perf/util/Build
+++ b/tools/perf/util/Build
@@ -82,6 +82,7 @@ libperf-y += parse-branch-options.o
82libperf-y += parse-regs-options.o 82libperf-y += parse-regs-options.o
83libperf-y += term.o 83libperf-y += term.o
84libperf-y += help-unknown-cmd.o 84libperf-y += help-unknown-cmd.o
85libperf-y += mem-events.o
85 86
86libperf-$(CONFIG_LIBBPF) += bpf-loader.o 87libperf-$(CONFIG_LIBBPF) += bpf-loader.o
87libperf-$(CONFIG_BPF_PROLOGUE) += bpf-prologue.o 88libperf-$(CONFIG_BPF_PROLOGUE) += bpf-prologue.o
@@ -105,8 +106,17 @@ libperf-y += scripting-engines/
105 106
106libperf-$(CONFIG_ZLIB) += zlib.o 107libperf-$(CONFIG_ZLIB) += zlib.o
107libperf-$(CONFIG_LZMA) += lzma.o 108libperf-$(CONFIG_LZMA) += lzma.o
109libperf-y += demangle-java.o
110
111ifdef CONFIG_JITDUMP
112libperf-$(CONFIG_LIBELF) += jitdump.o
113libperf-$(CONFIG_LIBELF) += genelf.o
114libperf-$(CONFIG_LIBELF) += genelf_debug.o
115endif
108 116
109CFLAGS_config.o += -DETC_PERFCONFIG="BUILD_STR($(ETC_PERFCONFIG_SQ))" 117CFLAGS_config.o += -DETC_PERFCONFIG="BUILD_STR($(ETC_PERFCONFIG_SQ))"
118# avoid compiler warnings in 32-bit mode
119CFLAGS_genelf_debug.o += -Wno-packed
110 120
111$(OUTPUT)util/parse-events-flex.c: util/parse-events.l $(OUTPUT)util/parse-events-bison.c 121$(OUTPUT)util/parse-events-flex.c: util/parse-events.l $(OUTPUT)util/parse-events-bison.c
112 $(call rule_mkdir) 122 $(call rule_mkdir)
diff --git a/tools/perf/util/auxtrace.c b/tools/perf/util/auxtrace.c
index 360fda01f3b0..ec164fe70718 100644
--- a/tools/perf/util/auxtrace.c
+++ b/tools/perf/util/auxtrace.c
@@ -478,10 +478,11 @@ void auxtrace_heap__pop(struct auxtrace_heap *heap)
478 heap_array[last].ordinal); 478 heap_array[last].ordinal);
479} 479}
480 480
481size_t auxtrace_record__info_priv_size(struct auxtrace_record *itr) 481size_t auxtrace_record__info_priv_size(struct auxtrace_record *itr,
482 struct perf_evlist *evlist)
482{ 483{
483 if (itr) 484 if (itr)
484 return itr->info_priv_size(itr); 485 return itr->info_priv_size(itr, evlist);
485 return 0; 486 return 0;
486} 487}
487 488
@@ -852,7 +853,7 @@ int perf_event__synthesize_auxtrace_info(struct auxtrace_record *itr,
852 int err; 853 int err;
853 854
854 pr_debug2("Synthesizing auxtrace information\n"); 855 pr_debug2("Synthesizing auxtrace information\n");
855 priv_size = auxtrace_record__info_priv_size(itr); 856 priv_size = auxtrace_record__info_priv_size(itr, session->evlist);
856 ev = zalloc(sizeof(struct auxtrace_info_event) + priv_size); 857 ev = zalloc(sizeof(struct auxtrace_info_event) + priv_size);
857 if (!ev) 858 if (!ev)
858 return -ENOMEM; 859 return -ENOMEM;
diff --git a/tools/perf/util/auxtrace.h b/tools/perf/util/auxtrace.h
index b86f90db1352..e5a8e2d4f2af 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,
diff --git a/tools/perf/util/bpf-loader.c b/tools/perf/util/bpf-loader.c
index 540a7efa657e..0967ce601931 100644
--- a/tools/perf/util/bpf-loader.c
+++ b/tools/perf/util/bpf-loader.c
@@ -7,6 +7,7 @@
7 7
8#include <linux/bpf.h> 8#include <linux/bpf.h>
9#include <bpf/libbpf.h> 9#include <bpf/libbpf.h>
10#include <bpf/bpf.h>
10#include <linux/err.h> 11#include <linux/err.h>
11#include <linux/string.h> 12#include <linux/string.h>
12#include "perf.h" 13#include "perf.h"
@@ -16,6 +17,7 @@
16#include "llvm-utils.h" 17#include "llvm-utils.h"
17#include "probe-event.h" 18#include "probe-event.h"
18#include "probe-finder.h" // for MAX_PROBES 19#include "probe-finder.h" // for MAX_PROBES
20#include "parse-events.h"
19#include "llvm-utils.h" 21#include "llvm-utils.h"
20 22
21#define DEFINE_PRINT_FN(name, level) \ 23#define DEFINE_PRINT_FN(name, level) \
@@ -108,8 +110,8 @@ void bpf__clear(void)
108} 110}
109 111
110static void 112static void
111bpf_prog_priv__clear(struct bpf_program *prog __maybe_unused, 113clear_prog_priv(struct bpf_program *prog __maybe_unused,
112 void *_priv) 114 void *_priv)
113{ 115{
114 struct bpf_prog_priv *priv = _priv; 116 struct bpf_prog_priv *priv = _priv;
115 117
@@ -337,7 +339,7 @@ config_bpf_program(struct bpf_program *prog)
337 } 339 }
338 pr_debug("bpf: config '%s' is ok\n", config_str); 340 pr_debug("bpf: config '%s' is ok\n", config_str);
339 341
340 err = bpf_program__set_private(prog, priv, bpf_prog_priv__clear); 342 err = bpf_program__set_private(prog, priv, clear_prog_priv);
341 if (err) { 343 if (err) {
342 pr_debug("Failed to set priv for program '%s'\n", config_str); 344 pr_debug("Failed to set priv for program '%s'\n", config_str);
343 goto errout; 345 goto errout;
@@ -739,6 +741,682 @@ int bpf__foreach_tev(struct bpf_object *obj,
739 return 0; 741 return 0;
740} 742}
741 743
744enum bpf_map_op_type {
745 BPF_MAP_OP_SET_VALUE,
746 BPF_MAP_OP_SET_EVSEL,
747};
748
749enum bpf_map_key_type {
750 BPF_MAP_KEY_ALL,
751 BPF_MAP_KEY_RANGES,
752};
753
754struct bpf_map_op {
755 struct list_head list;
756 enum bpf_map_op_type op_type;
757 enum bpf_map_key_type key_type;
758 union {
759 struct parse_events_array array;
760 } k;
761 union {
762 u64 value;
763 struct perf_evsel *evsel;
764 } v;
765};
766
767struct bpf_map_priv {
768 struct list_head ops_list;
769};
770
771static void
772bpf_map_op__delete(struct bpf_map_op *op)
773{
774 if (!list_empty(&op->list))
775 list_del(&op->list);
776 if (op->key_type == BPF_MAP_KEY_RANGES)
777 parse_events__clear_array(&op->k.array);
778 free(op);
779}
780
781static void
782bpf_map_priv__purge(struct bpf_map_priv *priv)
783{
784 struct bpf_map_op *pos, *n;
785
786 list_for_each_entry_safe(pos, n, &priv->ops_list, list) {
787 list_del_init(&pos->list);
788 bpf_map_op__delete(pos);
789 }
790}
791
792static void
793bpf_map_priv__clear(struct bpf_map *map __maybe_unused,
794 void *_priv)
795{
796 struct bpf_map_priv *priv = _priv;
797
798 bpf_map_priv__purge(priv);
799 free(priv);
800}
801
802static int
803bpf_map_op_setkey(struct bpf_map_op *op, struct parse_events_term *term)
804{
805 op->key_type = BPF_MAP_KEY_ALL;
806 if (!term)
807 return 0;
808
809 if (term->array.nr_ranges) {
810 size_t memsz = term->array.nr_ranges *
811 sizeof(op->k.array.ranges[0]);
812
813 op->k.array.ranges = memdup(term->array.ranges, memsz);
814 if (!op->k.array.ranges) {
815 pr_debug("No enough memory to alloc indices for map\n");
816 return -ENOMEM;
817 }
818 op->key_type = BPF_MAP_KEY_RANGES;
819 op->k.array.nr_ranges = term->array.nr_ranges;
820 }
821 return 0;
822}
823
824static struct bpf_map_op *
825bpf_map_op__new(struct parse_events_term *term)
826{
827 struct bpf_map_op *op;
828 int err;
829
830 op = zalloc(sizeof(*op));
831 if (!op) {
832 pr_debug("Failed to alloc bpf_map_op\n");
833 return ERR_PTR(-ENOMEM);
834 }
835 INIT_LIST_HEAD(&op->list);
836
837 err = bpf_map_op_setkey(op, term);
838 if (err) {
839 free(op);
840 return ERR_PTR(err);
841 }
842 return op;
843}
844
845static int
846bpf_map__add_op(struct bpf_map *map, struct bpf_map_op *op)
847{
848 struct bpf_map_priv *priv;
849 const char *map_name;
850 int err;
851
852 map_name = bpf_map__get_name(map);
853 err = bpf_map__get_private(map, (void **)&priv);
854 if (err) {
855 pr_debug("Failed to get private from map %s\n", map_name);
856 return err;
857 }
858
859 if (!priv) {
860 priv = zalloc(sizeof(*priv));
861 if (!priv) {
862 pr_debug("No enough memory to alloc map private\n");
863 return -ENOMEM;
864 }
865 INIT_LIST_HEAD(&priv->ops_list);
866
867 if (bpf_map__set_private(map, priv, bpf_map_priv__clear)) {
868 free(priv);
869 return -BPF_LOADER_ERRNO__INTERNAL;
870 }
871 }
872
873 list_add_tail(&op->list, &priv->ops_list);
874 return 0;
875}
876
877static struct bpf_map_op *
878bpf_map__add_newop(struct bpf_map *map, struct parse_events_term *term)
879{
880 struct bpf_map_op *op;
881 int err;
882
883 op = bpf_map_op__new(term);
884 if (IS_ERR(op))
885 return op;
886
887 err = bpf_map__add_op(map, op);
888 if (err) {
889 bpf_map_op__delete(op);
890 return ERR_PTR(err);
891 }
892 return op;
893}
894
895static int
896__bpf_map__config_value(struct bpf_map *map,
897 struct parse_events_term *term)
898{
899 struct bpf_map_def def;
900 struct bpf_map_op *op;
901 const char *map_name;
902 int err;
903
904 map_name = bpf_map__get_name(map);
905
906 err = bpf_map__get_def(map, &def);
907 if (err) {
908 pr_debug("Unable to get map definition from '%s'\n",
909 map_name);
910 return -BPF_LOADER_ERRNO__INTERNAL;
911 }
912
913 if (def.type != BPF_MAP_TYPE_ARRAY) {
914 pr_debug("Map %s type is not BPF_MAP_TYPE_ARRAY\n",
915 map_name);
916 return -BPF_LOADER_ERRNO__OBJCONF_MAP_TYPE;
917 }
918 if (def.key_size < sizeof(unsigned int)) {
919 pr_debug("Map %s has incorrect key size\n", map_name);
920 return -BPF_LOADER_ERRNO__OBJCONF_MAP_KEYSIZE;
921 }
922 switch (def.value_size) {
923 case 1:
924 case 2:
925 case 4:
926 case 8:
927 break;
928 default:
929 pr_debug("Map %s has incorrect value size\n", map_name);
930 return -BPF_LOADER_ERRNO__OBJCONF_MAP_VALUESIZE;
931 }
932
933 op = bpf_map__add_newop(map, term);
934 if (IS_ERR(op))
935 return PTR_ERR(op);
936 op->op_type = BPF_MAP_OP_SET_VALUE;
937 op->v.value = term->val.num;
938 return 0;
939}
940
941static int
942bpf_map__config_value(struct bpf_map *map,
943 struct parse_events_term *term,
944 struct perf_evlist *evlist __maybe_unused)
945{
946 if (!term->err_val) {
947 pr_debug("Config value not set\n");
948 return -BPF_LOADER_ERRNO__OBJCONF_CONF;
949 }
950
951 if (term->type_val != PARSE_EVENTS__TERM_TYPE_NUM) {
952 pr_debug("ERROR: wrong value type for 'value'\n");
953 return -BPF_LOADER_ERRNO__OBJCONF_MAP_VALUE;
954 }
955
956 return __bpf_map__config_value(map, term);
957}
958
959static int
960__bpf_map__config_event(struct bpf_map *map,
961 struct parse_events_term *term,
962 struct perf_evlist *evlist)
963{
964 struct perf_evsel *evsel;
965 struct bpf_map_def def;
966 struct bpf_map_op *op;
967 const char *map_name;
968 int err;
969
970 map_name = bpf_map__get_name(map);
971 evsel = perf_evlist__find_evsel_by_str(evlist, term->val.str);
972 if (!evsel) {
973 pr_debug("Event (for '%s') '%s' doesn't exist\n",
974 map_name, term->val.str);
975 return -BPF_LOADER_ERRNO__OBJCONF_MAP_NOEVT;
976 }
977
978 err = bpf_map__get_def(map, &def);
979 if (err) {
980 pr_debug("Unable to get map definition from '%s'\n",
981 map_name);
982 return err;
983 }
984
985 /*
986 * No need to check key_size and value_size:
987 * kernel has already checked them.
988 */
989 if (def.type != BPF_MAP_TYPE_PERF_EVENT_ARRAY) {
990 pr_debug("Map %s type is not BPF_MAP_TYPE_PERF_EVENT_ARRAY\n",
991 map_name);
992 return -BPF_LOADER_ERRNO__OBJCONF_MAP_TYPE;
993 }
994
995 op = bpf_map__add_newop(map, term);
996 if (IS_ERR(op))
997 return PTR_ERR(op);
998 op->op_type = BPF_MAP_OP_SET_EVSEL;
999 op->v.evsel = evsel;
1000 return 0;
1001}
1002
1003static int
1004bpf_map__config_event(struct bpf_map *map,
1005 struct parse_events_term *term,
1006 struct perf_evlist *evlist)
1007{
1008 if (!term->err_val) {
1009 pr_debug("Config value not set\n");
1010 return -BPF_LOADER_ERRNO__OBJCONF_CONF;
1011 }
1012
1013 if (term->type_val != PARSE_EVENTS__TERM_TYPE_STR) {
1014 pr_debug("ERROR: wrong value type for 'event'\n");
1015 return -BPF_LOADER_ERRNO__OBJCONF_MAP_VALUE;
1016 }
1017
1018 return __bpf_map__config_event(map, term, evlist);
1019}
1020
1021struct bpf_obj_config__map_func {
1022 const char *config_opt;
1023 int (*config_func)(struct bpf_map *, struct parse_events_term *,
1024 struct perf_evlist *);
1025};
1026
1027struct bpf_obj_config__map_func bpf_obj_config__map_funcs[] = {
1028 {"value", bpf_map__config_value},
1029 {"event", bpf_map__config_event},
1030};
1031
1032static int
1033config_map_indices_range_check(struct parse_events_term *term,
1034 struct bpf_map *map,
1035 const char *map_name)
1036{
1037 struct parse_events_array *array = &term->array;
1038 struct bpf_map_def def;
1039 unsigned int i;
1040 int err;
1041
1042 if (!array->nr_ranges)
1043 return 0;
1044 if (!array->ranges) {
1045 pr_debug("ERROR: map %s: array->nr_ranges is %d but range array is NULL\n",
1046 map_name, (int)array->nr_ranges);
1047 return -BPF_LOADER_ERRNO__INTERNAL;
1048 }
1049
1050 err = bpf_map__get_def(map, &def);
1051 if (err) {
1052 pr_debug("ERROR: Unable to get map definition from '%s'\n",
1053 map_name);
1054 return -BPF_LOADER_ERRNO__INTERNAL;
1055 }
1056
1057 for (i = 0; i < array->nr_ranges; i++) {
1058 unsigned int start = array->ranges[i].start;
1059 size_t length = array->ranges[i].length;
1060 unsigned int idx = start + length - 1;
1061
1062 if (idx >= def.max_entries) {
1063 pr_debug("ERROR: index %d too large\n", idx);
1064 return -BPF_LOADER_ERRNO__OBJCONF_MAP_IDX2BIG;
1065 }
1066 }
1067 return 0;
1068}
1069
1070static int
1071bpf__obj_config_map(struct bpf_object *obj,
1072 struct parse_events_term *term,
1073 struct perf_evlist *evlist,
1074 int *key_scan_pos)
1075{
1076 /* key is "map:<mapname>.<config opt>" */
1077 char *map_name = strdup(term->config + sizeof("map:") - 1);
1078 struct bpf_map *map;
1079 int err = -BPF_LOADER_ERRNO__OBJCONF_OPT;
1080 char *map_opt;
1081 size_t i;
1082
1083 if (!map_name)
1084 return -ENOMEM;
1085
1086 map_opt = strchr(map_name, '.');
1087 if (!map_opt) {
1088 pr_debug("ERROR: Invalid map config: %s\n", map_name);
1089 goto out;
1090 }
1091
1092 *map_opt++ = '\0';
1093 if (*map_opt == '\0') {
1094 pr_debug("ERROR: Invalid map option: %s\n", term->config);
1095 goto out;
1096 }
1097
1098 map = bpf_object__get_map_by_name(obj, map_name);
1099 if (!map) {
1100 pr_debug("ERROR: Map %s doesn't exist\n", map_name);
1101 err = -BPF_LOADER_ERRNO__OBJCONF_MAP_NOTEXIST;
1102 goto out;
1103 }
1104
1105 *key_scan_pos += strlen(map_opt);
1106 err = config_map_indices_range_check(term, map, map_name);
1107 if (err)
1108 goto out;
1109 *key_scan_pos -= strlen(map_opt);
1110
1111 for (i = 0; i < ARRAY_SIZE(bpf_obj_config__map_funcs); i++) {
1112 struct bpf_obj_config__map_func *func =
1113 &bpf_obj_config__map_funcs[i];
1114
1115 if (strcmp(map_opt, func->config_opt) == 0) {
1116 err = func->config_func(map, term, evlist);
1117 goto out;
1118 }
1119 }
1120
1121 pr_debug("ERROR: Invalid map config option '%s'\n", map_opt);
1122 err = -BPF_LOADER_ERRNO__OBJCONF_MAP_OPT;
1123out:
1124 free(map_name);
1125 if (!err)
1126 key_scan_pos += strlen(map_opt);
1127 return err;
1128}
1129
1130int bpf__config_obj(struct bpf_object *obj,
1131 struct parse_events_term *term,
1132 struct perf_evlist *evlist,
1133 int *error_pos)
1134{
1135 int key_scan_pos = 0;
1136 int err;
1137
1138 if (!obj || !term || !term->config)
1139 return -EINVAL;
1140
1141 if (!prefixcmp(term->config, "map:")) {
1142 key_scan_pos = sizeof("map:") - 1;
1143 err = bpf__obj_config_map(obj, term, evlist, &key_scan_pos);
1144 goto out;
1145 }
1146 err = -BPF_LOADER_ERRNO__OBJCONF_OPT;
1147out:
1148 if (error_pos)
1149 *error_pos = key_scan_pos;
1150 return err;
1151
1152}
1153
1154typedef int (*map_config_func_t)(const char *name, int map_fd,
1155 struct bpf_map_def *pdef,
1156 struct bpf_map_op *op,
1157 void *pkey, void *arg);
1158
1159static int
1160foreach_key_array_all(map_config_func_t func,
1161 void *arg, const char *name,
1162 int map_fd, struct bpf_map_def *pdef,
1163 struct bpf_map_op *op)
1164{
1165 unsigned int i;
1166 int err;
1167
1168 for (i = 0; i < pdef->max_entries; i++) {
1169 err = func(name, map_fd, pdef, op, &i, arg);
1170 if (err) {
1171 pr_debug("ERROR: failed to insert value to %s[%u]\n",
1172 name, i);
1173 return err;
1174 }
1175 }
1176 return 0;
1177}
1178
1179static int
1180foreach_key_array_ranges(map_config_func_t func, void *arg,
1181 const char *name, int map_fd,
1182 struct bpf_map_def *pdef,
1183 struct bpf_map_op *op)
1184{
1185 unsigned int i, j;
1186 int err;
1187
1188 for (i = 0; i < op->k.array.nr_ranges; i++) {
1189 unsigned int start = op->k.array.ranges[i].start;
1190 size_t length = op->k.array.ranges[i].length;
1191
1192 for (j = 0; j < length; j++) {
1193 unsigned int idx = start + j;
1194
1195 err = func(name, map_fd, pdef, op, &idx, arg);
1196 if (err) {
1197 pr_debug("ERROR: failed to insert value to %s[%u]\n",
1198 name, idx);
1199 return err;
1200 }
1201 }
1202 }
1203 return 0;
1204}
1205
1206static int
1207bpf_map_config_foreach_key(struct bpf_map *map,
1208 map_config_func_t func,
1209 void *arg)
1210{
1211 int err, map_fd;
1212 const char *name;
1213 struct bpf_map_op *op;
1214 struct bpf_map_def def;
1215 struct bpf_map_priv *priv;
1216
1217 name = bpf_map__get_name(map);
1218
1219 err = bpf_map__get_private(map, (void **)&priv);
1220 if (err) {
1221 pr_debug("ERROR: failed to get private from map %s\n", name);
1222 return -BPF_LOADER_ERRNO__INTERNAL;
1223 }
1224 if (!priv || list_empty(&priv->ops_list)) {
1225 pr_debug("INFO: nothing to config for map %s\n", name);
1226 return 0;
1227 }
1228
1229 err = bpf_map__get_def(map, &def);
1230 if (err) {
1231 pr_debug("ERROR: failed to get definition from map %s\n", name);
1232 return -BPF_LOADER_ERRNO__INTERNAL;
1233 }
1234 map_fd = bpf_map__get_fd(map);
1235 if (map_fd < 0) {
1236 pr_debug("ERROR: failed to get fd from map %s\n", name);
1237 return map_fd;
1238 }
1239
1240 list_for_each_entry(op, &priv->ops_list, list) {
1241 switch (def.type) {
1242 case BPF_MAP_TYPE_ARRAY:
1243 case BPF_MAP_TYPE_PERF_EVENT_ARRAY:
1244 switch (op->key_type) {
1245 case BPF_MAP_KEY_ALL:
1246 err = foreach_key_array_all(func, arg, name,
1247 map_fd, &def, op);
1248 break;
1249 case BPF_MAP_KEY_RANGES:
1250 err = foreach_key_array_ranges(func, arg, name,
1251 map_fd, &def,
1252 op);
1253 break;
1254 default:
1255 pr_debug("ERROR: keytype for map '%s' invalid\n",
1256 name);
1257 return -BPF_LOADER_ERRNO__INTERNAL;
1258 }
1259 if (err)
1260 return err;
1261 break;
1262 default:
1263 pr_debug("ERROR: type of '%s' incorrect\n", name);
1264 return -BPF_LOADER_ERRNO__OBJCONF_MAP_TYPE;
1265 }
1266 }
1267
1268 return 0;
1269}
1270
1271static int
1272apply_config_value_for_key(int map_fd, void *pkey,
1273 size_t val_size, u64 val)
1274{
1275 int err = 0;
1276
1277 switch (val_size) {
1278 case 1: {
1279 u8 _val = (u8)(val);
1280 err = bpf_map_update_elem(map_fd, pkey, &_val, BPF_ANY);
1281 break;
1282 }
1283 case 2: {
1284 u16 _val = (u16)(val);
1285 err = bpf_map_update_elem(map_fd, pkey, &_val, BPF_ANY);
1286 break;
1287 }
1288 case 4: {
1289 u32 _val = (u32)(val);
1290 err = bpf_map_update_elem(map_fd, pkey, &_val, BPF_ANY);
1291 break;
1292 }
1293 case 8: {
1294 err = bpf_map_update_elem(map_fd, pkey, &val, BPF_ANY);
1295 break;
1296 }
1297 default:
1298 pr_debug("ERROR: invalid value size\n");
1299 return -BPF_LOADER_ERRNO__OBJCONF_MAP_VALUESIZE;
1300 }
1301 if (err && errno)
1302 err = -errno;
1303 return err;
1304}
1305
1306static int
1307apply_config_evsel_for_key(const char *name, int map_fd, void *pkey,
1308 struct perf_evsel *evsel)
1309{
1310 struct xyarray *xy = evsel->fd;
1311 struct perf_event_attr *attr;
1312 unsigned int key, events;
1313 bool check_pass = false;
1314 int *evt_fd;
1315 int err;
1316
1317 if (!xy) {
1318 pr_debug("ERROR: evsel not ready for map %s\n", name);
1319 return -BPF_LOADER_ERRNO__INTERNAL;
1320 }
1321
1322 if (xy->row_size / xy->entry_size != 1) {
1323 pr_debug("ERROR: Dimension of target event is incorrect for map %s\n",
1324 name);
1325 return -BPF_LOADER_ERRNO__OBJCONF_MAP_EVTDIM;
1326 }
1327
1328 attr = &evsel->attr;
1329 if (attr->inherit) {
1330 pr_debug("ERROR: Can't put inherit event into map %s\n", name);
1331 return -BPF_LOADER_ERRNO__OBJCONF_MAP_EVTINH;
1332 }
1333
1334 if (perf_evsel__is_bpf_output(evsel))
1335 check_pass = true;
1336 if (attr->type == PERF_TYPE_RAW)
1337 check_pass = true;
1338 if (attr->type == PERF_TYPE_HARDWARE)
1339 check_pass = true;
1340 if (!check_pass) {
1341 pr_debug("ERROR: Event type is wrong for map %s\n", name);
1342 return -BPF_LOADER_ERRNO__OBJCONF_MAP_EVTTYPE;
1343 }
1344
1345 events = xy->entries / (xy->row_size / xy->entry_size);
1346 key = *((unsigned int *)pkey);
1347 if (key >= events) {
1348 pr_debug("ERROR: there is no event %d for map %s\n",
1349 key, name);
1350 return -BPF_LOADER_ERRNO__OBJCONF_MAP_MAPSIZE;
1351 }
1352 evt_fd = xyarray__entry(xy, key, 0);
1353 err = bpf_map_update_elem(map_fd, pkey, evt_fd, BPF_ANY);
1354 if (err && errno)
1355 err = -errno;
1356 return err;
1357}
1358
1359static int
1360apply_obj_config_map_for_key(const char *name, int map_fd,
1361 struct bpf_map_def *pdef __maybe_unused,
1362 struct bpf_map_op *op,
1363 void *pkey, void *arg __maybe_unused)
1364{
1365 int err;
1366
1367 switch (op->op_type) {
1368 case BPF_MAP_OP_SET_VALUE:
1369 err = apply_config_value_for_key(map_fd, pkey,
1370 pdef->value_size,
1371 op->v.value);
1372 break;
1373 case BPF_MAP_OP_SET_EVSEL:
1374 err = apply_config_evsel_for_key(name, map_fd, pkey,
1375 op->v.evsel);
1376 break;
1377 default:
1378 pr_debug("ERROR: unknown value type for '%s'\n", name);
1379 err = -BPF_LOADER_ERRNO__INTERNAL;
1380 }
1381 return err;
1382}
1383
1384static int
1385apply_obj_config_map(struct bpf_map *map)
1386{
1387 return bpf_map_config_foreach_key(map,
1388 apply_obj_config_map_for_key,
1389 NULL);
1390}
1391
1392static int
1393apply_obj_config_object(struct bpf_object *obj)
1394{
1395 struct bpf_map *map;
1396 int err;
1397
1398 bpf_map__for_each(map, obj) {
1399 err = apply_obj_config_map(map);
1400 if (err)
1401 return err;
1402 }
1403 return 0;
1404}
1405
1406int bpf__apply_obj_config(void)
1407{
1408 struct bpf_object *obj, *tmp;
1409 int err;
1410
1411 bpf_object__for_each_safe(obj, tmp) {
1412 err = apply_obj_config_object(obj);
1413 if (err)
1414 return err;
1415 }
1416
1417 return 0;
1418}
1419
742#define ERRNO_OFFSET(e) ((e) - __BPF_LOADER_ERRNO__START) 1420#define ERRNO_OFFSET(e) ((e) - __BPF_LOADER_ERRNO__START)
743#define ERRCODE_OFFSET(c) ERRNO_OFFSET(BPF_LOADER_ERRNO__##c) 1421#define ERRCODE_OFFSET(c) ERRNO_OFFSET(BPF_LOADER_ERRNO__##c)
744#define NR_ERRNO (__BPF_LOADER_ERRNO__END - __BPF_LOADER_ERRNO__START) 1422#define NR_ERRNO (__BPF_LOADER_ERRNO__END - __BPF_LOADER_ERRNO__START)
@@ -753,6 +1431,20 @@ static const char *bpf_loader_strerror_table[NR_ERRNO] = {
753 [ERRCODE_OFFSET(PROLOGUE)] = "Failed to generate prologue", 1431 [ERRCODE_OFFSET(PROLOGUE)] = "Failed to generate prologue",
754 [ERRCODE_OFFSET(PROLOGUE2BIG)] = "Prologue too big for program", 1432 [ERRCODE_OFFSET(PROLOGUE2BIG)] = "Prologue too big for program",
755 [ERRCODE_OFFSET(PROLOGUEOOB)] = "Offset out of bound for prologue", 1433 [ERRCODE_OFFSET(PROLOGUEOOB)] = "Offset out of bound for prologue",
1434 [ERRCODE_OFFSET(OBJCONF_OPT)] = "Invalid object config option",
1435 [ERRCODE_OFFSET(OBJCONF_CONF)] = "Config value not set (missing '=')",
1436 [ERRCODE_OFFSET(OBJCONF_MAP_OPT)] = "Invalid object map config option",
1437 [ERRCODE_OFFSET(OBJCONF_MAP_NOTEXIST)] = "Target map doesn't exist",
1438 [ERRCODE_OFFSET(OBJCONF_MAP_VALUE)] = "Incorrect value type for map",
1439 [ERRCODE_OFFSET(OBJCONF_MAP_TYPE)] = "Incorrect map type",
1440 [ERRCODE_OFFSET(OBJCONF_MAP_KEYSIZE)] = "Incorrect map key size",
1441 [ERRCODE_OFFSET(OBJCONF_MAP_VALUESIZE)] = "Incorrect map value size",
1442 [ERRCODE_OFFSET(OBJCONF_MAP_NOEVT)] = "Event not found for map setting",
1443 [ERRCODE_OFFSET(OBJCONF_MAP_MAPSIZE)] = "Invalid map size for event setting",
1444 [ERRCODE_OFFSET(OBJCONF_MAP_EVTDIM)] = "Event dimension too large",
1445 [ERRCODE_OFFSET(OBJCONF_MAP_EVTINH)] = "Doesn't support inherit event",
1446 [ERRCODE_OFFSET(OBJCONF_MAP_EVTTYPE)] = "Wrong event type for map",
1447 [ERRCODE_OFFSET(OBJCONF_MAP_IDX2BIG)] = "Index too large",
756}; 1448};
757 1449
758static int 1450static int
@@ -872,3 +1564,29 @@ int bpf__strerror_load(struct bpf_object *obj,
872 bpf__strerror_end(buf, size); 1564 bpf__strerror_end(buf, size);
873 return 0; 1565 return 0;
874} 1566}
1567
1568int bpf__strerror_config_obj(struct bpf_object *obj __maybe_unused,
1569 struct parse_events_term *term __maybe_unused,
1570 struct perf_evlist *evlist __maybe_unused,
1571 int *error_pos __maybe_unused, int err,
1572 char *buf, size_t size)
1573{
1574 bpf__strerror_head(err, buf, size);
1575 bpf__strerror_entry(BPF_LOADER_ERRNO__OBJCONF_MAP_TYPE,
1576 "Can't use this config term with this map type");
1577 bpf__strerror_end(buf, size);
1578 return 0;
1579}
1580
1581int bpf__strerror_apply_obj_config(int err, char *buf, size_t size)
1582{
1583 bpf__strerror_head(err, buf, size);
1584 bpf__strerror_entry(BPF_LOADER_ERRNO__OBJCONF_MAP_EVTDIM,
1585 "Cannot set event to BPF map in multi-thread tracing");
1586 bpf__strerror_entry(BPF_LOADER_ERRNO__OBJCONF_MAP_EVTINH,
1587 "%s (Hint: use -i to turn off inherit)", emsg);
1588 bpf__strerror_entry(BPF_LOADER_ERRNO__OBJCONF_MAP_EVTTYPE,
1589 "Can only put raw, hardware and BPF output event into a BPF map");
1590 bpf__strerror_end(buf, size);
1591 return 0;
1592}
diff --git a/tools/perf/util/bpf-loader.h b/tools/perf/util/bpf-loader.h
index 6fdc0457e2b6..be4311944e3d 100644
--- a/tools/perf/util/bpf-loader.h
+++ b/tools/perf/util/bpf-loader.h
@@ -10,6 +10,7 @@
10#include <string.h> 10#include <string.h>
11#include <bpf/libbpf.h> 11#include <bpf/libbpf.h>
12#include "probe-event.h" 12#include "probe-event.h"
13#include "evlist.h"
13#include "debug.h" 14#include "debug.h"
14 15
15enum bpf_loader_errno { 16enum bpf_loader_errno {
@@ -24,10 +25,25 @@ enum bpf_loader_errno {
24 BPF_LOADER_ERRNO__PROLOGUE, /* Failed to generate prologue */ 25 BPF_LOADER_ERRNO__PROLOGUE, /* Failed to generate prologue */
25 BPF_LOADER_ERRNO__PROLOGUE2BIG, /* Prologue too big for program */ 26 BPF_LOADER_ERRNO__PROLOGUE2BIG, /* Prologue too big for program */
26 BPF_LOADER_ERRNO__PROLOGUEOOB, /* Offset out of bound for prologue */ 27 BPF_LOADER_ERRNO__PROLOGUEOOB, /* Offset out of bound for prologue */
28 BPF_LOADER_ERRNO__OBJCONF_OPT, /* Invalid object config option */
29 BPF_LOADER_ERRNO__OBJCONF_CONF, /* Config value not set (lost '=')) */
30 BPF_LOADER_ERRNO__OBJCONF_MAP_OPT, /* Invalid object map config option */
31 BPF_LOADER_ERRNO__OBJCONF_MAP_NOTEXIST, /* Target map not exist */
32 BPF_LOADER_ERRNO__OBJCONF_MAP_VALUE, /* Incorrect value type for map */
33 BPF_LOADER_ERRNO__OBJCONF_MAP_TYPE, /* Incorrect map type */
34 BPF_LOADER_ERRNO__OBJCONF_MAP_KEYSIZE, /* Incorrect map key size */
35 BPF_LOADER_ERRNO__OBJCONF_MAP_VALUESIZE,/* Incorrect map value size */
36 BPF_LOADER_ERRNO__OBJCONF_MAP_NOEVT, /* Event not found for map setting */
37 BPF_LOADER_ERRNO__OBJCONF_MAP_MAPSIZE, /* Invalid map size for event setting */
38 BPF_LOADER_ERRNO__OBJCONF_MAP_EVTDIM, /* Event dimension too large */
39 BPF_LOADER_ERRNO__OBJCONF_MAP_EVTINH, /* Doesn't support inherit event */
40 BPF_LOADER_ERRNO__OBJCONF_MAP_EVTTYPE, /* Wrong event type for map */
41 BPF_LOADER_ERRNO__OBJCONF_MAP_IDX2BIG, /* Index too large */
27 __BPF_LOADER_ERRNO__END, 42 __BPF_LOADER_ERRNO__END,
28}; 43};
29 44
30struct bpf_object; 45struct bpf_object;
46struct parse_events_term;
31#define PERF_BPF_PROBE_GROUP "perf_bpf_probe" 47#define PERF_BPF_PROBE_GROUP "perf_bpf_probe"
32 48
33typedef int (*bpf_prog_iter_callback_t)(struct probe_trace_event *tev, 49typedef int (*bpf_prog_iter_callback_t)(struct probe_trace_event *tev,
@@ -53,6 +69,16 @@ int bpf__strerror_load(struct bpf_object *obj, int err,
53 char *buf, size_t size); 69 char *buf, size_t size);
54int bpf__foreach_tev(struct bpf_object *obj, 70int bpf__foreach_tev(struct bpf_object *obj,
55 bpf_prog_iter_callback_t func, void *arg); 71 bpf_prog_iter_callback_t func, void *arg);
72
73int bpf__config_obj(struct bpf_object *obj, struct parse_events_term *term,
74 struct perf_evlist *evlist, int *error_pos);
75int bpf__strerror_config_obj(struct bpf_object *obj,
76 struct parse_events_term *term,
77 struct perf_evlist *evlist,
78 int *error_pos, int err, char *buf,
79 size_t size);
80int bpf__apply_obj_config(void);
81int bpf__strerror_apply_obj_config(int err, char *buf, size_t size);
56#else 82#else
57static inline struct bpf_object * 83static inline struct bpf_object *
58bpf__prepare_load(const char *filename __maybe_unused, 84bpf__prepare_load(const char *filename __maybe_unused,
@@ -84,6 +110,21 @@ bpf__foreach_tev(struct bpf_object *obj __maybe_unused,
84} 110}
85 111
86static inline int 112static inline int
113bpf__config_obj(struct bpf_object *obj __maybe_unused,
114 struct parse_events_term *term __maybe_unused,
115 struct perf_evlist *evlist __maybe_unused,
116 int *error_pos __maybe_unused)
117{
118 return 0;
119}
120
121static inline int
122bpf__apply_obj_config(void)
123{
124 return 0;
125}
126
127static inline int
87__bpf_strerror(char *buf, size_t size) 128__bpf_strerror(char *buf, size_t size)
88{ 129{
89 if (!size) 130 if (!size)
@@ -118,5 +159,23 @@ static inline int bpf__strerror_load(struct bpf_object *obj __maybe_unused,
118{ 159{
119 return __bpf_strerror(buf, size); 160 return __bpf_strerror(buf, size);
120} 161}
162
163static inline int
164bpf__strerror_config_obj(struct bpf_object *obj __maybe_unused,
165 struct parse_events_term *term __maybe_unused,
166 struct perf_evlist *evlist __maybe_unused,
167 int *error_pos __maybe_unused,
168 int err __maybe_unused,
169 char *buf, size_t size)
170{
171 return __bpf_strerror(buf, size);
172}
173
174static inline int
175bpf__strerror_apply_obj_config(int err __maybe_unused,
176 char *buf, size_t size)
177{
178 return __bpf_strerror(buf, size);
179}
121#endif 180#endif
122#endif 181#endif
diff --git a/tools/perf/util/build-id.c b/tools/perf/util/build-id.c
index 6a7e273a514a..f1479eeef7da 100644
--- a/tools/perf/util/build-id.c
+++ b/tools/perf/util/build-id.c
@@ -166,6 +166,50 @@ char *dso__build_id_filename(const struct dso *dso, char *bf, size_t size)
166 return build_id__filename(build_id_hex, bf, size); 166 return build_id__filename(build_id_hex, bf, size);
167} 167}
168 168
169bool dso__build_id_is_kmod(const struct dso *dso, char *bf, size_t size)
170{
171 char *id_name, *ch;
172 struct stat sb;
173
174 id_name = dso__build_id_filename(dso, bf, size);
175 if (!id_name)
176 goto err;
177 if (access(id_name, F_OK))
178 goto err;
179 if (lstat(id_name, &sb) == -1)
180 goto err;
181 if ((size_t)sb.st_size > size - 1)
182 goto err;
183 if (readlink(id_name, bf, size - 1) < 0)
184 goto err;
185
186 bf[sb.st_size] = '\0';
187
188 /*
189 * link should be:
190 * ../../lib/modules/4.4.0-rc4/kernel/net/ipv4/netfilter/nf_nat_ipv4.ko/a09fe3eb3147dafa4e3b31dbd6257e4d696bdc92
191 */
192 ch = strrchr(bf, '/');
193 if (!ch)
194 goto err;
195 if (ch - 3 < bf)
196 goto err;
197
198 return strncmp(".ko", ch - 3, 3) == 0;
199err:
200 /*
201 * If dso__build_id_filename work, get id_name again,
202 * because id_name points to bf and is broken.
203 */
204 if (id_name)
205 id_name = dso__build_id_filename(dso, bf, size);
206 pr_err("Invalid build id: %s\n", id_name ? :
207 dso->long_name ? :
208 dso->short_name ? :
209 "[unknown]");
210 return false;
211}
212
169#define dsos__for_each_with_build_id(pos, head) \ 213#define dsos__for_each_with_build_id(pos, head) \
170 list_for_each_entry(pos, head, node) \ 214 list_for_each_entry(pos, head, node) \
171 if (!pos->has_build_id) \ 215 if (!pos->has_build_id) \
@@ -211,6 +255,7 @@ static int machine__write_buildid_table(struct machine *machine, int fd)
211 dsos__for_each_with_build_id(pos, &machine->dsos.head) { 255 dsos__for_each_with_build_id(pos, &machine->dsos.head) {
212 const char *name; 256 const char *name;
213 size_t name_len; 257 size_t name_len;
258 bool in_kernel = false;
214 259
215 if (!pos->hit) 260 if (!pos->hit)
216 continue; 261 continue;
@@ -227,8 +272,11 @@ static int machine__write_buildid_table(struct machine *machine, int fd)
227 name_len = pos->long_name_len + 1; 272 name_len = pos->long_name_len + 1;
228 } 273 }
229 274
275 in_kernel = pos->kernel ||
276 is_kernel_module(name,
277 PERF_RECORD_MISC_CPUMODE_UNKNOWN);
230 err = write_buildid(name, name_len, pos->build_id, machine->pid, 278 err = write_buildid(name, name_len, pos->build_id, machine->pid,
231 pos->kernel ? kmisc : umisc, fd); 279 in_kernel ? kmisc : umisc, fd);
232 if (err) 280 if (err)
233 break; 281 break;
234 } 282 }
diff --git a/tools/perf/util/build-id.h b/tools/perf/util/build-id.h
index 27a14a8a945b..64af3e20610d 100644
--- a/tools/perf/util/build-id.h
+++ b/tools/perf/util/build-id.h
@@ -16,6 +16,7 @@ int sysfs__sprintf_build_id(const char *root_dir, char *sbuild_id);
16int filename__sprintf_build_id(const char *pathname, char *sbuild_id); 16int filename__sprintf_build_id(const char *pathname, char *sbuild_id);
17 17
18char *dso__build_id_filename(const struct dso *dso, char *bf, size_t size); 18char *dso__build_id_filename(const struct dso *dso, char *bf, size_t size);
19bool dso__build_id_is_kmod(const struct dso *dso, char *bf, size_t size);
19 20
20int build_id__mark_dso_hit(struct perf_tool *tool, union perf_event *event, 21int build_id__mark_dso_hit(struct perf_tool *tool, union perf_event *event,
21 struct perf_sample *sample, struct perf_evsel *evsel, 22 struct perf_sample *sample, struct perf_evsel *evsel,
diff --git a/tools/perf/util/cache.h b/tools/perf/util/cache.h
index 07b5d63947b1..3ca453f0c51f 100644
--- a/tools/perf/util/cache.h
+++ b/tools/perf/util/cache.h
@@ -23,6 +23,8 @@
23#define PERF_TRACEFS_ENVIRONMENT "PERF_TRACEFS_DIR" 23#define PERF_TRACEFS_ENVIRONMENT "PERF_TRACEFS_DIR"
24#define PERF_PAGER_ENVIRONMENT "PERF_PAGER" 24#define PERF_PAGER_ENVIRONMENT "PERF_PAGER"
25 25
26extern const char *config_exclusive_filename;
27
26typedef int (*config_fn_t)(const char *, const char *, void *); 28typedef int (*config_fn_t)(const char *, const char *, void *);
27extern int perf_default_config(const char *, const char *, void *); 29extern int perf_default_config(const char *, const char *, void *);
28extern int perf_config(config_fn_t fn, void *); 30extern int perf_config(config_fn_t fn, void *);
@@ -31,6 +33,7 @@ extern u64 perf_config_u64(const char *, const char *);
31extern int perf_config_bool(const char *, const char *); 33extern int perf_config_bool(const char *, const char *);
32extern int config_error_nonbool(const char *); 34extern int config_error_nonbool(const char *);
33extern const char *perf_config_dirname(const char *, const char *); 35extern const char *perf_config_dirname(const char *, const char *);
36extern const char *perf_etc_perfconfig(void);
34 37
35char *alias_lookup(const char *alias); 38char *alias_lookup(const char *alias);
36int split_cmdline(char *cmdline, const char ***argv); 39int split_cmdline(char *cmdline, const char ***argv);
diff --git a/tools/perf/util/callchain.c b/tools/perf/util/callchain.c
index 53c43eb9489e..24b4bd0d7754 100644
--- a/tools/perf/util/callchain.c
+++ b/tools/perf/util/callchain.c
@@ -416,7 +416,7 @@ create_child(struct callchain_node *parent, bool inherit_children)
416/* 416/*
417 * Fill the node with callchain values 417 * Fill the node with callchain values
418 */ 418 */
419static void 419static int
420fill_node(struct callchain_node *node, struct callchain_cursor *cursor) 420fill_node(struct callchain_node *node, struct callchain_cursor *cursor)
421{ 421{
422 struct callchain_cursor_node *cursor_node; 422 struct callchain_cursor_node *cursor_node;
@@ -433,7 +433,7 @@ fill_node(struct callchain_node *node, struct callchain_cursor *cursor)
433 call = zalloc(sizeof(*call)); 433 call = zalloc(sizeof(*call));
434 if (!call) { 434 if (!call) {
435 perror("not enough memory for the code path tree"); 435 perror("not enough memory for the code path tree");
436 return; 436 return -1;
437 } 437 }
438 call->ip = cursor_node->ip; 438 call->ip = cursor_node->ip;
439 call->ms.sym = cursor_node->sym; 439 call->ms.sym = cursor_node->sym;
@@ -443,6 +443,7 @@ fill_node(struct callchain_node *node, struct callchain_cursor *cursor)
443 callchain_cursor_advance(cursor); 443 callchain_cursor_advance(cursor);
444 cursor_node = callchain_cursor_current(cursor); 444 cursor_node = callchain_cursor_current(cursor);
445 } 445 }
446 return 0;
446} 447}
447 448
448static struct callchain_node * 449static struct callchain_node *
@@ -453,7 +454,19 @@ add_child(struct callchain_node *parent,
453 struct callchain_node *new; 454 struct callchain_node *new;
454 455
455 new = create_child(parent, false); 456 new = create_child(parent, false);
456 fill_node(new, cursor); 457 if (new == NULL)
458 return NULL;
459
460 if (fill_node(new, cursor) < 0) {
461 struct callchain_list *call, *tmp;
462
463 list_for_each_entry_safe(call, tmp, &new->val, list) {
464 list_del(&call->list);
465 free(call);
466 }
467 free(new);
468 return NULL;
469 }
457 470
458 new->children_hit = 0; 471 new->children_hit = 0;
459 new->hit = period; 472 new->hit = period;
@@ -462,16 +475,32 @@ add_child(struct callchain_node *parent,
462 return new; 475 return new;
463} 476}
464 477
465static s64 match_chain(struct callchain_cursor_node *node, 478enum match_result {
466 struct callchain_list *cnode) 479 MATCH_ERROR = -1,
480 MATCH_EQ,
481 MATCH_LT,
482 MATCH_GT,
483};
484
485static enum match_result match_chain(struct callchain_cursor_node *node,
486 struct callchain_list *cnode)
467{ 487{
468 struct symbol *sym = node->sym; 488 struct symbol *sym = node->sym;
489 u64 left, right;
469 490
470 if (cnode->ms.sym && sym && 491 if (cnode->ms.sym && sym &&
471 callchain_param.key == CCKEY_FUNCTION) 492 callchain_param.key == CCKEY_FUNCTION) {
472 return cnode->ms.sym->start - sym->start; 493 left = cnode->ms.sym->start;
473 else 494 right = sym->start;
474 return cnode->ip - node->ip; 495 } else {
496 left = cnode->ip;
497 right = node->ip;
498 }
499
500 if (left == right)
501 return MATCH_EQ;
502
503 return left > right ? MATCH_GT : MATCH_LT;
475} 504}
476 505
477/* 506/*
@@ -479,7 +508,7 @@ static s64 match_chain(struct callchain_cursor_node *node,
479 * give a part of its callchain to the created child. 508 * give a part of its callchain to the created child.
480 * Then create another child to host the given callchain of new branch 509 * Then create another child to host the given callchain of new branch
481 */ 510 */
482static void 511static int
483split_add_child(struct callchain_node *parent, 512split_add_child(struct callchain_node *parent,
484 struct callchain_cursor *cursor, 513 struct callchain_cursor *cursor,
485 struct callchain_list *to_split, 514 struct callchain_list *to_split,
@@ -491,6 +520,8 @@ split_add_child(struct callchain_node *parent,
491 520
492 /* split */ 521 /* split */
493 new = create_child(parent, true); 522 new = create_child(parent, true);
523 if (new == NULL)
524 return -1;
494 525
495 /* split the callchain and move a part to the new child */ 526 /* split the callchain and move a part to the new child */
496 old_tail = parent->val.prev; 527 old_tail = parent->val.prev;
@@ -524,6 +555,8 @@ split_add_child(struct callchain_node *parent,
524 555
525 node = callchain_cursor_current(cursor); 556 node = callchain_cursor_current(cursor);
526 new = add_child(parent, cursor, period); 557 new = add_child(parent, cursor, period);
558 if (new == NULL)
559 return -1;
527 560
528 /* 561 /*
529 * This is second child since we moved parent's children 562 * This is second child since we moved parent's children
@@ -534,7 +567,7 @@ split_add_child(struct callchain_node *parent,
534 cnode = list_first_entry(&first->val, struct callchain_list, 567 cnode = list_first_entry(&first->val, struct callchain_list,
535 list); 568 list);
536 569
537 if (match_chain(node, cnode) < 0) 570 if (match_chain(node, cnode) == MATCH_LT)
538 pp = &p->rb_left; 571 pp = &p->rb_left;
539 else 572 else
540 pp = &p->rb_right; 573 pp = &p->rb_right;
@@ -545,14 +578,15 @@ split_add_child(struct callchain_node *parent,
545 parent->hit = period; 578 parent->hit = period;
546 parent->count = 1; 579 parent->count = 1;
547 } 580 }
581 return 0;
548} 582}
549 583
550static int 584static enum match_result
551append_chain(struct callchain_node *root, 585append_chain(struct callchain_node *root,
552 struct callchain_cursor *cursor, 586 struct callchain_cursor *cursor,
553 u64 period); 587 u64 period);
554 588
555static void 589static int
556append_chain_children(struct callchain_node *root, 590append_chain_children(struct callchain_node *root,
557 struct callchain_cursor *cursor, 591 struct callchain_cursor *cursor,
558 u64 period) 592 u64 period)
@@ -564,36 +598,42 @@ append_chain_children(struct callchain_node *root,
564 598
565 node = callchain_cursor_current(cursor); 599 node = callchain_cursor_current(cursor);
566 if (!node) 600 if (!node)
567 return; 601 return -1;
568 602
569 /* lookup in childrens */ 603 /* lookup in childrens */
570 while (*p) { 604 while (*p) {
571 s64 ret; 605 enum match_result ret;
572 606
573 parent = *p; 607 parent = *p;
574 rnode = rb_entry(parent, struct callchain_node, rb_node_in); 608 rnode = rb_entry(parent, struct callchain_node, rb_node_in);
575 609
576 /* If at least first entry matches, rely to children */ 610 /* If at least first entry matches, rely to children */
577 ret = append_chain(rnode, cursor, period); 611 ret = append_chain(rnode, cursor, period);
578 if (ret == 0) 612 if (ret == MATCH_EQ)
579 goto inc_children_hit; 613 goto inc_children_hit;
614 if (ret == MATCH_ERROR)
615 return -1;
580 616
581 if (ret < 0) 617 if (ret == MATCH_LT)
582 p = &parent->rb_left; 618 p = &parent->rb_left;
583 else 619 else
584 p = &parent->rb_right; 620 p = &parent->rb_right;
585 } 621 }
586 /* nothing in children, add to the current node */ 622 /* nothing in children, add to the current node */
587 rnode = add_child(root, cursor, period); 623 rnode = add_child(root, cursor, period);
624 if (rnode == NULL)
625 return -1;
626
588 rb_link_node(&rnode->rb_node_in, parent, p); 627 rb_link_node(&rnode->rb_node_in, parent, p);
589 rb_insert_color(&rnode->rb_node_in, &root->rb_root_in); 628 rb_insert_color(&rnode->rb_node_in, &root->rb_root_in);
590 629
591inc_children_hit: 630inc_children_hit:
592 root->children_hit += period; 631 root->children_hit += period;
593 root->children_count++; 632 root->children_count++;
633 return 0;
594} 634}
595 635
596static int 636static enum match_result
597append_chain(struct callchain_node *root, 637append_chain(struct callchain_node *root,
598 struct callchain_cursor *cursor, 638 struct callchain_cursor *cursor,
599 u64 period) 639 u64 period)
@@ -602,7 +642,7 @@ append_chain(struct callchain_node *root,
602 u64 start = cursor->pos; 642 u64 start = cursor->pos;
603 bool found = false; 643 bool found = false;
604 u64 matches; 644 u64 matches;
605 int cmp = 0; 645 enum match_result cmp = MATCH_ERROR;
606 646
607 /* 647 /*
608 * Lookup in the current node 648 * Lookup in the current node
@@ -618,7 +658,7 @@ append_chain(struct callchain_node *root,
618 break; 658 break;
619 659
620 cmp = match_chain(node, cnode); 660 cmp = match_chain(node, cnode);
621 if (cmp) 661 if (cmp != MATCH_EQ)
622 break; 662 break;
623 663
624 found = true; 664 found = true;
@@ -628,7 +668,7 @@ append_chain(struct callchain_node *root,
628 668
629 /* matches not, relay no the parent */ 669 /* matches not, relay no the parent */
630 if (!found) { 670 if (!found) {
631 WARN_ONCE(!cmp, "Chain comparison error\n"); 671 WARN_ONCE(cmp == MATCH_ERROR, "Chain comparison error\n");
632 return cmp; 672 return cmp;
633 } 673 }
634 674
@@ -636,21 +676,25 @@ append_chain(struct callchain_node *root,
636 676
637 /* we match only a part of the node. Split it and add the new chain */ 677 /* we match only a part of the node. Split it and add the new chain */
638 if (matches < root->val_nr) { 678 if (matches < root->val_nr) {
639 split_add_child(root, cursor, cnode, start, matches, period); 679 if (split_add_child(root, cursor, cnode, start, matches,
640 return 0; 680 period) < 0)
681 return MATCH_ERROR;
682
683 return MATCH_EQ;
641 } 684 }
642 685
643 /* we match 100% of the path, increment the hit */ 686 /* we match 100% of the path, increment the hit */
644 if (matches == root->val_nr && cursor->pos == cursor->nr) { 687 if (matches == root->val_nr && cursor->pos == cursor->nr) {
645 root->hit += period; 688 root->hit += period;
646 root->count++; 689 root->count++;
647 return 0; 690 return MATCH_EQ;
648 } 691 }
649 692
650 /* We match the node and still have a part remaining */ 693 /* We match the node and still have a part remaining */
651 append_chain_children(root, cursor, period); 694 if (append_chain_children(root, cursor, period) < 0)
695 return MATCH_ERROR;
652 696
653 return 0; 697 return MATCH_EQ;
654} 698}
655 699
656int callchain_append(struct callchain_root *root, 700int callchain_append(struct callchain_root *root,
@@ -662,7 +706,8 @@ int callchain_append(struct callchain_root *root,
662 706
663 callchain_cursor_commit(cursor); 707 callchain_cursor_commit(cursor);
664 708
665 append_chain_children(&root->node, cursor, period); 709 if (append_chain_children(&root->node, cursor, period) < 0)
710 return -1;
666 711
667 if (cursor->nr > root->max_depth) 712 if (cursor->nr > root->max_depth)
668 root->max_depth = cursor->nr; 713 root->max_depth = cursor->nr;
@@ -690,7 +735,8 @@ merge_chain_branch(struct callchain_cursor *cursor,
690 735
691 if (src->hit) { 736 if (src->hit) {
692 callchain_cursor_commit(cursor); 737 callchain_cursor_commit(cursor);
693 append_chain_children(dst, cursor, src->hit); 738 if (append_chain_children(dst, cursor, src->hit) < 0)
739 return -1;
694 } 740 }
695 741
696 n = rb_first(&src->rb_root_in); 742 n = rb_first(&src->rb_root_in);
diff --git a/tools/perf/util/color.c b/tools/perf/util/color.c
index e5fb88bab9e1..43e84aa27e4a 100644
--- a/tools/perf/util/color.c
+++ b/tools/perf/util/color.c
@@ -32,14 +32,15 @@ int perf_config_colorbool(const char *var, const char *value, int stdout_is_tty)
32 return 0; 32 return 0;
33} 33}
34 34
35int perf_color_default_config(const char *var, const char *value, void *cb) 35int perf_color_default_config(const char *var, const char *value,
36 void *cb __maybe_unused)
36{ 37{
37 if (!strcmp(var, "color.ui")) { 38 if (!strcmp(var, "color.ui")) {
38 perf_use_color_default = perf_config_colorbool(var, value, -1); 39 perf_use_color_default = perf_config_colorbool(var, value, -1);
39 return 0; 40 return 0;
40 } 41 }
41 42
42 return perf_default_config(var, value, cb); 43 return 0;
43} 44}
44 45
45static int __color_vsnprintf(char *bf, size_t size, const char *color, 46static int __color_vsnprintf(char *bf, size_t size, const char *color,
diff --git a/tools/perf/util/config.c b/tools/perf/util/config.c
index d3e12e30e1d5..4e727635476e 100644
--- a/tools/perf/util/config.c
+++ b/tools/perf/util/config.c
@@ -26,7 +26,7 @@ static const char *config_file_name;
26static int config_linenr; 26static int config_linenr;
27static int config_file_eof; 27static int config_file_eof;
28 28
29static const char *config_exclusive_filename; 29const char *config_exclusive_filename;
30 30
31static int get_next_char(void) 31static int get_next_char(void)
32{ 32{
@@ -434,7 +434,7 @@ static int perf_config_from_file(config_fn_t fn, const char *filename, void *dat
434 return ret; 434 return ret;
435} 435}
436 436
437static const char *perf_etc_perfconfig(void) 437const char *perf_etc_perfconfig(void)
438{ 438{
439 static const char *system_wide; 439 static const char *system_wide;
440 if (!system_wide) 440 if (!system_wide)
diff --git a/tools/perf/util/cpumap.c b/tools/perf/util/cpumap.c
index fa935093a599..9bcf2bed3a6d 100644
--- a/tools/perf/util/cpumap.c
+++ b/tools/perf/util/cpumap.c
@@ -8,6 +8,10 @@
8#include <linux/bitmap.h> 8#include <linux/bitmap.h>
9#include "asm/bug.h" 9#include "asm/bug.h"
10 10
11static int max_cpu_num;
12static int max_node_num;
13static int *cpunode_map;
14
11static struct cpu_map *cpu_map__default_new(void) 15static struct cpu_map *cpu_map__default_new(void)
12{ 16{
13 struct cpu_map *cpus; 17 struct cpu_map *cpus;
@@ -486,6 +490,32 @@ out:
486 pr_err("Failed to read max nodes, using default of %d\n", max_node_num); 490 pr_err("Failed to read max nodes, using default of %d\n", max_node_num);
487} 491}
488 492
493int cpu__max_node(void)
494{
495 if (unlikely(!max_node_num))
496 set_max_node_num();
497
498 return max_node_num;
499}
500
501int cpu__max_cpu(void)
502{
503 if (unlikely(!max_cpu_num))
504 set_max_cpu_num();
505
506 return max_cpu_num;
507}
508
509int cpu__get_node(int cpu)
510{
511 if (unlikely(cpunode_map == NULL)) {
512 pr_debug("cpu_map not initialized\n");
513 return -1;
514 }
515
516 return cpunode_map[cpu];
517}
518
489static int init_cpunode_map(void) 519static int init_cpunode_map(void)
490{ 520{
491 int i; 521 int i;
diff --git a/tools/perf/util/cpumap.h b/tools/perf/util/cpumap.h
index 71c41b9efabb..81a2562aaa2b 100644
--- a/tools/perf/util/cpumap.h
+++ b/tools/perf/util/cpumap.h
@@ -57,37 +57,11 @@ static inline bool cpu_map__empty(const struct cpu_map *map)
57 return map ? map->map[0] == -1 : true; 57 return map ? map->map[0] == -1 : true;
58} 58}
59 59
60int max_cpu_num;
61int max_node_num;
62int *cpunode_map;
63
64int cpu__setup_cpunode_map(void); 60int cpu__setup_cpunode_map(void);
65 61
66static inline int cpu__max_node(void) 62int cpu__max_node(void);
67{ 63int cpu__max_cpu(void);
68 if (unlikely(!max_node_num)) 64int cpu__get_node(int cpu);
69 pr_debug("cpu_map not initialized\n");
70
71 return max_node_num;
72}
73
74static inline int cpu__max_cpu(void)
75{
76 if (unlikely(!max_cpu_num))
77 pr_debug("cpu_map not initialized\n");
78
79 return max_cpu_num;
80}
81
82static inline int cpu__get_node(int cpu)
83{
84 if (unlikely(cpunode_map == NULL)) {
85 pr_debug("cpu_map not initialized\n");
86 return -1;
87 }
88
89 return cpunode_map[cpu];
90}
91 65
92int cpu_map__build_map(struct cpu_map *cpus, struct cpu_map **res, 66int cpu_map__build_map(struct cpu_map *cpus, struct cpu_map **res,
93 int (*f)(struct cpu_map *map, int cpu, void *data), 67 int (*f)(struct cpu_map *map, int cpu, void *data),
diff --git a/tools/perf/util/ctype.c b/tools/perf/util/ctype.c
index aada3ac5e891..d4a5a21c2a7e 100644
--- a/tools/perf/util/ctype.c
+++ b/tools/perf/util/ctype.c
@@ -32,8 +32,17 @@ unsigned char sane_ctype[256] = {
32 32
33const char *graph_line = 33const char *graph_line =
34 "_____________________________________________________________________" 34 "_____________________________________________________________________"
35 "_____________________________________________________________________"
35 "_____________________________________________________________________"; 36 "_____________________________________________________________________";
36const char *graph_dotted_line = 37const char *graph_dotted_line =
37 "---------------------------------------------------------------------" 38 "---------------------------------------------------------------------"
38 "---------------------------------------------------------------------" 39 "---------------------------------------------------------------------"
39 "---------------------------------------------------------------------"; 40 "---------------------------------------------------------------------";
41const char *spaces =
42 " "
43 " "
44 " ";
45const char *dots =
46 "....................................................................."
47 "....................................................................."
48 ".....................................................................";
diff --git a/tools/perf/util/data-convert-bt.c b/tools/perf/util/data-convert-bt.c
index 34cd1e4039d3..811af89ce0bb 100644
--- a/tools/perf/util/data-convert-bt.c
+++ b/tools/perf/util/data-convert-bt.c
@@ -352,6 +352,84 @@ static int add_tracepoint_values(struct ctf_writer *cw,
352 return ret; 352 return ret;
353} 353}
354 354
355static int
356add_bpf_output_values(struct bt_ctf_event_class *event_class,
357 struct bt_ctf_event *event,
358 struct perf_sample *sample)
359{
360 struct bt_ctf_field_type *len_type, *seq_type;
361 struct bt_ctf_field *len_field, *seq_field;
362 unsigned int raw_size = sample->raw_size;
363 unsigned int nr_elements = raw_size / sizeof(u32);
364 unsigned int i;
365 int ret;
366
367 if (nr_elements * sizeof(u32) != raw_size)
368 pr_warning("Incorrect raw_size (%u) in bpf output event, skip %lu bytes\n",
369 raw_size, nr_elements * sizeof(u32) - raw_size);
370
371 len_type = bt_ctf_event_class_get_field_by_name(event_class, "raw_len");
372 len_field = bt_ctf_field_create(len_type);
373 if (!len_field) {
374 pr_err("failed to create 'raw_len' for bpf output event\n");
375 ret = -1;
376 goto put_len_type;
377 }
378
379 ret = bt_ctf_field_unsigned_integer_set_value(len_field, nr_elements);
380 if (ret) {
381 pr_err("failed to set field value for raw_len\n");
382 goto put_len_field;
383 }
384 ret = bt_ctf_event_set_payload(event, "raw_len", len_field);
385 if (ret) {
386 pr_err("failed to set payload to raw_len\n");
387 goto put_len_field;
388 }
389
390 seq_type = bt_ctf_event_class_get_field_by_name(event_class, "raw_data");
391 seq_field = bt_ctf_field_create(seq_type);
392 if (!seq_field) {
393 pr_err("failed to create 'raw_data' for bpf output event\n");
394 ret = -1;
395 goto put_seq_type;
396 }
397
398 ret = bt_ctf_field_sequence_set_length(seq_field, len_field);
399 if (ret) {
400 pr_err("failed to set length of 'raw_data'\n");
401 goto put_seq_field;
402 }
403
404 for (i = 0; i < nr_elements; i++) {
405 struct bt_ctf_field *elem_field =
406 bt_ctf_field_sequence_get_field(seq_field, i);
407
408 ret = bt_ctf_field_unsigned_integer_set_value(elem_field,
409 ((u32 *)(sample->raw_data))[i]);
410
411 bt_ctf_field_put(elem_field);
412 if (ret) {
413 pr_err("failed to set raw_data[%d]\n", i);
414 goto put_seq_field;
415 }
416 }
417
418 ret = bt_ctf_event_set_payload(event, "raw_data", seq_field);
419 if (ret)
420 pr_err("failed to set payload for raw_data\n");
421
422put_seq_field:
423 bt_ctf_field_put(seq_field);
424put_seq_type:
425 bt_ctf_field_type_put(seq_type);
426put_len_field:
427 bt_ctf_field_put(len_field);
428put_len_type:
429 bt_ctf_field_type_put(len_type);
430 return ret;
431}
432
355static int add_generic_values(struct ctf_writer *cw, 433static int add_generic_values(struct ctf_writer *cw,
356 struct bt_ctf_event *event, 434 struct bt_ctf_event *event,
357 struct perf_evsel *evsel, 435 struct perf_evsel *evsel,
@@ -597,6 +675,12 @@ static int process_sample_event(struct perf_tool *tool,
597 return -1; 675 return -1;
598 } 676 }
599 677
678 if (perf_evsel__is_bpf_output(evsel)) {
679 ret = add_bpf_output_values(event_class, event, sample);
680 if (ret)
681 return -1;
682 }
683
600 cs = ctf_stream(cw, get_sample_cpu(cw, sample, evsel)); 684 cs = ctf_stream(cw, get_sample_cpu(cw, sample, evsel));
601 if (cs) { 685 if (cs) {
602 if (is_flush_needed(cs)) 686 if (is_flush_needed(cs))
@@ -744,6 +828,25 @@ static int add_tracepoint_types(struct ctf_writer *cw,
744 return ret; 828 return ret;
745} 829}
746 830
831static int add_bpf_output_types(struct ctf_writer *cw,
832 struct bt_ctf_event_class *class)
833{
834 struct bt_ctf_field_type *len_type = cw->data.u32;
835 struct bt_ctf_field_type *seq_base_type = cw->data.u32_hex;
836 struct bt_ctf_field_type *seq_type;
837 int ret;
838
839 ret = bt_ctf_event_class_add_field(class, len_type, "raw_len");
840 if (ret)
841 return ret;
842
843 seq_type = bt_ctf_field_type_sequence_create(seq_base_type, "raw_len");
844 if (!seq_type)
845 return -1;
846
847 return bt_ctf_event_class_add_field(class, seq_type, "raw_data");
848}
849
747static int add_generic_types(struct ctf_writer *cw, struct perf_evsel *evsel, 850static int add_generic_types(struct ctf_writer *cw, struct perf_evsel *evsel,
748 struct bt_ctf_event_class *event_class) 851 struct bt_ctf_event_class *event_class)
749{ 852{
@@ -755,7 +858,8 @@ static int add_generic_types(struct ctf_writer *cw, struct perf_evsel *evsel,
755 * ctf event header 858 * ctf event header
756 * PERF_SAMPLE_READ - TODO 859 * PERF_SAMPLE_READ - TODO
757 * PERF_SAMPLE_CALLCHAIN - TODO 860 * PERF_SAMPLE_CALLCHAIN - TODO
758 * PERF_SAMPLE_RAW - tracepoint fields are handled separately 861 * PERF_SAMPLE_RAW - tracepoint fields and BPF output
862 * are handled separately
759 * PERF_SAMPLE_BRANCH_STACK - TODO 863 * PERF_SAMPLE_BRANCH_STACK - TODO
760 * PERF_SAMPLE_REGS_USER - TODO 864 * PERF_SAMPLE_REGS_USER - TODO
761 * PERF_SAMPLE_STACK_USER - TODO 865 * PERF_SAMPLE_STACK_USER - TODO
@@ -824,6 +928,12 @@ static int add_event(struct ctf_writer *cw, struct perf_evsel *evsel)
824 goto err; 928 goto err;
825 } 929 }
826 930
931 if (perf_evsel__is_bpf_output(evsel)) {
932 ret = add_bpf_output_types(cw, event_class);
933 if (ret)
934 goto err;
935 }
936
827 ret = bt_ctf_stream_class_add_event_class(cw->stream_class, event_class); 937 ret = bt_ctf_stream_class_add_event_class(cw->stream_class, event_class);
828 if (ret) { 938 if (ret) {
829 pr("Failed to add event class into stream.\n"); 939 pr("Failed to add event class into stream.\n");
@@ -858,6 +968,23 @@ static int setup_events(struct ctf_writer *cw, struct perf_session *session)
858 return 0; 968 return 0;
859} 969}
860 970
971static void cleanup_events(struct perf_session *session)
972{
973 struct perf_evlist *evlist = session->evlist;
974 struct perf_evsel *evsel;
975
976 evlist__for_each(evlist, evsel) {
977 struct evsel_priv *priv;
978
979 priv = evsel->priv;
980 bt_ctf_event_class_put(priv->event_class);
981 zfree(&evsel->priv);
982 }
983
984 perf_evlist__delete(evlist);
985 session->evlist = NULL;
986}
987
861static int setup_streams(struct ctf_writer *cw, struct perf_session *session) 988static int setup_streams(struct ctf_writer *cw, struct perf_session *session)
862{ 989{
863 struct ctf_stream **stream; 990 struct ctf_stream **stream;
@@ -953,6 +1080,12 @@ static struct bt_ctf_field_type *create_int_type(int size, bool sign, bool hex)
953 bt_ctf_field_type_integer_set_base(type, BT_CTF_INTEGER_BASE_HEXADECIMAL)) 1080 bt_ctf_field_type_integer_set_base(type, BT_CTF_INTEGER_BASE_HEXADECIMAL))
954 goto err; 1081 goto err;
955 1082
1083#if __BYTE_ORDER == __BIG_ENDIAN
1084 bt_ctf_field_type_set_byte_order(type, BT_CTF_BYTE_ORDER_BIG_ENDIAN);
1085#else
1086 bt_ctf_field_type_set_byte_order(type, BT_CTF_BYTE_ORDER_LITTLE_ENDIAN);
1087#endif
1088
956 pr2("Created type: INTEGER %d-bit %ssigned %s\n", 1089 pr2("Created type: INTEGER %d-bit %ssigned %s\n",
957 size, sign ? "un" : "", hex ? "hex" : ""); 1090 size, sign ? "un" : "", hex ? "hex" : "");
958 return type; 1091 return type;
@@ -1100,7 +1233,7 @@ static int convert__config(const char *var, const char *value, void *cb)
1100 return 0; 1233 return 0;
1101 } 1234 }
1102 1235
1103 return perf_default_config(var, value, cb); 1236 return 0;
1104} 1237}
1105 1238
1106int bt_convert__perf2ctf(const char *input, const char *path, bool force) 1239int bt_convert__perf2ctf(const char *input, const char *path, bool force)
@@ -1171,6 +1304,7 @@ int bt_convert__perf2ctf(const char *input, const char *path, bool force)
1171 (double) c.events_size / 1024.0 / 1024.0, 1304 (double) c.events_size / 1024.0 / 1024.0,
1172 c.events_count); 1305 c.events_count);
1173 1306
1307 cleanup_events(session);
1174 perf_session__delete(session); 1308 perf_session__delete(session);
1175 ctf_writer__cleanup(cw); 1309 ctf_writer__cleanup(cw);
1176 1310
diff --git a/tools/perf/util/debug.c b/tools/perf/util/debug.c
index 86d9c7302598..8c4212abd19b 100644
--- a/tools/perf/util/debug.c
+++ b/tools/perf/util/debug.c
@@ -5,6 +5,7 @@
5#include <string.h> 5#include <string.h>
6#include <stdarg.h> 6#include <stdarg.h>
7#include <stdio.h> 7#include <stdio.h>
8#include <api/debug.h>
8 9
9#include "cache.h" 10#include "cache.h"
10#include "color.h" 11#include "color.h"
@@ -22,7 +23,7 @@ int debug_ordered_events;
22static int redirect_to_stderr; 23static int redirect_to_stderr;
23int debug_data_convert; 24int debug_data_convert;
24 25
25static int _eprintf(int level, int var, const char *fmt, va_list args) 26int veprintf(int level, int var, const char *fmt, va_list args)
26{ 27{
27 int ret = 0; 28 int ret = 0;
28 29
@@ -36,24 +37,19 @@ static int _eprintf(int level, int var, const char *fmt, va_list args)
36 return ret; 37 return ret;
37} 38}
38 39
39int veprintf(int level, int var, const char *fmt, va_list args)
40{
41 return _eprintf(level, var, fmt, args);
42}
43
44int eprintf(int level, int var, const char *fmt, ...) 40int eprintf(int level, int var, const char *fmt, ...)
45{ 41{
46 va_list args; 42 va_list args;
47 int ret; 43 int ret;
48 44
49 va_start(args, fmt); 45 va_start(args, fmt);
50 ret = _eprintf(level, var, fmt, args); 46 ret = veprintf(level, var, fmt, args);
51 va_end(args); 47 va_end(args);
52 48
53 return ret; 49 return ret;
54} 50}
55 51
56static int __eprintf_time(u64 t, const char *fmt, va_list args) 52static int veprintf_time(u64 t, const char *fmt, va_list args)
57{ 53{
58 int ret = 0; 54 int ret = 0;
59 u64 secs, usecs, nsecs = t; 55 u64 secs, usecs, nsecs = t;
@@ -75,7 +71,7 @@ int eprintf_time(int level, int var, u64 t, const char *fmt, ...)
75 71
76 if (var >= level) { 72 if (var >= level) {
77 va_start(args, fmt); 73 va_start(args, fmt);
78 ret = __eprintf_time(t, fmt, args); 74 ret = veprintf_time(t, fmt, args);
79 va_end(args); 75 va_end(args);
80 } 76 }
81 77
@@ -91,7 +87,7 @@ void pr_stat(const char *fmt, ...)
91 va_list args; 87 va_list args;
92 88
93 va_start(args, fmt); 89 va_start(args, fmt);
94 _eprintf(1, verbose, fmt, args); 90 veprintf(1, verbose, fmt, args);
95 va_end(args); 91 va_end(args);
96 eprintf(1, verbose, "\n"); 92 eprintf(1, verbose, "\n");
97} 93}
@@ -110,40 +106,61 @@ int dump_printf(const char *fmt, ...)
110 return ret; 106 return ret;
111} 107}
112 108
109static void trace_event_printer(enum binary_printer_ops op,
110 unsigned int val, void *extra)
111{
112 const char *color = PERF_COLOR_BLUE;
113 union perf_event *event = (union perf_event *)extra;
114 unsigned char ch = (unsigned char)val;
115
116 switch (op) {
117 case BINARY_PRINT_DATA_BEGIN:
118 printf(".");
119 color_fprintf(stdout, color, "\n. ... raw event: size %d bytes\n",
120 event->header.size);
121 break;
122 case BINARY_PRINT_LINE_BEGIN:
123 printf(".");
124 break;
125 case BINARY_PRINT_ADDR:
126 color_fprintf(stdout, color, " %04x: ", val);
127 break;
128 case BINARY_PRINT_NUM_DATA:
129 color_fprintf(stdout, color, " %02x", val);
130 break;
131 case BINARY_PRINT_NUM_PAD:
132 color_fprintf(stdout, color, " ");
133 break;
134 case BINARY_PRINT_SEP:
135 color_fprintf(stdout, color, " ");
136 break;
137 case BINARY_PRINT_CHAR_DATA:
138 color_fprintf(stdout, color, "%c",
139 isprint(ch) ? ch : '.');
140 break;
141 case BINARY_PRINT_CHAR_PAD:
142 color_fprintf(stdout, color, " ");
143 break;
144 case BINARY_PRINT_LINE_END:
145 color_fprintf(stdout, color, "\n");
146 break;
147 case BINARY_PRINT_DATA_END:
148 printf("\n");
149 break;
150 default:
151 break;
152 }
153}
154
113void trace_event(union perf_event *event) 155void trace_event(union perf_event *event)
114{ 156{
115 unsigned char *raw_event = (void *)event; 157 unsigned char *raw_event = (void *)event;
116 const char *color = PERF_COLOR_BLUE;
117 int i, j;
118 158
119 if (!dump_trace) 159 if (!dump_trace)
120 return; 160 return;
121 161
122 printf("."); 162 print_binary(raw_event, event->header.size, 16,
123 color_fprintf(stdout, color, "\n. ... raw event: size %d bytes\n", 163 trace_event_printer, event);
124 event->header.size);
125
126 for (i = 0; i < event->header.size; i++) {
127 if ((i & 15) == 0) {
128 printf(".");
129 color_fprintf(stdout, color, " %04x: ", i);
130 }
131
132 color_fprintf(stdout, color, " %02x", raw_event[i]);
133
134 if (((i & 15) == 15) || i == event->header.size-1) {
135 color_fprintf(stdout, color, " ");
136 for (j = 0; j < 15-(i & 15); j++)
137 color_fprintf(stdout, color, " ");
138 for (j = i & ~15; j <= i; j++) {
139 color_fprintf(stdout, color, "%c",
140 isprint(raw_event[j]) ?
141 raw_event[j] : '.');
142 }
143 color_fprintf(stdout, color, "\n");
144 }
145 }
146 printf(".\n");
147} 164}
148 165
149static struct debug_variable { 166static struct debug_variable {
@@ -192,3 +209,23 @@ int perf_debug_option(const char *str)
192 free(s); 209 free(s);
193 return 0; 210 return 0;
194} 211}
212
213#define DEBUG_WRAPPER(__n, __l) \
214static int pr_ ## __n ## _wrapper(const char *fmt, ...) \
215{ \
216 va_list args; \
217 int ret; \
218 \
219 va_start(args, fmt); \
220 ret = veprintf(__l, verbose, fmt, args); \
221 va_end(args); \
222 return ret; \
223}
224
225DEBUG_WRAPPER(warning, 0);
226DEBUG_WRAPPER(debug, 1);
227
228void perf_debug_setup(void)
229{
230 libapi_set_print(pr_warning_wrapper, pr_warning_wrapper, pr_debug_wrapper);
231}
diff --git a/tools/perf/util/debug.h b/tools/perf/util/debug.h
index 8b9a088c32ab..14bafda79eda 100644
--- a/tools/perf/util/debug.h
+++ b/tools/perf/util/debug.h
@@ -53,5 +53,6 @@ int eprintf_time(int level, int var, u64 t, const char *fmt, ...) __attribute__(
53int veprintf(int level, int var, const char *fmt, va_list args); 53int veprintf(int level, int var, const char *fmt, va_list args);
54 54
55int perf_debug_option(const char *str); 55int perf_debug_option(const char *str);
56void perf_debug_setup(void);
56 57
57#endif /* __PERF_DEBUG_H */ 58#endif /* __PERF_DEBUG_H */
diff --git a/tools/perf/util/demangle-java.c b/tools/perf/util/demangle-java.c
new file mode 100644
index 000000000000..3e6062ab2cdd
--- /dev/null
+++ b/tools/perf/util/demangle-java.c
@@ -0,0 +1,199 @@
1#include <sys/types.h>
2#include <stdio.h>
3#include <string.h>
4#include "util.h"
5#include "debug.h"
6#include "symbol.h"
7
8#include "demangle-java.h"
9
10enum {
11 MODE_PREFIX = 0,
12 MODE_CLASS = 1,
13 MODE_FUNC = 2,
14 MODE_TYPE = 3,
15 MODE_CTYPE = 3, /* class arg */
16};
17
18#define BASE_ENT(c, n) [c - 'A']=n
19static const char *base_types['Z' - 'A' + 1] = {
20 BASE_ENT('B', "byte" ),
21 BASE_ENT('C', "char" ),
22 BASE_ENT('D', "double" ),
23 BASE_ENT('F', "float" ),
24 BASE_ENT('I', "int" ),
25 BASE_ENT('J', "long" ),
26 BASE_ENT('S', "short" ),
27 BASE_ENT('Z', "bool" ),
28};
29
30/*
31 * demangle Java symbol between str and end positions and stores
32 * up to maxlen characters into buf. The parser starts in mode.
33 *
34 * Use MODE_PREFIX to process entire prototype till end position
35 * Use MODE_TYPE to process return type if str starts on return type char
36 *
37 * Return:
38 * success: buf
39 * error : NULL
40 */
41static char *
42__demangle_java_sym(const char *str, const char *end, char *buf, int maxlen, int mode)
43{
44 int rlen = 0;
45 int array = 0;
46 int narg = 0;
47 const char *q;
48
49 if (!end)
50 end = str + strlen(str);
51
52 for (q = str; q != end; q++) {
53
54 if (rlen == (maxlen - 1))
55 break;
56
57 switch (*q) {
58 case 'L':
59 if (mode == MODE_PREFIX || mode == MODE_CTYPE) {
60 if (mode == MODE_CTYPE) {
61 if (narg)
62 rlen += scnprintf(buf + rlen, maxlen - rlen, ", ");
63 narg++;
64 }
65 rlen += scnprintf(buf + rlen, maxlen - rlen, "class ");
66 if (mode == MODE_PREFIX)
67 mode = MODE_CLASS;
68 } else
69 buf[rlen++] = *q;
70 break;
71 case 'B':
72 case 'C':
73 case 'D':
74 case 'F':
75 case 'I':
76 case 'J':
77 case 'S':
78 case 'Z':
79 if (mode == MODE_TYPE) {
80 if (narg)
81 rlen += scnprintf(buf + rlen, maxlen - rlen, ", ");
82 rlen += scnprintf(buf + rlen, maxlen - rlen, "%s", base_types[*q - 'A']);
83 while (array--)
84 rlen += scnprintf(buf + rlen, maxlen - rlen, "[]");
85 array = 0;
86 narg++;
87 } else
88 buf[rlen++] = *q;
89 break;
90 case 'V':
91 if (mode == MODE_TYPE) {
92 rlen += scnprintf(buf + rlen, maxlen - rlen, "void");
93 while (array--)
94 rlen += scnprintf(buf + rlen, maxlen - rlen, "[]");
95 array = 0;
96 } else
97 buf[rlen++] = *q;
98 break;
99 case '[':
100 if (mode != MODE_TYPE)
101 goto error;
102 array++;
103 break;
104 case '(':
105 if (mode != MODE_FUNC)
106 goto error;
107 buf[rlen++] = *q;
108 mode = MODE_TYPE;
109 break;
110 case ')':
111 if (mode != MODE_TYPE)
112 goto error;
113 buf[rlen++] = *q;
114 narg = 0;
115 break;
116 case ';':
117 if (mode != MODE_CLASS && mode != MODE_CTYPE)
118 goto error;
119 /* safe because at least one other char to process */
120 if (isalpha(*(q + 1)))
121 rlen += scnprintf(buf + rlen, maxlen - rlen, ".");
122 if (mode == MODE_CLASS)
123 mode = MODE_FUNC;
124 else if (mode == MODE_CTYPE)
125 mode = MODE_TYPE;
126 break;
127 case '/':
128 if (mode != MODE_CLASS && mode != MODE_CTYPE)
129 goto error;
130 rlen += scnprintf(buf + rlen, maxlen - rlen, ".");
131 break;
132 default :
133 buf[rlen++] = *q;
134 }
135 }
136 buf[rlen] = '\0';
137 return buf;
138error:
139 return NULL;
140}
141
142/*
143 * Demangle Java function signature (openJDK, not GCJ)
144 * input:
145 * str: string to parse. String is not modified
146 * flags: comobination of JAVA_DEMANGLE_* flags to modify demangling
147 * return:
148 * if input can be demangled, then a newly allocated string is returned.
149 * if input cannot be demangled, then NULL is returned
150 *
151 * Note: caller is responsible for freeing demangled string
152 */
153char *
154java_demangle_sym(const char *str, int flags)
155{
156 char *buf, *ptr;
157 char *p;
158 size_t len, l1 = 0;
159
160 if (!str)
161 return NULL;
162
163 /* find start of retunr type */
164 p = strrchr(str, ')');
165 if (!p)
166 return NULL;
167
168 /*
169 * expansion factor estimated to 3x
170 */
171 len = strlen(str) * 3 + 1;
172 buf = malloc(len);
173 if (!buf)
174 return NULL;
175
176 buf[0] = '\0';
177 if (!(flags & JAVA_DEMANGLE_NORET)) {
178 /*
179 * get return type first
180 */
181 ptr = __demangle_java_sym(p + 1, NULL, buf, len, MODE_TYPE);
182 if (!ptr)
183 goto error;
184
185 /* add space between return type and function prototype */
186 l1 = strlen(buf);
187 buf[l1++] = ' ';
188 }
189
190 /* process function up to return type */
191 ptr = __demangle_java_sym(str, p + 1, buf + l1, len - l1, MODE_PREFIX);
192 if (!ptr)
193 goto error;
194
195 return buf;
196error:
197 free(buf);
198 return NULL;
199}
diff --git a/tools/perf/util/demangle-java.h b/tools/perf/util/demangle-java.h
new file mode 100644
index 000000000000..a981c1f968fe
--- /dev/null
+++ b/tools/perf/util/demangle-java.h
@@ -0,0 +1,10 @@
1#ifndef __PERF_DEMANGLE_JAVA
2#define __PERF_DEMANGLE_JAVA 1
3/*
4 * demangle function flags
5 */
6#define JAVA_DEMANGLE_NORET 0x1 /* do not process return type */
7
8char * java_demangle_sym(const char *str, int flags);
9
10#endif /* __PERF_DEMANGLE_JAVA */
diff --git a/tools/perf/util/dso.c b/tools/perf/util/dso.c
index e8e9a9dbf5e3..8e6395439ca0 100644
--- a/tools/perf/util/dso.c
+++ b/tools/perf/util/dso.c
@@ -52,6 +52,11 @@ int dso__read_binary_type_filename(const struct dso *dso,
52 debuglink--; 52 debuglink--;
53 if (*debuglink == '/') 53 if (*debuglink == '/')
54 debuglink++; 54 debuglink++;
55
56 ret = -1;
57 if (!is_regular_file(filename))
58 break;
59
55 ret = filename__read_debuglink(filename, debuglink, 60 ret = filename__read_debuglink(filename, debuglink,
56 size - (debuglink - filename)); 61 size - (debuglink - filename));
57 } 62 }
diff --git a/tools/perf/util/env.c b/tools/perf/util/env.c
index 7dd5939dea2e..49a11d9d8b8f 100644
--- a/tools/perf/util/env.c
+++ b/tools/perf/util/env.c
@@ -6,6 +6,8 @@ struct perf_env perf_env;
6 6
7void perf_env__exit(struct perf_env *env) 7void perf_env__exit(struct perf_env *env)
8{ 8{
9 int i;
10
9 zfree(&env->hostname); 11 zfree(&env->hostname);
10 zfree(&env->os_release); 12 zfree(&env->os_release);
11 zfree(&env->version); 13 zfree(&env->version);
@@ -19,6 +21,10 @@ void perf_env__exit(struct perf_env *env)
19 zfree(&env->numa_nodes); 21 zfree(&env->numa_nodes);
20 zfree(&env->pmu_mappings); 22 zfree(&env->pmu_mappings);
21 zfree(&env->cpu); 23 zfree(&env->cpu);
24
25 for (i = 0; i < env->caches_cnt; i++)
26 cpu_cache_level__free(&env->caches[i]);
27 zfree(&env->caches);
22} 28}
23 29
24int perf_env__set_cmdline(struct perf_env *env, int argc, const char *argv[]) 30int perf_env__set_cmdline(struct perf_env *env, int argc, const char *argv[])
@@ -75,3 +81,10 @@ int perf_env__read_cpu_topology_map(struct perf_env *env)
75 env->nr_cpus_avail = nr_cpus; 81 env->nr_cpus_avail = nr_cpus;
76 return 0; 82 return 0;
77} 83}
84
85void cpu_cache_level__free(struct cpu_cache_level *cache)
86{
87 free(cache->type);
88 free(cache->map);
89 free(cache->size);
90}
diff --git a/tools/perf/util/env.h b/tools/perf/util/env.h
index 0132b9557c02..56cffb60a0b4 100644
--- a/tools/perf/util/env.h
+++ b/tools/perf/util/env.h
@@ -1,11 +1,23 @@
1#ifndef __PERF_ENV_H 1#ifndef __PERF_ENV_H
2#define __PERF_ENV_H 2#define __PERF_ENV_H
3 3
4#include <linux/types.h>
5
4struct cpu_topology_map { 6struct cpu_topology_map {
5 int socket_id; 7 int socket_id;
6 int core_id; 8 int core_id;
7}; 9};
8 10
11struct cpu_cache_level {
12 u32 level;
13 u32 line_size;
14 u32 sets;
15 u32 ways;
16 char *type;
17 char *size;
18 char *map;
19};
20
9struct perf_env { 21struct perf_env {
10 char *hostname; 22 char *hostname;
11 char *os_release; 23 char *os_release;
@@ -31,6 +43,8 @@ struct perf_env {
31 char *numa_nodes; 43 char *numa_nodes;
32 char *pmu_mappings; 44 char *pmu_mappings;
33 struct cpu_topology_map *cpu; 45 struct cpu_topology_map *cpu;
46 struct cpu_cache_level *caches;
47 int caches_cnt;
34}; 48};
35 49
36extern struct perf_env perf_env; 50extern struct perf_env perf_env;
@@ -41,4 +55,5 @@ int perf_env__set_cmdline(struct perf_env *env, int argc, const char *argv[]);
41 55
42int perf_env__read_cpu_topology_map(struct perf_env *env); 56int perf_env__read_cpu_topology_map(struct perf_env *env);
43 57
58void cpu_cache_level__free(struct cpu_cache_level *cache);
44#endif /* __PERF_ENV_H */ 59#endif /* __PERF_ENV_H */
diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c
index 85155e91b61b..7bad5c3fa7b7 100644
--- a/tools/perf/util/event.c
+++ b/tools/perf/util/event.c
@@ -282,7 +282,7 @@ int perf_event__synthesize_mmap_events(struct perf_tool *tool,
282 strcpy(execname, ""); 282 strcpy(execname, "");
283 283
284 /* 00400000-0040c000 r-xp 00000000 fd:01 41038 /bin/cat */ 284 /* 00400000-0040c000 r-xp 00000000 fd:01 41038 /bin/cat */
285 n = sscanf(bf, "%"PRIx64"-%"PRIx64" %s %"PRIx64" %x:%x %u %s\n", 285 n = sscanf(bf, "%"PRIx64"-%"PRIx64" %s %"PRIx64" %x:%x %u %[^\n]\n",
286 &event->mmap2.start, &event->mmap2.len, prot, 286 &event->mmap2.start, &event->mmap2.len, prot,
287 &event->mmap2.pgoff, &event->mmap2.maj, 287 &event->mmap2.pgoff, &event->mmap2.maj,
288 &event->mmap2.min, 288 &event->mmap2.min,
diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c
index d81f13de2476..86a03836a83f 100644
--- a/tools/perf/util/evlist.c
+++ b/tools/perf/util/evlist.c
@@ -1181,12 +1181,12 @@ void perf_evlist__set_maps(struct perf_evlist *evlist, struct cpu_map *cpus,
1181 */ 1181 */
1182 if (cpus != evlist->cpus) { 1182 if (cpus != evlist->cpus) {
1183 cpu_map__put(evlist->cpus); 1183 cpu_map__put(evlist->cpus);
1184 evlist->cpus = cpus; 1184 evlist->cpus = cpu_map__get(cpus);
1185 } 1185 }
1186 1186
1187 if (threads != evlist->threads) { 1187 if (threads != evlist->threads) {
1188 thread_map__put(evlist->threads); 1188 thread_map__put(evlist->threads);
1189 evlist->threads = threads; 1189 evlist->threads = thread_map__get(threads);
1190 } 1190 }
1191 1191
1192 perf_evlist__propagate_maps(evlist); 1192 perf_evlist__propagate_maps(evlist);
@@ -1223,6 +1223,9 @@ int perf_evlist__set_filter(struct perf_evlist *evlist, const char *filter)
1223 int err = 0; 1223 int err = 0;
1224 1224
1225 evlist__for_each(evlist, evsel) { 1225 evlist__for_each(evlist, evsel) {
1226 if (evsel->attr.type != PERF_TYPE_TRACEPOINT)
1227 continue;
1228
1226 err = perf_evsel__set_filter(evsel, filter); 1229 err = perf_evsel__set_filter(evsel, filter);
1227 if (err) 1230 if (err)
1228 break; 1231 break;
@@ -1624,7 +1627,7 @@ size_t perf_evlist__fprintf(struct perf_evlist *evlist, FILE *fp)
1624 return printed + fprintf(fp, "\n"); 1627 return printed + fprintf(fp, "\n");
1625} 1628}
1626 1629
1627int perf_evlist__strerror_open(struct perf_evlist *evlist __maybe_unused, 1630int perf_evlist__strerror_open(struct perf_evlist *evlist,
1628 int err, char *buf, size_t size) 1631 int err, char *buf, size_t size)
1629{ 1632{
1630 int printed, value; 1633 int printed, value;
@@ -1652,7 +1655,25 @@ int perf_evlist__strerror_open(struct perf_evlist *evlist __maybe_unused,
1652 "Hint:\tTry: 'sudo sh -c \"echo -1 > /proc/sys/kernel/perf_event_paranoid\"'\n" 1655 "Hint:\tTry: 'sudo sh -c \"echo -1 > /proc/sys/kernel/perf_event_paranoid\"'\n"
1653 "Hint:\tThe current value is %d.", value); 1656 "Hint:\tThe current value is %d.", value);
1654 break; 1657 break;
1658 case EINVAL: {
1659 struct perf_evsel *first = perf_evlist__first(evlist);
1660 int max_freq;
1661
1662 if (sysctl__read_int("kernel/perf_event_max_sample_rate", &max_freq) < 0)
1663 goto out_default;
1664
1665 if (first->attr.sample_freq < (u64)max_freq)
1666 goto out_default;
1667
1668 printed = scnprintf(buf, size,
1669 "Error:\t%s.\n"
1670 "Hint:\tCheck /proc/sys/kernel/perf_event_max_sample_rate.\n"
1671 "Hint:\tThe current value is %d and %" PRIu64 " is being requested.",
1672 emsg, max_freq, first->attr.sample_freq);
1673 break;
1674 }
1655 default: 1675 default:
1676out_default:
1656 scnprintf(buf, size, "%s", emsg); 1677 scnprintf(buf, size, "%s", emsg);
1657 break; 1678 break;
1658 } 1679 }
@@ -1723,3 +1744,19 @@ void perf_evlist__set_tracking_event(struct perf_evlist *evlist,
1723 1744
1724 tracking_evsel->tracking = true; 1745 tracking_evsel->tracking = true;
1725} 1746}
1747
1748struct perf_evsel *
1749perf_evlist__find_evsel_by_str(struct perf_evlist *evlist,
1750 const char *str)
1751{
1752 struct perf_evsel *evsel;
1753
1754 evlist__for_each(evlist, evsel) {
1755 if (!evsel->name)
1756 continue;
1757 if (strcmp(str, evsel->name) == 0)
1758 return evsel;
1759 }
1760
1761 return NULL;
1762}
diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h
index 7c4d9a206776..a0d15221db6e 100644
--- a/tools/perf/util/evlist.h
+++ b/tools/perf/util/evlist.h
@@ -294,4 +294,7 @@ void perf_evlist__set_tracking_event(struct perf_evlist *evlist,
294 struct perf_evsel *tracking_evsel); 294 struct perf_evsel *tracking_evsel);
295 295
296void perf_event_attr__set_max_precise_ip(struct perf_event_attr *attr); 296void perf_event_attr__set_max_precise_ip(struct perf_event_attr *attr);
297
298struct perf_evsel *
299perf_evlist__find_evsel_by_str(struct perf_evlist *evlist, const char *str);
297#endif /* __PERF_EVLIST_H */ 300#endif /* __PERF_EVLIST_H */
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c
index cdbaf9b51e42..0902fe418754 100644
--- a/tools/perf/util/evsel.c
+++ b/tools/perf/util/evsel.c
@@ -225,6 +225,11 @@ struct perf_evsel *perf_evsel__new_idx(struct perf_event_attr *attr, int idx)
225 if (evsel != NULL) 225 if (evsel != NULL)
226 perf_evsel__init(evsel, attr, idx); 226 perf_evsel__init(evsel, attr, idx);
227 227
228 if (perf_evsel__is_bpf_output(evsel)) {
229 evsel->attr.sample_type |= PERF_SAMPLE_RAW;
230 evsel->attr.sample_period = 1;
231 }
232
228 return evsel; 233 return evsel;
229} 234}
230 235
@@ -898,6 +903,16 @@ void perf_evsel__config(struct perf_evsel *evsel, struct record_opts *opts)
898 if (evsel->precise_max) 903 if (evsel->precise_max)
899 perf_event_attr__set_max_precise_ip(attr); 904 perf_event_attr__set_max_precise_ip(attr);
900 905
906 if (opts->all_user) {
907 attr->exclude_kernel = 1;
908 attr->exclude_user = 0;
909 }
910
911 if (opts->all_kernel) {
912 attr->exclude_kernel = 0;
913 attr->exclude_user = 1;
914 }
915
901 /* 916 /*
902 * Apply event specific term settings, 917 * Apply event specific term settings,
903 * it overloads any global configuration. 918 * it overloads any global configuration.
@@ -2362,12 +2377,15 @@ int perf_evsel__open_strerror(struct perf_evsel *evsel, struct target *target,
2362 case EPERM: 2377 case EPERM:
2363 case EACCES: 2378 case EACCES:
2364 return scnprintf(msg, size, 2379 return scnprintf(msg, size,
2365 "You may not have permission to collect %sstats.\n" 2380 "You may not have permission to collect %sstats.\n\n"
2366 "Consider tweaking /proc/sys/kernel/perf_event_paranoid:\n" 2381 "Consider tweaking /proc/sys/kernel/perf_event_paranoid,\n"
2367 " -1 - Not paranoid at all\n" 2382 "which controls use of the performance events system by\n"
2368 " 0 - Disallow raw tracepoint access for unpriv\n" 2383 "unprivileged users (without CAP_SYS_ADMIN).\n\n"
2369 " 1 - Disallow cpu events for unpriv\n" 2384 "The default value is 1:\n\n"
2370 " 2 - Disallow kernel profiling for unpriv", 2385 " -1: Allow use of (almost) all events by all users\n"
2386 ">= 0: Disallow raw tracepoint access by users without CAP_IOC_LOCK\n"
2387 ">= 1: Disallow CPU event access by users without CAP_SYS_ADMIN\n"
2388 ">= 2: Disallow kernel profiling by users without CAP_SYS_ADMIN",
2371 target->system_wide ? "system-wide " : ""); 2389 target->system_wide ? "system-wide " : "");
2372 case ENOENT: 2390 case ENOENT:
2373 return scnprintf(msg, size, "The %s event is not supported.", 2391 return scnprintf(msg, size, "The %s event is not supported.",
diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h
index 8e75434bd01c..501ea6e565f1 100644
--- a/tools/perf/util/evsel.h
+++ b/tools/perf/util/evsel.h
@@ -93,10 +93,8 @@ struct perf_evsel {
93 const char *unit; 93 const char *unit;
94 struct event_format *tp_format; 94 struct event_format *tp_format;
95 off_t id_offset; 95 off_t id_offset;
96 union { 96 void *priv;
97 void *priv; 97 u64 db_id;
98 u64 db_id;
99 };
100 struct cgroup_sel *cgrp; 98 struct cgroup_sel *cgrp;
101 void *handler; 99 void *handler;
102 struct cpu_map *cpus; 100 struct cpu_map *cpus;
@@ -364,6 +362,14 @@ static inline bool perf_evsel__is_function_event(struct perf_evsel *evsel)
364#undef FUNCTION_EVENT 362#undef FUNCTION_EVENT
365} 363}
366 364
365static inline bool perf_evsel__is_bpf_output(struct perf_evsel *evsel)
366{
367 struct perf_event_attr *attr = &evsel->attr;
368
369 return (attr->config == PERF_COUNT_SW_BPF_OUTPUT) &&
370 (attr->type == PERF_TYPE_SOFTWARE);
371}
372
367struct perf_attr_details { 373struct perf_attr_details {
368 bool freq; 374 bool freq;
369 bool verbose; 375 bool verbose;
diff --git a/tools/perf/util/genelf.c b/tools/perf/util/genelf.c
new file mode 100644
index 000000000000..c1ef805c6a8f
--- /dev/null
+++ b/tools/perf/util/genelf.c
@@ -0,0 +1,449 @@
1/*
2 * genelf.c
3 * Copyright (C) 2014, Google, Inc
4 *
5 * Contributed by:
6 * Stephane Eranian <eranian@gmail.com>
7 *
8 * Released under the GPL v2. (and only v2, not any later version)
9 */
10
11#include <sys/types.h>
12#include <stdio.h>
13#include <getopt.h>
14#include <stddef.h>
15#include <libelf.h>
16#include <string.h>
17#include <stdlib.h>
18#include <inttypes.h>
19#include <limits.h>
20#include <fcntl.h>
21#include <err.h>
22#include <dwarf.h>
23
24#include "perf.h"
25#include "genelf.h"
26#include "../util/jitdump.h"
27
28#define JVMTI
29
30#define BUILD_ID_URANDOM /* different uuid for each run */
31
32#ifdef HAVE_LIBCRYPTO
33
34#define BUILD_ID_MD5
35#undef BUILD_ID_SHA /* does not seem to work well when linked with Java */
36#undef BUILD_ID_URANDOM /* different uuid for each run */
37
38#ifdef BUILD_ID_SHA
39#include <openssl/sha.h>
40#endif
41
42#ifdef BUILD_ID_MD5
43#include <openssl/md5.h>
44#endif
45#endif
46
47
48typedef struct {
49 unsigned int namesz; /* Size of entry's owner string */
50 unsigned int descsz; /* Size of the note descriptor */
51 unsigned int type; /* Interpretation of the descriptor */
52 char name[0]; /* Start of the name+desc data */
53} Elf_Note;
54
55struct options {
56 char *output;
57 int fd;
58};
59
60static char shd_string_table[] = {
61 0,
62 '.', 't', 'e', 'x', 't', 0, /* 1 */
63 '.', 's', 'h', 's', 't', 'r', 't', 'a', 'b', 0, /* 7 */
64 '.', 's', 'y', 'm', 't', 'a', 'b', 0, /* 17 */
65 '.', 's', 't', 'r', 't', 'a', 'b', 0, /* 25 */
66 '.', 'n', 'o', 't', 'e', '.', 'g', 'n', 'u', '.', 'b', 'u', 'i', 'l', 'd', '-', 'i', 'd', 0, /* 33 */
67 '.', 'd', 'e', 'b', 'u', 'g', '_', 'l', 'i', 'n', 'e', 0, /* 52 */
68 '.', 'd', 'e', 'b', 'u', 'g', '_', 'i', 'n', 'f', 'o', 0, /* 64 */
69 '.', 'd', 'e', 'b', 'u', 'g', '_', 'a', 'b', 'b', 'r', 'e', 'v', 0, /* 76 */
70};
71
72static struct buildid_note {
73 Elf_Note desc; /* descsz: size of build-id, must be multiple of 4 */
74 char name[4]; /* GNU\0 */
75 char build_id[20];
76} bnote;
77
78static Elf_Sym symtab[]={
79 /* symbol 0 MUST be the undefined symbol */
80 { .st_name = 0, /* index in sym_string table */
81 .st_info = ELF_ST_TYPE(STT_NOTYPE),
82 .st_shndx = 0, /* for now */
83 .st_value = 0x0,
84 .st_other = ELF_ST_VIS(STV_DEFAULT),
85 .st_size = 0,
86 },
87 { .st_name = 1, /* index in sym_string table */
88 .st_info = ELF_ST_BIND(STB_LOCAL) | ELF_ST_TYPE(STT_FUNC),
89 .st_shndx = 1,
90 .st_value = 0, /* for now */
91 .st_other = ELF_ST_VIS(STV_DEFAULT),
92 .st_size = 0, /* for now */
93 }
94};
95
96#ifdef BUILD_ID_URANDOM
97static void
98gen_build_id(struct buildid_note *note,
99 unsigned long load_addr __maybe_unused,
100 const void *code __maybe_unused,
101 size_t csize __maybe_unused)
102{
103 int fd;
104 size_t sz = sizeof(note->build_id);
105 ssize_t sret;
106
107 fd = open("/dev/urandom", O_RDONLY);
108 if (fd == -1)
109 err(1, "cannot access /dev/urandom for builid");
110
111 sret = read(fd, note->build_id, sz);
112
113 close(fd);
114
115 if (sret != (ssize_t)sz)
116 memset(note->build_id, 0, sz);
117}
118#endif
119
120#ifdef BUILD_ID_SHA
121static void
122gen_build_id(struct buildid_note *note,
123 unsigned long load_addr __maybe_unused,
124 const void *code,
125 size_t csize)
126{
127 if (sizeof(note->build_id) < SHA_DIGEST_LENGTH)
128 errx(1, "build_id too small for SHA1");
129
130 SHA1(code, csize, (unsigned char *)note->build_id);
131}
132#endif
133
134#ifdef BUILD_ID_MD5
135static void
136gen_build_id(struct buildid_note *note, unsigned long load_addr, const void *code, size_t csize)
137{
138 MD5_CTX context;
139
140 if (sizeof(note->build_id) < 16)
141 errx(1, "build_id too small for MD5");
142
143 MD5_Init(&context);
144 MD5_Update(&context, &load_addr, sizeof(load_addr));
145 MD5_Update(&context, code, csize);
146 MD5_Final((unsigned char *)note->build_id, &context);
147}
148#endif
149
150/*
151 * fd: file descriptor open for writing for the output file
152 * load_addr: code load address (could be zero, just used for buildid)
153 * sym: function name (for native code - used as the symbol)
154 * code: the native code
155 * csize: the code size in bytes
156 */
157int
158jit_write_elf(int fd, uint64_t load_addr, const char *sym,
159 const void *code, int csize,
160 void *debug, int nr_debug_entries)
161{
162 Elf *e;
163 Elf_Data *d;
164 Elf_Scn *scn;
165 Elf_Ehdr *ehdr;
166 Elf_Shdr *shdr;
167 char *strsym = NULL;
168 int symlen;
169 int retval = -1;
170
171 if (elf_version(EV_CURRENT) == EV_NONE) {
172 warnx("ELF initialization failed");
173 return -1;
174 }
175
176 e = elf_begin(fd, ELF_C_WRITE, NULL);
177 if (!e) {
178 warnx("elf_begin failed");
179 goto error;
180 }
181
182 /*
183 * setup ELF header
184 */
185 ehdr = elf_newehdr(e);
186 if (!ehdr) {
187 warnx("cannot get ehdr");
188 goto error;
189 }
190
191 ehdr->e_ident[EI_DATA] = GEN_ELF_ENDIAN;
192 ehdr->e_ident[EI_CLASS] = GEN_ELF_CLASS;
193 ehdr->e_machine = GEN_ELF_ARCH;
194 ehdr->e_type = ET_DYN;
195 ehdr->e_entry = GEN_ELF_TEXT_OFFSET;
196 ehdr->e_version = EV_CURRENT;
197 ehdr->e_shstrndx= 2; /* shdr index for section name */
198
199 /*
200 * setup text section
201 */
202 scn = elf_newscn(e);
203 if (!scn) {
204 warnx("cannot create section");
205 goto error;
206 }
207
208 d = elf_newdata(scn);
209 if (!d) {
210 warnx("cannot get new data");
211 goto error;
212 }
213
214 d->d_align = 16;
215 d->d_off = 0LL;
216 d->d_buf = (void *)code;
217 d->d_type = ELF_T_BYTE;
218 d->d_size = csize;
219 d->d_version = EV_CURRENT;
220
221 shdr = elf_getshdr(scn);
222 if (!shdr) {
223 warnx("cannot get section header");
224 goto error;
225 }
226
227 shdr->sh_name = 1;
228 shdr->sh_type = SHT_PROGBITS;
229 shdr->sh_addr = GEN_ELF_TEXT_OFFSET;
230 shdr->sh_flags = SHF_EXECINSTR | SHF_ALLOC;
231 shdr->sh_entsize = 0;
232
233 /*
234 * setup section headers string table
235 */
236 scn = elf_newscn(e);
237 if (!scn) {
238 warnx("cannot create section");
239 goto error;
240 }
241
242 d = elf_newdata(scn);
243 if (!d) {
244 warnx("cannot get new data");
245 goto error;
246 }
247
248 d->d_align = 1;
249 d->d_off = 0LL;
250 d->d_buf = shd_string_table;
251 d->d_type = ELF_T_BYTE;
252 d->d_size = sizeof(shd_string_table);
253 d->d_version = EV_CURRENT;
254
255 shdr = elf_getshdr(scn);
256 if (!shdr) {
257 warnx("cannot get section header");
258 goto error;
259 }
260
261 shdr->sh_name = 7; /* offset of '.shstrtab' in shd_string_table */
262 shdr->sh_type = SHT_STRTAB;
263 shdr->sh_flags = 0;
264 shdr->sh_entsize = 0;
265
266 /*
267 * setup symtab section
268 */
269 symtab[1].st_size = csize;
270 symtab[1].st_value = GEN_ELF_TEXT_OFFSET;
271
272 scn = elf_newscn(e);
273 if (!scn) {
274 warnx("cannot create section");
275 goto error;
276 }
277
278 d = elf_newdata(scn);
279 if (!d) {
280 warnx("cannot get new data");
281 goto error;
282 }
283
284 d->d_align = 8;
285 d->d_off = 0LL;
286 d->d_buf = symtab;
287 d->d_type = ELF_T_SYM;
288 d->d_size = sizeof(symtab);
289 d->d_version = EV_CURRENT;
290
291 shdr = elf_getshdr(scn);
292 if (!shdr) {
293 warnx("cannot get section header");
294 goto error;
295 }
296
297 shdr->sh_name = 17; /* offset of '.symtab' in shd_string_table */
298 shdr->sh_type = SHT_SYMTAB;
299 shdr->sh_flags = 0;
300 shdr->sh_entsize = sizeof(Elf_Sym);
301 shdr->sh_link = 4; /* index of .strtab section */
302
303 /*
304 * setup symbols string table
305 * 2 = 1 for 0 in 1st entry, 1 for the 0 at end of symbol for 2nd entry
306 */
307 symlen = 2 + strlen(sym);
308 strsym = calloc(1, symlen);
309 if (!strsym) {
310 warnx("cannot allocate strsym");
311 goto error;
312 }
313 strcpy(strsym + 1, sym);
314
315 scn = elf_newscn(e);
316 if (!scn) {
317 warnx("cannot create section");
318 goto error;
319 }
320
321 d = elf_newdata(scn);
322 if (!d) {
323 warnx("cannot get new data");
324 goto error;
325 }
326
327 d->d_align = 1;
328 d->d_off = 0LL;
329 d->d_buf = strsym;
330 d->d_type = ELF_T_BYTE;
331 d->d_size = symlen;
332 d->d_version = EV_CURRENT;
333
334 shdr = elf_getshdr(scn);
335 if (!shdr) {
336 warnx("cannot get section header");
337 goto error;
338 }
339
340 shdr->sh_name = 25; /* offset in shd_string_table */
341 shdr->sh_type = SHT_STRTAB;
342 shdr->sh_flags = 0;
343 shdr->sh_entsize = 0;
344
345 /*
346 * setup build-id section
347 */
348 scn = elf_newscn(e);
349 if (!scn) {
350 warnx("cannot create section");
351 goto error;
352 }
353
354 d = elf_newdata(scn);
355 if (!d) {
356 warnx("cannot get new data");
357 goto error;
358 }
359
360 /*
361 * build-id generation
362 */
363 gen_build_id(&bnote, load_addr, code, csize);
364 bnote.desc.namesz = sizeof(bnote.name); /* must include 0 termination */
365 bnote.desc.descsz = sizeof(bnote.build_id);
366 bnote.desc.type = NT_GNU_BUILD_ID;
367 strcpy(bnote.name, "GNU");
368
369 d->d_align = 4;
370 d->d_off = 0LL;
371 d->d_buf = &bnote;
372 d->d_type = ELF_T_BYTE;
373 d->d_size = sizeof(bnote);
374 d->d_version = EV_CURRENT;
375
376 shdr = elf_getshdr(scn);
377 if (!shdr) {
378 warnx("cannot get section header");
379 goto error;
380 }
381
382 shdr->sh_name = 33; /* offset in shd_string_table */
383 shdr->sh_type = SHT_NOTE;
384 shdr->sh_addr = 0x0;
385 shdr->sh_flags = SHF_ALLOC;
386 shdr->sh_size = sizeof(bnote);
387 shdr->sh_entsize = 0;
388
389 if (debug && nr_debug_entries) {
390 retval = jit_add_debug_info(e, load_addr, debug, nr_debug_entries);
391 if (retval)
392 goto error;
393 } else {
394 if (elf_update(e, ELF_C_WRITE) < 0) {
395 warnx("elf_update 4 failed");
396 goto error;
397 }
398 }
399
400 retval = 0;
401error:
402 (void)elf_end(e);
403
404 free(strsym);
405
406
407 return retval;
408}
409
410#ifndef JVMTI
411
412static unsigned char x86_code[] = {
413 0xBB, 0x2A, 0x00, 0x00, 0x00, /* movl $42, %ebx */
414 0xB8, 0x01, 0x00, 0x00, 0x00, /* movl $1, %eax */
415 0xCD, 0x80 /* int $0x80 */
416};
417
418static struct options options;
419
420int main(int argc, char **argv)
421{
422 int c, fd, ret;
423
424 while ((c = getopt(argc, argv, "o:h")) != -1) {
425 switch (c) {
426 case 'o':
427 options.output = optarg;
428 break;
429 case 'h':
430 printf("Usage: genelf -o output_file [-h]\n");
431 return 0;
432 default:
433 errx(1, "unknown option");
434 }
435 }
436
437 fd = open(options.output, O_CREAT|O_TRUNC|O_RDWR, 0666);
438 if (fd == -1)
439 err(1, "cannot create file %s", options.output);
440
441 ret = jit_write_elf(fd, "main", x86_code, sizeof(x86_code));
442 close(fd);
443
444 if (ret != 0)
445 unlink(options.output);
446
447 return ret;
448}
449#endif
diff --git a/tools/perf/util/genelf.h b/tools/perf/util/genelf.h
new file mode 100644
index 000000000000..45bf9c6d3257
--- /dev/null
+++ b/tools/perf/util/genelf.h
@@ -0,0 +1,67 @@
1#ifndef __GENELF_H__
2#define __GENELF_H__
3
4/* genelf.c */
5extern int jit_write_elf(int fd, uint64_t code_addr, const char *sym,
6 const void *code, int csize,
7 void *debug, int nr_debug_entries);
8/* genelf_debug.c */
9extern int jit_add_debug_info(Elf *e, uint64_t code_addr,
10 void *debug, int nr_debug_entries);
11
12#if defined(__arm__)
13#define GEN_ELF_ARCH EM_ARM
14#define GEN_ELF_ENDIAN ELFDATA2LSB
15#define GEN_ELF_CLASS ELFCLASS32
16#elif defined(__aarch64__)
17#define GEN_ELF_ARCH EM_AARCH64
18#define GEN_ELF_ENDIAN ELFDATA2LSB
19#define GEN_ELF_CLASS ELFCLASS64
20#elif defined(__x86_64__)
21#define GEN_ELF_ARCH EM_X86_64
22#define GEN_ELF_ENDIAN ELFDATA2LSB
23#define GEN_ELF_CLASS ELFCLASS64
24#elif defined(__i386__)
25#define GEN_ELF_ARCH EM_386
26#define GEN_ELF_ENDIAN ELFDATA2LSB
27#define GEN_ELF_CLASS ELFCLASS32
28#elif defined(__ppcle__)
29#define GEN_ELF_ARCH EM_PPC
30#define GEN_ELF_ENDIAN ELFDATA2LSB
31#define GEN_ELF_CLASS ELFCLASS64
32#elif defined(__powerpc__)
33#define GEN_ELF_ARCH EM_PPC64
34#define GEN_ELF_ENDIAN ELFDATA2MSB
35#define GEN_ELF_CLASS ELFCLASS64
36#elif defined(__powerpcle__)
37#define GEN_ELF_ARCH EM_PPC64
38#define GEN_ELF_ENDIAN ELFDATA2LSB
39#define GEN_ELF_CLASS ELFCLASS64
40#else
41#error "unsupported architecture"
42#endif
43
44#if GEN_ELF_CLASS == ELFCLASS64
45#define elf_newehdr elf64_newehdr
46#define elf_getshdr elf64_getshdr
47#define Elf_Ehdr Elf64_Ehdr
48#define Elf_Shdr Elf64_Shdr
49#define Elf_Sym Elf64_Sym
50#define ELF_ST_TYPE(a) ELF64_ST_TYPE(a)
51#define ELF_ST_BIND(a) ELF64_ST_BIND(a)
52#define ELF_ST_VIS(a) ELF64_ST_VISIBILITY(a)
53#else
54#define elf_newehdr elf32_newehdr
55#define elf_getshdr elf32_getshdr
56#define Elf_Ehdr Elf32_Ehdr
57#define Elf_Shdr Elf32_Shdr
58#define Elf_Sym Elf32_Sym
59#define ELF_ST_TYPE(a) ELF32_ST_TYPE(a)
60#define ELF_ST_BIND(a) ELF32_ST_BIND(a)
61#define ELF_ST_VIS(a) ELF32_ST_VISIBILITY(a)
62#endif
63
64/* The .text section is directly after the ELF header */
65#define GEN_ELF_TEXT_OFFSET sizeof(Elf_Ehdr)
66
67#endif
diff --git a/tools/perf/util/genelf_debug.c b/tools/perf/util/genelf_debug.c
new file mode 100644
index 000000000000..5980f7d256b1
--- /dev/null
+++ b/tools/perf/util/genelf_debug.c
@@ -0,0 +1,610 @@
1/*
2 * genelf_debug.c
3 * Copyright (C) 2015, Google, Inc
4 *
5 * Contributed by:
6 * Stephane Eranian <eranian@google.com>
7 *
8 * Released under the GPL v2.
9 *
10 * based on GPLv2 source code from Oprofile
11 * @remark Copyright 2007 OProfile authors
12 * @author Philippe Elie
13 */
14#include <sys/types.h>
15#include <stdio.h>
16#include <getopt.h>
17#include <stddef.h>
18#include <libelf.h>
19#include <string.h>
20#include <stdlib.h>
21#include <inttypes.h>
22#include <limits.h>
23#include <fcntl.h>
24#include <err.h>
25#include <dwarf.h>
26
27#include "perf.h"
28#include "genelf.h"
29#include "../util/jitdump.h"
30
31#define BUFFER_EXT_DFL_SIZE (4 * 1024)
32
33typedef uint32_t uword;
34typedef uint16_t uhalf;
35typedef int32_t sword;
36typedef int16_t shalf;
37typedef uint8_t ubyte;
38typedef int8_t sbyte;
39
40struct buffer_ext {
41 size_t cur_pos;
42 size_t max_sz;
43 void *data;
44};
45
46static void
47buffer_ext_dump(struct buffer_ext *be, const char *msg)
48{
49 size_t i;
50 warnx("DUMP for %s", msg);
51 for (i = 0 ; i < be->cur_pos; i++)
52 warnx("%4zu 0x%02x", i, (((char *)be->data)[i]) & 0xff);
53}
54
55static inline int
56buffer_ext_add(struct buffer_ext *be, void *addr, size_t sz)
57{
58 void *tmp;
59 size_t be_sz = be->max_sz;
60
61retry:
62 if ((be->cur_pos + sz) < be_sz) {
63 memcpy(be->data + be->cur_pos, addr, sz);
64 be->cur_pos += sz;
65 return 0;
66 }
67
68 if (!be_sz)
69 be_sz = BUFFER_EXT_DFL_SIZE;
70 else
71 be_sz <<= 1;
72
73 tmp = realloc(be->data, be_sz);
74 if (!tmp)
75 return -1;
76
77 be->data = tmp;
78 be->max_sz = be_sz;
79
80 goto retry;
81}
82
83static void
84buffer_ext_init(struct buffer_ext *be)
85{
86 be->data = NULL;
87 be->cur_pos = 0;
88 be->max_sz = 0;
89}
90
91static inline size_t
92buffer_ext_size(struct buffer_ext *be)
93{
94 return be->cur_pos;
95}
96
97static inline void *
98buffer_ext_addr(struct buffer_ext *be)
99{
100 return be->data;
101}
102
103struct debug_line_header {
104 // Not counting this field
105 uword total_length;
106 // version number (2 currently)
107 uhalf version;
108 // relative offset from next field to
109 // program statement
110 uword prolog_length;
111 ubyte minimum_instruction_length;
112 ubyte default_is_stmt;
113 // line_base - see DWARF 2 specs
114 sbyte line_base;
115 // line_range - see DWARF 2 specs
116 ubyte line_range;
117 // number of opcode + 1
118 ubyte opcode_base;
119 /* follow the array of opcode args nr: ubytes [nr_opcode_base] */
120 /* follow the search directories index, zero terminated string
121 * terminated by an empty string.
122 */
123 /* follow an array of { filename, LEB128, LEB128, LEB128 }, first is
124 * the directory index entry, 0 means current directory, then mtime
125 * and filesize, last entry is followed by en empty string.
126 */
127 /* follow the first program statement */
128} __attribute__((packed));
129
130/* DWARF 2 spec talk only about one possible compilation unit header while
131 * binutils can handle two flavours of dwarf 2, 32 and 64 bits, this is not
132 * related to the used arch, an ELF 32 can hold more than 4 Go of debug
133 * information. For now we handle only DWARF 2 32 bits comp unit. It'll only
134 * become a problem if we generate more than 4GB of debug information.
135 */
136struct compilation_unit_header {
137 uword total_length;
138 uhalf version;
139 uword debug_abbrev_offset;
140 ubyte pointer_size;
141} __attribute__((packed));
142
143#define DW_LNS_num_opcode (DW_LNS_set_isa + 1)
144
145/* field filled at run time are marked with -1 */
146static struct debug_line_header const default_debug_line_header = {
147 .total_length = -1,
148 .version = 2,
149 .prolog_length = -1,
150 .minimum_instruction_length = 1, /* could be better when min instruction size != 1 */
151 .default_is_stmt = 1, /* we don't take care about basic block */
152 .line_base = -5, /* sensible value for line base ... */
153 .line_range = -14, /* ... and line range are guessed statically */
154 .opcode_base = DW_LNS_num_opcode
155};
156
157static ubyte standard_opcode_length[] =
158{
159 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1
160};
161#if 0
162{
163 [DW_LNS_advance_pc] = 1,
164 [DW_LNS_advance_line] = 1,
165 [DW_LNS_set_file] = 1,
166 [DW_LNS_set_column] = 1,
167 [DW_LNS_fixed_advance_pc] = 1,
168 [DW_LNS_set_isa] = 1,
169};
170#endif
171
172/* field filled at run time are marked with -1 */
173static struct compilation_unit_header default_comp_unit_header = {
174 .total_length = -1,
175 .version = 2,
176 .debug_abbrev_offset = 0, /* we reuse the same abbrev entries for all comp unit */
177 .pointer_size = sizeof(void *)
178};
179
180static void emit_uword(struct buffer_ext *be, uword data)
181{
182 buffer_ext_add(be, &data, sizeof(uword));
183}
184
185static void emit_string(struct buffer_ext *be, const char *s)
186{
187 buffer_ext_add(be, (void *)s, strlen(s) + 1);
188}
189
190static void emit_unsigned_LEB128(struct buffer_ext *be,
191 unsigned long data)
192{
193 do {
194 ubyte cur = data & 0x7F;
195 data >>= 7;
196 if (data)
197 cur |= 0x80;
198 buffer_ext_add(be, &cur, 1);
199 } while (data);
200}
201
202static void emit_signed_LEB128(struct buffer_ext *be, long data)
203{
204 int more = 1;
205 int negative = data < 0;
206 int size = sizeof(long) * CHAR_BIT;
207 while (more) {
208 ubyte cur = data & 0x7F;
209 data >>= 7;
210 if (negative)
211 data |= - (1 << (size - 7));
212 if ((data == 0 && !(cur & 0x40)) ||
213 (data == -1l && (cur & 0x40)))
214 more = 0;
215 else
216 cur |= 0x80;
217 buffer_ext_add(be, &cur, 1);
218 }
219}
220
221static void emit_extended_opcode(struct buffer_ext *be, ubyte opcode,
222 void *data, size_t data_len)
223{
224 buffer_ext_add(be, (char *)"", 1);
225
226 emit_unsigned_LEB128(be, data_len + 1);
227
228 buffer_ext_add(be, &opcode, 1);
229 buffer_ext_add(be, data, data_len);
230}
231
232static void emit_opcode(struct buffer_ext *be, ubyte opcode)
233{
234 buffer_ext_add(be, &opcode, 1);
235}
236
237static void emit_opcode_signed(struct buffer_ext *be,
238 ubyte opcode, long data)
239{
240 buffer_ext_add(be, &opcode, 1);
241 emit_signed_LEB128(be, data);
242}
243
244static void emit_opcode_unsigned(struct buffer_ext *be, ubyte opcode,
245 unsigned long data)
246{
247 buffer_ext_add(be, &opcode, 1);
248 emit_unsigned_LEB128(be, data);
249}
250
251static void emit_advance_pc(struct buffer_ext *be, unsigned long delta_pc)
252{
253 emit_opcode_unsigned(be, DW_LNS_advance_pc, delta_pc);
254}
255
256static void emit_advance_lineno(struct buffer_ext *be, long delta_lineno)
257{
258 emit_opcode_signed(be, DW_LNS_advance_line, delta_lineno);
259}
260
261static void emit_lne_end_of_sequence(struct buffer_ext *be)
262{
263 emit_extended_opcode(be, DW_LNE_end_sequence, NULL, 0);
264}
265
266static void emit_set_file(struct buffer_ext *be, unsigned long idx)
267{
268 emit_opcode_unsigned(be, DW_LNS_set_file, idx);
269}
270
271static void emit_lne_define_filename(struct buffer_ext *be,
272 const char *filename)
273{
274 buffer_ext_add(be, (void *)"", 1);
275
276 /* LNE field, strlen(filename) + zero termination, 3 bytes for: the dir entry, timestamp, filesize */
277 emit_unsigned_LEB128(be, strlen(filename) + 5);
278 emit_opcode(be, DW_LNE_define_file);
279 emit_string(be, filename);
280 /* directory index 0=do not know */
281 emit_unsigned_LEB128(be, 0);
282 /* last modification date on file 0=do not know */
283 emit_unsigned_LEB128(be, 0);
284 /* filesize 0=do not know */
285 emit_unsigned_LEB128(be, 0);
286}
287
288static void emit_lne_set_address(struct buffer_ext *be,
289 void *address)
290{
291 emit_extended_opcode(be, DW_LNE_set_address, &address, sizeof(unsigned long));
292}
293
294static ubyte get_special_opcode(struct debug_entry *ent,
295 unsigned int last_line,
296 unsigned long last_vma)
297{
298 unsigned int temp;
299 unsigned long delta_addr;
300
301 /*
302 * delta from line_base
303 */
304 temp = (ent->lineno - last_line) - default_debug_line_header.line_base;
305
306 if (temp >= default_debug_line_header.line_range)
307 return 0;
308
309 /*
310 * delta of addresses
311 */
312 delta_addr = (ent->addr - last_vma) / default_debug_line_header.minimum_instruction_length;
313
314 /* This is not sufficient to ensure opcode will be in [0-256] but
315 * sufficient to ensure when summing with the delta lineno we will
316 * not overflow the unsigned long opcode */
317
318 if (delta_addr <= 256 / default_debug_line_header.line_range) {
319 unsigned long opcode = temp +
320 (delta_addr * default_debug_line_header.line_range) +
321 default_debug_line_header.opcode_base;
322
323 return opcode <= 255 ? opcode : 0;
324 }
325 return 0;
326}
327
328static void emit_lineno_info(struct buffer_ext *be,
329 struct debug_entry *ent, size_t nr_entry,
330 unsigned long code_addr)
331{
332 size_t i;
333
334 /*
335 * Machine state at start of a statement program
336 * address = 0
337 * file = 1
338 * line = 1
339 * column = 0
340 * is_stmt = default_is_stmt as given in the debug_line_header
341 * basic block = 0
342 * end sequence = 0
343 */
344
345 /* start state of the state machine we take care of */
346 unsigned long last_vma = code_addr;
347 char const *cur_filename = NULL;
348 unsigned long cur_file_idx = 0;
349 int last_line = 1;
350
351 emit_lne_set_address(be, (void *)code_addr);
352
353 for (i = 0; i < nr_entry; i++, ent = debug_entry_next(ent)) {
354 int need_copy = 0;
355 ubyte special_opcode;
356
357 /*
358 * check if filename changed, if so add it
359 */
360 if (!cur_filename || strcmp(cur_filename, ent->name)) {
361 emit_lne_define_filename(be, ent->name);
362 cur_filename = ent->name;
363 emit_set_file(be, ++cur_file_idx);
364 need_copy = 1;
365 }
366
367 special_opcode = get_special_opcode(ent, last_line, last_vma);
368 if (special_opcode != 0) {
369 last_line = ent->lineno;
370 last_vma = ent->addr;
371 emit_opcode(be, special_opcode);
372 } else {
373 /*
374 * lines differ, emit line delta
375 */
376 if (last_line != ent->lineno) {
377 emit_advance_lineno(be, ent->lineno - last_line);
378 last_line = ent->lineno;
379 need_copy = 1;
380 }
381 /*
382 * addresses differ, emit address delta
383 */
384 if (last_vma != ent->addr) {
385 emit_advance_pc(be, ent->addr - last_vma);
386 last_vma = ent->addr;
387 need_copy = 1;
388 }
389 /*
390 * add new row to matrix
391 */
392 if (need_copy)
393 emit_opcode(be, DW_LNS_copy);
394 }
395 }
396}
397
398static void add_debug_line(struct buffer_ext *be,
399 struct debug_entry *ent, size_t nr_entry,
400 unsigned long code_addr)
401{
402 struct debug_line_header * dbg_header;
403 size_t old_size;
404
405 old_size = buffer_ext_size(be);
406
407 buffer_ext_add(be, (void *)&default_debug_line_header,
408 sizeof(default_debug_line_header));
409
410 buffer_ext_add(be, &standard_opcode_length, sizeof(standard_opcode_length));
411
412 // empty directory entry
413 buffer_ext_add(be, (void *)"", 1);
414
415 // empty filename directory
416 buffer_ext_add(be, (void *)"", 1);
417
418 dbg_header = buffer_ext_addr(be) + old_size;
419 dbg_header->prolog_length = (buffer_ext_size(be) - old_size) -
420 offsetof(struct debug_line_header, minimum_instruction_length);
421
422 emit_lineno_info(be, ent, nr_entry, code_addr);
423
424 emit_lne_end_of_sequence(be);
425
426 dbg_header = buffer_ext_addr(be) + old_size;
427 dbg_header->total_length = (buffer_ext_size(be) - old_size) -
428 offsetof(struct debug_line_header, version);
429}
430
431static void
432add_debug_abbrev(struct buffer_ext *be)
433{
434 emit_unsigned_LEB128(be, 1);
435 emit_unsigned_LEB128(be, DW_TAG_compile_unit);
436 emit_unsigned_LEB128(be, DW_CHILDREN_yes);
437 emit_unsigned_LEB128(be, DW_AT_stmt_list);
438 emit_unsigned_LEB128(be, DW_FORM_data4);
439 emit_unsigned_LEB128(be, 0);
440 emit_unsigned_LEB128(be, 0);
441 emit_unsigned_LEB128(be, 0);
442}
443
444static void
445add_compilation_unit(struct buffer_ext *be,
446 size_t offset_debug_line)
447{
448 struct compilation_unit_header *comp_unit_header;
449 size_t old_size = buffer_ext_size(be);
450
451 buffer_ext_add(be, &default_comp_unit_header,
452 sizeof(default_comp_unit_header));
453
454 emit_unsigned_LEB128(be, 1);
455 emit_uword(be, offset_debug_line);
456
457 comp_unit_header = buffer_ext_addr(be) + old_size;
458 comp_unit_header->total_length = (buffer_ext_size(be) - old_size) -
459 offsetof(struct compilation_unit_header, version);
460}
461
462static int
463jit_process_debug_info(uint64_t code_addr,
464 void *debug, int nr_debug_entries,
465 struct buffer_ext *dl,
466 struct buffer_ext *da,
467 struct buffer_ext *di)
468{
469 struct debug_entry *ent = debug;
470 int i;
471
472 for (i = 0; i < nr_debug_entries; i++) {
473 ent->addr = ent->addr - code_addr;
474 ent = debug_entry_next(ent);
475 }
476 add_compilation_unit(di, buffer_ext_size(dl));
477 add_debug_line(dl, debug, nr_debug_entries, 0);
478 add_debug_abbrev(da);
479 if (0) buffer_ext_dump(da, "abbrev");
480
481 return 0;
482}
483
484int
485jit_add_debug_info(Elf *e, uint64_t code_addr, void *debug, int nr_debug_entries)
486{
487 Elf_Data *d;
488 Elf_Scn *scn;
489 Elf_Shdr *shdr;
490 struct buffer_ext dl, di, da;
491 int ret;
492
493 buffer_ext_init(&dl);
494 buffer_ext_init(&di);
495 buffer_ext_init(&da);
496
497 ret = jit_process_debug_info(code_addr, debug, nr_debug_entries, &dl, &da, &di);
498 if (ret)
499 return -1;
500 /*
501 * setup .debug_line section
502 */
503 scn = elf_newscn(e);
504 if (!scn) {
505 warnx("cannot create section");
506 return -1;
507 }
508
509 d = elf_newdata(scn);
510 if (!d) {
511 warnx("cannot get new data");
512 return -1;
513 }
514
515 d->d_align = 1;
516 d->d_off = 0LL;
517 d->d_buf = buffer_ext_addr(&dl);
518 d->d_type = ELF_T_BYTE;
519 d->d_size = buffer_ext_size(&dl);
520 d->d_version = EV_CURRENT;
521
522 shdr = elf_getshdr(scn);
523 if (!shdr) {
524 warnx("cannot get section header");
525 return -1;
526 }
527
528 shdr->sh_name = 52; /* .debug_line */
529 shdr->sh_type = SHT_PROGBITS;
530 shdr->sh_addr = 0; /* must be zero or == sh_offset -> dynamic object */
531 shdr->sh_flags = 0;
532 shdr->sh_entsize = 0;
533
534 /*
535 * setup .debug_info section
536 */
537 scn = elf_newscn(e);
538 if (!scn) {
539 warnx("cannot create section");
540 return -1;
541 }
542
543 d = elf_newdata(scn);
544 if (!d) {
545 warnx("cannot get new data");
546 return -1;
547 }
548
549 d->d_align = 1;
550 d->d_off = 0LL;
551 d->d_buf = buffer_ext_addr(&di);
552 d->d_type = ELF_T_BYTE;
553 d->d_size = buffer_ext_size(&di);
554 d->d_version = EV_CURRENT;
555
556 shdr = elf_getshdr(scn);
557 if (!shdr) {
558 warnx("cannot get section header");
559 return -1;
560 }
561
562 shdr->sh_name = 64; /* .debug_info */
563 shdr->sh_type = SHT_PROGBITS;
564 shdr->sh_addr = 0; /* must be zero or == sh_offset -> dynamic object */
565 shdr->sh_flags = 0;
566 shdr->sh_entsize = 0;
567
568 /*
569 * setup .debug_abbrev section
570 */
571 scn = elf_newscn(e);
572 if (!scn) {
573 warnx("cannot create section");
574 return -1;
575 }
576
577 d = elf_newdata(scn);
578 if (!d) {
579 warnx("cannot get new data");
580 return -1;
581 }
582
583 d->d_align = 1;
584 d->d_off = 0LL;
585 d->d_buf = buffer_ext_addr(&da);
586 d->d_type = ELF_T_BYTE;
587 d->d_size = buffer_ext_size(&da);
588 d->d_version = EV_CURRENT;
589
590 shdr = elf_getshdr(scn);
591 if (!shdr) {
592 warnx("cannot get section header");
593 return -1;
594 }
595
596 shdr->sh_name = 76; /* .debug_info */
597 shdr->sh_type = SHT_PROGBITS;
598 shdr->sh_addr = 0; /* must be zero or == sh_offset -> dynamic object */
599 shdr->sh_flags = 0;
600 shdr->sh_entsize = 0;
601
602 /*
603 * now we update the ELF image with all the sections
604 */
605 if (elf_update(e, ELF_C_WRITE) < 0) {
606 warnx("elf_update debug failed");
607 return -1;
608 }
609 return 0;
610}
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
index f50b7235ecb6..73e38e472ecd 100644
--- a/tools/perf/util/header.c
+++ b/tools/perf/util/header.c
@@ -23,6 +23,8 @@
23#include "strbuf.h" 23#include "strbuf.h"
24#include "build-id.h" 24#include "build-id.h"
25#include "data.h" 25#include "data.h"
26#include <api/fs/fs.h>
27#include "asm/bug.h"
26 28
27/* 29/*
28 * magic2 = "PERFILE2" 30 * magic2 = "PERFILE2"
@@ -868,6 +870,199 @@ static int write_auxtrace(int fd, struct perf_header *h,
868 return err; 870 return err;
869} 871}
870 872
873static int cpu_cache_level__sort(const void *a, const void *b)
874{
875 struct cpu_cache_level *cache_a = (struct cpu_cache_level *)a;
876 struct cpu_cache_level *cache_b = (struct cpu_cache_level *)b;
877
878 return cache_a->level - cache_b->level;
879}
880
881static bool cpu_cache_level__cmp(struct cpu_cache_level *a, struct cpu_cache_level *b)
882{
883 if (a->level != b->level)
884 return false;
885
886 if (a->line_size != b->line_size)
887 return false;
888
889 if (a->sets != b->sets)
890 return false;
891
892 if (a->ways != b->ways)
893 return false;
894
895 if (strcmp(a->type, b->type))
896 return false;
897
898 if (strcmp(a->size, b->size))
899 return false;
900
901 if (strcmp(a->map, b->map))
902 return false;
903
904 return true;
905}
906
907static int cpu_cache_level__read(struct cpu_cache_level *cache, u32 cpu, u16 level)
908{
909 char path[PATH_MAX], file[PATH_MAX];
910 struct stat st;
911 size_t len;
912
913 scnprintf(path, PATH_MAX, "devices/system/cpu/cpu%d/cache/index%d/", cpu, level);
914 scnprintf(file, PATH_MAX, "%s/%s", sysfs__mountpoint(), path);
915
916 if (stat(file, &st))
917 return 1;
918
919 scnprintf(file, PATH_MAX, "%s/level", path);
920 if (sysfs__read_int(file, (int *) &cache->level))
921 return -1;
922
923 scnprintf(file, PATH_MAX, "%s/coherency_line_size", path);
924 if (sysfs__read_int(file, (int *) &cache->line_size))
925 return -1;
926
927 scnprintf(file, PATH_MAX, "%s/number_of_sets", path);
928 if (sysfs__read_int(file, (int *) &cache->sets))
929 return -1;
930
931 scnprintf(file, PATH_MAX, "%s/ways_of_associativity", path);
932 if (sysfs__read_int(file, (int *) &cache->ways))
933 return -1;
934
935 scnprintf(file, PATH_MAX, "%s/type", path);
936 if (sysfs__read_str(file, &cache->type, &len))
937 return -1;
938
939 cache->type[len] = 0;
940 cache->type = rtrim(cache->type);
941
942 scnprintf(file, PATH_MAX, "%s/size", path);
943 if (sysfs__read_str(file, &cache->size, &len)) {
944 free(cache->type);
945 return -1;
946 }
947
948 cache->size[len] = 0;
949 cache->size = rtrim(cache->size);
950
951 scnprintf(file, PATH_MAX, "%s/shared_cpu_list", path);
952 if (sysfs__read_str(file, &cache->map, &len)) {
953 free(cache->map);
954 free(cache->type);
955 return -1;
956 }
957
958 cache->map[len] = 0;
959 cache->map = rtrim(cache->map);
960 return 0;
961}
962
963static void cpu_cache_level__fprintf(FILE *out, struct cpu_cache_level *c)
964{
965 fprintf(out, "L%d %-15s %8s [%s]\n", c->level, c->type, c->size, c->map);
966}
967
968static int build_caches(struct cpu_cache_level caches[], u32 size, u32 *cntp)
969{
970 u32 i, cnt = 0;
971 long ncpus;
972 u32 nr, cpu;
973 u16 level;
974
975 ncpus = sysconf(_SC_NPROCESSORS_CONF);
976 if (ncpus < 0)
977 return -1;
978
979 nr = (u32)(ncpus & UINT_MAX);
980
981 for (cpu = 0; cpu < nr; cpu++) {
982 for (level = 0; level < 10; level++) {
983 struct cpu_cache_level c;
984 int err;
985
986 err = cpu_cache_level__read(&c, cpu, level);
987 if (err < 0)
988 return err;
989
990 if (err == 1)
991 break;
992
993 for (i = 0; i < cnt; i++) {
994 if (cpu_cache_level__cmp(&c, &caches[i]))
995 break;
996 }
997
998 if (i == cnt)
999 caches[cnt++] = c;
1000 else
1001 cpu_cache_level__free(&c);
1002
1003 if (WARN_ONCE(cnt == size, "way too many cpu caches.."))
1004 goto out;
1005 }
1006 }
1007 out:
1008 *cntp = cnt;
1009 return 0;
1010}
1011
1012#define MAX_CACHES 2000
1013
1014static int write_cache(int fd, struct perf_header *h __maybe_unused,
1015 struct perf_evlist *evlist __maybe_unused)
1016{
1017 struct cpu_cache_level caches[MAX_CACHES];
1018 u32 cnt = 0, i, version = 1;
1019 int ret;
1020
1021 ret = build_caches(caches, MAX_CACHES, &cnt);
1022 if (ret)
1023 goto out;
1024
1025 qsort(&caches, cnt, sizeof(struct cpu_cache_level), cpu_cache_level__sort);
1026
1027 ret = do_write(fd, &version, sizeof(u32));
1028 if (ret < 0)
1029 goto out;
1030
1031 ret = do_write(fd, &cnt, sizeof(u32));
1032 if (ret < 0)
1033 goto out;
1034
1035 for (i = 0; i < cnt; i++) {
1036 struct cpu_cache_level *c = &caches[i];
1037
1038 #define _W(v) \
1039 ret = do_write(fd, &c->v, sizeof(u32)); \
1040 if (ret < 0) \
1041 goto out;
1042
1043 _W(level)
1044 _W(line_size)
1045 _W(sets)
1046 _W(ways)
1047 #undef _W
1048
1049 #define _W(v) \
1050 ret = do_write_string(fd, (const char *) c->v); \
1051 if (ret < 0) \
1052 goto out;
1053
1054 _W(type)
1055 _W(size)
1056 _W(map)
1057 #undef _W
1058 }
1059
1060out:
1061 for (i = 0; i < cnt; i++)
1062 cpu_cache_level__free(&caches[i]);
1063 return ret;
1064}
1065
871static int write_stat(int fd __maybe_unused, 1066static int write_stat(int fd __maybe_unused,
872 struct perf_header *h __maybe_unused, 1067 struct perf_header *h __maybe_unused,
873 struct perf_evlist *evlist __maybe_unused) 1068 struct perf_evlist *evlist __maybe_unused)
@@ -1172,6 +1367,18 @@ static void print_stat(struct perf_header *ph __maybe_unused,
1172 fprintf(fp, "# contains stat data\n"); 1367 fprintf(fp, "# contains stat data\n");
1173} 1368}
1174 1369
1370static void print_cache(struct perf_header *ph __maybe_unused,
1371 int fd __maybe_unused, FILE *fp __maybe_unused)
1372{
1373 int i;
1374
1375 fprintf(fp, "# CPU cache info:\n");
1376 for (i = 0; i < ph->env.caches_cnt; i++) {
1377 fprintf(fp, "# ");
1378 cpu_cache_level__fprintf(fp, &ph->env.caches[i]);
1379 }
1380}
1381
1175static void print_pmu_mappings(struct perf_header *ph, int fd __maybe_unused, 1382static void print_pmu_mappings(struct perf_header *ph, int fd __maybe_unused,
1176 FILE *fp) 1383 FILE *fp)
1177{ 1384{
@@ -1920,6 +2127,68 @@ static int process_auxtrace(struct perf_file_section *section,
1920 return err; 2127 return err;
1921} 2128}
1922 2129
2130static int process_cache(struct perf_file_section *section __maybe_unused,
2131 struct perf_header *ph __maybe_unused, int fd __maybe_unused,
2132 void *data __maybe_unused)
2133{
2134 struct cpu_cache_level *caches;
2135 u32 cnt, i, version;
2136
2137 if (readn(fd, &version, sizeof(version)) != sizeof(version))
2138 return -1;
2139
2140 if (ph->needs_swap)
2141 version = bswap_32(version);
2142
2143 if (version != 1)
2144 return -1;
2145
2146 if (readn(fd, &cnt, sizeof(cnt)) != sizeof(cnt))
2147 return -1;
2148
2149 if (ph->needs_swap)
2150 cnt = bswap_32(cnt);
2151
2152 caches = zalloc(sizeof(*caches) * cnt);
2153 if (!caches)
2154 return -1;
2155
2156 for (i = 0; i < cnt; i++) {
2157 struct cpu_cache_level c;
2158
2159 #define _R(v) \
2160 if (readn(fd, &c.v, sizeof(u32)) != sizeof(u32))\
2161 goto out_free_caches; \
2162 if (ph->needs_swap) \
2163 c.v = bswap_32(c.v); \
2164
2165 _R(level)
2166 _R(line_size)
2167 _R(sets)
2168 _R(ways)
2169 #undef _R
2170
2171 #define _R(v) \
2172 c.v = do_read_string(fd, ph); \
2173 if (!c.v) \
2174 goto out_free_caches;
2175
2176 _R(type)
2177 _R(size)
2178 _R(map)
2179 #undef _R
2180
2181 caches[i] = c;
2182 }
2183
2184 ph->env.caches = caches;
2185 ph->env.caches_cnt = cnt;
2186 return 0;
2187out_free_caches:
2188 free(caches);
2189 return -1;
2190}
2191
1923struct feature_ops { 2192struct feature_ops {
1924 int (*write)(int fd, struct perf_header *h, struct perf_evlist *evlist); 2193 int (*write)(int fd, struct perf_header *h, struct perf_evlist *evlist);
1925 void (*print)(struct perf_header *h, int fd, FILE *fp); 2194 void (*print)(struct perf_header *h, int fd, FILE *fp);
@@ -1962,6 +2231,7 @@ static const struct feature_ops feat_ops[HEADER_LAST_FEATURE] = {
1962 FEAT_OPP(HEADER_GROUP_DESC, group_desc), 2231 FEAT_OPP(HEADER_GROUP_DESC, group_desc),
1963 FEAT_OPP(HEADER_AUXTRACE, auxtrace), 2232 FEAT_OPP(HEADER_AUXTRACE, auxtrace),
1964 FEAT_OPA(HEADER_STAT, stat), 2233 FEAT_OPA(HEADER_STAT, stat),
2234 FEAT_OPF(HEADER_CACHE, cache),
1965}; 2235};
1966 2236
1967struct header_print_data { 2237struct header_print_data {
diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h
index cff9892452ee..3d87ca823c0a 100644
--- a/tools/perf/util/header.h
+++ b/tools/perf/util/header.h
@@ -32,6 +32,7 @@ enum {
32 HEADER_GROUP_DESC, 32 HEADER_GROUP_DESC,
33 HEADER_AUXTRACE, 33 HEADER_AUXTRACE,
34 HEADER_STAT, 34 HEADER_STAT,
35 HEADER_CACHE,
35 HEADER_LAST_FEATURE, 36 HEADER_LAST_FEATURE,
36 HEADER_FEAT_BITS = 256, 37 HEADER_FEAT_BITS = 256,
37}; 38};
diff --git a/tools/perf/util/help-unknown-cmd.c b/tools/perf/util/help-unknown-cmd.c
index dc1e41c9b054..43a98a4dc1e1 100644
--- a/tools/perf/util/help-unknown-cmd.c
+++ b/tools/perf/util/help-unknown-cmd.c
@@ -6,7 +6,8 @@
6static int autocorrect; 6static int autocorrect;
7static struct cmdnames aliases; 7static struct cmdnames aliases;
8 8
9static int perf_unknown_cmd_config(const char *var, const char *value, void *cb) 9static int perf_unknown_cmd_config(const char *var, const char *value,
10 void *cb __maybe_unused)
10{ 11{
11 if (!strcmp(var, "help.autocorrect")) 12 if (!strcmp(var, "help.autocorrect"))
12 autocorrect = perf_config_int(var,value); 13 autocorrect = perf_config_int(var,value);
@@ -14,7 +15,7 @@ static int perf_unknown_cmd_config(const char *var, const char *value, void *cb)
14 if (!prefixcmp(var, "alias.")) 15 if (!prefixcmp(var, "alias."))
15 add_cmdname(&aliases, var + 6, strlen(var + 6)); 16 add_cmdname(&aliases, var + 6, strlen(var + 6));
16 17
17 return perf_default_config(var, value, cb); 18 return 0;
18} 19}
19 20
20static int levenshtein_compare(const void *p1, const void *p2) 21static int levenshtein_compare(const void *p1, const void *p2)
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c
index 68a7612019dc..290b3cbf6877 100644
--- a/tools/perf/util/hist.c
+++ b/tools/perf/util/hist.c
@@ -179,6 +179,9 @@ void hists__calc_col_len(struct hists *hists, struct hist_entry *h)
179 if (h->transaction) 179 if (h->transaction)
180 hists__new_col_len(hists, HISTC_TRANSACTION, 180 hists__new_col_len(hists, HISTC_TRANSACTION,
181 hist_entry__transaction_len()); 181 hist_entry__transaction_len());
182
183 if (h->trace_output)
184 hists__new_col_len(hists, HISTC_TRACE, strlen(h->trace_output));
182} 185}
183 186
184void hists__output_recalc_col_len(struct hists *hists, int max_rows) 187void hists__output_recalc_col_len(struct hists *hists, int max_rows)
@@ -245,6 +248,8 @@ static void he_stat__decay(struct he_stat *he_stat)
245 /* XXX need decay for weight too? */ 248 /* XXX need decay for weight too? */
246} 249}
247 250
251static void hists__delete_entry(struct hists *hists, struct hist_entry *he);
252
248static bool hists__decay_entry(struct hists *hists, struct hist_entry *he) 253static bool hists__decay_entry(struct hists *hists, struct hist_entry *he)
249{ 254{
250 u64 prev_period = he->stat.period; 255 u64 prev_period = he->stat.period;
@@ -260,21 +265,45 @@ static bool hists__decay_entry(struct hists *hists, struct hist_entry *he)
260 265
261 diff = prev_period - he->stat.period; 266 diff = prev_period - he->stat.period;
262 267
263 hists->stats.total_period -= diff; 268 if (!he->depth) {
264 if (!he->filtered) 269 hists->stats.total_period -= diff;
265 hists->stats.total_non_filtered_period -= diff; 270 if (!he->filtered)
271 hists->stats.total_non_filtered_period -= diff;
272 }
273
274 if (!he->leaf) {
275 struct hist_entry *child;
276 struct rb_node *node = rb_first(&he->hroot_out);
277 while (node) {
278 child = rb_entry(node, struct hist_entry, rb_node);
279 node = rb_next(node);
280
281 if (hists__decay_entry(hists, child))
282 hists__delete_entry(hists, child);
283 }
284 }
266 285
267 return he->stat.period == 0; 286 return he->stat.period == 0;
268} 287}
269 288
270static void hists__delete_entry(struct hists *hists, struct hist_entry *he) 289static void hists__delete_entry(struct hists *hists, struct hist_entry *he)
271{ 290{
272 rb_erase(&he->rb_node, &hists->entries); 291 struct rb_root *root_in;
292 struct rb_root *root_out;
273 293
274 if (sort__need_collapse) 294 if (he->parent_he) {
275 rb_erase(&he->rb_node_in, &hists->entries_collapsed); 295 root_in = &he->parent_he->hroot_in;
276 else 296 root_out = &he->parent_he->hroot_out;
277 rb_erase(&he->rb_node_in, hists->entries_in); 297 } else {
298 if (sort__need_collapse)
299 root_in = &hists->entries_collapsed;
300 else
301 root_in = hists->entries_in;
302 root_out = &hists->entries;
303 }
304
305 rb_erase(&he->rb_node_in, root_in);
306 rb_erase(&he->rb_node, root_out);
278 307
279 --hists->nr_entries; 308 --hists->nr_entries;
280 if (!he->filtered) 309 if (!he->filtered)
@@ -393,6 +422,9 @@ static struct hist_entry *hist_entry__new(struct hist_entry *template,
393 } 422 }
394 INIT_LIST_HEAD(&he->pairs.node); 423 INIT_LIST_HEAD(&he->pairs.node);
395 thread__get(he->thread); 424 thread__get(he->thread);
425
426 if (!symbol_conf.report_hierarchy)
427 he->leaf = true;
396 } 428 }
397 429
398 return he; 430 return he;
@@ -405,6 +437,16 @@ static u8 symbol__parent_filter(const struct symbol *parent)
405 return 0; 437 return 0;
406} 438}
407 439
440static void hist_entry__add_callchain_period(struct hist_entry *he, u64 period)
441{
442 if (!symbol_conf.use_callchain)
443 return;
444
445 he->hists->callchain_period += period;
446 if (!he->filtered)
447 he->hists->callchain_non_filtered_period += period;
448}
449
408static struct hist_entry *hists__findnew_entry(struct hists *hists, 450static struct hist_entry *hists__findnew_entry(struct hists *hists,
409 struct hist_entry *entry, 451 struct hist_entry *entry,
410 struct addr_location *al, 452 struct addr_location *al,
@@ -432,8 +474,10 @@ static struct hist_entry *hists__findnew_entry(struct hists *hists,
432 cmp = hist_entry__cmp(he, entry); 474 cmp = hist_entry__cmp(he, entry);
433 475
434 if (!cmp) { 476 if (!cmp) {
435 if (sample_self) 477 if (sample_self) {
436 he_stat__add_period(&he->stat, period, weight); 478 he_stat__add_period(&he->stat, period, weight);
479 hist_entry__add_callchain_period(he, period);
480 }
437 if (symbol_conf.cumulate_callchain) 481 if (symbol_conf.cumulate_callchain)
438 he_stat__add_period(he->stat_acc, period, weight); 482 he_stat__add_period(he->stat_acc, period, weight);
439 483
@@ -466,6 +510,8 @@ static struct hist_entry *hists__findnew_entry(struct hists *hists,
466 if (!he) 510 if (!he)
467 return NULL; 511 return NULL;
468 512
513 if (sample_self)
514 hist_entry__add_callchain_period(he, period);
469 hists->nr_entries++; 515 hists->nr_entries++;
470 516
471 rb_link_node(&he->rb_node_in, parent, p); 517 rb_link_node(&he->rb_node_in, parent, p);
@@ -951,10 +997,15 @@ out:
951int64_t 997int64_t
952hist_entry__cmp(struct hist_entry *left, struct hist_entry *right) 998hist_entry__cmp(struct hist_entry *left, struct hist_entry *right)
953{ 999{
1000 struct hists *hists = left->hists;
954 struct perf_hpp_fmt *fmt; 1001 struct perf_hpp_fmt *fmt;
955 int64_t cmp = 0; 1002 int64_t cmp = 0;
956 1003
957 perf_hpp__for_each_sort_list(fmt) { 1004 hists__for_each_sort_list(hists, fmt) {
1005 if (perf_hpp__is_dynamic_entry(fmt) &&
1006 !perf_hpp__defined_dynamic_entry(fmt, hists))
1007 continue;
1008
958 cmp = fmt->cmp(fmt, left, right); 1009 cmp = fmt->cmp(fmt, left, right);
959 if (cmp) 1010 if (cmp)
960 break; 1011 break;
@@ -966,10 +1017,15 @@ hist_entry__cmp(struct hist_entry *left, struct hist_entry *right)
966int64_t 1017int64_t
967hist_entry__collapse(struct hist_entry *left, struct hist_entry *right) 1018hist_entry__collapse(struct hist_entry *left, struct hist_entry *right)
968{ 1019{
1020 struct hists *hists = left->hists;
969 struct perf_hpp_fmt *fmt; 1021 struct perf_hpp_fmt *fmt;
970 int64_t cmp = 0; 1022 int64_t cmp = 0;
971 1023
972 perf_hpp__for_each_sort_list(fmt) { 1024 hists__for_each_sort_list(hists, fmt) {
1025 if (perf_hpp__is_dynamic_entry(fmt) &&
1026 !perf_hpp__defined_dynamic_entry(fmt, hists))
1027 continue;
1028
973 cmp = fmt->collapse(fmt, left, right); 1029 cmp = fmt->collapse(fmt, left, right);
974 if (cmp) 1030 if (cmp)
975 break; 1031 break;
@@ -1006,17 +1062,250 @@ void hist_entry__delete(struct hist_entry *he)
1006} 1062}
1007 1063
1008/* 1064/*
1065 * If this is not the last column, then we need to pad it according to the
1066 * pre-calculated max lenght for this column, otherwise don't bother adding
1067 * spaces because that would break viewing this with, for instance, 'less',
1068 * that would show tons of trailing spaces when a long C++ demangled method
1069 * names is sampled.
1070*/
1071int hist_entry__snprintf_alignment(struct hist_entry *he, struct perf_hpp *hpp,
1072 struct perf_hpp_fmt *fmt, int printed)
1073{
1074 if (!list_is_last(&fmt->list, &he->hists->hpp_list->fields)) {
1075 const int width = fmt->width(fmt, hpp, hists_to_evsel(he->hists));
1076 if (printed < width) {
1077 advance_hpp(hpp, printed);
1078 printed = scnprintf(hpp->buf, hpp->size, "%-*s", width - printed, " ");
1079 }
1080 }
1081
1082 return printed;
1083}
1084
1085/*
1009 * collapse the histogram 1086 * collapse the histogram
1010 */ 1087 */
1011 1088
1012bool hists__collapse_insert_entry(struct hists *hists __maybe_unused, 1089static void hists__apply_filters(struct hists *hists, struct hist_entry *he);
1013 struct rb_root *root, struct hist_entry *he) 1090static void hists__remove_entry_filter(struct hists *hists, struct hist_entry *he,
1091 enum hist_filter type);
1092
1093typedef bool (*fmt_chk_fn)(struct perf_hpp_fmt *fmt);
1094
1095static bool check_thread_entry(struct perf_hpp_fmt *fmt)
1096{
1097 return perf_hpp__is_thread_entry(fmt) || perf_hpp__is_comm_entry(fmt);
1098}
1099
1100static void hist_entry__check_and_remove_filter(struct hist_entry *he,
1101 enum hist_filter type,
1102 fmt_chk_fn check)
1103{
1104 struct perf_hpp_fmt *fmt;
1105 bool type_match = false;
1106 struct hist_entry *parent = he->parent_he;
1107
1108 switch (type) {
1109 case HIST_FILTER__THREAD:
1110 if (symbol_conf.comm_list == NULL &&
1111 symbol_conf.pid_list == NULL &&
1112 symbol_conf.tid_list == NULL)
1113 return;
1114 break;
1115 case HIST_FILTER__DSO:
1116 if (symbol_conf.dso_list == NULL)
1117 return;
1118 break;
1119 case HIST_FILTER__SYMBOL:
1120 if (symbol_conf.sym_list == NULL)
1121 return;
1122 break;
1123 case HIST_FILTER__PARENT:
1124 case HIST_FILTER__GUEST:
1125 case HIST_FILTER__HOST:
1126 case HIST_FILTER__SOCKET:
1127 default:
1128 return;
1129 }
1130
1131 /* if it's filtered by own fmt, it has to have filter bits */
1132 perf_hpp_list__for_each_format(he->hpp_list, fmt) {
1133 if (check(fmt)) {
1134 type_match = true;
1135 break;
1136 }
1137 }
1138
1139 if (type_match) {
1140 /*
1141 * If the filter is for current level entry, propagate
1142 * filter marker to parents. The marker bit was
1143 * already set by default so it only needs to clear
1144 * non-filtered entries.
1145 */
1146 if (!(he->filtered & (1 << type))) {
1147 while (parent) {
1148 parent->filtered &= ~(1 << type);
1149 parent = parent->parent_he;
1150 }
1151 }
1152 } else {
1153 /*
1154 * If current entry doesn't have matching formats, set
1155 * filter marker for upper level entries. it will be
1156 * cleared if its lower level entries is not filtered.
1157 *
1158 * For lower-level entries, it inherits parent's
1159 * filter bit so that lower level entries of a
1160 * non-filtered entry won't set the filter marker.
1161 */
1162 if (parent == NULL)
1163 he->filtered |= (1 << type);
1164 else
1165 he->filtered |= (parent->filtered & (1 << type));
1166 }
1167}
1168
1169static void hist_entry__apply_hierarchy_filters(struct hist_entry *he)
1170{
1171 hist_entry__check_and_remove_filter(he, HIST_FILTER__THREAD,
1172 check_thread_entry);
1173
1174 hist_entry__check_and_remove_filter(he, HIST_FILTER__DSO,
1175 perf_hpp__is_dso_entry);
1176
1177 hist_entry__check_and_remove_filter(he, HIST_FILTER__SYMBOL,
1178 perf_hpp__is_sym_entry);
1179
1180 hists__apply_filters(he->hists, he);
1181}
1182
1183static struct hist_entry *hierarchy_insert_entry(struct hists *hists,
1184 struct rb_root *root,
1185 struct hist_entry *he,
1186 struct hist_entry *parent_he,
1187 struct perf_hpp_list *hpp_list)
1188{
1189 struct rb_node **p = &root->rb_node;
1190 struct rb_node *parent = NULL;
1191 struct hist_entry *iter, *new;
1192 struct perf_hpp_fmt *fmt;
1193 int64_t cmp;
1194
1195 while (*p != NULL) {
1196 parent = *p;
1197 iter = rb_entry(parent, struct hist_entry, rb_node_in);
1198
1199 cmp = 0;
1200 perf_hpp_list__for_each_sort_list(hpp_list, fmt) {
1201 cmp = fmt->collapse(fmt, iter, he);
1202 if (cmp)
1203 break;
1204 }
1205
1206 if (!cmp) {
1207 he_stat__add_stat(&iter->stat, &he->stat);
1208 return iter;
1209 }
1210
1211 if (cmp < 0)
1212 p = &parent->rb_left;
1213 else
1214 p = &parent->rb_right;
1215 }
1216
1217 new = hist_entry__new(he, true);
1218 if (new == NULL)
1219 return NULL;
1220
1221 hists->nr_entries++;
1222
1223 /* save related format list for output */
1224 new->hpp_list = hpp_list;
1225 new->parent_he = parent_he;
1226
1227 hist_entry__apply_hierarchy_filters(new);
1228
1229 /* some fields are now passed to 'new' */
1230 perf_hpp_list__for_each_sort_list(hpp_list, fmt) {
1231 if (perf_hpp__is_trace_entry(fmt) || perf_hpp__is_dynamic_entry(fmt))
1232 he->trace_output = NULL;
1233 else
1234 new->trace_output = NULL;
1235
1236 if (perf_hpp__is_srcline_entry(fmt))
1237 he->srcline = NULL;
1238 else
1239 new->srcline = NULL;
1240
1241 if (perf_hpp__is_srcfile_entry(fmt))
1242 he->srcfile = NULL;
1243 else
1244 new->srcfile = NULL;
1245 }
1246
1247 rb_link_node(&new->rb_node_in, parent, p);
1248 rb_insert_color(&new->rb_node_in, root);
1249 return new;
1250}
1251
1252static int hists__hierarchy_insert_entry(struct hists *hists,
1253 struct rb_root *root,
1254 struct hist_entry *he)
1255{
1256 struct perf_hpp_list_node *node;
1257 struct hist_entry *new_he = NULL;
1258 struct hist_entry *parent = NULL;
1259 int depth = 0;
1260 int ret = 0;
1261
1262 list_for_each_entry(node, &hists->hpp_formats, list) {
1263 /* skip period (overhead) and elided columns */
1264 if (node->level == 0 || node->skip)
1265 continue;
1266
1267 /* insert copy of 'he' for each fmt into the hierarchy */
1268 new_he = hierarchy_insert_entry(hists, root, he, parent, &node->hpp);
1269 if (new_he == NULL) {
1270 ret = -1;
1271 break;
1272 }
1273
1274 root = &new_he->hroot_in;
1275 new_he->depth = depth++;
1276 parent = new_he;
1277 }
1278
1279 if (new_he) {
1280 new_he->leaf = true;
1281
1282 if (symbol_conf.use_callchain) {
1283 callchain_cursor_reset(&callchain_cursor);
1284 if (callchain_merge(&callchain_cursor,
1285 new_he->callchain,
1286 he->callchain) < 0)
1287 ret = -1;
1288 }
1289 }
1290
1291 /* 'he' is no longer used */
1292 hist_entry__delete(he);
1293
1294 /* return 0 (or -1) since it already applied filters */
1295 return ret;
1296}
1297
1298int hists__collapse_insert_entry(struct hists *hists, struct rb_root *root,
1299 struct hist_entry *he)
1014{ 1300{
1015 struct rb_node **p = &root->rb_node; 1301 struct rb_node **p = &root->rb_node;
1016 struct rb_node *parent = NULL; 1302 struct rb_node *parent = NULL;
1017 struct hist_entry *iter; 1303 struct hist_entry *iter;
1018 int64_t cmp; 1304 int64_t cmp;
1019 1305
1306 if (symbol_conf.report_hierarchy)
1307 return hists__hierarchy_insert_entry(hists, root, he);
1308
1020 while (*p != NULL) { 1309 while (*p != NULL) {
1021 parent = *p; 1310 parent = *p;
1022 iter = rb_entry(parent, struct hist_entry, rb_node_in); 1311 iter = rb_entry(parent, struct hist_entry, rb_node_in);
@@ -1024,18 +1313,21 @@ bool hists__collapse_insert_entry(struct hists *hists __maybe_unused,
1024 cmp = hist_entry__collapse(iter, he); 1313 cmp = hist_entry__collapse(iter, he);
1025 1314
1026 if (!cmp) { 1315 if (!cmp) {
1316 int ret = 0;
1317
1027 he_stat__add_stat(&iter->stat, &he->stat); 1318 he_stat__add_stat(&iter->stat, &he->stat);
1028 if (symbol_conf.cumulate_callchain) 1319 if (symbol_conf.cumulate_callchain)
1029 he_stat__add_stat(iter->stat_acc, he->stat_acc); 1320 he_stat__add_stat(iter->stat_acc, he->stat_acc);
1030 1321
1031 if (symbol_conf.use_callchain) { 1322 if (symbol_conf.use_callchain) {
1032 callchain_cursor_reset(&callchain_cursor); 1323 callchain_cursor_reset(&callchain_cursor);
1033 callchain_merge(&callchain_cursor, 1324 if (callchain_merge(&callchain_cursor,
1034 iter->callchain, 1325 iter->callchain,
1035 he->callchain); 1326 he->callchain) < 0)
1327 ret = -1;
1036 } 1328 }
1037 hist_entry__delete(he); 1329 hist_entry__delete(he);
1038 return false; 1330 return ret;
1039 } 1331 }
1040 1332
1041 if (cmp < 0) 1333 if (cmp < 0)
@@ -1047,7 +1339,7 @@ bool hists__collapse_insert_entry(struct hists *hists __maybe_unused,
1047 1339
1048 rb_link_node(&he->rb_node_in, parent, p); 1340 rb_link_node(&he->rb_node_in, parent, p);
1049 rb_insert_color(&he->rb_node_in, root); 1341 rb_insert_color(&he->rb_node_in, root);
1050 return true; 1342 return 1;
1051} 1343}
1052 1344
1053struct rb_root *hists__get_rotate_entries_in(struct hists *hists) 1345struct rb_root *hists__get_rotate_entries_in(struct hists *hists)
@@ -1073,14 +1365,15 @@ static void hists__apply_filters(struct hists *hists, struct hist_entry *he)
1073 hists__filter_entry_by_socket(hists, he); 1365 hists__filter_entry_by_socket(hists, he);
1074} 1366}
1075 1367
1076void hists__collapse_resort(struct hists *hists, struct ui_progress *prog) 1368int hists__collapse_resort(struct hists *hists, struct ui_progress *prog)
1077{ 1369{
1078 struct rb_root *root; 1370 struct rb_root *root;
1079 struct rb_node *next; 1371 struct rb_node *next;
1080 struct hist_entry *n; 1372 struct hist_entry *n;
1373 int ret;
1081 1374
1082 if (!sort__need_collapse) 1375 if (!sort__need_collapse)
1083 return; 1376 return 0;
1084 1377
1085 hists->nr_entries = 0; 1378 hists->nr_entries = 0;
1086 1379
@@ -1095,7 +1388,11 @@ void hists__collapse_resort(struct hists *hists, struct ui_progress *prog)
1095 next = rb_next(&n->rb_node_in); 1388 next = rb_next(&n->rb_node_in);
1096 1389
1097 rb_erase(&n->rb_node_in, root); 1390 rb_erase(&n->rb_node_in, root);
1098 if (hists__collapse_insert_entry(hists, &hists->entries_collapsed, n)) { 1391 ret = hists__collapse_insert_entry(hists, &hists->entries_collapsed, n);
1392 if (ret < 0)
1393 return -1;
1394
1395 if (ret) {
1099 /* 1396 /*
1100 * If it wasn't combined with one of the entries already 1397 * If it wasn't combined with one of the entries already
1101 * collapsed, we need to apply the filters that may have 1398 * collapsed, we need to apply the filters that may have
@@ -1106,14 +1403,16 @@ void hists__collapse_resort(struct hists *hists, struct ui_progress *prog)
1106 if (prog) 1403 if (prog)
1107 ui_progress__update(prog, 1); 1404 ui_progress__update(prog, 1);
1108 } 1405 }
1406 return 0;
1109} 1407}
1110 1408
1111static int hist_entry__sort(struct hist_entry *a, struct hist_entry *b) 1409static int hist_entry__sort(struct hist_entry *a, struct hist_entry *b)
1112{ 1410{
1411 struct hists *hists = a->hists;
1113 struct perf_hpp_fmt *fmt; 1412 struct perf_hpp_fmt *fmt;
1114 int64_t cmp = 0; 1413 int64_t cmp = 0;
1115 1414
1116 perf_hpp__for_each_sort_list(fmt) { 1415 hists__for_each_sort_list(hists, fmt) {
1117 if (perf_hpp__should_skip(fmt, a->hists)) 1416 if (perf_hpp__should_skip(fmt, a->hists))
1118 continue; 1417 continue;
1119 1418
@@ -1154,6 +1453,113 @@ void hists__inc_stats(struct hists *hists, struct hist_entry *h)
1154 hists->stats.total_period += h->stat.period; 1453 hists->stats.total_period += h->stat.period;
1155} 1454}
1156 1455
1456static void hierarchy_recalc_total_periods(struct hists *hists)
1457{
1458 struct rb_node *node;
1459 struct hist_entry *he;
1460
1461 node = rb_first(&hists->entries);
1462
1463 hists->stats.total_period = 0;
1464 hists->stats.total_non_filtered_period = 0;
1465
1466 /*
1467 * recalculate total period using top-level entries only
1468 * since lower level entries only see non-filtered entries
1469 * but upper level entries have sum of both entries.
1470 */
1471 while (node) {
1472 he = rb_entry(node, struct hist_entry, rb_node);
1473 node = rb_next(node);
1474
1475 hists->stats.total_period += he->stat.period;
1476 if (!he->filtered)
1477 hists->stats.total_non_filtered_period += he->stat.period;
1478 }
1479}
1480
1481static void hierarchy_insert_output_entry(struct rb_root *root,
1482 struct hist_entry *he)
1483{
1484 struct rb_node **p = &root->rb_node;
1485 struct rb_node *parent = NULL;
1486 struct hist_entry *iter;
1487 struct perf_hpp_fmt *fmt;
1488
1489 while (*p != NULL) {
1490 parent = *p;
1491 iter = rb_entry(parent, struct hist_entry, rb_node);
1492
1493 if (hist_entry__sort(he, iter) > 0)
1494 p = &parent->rb_left;
1495 else
1496 p = &parent->rb_right;
1497 }
1498
1499 rb_link_node(&he->rb_node, parent, p);
1500 rb_insert_color(&he->rb_node, root);
1501
1502 /* update column width of dynamic entry */
1503 perf_hpp_list__for_each_sort_list(he->hpp_list, fmt) {
1504 if (perf_hpp__is_dynamic_entry(fmt))
1505 fmt->sort(fmt, he, NULL);
1506 }
1507}
1508
1509static void hists__hierarchy_output_resort(struct hists *hists,
1510 struct ui_progress *prog,
1511 struct rb_root *root_in,
1512 struct rb_root *root_out,
1513 u64 min_callchain_hits,
1514 bool use_callchain)
1515{
1516 struct rb_node *node;
1517 struct hist_entry *he;
1518
1519 *root_out = RB_ROOT;
1520 node = rb_first(root_in);
1521
1522 while (node) {
1523 he = rb_entry(node, struct hist_entry, rb_node_in);
1524 node = rb_next(node);
1525
1526 hierarchy_insert_output_entry(root_out, he);
1527
1528 if (prog)
1529 ui_progress__update(prog, 1);
1530
1531 if (!he->leaf) {
1532 hists__hierarchy_output_resort(hists, prog,
1533 &he->hroot_in,
1534 &he->hroot_out,
1535 min_callchain_hits,
1536 use_callchain);
1537 hists->nr_entries++;
1538 if (!he->filtered) {
1539 hists->nr_non_filtered_entries++;
1540 hists__calc_col_len(hists, he);
1541 }
1542
1543 continue;
1544 }
1545
1546 if (!use_callchain)
1547 continue;
1548
1549 if (callchain_param.mode == CHAIN_GRAPH_REL) {
1550 u64 total = he->stat.period;
1551
1552 if (symbol_conf.cumulate_callchain)
1553 total = he->stat_acc->period;
1554
1555 min_callchain_hits = total * (callchain_param.min_percent / 100);
1556 }
1557
1558 callchain_param.sort(&he->sorted_chain, he->callchain,
1559 min_callchain_hits, &callchain_param);
1560 }
1561}
1562
1157static void __hists__insert_output_entry(struct rb_root *entries, 1563static void __hists__insert_output_entry(struct rb_root *entries,
1158 struct hist_entry *he, 1564 struct hist_entry *he,
1159 u64 min_callchain_hits, 1565 u64 min_callchain_hits,
@@ -1162,10 +1568,20 @@ static void __hists__insert_output_entry(struct rb_root *entries,
1162 struct rb_node **p = &entries->rb_node; 1568 struct rb_node **p = &entries->rb_node;
1163 struct rb_node *parent = NULL; 1569 struct rb_node *parent = NULL;
1164 struct hist_entry *iter; 1570 struct hist_entry *iter;
1571 struct perf_hpp_fmt *fmt;
1572
1573 if (use_callchain) {
1574 if (callchain_param.mode == CHAIN_GRAPH_REL) {
1575 u64 total = he->stat.period;
1576
1577 if (symbol_conf.cumulate_callchain)
1578 total = he->stat_acc->period;
1165 1579
1166 if (use_callchain) 1580 min_callchain_hits = total * (callchain_param.min_percent / 100);
1581 }
1167 callchain_param.sort(&he->sorted_chain, he->callchain, 1582 callchain_param.sort(&he->sorted_chain, he->callchain,
1168 min_callchain_hits, &callchain_param); 1583 min_callchain_hits, &callchain_param);
1584 }
1169 1585
1170 while (*p != NULL) { 1586 while (*p != NULL) {
1171 parent = *p; 1587 parent = *p;
@@ -1179,23 +1595,41 @@ static void __hists__insert_output_entry(struct rb_root *entries,
1179 1595
1180 rb_link_node(&he->rb_node, parent, p); 1596 rb_link_node(&he->rb_node, parent, p);
1181 rb_insert_color(&he->rb_node, entries); 1597 rb_insert_color(&he->rb_node, entries);
1598
1599 perf_hpp_list__for_each_sort_list(&perf_hpp_list, fmt) {
1600 if (perf_hpp__is_dynamic_entry(fmt) &&
1601 perf_hpp__defined_dynamic_entry(fmt, he->hists))
1602 fmt->sort(fmt, he, NULL); /* update column width */
1603 }
1182} 1604}
1183 1605
1184void hists__output_resort(struct hists *hists, struct ui_progress *prog) 1606static void output_resort(struct hists *hists, struct ui_progress *prog,
1607 bool use_callchain)
1185{ 1608{
1186 struct rb_root *root; 1609 struct rb_root *root;
1187 struct rb_node *next; 1610 struct rb_node *next;
1188 struct hist_entry *n; 1611 struct hist_entry *n;
1612 u64 callchain_total;
1189 u64 min_callchain_hits; 1613 u64 min_callchain_hits;
1190 struct perf_evsel *evsel = hists_to_evsel(hists);
1191 bool use_callchain;
1192 1614
1193 if (evsel && symbol_conf.use_callchain && !symbol_conf.show_ref_callgraph) 1615 callchain_total = hists->callchain_period;
1194 use_callchain = evsel->attr.sample_type & PERF_SAMPLE_CALLCHAIN; 1616 if (symbol_conf.filter_relative)
1195 else 1617 callchain_total = hists->callchain_non_filtered_period;
1196 use_callchain = symbol_conf.use_callchain;
1197 1618
1198 min_callchain_hits = hists->stats.total_period * (callchain_param.min_percent / 100); 1619 min_callchain_hits = callchain_total * (callchain_param.min_percent / 100);
1620
1621 hists__reset_stats(hists);
1622 hists__reset_col_len(hists);
1623
1624 if (symbol_conf.report_hierarchy) {
1625 hists__hierarchy_output_resort(hists, prog,
1626 &hists->entries_collapsed,
1627 &hists->entries,
1628 min_callchain_hits,
1629 use_callchain);
1630 hierarchy_recalc_total_periods(hists);
1631 return;
1632 }
1199 1633
1200 if (sort__need_collapse) 1634 if (sort__need_collapse)
1201 root = &hists->entries_collapsed; 1635 root = &hists->entries_collapsed;
@@ -1205,9 +1639,6 @@ void hists__output_resort(struct hists *hists, struct ui_progress *prog)
1205 next = rb_first(root); 1639 next = rb_first(root);
1206 hists->entries = RB_ROOT; 1640 hists->entries = RB_ROOT;
1207 1641
1208 hists__reset_stats(hists);
1209 hists__reset_col_len(hists);
1210
1211 while (next) { 1642 while (next) {
1212 n = rb_entry(next, struct hist_entry, rb_node_in); 1643 n = rb_entry(next, struct hist_entry, rb_node_in);
1213 next = rb_next(&n->rb_node_in); 1644 next = rb_next(&n->rb_node_in);
@@ -1223,15 +1654,136 @@ void hists__output_resort(struct hists *hists, struct ui_progress *prog)
1223 } 1654 }
1224} 1655}
1225 1656
1657void perf_evsel__output_resort(struct perf_evsel *evsel, struct ui_progress *prog)
1658{
1659 bool use_callchain;
1660
1661 if (evsel && symbol_conf.use_callchain && !symbol_conf.show_ref_callgraph)
1662 use_callchain = evsel->attr.sample_type & PERF_SAMPLE_CALLCHAIN;
1663 else
1664 use_callchain = symbol_conf.use_callchain;
1665
1666 output_resort(evsel__hists(evsel), prog, use_callchain);
1667}
1668
1669void hists__output_resort(struct hists *hists, struct ui_progress *prog)
1670{
1671 output_resort(hists, prog, symbol_conf.use_callchain);
1672}
1673
1674static bool can_goto_child(struct hist_entry *he, enum hierarchy_move_dir hmd)
1675{
1676 if (he->leaf || hmd == HMD_FORCE_SIBLING)
1677 return false;
1678
1679 if (he->unfolded || hmd == HMD_FORCE_CHILD)
1680 return true;
1681
1682 return false;
1683}
1684
1685struct rb_node *rb_hierarchy_last(struct rb_node *node)
1686{
1687 struct hist_entry *he = rb_entry(node, struct hist_entry, rb_node);
1688
1689 while (can_goto_child(he, HMD_NORMAL)) {
1690 node = rb_last(&he->hroot_out);
1691 he = rb_entry(node, struct hist_entry, rb_node);
1692 }
1693 return node;
1694}
1695
1696struct rb_node *__rb_hierarchy_next(struct rb_node *node, enum hierarchy_move_dir hmd)
1697{
1698 struct hist_entry *he = rb_entry(node, struct hist_entry, rb_node);
1699
1700 if (can_goto_child(he, hmd))
1701 node = rb_first(&he->hroot_out);
1702 else
1703 node = rb_next(node);
1704
1705 while (node == NULL) {
1706 he = he->parent_he;
1707 if (he == NULL)
1708 break;
1709
1710 node = rb_next(&he->rb_node);
1711 }
1712 return node;
1713}
1714
1715struct rb_node *rb_hierarchy_prev(struct rb_node *node)
1716{
1717 struct hist_entry *he = rb_entry(node, struct hist_entry, rb_node);
1718
1719 node = rb_prev(node);
1720 if (node)
1721 return rb_hierarchy_last(node);
1722
1723 he = he->parent_he;
1724 if (he == NULL)
1725 return NULL;
1726
1727 return &he->rb_node;
1728}
1729
1730bool hist_entry__has_hierarchy_children(struct hist_entry *he, float limit)
1731{
1732 struct rb_node *node;
1733 struct hist_entry *child;
1734 float percent;
1735
1736 if (he->leaf)
1737 return false;
1738
1739 node = rb_first(&he->hroot_out);
1740 child = rb_entry(node, struct hist_entry, rb_node);
1741
1742 while (node && child->filtered) {
1743 node = rb_next(node);
1744 child = rb_entry(node, struct hist_entry, rb_node);
1745 }
1746
1747 if (node)
1748 percent = hist_entry__get_percent_limit(child);
1749 else
1750 percent = 0;
1751
1752 return node && percent >= limit;
1753}
1754
1226static void hists__remove_entry_filter(struct hists *hists, struct hist_entry *h, 1755static void hists__remove_entry_filter(struct hists *hists, struct hist_entry *h,
1227 enum hist_filter filter) 1756 enum hist_filter filter)
1228{ 1757{
1229 h->filtered &= ~(1 << filter); 1758 h->filtered &= ~(1 << filter);
1759
1760 if (symbol_conf.report_hierarchy) {
1761 struct hist_entry *parent = h->parent_he;
1762
1763 while (parent) {
1764 he_stat__add_stat(&parent->stat, &h->stat);
1765
1766 parent->filtered &= ~(1 << filter);
1767
1768 if (parent->filtered)
1769 goto next;
1770
1771 /* force fold unfiltered entry for simplicity */
1772 parent->unfolded = false;
1773 parent->has_no_entry = false;
1774 parent->row_offset = 0;
1775 parent->nr_rows = 0;
1776next:
1777 parent = parent->parent_he;
1778 }
1779 }
1780
1230 if (h->filtered) 1781 if (h->filtered)
1231 return; 1782 return;
1232 1783
1233 /* force fold unfiltered entry for simplicity */ 1784 /* force fold unfiltered entry for simplicity */
1234 h->unfolded = false; 1785 h->unfolded = false;
1786 h->has_no_entry = false;
1235 h->row_offset = 0; 1787 h->row_offset = 0;
1236 h->nr_rows = 0; 1788 h->nr_rows = 0;
1237 1789
@@ -1254,28 +1806,6 @@ static bool hists__filter_entry_by_dso(struct hists *hists,
1254 return false; 1806 return false;
1255} 1807}
1256 1808
1257void hists__filter_by_dso(struct hists *hists)
1258{
1259 struct rb_node *nd;
1260
1261 hists->stats.nr_non_filtered_samples = 0;
1262
1263 hists__reset_filter_stats(hists);
1264 hists__reset_col_len(hists);
1265
1266 for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) {
1267 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
1268
1269 if (symbol_conf.exclude_other && !h->parent)
1270 continue;
1271
1272 if (hists__filter_entry_by_dso(hists, h))
1273 continue;
1274
1275 hists__remove_entry_filter(hists, h, HIST_FILTER__DSO);
1276 }
1277}
1278
1279static bool hists__filter_entry_by_thread(struct hists *hists, 1809static bool hists__filter_entry_by_thread(struct hists *hists,
1280 struct hist_entry *he) 1810 struct hist_entry *he)
1281{ 1811{
@@ -1288,25 +1818,6 @@ static bool hists__filter_entry_by_thread(struct hists *hists,
1288 return false; 1818 return false;
1289} 1819}
1290 1820
1291void hists__filter_by_thread(struct hists *hists)
1292{
1293 struct rb_node *nd;
1294
1295 hists->stats.nr_non_filtered_samples = 0;
1296
1297 hists__reset_filter_stats(hists);
1298 hists__reset_col_len(hists);
1299
1300 for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) {
1301 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
1302
1303 if (hists__filter_entry_by_thread(hists, h))
1304 continue;
1305
1306 hists__remove_entry_filter(hists, h, HIST_FILTER__THREAD);
1307 }
1308}
1309
1310static bool hists__filter_entry_by_symbol(struct hists *hists, 1821static bool hists__filter_entry_by_symbol(struct hists *hists,
1311 struct hist_entry *he) 1822 struct hist_entry *he)
1312{ 1823{
@@ -1320,7 +1831,21 @@ static bool hists__filter_entry_by_symbol(struct hists *hists,
1320 return false; 1831 return false;
1321} 1832}
1322 1833
1323void hists__filter_by_symbol(struct hists *hists) 1834static bool hists__filter_entry_by_socket(struct hists *hists,
1835 struct hist_entry *he)
1836{
1837 if ((hists->socket_filter > -1) &&
1838 (he->socket != hists->socket_filter)) {
1839 he->filtered |= (1 << HIST_FILTER__SOCKET);
1840 return true;
1841 }
1842
1843 return false;
1844}
1845
1846typedef bool (*filter_fn_t)(struct hists *hists, struct hist_entry *he);
1847
1848static void hists__filter_by_type(struct hists *hists, int type, filter_fn_t filter)
1324{ 1849{
1325 struct rb_node *nd; 1850 struct rb_node *nd;
1326 1851
@@ -1332,42 +1857,155 @@ void hists__filter_by_symbol(struct hists *hists)
1332 for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) { 1857 for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) {
1333 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); 1858 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
1334 1859
1335 if (hists__filter_entry_by_symbol(hists, h)) 1860 if (filter(hists, h))
1336 continue; 1861 continue;
1337 1862
1338 hists__remove_entry_filter(hists, h, HIST_FILTER__SYMBOL); 1863 hists__remove_entry_filter(hists, h, type);
1339 } 1864 }
1340} 1865}
1341 1866
1342static bool hists__filter_entry_by_socket(struct hists *hists, 1867static void resort_filtered_entry(struct rb_root *root, struct hist_entry *he)
1343 struct hist_entry *he)
1344{ 1868{
1345 if ((hists->socket_filter > -1) && 1869 struct rb_node **p = &root->rb_node;
1346 (he->socket != hists->socket_filter)) { 1870 struct rb_node *parent = NULL;
1347 he->filtered |= (1 << HIST_FILTER__SOCKET); 1871 struct hist_entry *iter;
1348 return true; 1872 struct rb_root new_root = RB_ROOT;
1873 struct rb_node *nd;
1874
1875 while (*p != NULL) {
1876 parent = *p;
1877 iter = rb_entry(parent, struct hist_entry, rb_node);
1878
1879 if (hist_entry__sort(he, iter) > 0)
1880 p = &(*p)->rb_left;
1881 else
1882 p = &(*p)->rb_right;
1349 } 1883 }
1350 1884
1351 return false; 1885 rb_link_node(&he->rb_node, parent, p);
1886 rb_insert_color(&he->rb_node, root);
1887
1888 if (he->leaf || he->filtered)
1889 return;
1890
1891 nd = rb_first(&he->hroot_out);
1892 while (nd) {
1893 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
1894
1895 nd = rb_next(nd);
1896 rb_erase(&h->rb_node, &he->hroot_out);
1897
1898 resort_filtered_entry(&new_root, h);
1899 }
1900
1901 he->hroot_out = new_root;
1352} 1902}
1353 1903
1354void hists__filter_by_socket(struct hists *hists) 1904static void hists__filter_hierarchy(struct hists *hists, int type, const void *arg)
1355{ 1905{
1356 struct rb_node *nd; 1906 struct rb_node *nd;
1907 struct rb_root new_root = RB_ROOT;
1357 1908
1358 hists->stats.nr_non_filtered_samples = 0; 1909 hists->stats.nr_non_filtered_samples = 0;
1359 1910
1360 hists__reset_filter_stats(hists); 1911 hists__reset_filter_stats(hists);
1361 hists__reset_col_len(hists); 1912 hists__reset_col_len(hists);
1362 1913
1363 for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) { 1914 nd = rb_first(&hists->entries);
1915 while (nd) {
1364 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); 1916 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
1917 int ret;
1365 1918
1366 if (hists__filter_entry_by_socket(hists, h)) 1919 ret = hist_entry__filter(h, type, arg);
1367 continue;
1368 1920
1369 hists__remove_entry_filter(hists, h, HIST_FILTER__SOCKET); 1921 /*
1922 * case 1. non-matching type
1923 * zero out the period, set filter marker and move to child
1924 */
1925 if (ret < 0) {
1926 memset(&h->stat, 0, sizeof(h->stat));
1927 h->filtered |= (1 << type);
1928
1929 nd = __rb_hierarchy_next(&h->rb_node, HMD_FORCE_CHILD);
1930 }
1931 /*
1932 * case 2. matched type (filter out)
1933 * set filter marker and move to next
1934 */
1935 else if (ret == 1) {
1936 h->filtered |= (1 << type);
1937
1938 nd = __rb_hierarchy_next(&h->rb_node, HMD_FORCE_SIBLING);
1939 }
1940 /*
1941 * case 3. ok (not filtered)
1942 * add period to hists and parents, erase the filter marker
1943 * and move to next sibling
1944 */
1945 else {
1946 hists__remove_entry_filter(hists, h, type);
1947
1948 nd = __rb_hierarchy_next(&h->rb_node, HMD_FORCE_SIBLING);
1949 }
1950 }
1951
1952 hierarchy_recalc_total_periods(hists);
1953
1954 /*
1955 * resort output after applying a new filter since filter in a lower
1956 * hierarchy can change periods in a upper hierarchy.
1957 */
1958 nd = rb_first(&hists->entries);
1959 while (nd) {
1960 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
1961
1962 nd = rb_next(nd);
1963 rb_erase(&h->rb_node, &hists->entries);
1964
1965 resort_filtered_entry(&new_root, h);
1370 } 1966 }
1967
1968 hists->entries = new_root;
1969}
1970
1971void hists__filter_by_thread(struct hists *hists)
1972{
1973 if (symbol_conf.report_hierarchy)
1974 hists__filter_hierarchy(hists, HIST_FILTER__THREAD,
1975 hists->thread_filter);
1976 else
1977 hists__filter_by_type(hists, HIST_FILTER__THREAD,
1978 hists__filter_entry_by_thread);
1979}
1980
1981void hists__filter_by_dso(struct hists *hists)
1982{
1983 if (symbol_conf.report_hierarchy)
1984 hists__filter_hierarchy(hists, HIST_FILTER__DSO,
1985 hists->dso_filter);
1986 else
1987 hists__filter_by_type(hists, HIST_FILTER__DSO,
1988 hists__filter_entry_by_dso);
1989}
1990
1991void hists__filter_by_symbol(struct hists *hists)
1992{
1993 if (symbol_conf.report_hierarchy)
1994 hists__filter_hierarchy(hists, HIST_FILTER__SYMBOL,
1995 hists->symbol_filter_str);
1996 else
1997 hists__filter_by_type(hists, HIST_FILTER__SYMBOL,
1998 hists__filter_entry_by_symbol);
1999}
2000
2001void hists__filter_by_socket(struct hists *hists)
2002{
2003 if (symbol_conf.report_hierarchy)
2004 hists__filter_hierarchy(hists, HIST_FILTER__SOCKET,
2005 &hists->socket_filter);
2006 else
2007 hists__filter_by_type(hists, HIST_FILTER__SOCKET,
2008 hists__filter_entry_by_socket);
1371} 2009}
1372 2010
1373void events_stats__inc(struct events_stats *stats, u32 type) 2011void events_stats__inc(struct events_stats *stats, u32 type)
@@ -1585,7 +2223,7 @@ int perf_hist_config(const char *var, const char *value)
1585 return 0; 2223 return 0;
1586} 2224}
1587 2225
1588int __hists__init(struct hists *hists) 2226int __hists__init(struct hists *hists, struct perf_hpp_list *hpp_list)
1589{ 2227{
1590 memset(hists, 0, sizeof(*hists)); 2228 memset(hists, 0, sizeof(*hists));
1591 hists->entries_in_array[0] = hists->entries_in_array[1] = RB_ROOT; 2229 hists->entries_in_array[0] = hists->entries_in_array[1] = RB_ROOT;
@@ -1594,6 +2232,8 @@ int __hists__init(struct hists *hists)
1594 hists->entries = RB_ROOT; 2232 hists->entries = RB_ROOT;
1595 pthread_mutex_init(&hists->lock, NULL); 2233 pthread_mutex_init(&hists->lock, NULL);
1596 hists->socket_filter = -1; 2234 hists->socket_filter = -1;
2235 hists->hpp_list = hpp_list;
2236 INIT_LIST_HEAD(&hists->hpp_formats);
1597 return 0; 2237 return 0;
1598} 2238}
1599 2239
@@ -1622,15 +2262,26 @@ static void hists__delete_all_entries(struct hists *hists)
1622static void hists_evsel__exit(struct perf_evsel *evsel) 2262static void hists_evsel__exit(struct perf_evsel *evsel)
1623{ 2263{
1624 struct hists *hists = evsel__hists(evsel); 2264 struct hists *hists = evsel__hists(evsel);
2265 struct perf_hpp_fmt *fmt, *pos;
2266 struct perf_hpp_list_node *node, *tmp;
1625 2267
1626 hists__delete_all_entries(hists); 2268 hists__delete_all_entries(hists);
2269
2270 list_for_each_entry_safe(node, tmp, &hists->hpp_formats, list) {
2271 perf_hpp_list__for_each_format_safe(&node->hpp, fmt, pos) {
2272 list_del(&fmt->list);
2273 free(fmt);
2274 }
2275 list_del(&node->list);
2276 free(node);
2277 }
1627} 2278}
1628 2279
1629static int hists_evsel__init(struct perf_evsel *evsel) 2280static int hists_evsel__init(struct perf_evsel *evsel)
1630{ 2281{
1631 struct hists *hists = evsel__hists(evsel); 2282 struct hists *hists = evsel__hists(evsel);
1632 2283
1633 __hists__init(hists); 2284 __hists__init(hists, &perf_hpp_list);
1634 return 0; 2285 return 0;
1635} 2286}
1636 2287
@@ -1649,3 +2300,9 @@ int hists__init(void)
1649 2300
1650 return err; 2301 return err;
1651} 2302}
2303
2304void perf_hpp_list__init(struct perf_hpp_list *list)
2305{
2306 INIT_LIST_HEAD(&list->fields);
2307 INIT_LIST_HEAD(&list->sorts);
2308}
diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h
index d4ec4822a103..ead18c82294f 100644
--- a/tools/perf/util/hist.h
+++ b/tools/perf/util/hist.h
@@ -66,6 +66,8 @@ struct hists {
66 struct rb_root entries_collapsed; 66 struct rb_root entries_collapsed;
67 u64 nr_entries; 67 u64 nr_entries;
68 u64 nr_non_filtered_entries; 68 u64 nr_non_filtered_entries;
69 u64 callchain_period;
70 u64 callchain_non_filtered_period;
69 struct thread *thread_filter; 71 struct thread *thread_filter;
70 const struct dso *dso_filter; 72 const struct dso *dso_filter;
71 const char *uid_filter_str; 73 const char *uid_filter_str;
@@ -75,6 +77,9 @@ struct hists {
75 u64 event_stream; 77 u64 event_stream;
76 u16 col_len[HISTC_NR_COLS]; 78 u16 col_len[HISTC_NR_COLS];
77 int socket_filter; 79 int socket_filter;
80 struct perf_hpp_list *hpp_list;
81 struct list_head hpp_formats;
82 int nr_hpp_node;
78}; 83};
79 84
80struct hist_entry_iter; 85struct hist_entry_iter;
@@ -121,15 +126,21 @@ struct hist_entry *__hists__add_entry(struct hists *hists,
121int hist_entry_iter__add(struct hist_entry_iter *iter, struct addr_location *al, 126int hist_entry_iter__add(struct hist_entry_iter *iter, struct addr_location *al,
122 int max_stack_depth, void *arg); 127 int max_stack_depth, void *arg);
123 128
129struct perf_hpp;
130struct perf_hpp_fmt;
131
124int64_t hist_entry__cmp(struct hist_entry *left, struct hist_entry *right); 132int64_t hist_entry__cmp(struct hist_entry *left, struct hist_entry *right);
125int64_t hist_entry__collapse(struct hist_entry *left, struct hist_entry *right); 133int64_t hist_entry__collapse(struct hist_entry *left, struct hist_entry *right);
126int hist_entry__transaction_len(void); 134int hist_entry__transaction_len(void);
127int hist_entry__sort_snprintf(struct hist_entry *he, char *bf, size_t size, 135int hist_entry__sort_snprintf(struct hist_entry *he, char *bf, size_t size,
128 struct hists *hists); 136 struct hists *hists);
137int hist_entry__snprintf_alignment(struct hist_entry *he, struct perf_hpp *hpp,
138 struct perf_hpp_fmt *fmt, int printed);
129void hist_entry__delete(struct hist_entry *he); 139void hist_entry__delete(struct hist_entry *he);
130 140
141void perf_evsel__output_resort(struct perf_evsel *evsel, struct ui_progress *prog);
131void hists__output_resort(struct hists *hists, struct ui_progress *prog); 142void hists__output_resort(struct hists *hists, struct ui_progress *prog);
132void hists__collapse_resort(struct hists *hists, struct ui_progress *prog); 143int hists__collapse_resort(struct hists *hists, struct ui_progress *prog);
133 144
134void hists__decay_entries(struct hists *hists, bool zap_user, bool zap_kernel); 145void hists__decay_entries(struct hists *hists, bool zap_user, bool zap_kernel);
135void hists__delete_entries(struct hists *hists); 146void hists__delete_entries(struct hists *hists);
@@ -185,10 +196,10 @@ static inline struct hists *evsel__hists(struct perf_evsel *evsel)
185} 196}
186 197
187int hists__init(void); 198int hists__init(void);
188int __hists__init(struct hists *hists); 199int __hists__init(struct hists *hists, struct perf_hpp_list *hpp_list);
189 200
190struct rb_root *hists__get_rotate_entries_in(struct hists *hists); 201struct rb_root *hists__get_rotate_entries_in(struct hists *hists);
191bool hists__collapse_insert_entry(struct hists *hists __maybe_unused, 202int hists__collapse_insert_entry(struct hists *hists,
192 struct rb_root *root, struct hist_entry *he); 203 struct rb_root *root, struct hist_entry *he);
193 204
194struct perf_hpp { 205struct perf_hpp {
@@ -214,28 +225,64 @@ struct perf_hpp_fmt {
214 struct hist_entry *a, struct hist_entry *b); 225 struct hist_entry *a, struct hist_entry *b);
215 int64_t (*sort)(struct perf_hpp_fmt *fmt, 226 int64_t (*sort)(struct perf_hpp_fmt *fmt,
216 struct hist_entry *a, struct hist_entry *b); 227 struct hist_entry *a, struct hist_entry *b);
228 bool (*equal)(struct perf_hpp_fmt *a, struct perf_hpp_fmt *b);
229 void (*free)(struct perf_hpp_fmt *fmt);
217 230
218 struct list_head list; 231 struct list_head list;
219 struct list_head sort_list; 232 struct list_head sort_list;
220 bool elide; 233 bool elide;
221 int len; 234 int len;
222 int user_len; 235 int user_len;
236 int idx;
237 int level;
238};
239
240struct perf_hpp_list {
241 struct list_head fields;
242 struct list_head sorts;
223}; 243};
224 244
225extern struct list_head perf_hpp__list; 245extern struct perf_hpp_list perf_hpp_list;
226extern struct list_head perf_hpp__sort_list; 246
247struct perf_hpp_list_node {
248 struct list_head list;
249 struct perf_hpp_list hpp;
250 int level;
251 bool skip;
252};
253
254void perf_hpp_list__column_register(struct perf_hpp_list *list,
255 struct perf_hpp_fmt *format);
256void perf_hpp_list__register_sort_field(struct perf_hpp_list *list,
257 struct perf_hpp_fmt *format);
258
259static inline void perf_hpp__column_register(struct perf_hpp_fmt *format)
260{
261 perf_hpp_list__column_register(&perf_hpp_list, format);
262}
263
264static inline void perf_hpp__register_sort_field(struct perf_hpp_fmt *format)
265{
266 perf_hpp_list__register_sort_field(&perf_hpp_list, format);
267}
268
269#define perf_hpp_list__for_each_format(_list, format) \
270 list_for_each_entry(format, &(_list)->fields, list)
227 271
228#define perf_hpp__for_each_format(format) \ 272#define perf_hpp_list__for_each_format_safe(_list, format, tmp) \
229 list_for_each_entry(format, &perf_hpp__list, list) 273 list_for_each_entry_safe(format, tmp, &(_list)->fields, list)
230 274
231#define perf_hpp__for_each_format_safe(format, tmp) \ 275#define perf_hpp_list__for_each_sort_list(_list, format) \
232 list_for_each_entry_safe(format, tmp, &perf_hpp__list, list) 276 list_for_each_entry(format, &(_list)->sorts, sort_list)
233 277
234#define perf_hpp__for_each_sort_list(format) \ 278#define perf_hpp_list__for_each_sort_list_safe(_list, format, tmp) \
235 list_for_each_entry(format, &perf_hpp__sort_list, sort_list) 279 list_for_each_entry_safe(format, tmp, &(_list)->sorts, sort_list)
236 280
237#define perf_hpp__for_each_sort_list_safe(format, tmp) \ 281#define hists__for_each_format(hists, format) \
238 list_for_each_entry_safe(format, tmp, &perf_hpp__sort_list, sort_list) 282 perf_hpp_list__for_each_format((hists)->hpp_list, fmt)
283
284#define hists__for_each_sort_list(hists, format) \
285 perf_hpp_list__for_each_sort_list((hists)->hpp_list, fmt)
239 286
240extern struct perf_hpp_fmt perf_hpp__format[]; 287extern struct perf_hpp_fmt perf_hpp__format[];
241 288
@@ -254,21 +301,29 @@ enum {
254}; 301};
255 302
256void perf_hpp__init(void); 303void perf_hpp__init(void);
257void perf_hpp__column_register(struct perf_hpp_fmt *format);
258void perf_hpp__column_unregister(struct perf_hpp_fmt *format); 304void perf_hpp__column_unregister(struct perf_hpp_fmt *format);
259void perf_hpp__column_enable(unsigned col);
260void perf_hpp__column_disable(unsigned col);
261void perf_hpp__cancel_cumulate(void); 305void perf_hpp__cancel_cumulate(void);
306void perf_hpp__setup_output_field(struct perf_hpp_list *list);
307void perf_hpp__reset_output_field(struct perf_hpp_list *list);
308void perf_hpp__append_sort_keys(struct perf_hpp_list *list);
309int perf_hpp__setup_hists_formats(struct perf_hpp_list *list,
310 struct perf_evlist *evlist);
262 311
263void perf_hpp__register_sort_field(struct perf_hpp_fmt *format);
264void perf_hpp__setup_output_field(void);
265void perf_hpp__reset_output_field(void);
266void perf_hpp__append_sort_keys(void);
267 312
268bool perf_hpp__is_sort_entry(struct perf_hpp_fmt *format); 313bool perf_hpp__is_sort_entry(struct perf_hpp_fmt *format);
269bool perf_hpp__same_sort_entry(struct perf_hpp_fmt *a, struct perf_hpp_fmt *b);
270bool perf_hpp__is_dynamic_entry(struct perf_hpp_fmt *format); 314bool perf_hpp__is_dynamic_entry(struct perf_hpp_fmt *format);
271bool perf_hpp__defined_dynamic_entry(struct perf_hpp_fmt *fmt, struct hists *hists); 315bool perf_hpp__defined_dynamic_entry(struct perf_hpp_fmt *fmt, struct hists *hists);
316bool perf_hpp__is_trace_entry(struct perf_hpp_fmt *fmt);
317bool perf_hpp__is_srcline_entry(struct perf_hpp_fmt *fmt);
318bool perf_hpp__is_srcfile_entry(struct perf_hpp_fmt *fmt);
319bool perf_hpp__is_thread_entry(struct perf_hpp_fmt *fmt);
320bool perf_hpp__is_comm_entry(struct perf_hpp_fmt *fmt);
321bool perf_hpp__is_dso_entry(struct perf_hpp_fmt *fmt);
322bool perf_hpp__is_sym_entry(struct perf_hpp_fmt *fmt);
323
324struct perf_hpp_fmt *perf_hpp_fmt__dup(struct perf_hpp_fmt *fmt);
325
326int hist_entry__filter(struct hist_entry *he, int type, const void *arg);
272 327
273static inline bool perf_hpp__should_skip(struct perf_hpp_fmt *format, 328static inline bool perf_hpp__should_skip(struct perf_hpp_fmt *format,
274 struct hists *hists) 329 struct hists *hists)
@@ -372,6 +427,7 @@ static inline int script_browse(const char *script_opt __maybe_unused)
372#endif 427#endif
373 428
374unsigned int hists__sort_list_width(struct hists *hists); 429unsigned int hists__sort_list_width(struct hists *hists);
430unsigned int hists__overhead_width(struct hists *hists);
375 431
376void hist__account_cycles(struct branch_stack *bs, struct addr_location *al, 432void hist__account_cycles(struct branch_stack *bs, struct addr_location *al,
377 struct perf_sample *sample, bool nonany_branch_mode); 433 struct perf_sample *sample, bool nonany_branch_mode);
@@ -381,4 +437,26 @@ int parse_filter_percentage(const struct option *opt __maybe_unused,
381 const char *arg, int unset __maybe_unused); 437 const char *arg, int unset __maybe_unused);
382int perf_hist_config(const char *var, const char *value); 438int perf_hist_config(const char *var, const char *value);
383 439
440void perf_hpp_list__init(struct perf_hpp_list *list);
441
442enum hierarchy_move_dir {
443 HMD_NORMAL,
444 HMD_FORCE_SIBLING,
445 HMD_FORCE_CHILD,
446};
447
448struct rb_node *rb_hierarchy_last(struct rb_node *node);
449struct rb_node *__rb_hierarchy_next(struct rb_node *node,
450 enum hierarchy_move_dir hmd);
451struct rb_node *rb_hierarchy_prev(struct rb_node *node);
452
453static inline struct rb_node *rb_hierarchy_next(struct rb_node *node)
454{
455 return __rb_hierarchy_next(node, HMD_NORMAL);
456}
457
458#define HIERARCHY_INDENT 3
459
460bool hist_entry__has_hierarchy_children(struct hist_entry *he, float limit);
461
384#endif /* __PERF_HIST_H */ 462#endif /* __PERF_HIST_H */
diff --git a/tools/perf/util/jit.h b/tools/perf/util/jit.h
new file mode 100644
index 000000000000..a1e99da0715a
--- /dev/null
+++ b/tools/perf/util/jit.h
@@ -0,0 +1,15 @@
1#ifndef __JIT_H__
2#define __JIT_H__
3
4#include <data.h>
5
6extern int jit_process(struct perf_session *session,
7 struct perf_data_file *output,
8 struct machine *machine,
9 char *filename,
10 pid_t pid,
11 u64 *nbytes);
12
13extern int jit_inject_record(const char *filename);
14
15#endif /* __JIT_H__ */
diff --git a/tools/perf/util/jitdump.c b/tools/perf/util/jitdump.c
new file mode 100644
index 000000000000..cd272cc21e05
--- /dev/null
+++ b/tools/perf/util/jitdump.c
@@ -0,0 +1,697 @@
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.pid = pid;
421 sample.tid = tid;
422 sample.time = id->time;
423 sample.ip = addr;
424
425 ret = perf_event__process_mmap2(tool, event, &sample, jd->machine);
426 if (ret)
427 return ret;
428
429 ret = jit_inject_event(jd, event);
430 /*
431 * mark dso as use to generate buildid in the header
432 */
433 if (!ret)
434 build_id__mark_dso_hit(tool, event, &sample, NULL, jd->machine);
435
436 return ret;
437}
438
439static int jit_repipe_code_move(struct jit_buf_desc *jd, union jr_entry *jr)
440{
441 struct perf_sample sample;
442 union perf_event *event;
443 struct perf_tool *tool = jd->session->tool;
444 char *filename;
445 size_t size;
446 struct stat st;
447 u16 idr_size;
448 int ret;
449 pid_t pid, tid;
450 struct {
451 u32 pid, tid;
452 u64 time;
453 } *id;
454
455 pid = jr->move.pid;
456 tid = jr->move.tid;
457 idr_size = jd->machine->id_hdr_size;
458
459 /*
460 * +16 to account for sample_id_all (hack)
461 */
462 event = calloc(1, sizeof(*event) + 16);
463 if (!event)
464 return -1;
465
466 filename = event->mmap2.filename;
467 size = snprintf(filename, PATH_MAX, "%s/jitted-%d-%"PRIu64,
468 jd->dir,
469 pid,
470 jr->move.code_index);
471
472 size++; /* for \0 */
473
474 if (stat(filename, &st))
475 memset(&st, 0, sizeof(stat));
476
477 size = PERF_ALIGN(size, sizeof(u64));
478
479 event->mmap2.header.type = PERF_RECORD_MMAP2;
480 event->mmap2.header.misc = PERF_RECORD_MISC_USER;
481 event->mmap2.header.size = (sizeof(event->mmap2) -
482 (sizeof(event->mmap2.filename) - size) + idr_size);
483 event->mmap2.pgoff = GEN_ELF_TEXT_OFFSET;
484 event->mmap2.start = jr->move.new_code_addr;
485 event->mmap2.len = jr->move.code_size;
486 event->mmap2.pid = pid;
487 event->mmap2.tid = tid;
488 event->mmap2.ino = st.st_ino;
489 event->mmap2.maj = major(st.st_dev);
490 event->mmap2.min = minor(st.st_dev);
491 event->mmap2.prot = st.st_mode;
492 event->mmap2.flags = MAP_SHARED;
493 event->mmap2.ino_generation = 1;
494
495 id = (void *)((unsigned long)event + event->mmap.header.size - idr_size);
496 if (jd->sample_type & PERF_SAMPLE_TID) {
497 id->pid = pid;
498 id->tid = tid;
499 }
500 if (jd->sample_type & PERF_SAMPLE_TIME)
501 id->time = jr->load.p.timestamp;
502
503 /*
504 * create pseudo sample to induce dso hit increment
505 * use first address as sample address
506 */
507 memset(&sample, 0, sizeof(sample));
508 sample.pid = pid;
509 sample.tid = tid;
510 sample.time = id->time;
511 sample.ip = jr->move.new_code_addr;
512
513 ret = perf_event__process_mmap2(tool, event, &sample, jd->machine);
514 if (ret)
515 return ret;
516
517 ret = jit_inject_event(jd, event);
518 if (!ret)
519 build_id__mark_dso_hit(tool, event, &sample, NULL, jd->machine);
520
521 return ret;
522}
523
524static int jit_repipe_debug_info(struct jit_buf_desc *jd, union jr_entry *jr)
525{
526 void *data;
527 size_t sz;
528
529 if (!(jd && jr))
530 return -1;
531
532 sz = jr->prefix.total_size - sizeof(jr->info);
533 data = malloc(sz);
534 if (!data)
535 return -1;
536
537 memcpy(data, &jr->info.entries, sz);
538
539 jd->debug_data = data;
540
541 /*
542 * we must use nr_entry instead of size here because
543 * we cannot distinguish actual entry from padding otherwise
544 */
545 jd->nr_debug_entries = jr->info.nr_entry;
546
547 return 0;
548}
549
550static int
551jit_process_dump(struct jit_buf_desc *jd)
552{
553 union jr_entry *jr;
554 int ret;
555
556 while ((jr = jit_get_next_entry(jd))) {
557 switch(jr->prefix.id) {
558 case JIT_CODE_LOAD:
559 ret = jit_repipe_code_load(jd, jr);
560 break;
561 case JIT_CODE_MOVE:
562 ret = jit_repipe_code_move(jd, jr);
563 break;
564 case JIT_CODE_DEBUG_INFO:
565 ret = jit_repipe_debug_info(jd, jr);
566 break;
567 default:
568 ret = 0;
569 continue;
570 }
571 }
572 return ret;
573}
574
575static int
576jit_inject(struct jit_buf_desc *jd, char *path)
577{
578 int ret;
579
580 if (verbose > 0)
581 fprintf(stderr, "injecting: %s\n", path);
582
583 ret = jit_open(jd, path);
584 if (ret)
585 return -1;
586
587 ret = jit_process_dump(jd);
588
589 jit_close(jd);
590
591 if (verbose > 0)
592 fprintf(stderr, "injected: %s (%d)\n", path, ret);
593
594 return 0;
595}
596
597/*
598 * File must be with pattern .../jit-XXXX.dump
599 * where XXXX is the PID of the process which did the mmap()
600 * as captured in the RECORD_MMAP record
601 */
602static int
603jit_detect(char *mmap_name, pid_t pid)
604 {
605 char *p;
606 char *end = NULL;
607 pid_t pid2;
608
609 if (verbose > 2)
610 fprintf(stderr, "jit marker trying : %s\n", mmap_name);
611 /*
612 * get file name
613 */
614 p = strrchr(mmap_name, '/');
615 if (!p)
616 return -1;
617
618 /*
619 * match prefix
620 */
621 if (strncmp(p, "/jit-", 5))
622 return -1;
623
624 /*
625 * skip prefix
626 */
627 p += 5;
628
629 /*
630 * must be followed by a pid
631 */
632 if (!isdigit(*p))
633 return -1;
634
635 pid2 = (int)strtol(p, &end, 10);
636 if (!end)
637 return -1;
638
639 /*
640 * pid does not match mmap pid
641 * pid==0 in system-wide mode (synthesized)
642 */
643 if (pid && pid2 != pid)
644 return -1;
645 /*
646 * validate suffix
647 */
648 if (strcmp(end, ".dump"))
649 return -1;
650
651 if (verbose > 0)
652 fprintf(stderr, "jit marker found: %s\n", mmap_name);
653
654 return 0;
655}
656
657int
658jit_process(struct perf_session *session,
659 struct perf_data_file *output,
660 struct machine *machine,
661 char *filename,
662 pid_t pid,
663 u64 *nbytes)
664{
665 struct perf_evsel *first;
666 struct jit_buf_desc jd;
667 int ret;
668
669 /*
670 * first, detect marker mmap (i.e., the jitdump mmap)
671 */
672 if (jit_detect(filename, pid))
673 return 0;
674
675 memset(&jd, 0, sizeof(jd));
676
677 jd.session = session;
678 jd.output = output;
679 jd.machine = machine;
680
681 /*
682 * track sample_type to compute id_all layout
683 * perf sets the same sample type to all events as of now
684 */
685 first = perf_evlist__first(session->evlist);
686 jd.sample_type = first->attr.sample_type;
687
688 *nbytes = 0;
689
690 ret = jit_inject(&jd, filename);
691 if (!ret) {
692 *nbytes = jd.bytes_written;
693 ret = 1;
694 }
695
696 return ret;
697}
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/machine.h b/tools/perf/util/machine.h
index 2c2b443df5ba..1a3e45baf97f 100644
--- a/tools/perf/util/machine.h
+++ b/tools/perf/util/machine.h
@@ -180,6 +180,16 @@ struct symbol *machine__find_kernel_symbol(struct machine *machine,
180} 180}
181 181
182static inline 182static inline
183struct symbol *machine__find_kernel_symbol_by_name(struct machine *machine,
184 enum map_type type, const char *name,
185 struct map **mapp,
186 symbol_filter_t filter)
187{
188 return map_groups__find_symbol_by_name(&machine->kmaps, type, name,
189 mapp, filter);
190}
191
192static inline
183struct symbol *machine__find_kernel_function(struct machine *machine, u64 addr, 193struct symbol *machine__find_kernel_function(struct machine *machine, u64 addr,
184 struct map **mapp, 194 struct map **mapp,
185 symbol_filter_t filter) 195 symbol_filter_t filter)
diff --git a/tools/perf/util/mem-events.c b/tools/perf/util/mem-events.c
new file mode 100644
index 000000000000..75465f89a413
--- /dev/null
+++ b/tools/perf/util/mem-events.c
@@ -0,0 +1,255 @@
1#include <stddef.h>
2#include <stdlib.h>
3#include <string.h>
4#include <errno.h>
5#include <sys/types.h>
6#include <sys/stat.h>
7#include <unistd.h>
8#include <api/fs/fs.h>
9#include "mem-events.h"
10#include "debug.h"
11#include "symbol.h"
12
13#define E(t, n, s) { .tag = t, .name = n, .sysfs_name = s }
14
15struct perf_mem_event perf_mem_events[PERF_MEM_EVENTS__MAX] = {
16 E("ldlat-loads", "cpu/mem-loads,ldlat=30/P", "mem-loads"),
17 E("ldlat-stores", "cpu/mem-stores/P", "mem-stores"),
18};
19#undef E
20
21#undef E
22
23char *perf_mem_events__name(int i)
24{
25 return (char *)perf_mem_events[i].name;
26}
27
28int perf_mem_events__parse(const char *str)
29{
30 char *tok, *saveptr = NULL;
31 bool found = false;
32 char *buf;
33 int j;
34
35 /* We need buffer that we know we can write to. */
36 buf = malloc(strlen(str) + 1);
37 if (!buf)
38 return -ENOMEM;
39
40 strcpy(buf, str);
41
42 tok = strtok_r((char *)buf, ",", &saveptr);
43
44 while (tok) {
45 for (j = 0; j < PERF_MEM_EVENTS__MAX; j++) {
46 struct perf_mem_event *e = &perf_mem_events[j];
47
48 if (strstr(e->tag, tok))
49 e->record = found = true;
50 }
51
52 tok = strtok_r(NULL, ",", &saveptr);
53 }
54
55 free(buf);
56
57 if (found)
58 return 0;
59
60 pr_err("failed: event '%s' not found, use '-e list' to get list of available events\n", str);
61 return -1;
62}
63
64int perf_mem_events__init(void)
65{
66 const char *mnt = sysfs__mount();
67 bool found = false;
68 int j;
69
70 if (!mnt)
71 return -ENOENT;
72
73 for (j = 0; j < PERF_MEM_EVENTS__MAX; j++) {
74 char path[PATH_MAX];
75 struct perf_mem_event *e = &perf_mem_events[j];
76 struct stat st;
77
78 scnprintf(path, PATH_MAX, "%s/devices/cpu/events/%s",
79 mnt, e->sysfs_name);
80
81 if (!stat(path, &st))
82 e->supported = found = true;
83 }
84
85 return found ? 0 : -ENOENT;
86}
87
88static const char * const tlb_access[] = {
89 "N/A",
90 "HIT",
91 "MISS",
92 "L1",
93 "L2",
94 "Walker",
95 "Fault",
96};
97
98int perf_mem__tlb_scnprintf(char *out, size_t sz, struct mem_info *mem_info)
99{
100 size_t l = 0, i;
101 u64 m = PERF_MEM_TLB_NA;
102 u64 hit, miss;
103
104 sz -= 1; /* -1 for null termination */
105 out[0] = '\0';
106
107 if (mem_info)
108 m = mem_info->data_src.mem_dtlb;
109
110 hit = m & PERF_MEM_TLB_HIT;
111 miss = m & PERF_MEM_TLB_MISS;
112
113 /* already taken care of */
114 m &= ~(PERF_MEM_TLB_HIT|PERF_MEM_TLB_MISS);
115
116 for (i = 0; m && i < ARRAY_SIZE(tlb_access); i++, m >>= 1) {
117 if (!(m & 0x1))
118 continue;
119 if (l) {
120 strcat(out, " or ");
121 l += 4;
122 }
123 l += scnprintf(out + l, sz - l, tlb_access[i]);
124 }
125 if (*out == '\0')
126 l += scnprintf(out, sz - l, "N/A");
127 if (hit)
128 l += scnprintf(out + l, sz - l, " hit");
129 if (miss)
130 l += scnprintf(out + l, sz - l, " miss");
131
132 return l;
133}
134
135static const char * const mem_lvl[] = {
136 "N/A",
137 "HIT",
138 "MISS",
139 "L1",
140 "LFB",
141 "L2",
142 "L3",
143 "Local RAM",
144 "Remote RAM (1 hop)",
145 "Remote RAM (2 hops)",
146 "Remote Cache (1 hop)",
147 "Remote Cache (2 hops)",
148 "I/O",
149 "Uncached",
150};
151
152int perf_mem__lvl_scnprintf(char *out, size_t sz, struct mem_info *mem_info)
153{
154 size_t i, l = 0;
155 u64 m = PERF_MEM_LVL_NA;
156 u64 hit, miss;
157
158 if (mem_info)
159 m = mem_info->data_src.mem_lvl;
160
161 sz -= 1; /* -1 for null termination */
162 out[0] = '\0';
163
164 hit = m & PERF_MEM_LVL_HIT;
165 miss = m & PERF_MEM_LVL_MISS;
166
167 /* already taken care of */
168 m &= ~(PERF_MEM_LVL_HIT|PERF_MEM_LVL_MISS);
169
170 for (i = 0; m && i < ARRAY_SIZE(mem_lvl); i++, m >>= 1) {
171 if (!(m & 0x1))
172 continue;
173 if (l) {
174 strcat(out, " or ");
175 l += 4;
176 }
177 l += scnprintf(out + l, sz - l, mem_lvl[i]);
178 }
179 if (*out == '\0')
180 l += scnprintf(out, sz - l, "N/A");
181 if (hit)
182 l += scnprintf(out + l, sz - l, " hit");
183 if (miss)
184 l += scnprintf(out + l, sz - l, " miss");
185
186 return l;
187}
188
189static const char * const snoop_access[] = {
190 "N/A",
191 "None",
192 "Miss",
193 "Hit",
194 "HitM",
195};
196
197int perf_mem__snp_scnprintf(char *out, size_t sz, struct mem_info *mem_info)
198{
199 size_t i, l = 0;
200 u64 m = PERF_MEM_SNOOP_NA;
201
202 sz -= 1; /* -1 for null termination */
203 out[0] = '\0';
204
205 if (mem_info)
206 m = mem_info->data_src.mem_snoop;
207
208 for (i = 0; m && i < ARRAY_SIZE(snoop_access); i++, m >>= 1) {
209 if (!(m & 0x1))
210 continue;
211 if (l) {
212 strcat(out, " or ");
213 l += 4;
214 }
215 l += scnprintf(out + l, sz - l, snoop_access[i]);
216 }
217
218 if (*out == '\0')
219 l += scnprintf(out, sz - l, "N/A");
220
221 return l;
222}
223
224int perf_mem__lck_scnprintf(char *out, size_t sz, struct mem_info *mem_info)
225{
226 u64 mask = PERF_MEM_LOCK_NA;
227 int l;
228
229 if (mem_info)
230 mask = mem_info->data_src.mem_lock;
231
232 if (mask & PERF_MEM_LOCK_NA)
233 l = scnprintf(out, sz, "N/A");
234 else if (mask & PERF_MEM_LOCK_LOCKED)
235 l = scnprintf(out, sz, "Yes");
236 else
237 l = scnprintf(out, sz, "No");
238
239 return l;
240}
241
242int perf_script__meminfo_scnprintf(char *out, size_t sz, struct mem_info *mem_info)
243{
244 int i = 0;
245
246 i += perf_mem__lvl_scnprintf(out, sz, mem_info);
247 i += scnprintf(out + i, sz - i, "|SNP ");
248 i += perf_mem__snp_scnprintf(out + i, sz - i, mem_info);
249 i += scnprintf(out + i, sz - i, "|TLB ");
250 i += perf_mem__tlb_scnprintf(out + i, sz - i, mem_info);
251 i += scnprintf(out + i, sz - i, "|LCK ");
252 i += perf_mem__lck_scnprintf(out + i, sz - i, mem_info);
253
254 return i;
255}
diff --git a/tools/perf/util/mem-events.h b/tools/perf/util/mem-events.h
new file mode 100644
index 000000000000..5d6d93066a6e
--- /dev/null
+++ b/tools/perf/util/mem-events.h
@@ -0,0 +1,35 @@
1#ifndef __PERF_MEM_EVENTS_H
2#define __PERF_MEM_EVENTS_H
3
4#include <stdbool.h>
5
6struct perf_mem_event {
7 bool record;
8 bool supported;
9 const char *tag;
10 const char *name;
11 const char *sysfs_name;
12};
13
14enum {
15 PERF_MEM_EVENTS__LOAD,
16 PERF_MEM_EVENTS__STORE,
17 PERF_MEM_EVENTS__MAX,
18};
19
20extern struct perf_mem_event perf_mem_events[PERF_MEM_EVENTS__MAX];
21
22int perf_mem_events__parse(const char *str);
23int perf_mem_events__init(void);
24
25char *perf_mem_events__name(int i);
26
27struct mem_info;
28int perf_mem__tlb_scnprintf(char *out, size_t sz, struct mem_info *mem_info);
29int perf_mem__lvl_scnprintf(char *out, size_t sz, struct mem_info *mem_info);
30int perf_mem__snp_scnprintf(char *out, size_t sz, struct mem_info *mem_info);
31int perf_mem__lck_scnprintf(char *out, size_t sz, struct mem_info *mem_info);
32
33int perf_script__meminfo_scnprintf(char *bf, size_t size, struct mem_info *mem_info);
34
35#endif /* __PERF_MEM_EVENTS_H */
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index 813d9b272c81..4c19d5e79d8c 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -279,7 +279,24 @@ const char *event_type(int type)
279 return "unknown"; 279 return "unknown";
280} 280}
281 281
282static int parse_events__is_name_term(struct parse_events_term *term)
283{
284 return term->type_term == PARSE_EVENTS__TERM_TYPE_NAME;
285}
282 286
287static char *get_config_name(struct list_head *head_terms)
288{
289 struct parse_events_term *term;
290
291 if (!head_terms)
292 return NULL;
293
294 list_for_each_entry(term, head_terms, list)
295 if (parse_events__is_name_term(term))
296 return term->val.str;
297
298 return NULL;
299}
283 300
284static struct perf_evsel * 301static struct perf_evsel *
285__add_event(struct list_head *list, int *idx, 302__add_event(struct list_head *list, int *idx,
@@ -333,11 +350,25 @@ static int parse_aliases(char *str, const char *names[][PERF_EVSEL__MAX_ALIASES]
333 return -1; 350 return -1;
334} 351}
335 352
353typedef int config_term_func_t(struct perf_event_attr *attr,
354 struct parse_events_term *term,
355 struct parse_events_error *err);
356static int config_term_common(struct perf_event_attr *attr,
357 struct parse_events_term *term,
358 struct parse_events_error *err);
359static int config_attr(struct perf_event_attr *attr,
360 struct list_head *head,
361 struct parse_events_error *err,
362 config_term_func_t config_term);
363
336int parse_events_add_cache(struct list_head *list, int *idx, 364int parse_events_add_cache(struct list_head *list, int *idx,
337 char *type, char *op_result1, char *op_result2) 365 char *type, char *op_result1, char *op_result2,
366 struct parse_events_error *err,
367 struct list_head *head_config)
338{ 368{
339 struct perf_event_attr attr; 369 struct perf_event_attr attr;
340 char name[MAX_NAME_LEN]; 370 LIST_HEAD(config_terms);
371 char name[MAX_NAME_LEN], *config_name;
341 int cache_type = -1, cache_op = -1, cache_result = -1; 372 int cache_type = -1, cache_op = -1, cache_result = -1;
342 char *op_result[2] = { op_result1, op_result2 }; 373 char *op_result[2] = { op_result1, op_result2 };
343 int i, n; 374 int i, n;
@@ -351,6 +382,7 @@ int parse_events_add_cache(struct list_head *list, int *idx,
351 if (cache_type == -1) 382 if (cache_type == -1)
352 return -EINVAL; 383 return -EINVAL;
353 384
385 config_name = get_config_name(head_config);
354 n = snprintf(name, MAX_NAME_LEN, "%s", type); 386 n = snprintf(name, MAX_NAME_LEN, "%s", type);
355 387
356 for (i = 0; (i < 2) && (op_result[i]); i++) { 388 for (i = 0; (i < 2) && (op_result[i]); i++) {
@@ -391,7 +423,16 @@ int parse_events_add_cache(struct list_head *list, int *idx,
391 memset(&attr, 0, sizeof(attr)); 423 memset(&attr, 0, sizeof(attr));
392 attr.config = cache_type | (cache_op << 8) | (cache_result << 16); 424 attr.config = cache_type | (cache_op << 8) | (cache_result << 16);
393 attr.type = PERF_TYPE_HW_CACHE; 425 attr.type = PERF_TYPE_HW_CACHE;
394 return add_event(list, idx, &attr, name, NULL); 426
427 if (head_config) {
428 if (config_attr(&attr, head_config, err,
429 config_term_common))
430 return -EINVAL;
431
432 if (get_config_terms(head_config, &config_terms))
433 return -ENOMEM;
434 }
435 return add_event(list, idx, &attr, config_name ? : name, &config_terms);
395} 436}
396 437
397static void tracepoint_error(struct parse_events_error *e, int err, 438static void tracepoint_error(struct parse_events_error *e, int err,
@@ -540,6 +581,7 @@ static int add_tracepoint_multi_sys(struct list_head *list, int *idx,
540struct __add_bpf_event_param { 581struct __add_bpf_event_param {
541 struct parse_events_evlist *data; 582 struct parse_events_evlist *data;
542 struct list_head *list; 583 struct list_head *list;
584 struct list_head *head_config;
543}; 585};
544 586
545static int add_bpf_event(struct probe_trace_event *tev, int fd, 587static int add_bpf_event(struct probe_trace_event *tev, int fd,
@@ -556,7 +598,8 @@ static int add_bpf_event(struct probe_trace_event *tev, int fd,
556 tev->group, tev->event, fd); 598 tev->group, tev->event, fd);
557 599
558 err = parse_events_add_tracepoint(&new_evsels, &evlist->idx, tev->group, 600 err = parse_events_add_tracepoint(&new_evsels, &evlist->idx, tev->group,
559 tev->event, evlist->error, NULL); 601 tev->event, evlist->error,
602 param->head_config);
560 if (err) { 603 if (err) {
561 struct perf_evsel *evsel, *tmp; 604 struct perf_evsel *evsel, *tmp;
562 605
@@ -581,11 +624,12 @@ static int add_bpf_event(struct probe_trace_event *tev, int fd,
581 624
582int parse_events_load_bpf_obj(struct parse_events_evlist *data, 625int parse_events_load_bpf_obj(struct parse_events_evlist *data,
583 struct list_head *list, 626 struct list_head *list,
584 struct bpf_object *obj) 627 struct bpf_object *obj,
628 struct list_head *head_config)
585{ 629{
586 int err; 630 int err;
587 char errbuf[BUFSIZ]; 631 char errbuf[BUFSIZ];
588 struct __add_bpf_event_param param = {data, list}; 632 struct __add_bpf_event_param param = {data, list, head_config};
589 static bool registered_unprobe_atexit = false; 633 static bool registered_unprobe_atexit = false;
590 634
591 if (IS_ERR(obj) || !obj) { 635 if (IS_ERR(obj) || !obj) {
@@ -631,17 +675,99 @@ errout:
631 return err; 675 return err;
632} 676}
633 677
678static int
679parse_events_config_bpf(struct parse_events_evlist *data,
680 struct bpf_object *obj,
681 struct list_head *head_config)
682{
683 struct parse_events_term *term;
684 int error_pos;
685
686 if (!head_config || list_empty(head_config))
687 return 0;
688
689 list_for_each_entry(term, head_config, list) {
690 char errbuf[BUFSIZ];
691 int err;
692
693 if (term->type_term != PARSE_EVENTS__TERM_TYPE_USER) {
694 snprintf(errbuf, sizeof(errbuf),
695 "Invalid config term for BPF object");
696 errbuf[BUFSIZ - 1] = '\0';
697
698 data->error->idx = term->err_term;
699 data->error->str = strdup(errbuf);
700 return -EINVAL;
701 }
702
703 err = bpf__config_obj(obj, term, data->evlist, &error_pos);
704 if (err) {
705 bpf__strerror_config_obj(obj, term, data->evlist,
706 &error_pos, err, errbuf,
707 sizeof(errbuf));
708 data->error->help = strdup(
709"Hint:\tValid config terms:\n"
710" \tmap:[<arraymap>].value<indices>=[value]\n"
711" \tmap:[<eventmap>].event<indices>=[event]\n"
712"\n"
713" \twhere <indices> is something like [0,3...5] or [all]\n"
714" \t(add -v to see detail)");
715 data->error->str = strdup(errbuf);
716 if (err == -BPF_LOADER_ERRNO__OBJCONF_MAP_VALUE)
717 data->error->idx = term->err_val;
718 else
719 data->error->idx = term->err_term + error_pos;
720 return err;
721 }
722 }
723 return 0;
724}
725
726/*
727 * Split config terms:
728 * perf record -e bpf.c/call-graph=fp,map:array.value[0]=1/ ...
729 * 'call-graph=fp' is 'evt config', should be applied to each
730 * events in bpf.c.
731 * 'map:array.value[0]=1' is 'obj config', should be processed
732 * with parse_events_config_bpf.
733 *
734 * Move object config terms from the first list to obj_head_config.
735 */
736static void
737split_bpf_config_terms(struct list_head *evt_head_config,
738 struct list_head *obj_head_config)
739{
740 struct parse_events_term *term, *temp;
741
742 /*
743 * Currectly, all possible user config term
744 * belong to bpf object. parse_events__is_hardcoded_term()
745 * happends to be a good flag.
746 *
747 * See parse_events_config_bpf() and
748 * config_term_tracepoint().
749 */
750 list_for_each_entry_safe(term, temp, evt_head_config, list)
751 if (!parse_events__is_hardcoded_term(term))
752 list_move_tail(&term->list, obj_head_config);
753}
754
634int parse_events_load_bpf(struct parse_events_evlist *data, 755int parse_events_load_bpf(struct parse_events_evlist *data,
635 struct list_head *list, 756 struct list_head *list,
636 char *bpf_file_name, 757 char *bpf_file_name,
637 bool source) 758 bool source,
759 struct list_head *head_config)
638{ 760{
761 int err;
639 struct bpf_object *obj; 762 struct bpf_object *obj;
763 LIST_HEAD(obj_head_config);
764
765 if (head_config)
766 split_bpf_config_terms(head_config, &obj_head_config);
640 767
641 obj = bpf__prepare_load(bpf_file_name, source); 768 obj = bpf__prepare_load(bpf_file_name, source);
642 if (IS_ERR(obj)) { 769 if (IS_ERR(obj)) {
643 char errbuf[BUFSIZ]; 770 char errbuf[BUFSIZ];
644 int err;
645 771
646 err = PTR_ERR(obj); 772 err = PTR_ERR(obj);
647 773
@@ -659,7 +785,18 @@ int parse_events_load_bpf(struct parse_events_evlist *data,
659 return err; 785 return err;
660 } 786 }
661 787
662 return parse_events_load_bpf_obj(data, list, obj); 788 err = parse_events_load_bpf_obj(data, list, obj, head_config);
789 if (err)
790 return err;
791 err = parse_events_config_bpf(data, obj, &obj_head_config);
792
793 /*
794 * Caller doesn't know anything about obj_head_config,
795 * so combine them together again before returnning.
796 */
797 if (head_config)
798 list_splice_tail(&obj_head_config, head_config);
799 return err;
663} 800}
664 801
665static int 802static int
@@ -746,9 +883,59 @@ static int check_type_val(struct parse_events_term *term,
746 return -EINVAL; 883 return -EINVAL;
747} 884}
748 885
749typedef int config_term_func_t(struct perf_event_attr *attr, 886/*
750 struct parse_events_term *term, 887 * Update according to parse-events.l
751 struct parse_events_error *err); 888 */
889static const char *config_term_names[__PARSE_EVENTS__TERM_TYPE_NR] = {
890 [PARSE_EVENTS__TERM_TYPE_USER] = "<sysfs term>",
891 [PARSE_EVENTS__TERM_TYPE_CONFIG] = "config",
892 [PARSE_EVENTS__TERM_TYPE_CONFIG1] = "config1",
893 [PARSE_EVENTS__TERM_TYPE_CONFIG2] = "config2",
894 [PARSE_EVENTS__TERM_TYPE_NAME] = "name",
895 [PARSE_EVENTS__TERM_TYPE_SAMPLE_PERIOD] = "period",
896 [PARSE_EVENTS__TERM_TYPE_SAMPLE_FREQ] = "freq",
897 [PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE] = "branch_type",
898 [PARSE_EVENTS__TERM_TYPE_TIME] = "time",
899 [PARSE_EVENTS__TERM_TYPE_CALLGRAPH] = "call-graph",
900 [PARSE_EVENTS__TERM_TYPE_STACKSIZE] = "stack-size",
901 [PARSE_EVENTS__TERM_TYPE_NOINHERIT] = "no-inherit",
902 [PARSE_EVENTS__TERM_TYPE_INHERIT] = "inherit",
903};
904
905static bool config_term_shrinked;
906
907static bool
908config_term_avail(int term_type, struct parse_events_error *err)
909{
910 if (term_type < 0 || term_type >= __PARSE_EVENTS__TERM_TYPE_NR) {
911 err->str = strdup("Invalid term_type");
912 return false;
913 }
914 if (!config_term_shrinked)
915 return true;
916
917 switch (term_type) {
918 case PARSE_EVENTS__TERM_TYPE_CONFIG:
919 case PARSE_EVENTS__TERM_TYPE_CONFIG1:
920 case PARSE_EVENTS__TERM_TYPE_CONFIG2:
921 case PARSE_EVENTS__TERM_TYPE_NAME:
922 return true;
923 default:
924 if (!err)
925 return false;
926
927 /* term_type is validated so indexing is safe */
928 if (asprintf(&err->str, "'%s' is not usable in 'perf stat'",
929 config_term_names[term_type]) < 0)
930 err->str = NULL;
931 return false;
932 }
933}
934
935void parse_events__shrink_config_terms(void)
936{
937 config_term_shrinked = true;
938}
752 939
753static int config_term_common(struct perf_event_attr *attr, 940static int config_term_common(struct perf_event_attr *attr,
754 struct parse_events_term *term, 941 struct parse_events_term *term,
@@ -815,6 +1002,17 @@ do { \
815 return -EINVAL; 1002 return -EINVAL;
816 } 1003 }
817 1004
1005 /*
1006 * Check term availbility after basic checking so
1007 * PARSE_EVENTS__TERM_TYPE_USER can be found and filtered.
1008 *
1009 * If check availbility at the entry of this function,
1010 * user will see "'<sysfs term>' is not usable in 'perf stat'"
1011 * if an invalid config term is provided for legacy events
1012 * (for example, instructions/badterm/...), which is confusing.
1013 */
1014 if (!config_term_avail(term->type_term, err))
1015 return -EINVAL;
818 return 0; 1016 return 0;
819#undef CHECK_TYPE_VAL 1017#undef CHECK_TYPE_VAL
820} 1018}
@@ -961,23 +1159,8 @@ int parse_events_add_numeric(struct parse_events_evlist *data,
961 return -ENOMEM; 1159 return -ENOMEM;
962 } 1160 }
963 1161
964 return add_event(list, &data->idx, &attr, NULL, &config_terms); 1162 return add_event(list, &data->idx, &attr,
965} 1163 get_config_name(head_config), &config_terms);
966
967static int parse_events__is_name_term(struct parse_events_term *term)
968{
969 return term->type_term == PARSE_EVENTS__TERM_TYPE_NAME;
970}
971
972static char *pmu_event_name(struct list_head *head_terms)
973{
974 struct parse_events_term *term;
975
976 list_for_each_entry(term, head_terms, list)
977 if (parse_events__is_name_term(term))
978 return term->val.str;
979
980 return NULL;
981} 1164}
982 1165
983int parse_events_add_pmu(struct parse_events_evlist *data, 1166int parse_events_add_pmu(struct parse_events_evlist *data,
@@ -1024,7 +1207,7 @@ int parse_events_add_pmu(struct parse_events_evlist *data,
1024 return -EINVAL; 1207 return -EINVAL;
1025 1208
1026 evsel = __add_event(list, &data->idx, &attr, 1209 evsel = __add_event(list, &data->idx, &attr,
1027 pmu_event_name(head_config), pmu->cpus, 1210 get_config_name(head_config), pmu->cpus,
1028 &config_terms); 1211 &config_terms);
1029 if (evsel) { 1212 if (evsel) {
1030 evsel->unit = info.unit; 1213 evsel->unit = info.unit;
@@ -1386,8 +1569,7 @@ int parse_events_terms(struct list_head *terms, const char *str)
1386 return 0; 1569 return 0;
1387 } 1570 }
1388 1571
1389 if (data.terms) 1572 parse_events_terms__delete(data.terms);
1390 parse_events__free_terms(data.terms);
1391 return ret; 1573 return ret;
1392} 1574}
1393 1575
@@ -1395,9 +1577,10 @@ int parse_events(struct perf_evlist *evlist, const char *str,
1395 struct parse_events_error *err) 1577 struct parse_events_error *err)
1396{ 1578{
1397 struct parse_events_evlist data = { 1579 struct parse_events_evlist data = {
1398 .list = LIST_HEAD_INIT(data.list), 1580 .list = LIST_HEAD_INIT(data.list),
1399 .idx = evlist->nr_entries, 1581 .idx = evlist->nr_entries,
1400 .error = err, 1582 .error = err,
1583 .evlist = evlist,
1401 }; 1584 };
1402 int ret; 1585 int ret;
1403 1586
@@ -2068,12 +2251,29 @@ int parse_events_term__clone(struct parse_events_term **new,
2068 term->err_term, term->err_val); 2251 term->err_term, term->err_val);
2069} 2252}
2070 2253
2071void parse_events__free_terms(struct list_head *terms) 2254void parse_events_terms__purge(struct list_head *terms)
2072{ 2255{
2073 struct parse_events_term *term, *h; 2256 struct parse_events_term *term, *h;
2074 2257
2075 list_for_each_entry_safe(term, h, terms, list) 2258 list_for_each_entry_safe(term, h, terms, list) {
2259 if (term->array.nr_ranges)
2260 free(term->array.ranges);
2261 list_del_init(&term->list);
2076 free(term); 2262 free(term);
2263 }
2264}
2265
2266void parse_events_terms__delete(struct list_head *terms)
2267{
2268 if (!terms)
2269 return;
2270 parse_events_terms__purge(terms);
2271 free(terms);
2272}
2273
2274void parse_events__clear_array(struct parse_events_array *a)
2275{
2276 free(a->ranges);
2077} 2277}
2078 2278
2079void parse_events_evlist_error(struct parse_events_evlist *data, 2279void parse_events_evlist_error(struct parse_events_evlist *data,
@@ -2088,6 +2288,33 @@ void parse_events_evlist_error(struct parse_events_evlist *data,
2088 WARN_ONCE(!err->str, "WARNING: failed to allocate error string"); 2288 WARN_ONCE(!err->str, "WARNING: failed to allocate error string");
2089} 2289}
2090 2290
2291static void config_terms_list(char *buf, size_t buf_sz)
2292{
2293 int i;
2294 bool first = true;
2295
2296 buf[0] = '\0';
2297 for (i = 0; i < __PARSE_EVENTS__TERM_TYPE_NR; i++) {
2298 const char *name = config_term_names[i];
2299
2300 if (!config_term_avail(i, NULL))
2301 continue;
2302 if (!name)
2303 continue;
2304 if (name[0] == '<')
2305 continue;
2306
2307 if (strlen(buf) + strlen(name) + 2 >= buf_sz)
2308 return;
2309
2310 if (!first)
2311 strcat(buf, ",");
2312 else
2313 first = false;
2314 strcat(buf, name);
2315 }
2316}
2317
2091/* 2318/*
2092 * Return string contains valid config terms of an event. 2319 * Return string contains valid config terms of an event.
2093 * @additional_terms: For terms such as PMU sysfs terms. 2320 * @additional_terms: For terms such as PMU sysfs terms.
@@ -2095,17 +2322,18 @@ void parse_events_evlist_error(struct parse_events_evlist *data,
2095char *parse_events_formats_error_string(char *additional_terms) 2322char *parse_events_formats_error_string(char *additional_terms)
2096{ 2323{
2097 char *str; 2324 char *str;
2098 static const char *static_terms = "config,config1,config2,name," 2325 /* "branch_type" is the longest name */
2099 "period,freq,branch_type,time," 2326 char static_terms[__PARSE_EVENTS__TERM_TYPE_NR *
2100 "call-graph,stack-size\n"; 2327 (sizeof("branch_type") - 1)];
2101 2328
2329 config_terms_list(static_terms, sizeof(static_terms));
2102 /* valid terms */ 2330 /* valid terms */
2103 if (additional_terms) { 2331 if (additional_terms) {
2104 if (!asprintf(&str, "valid terms: %s,%s", 2332 if (asprintf(&str, "valid terms: %s,%s",
2105 additional_terms, static_terms)) 2333 additional_terms, static_terms) < 0)
2106 goto fail; 2334 goto fail;
2107 } else { 2335 } else {
2108 if (!asprintf(&str, "valid terms: %s", static_terms)) 2336 if (asprintf(&str, "valid terms: %s", static_terms) < 0)
2109 goto fail; 2337 goto fail;
2110 } 2338 }
2111 return str; 2339 return str;
diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h
index f1a6db107241..67e493088e81 100644
--- a/tools/perf/util/parse-events.h
+++ b/tools/perf/util/parse-events.h
@@ -68,11 +68,21 @@ enum {
68 PARSE_EVENTS__TERM_TYPE_CALLGRAPH, 68 PARSE_EVENTS__TERM_TYPE_CALLGRAPH,
69 PARSE_EVENTS__TERM_TYPE_STACKSIZE, 69 PARSE_EVENTS__TERM_TYPE_STACKSIZE,
70 PARSE_EVENTS__TERM_TYPE_NOINHERIT, 70 PARSE_EVENTS__TERM_TYPE_NOINHERIT,
71 PARSE_EVENTS__TERM_TYPE_INHERIT 71 PARSE_EVENTS__TERM_TYPE_INHERIT,
72 __PARSE_EVENTS__TERM_TYPE_NR,
73};
74
75struct parse_events_array {
76 size_t nr_ranges;
77 struct {
78 unsigned int start;
79 size_t length;
80 } *ranges;
72}; 81};
73 82
74struct parse_events_term { 83struct parse_events_term {
75 char *config; 84 char *config;
85 struct parse_events_array array;
76 union { 86 union {
77 char *str; 87 char *str;
78 u64 num; 88 u64 num;
@@ -98,12 +108,14 @@ struct parse_events_evlist {
98 int idx; 108 int idx;
99 int nr_groups; 109 int nr_groups;
100 struct parse_events_error *error; 110 struct parse_events_error *error;
111 struct perf_evlist *evlist;
101}; 112};
102 113
103struct parse_events_terms { 114struct parse_events_terms {
104 struct list_head *terms; 115 struct list_head *terms;
105}; 116};
106 117
118void parse_events__shrink_config_terms(void);
107int parse_events__is_hardcoded_term(struct parse_events_term *term); 119int parse_events__is_hardcoded_term(struct parse_events_term *term);
108int parse_events_term__num(struct parse_events_term **term, 120int parse_events_term__num(struct parse_events_term **term,
109 int type_term, char *config, u64 num, 121 int type_term, char *config, u64 num,
@@ -115,7 +127,9 @@ int parse_events_term__sym_hw(struct parse_events_term **term,
115 char *config, unsigned idx); 127 char *config, unsigned idx);
116int parse_events_term__clone(struct parse_events_term **new, 128int parse_events_term__clone(struct parse_events_term **new,
117 struct parse_events_term *term); 129 struct parse_events_term *term);
118void parse_events__free_terms(struct list_head *terms); 130void parse_events_terms__delete(struct list_head *terms);
131void parse_events_terms__purge(struct list_head *terms);
132void parse_events__clear_array(struct parse_events_array *a);
119int parse_events__modifier_event(struct list_head *list, char *str, bool add); 133int parse_events__modifier_event(struct list_head *list, char *str, bool add);
120int parse_events__modifier_group(struct list_head *list, char *event_mod); 134int parse_events__modifier_group(struct list_head *list, char *event_mod);
121int parse_events_name(struct list_head *list, char *name); 135int parse_events_name(struct list_head *list, char *name);
@@ -126,18 +140,22 @@ int parse_events_add_tracepoint(struct list_head *list, int *idx,
126int parse_events_load_bpf(struct parse_events_evlist *data, 140int parse_events_load_bpf(struct parse_events_evlist *data,
127 struct list_head *list, 141 struct list_head *list,
128 char *bpf_file_name, 142 char *bpf_file_name,
129 bool source); 143 bool source,
144 struct list_head *head_config);
130/* Provide this function for perf test */ 145/* Provide this function for perf test */
131struct bpf_object; 146struct bpf_object;
132int parse_events_load_bpf_obj(struct parse_events_evlist *data, 147int parse_events_load_bpf_obj(struct parse_events_evlist *data,
133 struct list_head *list, 148 struct list_head *list,
134 struct bpf_object *obj); 149 struct bpf_object *obj,
150 struct list_head *head_config);
135int parse_events_add_numeric(struct parse_events_evlist *data, 151int parse_events_add_numeric(struct parse_events_evlist *data,
136 struct list_head *list, 152 struct list_head *list,
137 u32 type, u64 config, 153 u32 type, u64 config,
138 struct list_head *head_config); 154 struct list_head *head_config);
139int parse_events_add_cache(struct list_head *list, int *idx, 155int parse_events_add_cache(struct list_head *list, int *idx,
140 char *type, char *op_result1, char *op_result2); 156 char *type, char *op_result1, char *op_result2,
157 struct parse_events_error *error,
158 struct list_head *head_config);
141int parse_events_add_breakpoint(struct list_head *list, int *idx, 159int parse_events_add_breakpoint(struct list_head *list, int *idx,
142 void *ptr, char *type, u64 len); 160 void *ptr, char *type, u64 len);
143int parse_events_add_pmu(struct parse_events_evlist *data, 161int parse_events_add_pmu(struct parse_events_evlist *data,
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/pmu.c b/tools/perf/util/pmu.c
index b597bcc8fc78..adef23b1352e 100644
--- a/tools/perf/util/pmu.c
+++ b/tools/perf/util/pmu.c
@@ -98,7 +98,7 @@ static int perf_pmu__parse_scale(struct perf_pmu_alias *alias, char *dir, char *
98 char scale[128]; 98 char scale[128];
99 int fd, ret = -1; 99 int fd, ret = -1;
100 char path[PATH_MAX]; 100 char path[PATH_MAX];
101 const char *lc; 101 char *lc;
102 102
103 snprintf(path, PATH_MAX, "%s/%s.scale", dir, name); 103 snprintf(path, PATH_MAX, "%s/%s.scale", dir, name);
104 104
@@ -124,6 +124,17 @@ static int perf_pmu__parse_scale(struct perf_pmu_alias *alias, char *dir, char *
124 lc = setlocale(LC_NUMERIC, NULL); 124 lc = setlocale(LC_NUMERIC, NULL);
125 125
126 /* 126 /*
127 * The lc string may be allocated in static storage,
128 * so get a dynamic copy to make it survive setlocale
129 * call below.
130 */
131 lc = strdup(lc);
132 if (!lc) {
133 ret = -ENOMEM;
134 goto error;
135 }
136
137 /*
127 * force to C locale to ensure kernel 138 * force to C locale to ensure kernel
128 * scale string is converted correctly. 139 * scale string is converted correctly.
129 * kernel uses default C locale. 140 * kernel uses default C locale.
@@ -135,6 +146,8 @@ static int perf_pmu__parse_scale(struct perf_pmu_alias *alias, char *dir, char *
135 /* restore locale */ 146 /* restore locale */
136 setlocale(LC_NUMERIC, lc); 147 setlocale(LC_NUMERIC, lc);
137 148
149 free(lc);
150
138 ret = 0; 151 ret = 0;
139error: 152error:
140 close(fd); 153 close(fd);
@@ -153,7 +166,7 @@ static int perf_pmu__parse_unit(struct perf_pmu_alias *alias, char *dir, char *n
153 if (fd == -1) 166 if (fd == -1)
154 return -1; 167 return -1;
155 168
156 sret = read(fd, alias->unit, UNIT_MAX_LEN); 169 sret = read(fd, alias->unit, UNIT_MAX_LEN);
157 if (sret < 0) 170 if (sret < 0)
158 goto error; 171 goto error;
159 172
@@ -284,13 +297,12 @@ static int pmu_aliases_parse(char *dir, struct list_head *head)
284{ 297{
285 struct dirent *evt_ent; 298 struct dirent *evt_ent;
286 DIR *event_dir; 299 DIR *event_dir;
287 int ret = 0;
288 300
289 event_dir = opendir(dir); 301 event_dir = opendir(dir);
290 if (!event_dir) 302 if (!event_dir)
291 return -EINVAL; 303 return -EINVAL;
292 304
293 while (!ret && (evt_ent = readdir(event_dir))) { 305 while ((evt_ent = readdir(event_dir))) {
294 char path[PATH_MAX]; 306 char path[PATH_MAX];
295 char *name = evt_ent->d_name; 307 char *name = evt_ent->d_name;
296 FILE *file; 308 FILE *file;
@@ -306,17 +318,19 @@ static int pmu_aliases_parse(char *dir, struct list_head *head)
306 318
307 snprintf(path, PATH_MAX, "%s/%s", dir, name); 319 snprintf(path, PATH_MAX, "%s/%s", dir, name);
308 320
309 ret = -EINVAL;
310 file = fopen(path, "r"); 321 file = fopen(path, "r");
311 if (!file) 322 if (!file) {
312 break; 323 pr_debug("Cannot open %s\n", path);
324 continue;
325 }
313 326
314 ret = perf_pmu__new_alias(head, dir, name, file); 327 if (perf_pmu__new_alias(head, dir, name, file) < 0)
328 pr_debug("Cannot set up %s\n", name);
315 fclose(file); 329 fclose(file);
316 } 330 }
317 331
318 closedir(event_dir); 332 closedir(event_dir);
319 return ret; 333 return 0;
320} 334}
321 335
322/* 336/*
@@ -354,7 +368,7 @@ static int pmu_alias_terms(struct perf_pmu_alias *alias,
354 list_for_each_entry(term, &alias->terms, list) { 368 list_for_each_entry(term, &alias->terms, list) {
355 ret = parse_events_term__clone(&cloned, term); 369 ret = parse_events_term__clone(&cloned, term);
356 if (ret) { 370 if (ret) {
357 parse_events__free_terms(&list); 371 parse_events_terms__purge(&list);
358 return ret; 372 return ret;
359 } 373 }
360 list_add_tail(&cloned->list, &list); 374 list_add_tail(&cloned->list, &list);
diff --git a/tools/perf/util/scripting-engines/trace-event-perl.c b/tools/perf/util/scripting-engines/trace-event-perl.c
index 544509c159ce..b3aabc0d4eb0 100644
--- a/tools/perf/util/scripting-engines/trace-event-perl.c
+++ b/tools/perf/util/scripting-engines/trace-event-perl.c
@@ -187,6 +187,9 @@ static void define_event_symbols(struct event_format *event,
187 const char *ev_name, 187 const char *ev_name,
188 struct print_arg *args) 188 struct print_arg *args)
189{ 189{
190 if (args == NULL)
191 return;
192
190 switch (args->type) { 193 switch (args->type) {
191 case PRINT_NULL: 194 case PRINT_NULL:
192 break; 195 break;
diff --git a/tools/perf/util/scripting-engines/trace-event-python.c b/tools/perf/util/scripting-engines/trace-event-python.c
index d72fafc1c800..fbd05242b4e5 100644
--- a/tools/perf/util/scripting-engines/trace-event-python.c
+++ b/tools/perf/util/scripting-engines/trace-event-python.c
@@ -205,6 +205,9 @@ static void define_event_symbols(struct event_format *event,
205 const char *ev_name, 205 const char *ev_name,
206 struct print_arg *args) 206 struct print_arg *args)
207{ 207{
208 if (args == NULL)
209 return;
210
208 switch (args->type) { 211 switch (args->type) {
209 case PRINT_NULL: 212 case PRINT_NULL:
210 break; 213 break;
@@ -1091,8 +1094,6 @@ static int python_start_script(const char *script, int argc, const char **argv)
1091 goto error; 1094 goto error;
1092 } 1095 }
1093 1096
1094 free(command_line);
1095
1096 set_table_handlers(tables); 1097 set_table_handlers(tables);
1097 1098
1098 if (tables->db_export_mode) { 1099 if (tables->db_export_mode) {
@@ -1101,6 +1102,8 @@ static int python_start_script(const char *script, int argc, const char **argv)
1101 goto error; 1102 goto error;
1102 } 1103 }
1103 1104
1105 free(command_line);
1106
1104 return err; 1107 return err;
1105error: 1108error:
1106 Py_Finalize(); 1109 Py_Finalize();
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
index 40b7a0d0905b..60b3593d210d 100644
--- a/tools/perf/util/session.c
+++ b/tools/perf/util/session.c
@@ -240,14 +240,6 @@ static int process_event_stub(struct perf_tool *tool __maybe_unused,
240 return 0; 240 return 0;
241} 241}
242 242
243static int process_build_id_stub(struct perf_tool *tool __maybe_unused,
244 union perf_event *event __maybe_unused,
245 struct perf_session *session __maybe_unused)
246{
247 dump_printf(": unhandled!\n");
248 return 0;
249}
250
251static int process_finished_round_stub(struct perf_tool *tool __maybe_unused, 243static int process_finished_round_stub(struct perf_tool *tool __maybe_unused,
252 union perf_event *event __maybe_unused, 244 union perf_event *event __maybe_unused,
253 struct ordered_events *oe __maybe_unused) 245 struct ordered_events *oe __maybe_unused)
@@ -260,23 +252,6 @@ static int process_finished_round(struct perf_tool *tool,
260 union perf_event *event, 252 union perf_event *event,
261 struct ordered_events *oe); 253 struct ordered_events *oe);
262 254
263static int process_id_index_stub(struct perf_tool *tool __maybe_unused,
264 union perf_event *event __maybe_unused,
265 struct perf_session *perf_session
266 __maybe_unused)
267{
268 dump_printf(": unhandled!\n");
269 return 0;
270}
271
272static int process_event_auxtrace_info_stub(struct perf_tool *tool __maybe_unused,
273 union perf_event *event __maybe_unused,
274 struct perf_session *session __maybe_unused)
275{
276 dump_printf(": unhandled!\n");
277 return 0;
278}
279
280static int skipn(int fd, off_t n) 255static int skipn(int fd, off_t n)
281{ 256{
282 char buf[4096]; 257 char buf[4096];
@@ -303,10 +278,9 @@ static s64 process_event_auxtrace_stub(struct perf_tool *tool __maybe_unused,
303 return event->auxtrace.size; 278 return event->auxtrace.size;
304} 279}
305 280
306static 281static int process_event_op2_stub(struct perf_tool *tool __maybe_unused,
307int process_event_auxtrace_error_stub(struct perf_tool *tool __maybe_unused, 282 union perf_event *event __maybe_unused,
308 union perf_event *event __maybe_unused, 283 struct perf_session *session __maybe_unused)
309 struct perf_session *session __maybe_unused)
310{ 284{
311 dump_printf(": unhandled!\n"); 285 dump_printf(": unhandled!\n");
312 return 0; 286 return 0;
@@ -410,7 +384,7 @@ void perf_tool__fill_defaults(struct perf_tool *tool)
410 if (tool->tracing_data == NULL) 384 if (tool->tracing_data == NULL)
411 tool->tracing_data = process_event_synth_tracing_data_stub; 385 tool->tracing_data = process_event_synth_tracing_data_stub;
412 if (tool->build_id == NULL) 386 if (tool->build_id == NULL)
413 tool->build_id = process_build_id_stub; 387 tool->build_id = process_event_op2_stub;
414 if (tool->finished_round == NULL) { 388 if (tool->finished_round == NULL) {
415 if (tool->ordered_events) 389 if (tool->ordered_events)
416 tool->finished_round = process_finished_round; 390 tool->finished_round = process_finished_round;
@@ -418,13 +392,13 @@ void perf_tool__fill_defaults(struct perf_tool *tool)
418 tool->finished_round = process_finished_round_stub; 392 tool->finished_round = process_finished_round_stub;
419 } 393 }
420 if (tool->id_index == NULL) 394 if (tool->id_index == NULL)
421 tool->id_index = process_id_index_stub; 395 tool->id_index = process_event_op2_stub;
422 if (tool->auxtrace_info == NULL) 396 if (tool->auxtrace_info == NULL)
423 tool->auxtrace_info = process_event_auxtrace_info_stub; 397 tool->auxtrace_info = process_event_op2_stub;
424 if (tool->auxtrace == NULL) 398 if (tool->auxtrace == NULL)
425 tool->auxtrace = process_event_auxtrace_stub; 399 tool->auxtrace = process_event_auxtrace_stub;
426 if (tool->auxtrace_error == NULL) 400 if (tool->auxtrace_error == NULL)
427 tool->auxtrace_error = process_event_auxtrace_error_stub; 401 tool->auxtrace_error = process_event_op2_stub;
428 if (tool->thread_map == NULL) 402 if (tool->thread_map == NULL)
429 tool->thread_map = process_event_thread_map_stub; 403 tool->thread_map = process_event_thread_map_stub;
430 if (tool->cpu_map == NULL) 404 if (tool->cpu_map == NULL)
diff --git a/tools/perf/util/setup.py b/tools/perf/util/setup.py
index 1833103768cb..c8680984d2d6 100644
--- a/tools/perf/util/setup.py
+++ b/tools/perf/util/setup.py
@@ -22,6 +22,7 @@ cflags = getenv('CFLAGS', '').split()
22# switch off several checks (need to be at the end of cflags list) 22# switch off several checks (need to be at the end of cflags list)
23cflags += ['-fno-strict-aliasing', '-Wno-write-strings', '-Wno-unused-parameter' ] 23cflags += ['-fno-strict-aliasing', '-Wno-write-strings', '-Wno-unused-parameter' ]
24 24
25src_perf = getenv('srctree') + '/tools/perf'
25build_lib = getenv('PYTHON_EXTBUILD_LIB') 26build_lib = getenv('PYTHON_EXTBUILD_LIB')
26build_tmp = getenv('PYTHON_EXTBUILD_TMP') 27build_tmp = getenv('PYTHON_EXTBUILD_TMP')
27libtraceevent = getenv('LIBTRACEEVENT') 28libtraceevent = getenv('LIBTRACEEVENT')
@@ -30,6 +31,9 @@ libapikfs = getenv('LIBAPI')
30ext_sources = [f.strip() for f in file('util/python-ext-sources') 31ext_sources = [f.strip() for f in file('util/python-ext-sources')
31 if len(f.strip()) > 0 and f[0] != '#'] 32 if len(f.strip()) > 0 and f[0] != '#']
32 33
34# use full paths with source files
35ext_sources = map(lambda x: '%s/%s' % (src_perf, x) , ext_sources)
36
33perf = Extension('perf', 37perf = Extension('perf',
34 sources = ext_sources, 38 sources = ext_sources,
35 include_dirs = ['util/include'], 39 include_dirs = ['util/include'],
diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c
index ec722346e6ff..93fa136b0025 100644
--- a/tools/perf/util/sort.c
+++ b/tools/perf/util/sort.c
@@ -6,6 +6,7 @@
6#include "evsel.h" 6#include "evsel.h"
7#include "evlist.h" 7#include "evlist.h"
8#include <traceevent/event-parse.h> 8#include <traceevent/event-parse.h>
9#include "mem-events.h"
9 10
10regex_t parent_regex; 11regex_t parent_regex;
11const char default_parent_pattern[] = "^sys_|^do_page_fault"; 12const char default_parent_pattern[] = "^sys_|^do_page_fault";
@@ -25,9 +26,19 @@ int sort__has_parent = 0;
25int sort__has_sym = 0; 26int sort__has_sym = 0;
26int sort__has_dso = 0; 27int sort__has_dso = 0;
27int sort__has_socket = 0; 28int sort__has_socket = 0;
29int sort__has_thread = 0;
30int sort__has_comm = 0;
28enum sort_mode sort__mode = SORT_MODE__NORMAL; 31enum sort_mode sort__mode = SORT_MODE__NORMAL;
29 32
30 33/*
34 * Replaces all occurrences of a char used with the:
35 *
36 * -t, --field-separator
37 *
38 * option, that uses a special separator character and don't pad with spaces,
39 * replacing all occurances of this separator in symbol names (and other
40 * output) with a '.' character, that thus it's the only non valid separator.
41*/
31static int repsep_snprintf(char *bf, size_t size, const char *fmt, ...) 42static int repsep_snprintf(char *bf, size_t size, const char *fmt, ...)
32{ 43{
33 int n; 44 int n;
@@ -80,10 +91,21 @@ static int hist_entry__thread_snprintf(struct hist_entry *he, char *bf,
80 width, width, comm ?: ""); 91 width, width, comm ?: "");
81} 92}
82 93
94static int hist_entry__thread_filter(struct hist_entry *he, int type, const void *arg)
95{
96 const struct thread *th = arg;
97
98 if (type != HIST_FILTER__THREAD)
99 return -1;
100
101 return th && he->thread != th;
102}
103
83struct sort_entry sort_thread = { 104struct sort_entry sort_thread = {
84 .se_header = " Pid:Command", 105 .se_header = " Pid:Command",
85 .se_cmp = sort__thread_cmp, 106 .se_cmp = sort__thread_cmp,
86 .se_snprintf = hist_entry__thread_snprintf, 107 .se_snprintf = hist_entry__thread_snprintf,
108 .se_filter = hist_entry__thread_filter,
87 .se_width_idx = HISTC_THREAD, 109 .se_width_idx = HISTC_THREAD,
88}; 110};
89 111
@@ -121,6 +143,7 @@ struct sort_entry sort_comm = {
121 .se_collapse = sort__comm_collapse, 143 .se_collapse = sort__comm_collapse,
122 .se_sort = sort__comm_sort, 144 .se_sort = sort__comm_sort,
123 .se_snprintf = hist_entry__comm_snprintf, 145 .se_snprintf = hist_entry__comm_snprintf,
146 .se_filter = hist_entry__thread_filter,
124 .se_width_idx = HISTC_COMM, 147 .se_width_idx = HISTC_COMM,
125}; 148};
126 149
@@ -170,10 +193,21 @@ static int hist_entry__dso_snprintf(struct hist_entry *he, char *bf,
170 return _hist_entry__dso_snprintf(he->ms.map, bf, size, width); 193 return _hist_entry__dso_snprintf(he->ms.map, bf, size, width);
171} 194}
172 195
196static int hist_entry__dso_filter(struct hist_entry *he, int type, const void *arg)
197{
198 const struct dso *dso = arg;
199
200 if (type != HIST_FILTER__DSO)
201 return -1;
202
203 return dso && (!he->ms.map || he->ms.map->dso != dso);
204}
205
173struct sort_entry sort_dso = { 206struct sort_entry sort_dso = {
174 .se_header = "Shared Object", 207 .se_header = "Shared Object",
175 .se_cmp = sort__dso_cmp, 208 .se_cmp = sort__dso_cmp,
176 .se_snprintf = hist_entry__dso_snprintf, 209 .se_snprintf = hist_entry__dso_snprintf,
210 .se_filter = hist_entry__dso_filter,
177 .se_width_idx = HISTC_DSO, 211 .se_width_idx = HISTC_DSO,
178}; 212};
179 213
@@ -246,10 +280,8 @@ static int _hist_entry__sym_snprintf(struct map *map, struct symbol *sym,
246 ret += repsep_snprintf(bf + ret, size - ret, "%s", sym->name); 280 ret += repsep_snprintf(bf + ret, size - ret, "%s", sym->name);
247 ret += repsep_snprintf(bf + ret, size - ret, "+0x%llx", 281 ret += repsep_snprintf(bf + ret, size - ret, "+0x%llx",
248 ip - map->unmap_ip(map, sym->start)); 282 ip - map->unmap_ip(map, sym->start));
249 ret += repsep_snprintf(bf + ret, size - ret, "%-*s",
250 width - ret, "");
251 } else { 283 } else {
252 ret += repsep_snprintf(bf + ret, size - ret, "%-*s", 284 ret += repsep_snprintf(bf + ret, size - ret, "%.*s",
253 width - ret, 285 width - ret,
254 sym->name); 286 sym->name);
255 } 287 }
@@ -257,14 +289,9 @@ static int _hist_entry__sym_snprintf(struct map *map, struct symbol *sym,
257 size_t len = BITS_PER_LONG / 4; 289 size_t len = BITS_PER_LONG / 4;
258 ret += repsep_snprintf(bf + ret, size - ret, "%-#.*llx", 290 ret += repsep_snprintf(bf + ret, size - ret, "%-#.*llx",
259 len, ip); 291 len, ip);
260 ret += repsep_snprintf(bf + ret, size - ret, "%-*s",
261 width - ret, "");
262 } 292 }
263 293
264 if (ret > width) 294 return ret;
265 bf[width] = '\0';
266
267 return width;
268} 295}
269 296
270static int hist_entry__sym_snprintf(struct hist_entry *he, char *bf, 297static int hist_entry__sym_snprintf(struct hist_entry *he, char *bf,
@@ -274,46 +301,56 @@ static int hist_entry__sym_snprintf(struct hist_entry *he, char *bf,
274 he->level, bf, size, width); 301 he->level, bf, size, width);
275} 302}
276 303
304static int hist_entry__sym_filter(struct hist_entry *he, int type, const void *arg)
305{
306 const char *sym = arg;
307
308 if (type != HIST_FILTER__SYMBOL)
309 return -1;
310
311 return sym && (!he->ms.sym || !strstr(he->ms.sym->name, sym));
312}
313
277struct sort_entry sort_sym = { 314struct sort_entry sort_sym = {
278 .se_header = "Symbol", 315 .se_header = "Symbol",
279 .se_cmp = sort__sym_cmp, 316 .se_cmp = sort__sym_cmp,
280 .se_sort = sort__sym_sort, 317 .se_sort = sort__sym_sort,
281 .se_snprintf = hist_entry__sym_snprintf, 318 .se_snprintf = hist_entry__sym_snprintf,
319 .se_filter = hist_entry__sym_filter,
282 .se_width_idx = HISTC_SYMBOL, 320 .se_width_idx = HISTC_SYMBOL,
283}; 321};
284 322
285/* --sort srcline */ 323/* --sort srcline */
286 324
325static char *hist_entry__get_srcline(struct hist_entry *he)
326{
327 struct map *map = he->ms.map;
328
329 if (!map)
330 return SRCLINE_UNKNOWN;
331
332 return get_srcline(map->dso, map__rip_2objdump(map, he->ip),
333 he->ms.sym, true);
334}
335
287static int64_t 336static int64_t
288sort__srcline_cmp(struct hist_entry *left, struct hist_entry *right) 337sort__srcline_cmp(struct hist_entry *left, struct hist_entry *right)
289{ 338{
290 if (!left->srcline) { 339 if (!left->srcline)
291 if (!left->ms.map) 340 left->srcline = hist_entry__get_srcline(left);
292 left->srcline = SRCLINE_UNKNOWN; 341 if (!right->srcline)
293 else { 342 right->srcline = hist_entry__get_srcline(right);
294 struct map *map = left->ms.map; 343
295 left->srcline = get_srcline(map->dso,
296 map__rip_2objdump(map, left->ip),
297 left->ms.sym, true);
298 }
299 }
300 if (!right->srcline) {
301 if (!right->ms.map)
302 right->srcline = SRCLINE_UNKNOWN;
303 else {
304 struct map *map = right->ms.map;
305 right->srcline = get_srcline(map->dso,
306 map__rip_2objdump(map, right->ip),
307 right->ms.sym, true);
308 }
309 }
310 return strcmp(right->srcline, left->srcline); 344 return strcmp(right->srcline, left->srcline);
311} 345}
312 346
313static int hist_entry__srcline_snprintf(struct hist_entry *he, char *bf, 347static int hist_entry__srcline_snprintf(struct hist_entry *he, char *bf,
314 size_t size, unsigned int width) 348 size_t size, unsigned int width)
315{ 349{
316 return repsep_snprintf(bf, size, "%-*.*s", width, width, he->srcline); 350 if (!he->srcline)
351 he->srcline = hist_entry__get_srcline(he);
352
353 return repsep_snprintf(bf, size, "%-.*s", width, he->srcline);
317} 354}
318 355
319struct sort_entry sort_srcline = { 356struct sort_entry sort_srcline = {
@@ -327,11 +364,14 @@ struct sort_entry sort_srcline = {
327 364
328static char no_srcfile[1]; 365static char no_srcfile[1];
329 366
330static char *get_srcfile(struct hist_entry *e) 367static char *hist_entry__get_srcfile(struct hist_entry *e)
331{ 368{
332 char *sf, *p; 369 char *sf, *p;
333 struct map *map = e->ms.map; 370 struct map *map = e->ms.map;
334 371
372 if (!map)
373 return no_srcfile;
374
335 sf = __get_srcline(map->dso, map__rip_2objdump(map, e->ip), 375 sf = __get_srcline(map->dso, map__rip_2objdump(map, e->ip),
336 e->ms.sym, false, true); 376 e->ms.sym, false, true);
337 if (!strcmp(sf, SRCLINE_UNKNOWN)) 377 if (!strcmp(sf, SRCLINE_UNKNOWN))
@@ -348,25 +388,21 @@ static char *get_srcfile(struct hist_entry *e)
348static int64_t 388static int64_t
349sort__srcfile_cmp(struct hist_entry *left, struct hist_entry *right) 389sort__srcfile_cmp(struct hist_entry *left, struct hist_entry *right)
350{ 390{
351 if (!left->srcfile) { 391 if (!left->srcfile)
352 if (!left->ms.map) 392 left->srcfile = hist_entry__get_srcfile(left);
353 left->srcfile = no_srcfile; 393 if (!right->srcfile)
354 else 394 right->srcfile = hist_entry__get_srcfile(right);
355 left->srcfile = get_srcfile(left); 395
356 }
357 if (!right->srcfile) {
358 if (!right->ms.map)
359 right->srcfile = no_srcfile;
360 else
361 right->srcfile = get_srcfile(right);
362 }
363 return strcmp(right->srcfile, left->srcfile); 396 return strcmp(right->srcfile, left->srcfile);
364} 397}
365 398
366static int hist_entry__srcfile_snprintf(struct hist_entry *he, char *bf, 399static int hist_entry__srcfile_snprintf(struct hist_entry *he, char *bf,
367 size_t size, unsigned int width) 400 size_t size, unsigned int width)
368{ 401{
369 return repsep_snprintf(bf, size, "%-*.*s", width, width, he->srcfile); 402 if (!he->srcfile)
403 he->srcfile = hist_entry__get_srcfile(he);
404
405 return repsep_snprintf(bf, size, "%-.*s", width, he->srcfile);
370} 406}
371 407
372struct sort_entry sort_srcfile = { 408struct sort_entry sort_srcfile = {
@@ -439,10 +475,21 @@ static int hist_entry__socket_snprintf(struct hist_entry *he, char *bf,
439 return repsep_snprintf(bf, size, "%*.*d", width, width-3, he->socket); 475 return repsep_snprintf(bf, size, "%*.*d", width, width-3, he->socket);
440} 476}
441 477
478static int hist_entry__socket_filter(struct hist_entry *he, int type, const void *arg)
479{
480 int sk = *(const int *)arg;
481
482 if (type != HIST_FILTER__SOCKET)
483 return -1;
484
485 return sk >= 0 && he->socket != sk;
486}
487
442struct sort_entry sort_socket = { 488struct sort_entry sort_socket = {
443 .se_header = "Socket", 489 .se_header = "Socket",
444 .se_cmp = sort__socket_cmp, 490 .se_cmp = sort__socket_cmp,
445 .se_snprintf = hist_entry__socket_snprintf, 491 .se_snprintf = hist_entry__socket_snprintf,
492 .se_filter = hist_entry__socket_filter,
446 .se_width_idx = HISTC_SOCKET, 493 .se_width_idx = HISTC_SOCKET,
447}; 494};
448 495
@@ -483,9 +530,6 @@ sort__trace_cmp(struct hist_entry *left, struct hist_entry *right)
483 if (right->trace_output == NULL) 530 if (right->trace_output == NULL)
484 right->trace_output = get_trace_output(right); 531 right->trace_output = get_trace_output(right);
485 532
486 hists__new_col_len(left->hists, HISTC_TRACE, strlen(left->trace_output));
487 hists__new_col_len(right->hists, HISTC_TRACE, strlen(right->trace_output));
488
489 return strcmp(right->trace_output, left->trace_output); 533 return strcmp(right->trace_output, left->trace_output);
490} 534}
491 535
@@ -496,11 +540,11 @@ static int hist_entry__trace_snprintf(struct hist_entry *he, char *bf,
496 540
497 evsel = hists_to_evsel(he->hists); 541 evsel = hists_to_evsel(he->hists);
498 if (evsel->attr.type != PERF_TYPE_TRACEPOINT) 542 if (evsel->attr.type != PERF_TYPE_TRACEPOINT)
499 return scnprintf(bf, size, "%-*.*s", width, width, "N/A"); 543 return scnprintf(bf, size, "%-.*s", width, "N/A");
500 544
501 if (he->trace_output == NULL) 545 if (he->trace_output == NULL)
502 he->trace_output = get_trace_output(he); 546 he->trace_output = get_trace_output(he);
503 return repsep_snprintf(bf, size, "%-*.*s", width, width, he->trace_output); 547 return repsep_snprintf(bf, size, "%-.*s", width, he->trace_output);
504} 548}
505 549
506struct sort_entry sort_trace = { 550struct sort_entry sort_trace = {
@@ -532,6 +576,18 @@ static int hist_entry__dso_from_snprintf(struct hist_entry *he, char *bf,
532 return repsep_snprintf(bf, size, "%-*.*s", width, width, "N/A"); 576 return repsep_snprintf(bf, size, "%-*.*s", width, width, "N/A");
533} 577}
534 578
579static int hist_entry__dso_from_filter(struct hist_entry *he, int type,
580 const void *arg)
581{
582 const struct dso *dso = arg;
583
584 if (type != HIST_FILTER__DSO)
585 return -1;
586
587 return dso && (!he->branch_info || !he->branch_info->from.map ||
588 he->branch_info->from.map->dso != dso);
589}
590
535static int64_t 591static int64_t
536sort__dso_to_cmp(struct hist_entry *left, struct hist_entry *right) 592sort__dso_to_cmp(struct hist_entry *left, struct hist_entry *right)
537{ 593{
@@ -552,6 +608,18 @@ static int hist_entry__dso_to_snprintf(struct hist_entry *he, char *bf,
552 return repsep_snprintf(bf, size, "%-*.*s", width, width, "N/A"); 608 return repsep_snprintf(bf, size, "%-*.*s", width, width, "N/A");
553} 609}
554 610
611static int hist_entry__dso_to_filter(struct hist_entry *he, int type,
612 const void *arg)
613{
614 const struct dso *dso = arg;
615
616 if (type != HIST_FILTER__DSO)
617 return -1;
618
619 return dso && (!he->branch_info || !he->branch_info->to.map ||
620 he->branch_info->to.map->dso != dso);
621}
622
555static int64_t 623static int64_t
556sort__sym_from_cmp(struct hist_entry *left, struct hist_entry *right) 624sort__sym_from_cmp(struct hist_entry *left, struct hist_entry *right)
557{ 625{
@@ -613,10 +681,35 @@ static int hist_entry__sym_to_snprintf(struct hist_entry *he, char *bf,
613 return repsep_snprintf(bf, size, "%-*.*s", width, width, "N/A"); 681 return repsep_snprintf(bf, size, "%-*.*s", width, width, "N/A");
614} 682}
615 683
684static int hist_entry__sym_from_filter(struct hist_entry *he, int type,
685 const void *arg)
686{
687 const char *sym = arg;
688
689 if (type != HIST_FILTER__SYMBOL)
690 return -1;
691
692 return sym && !(he->branch_info && he->branch_info->from.sym &&
693 strstr(he->branch_info->from.sym->name, sym));
694}
695
696static int hist_entry__sym_to_filter(struct hist_entry *he, int type,
697 const void *arg)
698{
699 const char *sym = arg;
700
701 if (type != HIST_FILTER__SYMBOL)
702 return -1;
703
704 return sym && !(he->branch_info && he->branch_info->to.sym &&
705 strstr(he->branch_info->to.sym->name, sym));
706}
707
616struct sort_entry sort_dso_from = { 708struct sort_entry sort_dso_from = {
617 .se_header = "Source Shared Object", 709 .se_header = "Source Shared Object",
618 .se_cmp = sort__dso_from_cmp, 710 .se_cmp = sort__dso_from_cmp,
619 .se_snprintf = hist_entry__dso_from_snprintf, 711 .se_snprintf = hist_entry__dso_from_snprintf,
712 .se_filter = hist_entry__dso_from_filter,
620 .se_width_idx = HISTC_DSO_FROM, 713 .se_width_idx = HISTC_DSO_FROM,
621}; 714};
622 715
@@ -624,6 +717,7 @@ struct sort_entry sort_dso_to = {
624 .se_header = "Target Shared Object", 717 .se_header = "Target Shared Object",
625 .se_cmp = sort__dso_to_cmp, 718 .se_cmp = sort__dso_to_cmp,
626 .se_snprintf = hist_entry__dso_to_snprintf, 719 .se_snprintf = hist_entry__dso_to_snprintf,
720 .se_filter = hist_entry__dso_to_filter,
627 .se_width_idx = HISTC_DSO_TO, 721 .se_width_idx = HISTC_DSO_TO,
628}; 722};
629 723
@@ -631,6 +725,7 @@ struct sort_entry sort_sym_from = {
631 .se_header = "Source Symbol", 725 .se_header = "Source Symbol",
632 .se_cmp = sort__sym_from_cmp, 726 .se_cmp = sort__sym_from_cmp,
633 .se_snprintf = hist_entry__sym_from_snprintf, 727 .se_snprintf = hist_entry__sym_from_snprintf,
728 .se_filter = hist_entry__sym_from_filter,
634 .se_width_idx = HISTC_SYMBOL_FROM, 729 .se_width_idx = HISTC_SYMBOL_FROM,
635}; 730};
636 731
@@ -638,6 +733,7 @@ struct sort_entry sort_sym_to = {
638 .se_header = "Target Symbol", 733 .se_header = "Target Symbol",
639 .se_cmp = sort__sym_to_cmp, 734 .se_cmp = sort__sym_to_cmp,
640 .se_snprintf = hist_entry__sym_to_snprintf, 735 .se_snprintf = hist_entry__sym_to_snprintf,
736 .se_filter = hist_entry__sym_to_filter,
641 .se_width_idx = HISTC_SYMBOL_TO, 737 .se_width_idx = HISTC_SYMBOL_TO,
642}; 738};
643 739
@@ -797,20 +893,10 @@ sort__locked_cmp(struct hist_entry *left, struct hist_entry *right)
797static int hist_entry__locked_snprintf(struct hist_entry *he, char *bf, 893static int hist_entry__locked_snprintf(struct hist_entry *he, char *bf,
798 size_t size, unsigned int width) 894 size_t size, unsigned int width)
799{ 895{
800 const char *out; 896 char out[10];
801 u64 mask = PERF_MEM_LOCK_NA;
802 897
803 if (he->mem_info) 898 perf_mem__lck_scnprintf(out, sizeof(out), he->mem_info);
804 mask = he->mem_info->data_src.mem_lock; 899 return repsep_snprintf(bf, size, "%.*s", width, out);
805
806 if (mask & PERF_MEM_LOCK_NA)
807 out = "N/A";
808 else if (mask & PERF_MEM_LOCK_LOCKED)
809 out = "Yes";
810 else
811 out = "No";
812
813 return repsep_snprintf(bf, size, "%-*s", width, out);
814} 900}
815 901
816static int64_t 902static int64_t
@@ -832,54 +918,12 @@ sort__tlb_cmp(struct hist_entry *left, struct hist_entry *right)
832 return (int64_t)(data_src_r.mem_dtlb - data_src_l.mem_dtlb); 918 return (int64_t)(data_src_r.mem_dtlb - data_src_l.mem_dtlb);
833} 919}
834 920
835static const char * const tlb_access[] = {
836 "N/A",
837 "HIT",
838 "MISS",
839 "L1",
840 "L2",
841 "Walker",
842 "Fault",
843};
844#define NUM_TLB_ACCESS (sizeof(tlb_access)/sizeof(const char *))
845
846static int hist_entry__tlb_snprintf(struct hist_entry *he, char *bf, 921static int hist_entry__tlb_snprintf(struct hist_entry *he, char *bf,
847 size_t size, unsigned int width) 922 size_t size, unsigned int width)
848{ 923{
849 char out[64]; 924 char out[64];
850 size_t sz = sizeof(out) - 1; /* -1 for null termination */
851 size_t l = 0, i;
852 u64 m = PERF_MEM_TLB_NA;
853 u64 hit, miss;
854
855 out[0] = '\0';
856
857 if (he->mem_info)
858 m = he->mem_info->data_src.mem_dtlb;
859
860 hit = m & PERF_MEM_TLB_HIT;
861 miss = m & PERF_MEM_TLB_MISS;
862
863 /* already taken care of */
864 m &= ~(PERF_MEM_TLB_HIT|PERF_MEM_TLB_MISS);
865
866 for (i = 0; m && i < NUM_TLB_ACCESS; i++, m >>= 1) {
867 if (!(m & 0x1))
868 continue;
869 if (l) {
870 strcat(out, " or ");
871 l += 4;
872 }
873 strncat(out, tlb_access[i], sz - l);
874 l += strlen(tlb_access[i]);
875 }
876 if (*out == '\0')
877 strcpy(out, "N/A");
878 if (hit)
879 strncat(out, " hit", sz - l);
880 if (miss)
881 strncat(out, " miss", sz - l);
882 925
926 perf_mem__tlb_scnprintf(out, sizeof(out), he->mem_info);
883 return repsep_snprintf(bf, size, "%-*s", width, out); 927 return repsep_snprintf(bf, size, "%-*s", width, out);
884} 928}
885 929
@@ -902,61 +946,12 @@ sort__lvl_cmp(struct hist_entry *left, struct hist_entry *right)
902 return (int64_t)(data_src_r.mem_lvl - data_src_l.mem_lvl); 946 return (int64_t)(data_src_r.mem_lvl - data_src_l.mem_lvl);
903} 947}
904 948
905static const char * const mem_lvl[] = {
906 "N/A",
907 "HIT",
908 "MISS",
909 "L1",
910 "LFB",
911 "L2",
912 "L3",
913 "Local RAM",
914 "Remote RAM (1 hop)",
915 "Remote RAM (2 hops)",
916 "Remote Cache (1 hop)",
917 "Remote Cache (2 hops)",
918 "I/O",
919 "Uncached",
920};
921#define NUM_MEM_LVL (sizeof(mem_lvl)/sizeof(const char *))
922
923static int hist_entry__lvl_snprintf(struct hist_entry *he, char *bf, 949static int hist_entry__lvl_snprintf(struct hist_entry *he, char *bf,
924 size_t size, unsigned int width) 950 size_t size, unsigned int width)
925{ 951{
926 char out[64]; 952 char out[64];
927 size_t sz = sizeof(out) - 1; /* -1 for null termination */
928 size_t i, l = 0;
929 u64 m = PERF_MEM_LVL_NA;
930 u64 hit, miss;
931
932 if (he->mem_info)
933 m = he->mem_info->data_src.mem_lvl;
934
935 out[0] = '\0';
936
937 hit = m & PERF_MEM_LVL_HIT;
938 miss = m & PERF_MEM_LVL_MISS;
939
940 /* already taken care of */
941 m &= ~(PERF_MEM_LVL_HIT|PERF_MEM_LVL_MISS);
942
943 for (i = 0; m && i < NUM_MEM_LVL; i++, m >>= 1) {
944 if (!(m & 0x1))
945 continue;
946 if (l) {
947 strcat(out, " or ");
948 l += 4;
949 }
950 strncat(out, mem_lvl[i], sz - l);
951 l += strlen(mem_lvl[i]);
952 }
953 if (*out == '\0')
954 strcpy(out, "N/A");
955 if (hit)
956 strncat(out, " hit", sz - l);
957 if (miss)
958 strncat(out, " miss", sz - l);
959 953
954 perf_mem__lvl_scnprintf(out, sizeof(out), he->mem_info);
960 return repsep_snprintf(bf, size, "%-*s", width, out); 955 return repsep_snprintf(bf, size, "%-*s", width, out);
961} 956}
962 957
@@ -979,51 +974,15 @@ sort__snoop_cmp(struct hist_entry *left, struct hist_entry *right)
979 return (int64_t)(data_src_r.mem_snoop - data_src_l.mem_snoop); 974 return (int64_t)(data_src_r.mem_snoop - data_src_l.mem_snoop);
980} 975}
981 976
982static const char * const snoop_access[] = {
983 "N/A",
984 "None",
985 "Miss",
986 "Hit",
987 "HitM",
988};
989#define NUM_SNOOP_ACCESS (sizeof(snoop_access)/sizeof(const char *))
990
991static int hist_entry__snoop_snprintf(struct hist_entry *he, char *bf, 977static int hist_entry__snoop_snprintf(struct hist_entry *he, char *bf,
992 size_t size, unsigned int width) 978 size_t size, unsigned int width)
993{ 979{
994 char out[64]; 980 char out[64];
995 size_t sz = sizeof(out) - 1; /* -1 for null termination */
996 size_t i, l = 0;
997 u64 m = PERF_MEM_SNOOP_NA;
998
999 out[0] = '\0';
1000
1001 if (he->mem_info)
1002 m = he->mem_info->data_src.mem_snoop;
1003
1004 for (i = 0; m && i < NUM_SNOOP_ACCESS; i++, m >>= 1) {
1005 if (!(m & 0x1))
1006 continue;
1007 if (l) {
1008 strcat(out, " or ");
1009 l += 4;
1010 }
1011 strncat(out, snoop_access[i], sz - l);
1012 l += strlen(snoop_access[i]);
1013 }
1014
1015 if (*out == '\0')
1016 strcpy(out, "N/A");
1017 981
982 perf_mem__snp_scnprintf(out, sizeof(out), he->mem_info);
1018 return repsep_snprintf(bf, size, "%-*s", width, out); 983 return repsep_snprintf(bf, size, "%-*s", width, out);
1019} 984}
1020 985
1021static inline u64 cl_address(u64 address)
1022{
1023 /* return the cacheline of the address */
1024 return (address & ~(cacheline_size - 1));
1025}
1026
1027static int64_t 986static int64_t
1028sort__dcacheline_cmp(struct hist_entry *left, struct hist_entry *right) 987sort__dcacheline_cmp(struct hist_entry *left, struct hist_entry *right)
1029{ 988{
@@ -1440,20 +1399,6 @@ struct hpp_sort_entry {
1440 struct sort_entry *se; 1399 struct sort_entry *se;
1441}; 1400};
1442 1401
1443bool perf_hpp__same_sort_entry(struct perf_hpp_fmt *a, struct perf_hpp_fmt *b)
1444{
1445 struct hpp_sort_entry *hse_a;
1446 struct hpp_sort_entry *hse_b;
1447
1448 if (!perf_hpp__is_sort_entry(a) || !perf_hpp__is_sort_entry(b))
1449 return false;
1450
1451 hse_a = container_of(a, struct hpp_sort_entry, hpp);
1452 hse_b = container_of(b, struct hpp_sort_entry, hpp);
1453
1454 return hse_a->se == hse_b->se;
1455}
1456
1457void perf_hpp__reset_sort_width(struct perf_hpp_fmt *fmt, struct hists *hists) 1402void perf_hpp__reset_sort_width(struct perf_hpp_fmt *fmt, struct hists *hists)
1458{ 1403{
1459 struct hpp_sort_entry *hse; 1404 struct hpp_sort_entry *hse;
@@ -1539,8 +1484,56 @@ static int64_t __sort__hpp_sort(struct perf_hpp_fmt *fmt,
1539 return sort_fn(a, b); 1484 return sort_fn(a, b);
1540} 1485}
1541 1486
1487bool perf_hpp__is_sort_entry(struct perf_hpp_fmt *format)
1488{
1489 return format->header == __sort__hpp_header;
1490}
1491
1492#define MK_SORT_ENTRY_CHK(key) \
1493bool perf_hpp__is_ ## key ## _entry(struct perf_hpp_fmt *fmt) \
1494{ \
1495 struct hpp_sort_entry *hse; \
1496 \
1497 if (!perf_hpp__is_sort_entry(fmt)) \
1498 return false; \
1499 \
1500 hse = container_of(fmt, struct hpp_sort_entry, hpp); \
1501 return hse->se == &sort_ ## key ; \
1502}
1503
1504MK_SORT_ENTRY_CHK(trace)
1505MK_SORT_ENTRY_CHK(srcline)
1506MK_SORT_ENTRY_CHK(srcfile)
1507MK_SORT_ENTRY_CHK(thread)
1508MK_SORT_ENTRY_CHK(comm)
1509MK_SORT_ENTRY_CHK(dso)
1510MK_SORT_ENTRY_CHK(sym)
1511
1512
1513static bool __sort__hpp_equal(struct perf_hpp_fmt *a, struct perf_hpp_fmt *b)
1514{
1515 struct hpp_sort_entry *hse_a;
1516 struct hpp_sort_entry *hse_b;
1517
1518 if (!perf_hpp__is_sort_entry(a) || !perf_hpp__is_sort_entry(b))
1519 return false;
1520
1521 hse_a = container_of(a, struct hpp_sort_entry, hpp);
1522 hse_b = container_of(b, struct hpp_sort_entry, hpp);
1523
1524 return hse_a->se == hse_b->se;
1525}
1526
1527static void hse_free(struct perf_hpp_fmt *fmt)
1528{
1529 struct hpp_sort_entry *hse;
1530
1531 hse = container_of(fmt, struct hpp_sort_entry, hpp);
1532 free(hse);
1533}
1534
1542static struct hpp_sort_entry * 1535static struct hpp_sort_entry *
1543__sort_dimension__alloc_hpp(struct sort_dimension *sd) 1536__sort_dimension__alloc_hpp(struct sort_dimension *sd, int level)
1544{ 1537{
1545 struct hpp_sort_entry *hse; 1538 struct hpp_sort_entry *hse;
1546 1539
@@ -1560,40 +1553,92 @@ __sort_dimension__alloc_hpp(struct sort_dimension *sd)
1560 hse->hpp.cmp = __sort__hpp_cmp; 1553 hse->hpp.cmp = __sort__hpp_cmp;
1561 hse->hpp.collapse = __sort__hpp_collapse; 1554 hse->hpp.collapse = __sort__hpp_collapse;
1562 hse->hpp.sort = __sort__hpp_sort; 1555 hse->hpp.sort = __sort__hpp_sort;
1556 hse->hpp.equal = __sort__hpp_equal;
1557 hse->hpp.free = hse_free;
1563 1558
1564 INIT_LIST_HEAD(&hse->hpp.list); 1559 INIT_LIST_HEAD(&hse->hpp.list);
1565 INIT_LIST_HEAD(&hse->hpp.sort_list); 1560 INIT_LIST_HEAD(&hse->hpp.sort_list);
1566 hse->hpp.elide = false; 1561 hse->hpp.elide = false;
1567 hse->hpp.len = 0; 1562 hse->hpp.len = 0;
1568 hse->hpp.user_len = 0; 1563 hse->hpp.user_len = 0;
1564 hse->hpp.level = level;
1569 1565
1570 return hse; 1566 return hse;
1571} 1567}
1572 1568
1573bool perf_hpp__is_sort_entry(struct perf_hpp_fmt *format) 1569static void hpp_free(struct perf_hpp_fmt *fmt)
1574{ 1570{
1575 return format->header == __sort__hpp_header; 1571 free(fmt);
1572}
1573
1574static struct perf_hpp_fmt *__hpp_dimension__alloc_hpp(struct hpp_dimension *hd,
1575 int level)
1576{
1577 struct perf_hpp_fmt *fmt;
1578
1579 fmt = memdup(hd->fmt, sizeof(*fmt));
1580 if (fmt) {
1581 INIT_LIST_HEAD(&fmt->list);
1582 INIT_LIST_HEAD(&fmt->sort_list);
1583 fmt->free = hpp_free;
1584 fmt->level = level;
1585 }
1586
1587 return fmt;
1588}
1589
1590int hist_entry__filter(struct hist_entry *he, int type, const void *arg)
1591{
1592 struct perf_hpp_fmt *fmt;
1593 struct hpp_sort_entry *hse;
1594 int ret = -1;
1595 int r;
1596
1597 perf_hpp_list__for_each_format(he->hpp_list, fmt) {
1598 if (!perf_hpp__is_sort_entry(fmt))
1599 continue;
1600
1601 hse = container_of(fmt, struct hpp_sort_entry, hpp);
1602 if (hse->se->se_filter == NULL)
1603 continue;
1604
1605 /*
1606 * hist entry is filtered if any of sort key in the hpp list
1607 * is applied. But it should skip non-matched filter types.
1608 */
1609 r = hse->se->se_filter(he, type, arg);
1610 if (r >= 0) {
1611 if (ret < 0)
1612 ret = 0;
1613 ret |= r;
1614 }
1615 }
1616
1617 return ret;
1576} 1618}
1577 1619
1578static int __sort_dimension__add_hpp_sort(struct sort_dimension *sd) 1620static int __sort_dimension__add_hpp_sort(struct sort_dimension *sd,
1621 struct perf_hpp_list *list,
1622 int level)
1579{ 1623{
1580 struct hpp_sort_entry *hse = __sort_dimension__alloc_hpp(sd); 1624 struct hpp_sort_entry *hse = __sort_dimension__alloc_hpp(sd, level);
1581 1625
1582 if (hse == NULL) 1626 if (hse == NULL)
1583 return -1; 1627 return -1;
1584 1628
1585 perf_hpp__register_sort_field(&hse->hpp); 1629 perf_hpp_list__register_sort_field(list, &hse->hpp);
1586 return 0; 1630 return 0;
1587} 1631}
1588 1632
1589static int __sort_dimension__add_hpp_output(struct sort_dimension *sd) 1633static int __sort_dimension__add_hpp_output(struct sort_dimension *sd,
1634 struct perf_hpp_list *list)
1590{ 1635{
1591 struct hpp_sort_entry *hse = __sort_dimension__alloc_hpp(sd); 1636 struct hpp_sort_entry *hse = __sort_dimension__alloc_hpp(sd, 0);
1592 1637
1593 if (hse == NULL) 1638 if (hse == NULL)
1594 return -1; 1639 return -1;
1595 1640
1596 perf_hpp__column_register(&hse->hpp); 1641 perf_hpp_list__column_register(list, &hse->hpp);
1597 return 0; 1642 return 0;
1598} 1643}
1599 1644
@@ -1727,6 +1772,9 @@ static int __sort__hde_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
1727 if (hde->raw_trace) 1772 if (hde->raw_trace)
1728 goto raw_field; 1773 goto raw_field;
1729 1774
1775 if (!he->trace_output)
1776 he->trace_output = get_trace_output(he);
1777
1730 field = hde->field; 1778 field = hde->field;
1731 namelen = strlen(field->name); 1779 namelen = strlen(field->name);
1732 str = he->trace_output; 1780 str = he->trace_output;
@@ -1776,6 +1824,11 @@ static int64_t __sort__hde_cmp(struct perf_hpp_fmt *fmt,
1776 1824
1777 hde = container_of(fmt, struct hpp_dynamic_entry, hpp); 1825 hde = container_of(fmt, struct hpp_dynamic_entry, hpp);
1778 1826
1827 if (b == NULL) {
1828 update_dynamic_len(hde, a);
1829 return 0;
1830 }
1831
1779 field = hde->field; 1832 field = hde->field;
1780 if (field->flags & FIELD_IS_DYNAMIC) { 1833 if (field->flags & FIELD_IS_DYNAMIC) {
1781 unsigned long long dyn; 1834 unsigned long long dyn;
@@ -1790,9 +1843,6 @@ static int64_t __sort__hde_cmp(struct perf_hpp_fmt *fmt,
1790 } else { 1843 } else {
1791 offset = field->offset; 1844 offset = field->offset;
1792 size = field->size; 1845 size = field->size;
1793
1794 update_dynamic_len(hde, a);
1795 update_dynamic_len(hde, b);
1796 } 1846 }
1797 1847
1798 return memcmp(a->raw_data + offset, b->raw_data + offset, size); 1848 return memcmp(a->raw_data + offset, b->raw_data + offset, size);
@@ -1803,8 +1853,31 @@ bool perf_hpp__is_dynamic_entry(struct perf_hpp_fmt *fmt)
1803 return fmt->cmp == __sort__hde_cmp; 1853 return fmt->cmp == __sort__hde_cmp;
1804} 1854}
1805 1855
1856static bool __sort__hde_equal(struct perf_hpp_fmt *a, struct perf_hpp_fmt *b)
1857{
1858 struct hpp_dynamic_entry *hde_a;
1859 struct hpp_dynamic_entry *hde_b;
1860
1861 if (!perf_hpp__is_dynamic_entry(a) || !perf_hpp__is_dynamic_entry(b))
1862 return false;
1863
1864 hde_a = container_of(a, struct hpp_dynamic_entry, hpp);
1865 hde_b = container_of(b, struct hpp_dynamic_entry, hpp);
1866
1867 return hde_a->field == hde_b->field;
1868}
1869
1870static void hde_free(struct perf_hpp_fmt *fmt)
1871{
1872 struct hpp_dynamic_entry *hde;
1873
1874 hde = container_of(fmt, struct hpp_dynamic_entry, hpp);
1875 free(hde);
1876}
1877
1806static struct hpp_dynamic_entry * 1878static struct hpp_dynamic_entry *
1807__alloc_dynamic_entry(struct perf_evsel *evsel, struct format_field *field) 1879__alloc_dynamic_entry(struct perf_evsel *evsel, struct format_field *field,
1880 int level)
1808{ 1881{
1809 struct hpp_dynamic_entry *hde; 1882 struct hpp_dynamic_entry *hde;
1810 1883
@@ -1827,16 +1900,47 @@ __alloc_dynamic_entry(struct perf_evsel *evsel, struct format_field *field)
1827 hde->hpp.cmp = __sort__hde_cmp; 1900 hde->hpp.cmp = __sort__hde_cmp;
1828 hde->hpp.collapse = __sort__hde_cmp; 1901 hde->hpp.collapse = __sort__hde_cmp;
1829 hde->hpp.sort = __sort__hde_cmp; 1902 hde->hpp.sort = __sort__hde_cmp;
1903 hde->hpp.equal = __sort__hde_equal;
1904 hde->hpp.free = hde_free;
1830 1905
1831 INIT_LIST_HEAD(&hde->hpp.list); 1906 INIT_LIST_HEAD(&hde->hpp.list);
1832 INIT_LIST_HEAD(&hde->hpp.sort_list); 1907 INIT_LIST_HEAD(&hde->hpp.sort_list);
1833 hde->hpp.elide = false; 1908 hde->hpp.elide = false;
1834 hde->hpp.len = 0; 1909 hde->hpp.len = 0;
1835 hde->hpp.user_len = 0; 1910 hde->hpp.user_len = 0;
1911 hde->hpp.level = level;
1836 1912
1837 return hde; 1913 return hde;
1838} 1914}
1839 1915
1916struct perf_hpp_fmt *perf_hpp_fmt__dup(struct perf_hpp_fmt *fmt)
1917{
1918 struct perf_hpp_fmt *new_fmt = NULL;
1919
1920 if (perf_hpp__is_sort_entry(fmt)) {
1921 struct hpp_sort_entry *hse, *new_hse;
1922
1923 hse = container_of(fmt, struct hpp_sort_entry, hpp);
1924 new_hse = memdup(hse, sizeof(*hse));
1925 if (new_hse)
1926 new_fmt = &new_hse->hpp;
1927 } else if (perf_hpp__is_dynamic_entry(fmt)) {
1928 struct hpp_dynamic_entry *hde, *new_hde;
1929
1930 hde = container_of(fmt, struct hpp_dynamic_entry, hpp);
1931 new_hde = memdup(hde, sizeof(*hde));
1932 if (new_hde)
1933 new_fmt = &new_hde->hpp;
1934 } else {
1935 new_fmt = memdup(fmt, sizeof(*fmt));
1936 }
1937
1938 INIT_LIST_HEAD(&new_fmt->list);
1939 INIT_LIST_HEAD(&new_fmt->sort_list);
1940
1941 return new_fmt;
1942}
1943
1840static int parse_field_name(char *str, char **event, char **field, char **opt) 1944static int parse_field_name(char *str, char **event, char **field, char **opt)
1841{ 1945{
1842 char *event_name, *field_name, *opt_name; 1946 char *event_name, *field_name, *opt_name;
@@ -1908,11 +2012,11 @@ static struct perf_evsel *find_evsel(struct perf_evlist *evlist, char *event_nam
1908 2012
1909static int __dynamic_dimension__add(struct perf_evsel *evsel, 2013static int __dynamic_dimension__add(struct perf_evsel *evsel,
1910 struct format_field *field, 2014 struct format_field *field,
1911 bool raw_trace) 2015 bool raw_trace, int level)
1912{ 2016{
1913 struct hpp_dynamic_entry *hde; 2017 struct hpp_dynamic_entry *hde;
1914 2018
1915 hde = __alloc_dynamic_entry(evsel, field); 2019 hde = __alloc_dynamic_entry(evsel, field, level);
1916 if (hde == NULL) 2020 if (hde == NULL)
1917 return -ENOMEM; 2021 return -ENOMEM;
1918 2022
@@ -1922,14 +2026,14 @@ static int __dynamic_dimension__add(struct perf_evsel *evsel,
1922 return 0; 2026 return 0;
1923} 2027}
1924 2028
1925static int add_evsel_fields(struct perf_evsel *evsel, bool raw_trace) 2029static int add_evsel_fields(struct perf_evsel *evsel, bool raw_trace, int level)
1926{ 2030{
1927 int ret; 2031 int ret;
1928 struct format_field *field; 2032 struct format_field *field;
1929 2033
1930 field = evsel->tp_format->format.fields; 2034 field = evsel->tp_format->format.fields;
1931 while (field) { 2035 while (field) {
1932 ret = __dynamic_dimension__add(evsel, field, raw_trace); 2036 ret = __dynamic_dimension__add(evsel, field, raw_trace, level);
1933 if (ret < 0) 2037 if (ret < 0)
1934 return ret; 2038 return ret;
1935 2039
@@ -1938,7 +2042,8 @@ static int add_evsel_fields(struct perf_evsel *evsel, bool raw_trace)
1938 return 0; 2042 return 0;
1939} 2043}
1940 2044
1941static int add_all_dynamic_fields(struct perf_evlist *evlist, bool raw_trace) 2045static int add_all_dynamic_fields(struct perf_evlist *evlist, bool raw_trace,
2046 int level)
1942{ 2047{
1943 int ret; 2048 int ret;
1944 struct perf_evsel *evsel; 2049 struct perf_evsel *evsel;
@@ -1947,7 +2052,7 @@ static int add_all_dynamic_fields(struct perf_evlist *evlist, bool raw_trace)
1947 if (evsel->attr.type != PERF_TYPE_TRACEPOINT) 2052 if (evsel->attr.type != PERF_TYPE_TRACEPOINT)
1948 continue; 2053 continue;
1949 2054
1950 ret = add_evsel_fields(evsel, raw_trace); 2055 ret = add_evsel_fields(evsel, raw_trace, level);
1951 if (ret < 0) 2056 if (ret < 0)
1952 return ret; 2057 return ret;
1953 } 2058 }
@@ -1955,7 +2060,7 @@ static int add_all_dynamic_fields(struct perf_evlist *evlist, bool raw_trace)
1955} 2060}
1956 2061
1957static int add_all_matching_fields(struct perf_evlist *evlist, 2062static int add_all_matching_fields(struct perf_evlist *evlist,
1958 char *field_name, bool raw_trace) 2063 char *field_name, bool raw_trace, int level)
1959{ 2064{
1960 int ret = -ESRCH; 2065 int ret = -ESRCH;
1961 struct perf_evsel *evsel; 2066 struct perf_evsel *evsel;
@@ -1969,14 +2074,15 @@ static int add_all_matching_fields(struct perf_evlist *evlist,
1969 if (field == NULL) 2074 if (field == NULL)
1970 continue; 2075 continue;
1971 2076
1972 ret = __dynamic_dimension__add(evsel, field, raw_trace); 2077 ret = __dynamic_dimension__add(evsel, field, raw_trace, level);
1973 if (ret < 0) 2078 if (ret < 0)
1974 break; 2079 break;
1975 } 2080 }
1976 return ret; 2081 return ret;
1977} 2082}
1978 2083
1979static int add_dynamic_entry(struct perf_evlist *evlist, const char *tok) 2084static int add_dynamic_entry(struct perf_evlist *evlist, const char *tok,
2085 int level)
1980{ 2086{
1981 char *str, *event_name, *field_name, *opt_name; 2087 char *str, *event_name, *field_name, *opt_name;
1982 struct perf_evsel *evsel; 2088 struct perf_evsel *evsel;
@@ -2006,12 +2112,12 @@ static int add_dynamic_entry(struct perf_evlist *evlist, const char *tok)
2006 } 2112 }
2007 2113
2008 if (!strcmp(field_name, "trace_fields")) { 2114 if (!strcmp(field_name, "trace_fields")) {
2009 ret = add_all_dynamic_fields(evlist, raw_trace); 2115 ret = add_all_dynamic_fields(evlist, raw_trace, level);
2010 goto out; 2116 goto out;
2011 } 2117 }
2012 2118
2013 if (event_name == NULL) { 2119 if (event_name == NULL) {
2014 ret = add_all_matching_fields(evlist, field_name, raw_trace); 2120 ret = add_all_matching_fields(evlist, field_name, raw_trace, level);
2015 goto out; 2121 goto out;
2016 } 2122 }
2017 2123
@@ -2029,7 +2135,7 @@ static int add_dynamic_entry(struct perf_evlist *evlist, const char *tok)
2029 } 2135 }
2030 2136
2031 if (!strcmp(field_name, "*")) { 2137 if (!strcmp(field_name, "*")) {
2032 ret = add_evsel_fields(evsel, raw_trace); 2138 ret = add_evsel_fields(evsel, raw_trace, level);
2033 } else { 2139 } else {
2034 field = pevent_find_any_field(evsel->tp_format, field_name); 2140 field = pevent_find_any_field(evsel->tp_format, field_name);
2035 if (field == NULL) { 2141 if (field == NULL) {
@@ -2038,7 +2144,7 @@ static int add_dynamic_entry(struct perf_evlist *evlist, const char *tok)
2038 return -ENOENT; 2144 return -ENOENT;
2039 } 2145 }
2040 2146
2041 ret = __dynamic_dimension__add(evsel, field, raw_trace); 2147 ret = __dynamic_dimension__add(evsel, field, raw_trace, level);
2042 } 2148 }
2043 2149
2044out: 2150out:
@@ -2046,12 +2152,14 @@ out:
2046 return ret; 2152 return ret;
2047} 2153}
2048 2154
2049static int __sort_dimension__add(struct sort_dimension *sd) 2155static int __sort_dimension__add(struct sort_dimension *sd,
2156 struct perf_hpp_list *list,
2157 int level)
2050{ 2158{
2051 if (sd->taken) 2159 if (sd->taken)
2052 return 0; 2160 return 0;
2053 2161
2054 if (__sort_dimension__add_hpp_sort(sd) < 0) 2162 if (__sort_dimension__add_hpp_sort(sd, list, level) < 0)
2055 return -1; 2163 return -1;
2056 2164
2057 if (sd->entry->se_collapse) 2165 if (sd->entry->se_collapse)
@@ -2062,46 +2170,63 @@ static int __sort_dimension__add(struct sort_dimension *sd)
2062 return 0; 2170 return 0;
2063} 2171}
2064 2172
2065static int __hpp_dimension__add(struct hpp_dimension *hd) 2173static int __hpp_dimension__add(struct hpp_dimension *hd,
2174 struct perf_hpp_list *list,
2175 int level)
2066{ 2176{
2067 if (!hd->taken) { 2177 struct perf_hpp_fmt *fmt;
2068 hd->taken = 1;
2069 2178
2070 perf_hpp__register_sort_field(hd->fmt); 2179 if (hd->taken)
2071 } 2180 return 0;
2181
2182 fmt = __hpp_dimension__alloc_hpp(hd, level);
2183 if (!fmt)
2184 return -1;
2185
2186 hd->taken = 1;
2187 perf_hpp_list__register_sort_field(list, fmt);
2072 return 0; 2188 return 0;
2073} 2189}
2074 2190
2075static int __sort_dimension__add_output(struct sort_dimension *sd) 2191static int __sort_dimension__add_output(struct perf_hpp_list *list,
2192 struct sort_dimension *sd)
2076{ 2193{
2077 if (sd->taken) 2194 if (sd->taken)
2078 return 0; 2195 return 0;
2079 2196
2080 if (__sort_dimension__add_hpp_output(sd) < 0) 2197 if (__sort_dimension__add_hpp_output(sd, list) < 0)
2081 return -1; 2198 return -1;
2082 2199
2083 sd->taken = 1; 2200 sd->taken = 1;
2084 return 0; 2201 return 0;
2085} 2202}
2086 2203
2087static int __hpp_dimension__add_output(struct hpp_dimension *hd) 2204static int __hpp_dimension__add_output(struct perf_hpp_list *list,
2205 struct hpp_dimension *hd)
2088{ 2206{
2089 if (!hd->taken) { 2207 struct perf_hpp_fmt *fmt;
2090 hd->taken = 1;
2091 2208
2092 perf_hpp__column_register(hd->fmt); 2209 if (hd->taken)
2093 } 2210 return 0;
2211
2212 fmt = __hpp_dimension__alloc_hpp(hd, 0);
2213 if (!fmt)
2214 return -1;
2215
2216 hd->taken = 1;
2217 perf_hpp_list__column_register(list, fmt);
2094 return 0; 2218 return 0;
2095} 2219}
2096 2220
2097int hpp_dimension__add_output(unsigned col) 2221int hpp_dimension__add_output(unsigned col)
2098{ 2222{
2099 BUG_ON(col >= PERF_HPP__MAX_INDEX); 2223 BUG_ON(col >= PERF_HPP__MAX_INDEX);
2100 return __hpp_dimension__add_output(&hpp_sort_dimensions[col]); 2224 return __hpp_dimension__add_output(&perf_hpp_list, &hpp_sort_dimensions[col]);
2101} 2225}
2102 2226
2103static int sort_dimension__add(const char *tok, 2227static int sort_dimension__add(struct perf_hpp_list *list, const char *tok,
2104 struct perf_evlist *evlist __maybe_unused) 2228 struct perf_evlist *evlist __maybe_unused,
2229 int level)
2105{ 2230{
2106 unsigned int i; 2231 unsigned int i;
2107 2232
@@ -2136,9 +2261,13 @@ static int sort_dimension__add(const char *tok,
2136 sort__has_dso = 1; 2261 sort__has_dso = 1;
2137 } else if (sd->entry == &sort_socket) { 2262 } else if (sd->entry == &sort_socket) {
2138 sort__has_socket = 1; 2263 sort__has_socket = 1;
2264 } else if (sd->entry == &sort_thread) {
2265 sort__has_thread = 1;
2266 } else if (sd->entry == &sort_comm) {
2267 sort__has_comm = 1;
2139 } 2268 }
2140 2269
2141 return __sort_dimension__add(sd); 2270 return __sort_dimension__add(sd, list, level);
2142 } 2271 }
2143 2272
2144 for (i = 0; i < ARRAY_SIZE(hpp_sort_dimensions); i++) { 2273 for (i = 0; i < ARRAY_SIZE(hpp_sort_dimensions); i++) {
@@ -2147,7 +2276,7 @@ static int sort_dimension__add(const char *tok,
2147 if (strncasecmp(tok, hd->name, strlen(tok))) 2276 if (strncasecmp(tok, hd->name, strlen(tok)))
2148 continue; 2277 continue;
2149 2278
2150 return __hpp_dimension__add(hd); 2279 return __hpp_dimension__add(hd, list, level);
2151 } 2280 }
2152 2281
2153 for (i = 0; i < ARRAY_SIZE(bstack_sort_dimensions); i++) { 2282 for (i = 0; i < ARRAY_SIZE(bstack_sort_dimensions); i++) {
@@ -2162,7 +2291,7 @@ static int sort_dimension__add(const char *tok,
2162 if (sd->entry == &sort_sym_from || sd->entry == &sort_sym_to) 2291 if (sd->entry == &sort_sym_from || sd->entry == &sort_sym_to)
2163 sort__has_sym = 1; 2292 sort__has_sym = 1;
2164 2293
2165 __sort_dimension__add(sd); 2294 __sort_dimension__add(sd, list, level);
2166 return 0; 2295 return 0;
2167 } 2296 }
2168 2297
@@ -2178,16 +2307,60 @@ static int sort_dimension__add(const char *tok,
2178 if (sd->entry == &sort_mem_daddr_sym) 2307 if (sd->entry == &sort_mem_daddr_sym)
2179 sort__has_sym = 1; 2308 sort__has_sym = 1;
2180 2309
2181 __sort_dimension__add(sd); 2310 __sort_dimension__add(sd, list, level);
2182 return 0; 2311 return 0;
2183 } 2312 }
2184 2313
2185 if (!add_dynamic_entry(evlist, tok)) 2314 if (!add_dynamic_entry(evlist, tok, level))
2186 return 0; 2315 return 0;
2187 2316
2188 return -ESRCH; 2317 return -ESRCH;
2189} 2318}
2190 2319
2320static int setup_sort_list(struct perf_hpp_list *list, char *str,
2321 struct perf_evlist *evlist)
2322{
2323 char *tmp, *tok;
2324 int ret = 0;
2325 int level = 0;
2326 int next_level = 1;
2327 bool in_group = false;
2328
2329 do {
2330 tok = str;
2331 tmp = strpbrk(str, "{}, ");
2332 if (tmp) {
2333 if (in_group)
2334 next_level = level;
2335 else
2336 next_level = level + 1;
2337
2338 if (*tmp == '{')
2339 in_group = true;
2340 else if (*tmp == '}')
2341 in_group = false;
2342
2343 *tmp = '\0';
2344 str = tmp + 1;
2345 }
2346
2347 if (*tok) {
2348 ret = sort_dimension__add(list, tok, evlist, level);
2349 if (ret == -EINVAL) {
2350 error("Invalid --sort key: `%s'", tok);
2351 break;
2352 } else if (ret == -ESRCH) {
2353 error("Unknown --sort key: `%s'", tok);
2354 break;
2355 }
2356 }
2357
2358 level = next_level;
2359 } while (tmp);
2360
2361 return ret;
2362}
2363
2191static const char *get_default_sort_order(struct perf_evlist *evlist) 2364static const char *get_default_sort_order(struct perf_evlist *evlist)
2192{ 2365{
2193 const char *default_sort_orders[] = { 2366 const char *default_sort_orders[] = {
@@ -2282,7 +2455,7 @@ static char *setup_overhead(char *keys)
2282 2455
2283static int __setup_sorting(struct perf_evlist *evlist) 2456static int __setup_sorting(struct perf_evlist *evlist)
2284{ 2457{
2285 char *tmp, *tok, *str; 2458 char *str;
2286 const char *sort_keys; 2459 const char *sort_keys;
2287 int ret = 0; 2460 int ret = 0;
2288 2461
@@ -2320,17 +2493,7 @@ static int __setup_sorting(struct perf_evlist *evlist)
2320 } 2493 }
2321 } 2494 }
2322 2495
2323 for (tok = strtok_r(str, ", ", &tmp); 2496 ret = setup_sort_list(&perf_hpp_list, str, evlist);
2324 tok; tok = strtok_r(NULL, ", ", &tmp)) {
2325 ret = sort_dimension__add(tok, evlist);
2326 if (ret == -EINVAL) {
2327 error("Invalid --sort key: `%s'", tok);
2328 break;
2329 } else if (ret == -ESRCH) {
2330 error("Unknown --sort key: `%s'", tok);
2331 break;
2332 }
2333 }
2334 2497
2335 free(str); 2498 free(str);
2336 return ret; 2499 return ret;
@@ -2341,7 +2504,7 @@ void perf_hpp__set_elide(int idx, bool elide)
2341 struct perf_hpp_fmt *fmt; 2504 struct perf_hpp_fmt *fmt;
2342 struct hpp_sort_entry *hse; 2505 struct hpp_sort_entry *hse;
2343 2506
2344 perf_hpp__for_each_format(fmt) { 2507 perf_hpp_list__for_each_format(&perf_hpp_list, fmt) {
2345 if (!perf_hpp__is_sort_entry(fmt)) 2508 if (!perf_hpp__is_sort_entry(fmt))
2346 continue; 2509 continue;
2347 2510
@@ -2401,7 +2564,7 @@ void sort__setup_elide(FILE *output)
2401 struct perf_hpp_fmt *fmt; 2564 struct perf_hpp_fmt *fmt;
2402 struct hpp_sort_entry *hse; 2565 struct hpp_sort_entry *hse;
2403 2566
2404 perf_hpp__for_each_format(fmt) { 2567 perf_hpp_list__for_each_format(&perf_hpp_list, fmt) {
2405 if (!perf_hpp__is_sort_entry(fmt)) 2568 if (!perf_hpp__is_sort_entry(fmt))
2406 continue; 2569 continue;
2407 2570
@@ -2413,7 +2576,7 @@ void sort__setup_elide(FILE *output)
2413 * It makes no sense to elide all of sort entries. 2576 * It makes no sense to elide all of sort entries.
2414 * Just revert them to show up again. 2577 * Just revert them to show up again.
2415 */ 2578 */
2416 perf_hpp__for_each_format(fmt) { 2579 perf_hpp_list__for_each_format(&perf_hpp_list, fmt) {
2417 if (!perf_hpp__is_sort_entry(fmt)) 2580 if (!perf_hpp__is_sort_entry(fmt))
2418 continue; 2581 continue;
2419 2582
@@ -2421,7 +2584,7 @@ void sort__setup_elide(FILE *output)
2421 return; 2584 return;
2422 } 2585 }
2423 2586
2424 perf_hpp__for_each_format(fmt) { 2587 perf_hpp_list__for_each_format(&perf_hpp_list, fmt) {
2425 if (!perf_hpp__is_sort_entry(fmt)) 2588 if (!perf_hpp__is_sort_entry(fmt))
2426 continue; 2589 continue;
2427 2590
@@ -2429,7 +2592,7 @@ void sort__setup_elide(FILE *output)
2429 } 2592 }
2430} 2593}
2431 2594
2432static int output_field_add(char *tok) 2595static int output_field_add(struct perf_hpp_list *list, char *tok)
2433{ 2596{
2434 unsigned int i; 2597 unsigned int i;
2435 2598
@@ -2439,7 +2602,7 @@ static int output_field_add(char *tok)
2439 if (strncasecmp(tok, sd->name, strlen(tok))) 2602 if (strncasecmp(tok, sd->name, strlen(tok)))
2440 continue; 2603 continue;
2441 2604
2442 return __sort_dimension__add_output(sd); 2605 return __sort_dimension__add_output(list, sd);
2443 } 2606 }
2444 2607
2445 for (i = 0; i < ARRAY_SIZE(hpp_sort_dimensions); i++) { 2608 for (i = 0; i < ARRAY_SIZE(hpp_sort_dimensions); i++) {
@@ -2448,7 +2611,7 @@ static int output_field_add(char *tok)
2448 if (strncasecmp(tok, hd->name, strlen(tok))) 2611 if (strncasecmp(tok, hd->name, strlen(tok)))
2449 continue; 2612 continue;
2450 2613
2451 return __hpp_dimension__add_output(hd); 2614 return __hpp_dimension__add_output(list, hd);
2452 } 2615 }
2453 2616
2454 for (i = 0; i < ARRAY_SIZE(bstack_sort_dimensions); i++) { 2617 for (i = 0; i < ARRAY_SIZE(bstack_sort_dimensions); i++) {
@@ -2457,7 +2620,7 @@ static int output_field_add(char *tok)
2457 if (strncasecmp(tok, sd->name, strlen(tok))) 2620 if (strncasecmp(tok, sd->name, strlen(tok)))
2458 continue; 2621 continue;
2459 2622
2460 return __sort_dimension__add_output(sd); 2623 return __sort_dimension__add_output(list, sd);
2461 } 2624 }
2462 2625
2463 for (i = 0; i < ARRAY_SIZE(memory_sort_dimensions); i++) { 2626 for (i = 0; i < ARRAY_SIZE(memory_sort_dimensions); i++) {
@@ -2466,12 +2629,32 @@ static int output_field_add(char *tok)
2466 if (strncasecmp(tok, sd->name, strlen(tok))) 2629 if (strncasecmp(tok, sd->name, strlen(tok)))
2467 continue; 2630 continue;
2468 2631
2469 return __sort_dimension__add_output(sd); 2632 return __sort_dimension__add_output(list, sd);
2470 } 2633 }
2471 2634
2472 return -ESRCH; 2635 return -ESRCH;
2473} 2636}
2474 2637
2638static int setup_output_list(struct perf_hpp_list *list, char *str)
2639{
2640 char *tmp, *tok;
2641 int ret = 0;
2642
2643 for (tok = strtok_r(str, ", ", &tmp);
2644 tok; tok = strtok_r(NULL, ", ", &tmp)) {
2645 ret = output_field_add(list, tok);
2646 if (ret == -EINVAL) {
2647 error("Invalid --fields key: `%s'", tok);
2648 break;
2649 } else if (ret == -ESRCH) {
2650 error("Unknown --fields key: `%s'", tok);
2651 break;
2652 }
2653 }
2654
2655 return ret;
2656}
2657
2475static void reset_dimensions(void) 2658static void reset_dimensions(void)
2476{ 2659{
2477 unsigned int i; 2660 unsigned int i;
@@ -2496,7 +2679,7 @@ bool is_strict_order(const char *order)
2496 2679
2497static int __setup_output_field(void) 2680static int __setup_output_field(void)
2498{ 2681{
2499 char *tmp, *tok, *str, *strp; 2682 char *str, *strp;
2500 int ret = -EINVAL; 2683 int ret = -EINVAL;
2501 2684
2502 if (field_order == NULL) 2685 if (field_order == NULL)
@@ -2516,17 +2699,7 @@ static int __setup_output_field(void)
2516 goto out; 2699 goto out;
2517 } 2700 }
2518 2701
2519 for (tok = strtok_r(strp, ", ", &tmp); 2702 ret = setup_output_list(&perf_hpp_list, strp);
2520 tok; tok = strtok_r(NULL, ", ", &tmp)) {
2521 ret = output_field_add(tok);
2522 if (ret == -EINVAL) {
2523 error("Invalid --fields key: `%s'", tok);
2524 break;
2525 } else if (ret == -ESRCH) {
2526 error("Unknown --fields key: `%s'", tok);
2527 break;
2528 }
2529 }
2530 2703
2531out: 2704out:
2532 free(str); 2705 free(str);
@@ -2542,7 +2715,7 @@ int setup_sorting(struct perf_evlist *evlist)
2542 return err; 2715 return err;
2543 2716
2544 if (parent_pattern != default_parent_pattern) { 2717 if (parent_pattern != default_parent_pattern) {
2545 err = sort_dimension__add("parent", evlist); 2718 err = sort_dimension__add(&perf_hpp_list, "parent", evlist, -1);
2546 if (err < 0) 2719 if (err < 0)
2547 return err; 2720 return err;
2548 } 2721 }
@@ -2560,9 +2733,13 @@ int setup_sorting(struct perf_evlist *evlist)
2560 return err; 2733 return err;
2561 2734
2562 /* copy sort keys to output fields */ 2735 /* copy sort keys to output fields */
2563 perf_hpp__setup_output_field(); 2736 perf_hpp__setup_output_field(&perf_hpp_list);
2564 /* and then copy output fields to sort keys */ 2737 /* and then copy output fields to sort keys */
2565 perf_hpp__append_sort_keys(); 2738 perf_hpp__append_sort_keys(&perf_hpp_list);
2739
2740 /* setup hists-specific output fields */
2741 if (perf_hpp__setup_hists_formats(&perf_hpp_list, evlist) < 0)
2742 return -1;
2566 2743
2567 return 0; 2744 return 0;
2568} 2745}
@@ -2578,5 +2755,5 @@ void reset_output_field(void)
2578 sort_order = NULL; 2755 sort_order = NULL;
2579 2756
2580 reset_dimensions(); 2757 reset_dimensions();
2581 perf_hpp__reset_output_field(); 2758 perf_hpp__reset_output_field(&perf_hpp_list);
2582} 2759}
diff --git a/tools/perf/util/sort.h b/tools/perf/util/sort.h
index 687bbb124428..3f4e35998119 100644
--- a/tools/perf/util/sort.h
+++ b/tools/perf/util/sort.h
@@ -32,9 +32,12 @@ extern const char default_sort_order[];
32extern regex_t ignore_callees_regex; 32extern regex_t ignore_callees_regex;
33extern int have_ignore_callees; 33extern int have_ignore_callees;
34extern int sort__need_collapse; 34extern int sort__need_collapse;
35extern int sort__has_dso;
35extern int sort__has_parent; 36extern int sort__has_parent;
36extern int sort__has_sym; 37extern int sort__has_sym;
37extern int sort__has_socket; 38extern int sort__has_socket;
39extern int sort__has_thread;
40extern int sort__has_comm;
38extern enum sort_mode sort__mode; 41extern enum sort_mode sort__mode;
39extern struct sort_entry sort_comm; 42extern struct sort_entry sort_comm;
40extern struct sort_entry sort_dso; 43extern struct sort_entry sort_dso;
@@ -94,9 +97,11 @@ struct hist_entry {
94 s32 socket; 97 s32 socket;
95 s32 cpu; 98 s32 cpu;
96 u8 cpumode; 99 u8 cpumode;
100 u8 depth;
97 101
98 /* We are added by hists__add_dummy_entry. */ 102 /* We are added by hists__add_dummy_entry. */
99 bool dummy; 103 bool dummy;
104 bool leaf;
100 105
101 char level; 106 char level;
102 u8 filtered; 107 u8 filtered;
@@ -113,18 +118,28 @@ struct hist_entry {
113 bool init_have_children; 118 bool init_have_children;
114 bool unfolded; 119 bool unfolded;
115 bool has_children; 120 bool has_children;
121 bool has_no_entry;
116 }; 122 };
117 }; 123 };
118 char *srcline; 124 char *srcline;
119 char *srcfile; 125 char *srcfile;
120 struct symbol *parent; 126 struct symbol *parent;
121 struct rb_root sorted_chain;
122 struct branch_info *branch_info; 127 struct branch_info *branch_info;
123 struct hists *hists; 128 struct hists *hists;
124 struct mem_info *mem_info; 129 struct mem_info *mem_info;
125 void *raw_data; 130 void *raw_data;
126 u32 raw_size; 131 u32 raw_size;
127 void *trace_output; 132 void *trace_output;
133 struct perf_hpp_list *hpp_list;
134 struct hist_entry *parent_he;
135 union {
136 /* this is for hierarchical entry structure */
137 struct {
138 struct rb_root hroot_in;
139 struct rb_root hroot_out;
140 }; /* non-leaf entries */
141 struct rb_root sorted_chain; /* leaf entry has callchains */
142 };
128 struct callchain_root callchain[0]; /* must be last member */ 143 struct callchain_root callchain[0]; /* must be last member */
129}; 144};
130 145
@@ -160,6 +175,17 @@ static inline float hist_entry__get_percent_limit(struct hist_entry *he)
160 return period * 100.0 / total_period; 175 return period * 100.0 / total_period;
161} 176}
162 177
178static inline u64 cl_address(u64 address)
179{
180 /* return the cacheline of the address */
181 return (address & ~(cacheline_size - 1));
182}
183
184static inline u64 cl_offset(u64 address)
185{
186 /* return the cacheline of the address */
187 return (address & (cacheline_size - 1));
188}
163 189
164enum sort_mode { 190enum sort_mode {
165 SORT_MODE__NORMAL, 191 SORT_MODE__NORMAL,
@@ -221,6 +247,7 @@ struct sort_entry {
221 int64_t (*se_sort)(struct hist_entry *, struct hist_entry *); 247 int64_t (*se_sort)(struct hist_entry *, struct hist_entry *);
222 int (*se_snprintf)(struct hist_entry *he, char *bf, size_t size, 248 int (*se_snprintf)(struct hist_entry *he, char *bf, size_t size,
223 unsigned int width); 249 unsigned int width);
250 int (*se_filter)(struct hist_entry *he, int type, const void *arg);
224 u8 se_width_idx; 251 u8 se_width_idx;
225}; 252};
226 253
diff --git a/tools/perf/util/stat-shadow.c b/tools/perf/util/stat-shadow.c
index 6ac03146889d..b33ffb2af2cf 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,10 @@ 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
142 __maybe_unused, double avg) 156 __maybe_unused, double avg,
157 struct perf_stat_output_ctx *out)
143{ 158{
144 double total, ratio = 0.0; 159 double total, ratio = 0.0;
145 const char *color; 160 const char *color;
@@ -152,14 +167,17 @@ static void print_stalled_cycles_frontend(FILE *out, int cpu,
152 167
153 color = get_ratio_color(GRC_STALLED_CYCLES_FE, ratio); 168 color = get_ratio_color(GRC_STALLED_CYCLES_FE, ratio);
154 169
155 fprintf(out, " # "); 170 if (ratio)
156 color_fprintf(out, color, "%6.2f%%", ratio); 171 out->print_metric(out->ctx, color, "%7.2f%%", "frontend cycles idle",
157 fprintf(out, " frontend cycles idle "); 172 ratio);
173 else
174 out->print_metric(out->ctx, NULL, NULL, "frontend cycles idle", 0);
158} 175}
159 176
160static void print_stalled_cycles_backend(FILE *out, int cpu, 177static void print_stalled_cycles_backend(int cpu,
161 struct perf_evsel *evsel 178 struct perf_evsel *evsel
162 __maybe_unused, double avg) 179 __maybe_unused, double avg,
180 struct perf_stat_output_ctx *out)
163{ 181{
164 double total, ratio = 0.0; 182 double total, ratio = 0.0;
165 const char *color; 183 const char *color;
@@ -172,14 +190,13 @@ static void print_stalled_cycles_backend(FILE *out, int cpu,
172 190
173 color = get_ratio_color(GRC_STALLED_CYCLES_BE, ratio); 191 color = get_ratio_color(GRC_STALLED_CYCLES_BE, ratio);
174 192
175 fprintf(out, " # "); 193 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} 194}
179 195
180static void print_branch_misses(FILE *out, int cpu, 196static void print_branch_misses(int cpu,
181 struct perf_evsel *evsel __maybe_unused, 197 struct perf_evsel *evsel __maybe_unused,
182 double avg) 198 double avg,
199 struct perf_stat_output_ctx *out)
183{ 200{
184 double total, ratio = 0.0; 201 double total, ratio = 0.0;
185 const char *color; 202 const char *color;
@@ -192,14 +209,13 @@ static void print_branch_misses(FILE *out, int cpu,
192 209
193 color = get_ratio_color(GRC_CACHE_MISSES, ratio); 210 color = get_ratio_color(GRC_CACHE_MISSES, ratio);
194 211
195 fprintf(out, " # "); 212 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} 213}
199 214
200static void print_l1_dcache_misses(FILE *out, int cpu, 215static void print_l1_dcache_misses(int cpu,
201 struct perf_evsel *evsel __maybe_unused, 216 struct perf_evsel *evsel __maybe_unused,
202 double avg) 217 double avg,
218 struct perf_stat_output_ctx *out)
203{ 219{
204 double total, ratio = 0.0; 220 double total, ratio = 0.0;
205 const char *color; 221 const char *color;
@@ -212,14 +228,13 @@ static void print_l1_dcache_misses(FILE *out, int cpu,
212 228
213 color = get_ratio_color(GRC_CACHE_MISSES, ratio); 229 color = get_ratio_color(GRC_CACHE_MISSES, ratio);
214 230
215 fprintf(out, " # "); 231 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} 232}
219 233
220static void print_l1_icache_misses(FILE *out, int cpu, 234static void print_l1_icache_misses(int cpu,
221 struct perf_evsel *evsel __maybe_unused, 235 struct perf_evsel *evsel __maybe_unused,
222 double avg) 236 double avg,
237 struct perf_stat_output_ctx *out)
223{ 238{
224 double total, ratio = 0.0; 239 double total, ratio = 0.0;
225 const char *color; 240 const char *color;
@@ -231,15 +246,13 @@ static void print_l1_icache_misses(FILE *out, int cpu,
231 ratio = avg / total * 100.0; 246 ratio = avg / total * 100.0;
232 247
233 color = get_ratio_color(GRC_CACHE_MISSES, ratio); 248 color = get_ratio_color(GRC_CACHE_MISSES, ratio);
234 249 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} 250}
239 251
240static void print_dtlb_cache_misses(FILE *out, int cpu, 252static void print_dtlb_cache_misses(int cpu,
241 struct perf_evsel *evsel __maybe_unused, 253 struct perf_evsel *evsel __maybe_unused,
242 double avg) 254 double avg,
255 struct perf_stat_output_ctx *out)
243{ 256{
244 double total, ratio = 0.0; 257 double total, ratio = 0.0;
245 const char *color; 258 const char *color;
@@ -251,15 +264,13 @@ static void print_dtlb_cache_misses(FILE *out, int cpu,
251 ratio = avg / total * 100.0; 264 ratio = avg / total * 100.0;
252 265
253 color = get_ratio_color(GRC_CACHE_MISSES, ratio); 266 color = get_ratio_color(GRC_CACHE_MISSES, ratio);
254 267 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} 268}
259 269
260static void print_itlb_cache_misses(FILE *out, int cpu, 270static void print_itlb_cache_misses(int cpu,
261 struct perf_evsel *evsel __maybe_unused, 271 struct perf_evsel *evsel __maybe_unused,
262 double avg) 272 double avg,
273 struct perf_stat_output_ctx *out)
263{ 274{
264 double total, ratio = 0.0; 275 double total, ratio = 0.0;
265 const char *color; 276 const char *color;
@@ -271,15 +282,13 @@ static void print_itlb_cache_misses(FILE *out, int cpu,
271 ratio = avg / total * 100.0; 282 ratio = avg / total * 100.0;
272 283
273 color = get_ratio_color(GRC_CACHE_MISSES, ratio); 284 color = get_ratio_color(GRC_CACHE_MISSES, ratio);
274 285 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} 286}
279 287
280static void print_ll_cache_misses(FILE *out, int cpu, 288static void print_ll_cache_misses(int cpu,
281 struct perf_evsel *evsel __maybe_unused, 289 struct perf_evsel *evsel __maybe_unused,
282 double avg) 290 double avg,
291 struct perf_stat_output_ctx *out)
283{ 292{
284 double total, ratio = 0.0; 293 double total, ratio = 0.0;
285 const char *color; 294 const char *color;
@@ -291,15 +300,15 @@ static void print_ll_cache_misses(FILE *out, int cpu,
291 ratio = avg / total * 100.0; 300 ratio = avg / total * 100.0;
292 301
293 color = get_ratio_color(GRC_CACHE_MISSES, ratio); 302 color = get_ratio_color(GRC_CACHE_MISSES, ratio);
294 303 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} 304}
299 305
300void perf_stat__print_shadow_stats(FILE *out, struct perf_evsel *evsel, 306void perf_stat__print_shadow_stats(struct perf_evsel *evsel,
301 double avg, int cpu, enum aggr_mode aggr) 307 double avg, int cpu,
308 struct perf_stat_output_ctx *out)
302{ 309{
310 void *ctxp = out->ctx;
311 print_metric_t print_metric = out->print_metric;
303 double total, ratio = 0.0, total2; 312 double total, ratio = 0.0, total2;
304 int ctx = evsel_context(evsel); 313 int ctx = evsel_context(evsel);
305 314
@@ -307,119 +316,145 @@ void perf_stat__print_shadow_stats(FILE *out, struct perf_evsel *evsel,
307 total = avg_stats(&runtime_cycles_stats[ctx][cpu]); 316 total = avg_stats(&runtime_cycles_stats[ctx][cpu]);
308 if (total) { 317 if (total) {
309 ratio = avg / total; 318 ratio = avg / total;
310 fprintf(out, " # %5.2f insns per cycle ", ratio); 319 print_metric(ctxp, NULL, "%7.2f ",
320 "insn per cycle", ratio);
311 } else { 321 } else {
312 fprintf(out, " "); 322 print_metric(ctxp, NULL, NULL, "insn per cycle", 0);
313 } 323 }
314 total = avg_stats(&runtime_stalled_cycles_front_stats[ctx][cpu]); 324 total = avg_stats(&runtime_stalled_cycles_front_stats[ctx][cpu]);
315 total = max(total, avg_stats(&runtime_stalled_cycles_back_stats[ctx][cpu])); 325 total = max(total, avg_stats(&runtime_stalled_cycles_back_stats[ctx][cpu]));
316 326
317 if (total && avg) { 327 if (total && avg) {
328 out->new_line(ctxp);
318 ratio = total / avg; 329 ratio = total / avg;
319 fprintf(out, "\n"); 330 print_metric(ctxp, NULL, "%7.2f ",
320 if (aggr == AGGR_NONE) 331 "stalled cycles per insn",
321 fprintf(out, " "); 332 ratio);
322 fprintf(out, " # %5.2f stalled cycles per insn", ratio); 333 } else if (have_frontend_stalled) {
334 print_metric(ctxp, NULL, NULL,
335 "stalled cycles per insn", 0);
323 } 336 }
324 337 } else if (perf_evsel__match(evsel, HARDWARE, HW_BRANCH_MISSES)) {
325 } else if (perf_evsel__match(evsel, HARDWARE, HW_BRANCH_MISSES) && 338 if (runtime_branches_stats[ctx][cpu].n != 0)
326 runtime_branches_stats[ctx][cpu].n != 0) { 339 print_branch_misses(cpu, evsel, avg, out);
327 print_branch_misses(out, cpu, evsel, avg); 340 else
341 print_metric(ctxp, NULL, NULL, "of all branches", 0);
328 } else if ( 342 } else if (
329 evsel->attr.type == PERF_TYPE_HW_CACHE && 343 evsel->attr.type == PERF_TYPE_HW_CACHE &&
330 evsel->attr.config == ( PERF_COUNT_HW_CACHE_L1D | 344 evsel->attr.config == ( PERF_COUNT_HW_CACHE_L1D |
331 ((PERF_COUNT_HW_CACHE_OP_READ) << 8) | 345 ((PERF_COUNT_HW_CACHE_OP_READ) << 8) |
332 ((PERF_COUNT_HW_CACHE_RESULT_MISS) << 16)) && 346 ((PERF_COUNT_HW_CACHE_RESULT_MISS) << 16))) {
333 runtime_l1_dcache_stats[ctx][cpu].n != 0) { 347 if (runtime_l1_dcache_stats[ctx][cpu].n != 0)
334 print_l1_dcache_misses(out, cpu, evsel, avg); 348 print_l1_dcache_misses(cpu, evsel, avg, out);
349 else
350 print_metric(ctxp, NULL, NULL, "of all L1-dcache hits", 0);
335 } else if ( 351 } else if (
336 evsel->attr.type == PERF_TYPE_HW_CACHE && 352 evsel->attr.type == PERF_TYPE_HW_CACHE &&
337 evsel->attr.config == ( PERF_COUNT_HW_CACHE_L1I | 353 evsel->attr.config == ( PERF_COUNT_HW_CACHE_L1I |
338 ((PERF_COUNT_HW_CACHE_OP_READ) << 8) | 354 ((PERF_COUNT_HW_CACHE_OP_READ) << 8) |
339 ((PERF_COUNT_HW_CACHE_RESULT_MISS) << 16)) && 355 ((PERF_COUNT_HW_CACHE_RESULT_MISS) << 16))) {
340 runtime_l1_icache_stats[ctx][cpu].n != 0) { 356 if (runtime_l1_icache_stats[ctx][cpu].n != 0)
341 print_l1_icache_misses(out, cpu, evsel, avg); 357 print_l1_icache_misses(cpu, evsel, avg, out);
358 else
359 print_metric(ctxp, NULL, NULL, "of all L1-icache hits", 0);
342 } else if ( 360 } else if (
343 evsel->attr.type == PERF_TYPE_HW_CACHE && 361 evsel->attr.type == PERF_TYPE_HW_CACHE &&
344 evsel->attr.config == ( PERF_COUNT_HW_CACHE_DTLB | 362 evsel->attr.config == ( PERF_COUNT_HW_CACHE_DTLB |
345 ((PERF_COUNT_HW_CACHE_OP_READ) << 8) | 363 ((PERF_COUNT_HW_CACHE_OP_READ) << 8) |
346 ((PERF_COUNT_HW_CACHE_RESULT_MISS) << 16)) && 364 ((PERF_COUNT_HW_CACHE_RESULT_MISS) << 16))) {
347 runtime_dtlb_cache_stats[ctx][cpu].n != 0) { 365 if (runtime_dtlb_cache_stats[ctx][cpu].n != 0)
348 print_dtlb_cache_misses(out, cpu, evsel, avg); 366 print_dtlb_cache_misses(cpu, evsel, avg, out);
367 else
368 print_metric(ctxp, NULL, NULL, "of all dTLB cache hits", 0);
349 } else if ( 369 } else if (
350 evsel->attr.type == PERF_TYPE_HW_CACHE && 370 evsel->attr.type == PERF_TYPE_HW_CACHE &&
351 evsel->attr.config == ( PERF_COUNT_HW_CACHE_ITLB | 371 evsel->attr.config == ( PERF_COUNT_HW_CACHE_ITLB |
352 ((PERF_COUNT_HW_CACHE_OP_READ) << 8) | 372 ((PERF_COUNT_HW_CACHE_OP_READ) << 8) |
353 ((PERF_COUNT_HW_CACHE_RESULT_MISS) << 16)) && 373 ((PERF_COUNT_HW_CACHE_RESULT_MISS) << 16))) {
354 runtime_itlb_cache_stats[ctx][cpu].n != 0) { 374 if (runtime_itlb_cache_stats[ctx][cpu].n != 0)
355 print_itlb_cache_misses(out, cpu, evsel, avg); 375 print_itlb_cache_misses(cpu, evsel, avg, out);
376 else
377 print_metric(ctxp, NULL, NULL, "of all iTLB cache hits", 0);
356 } else if ( 378 } else if (
357 evsel->attr.type == PERF_TYPE_HW_CACHE && 379 evsel->attr.type == PERF_TYPE_HW_CACHE &&
358 evsel->attr.config == ( PERF_COUNT_HW_CACHE_LL | 380 evsel->attr.config == ( PERF_COUNT_HW_CACHE_LL |
359 ((PERF_COUNT_HW_CACHE_OP_READ) << 8) | 381 ((PERF_COUNT_HW_CACHE_OP_READ) << 8) |
360 ((PERF_COUNT_HW_CACHE_RESULT_MISS) << 16)) && 382 ((PERF_COUNT_HW_CACHE_RESULT_MISS) << 16))) {
361 runtime_ll_cache_stats[ctx][cpu].n != 0) { 383 if (runtime_ll_cache_stats[ctx][cpu].n != 0)
362 print_ll_cache_misses(out, cpu, evsel, avg); 384 print_ll_cache_misses(cpu, evsel, avg, out);
363 } else if (perf_evsel__match(evsel, HARDWARE, HW_CACHE_MISSES) && 385 else
364 runtime_cacherefs_stats[ctx][cpu].n != 0) { 386 print_metric(ctxp, NULL, NULL, "of all LL-cache hits", 0);
387 } else if (perf_evsel__match(evsel, HARDWARE, HW_CACHE_MISSES)) {
365 total = avg_stats(&runtime_cacherefs_stats[ctx][cpu]); 388 total = avg_stats(&runtime_cacherefs_stats[ctx][cpu]);
366 389
367 if (total) 390 if (total)
368 ratio = avg * 100 / total; 391 ratio = avg * 100 / total;
369 392
370 fprintf(out, " # %8.3f %% of all cache refs ", ratio); 393 if (runtime_cacherefs_stats[ctx][cpu].n != 0)
371 394 print_metric(ctxp, NULL, "%8.3f %%",
395 "of all cache refs", ratio);
396 else
397 print_metric(ctxp, NULL, NULL, "of all cache refs", 0);
372 } else if (perf_evsel__match(evsel, HARDWARE, HW_STALLED_CYCLES_FRONTEND)) { 398 } else if (perf_evsel__match(evsel, HARDWARE, HW_STALLED_CYCLES_FRONTEND)) {
373 print_stalled_cycles_frontend(out, cpu, evsel, avg); 399 print_stalled_cycles_frontend(cpu, evsel, avg, out);
374 } else if (perf_evsel__match(evsel, HARDWARE, HW_STALLED_CYCLES_BACKEND)) { 400 } else if (perf_evsel__match(evsel, HARDWARE, HW_STALLED_CYCLES_BACKEND)) {
375 print_stalled_cycles_backend(out, cpu, evsel, avg); 401 print_stalled_cycles_backend(cpu, evsel, avg, out);
376 } else if (perf_evsel__match(evsel, HARDWARE, HW_CPU_CYCLES)) { 402 } else if (perf_evsel__match(evsel, HARDWARE, HW_CPU_CYCLES)) {
377 total = avg_stats(&runtime_nsecs_stats[cpu]); 403 total = avg_stats(&runtime_nsecs_stats[cpu]);
378 404
379 if (total) { 405 if (total) {
380 ratio = avg / total; 406 ratio = avg / total;
381 fprintf(out, " # %8.3f GHz ", ratio); 407 print_metric(ctxp, NULL, "%8.3f", "GHz", ratio);
382 } else { 408 } else {
383 fprintf(out, " "); 409 print_metric(ctxp, NULL, NULL, "Ghz", 0);
384 } 410 }
385 } else if (perf_stat_evsel__is(evsel, CYCLES_IN_TX)) { 411 } else if (perf_stat_evsel__is(evsel, CYCLES_IN_TX)) {
386 total = avg_stats(&runtime_cycles_stats[ctx][cpu]); 412 total = avg_stats(&runtime_cycles_stats[ctx][cpu]);
387 if (total) 413 if (total)
388 fprintf(out, 414 print_metric(ctxp, NULL,
389 " # %5.2f%% transactional cycles ", 415 "%7.2f%%", "transactional cycles",
390 100.0 * (avg / total)); 416 100.0 * (avg / total));
417 else
418 print_metric(ctxp, NULL, NULL, "transactional cycles",
419 0);
391 } else if (perf_stat_evsel__is(evsel, CYCLES_IN_TX_CP)) { 420 } else if (perf_stat_evsel__is(evsel, CYCLES_IN_TX_CP)) {
392 total = avg_stats(&runtime_cycles_stats[ctx][cpu]); 421 total = avg_stats(&runtime_cycles_stats[ctx][cpu]);
393 total2 = avg_stats(&runtime_cycles_in_tx_stats[ctx][cpu]); 422 total2 = avg_stats(&runtime_cycles_in_tx_stats[ctx][cpu]);
394 if (total2 < avg) 423 if (total2 < avg)
395 total2 = avg; 424 total2 = avg;
396 if (total) 425 if (total)
397 fprintf(out, 426 print_metric(ctxp, NULL, "%7.2f%%", "aborted cycles",
398 " # %5.2f%% aborted cycles ",
399 100.0 * ((total2-avg) / total)); 427 100.0 * ((total2-avg) / total));
400 } else if (perf_stat_evsel__is(evsel, TRANSACTION_START) && 428 else
401 runtime_cycles_in_tx_stats[ctx][cpu].n != 0) { 429 print_metric(ctxp, NULL, NULL, "aborted cycles", 0);
430 } else if (perf_stat_evsel__is(evsel, TRANSACTION_START)) {
402 total = avg_stats(&runtime_cycles_in_tx_stats[ctx][cpu]); 431 total = avg_stats(&runtime_cycles_in_tx_stats[ctx][cpu]);
403 432
404 if (avg) 433 if (avg)
405 ratio = total / avg; 434 ratio = total / avg;
406 435
407 fprintf(out, " # %8.0f cycles / transaction ", ratio); 436 if (runtime_cycles_in_tx_stats[ctx][cpu].n != 0)
408 } else if (perf_stat_evsel__is(evsel, ELISION_START) && 437 print_metric(ctxp, NULL, "%8.0f",
409 runtime_cycles_in_tx_stats[ctx][cpu].n != 0) { 438 "cycles / transaction", ratio);
439 else
440 print_metric(ctxp, NULL, NULL, "cycles / transaction",
441 0);
442 } else if (perf_stat_evsel__is(evsel, ELISION_START)) {
410 total = avg_stats(&runtime_cycles_in_tx_stats[ctx][cpu]); 443 total = avg_stats(&runtime_cycles_in_tx_stats[ctx][cpu]);
411 444
412 if (avg) 445 if (avg)
413 ratio = total / avg; 446 ratio = total / avg;
414 447
415 fprintf(out, " # %8.0f cycles / elision ", ratio); 448 print_metric(ctxp, NULL, "%8.0f", "cycles / elision", ratio);
416 } else if (perf_evsel__match(evsel, SOFTWARE, SW_TASK_CLOCK)) { 449 } else if (perf_evsel__match(evsel, SOFTWARE, SW_TASK_CLOCK)) {
417 if ((ratio = avg_stats(&walltime_nsecs_stats)) != 0) 450 if ((ratio = avg_stats(&walltime_nsecs_stats)) != 0)
418 fprintf(out, " # %8.3f CPUs utilized ", avg / ratio); 451 print_metric(ctxp, NULL, "%8.3f", "CPUs utilized",
452 avg / ratio);
419 else 453 else
420 fprintf(out, " "); 454 print_metric(ctxp, NULL, NULL, "CPUs utilized", 0);
421 } else if (runtime_nsecs_stats[cpu].n != 0) { 455 } else if (runtime_nsecs_stats[cpu].n != 0) {
422 char unit = 'M'; 456 char unit = 'M';
457 char unit_buf[10];
423 458
424 total = avg_stats(&runtime_nsecs_stats[cpu]); 459 total = avg_stats(&runtime_nsecs_stats[cpu]);
425 460
@@ -429,9 +464,9 @@ void perf_stat__print_shadow_stats(FILE *out, struct perf_evsel *evsel,
429 ratio *= 1000; 464 ratio *= 1000;
430 unit = 'K'; 465 unit = 'K';
431 } 466 }
432 467 snprintf(unit_buf, sizeof(unit_buf), "%c/sec", unit);
433 fprintf(out, " # %8.3f %c/sec ", ratio, unit); 468 print_metric(ctxp, NULL, "%8.3f", unit_buf, ratio);
434 } else { 469 } else {
435 fprintf(out, " "); 470 print_metric(ctxp, NULL, NULL, NULL, 0);
436 } 471 }
437} 472}
diff --git a/tools/perf/util/stat.c b/tools/perf/util/stat.c
index afb0c45eba34..4d9b481cf3b6 100644
--- a/tools/perf/util/stat.c
+++ b/tools/perf/util/stat.c
@@ -97,7 +97,7 @@ void perf_stat_evsel_id_init(struct perf_evsel *evsel)
97 } 97 }
98} 98}
99 99
100void perf_evsel__reset_stat_priv(struct perf_evsel *evsel) 100static void perf_evsel__reset_stat_priv(struct perf_evsel *evsel)
101{ 101{
102 int i; 102 int i;
103 struct perf_stat_evsel *ps = evsel->priv; 103 struct perf_stat_evsel *ps = evsel->priv;
@@ -108,7 +108,7 @@ void perf_evsel__reset_stat_priv(struct perf_evsel *evsel)
108 perf_stat_evsel_id_init(evsel); 108 perf_stat_evsel_id_init(evsel);
109} 109}
110 110
111int perf_evsel__alloc_stat_priv(struct perf_evsel *evsel) 111static int perf_evsel__alloc_stat_priv(struct perf_evsel *evsel)
112{ 112{
113 evsel->priv = zalloc(sizeof(struct perf_stat_evsel)); 113 evsel->priv = zalloc(sizeof(struct perf_stat_evsel));
114 if (evsel->priv == NULL) 114 if (evsel->priv == NULL)
@@ -117,13 +117,13 @@ int perf_evsel__alloc_stat_priv(struct perf_evsel *evsel)
117 return 0; 117 return 0;
118} 118}
119 119
120void perf_evsel__free_stat_priv(struct perf_evsel *evsel) 120static void perf_evsel__free_stat_priv(struct perf_evsel *evsel)
121{ 121{
122 zfree(&evsel->priv); 122 zfree(&evsel->priv);
123} 123}
124 124
125int perf_evsel__alloc_prev_raw_counts(struct perf_evsel *evsel, 125static int perf_evsel__alloc_prev_raw_counts(struct perf_evsel *evsel,
126 int ncpus, int nthreads) 126 int ncpus, int nthreads)
127{ 127{
128 struct perf_counts *counts; 128 struct perf_counts *counts;
129 129
@@ -134,13 +134,13 @@ int perf_evsel__alloc_prev_raw_counts(struct perf_evsel *evsel,
134 return counts ? 0 : -ENOMEM; 134 return counts ? 0 : -ENOMEM;
135} 135}
136 136
137void perf_evsel__free_prev_raw_counts(struct perf_evsel *evsel) 137static void perf_evsel__free_prev_raw_counts(struct perf_evsel *evsel)
138{ 138{
139 perf_counts__delete(evsel->prev_raw_counts); 139 perf_counts__delete(evsel->prev_raw_counts);
140 evsel->prev_raw_counts = NULL; 140 evsel->prev_raw_counts = NULL;
141} 141}
142 142
143int perf_evsel__alloc_stats(struct perf_evsel *evsel, bool alloc_raw) 143static int perf_evsel__alloc_stats(struct perf_evsel *evsel, bool alloc_raw)
144{ 144{
145 int ncpus = perf_evsel__nr_cpus(evsel); 145 int ncpus = perf_evsel__nr_cpus(evsel);
146 int nthreads = thread_map__nr(evsel->threads); 146 int nthreads = thread_map__nr(evsel->threads);
diff --git a/tools/perf/util/stat.h b/tools/perf/util/stat.h
index 086f4e128d63..0150e786ccc7 100644
--- a/tools/perf/util/stat.h
+++ b/tools/perf/util/stat.h
@@ -68,21 +68,23 @@ void perf_stat_evsel_id_init(struct perf_evsel *evsel);
68 68
69extern struct stats walltime_nsecs_stats; 69extern struct stats walltime_nsecs_stats;
70 70
71typedef void (*print_metric_t)(void *ctx, const char *color, const char *unit,
72 const char *fmt, double val);
73typedef void (*new_line_t )(void *ctx);
74
75void perf_stat__init_shadow_stats(void);
71void perf_stat__reset_shadow_stats(void); 76void perf_stat__reset_shadow_stats(void);
72void perf_stat__update_shadow_stats(struct perf_evsel *counter, u64 *count, 77void perf_stat__update_shadow_stats(struct perf_evsel *counter, u64 *count,
73 int cpu); 78 int cpu);
74void perf_stat__print_shadow_stats(FILE *out, struct perf_evsel *evsel, 79struct perf_stat_output_ctx {
75 double avg, int cpu, enum aggr_mode aggr); 80 void *ctx;
76 81 print_metric_t print_metric;
77void perf_evsel__reset_stat_priv(struct perf_evsel *evsel); 82 new_line_t new_line;
78int perf_evsel__alloc_stat_priv(struct perf_evsel *evsel); 83};
79void perf_evsel__free_stat_priv(struct perf_evsel *evsel);
80
81int perf_evsel__alloc_prev_raw_counts(struct perf_evsel *evsel,
82 int ncpus, int nthreads);
83void perf_evsel__free_prev_raw_counts(struct perf_evsel *evsel);
84 84
85int perf_evsel__alloc_stats(struct perf_evsel *evsel, bool alloc_raw); 85void perf_stat__print_shadow_stats(struct perf_evsel *evsel,
86 double avg, int cpu,
87 struct perf_stat_output_ctx *out);
86 88
87int perf_evlist__alloc_stats(struct perf_evlist *evlist, bool alloc_raw); 89int perf_evlist__alloc_stats(struct perf_evlist *evlist, bool alloc_raw);
88void perf_evlist__free_stats(struct perf_evlist *evlist); 90void perf_evlist__free_stats(struct perf_evlist *evlist);
diff --git a/tools/perf/util/strbuf.c b/tools/perf/util/strbuf.c
index 25671fa16618..d3d279275432 100644
--- a/tools/perf/util/strbuf.c
+++ b/tools/perf/util/strbuf.c
@@ -51,30 +51,6 @@ 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,
55 const void *data, size_t dlen)
56{
57 if (pos + len < pos)
58 die("you want to use way too much memory");
59 if (pos > sb->len)
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}
77
78void strbuf_add(struct strbuf *sb, const void *data, size_t len) 54void strbuf_add(struct strbuf *sb, const void *data, size_t len)
79{ 55{
80 strbuf_grow(sb, len); 56 strbuf_grow(sb, len);
diff --git a/tools/perf/util/strbuf.h b/tools/perf/util/strbuf.h
index 529f2f035249..7a32c838884d 100644
--- a/tools/perf/util/strbuf.h
+++ b/tools/perf/util/strbuf.h
@@ -77,8 +77,6 @@ static inline void strbuf_addch(struct strbuf *sb, int c) {
77 sb->buf[sb->len] = '\0'; 77 sb->buf[sb->len] = '\0';
78} 78}
79 79
80extern void strbuf_remove(struct strbuf *, size_t pos, size_t len);
81
82extern void strbuf_add(struct strbuf *, const void *, size_t); 80extern void strbuf_add(struct strbuf *, const void *, size_t);
83static inline void strbuf_addstr(struct strbuf *sb, const char *s) { 81static inline void strbuf_addstr(struct strbuf *sb, const char *s) {
84 strbuf_add(sb, s, strlen(s)); 82 strbuf_add(sb, s, strlen(s));
diff --git a/tools/perf/util/symbol-elf.c b/tools/perf/util/symbol-elf.c
index 562b8ebeae5b..b1dd68f358fc 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>
@@ -1077,6 +1078,8 @@ new_symbol:
1077 demangle_flags = DMGL_PARAMS | DMGL_ANSI; 1078 demangle_flags = DMGL_PARAMS | DMGL_ANSI;
1078 1079
1079 demangled = bfd_demangle(NULL, elf_name, demangle_flags); 1080 demangled = bfd_demangle(NULL, elf_name, demangle_flags);
1081 if (demangled == NULL)
1082 demangled = java_demangle_sym(elf_name, JAVA_DEMANGLE_NORET);
1080 if (demangled != NULL) 1083 if (demangled != NULL)
1081 elf_name = demangled; 1084 elf_name = demangled;
1082 } 1085 }
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
index ab02209a7cf3..e7588dc91518 100644
--- a/tools/perf/util/symbol.c
+++ b/tools/perf/util/symbol.c
@@ -1466,7 +1466,8 @@ int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter)
1466 * Read the build id if possible. This is required for 1466 * Read the build id if possible. This is required for
1467 * DSO_BINARY_TYPE__BUILDID_DEBUGINFO to work 1467 * DSO_BINARY_TYPE__BUILDID_DEBUGINFO to work
1468 */ 1468 */
1469 if (filename__read_build_id(dso->long_name, build_id, BUILD_ID_SIZE) > 0) 1469 if (is_regular_file(name) &&
1470 filename__read_build_id(dso->long_name, build_id, BUILD_ID_SIZE) > 0)
1470 dso__set_build_id(dso, build_id); 1471 dso__set_build_id(dso, build_id);
1471 1472
1472 /* 1473 /*
@@ -1487,6 +1488,9 @@ int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter)
1487 root_dir, name, PATH_MAX)) 1488 root_dir, name, PATH_MAX))
1488 continue; 1489 continue;
1489 1490
1491 if (!is_regular_file(name))
1492 continue;
1493
1490 /* Name is now the name of the next image to try */ 1494 /* Name is now the name of the next image to try */
1491 if (symsrc__init(ss, dso, name, symtab_type) < 0) 1495 if (symsrc__init(ss, dso, name, symtab_type) < 0)
1492 continue; 1496 continue;
@@ -1525,6 +1529,10 @@ int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter)
1525 if (!runtime_ss && syms_ss) 1529 if (!runtime_ss && syms_ss)
1526 runtime_ss = syms_ss; 1530 runtime_ss = syms_ss;
1527 1531
1532 if (syms_ss && syms_ss->type == DSO_BINARY_TYPE__BUILD_ID_CACHE)
1533 if (dso__build_id_is_kmod(dso, name, PATH_MAX))
1534 kmod = true;
1535
1528 if (syms_ss) 1536 if (syms_ss)
1529 ret = dso__load_sym(dso, map, syms_ss, runtime_ss, filter, kmod); 1537 ret = dso__load_sym(dso, map, syms_ss, runtime_ss, filter, kmod);
1530 else 1538 else
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h
index ccd1caa40e11..a937053a0ae0 100644
--- a/tools/perf/util/symbol.h
+++ b/tools/perf/util/symbol.h
@@ -110,7 +110,8 @@ struct symbol_conf {
110 has_filter, 110 has_filter,
111 show_ref_callgraph, 111 show_ref_callgraph,
112 hide_unresolved, 112 hide_unresolved,
113 raw_trace; 113 raw_trace,
114 report_hierarchy;
114 const char *vmlinux_name, 115 const char *vmlinux_name,
115 *kallsyms_name, 116 *kallsyms_name,
116 *source_prefix, 117 *source_prefix,
diff --git a/tools/perf/util/trace-event.c b/tools/perf/util/trace-event.c
index 802bb868d446..8ae051e0ec79 100644
--- a/tools/perf/util/trace-event.c
+++ b/tools/perf/util/trace-event.c
@@ -10,6 +10,7 @@
10#include <linux/err.h> 10#include <linux/err.h>
11#include <traceevent/event-parse.h> 11#include <traceevent/event-parse.h>
12#include <api/fs/tracing_path.h> 12#include <api/fs/tracing_path.h>
13#include <api/fs/fs.h>
13#include "trace-event.h" 14#include "trace-event.h"
14#include "machine.h" 15#include "machine.h"
15#include "util.h" 16#include "util.h"
diff --git a/tools/perf/util/tsc.c b/tools/perf/util/tsc.c
index 4d4210d4e13d..1b741646eed0 100644
--- a/tools/perf/util/tsc.c
+++ b/tools/perf/util/tsc.c
@@ -19,7 +19,7 @@ u64 tsc_to_perf_time(u64 cyc, struct perf_tsc_conversion *tc)
19 u64 quot, rem; 19 u64 quot, rem;
20 20
21 quot = cyc >> tc->time_shift; 21 quot = cyc >> tc->time_shift;
22 rem = cyc & ((1 << tc->time_shift) - 1); 22 rem = cyc & (((u64)1 << tc->time_shift) - 1);
23 return tc->time_zero + quot * tc->time_mult + 23 return tc->time_zero + quot * tc->time_mult +
24 ((rem * tc->time_mult) >> tc->time_shift); 24 ((rem * tc->time_mult) >> tc->time_shift);
25} 25}
diff --git a/tools/perf/util/util.c b/tools/perf/util/util.c
index ead9509835d2..b7766c577b01 100644
--- a/tools/perf/util/util.c
+++ b/tools/perf/util/util.c
@@ -14,6 +14,7 @@
14#include <limits.h> 14#include <limits.h>
15#include <byteswap.h> 15#include <byteswap.h>
16#include <linux/kernel.h> 16#include <linux/kernel.h>
17#include <linux/log2.h>
17#include <unistd.h> 18#include <unistd.h>
18#include "callchain.h" 19#include "callchain.h"
19#include "strlist.h" 20#include "strlist.h"
@@ -507,54 +508,6 @@ int parse_callchain_record(const char *arg, struct callchain_param *param)
507 return ret; 508 return ret;
508} 509}
509 510
510int filename__read_str(const char *filename, char **buf, size_t *sizep)
511{
512 size_t size = 0, alloc_size = 0;
513 void *bf = NULL, *nbf;
514 int fd, n, err = 0;
515 char sbuf[STRERR_BUFSIZE];
516
517 fd = open(filename, O_RDONLY);
518 if (fd < 0)
519 return -errno;
520
521 do {
522 if (size == alloc_size) {
523 alloc_size += BUFSIZ;
524 nbf = realloc(bf, alloc_size);
525 if (!nbf) {
526 err = -ENOMEM;
527 break;
528 }
529
530 bf = nbf;
531 }
532
533 n = read(fd, bf + size, alloc_size - size);
534 if (n < 0) {
535 if (size) {
536 pr_warning("read failed %d: %s\n", errno,
537 strerror_r(errno, sbuf, sizeof(sbuf)));
538 err = 0;
539 } else
540 err = -errno;
541
542 break;
543 }
544
545 size += n;
546 } while (n > 0);
547
548 if (!err) {
549 *sizep = size;
550 *buf = bf;
551 } else
552 free(bf);
553
554 close(fd);
555 return err;
556}
557
558const char *get_filename_for_perf_kvm(void) 511const char *get_filename_for_perf_kvm(void)
559{ 512{
560 const char *filename; 513 const char *filename;
@@ -691,3 +644,66 @@ out:
691 644
692 return tip; 645 return tip;
693} 646}
647
648bool is_regular_file(const char *file)
649{
650 struct stat st;
651
652 if (stat(file, &st))
653 return false;
654
655 return S_ISREG(st.st_mode);
656}
657
658int fetch_current_timestamp(char *buf, size_t sz)
659{
660 struct timeval tv;
661 struct tm tm;
662 char dt[32];
663
664 if (gettimeofday(&tv, NULL) || !localtime_r(&tv.tv_sec, &tm))
665 return -1;
666
667 if (!strftime(dt, sizeof(dt), "%Y%m%d%H%M%S", &tm))
668 return -1;
669
670 scnprintf(buf, sz, "%s%02u", dt, (unsigned)tv.tv_usec / 10000);
671
672 return 0;
673}
674
675void print_binary(unsigned char *data, size_t len,
676 size_t bytes_per_line, print_binary_t printer,
677 void *extra)
678{
679 size_t i, j, mask;
680
681 if (!printer)
682 return;
683
684 bytes_per_line = roundup_pow_of_two(bytes_per_line);
685 mask = bytes_per_line - 1;
686
687 printer(BINARY_PRINT_DATA_BEGIN, 0, extra);
688 for (i = 0; i < len; i++) {
689 if ((i & mask) == 0) {
690 printer(BINARY_PRINT_LINE_BEGIN, -1, extra);
691 printer(BINARY_PRINT_ADDR, i, extra);
692 }
693
694 printer(BINARY_PRINT_NUM_DATA, data[i], extra);
695
696 if (((i & mask) == mask) || i == len - 1) {
697 for (j = 0; j < mask-(i & mask); j++)
698 printer(BINARY_PRINT_NUM_PAD, -1, extra);
699
700 printer(BINARY_PRINT_SEP, i, extra);
701 for (j = i & ~mask; j <= i; j++)
702 printer(BINARY_PRINT_CHAR_DATA, data[j], extra);
703 for (j = 0; j < mask-(i & mask); j++)
704 printer(BINARY_PRINT_CHAR_PAD, i, extra);
705 printer(BINARY_PRINT_LINE_END, -1, extra);
706 }
707 }
708 printer(BINARY_PRINT_DATA_END, -1, extra);
709}
diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h
index fe915e616f9b..d0d50cef8b2a 100644
--- a/tools/perf/util/util.h
+++ b/tools/perf/util/util.h
@@ -82,6 +82,8 @@
82 82
83extern const char *graph_line; 83extern const char *graph_line;
84extern const char *graph_dotted_line; 84extern const char *graph_dotted_line;
85extern const char *spaces;
86extern const char *dots;
85extern char buildid_dir[]; 87extern char buildid_dir[];
86 88
87/* On most systems <limits.h> would have given us this, but 89/* On most systems <limits.h> would have given us this, but
@@ -303,7 +305,6 @@ char *__get_srcline(struct dso *dso, u64 addr, struct symbol *sym,
303 bool show_sym, bool unwind_inlines); 305 bool show_sym, bool unwind_inlines);
304void free_srcline(char *srcline); 306void free_srcline(char *srcline);
305 307
306int filename__read_str(const char *filename, char **buf, size_t *sizep);
307int perf_event_paranoid(void); 308int perf_event_paranoid(void);
308 309
309void mem_bswap_64(void *src, int byte_size); 310void mem_bswap_64(void *src, int byte_size);
@@ -343,5 +344,27 @@ int fetch_kernel_version(unsigned int *puint,
343#define KVER_PARAM(x) KVER_VERSION(x), KVER_PATCHLEVEL(x), KVER_SUBLEVEL(x) 344#define KVER_PARAM(x) KVER_VERSION(x), KVER_PATCHLEVEL(x), KVER_SUBLEVEL(x)
344 345
345const char *perf_tip(const char *dirpath); 346const char *perf_tip(const char *dirpath);
347bool is_regular_file(const char *file);
348int fetch_current_timestamp(char *buf, size_t sz);
349
350enum binary_printer_ops {
351 BINARY_PRINT_DATA_BEGIN,
352 BINARY_PRINT_LINE_BEGIN,
353 BINARY_PRINT_ADDR,
354 BINARY_PRINT_NUM_DATA,
355 BINARY_PRINT_NUM_PAD,
356 BINARY_PRINT_SEP,
357 BINARY_PRINT_CHAR_DATA,
358 BINARY_PRINT_CHAR_PAD,
359 BINARY_PRINT_LINE_END,
360 BINARY_PRINT_DATA_END,
361};
362
363typedef void (*print_binary_t)(enum binary_printer_ops,
364 unsigned int val,
365 void *extra);
346 366
367void print_binary(unsigned char *data, size_t len,
368 size_t bytes_per_line, print_binary_t printer,
369 void *extra);
347#endif /* GIT_COMPAT_UTIL_H */ 370#endif /* GIT_COMPAT_UTIL_H */
diff --git a/tools/power/x86/turbostat/turbostat.c b/tools/power/x86/turbostat/turbostat.c
index 0dac7e05a6ac..3fa94e291d16 100644
--- a/tools/power/x86/turbostat/turbostat.c
+++ b/tools/power/x86/turbostat/turbostat.c
@@ -1970,7 +1970,7 @@ int has_config_tdp(unsigned int family, unsigned int model)
1970} 1970}
1971 1971
1972static void 1972static void
1973dump_cstate_pstate_config_info(family, model) 1973dump_cstate_pstate_config_info(unsigned int family, unsigned int model)
1974{ 1974{
1975 if (!do_nhm_platform_info) 1975 if (!do_nhm_platform_info)
1976 return; 1976 return;
@@ -2142,7 +2142,7 @@ int print_perf_limit(struct thread_data *t, struct core_data *c, struct pkg_data
2142#define RAPL_POWER_GRANULARITY 0x7FFF /* 15 bit power granularity */ 2142#define RAPL_POWER_GRANULARITY 0x7FFF /* 15 bit power granularity */
2143#define RAPL_TIME_GRANULARITY 0x3F /* 6 bit time granularity */ 2143#define RAPL_TIME_GRANULARITY 0x3F /* 6 bit time granularity */
2144 2144
2145double get_tdp(model) 2145double get_tdp(unsigned int model)
2146{ 2146{
2147 unsigned long long msr; 2147 unsigned long long msr;
2148 2148
@@ -2256,7 +2256,7 @@ void rapl_probe(unsigned int family, unsigned int model)
2256 return; 2256 return;
2257} 2257}
2258 2258
2259void perf_limit_reasons_probe(family, model) 2259void perf_limit_reasons_probe(unsigned int family, unsigned int model)
2260{ 2260{
2261 if (!genuine_intel) 2261 if (!genuine_intel)
2262 return; 2262 return;
@@ -2792,7 +2792,7 @@ void process_cpuid()
2792 perf_limit_reasons_probe(family, model); 2792 perf_limit_reasons_probe(family, model);
2793 2793
2794 if (debug) 2794 if (debug)
2795 dump_cstate_pstate_config_info(); 2795 dump_cstate_pstate_config_info(family, model);
2796 2796
2797 if (has_skl_msrs(family, model)) 2797 if (has_skl_msrs(family, model))
2798 calculate_tsc_tweak(); 2798 calculate_tsc_tweak();
diff --git a/tools/testing/selftests/rcutorture/bin/parse-console.sh b/tools/testing/selftests/rcutorture/bin/parse-console.sh
index 844787a0d7be..5eb49b7f864c 100755
--- a/tools/testing/selftests/rcutorture/bin/parse-console.sh
+++ b/tools/testing/selftests/rcutorture/bin/parse-console.sh
@@ -33,7 +33,7 @@ if grep -Pq '\x00' < $file
33then 33then
34 print_warning Console output contains nul bytes, old qemu still running? 34 print_warning Console output contains nul bytes, old qemu still running?
35fi 35fi
36egrep 'Badness|WARNING:|Warn|BUG|===========|Call Trace:|Oops:|detected stalls on CPUs/tasks:|Stall ended before state dump start' < $file | grep -v 'ODEBUG: ' | grep -v 'Warning: unable to open an initial console' > $1.diags 36egrep 'Badness|WARNING:|Warn|BUG|===========|Call Trace:|Oops:|detected stalls on CPUs/tasks:|self-detected stall on CPU|Stall ended before state dump start|\?\?\? Writer stall state' < $file | grep -v 'ODEBUG: ' | grep -v 'Warning: unable to open an initial console' > $1.diags
37if test -s $1.diags 37if test -s $1.diags
38then 38then
39 print_warning Assertion failure in $file $title 39 print_warning Assertion failure in $file $title
@@ -64,10 +64,12 @@ then
64 then 64 then
65 summary="$summary lockdep: $n_badness" 65 summary="$summary lockdep: $n_badness"
66 fi 66 fi
67 n_stalls=`egrep -c 'detected stalls on CPUs/tasks:|Stall ended before state dump start' $1` 67 n_stalls=`egrep -c 'detected stalls on CPUs/tasks:|self-detected stall on CPU|Stall ended before state dump start|\?\?\? Writer stall state' $1`
68 if test "$n_stalls" -ne 0 68 if test "$n_stalls" -ne 0
69 then 69 then
70 summary="$summary Stalls: $n_stalls" 70 summary="$summary Stalls: $n_stalls"
71 fi 71 fi
72 print_warning Summary: $summary 72 print_warning Summary: $summary
73else
74 rm $1.diags
73fi 75fi
diff --git a/tools/testing/selftests/x86/Makefile b/tools/testing/selftests/x86/Makefile
index d0c473f65850..d5ce7d7aae3e 100644
--- a/tools/testing/selftests/x86/Makefile
+++ b/tools/testing/selftests/x86/Makefile
@@ -4,15 +4,16 @@ include ../lib.mk
4 4
5.PHONY: all all_32 all_64 warn_32bit_failure clean 5.PHONY: all all_32 all_64 warn_32bit_failure clean
6 6
7TARGETS_C_BOTHBITS := single_step_syscall sysret_ss_attrs syscall_nt ptrace_syscall 7TARGETS_C_BOTHBITS := single_step_syscall sysret_ss_attrs syscall_nt ptrace_syscall \
8TARGETS_C_32BIT_ONLY := entry_from_vm86 syscall_arg_fault sigreturn test_syscall_vdso unwind_vdso \ 8 check_initial_reg_state sigreturn ldt_gdt
9TARGETS_C_32BIT_ONLY := entry_from_vm86 syscall_arg_fault test_syscall_vdso unwind_vdso \
9 test_FCMOV test_FCOMI test_FISTTP \ 10 test_FCMOV test_FCOMI test_FISTTP \
10 ldt_gdt \
11 vdso_restorer 11 vdso_restorer
12 12
13TARGETS_C_32BIT_ALL := $(TARGETS_C_BOTHBITS) $(TARGETS_C_32BIT_ONLY) 13TARGETS_C_32BIT_ALL := $(TARGETS_C_BOTHBITS) $(TARGETS_C_32BIT_ONLY)
14TARGETS_C_64BIT_ALL := $(TARGETS_C_BOTHBITS) $(TARGETS_C_64BIT_ONLY)
14BINARIES_32 := $(TARGETS_C_32BIT_ALL:%=%_32) 15BINARIES_32 := $(TARGETS_C_32BIT_ALL:%=%_32)
15BINARIES_64 := $(TARGETS_C_BOTHBITS:%=%_64) 16BINARIES_64 := $(TARGETS_C_64BIT_ALL:%=%_64)
16 17
17CFLAGS := -O2 -g -std=gnu99 -pthread -Wall 18CFLAGS := -O2 -g -std=gnu99 -pthread -Wall
18 19
@@ -40,7 +41,7 @@ clean:
40$(TARGETS_C_32BIT_ALL:%=%_32): %_32: %.c 41$(TARGETS_C_32BIT_ALL:%=%_32): %_32: %.c
41 $(CC) -m32 -o $@ $(CFLAGS) $(EXTRA_CFLAGS) $^ -lrt -ldl -lm 42 $(CC) -m32 -o $@ $(CFLAGS) $(EXTRA_CFLAGS) $^ -lrt -ldl -lm
42 43
43$(TARGETS_C_BOTHBITS:%=%_64): %_64: %.c 44$(TARGETS_C_64BIT_ALL:%=%_64): %_64: %.c
44 $(CC) -m64 -o $@ $(CFLAGS) $(EXTRA_CFLAGS) $^ -lrt -ldl 45 $(CC) -m64 -o $@ $(CFLAGS) $(EXTRA_CFLAGS) $^ -lrt -ldl
45 46
46# x86_64 users should be encouraged to install 32-bit libraries 47# x86_64 users should be encouraged to install 32-bit libraries
@@ -65,3 +66,9 @@ endif
65sysret_ss_attrs_64: thunks.S 66sysret_ss_attrs_64: thunks.S
66ptrace_syscall_32: raw_syscall_helper_32.S 67ptrace_syscall_32: raw_syscall_helper_32.S
67test_syscall_vdso_32: thunks_32.S 68test_syscall_vdso_32: thunks_32.S
69
70# check_initial_reg_state is special: it needs a custom entry, and it
71# needs to be static so that its interpreter doesn't destroy its initial
72# state.
73check_initial_reg_state_32: CFLAGS += -Wl,-ereal_start -static
74check_initial_reg_state_64: CFLAGS += -Wl,-ereal_start -static
diff --git a/tools/testing/selftests/x86/check_initial_reg_state.c b/tools/testing/selftests/x86/check_initial_reg_state.c
new file mode 100644
index 000000000000..6aaed9b85baf
--- /dev/null
+++ b/tools/testing/selftests/x86/check_initial_reg_state.c
@@ -0,0 +1,109 @@
1/*
2 * check_initial_reg_state.c - check that execve sets the correct state
3 * Copyright (c) 2014-2016 Andrew Lutomirski
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms and conditions of the GNU General Public License,
7 * version 2, as published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
13 */
14
15#define _GNU_SOURCE
16
17#include <stdio.h>
18
19unsigned long ax, bx, cx, dx, si, di, bp, sp, flags;
20unsigned long r8, r9, r10, r11, r12, r13, r14, r15;
21
22asm (
23 ".pushsection .text\n\t"
24 ".type real_start, @function\n\t"
25 ".global real_start\n\t"
26 "real_start:\n\t"
27#ifdef __x86_64__
28 "mov %rax, ax\n\t"
29 "mov %rbx, bx\n\t"
30 "mov %rcx, cx\n\t"
31 "mov %rdx, dx\n\t"
32 "mov %rsi, si\n\t"
33 "mov %rdi, di\n\t"
34 "mov %rbp, bp\n\t"
35 "mov %rsp, sp\n\t"
36 "mov %r8, r8\n\t"
37 "mov %r9, r9\n\t"
38 "mov %r10, r10\n\t"
39 "mov %r11, r11\n\t"
40 "mov %r12, r12\n\t"
41 "mov %r13, r13\n\t"
42 "mov %r14, r14\n\t"
43 "mov %r15, r15\n\t"
44 "pushfq\n\t"
45 "popq flags\n\t"
46#else
47 "mov %eax, ax\n\t"
48 "mov %ebx, bx\n\t"
49 "mov %ecx, cx\n\t"
50 "mov %edx, dx\n\t"
51 "mov %esi, si\n\t"
52 "mov %edi, di\n\t"
53 "mov %ebp, bp\n\t"
54 "mov %esp, sp\n\t"
55 "pushfl\n\t"
56 "popl flags\n\t"
57#endif
58 "jmp _start\n\t"
59 ".size real_start, . - real_start\n\t"
60 ".popsection");
61
62int main()
63{
64 int nerrs = 0;
65
66 if (sp == 0) {
67 printf("[FAIL]\tTest was built incorrectly\n");
68 return 1;
69 }
70
71 if (ax || bx || cx || dx || si || di || bp
72#ifdef __x86_64__
73 || r8 || r9 || r10 || r11 || r12 || r13 || r14 || r15
74#endif
75 ) {
76 printf("[FAIL]\tAll GPRs except SP should be 0\n");
77#define SHOW(x) printf("\t" #x " = 0x%lx\n", x);
78 SHOW(ax);
79 SHOW(bx);
80 SHOW(cx);
81 SHOW(dx);
82 SHOW(si);
83 SHOW(di);
84 SHOW(bp);
85 SHOW(sp);
86#ifdef __x86_64__
87 SHOW(r8);
88 SHOW(r9);
89 SHOW(r10);
90 SHOW(r11);
91 SHOW(r12);
92 SHOW(r13);
93 SHOW(r14);
94 SHOW(r15);
95#endif
96 nerrs++;
97 } else {
98 printf("[OK]\tAll GPRs except SP are 0\n");
99 }
100
101 if (flags != 0x202) {
102 printf("[FAIL]\tFLAGS is 0x%lx, but it should be 0x202\n", flags);
103 nerrs++;
104 } else {
105 printf("[OK]\tFLAGS is 0x202\n");
106 }
107
108 return nerrs ? 1 : 0;
109}
diff --git a/tools/testing/selftests/x86/ptrace_syscall.c b/tools/testing/selftests/x86/ptrace_syscall.c
index 5105b49cd8aa..421456784bc6 100644
--- a/tools/testing/selftests/x86/ptrace_syscall.c
+++ b/tools/testing/selftests/x86/ptrace_syscall.c
@@ -103,6 +103,17 @@ static void sethandler(int sig, void (*handler)(int, siginfo_t *, void *),
103 err(1, "sigaction"); 103 err(1, "sigaction");
104} 104}
105 105
106static void setsigign(int sig, int flags)
107{
108 struct sigaction sa;
109 memset(&sa, 0, sizeof(sa));
110 sa.sa_sigaction = (void *)SIG_IGN;
111 sa.sa_flags = flags;
112 sigemptyset(&sa.sa_mask);
113 if (sigaction(sig, &sa, 0))
114 err(1, "sigaction");
115}
116
106static void clearhandler(int sig) 117static void clearhandler(int sig)
107{ 118{
108 struct sigaction sa; 119 struct sigaction sa;
@@ -187,7 +198,7 @@ static void test_ptrace_syscall_restart(void)
187 198
188 printf("[RUN]\tSYSEMU\n"); 199 printf("[RUN]\tSYSEMU\n");
189 if (ptrace(PTRACE_SYSEMU, chld, 0, 0) != 0) 200 if (ptrace(PTRACE_SYSEMU, chld, 0, 0) != 0)
190 err(1, "PTRACE_SYSCALL"); 201 err(1, "PTRACE_SYSEMU");
191 wait_trap(chld); 202 wait_trap(chld);
192 203
193 if (ptrace(PTRACE_GETREGS, chld, 0, &regs) != 0) 204 if (ptrace(PTRACE_GETREGS, chld, 0, &regs) != 0)
@@ -218,7 +229,7 @@ static void test_ptrace_syscall_restart(void)
218 err(1, "PTRACE_SETREGS"); 229 err(1, "PTRACE_SETREGS");
219 230
220 if (ptrace(PTRACE_SYSEMU, chld, 0, 0) != 0) 231 if (ptrace(PTRACE_SYSEMU, chld, 0, 0) != 0)
221 err(1, "PTRACE_SYSCALL"); 232 err(1, "PTRACE_SYSEMU");
222 wait_trap(chld); 233 wait_trap(chld);
223 234
224 if (ptrace(PTRACE_GETREGS, chld, 0, &regs) != 0) 235 if (ptrace(PTRACE_GETREGS, chld, 0, &regs) != 0)
@@ -250,7 +261,7 @@ static void test_ptrace_syscall_restart(void)
250 err(1, "PTRACE_SETREGS"); 261 err(1, "PTRACE_SETREGS");
251 262
252 if (ptrace(PTRACE_SYSEMU, chld, 0, 0) != 0) 263 if (ptrace(PTRACE_SYSEMU, chld, 0, 0) != 0)
253 err(1, "PTRACE_SYSCALL"); 264 err(1, "PTRACE_SYSEMU");
254 wait_trap(chld); 265 wait_trap(chld);
255 266
256 if (ptrace(PTRACE_GETREGS, chld, 0, &regs) != 0) 267 if (ptrace(PTRACE_GETREGS, chld, 0, &regs) != 0)
@@ -277,6 +288,119 @@ static void test_ptrace_syscall_restart(void)
277 } 288 }
278} 289}
279 290
291static void test_restart_under_ptrace(void)
292{
293 printf("[RUN]\tkernel syscall restart under ptrace\n");
294 pid_t chld = fork();
295 if (chld < 0)
296 err(1, "fork");
297
298 if (chld == 0) {
299 if (ptrace(PTRACE_TRACEME, 0, 0, 0) != 0)
300 err(1, "PTRACE_TRACEME");
301
302 printf("\tChild will take a nap until signaled\n");
303 setsigign(SIGUSR1, SA_RESTART);
304 raise(SIGSTOP);
305
306 syscall(SYS_pause, 0, 0, 0, 0, 0, 0);
307 _exit(0);
308 }
309
310 int status;
311
312 /* Wait for SIGSTOP. */
313 if (waitpid(chld, &status, 0) != chld || !WIFSTOPPED(status))
314 err(1, "waitpid");
315
316 struct user_regs_struct regs;
317
318 printf("[RUN]\tSYSCALL\n");
319 if (ptrace(PTRACE_SYSCALL, chld, 0, 0) != 0)
320 err(1, "PTRACE_SYSCALL");
321 wait_trap(chld);
322
323 /* We should be stopped at pause(2) entry. */
324
325 if (ptrace(PTRACE_GETREGS, chld, 0, &regs) != 0)
326 err(1, "PTRACE_GETREGS");
327
328 if (regs.user_syscall_nr != SYS_pause ||
329 regs.user_arg0 != 0 || regs.user_arg1 != 0 ||
330 regs.user_arg2 != 0 || regs.user_arg3 != 0 ||
331 regs.user_arg4 != 0 || regs.user_arg5 != 0) {
332 printf("[FAIL]\tInitial args are wrong (nr=%lu, args=%lu %lu %lu %lu %lu %lu)\n", (unsigned long)regs.user_syscall_nr, (unsigned long)regs.user_arg0, (unsigned long)regs.user_arg1, (unsigned long)regs.user_arg2, (unsigned long)regs.user_arg3, (unsigned long)regs.user_arg4, (unsigned long)regs.user_arg5);
333 nerrs++;
334 } else {
335 printf("[OK]\tInitial nr and args are correct\n");
336 }
337
338 /* Interrupt it. */
339 kill(chld, SIGUSR1);
340
341 /* Advance. We should be stopped at exit. */
342 printf("[RUN]\tSYSCALL\n");
343 if (ptrace(PTRACE_SYSCALL, chld, 0, 0) != 0)
344 err(1, "PTRACE_SYSCALL");
345 wait_trap(chld);
346
347 if (ptrace(PTRACE_GETREGS, chld, 0, &regs) != 0)
348 err(1, "PTRACE_GETREGS");
349
350 if (regs.user_syscall_nr != SYS_pause ||
351 regs.user_arg0 != 0 || regs.user_arg1 != 0 ||
352 regs.user_arg2 != 0 || regs.user_arg3 != 0 ||
353 regs.user_arg4 != 0 || regs.user_arg5 != 0) {
354 printf("[FAIL]\tArgs after SIGUSR1 are wrong (nr=%lu, args=%lu %lu %lu %lu %lu %lu)\n", (unsigned long)regs.user_syscall_nr, (unsigned long)regs.user_arg0, (unsigned long)regs.user_arg1, (unsigned long)regs.user_arg2, (unsigned long)regs.user_arg3, (unsigned long)regs.user_arg4, (unsigned long)regs.user_arg5);
355 nerrs++;
356 } else {
357 printf("[OK]\tArgs after SIGUSR1 are correct (ax = %ld)\n",
358 (long)regs.user_ax);
359 }
360
361 /* Poke the regs back in. This must not break anything. */
362 if (ptrace(PTRACE_SETREGS, chld, 0, &regs) != 0)
363 err(1, "PTRACE_SETREGS");
364
365 /* Catch the (ignored) SIGUSR1. */
366 if (ptrace(PTRACE_CONT, chld, 0, 0) != 0)
367 err(1, "PTRACE_CONT");
368 if (waitpid(chld, &status, 0) != chld)
369 err(1, "waitpid");
370 if (!WIFSTOPPED(status)) {
371 printf("[FAIL]\tChild was stopped for SIGUSR1 (status = 0x%x)\n", status);
372 nerrs++;
373 } else {
374 printf("[OK]\tChild got SIGUSR1\n");
375 }
376
377 /* The next event should be pause(2) again. */
378 printf("[RUN]\tStep again\n");
379 if (ptrace(PTRACE_SYSCALL, chld, 0, 0) != 0)
380 err(1, "PTRACE_SYSCALL");
381 wait_trap(chld);
382
383 /* We should be stopped at pause(2) entry. */
384
385 if (ptrace(PTRACE_GETREGS, chld, 0, &regs) != 0)
386 err(1, "PTRACE_GETREGS");
387
388 if (regs.user_syscall_nr != SYS_pause ||
389 regs.user_arg0 != 0 || regs.user_arg1 != 0 ||
390 regs.user_arg2 != 0 || regs.user_arg3 != 0 ||
391 regs.user_arg4 != 0 || regs.user_arg5 != 0) {
392 printf("[FAIL]\tpause did not restart (nr=%lu, args=%lu %lu %lu %lu %lu %lu)\n", (unsigned long)regs.user_syscall_nr, (unsigned long)regs.user_arg0, (unsigned long)regs.user_arg1, (unsigned long)regs.user_arg2, (unsigned long)regs.user_arg3, (unsigned long)regs.user_arg4, (unsigned long)regs.user_arg5);
393 nerrs++;
394 } else {
395 printf("[OK]\tpause(2) restarted correctly\n");
396 }
397
398 /* Kill it. */
399 kill(chld, SIGKILL);
400 if (waitpid(chld, &status, 0) != chld)
401 err(1, "waitpid");
402}
403
280int main() 404int main()
281{ 405{
282 printf("[RUN]\tCheck int80 return regs\n"); 406 printf("[RUN]\tCheck int80 return regs\n");
@@ -290,5 +414,7 @@ int main()
290 414
291 test_ptrace_syscall_restart(); 415 test_ptrace_syscall_restart();
292 416
417 test_restart_under_ptrace();
418
293 return 0; 419 return 0;
294} 420}
diff --git a/tools/testing/selftests/x86/sigreturn.c b/tools/testing/selftests/x86/sigreturn.c
index b5aa1bab7416..8a577e7070c6 100644
--- a/tools/testing/selftests/x86/sigreturn.c
+++ b/tools/testing/selftests/x86/sigreturn.c
@@ -54,6 +54,37 @@
54#include <sys/ptrace.h> 54#include <sys/ptrace.h>
55#include <sys/user.h> 55#include <sys/user.h>
56 56
57/* Pull in AR_xyz defines. */
58typedef unsigned int u32;
59typedef unsigned short u16;
60#include "../../../../arch/x86/include/asm/desc_defs.h"
61
62/*
63 * Copied from asm/ucontext.h, as asm/ucontext.h conflicts badly with the glibc
64 * headers.
65 */
66#ifdef __x86_64__
67/*
68 * UC_SIGCONTEXT_SS will be set when delivering 64-bit or x32 signals on
69 * kernels that save SS in the sigcontext. All kernels that set
70 * UC_SIGCONTEXT_SS will correctly restore at least the low 32 bits of esp
71 * regardless of SS (i.e. they implement espfix).
72 *
73 * Kernels that set UC_SIGCONTEXT_SS will also set UC_STRICT_RESTORE_SS
74 * when delivering a signal that came from 64-bit code.
75 *
76 * Sigreturn restores SS as follows:
77 *
78 * if (saved SS is valid || UC_STRICT_RESTORE_SS is set ||
79 * saved CS is not 64-bit)
80 * new SS = saved SS (will fail IRET and signal if invalid)
81 * else
82 * new SS = a flat 32-bit data segment
83 */
84#define UC_SIGCONTEXT_SS 0x2
85#define UC_STRICT_RESTORE_SS 0x4
86#endif
87
57/* 88/*
58 * In principle, this test can run on Linux emulation layers (e.g. 89 * In principle, this test can run on Linux emulation layers (e.g.
59 * Illumos "LX branded zones"). Solaris-based kernels reserve LDT 90 * Illumos "LX branded zones"). Solaris-based kernels reserve LDT
@@ -267,6 +298,9 @@ static gregset_t initial_regs, requested_regs, resulting_regs;
267/* Instructions for the SIGUSR1 handler. */ 298/* Instructions for the SIGUSR1 handler. */
268static volatile unsigned short sig_cs, sig_ss; 299static volatile unsigned short sig_cs, sig_ss;
269static volatile sig_atomic_t sig_trapped, sig_err, sig_trapno; 300static volatile sig_atomic_t sig_trapped, sig_err, sig_trapno;
301#ifdef __x86_64__
302static volatile sig_atomic_t sig_corrupt_final_ss;
303#endif
270 304
271/* Abstractions for some 32-bit vs 64-bit differences. */ 305/* Abstractions for some 32-bit vs 64-bit differences. */
272#ifdef __x86_64__ 306#ifdef __x86_64__
@@ -305,9 +339,105 @@ static greg_t *csptr(ucontext_t *ctx)
305} 339}
306#endif 340#endif
307 341
342/*
343 * Checks a given selector for its code bitness or returns -1 if it's not
344 * a usable code segment selector.
345 */
346int cs_bitness(unsigned short cs)
347{
348 uint32_t valid = 0, ar;
349 asm ("lar %[cs], %[ar]\n\t"
350 "jnz 1f\n\t"
351 "mov $1, %[valid]\n\t"
352 "1:"
353 : [ar] "=r" (ar), [valid] "+rm" (valid)
354 : [cs] "r" (cs));
355
356 if (!valid)
357 return -1;
358
359 bool db = (ar & (1 << 22));
360 bool l = (ar & (1 << 21));
361
362 if (!(ar & (1<<11)))
363 return -1; /* Not code. */
364
365 if (l && !db)
366 return 64;
367 else if (!l && db)
368 return 32;
369 else if (!l && !db)
370 return 16;
371 else
372 return -1; /* Unknown bitness. */
373}
374
375/*
376 * Checks a given selector for its code bitness or returns -1 if it's not
377 * a usable code segment selector.
378 */
379bool is_valid_ss(unsigned short cs)
380{
381 uint32_t valid = 0, ar;
382 asm ("lar %[cs], %[ar]\n\t"
383 "jnz 1f\n\t"
384 "mov $1, %[valid]\n\t"
385 "1:"
386 : [ar] "=r" (ar), [valid] "+rm" (valid)
387 : [cs] "r" (cs));
388
389 if (!valid)
390 return false;
391
392 if ((ar & AR_TYPE_MASK) != AR_TYPE_RWDATA &&
393 (ar & AR_TYPE_MASK) != AR_TYPE_RWDATA_EXPDOWN)
394 return false;
395
396 return (ar & AR_P);
397}
398
308/* Number of errors in the current test case. */ 399/* Number of errors in the current test case. */
309static volatile sig_atomic_t nerrs; 400static volatile sig_atomic_t nerrs;
310 401
402static void validate_signal_ss(int sig, ucontext_t *ctx)
403{
404#ifdef __x86_64__
405 bool was_64bit = (cs_bitness(*csptr(ctx)) == 64);
406
407 if (!(ctx->uc_flags & UC_SIGCONTEXT_SS)) {
408 printf("[FAIL]\tUC_SIGCONTEXT_SS was not set\n");
409 nerrs++;
410
411 /*
412 * This happens on Linux 4.1. The rest will fail, too, so
413 * return now to reduce the noise.
414 */
415 return;
416 }
417
418 /* UC_STRICT_RESTORE_SS is set iff we came from 64-bit mode. */
419 if (!!(ctx->uc_flags & UC_STRICT_RESTORE_SS) != was_64bit) {
420 printf("[FAIL]\tUC_STRICT_RESTORE_SS was wrong in signal %d\n",
421 sig);
422 nerrs++;
423 }
424
425 if (is_valid_ss(*ssptr(ctx))) {
426 /*
427 * DOSEMU was written before 64-bit sigcontext had SS, and
428 * it tries to figure out the signal source SS by looking at
429 * the physical register. Make sure that keeps working.
430 */
431 unsigned short hw_ss;
432 asm ("mov %%ss, %0" : "=rm" (hw_ss));
433 if (hw_ss != *ssptr(ctx)) {
434 printf("[FAIL]\tHW SS didn't match saved SS\n");
435 nerrs++;
436 }
437 }
438#endif
439}
440
311/* 441/*
312 * SIGUSR1 handler. Sets CS and SS as requested and points IP to the 442 * SIGUSR1 handler. Sets CS and SS as requested and points IP to the
313 * int3 trampoline. Sets SP to a large known value so that we can see 443 * int3 trampoline. Sets SP to a large known value so that we can see
@@ -317,6 +447,8 @@ static void sigusr1(int sig, siginfo_t *info, void *ctx_void)
317{ 447{
318 ucontext_t *ctx = (ucontext_t*)ctx_void; 448 ucontext_t *ctx = (ucontext_t*)ctx_void;
319 449
450 validate_signal_ss(sig, ctx);
451
320 memcpy(&initial_regs, &ctx->uc_mcontext.gregs, sizeof(gregset_t)); 452 memcpy(&initial_regs, &ctx->uc_mcontext.gregs, sizeof(gregset_t));
321 453
322 *csptr(ctx) = sig_cs; 454 *csptr(ctx) = sig_cs;
@@ -334,13 +466,16 @@ static void sigusr1(int sig, siginfo_t *info, void *ctx_void)
334} 466}
335 467
336/* 468/*
337 * Called after a successful sigreturn. Restores our state so that 469 * Called after a successful sigreturn (via int3) or from a failed
338 * the original raise(SIGUSR1) returns. 470 * sigreturn (directly by kernel). Restores our state so that the
471 * original raise(SIGUSR1) returns.
339 */ 472 */
340static void sigtrap(int sig, siginfo_t *info, void *ctx_void) 473static void sigtrap(int sig, siginfo_t *info, void *ctx_void)
341{ 474{
342 ucontext_t *ctx = (ucontext_t*)ctx_void; 475 ucontext_t *ctx = (ucontext_t*)ctx_void;
343 476
477 validate_signal_ss(sig, ctx);
478
344 sig_err = ctx->uc_mcontext.gregs[REG_ERR]; 479 sig_err = ctx->uc_mcontext.gregs[REG_ERR];
345 sig_trapno = ctx->uc_mcontext.gregs[REG_TRAPNO]; 480 sig_trapno = ctx->uc_mcontext.gregs[REG_TRAPNO];
346 481
@@ -358,41 +493,62 @@ static void sigtrap(int sig, siginfo_t *info, void *ctx_void)
358 memcpy(&resulting_regs, &ctx->uc_mcontext.gregs, sizeof(gregset_t)); 493 memcpy(&resulting_regs, &ctx->uc_mcontext.gregs, sizeof(gregset_t));
359 memcpy(&ctx->uc_mcontext.gregs, &initial_regs, sizeof(gregset_t)); 494 memcpy(&ctx->uc_mcontext.gregs, &initial_regs, sizeof(gregset_t));
360 495
496#ifdef __x86_64__
497 if (sig_corrupt_final_ss) {
498 if (ctx->uc_flags & UC_STRICT_RESTORE_SS) {
499 printf("[FAIL]\tUC_STRICT_RESTORE_SS was set inappropriately\n");
500 nerrs++;
501 } else {
502 /*
503 * DOSEMU transitions from 32-bit to 64-bit mode by
504 * adjusting sigcontext, and it requires that this work
505 * even if the saved SS is bogus.
506 */
507 printf("\tCorrupting SS on return to 64-bit mode\n");
508 *ssptr(ctx) = 0;
509 }
510 }
511#endif
512
361 sig_trapped = sig; 513 sig_trapped = sig;
362} 514}
363 515
364/* 516#ifdef __x86_64__
365 * Checks a given selector for its code bitness or returns -1 if it's not 517/* Tests recovery if !UC_STRICT_RESTORE_SS */
366 * a usable code segment selector. 518static void sigusr2(int sig, siginfo_t *info, void *ctx_void)
367 */
368int cs_bitness(unsigned short cs)
369{ 519{
370 uint32_t valid = 0, ar; 520 ucontext_t *ctx = (ucontext_t*)ctx_void;
371 asm ("lar %[cs], %[ar]\n\t"
372 "jnz 1f\n\t"
373 "mov $1, %[valid]\n\t"
374 "1:"
375 : [ar] "=r" (ar), [valid] "+rm" (valid)
376 : [cs] "r" (cs));
377 521
378 if (!valid) 522 if (!(ctx->uc_flags & UC_STRICT_RESTORE_SS)) {
379 return -1; 523 printf("[FAIL]\traise(2) didn't set UC_STRICT_RESTORE_SS\n");
524 nerrs++;
525 return; /* We can't do the rest. */
526 }
380 527
381 bool db = (ar & (1 << 22)); 528 ctx->uc_flags &= ~UC_STRICT_RESTORE_SS;
382 bool l = (ar & (1 << 21)); 529 *ssptr(ctx) = 0;
383 530
384 if (!(ar & (1<<11))) 531 /* Return. The kernel should recover without sending another signal. */
385 return -1; /* Not code. */ 532}
386 533
387 if (l && !db) 534static int test_nonstrict_ss(void)
388 return 64; 535{
389 else if (!l && db) 536 clearhandler(SIGUSR1);
390 return 32; 537 clearhandler(SIGTRAP);
391 else if (!l && !db) 538 clearhandler(SIGSEGV);
392 return 16; 539 clearhandler(SIGILL);
393 else 540 sethandler(SIGUSR2, sigusr2, 0);
394 return -1; /* Unknown bitness. */ 541
542 nerrs = 0;
543
544 printf("[RUN]\tClear UC_STRICT_RESTORE_SS and corrupt SS\n");
545 raise(SIGUSR2);
546 if (!nerrs)
547 printf("[OK]\tIt worked\n");
548
549 return nerrs;
395} 550}
551#endif
396 552
397/* Finds a usable code segment of the requested bitness. */ 553/* Finds a usable code segment of the requested bitness. */
398int find_cs(int bitness) 554int find_cs(int bitness)
@@ -576,6 +732,12 @@ static int test_bad_iret(int cs_bits, unsigned short ss, int force_cs)
576 errdesc, strsignal(sig_trapped)); 732 errdesc, strsignal(sig_trapped));
577 return 0; 733 return 0;
578 } else { 734 } else {
735 /*
736 * This also implicitly tests UC_STRICT_RESTORE_SS:
737 * We check that these signals set UC_STRICT_RESTORE_SS and,
738 * if UC_STRICT_RESTORE_SS doesn't cause strict behavior,
739 * then we won't get SIGSEGV.
740 */
579 printf("[FAIL]\tDid not get SIGSEGV\n"); 741 printf("[FAIL]\tDid not get SIGSEGV\n");
580 return 1; 742 return 1;
581 } 743 }
@@ -632,6 +794,14 @@ int main()
632 GDT3(gdt_data16_idx)); 794 GDT3(gdt_data16_idx));
633 } 795 }
634 796
797#ifdef __x86_64__
798 /* Nasty ABI case: check SS corruption handling. */
799 sig_corrupt_final_ss = 1;
800 total_nerrs += test_valid_sigreturn(32, false, -1);
801 total_nerrs += test_valid_sigreturn(32, true, -1);
802 sig_corrupt_final_ss = 0;
803#endif
804
635 /* 805 /*
636 * We're done testing valid sigreturn cases. Now we test states 806 * We're done testing valid sigreturn cases. Now we test states
637 * for which sigreturn itself will succeed but the subsequent 807 * for which sigreturn itself will succeed but the subsequent
@@ -680,5 +850,9 @@ int main()
680 if (gdt_npdata32_idx) 850 if (gdt_npdata32_idx)
681 test_bad_iret(32, GDT3(gdt_npdata32_idx), -1); 851 test_bad_iret(32, GDT3(gdt_npdata32_idx), -1);
682 852
853#ifdef __x86_64__
854 total_nerrs += test_nonstrict_ss();
855#endif
856
683 return total_nerrs ? 1 : 0; 857 return total_nerrs ? 1 : 0;
684} 858}
diff --git a/tools/testing/selftests/x86/syscall_nt.c b/tools/testing/selftests/x86/syscall_nt.c
index 60c06af4646a..43fcab367fb0 100644
--- a/tools/testing/selftests/x86/syscall_nt.c
+++ b/tools/testing/selftests/x86/syscall_nt.c
@@ -17,6 +17,9 @@
17 17
18#include <stdio.h> 18#include <stdio.h>
19#include <unistd.h> 19#include <unistd.h>
20#include <string.h>
21#include <signal.h>
22#include <err.h>
20#include <sys/syscall.h> 23#include <sys/syscall.h>
21#include <asm/processor-flags.h> 24#include <asm/processor-flags.h>
22 25
@@ -26,6 +29,8 @@
26# define WIDTH "l" 29# define WIDTH "l"
27#endif 30#endif
28 31
32static unsigned int nerrs;
33
29static unsigned long get_eflags(void) 34static unsigned long get_eflags(void)
30{ 35{
31 unsigned long eflags; 36 unsigned long eflags;
@@ -39,16 +44,52 @@ static void set_eflags(unsigned long eflags)
39 : : "rm" (eflags) : "flags"); 44 : : "rm" (eflags) : "flags");
40} 45}
41 46
42int main() 47static void sethandler(int sig, void (*handler)(int, siginfo_t *, void *),
48 int flags)
43{ 49{
44 printf("[RUN]\tSet NT and issue a syscall\n"); 50 struct sigaction sa;
45 set_eflags(get_eflags() | X86_EFLAGS_NT); 51 memset(&sa, 0, sizeof(sa));
52 sa.sa_sigaction = handler;
53 sa.sa_flags = SA_SIGINFO | flags;
54 sigemptyset(&sa.sa_mask);
55 if (sigaction(sig, &sa, 0))
56 err(1, "sigaction");
57}
58
59static void sigtrap(int sig, siginfo_t *si, void *ctx_void)
60{
61}
62
63static void do_it(unsigned long extraflags)
64{
65 unsigned long flags;
66
67 set_eflags(get_eflags() | extraflags);
46 syscall(SYS_getpid); 68 syscall(SYS_getpid);
47 if (get_eflags() & X86_EFLAGS_NT) { 69 flags = get_eflags();
48 printf("[OK]\tThe syscall worked and NT is still set\n"); 70 if ((flags & extraflags) == extraflags) {
49 return 0; 71 printf("[OK]\tThe syscall worked and flags are still set\n");
50 } else { 72 } else {
51 printf("[FAIL]\tThe syscall worked but NT was cleared\n"); 73 printf("[FAIL]\tThe syscall worked but flags were cleared (flags = 0x%lx but expected 0x%lx set)\n",
52 return 1; 74 flags, extraflags);
75 nerrs++;
53 } 76 }
54} 77}
78
79int main(void)
80{
81 printf("[RUN]\tSet NT and issue a syscall\n");
82 do_it(X86_EFLAGS_NT);
83
84 /*
85 * Now try it again with TF set -- TF forces returns via IRET in all
86 * cases except non-ptregs-using 64-bit full fast path syscalls.
87 */
88
89 sethandler(SIGTRAP, sigtrap, 0);
90
91 printf("[RUN]\tSet NT|TF and issue a syscall\n");
92 do_it(X86_EFLAGS_NT | X86_EFLAGS_TF);
93
94 return nerrs == 0 ? 0 : 1;
95}