aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2016-10-10 13:33:58 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2016-10-10 13:33:58 -0400
commitc48ce9f190266b763e809dd79fcf4152f558793c (patch)
tree60490f3c5ae8e236dc6ea336ca9c695527c835f5
parent84ed2da02f4cda6759880c87a213ee80c91ca3bd (diff)
parentc68306ce20ad03ce655a367fc33ad06e12bb87a6 (diff)
Merge branch 'perf-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull perf tooling updates from Thomas Gleixner: - handle uretprobe placement proper on little endian PPC64 - fix buffer handling in libtraceevent - add a missing pointer derefence in perf probe - fix the build of host tools in cross builds - fix Intel PT timestamp handling - synchronize memcpy, cpufeatures and bpf headers with the kernel headers - support for vendor supplied JSON files describing PMU events - a new set of tool tips - initial work for clang/llvm support - address some style issues found by cppcheck * 'perf-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (35 commits) tools build: Add feature detection for g++ tools build: Support compiling C++ source file perf top/report: Add tips about a list option perf report/top: Add a tip about system-wide collection from all CPUs perf report/top: Add a tip about source line numbers with overhead tools: Synchronize tools/include/uapi/linux/bpf.h tools: Synchronize tools/arch/x86/include/asm/cpufeatures.h perf bench mem: Sync memcpy assembly sources with the kernel perf jevents: Fix Intel JSON fixed counter conversions tools lib traceevent: Fix kbuffer_read_at_offset() perf intel-pt: Fix MTC timestamp calculation for large MTC periods perf intel-pt: Fix estimated timestamps for cycle-accurate mode perf uretprobe ppc64le: Fix probe location perf pmu-events: Add Skylake frontend MSR support perf pmu-events: Fix fixed counters on Intel perf tools: Make alias matching case-insensitive perf tools: Allow period= in perf stat CPU event descriptions. perf tools: Add README for info on parsing JSON/map files perf list jevents: Add support for event list topics perf list: Support long jevents descriptions ...
-rw-r--r--tools/arch/x86/include/asm/cpufeatures.h1
-rw-r--r--tools/arch/x86/lib/memcpy_64.S6
-rw-r--r--tools/build/Build2
-rw-r--r--tools/build/Build.include6
-rw-r--r--tools/build/Makefile8
-rw-r--r--tools/build/Makefile.build26
-rw-r--r--tools/build/Makefile.feature2
-rw-r--r--tools/build/Makefile.include4
-rw-r--r--tools/build/feature/Makefile10
-rw-r--r--tools/build/feature/test-cxx.cpp15
-rw-r--r--tools/include/uapi/linux/bpf.h4
-rw-r--r--tools/lib/subcmd/pager.c16
-rw-r--r--tools/lib/subcmd/pager.h1
-rw-r--r--tools/lib/traceevent/kbuffer-parse.c1
-rw-r--r--tools/perf/Documentation/perf-list.txt12
-rw-r--r--tools/perf/Documentation/tips.txt4
-rw-r--r--tools/perf/Makefile.perf34
-rw-r--r--tools/perf/arch/powerpc/util/header.c11
-rw-r--r--tools/perf/arch/powerpc/util/sym-handling.c3
-rw-r--r--tools/perf/arch/x86/util/header.c24
-rw-r--r--tools/perf/builtin-list.c20
-rw-r--r--tools/perf/pmu-events/Build13
-rw-r--r--tools/perf/pmu-events/README147
-rw-r--r--tools/perf/pmu-events/jevents.c814
-rw-r--r--tools/perf/pmu-events/jevents.h18
-rw-r--r--tools/perf/pmu-events/jsmn.c313
-rw-r--r--tools/perf/pmu-events/jsmn.h67
-rw-r--r--tools/perf/pmu-events/json.c162
-rw-r--r--tools/perf/pmu-events/json.h38
-rw-r--r--tools/perf/pmu-events/pmu-events.h37
-rw-r--r--tools/perf/util/evlist.c12
-rw-r--r--tools/perf/util/evsel.c3
-rw-r--r--tools/perf/util/header.h1
-rw-r--r--tools/perf/util/intel-pt-decoder/intel-pt-decoder.c38
-rw-r--r--tools/perf/util/machine.c6
-rw-r--r--tools/perf/util/parse-events.c8
-rw-r--r--tools/perf/util/parse-events.h3
-rw-r--r--tools/perf/util/pmu.c176
-rw-r--r--tools/perf/util/pmu.h6
-rw-r--r--tools/perf/util/probe-event.c2
-rw-r--r--tools/perf/util/strbuf.h3
-rw-r--r--tools/perf/util/thread.c9
42 files changed, 2011 insertions, 75 deletions
diff --git a/tools/arch/x86/include/asm/cpufeatures.h b/tools/arch/x86/include/asm/cpufeatures.h
index 92a8308b96f6..1188bc849ee3 100644
--- a/tools/arch/x86/include/asm/cpufeatures.h
+++ b/tools/arch/x86/include/asm/cpufeatures.h
@@ -106,7 +106,6 @@
106#define X86_FEATURE_APERFMPERF ( 3*32+28) /* APERFMPERF */ 106#define X86_FEATURE_APERFMPERF ( 3*32+28) /* APERFMPERF */
107#define X86_FEATURE_EAGER_FPU ( 3*32+29) /* "eagerfpu" Non lazy FPU restore */ 107#define X86_FEATURE_EAGER_FPU ( 3*32+29) /* "eagerfpu" Non lazy FPU restore */
108#define X86_FEATURE_NONSTOP_TSC_S3 ( 3*32+30) /* TSC doesn't stop in S3 state */ 108#define X86_FEATURE_NONSTOP_TSC_S3 ( 3*32+30) /* TSC doesn't stop in S3 state */
109#define X86_FEATURE_MCE_RECOVERY ( 3*32+31) /* cpu has recoverable machine checks */
110 109
111/* Intel-defined CPU features, CPUID level 0x00000001 (ecx), word 4 */ 110/* Intel-defined CPU features, CPUID level 0x00000001 (ecx), word 4 */
112#define X86_FEATURE_XMM3 ( 4*32+ 0) /* "pni" SSE-3 */ 111#define X86_FEATURE_XMM3 ( 4*32+ 0) /* "pni" SSE-3 */
diff --git a/tools/arch/x86/lib/memcpy_64.S b/tools/arch/x86/lib/memcpy_64.S
index 2ec0b0abbfaa..49e6ebac7e73 100644
--- a/tools/arch/x86/lib/memcpy_64.S
+++ b/tools/arch/x86/lib/memcpy_64.S
@@ -181,11 +181,11 @@ ENDPROC(memcpy_orig)
181 181
182#ifndef CONFIG_UML 182#ifndef CONFIG_UML
183/* 183/*
184 * memcpy_mcsafe - memory copy with machine check exception handling 184 * memcpy_mcsafe_unrolled - memory copy with machine check exception handling
185 * Note that we only catch machine checks when reading the source addresses. 185 * Note that we only catch machine checks when reading the source addresses.
186 * Writes to target are posted and don't generate machine checks. 186 * Writes to target are posted and don't generate machine checks.
187 */ 187 */
188ENTRY(memcpy_mcsafe) 188ENTRY(memcpy_mcsafe_unrolled)
189 cmpl $8, %edx 189 cmpl $8, %edx
190 /* Less than 8 bytes? Go to byte copy loop */ 190 /* Less than 8 bytes? Go to byte copy loop */
191 jb .L_no_whole_words 191 jb .L_no_whole_words
@@ -273,7 +273,7 @@ ENTRY(memcpy_mcsafe)
273.L_done_memcpy_trap: 273.L_done_memcpy_trap:
274 xorq %rax, %rax 274 xorq %rax, %rax
275 ret 275 ret
276ENDPROC(memcpy_mcsafe) 276ENDPROC(memcpy_mcsafe_unrolled)
277 277
278 .section .fixup, "ax" 278 .section .fixup, "ax"
279 /* Return -EFAULT for any failure */ 279 /* Return -EFAULT for any failure */
diff --git a/tools/build/Build b/tools/build/Build
index 63a6c34c0c88..76d1a4960973 100644
--- a/tools/build/Build
+++ b/tools/build/Build
@@ -1 +1,3 @@
1hostprogs := fixdep
2
1fixdep-y := fixdep.o 3fixdep-y := fixdep.o
diff --git a/tools/build/Build.include b/tools/build/Build.include
index 4d000bc959b4..1dcb95e76f70 100644
--- a/tools/build/Build.include
+++ b/tools/build/Build.include
@@ -90,3 +90,9 @@ if_changed = $(if $(strip $(any-prereq) $(arg-check)), \
90# - per object C flags 90# - per object C flags
91# - BUILD_STR macro to allow '-D"$(variable)"' constructs 91# - BUILD_STR macro to allow '-D"$(variable)"' constructs
92c_flags = -Wp,-MD,$(depfile),-MT,$@ $(CFLAGS) -D"BUILD_STR(s)=\#s" $(CFLAGS_$(basetarget).o) $(CFLAGS_$(obj)) 92c_flags = -Wp,-MD,$(depfile),-MT,$@ $(CFLAGS) -D"BUILD_STR(s)=\#s" $(CFLAGS_$(basetarget).o) $(CFLAGS_$(obj))
93cxx_flags = -Wp,-MD,$(depfile),-MT,$@ $(CXXFLAGS) -D"BUILD_STR(s)=\#s" $(CXXFLAGS_$(basetarget).o) $(CXXFLAGS_$(obj))
94
95###
96## HOSTCC C flags
97
98host_c_flags = -Wp,-MD,$(depfile),-MT,$@ $(CHOSTFLAGS) -D"BUILD_STR(s)=\#s" $(CHOSTFLAGS_$(basetarget).o) $(CHOSTFLAGS_$(obj))
diff --git a/tools/build/Makefile b/tools/build/Makefile
index 0d5a0e3a8fa9..8332959fbca4 100644
--- a/tools/build/Makefile
+++ b/tools/build/Makefile
@@ -14,6 +14,12 @@ endef
14$(call allow-override,CC,$(CROSS_COMPILE)gcc) 14$(call allow-override,CC,$(CROSS_COMPILE)gcc)
15$(call allow-override,LD,$(CROSS_COMPILE)ld) 15$(call allow-override,LD,$(CROSS_COMPILE)ld)
16 16
17HOSTCC ?= gcc
18HOSTLD ?= ld
19HOSTAR ?= ar
20
21export HOSTCC HOSTLD HOSTAR
22
17ifeq ($(V),1) 23ifeq ($(V),1)
18 Q = 24 Q =
19else 25else
@@ -36,7 +42,7 @@ $(OUTPUT)fixdep-in.o: FORCE
36 $(Q)$(MAKE) $(build)=fixdep 42 $(Q)$(MAKE) $(build)=fixdep
37 43
38$(OUTPUT)fixdep: $(OUTPUT)fixdep-in.o 44$(OUTPUT)fixdep: $(OUTPUT)fixdep-in.o
39 $(QUIET_LINK)$(CC) $(LDFLAGS) -o $@ $< 45 $(QUIET_LINK)$(HOSTCC) $(LDFLAGS) -o $@ $<
40 46
41FORCE: 47FORCE:
42 48
diff --git a/tools/build/Makefile.build b/tools/build/Makefile.build
index 27f3583193e6..99c0ccd2f176 100644
--- a/tools/build/Makefile.build
+++ b/tools/build/Makefile.build
@@ -58,6 +58,12 @@ quiet_cmd_mkdir = MKDIR $(dir $@)
58quiet_cmd_cc_o_c = CC $@ 58quiet_cmd_cc_o_c = CC $@
59 cmd_cc_o_c = $(CC) $(c_flags) -c -o $@ $< 59 cmd_cc_o_c = $(CC) $(c_flags) -c -o $@ $<
60 60
61quiet_cmd_host_cc_o_c = HOSTCC $@
62 cmd_host_cc_o_c = $(HOSTCC) $(host_c_flags) -c -o $@ $<
63
64quiet_cmd_cxx_o_c = CXX $@
65 cmd_cxx_o_c = $(CXX) $(cxx_flags) -c -o $@ $<
66
61quiet_cmd_cpp_i_c = CPP $@ 67quiet_cmd_cpp_i_c = CPP $@
62 cmd_cpp_i_c = $(CC) $(c_flags) -E -o $@ $< 68 cmd_cpp_i_c = $(CC) $(c_flags) -E -o $@ $<
63 69
@@ -70,16 +76,28 @@ quiet_cmd_gen = GEN $@
70# If there's nothing to link, create empty $@ object. 76# If there's nothing to link, create empty $@ object.
71quiet_cmd_ld_multi = LD $@ 77quiet_cmd_ld_multi = LD $@
72 cmd_ld_multi = $(if $(strip $(obj-y)),\ 78 cmd_ld_multi = $(if $(strip $(obj-y)),\
73 $(LD) -r -o $@ $(filter $(obj-y),$^),rm -f $@; $(AR) rcs $@) 79 $(LD) -r -o $@ $(filter $(obj-y),$^),rm -f $@; $(AR) rcs $@)
80
81quiet_cmd_host_ld_multi = HOSTLD $@
82 cmd_host_ld_multi = $(if $(strip $(obj-y)),\
83 $(HOSTLD) -r -o $@ $(filter $(obj-y),$^),rm -f $@; $(HOSTAR) rcs $@)
84
85ifneq ($(filter $(obj),$(hostprogs)),)
86 host = host_
87endif
74 88
75# Build rules 89# Build rules
76$(OUTPUT)%.o: %.c FORCE 90$(OUTPUT)%.o: %.c FORCE
77 $(call rule_mkdir) 91 $(call rule_mkdir)
78 $(call if_changed_dep,cc_o_c) 92 $(call if_changed_dep,$(host)cc_o_c)
93
94$(OUTPUT)%.o: %.cpp FORCE
95 $(call rule_mkdir)
96 $(call if_changed_dep,cxx_o_c)
79 97
80$(OUTPUT)%.o: %.S FORCE 98$(OUTPUT)%.o: %.S FORCE
81 $(call rule_mkdir) 99 $(call rule_mkdir)
82 $(call if_changed_dep,cc_o_c) 100 $(call if_changed_dep,$(host)cc_o_c)
83 101
84$(OUTPUT)%.i: %.c FORCE 102$(OUTPUT)%.i: %.c FORCE
85 $(call rule_mkdir) 103 $(call rule_mkdir)
@@ -119,7 +137,7 @@ $(sort $(subdir-obj-y)): $(subdir-y) ;
119 137
120$(in-target): $(obj-y) FORCE 138$(in-target): $(obj-y) FORCE
121 $(call rule_mkdir) 139 $(call rule_mkdir)
122 $(call if_changed,ld_multi) 140 $(call if_changed,$(host)ld_multi)
123 141
124__build: $(in-target) 142__build: $(in-target)
125 @: 143 @:
diff --git a/tools/build/Makefile.feature b/tools/build/Makefile.feature
index a120c6b755a9..ae52e029dd22 100644
--- a/tools/build/Makefile.feature
+++ b/tools/build/Makefile.feature
@@ -7,7 +7,7 @@ endif
7 7
8feature_check = $(eval $(feature_check_code)) 8feature_check = $(eval $(feature_check_code))
9define feature_check_code 9define feature_check_code
10 feature-$(1) := $(shell $(MAKE) OUTPUT=$(OUTPUT_FEATURES) CFLAGS="$(EXTRA_CFLAGS) $(FEATURE_CHECK_CFLAGS-$(1))" LDFLAGS="$(LDFLAGS) $(FEATURE_CHECK_LDFLAGS-$(1))" -C $(feature_dir) $(OUTPUT_FEATURES)test-$1.bin >/dev/null 2>/dev/null && echo 1 || echo 0) 10 feature-$(1) := $(shell $(MAKE) OUTPUT=$(OUTPUT_FEATURES) CFLAGS="$(EXTRA_CFLAGS) $(FEATURE_CHECK_CFLAGS-$(1))" CXXFLAGS="$(EXTRA_CXXFLAGS) $(FEATURE_CHECK_CXXFLAGS-$(1))" LDFLAGS="$(LDFLAGS) $(FEATURE_CHECK_LDFLAGS-$(1))" -C $(feature_dir) $(OUTPUT_FEATURES)test-$1.bin >/dev/null 2>/dev/null && echo 1 || echo 0)
11endef 11endef
12 12
13feature_set = $(eval $(feature_set_code)) 13feature_set = $(eval $(feature_set_code))
diff --git a/tools/build/Makefile.include b/tools/build/Makefile.include
index be630bed66d2..ad22e4e7bc59 100644
--- a/tools/build/Makefile.include
+++ b/tools/build/Makefile.include
@@ -1,10 +1,6 @@
1build := -f $(srctree)/tools/build/Makefile.build dir=. obj 1build := -f $(srctree)/tools/build/Makefile.build dir=. obj
2 2
3ifdef CROSS_COMPILE
4fixdep:
5else
6fixdep: 3fixdep:
7 $(Q)$(MAKE) -C $(srctree)/tools/build CFLAGS= LDFLAGS= $(OUTPUT)fixdep 4 $(Q)$(MAKE) -C $(srctree)/tools/build CFLAGS= LDFLAGS= $(OUTPUT)fixdep
8endif
9 5
10.PHONY: fixdep 6.PHONY: fixdep
diff --git a/tools/build/feature/Makefile b/tools/build/feature/Makefile
index a0b29a311816..ac9c477a2a48 100644
--- a/tools/build/feature/Makefile
+++ b/tools/build/feature/Makefile
@@ -46,11 +46,13 @@ FILES= \
46 test-lzma.bin \ 46 test-lzma.bin \
47 test-bpf.bin \ 47 test-bpf.bin \
48 test-get_cpuid.bin \ 48 test-get_cpuid.bin \
49 test-sdt.bin 49 test-sdt.bin \
50 test-cxx.bin
50 51
51FILES := $(addprefix $(OUTPUT),$(FILES)) 52FILES := $(addprefix $(OUTPUT),$(FILES))
52 53
53CC := $(CROSS_COMPILE)gcc -MD 54CC := $(CROSS_COMPILE)gcc -MD
55CXX := $(CROSS_COMPILE)g++ -MD
54PKG_CONFIG := $(CROSS_COMPILE)pkg-config 56PKG_CONFIG := $(CROSS_COMPILE)pkg-config
55 57
56all: $(FILES) 58all: $(FILES)
@@ -58,6 +60,9 @@ all: $(FILES)
58__BUILD = $(CC) $(CFLAGS) -Wall -Werror -o $@ $(patsubst %.bin,%.c,$(@F)) $(LDFLAGS) 60__BUILD = $(CC) $(CFLAGS) -Wall -Werror -o $@ $(patsubst %.bin,%.c,$(@F)) $(LDFLAGS)
59 BUILD = $(__BUILD) > $(@:.bin=.make.output) 2>&1 61 BUILD = $(__BUILD) > $(@:.bin=.make.output) 2>&1
60 62
63__BUILDXX = $(CXX) $(CXXFLAGS) -Wall -Werror -o $@ $(patsubst %.bin,%.cpp,$(@F)) $(LDFLAGS)
64 BUILDXX = $(__BUILDXX) > $(@:.bin=.make.output) 2>&1
65
61############################### 66###############################
62 67
63$(OUTPUT)test-all.bin: 68$(OUTPUT)test-all.bin:
@@ -217,6 +222,9 @@ $(OUTPUT)test-bpf.bin:
217$(OUTPUT)test-sdt.bin: 222$(OUTPUT)test-sdt.bin:
218 $(BUILD) 223 $(BUILD)
219 224
225$(OUTPUT)test-cxx.bin:
226 $(BUILDXX) -std=gnu++11
227
220-include $(OUTPUT)*.d 228-include $(OUTPUT)*.d
221 229
222############################### 230###############################
diff --git a/tools/build/feature/test-cxx.cpp b/tools/build/feature/test-cxx.cpp
new file mode 100644
index 000000000000..b1dee9a31d6c
--- /dev/null
+++ b/tools/build/feature/test-cxx.cpp
@@ -0,0 +1,15 @@
1#include <iostream>
2#include <memory>
3
4static void print_str(std::string s)
5{
6 std::cout << s << std::endl;
7}
8
9int main()
10{
11 std::string s("Hello World!");
12 print_str(std::move(s));
13 std::cout << "|" << s << "|" << std::endl;
14 return 0;
15}
diff --git a/tools/include/uapi/linux/bpf.h b/tools/include/uapi/linux/bpf.h
index da218fec6056..9e5fc168c8a3 100644
--- a/tools/include/uapi/linux/bpf.h
+++ b/tools/include/uapi/linux/bpf.h
@@ -339,7 +339,7 @@ enum bpf_func_id {
339 BPF_FUNC_skb_change_type, 339 BPF_FUNC_skb_change_type,
340 340
341 /** 341 /**
342 * bpf_skb_in_cgroup(skb, map, index) - Check cgroup2 membership of skb 342 * bpf_skb_under_cgroup(skb, map, index) - Check cgroup2 membership of skb
343 * @skb: pointer to skb 343 * @skb: pointer to skb
344 * @map: pointer to bpf_map in BPF_MAP_TYPE_CGROUP_ARRAY type 344 * @map: pointer to bpf_map in BPF_MAP_TYPE_CGROUP_ARRAY type
345 * @index: index of the cgroup in the bpf_map 345 * @index: index of the cgroup in the bpf_map
@@ -348,7 +348,7 @@ enum bpf_func_id {
348 * == 1 skb succeeded the cgroup2 descendant test 348 * == 1 skb succeeded the cgroup2 descendant test
349 * < 0 error 349 * < 0 error
350 */ 350 */
351 BPF_FUNC_skb_in_cgroup, 351 BPF_FUNC_skb_under_cgroup,
352 352
353 /** 353 /**
354 * bpf_get_hash_recalc(skb) 354 * bpf_get_hash_recalc(skb)
diff --git a/tools/lib/subcmd/pager.c b/tools/lib/subcmd/pager.c
index d50f3b58606b..6518bea926d6 100644
--- a/tools/lib/subcmd/pager.c
+++ b/tools/lib/subcmd/pager.c
@@ -3,6 +3,7 @@
3#include <stdio.h> 3#include <stdio.h>
4#include <string.h> 4#include <string.h>
5#include <signal.h> 5#include <signal.h>
6#include <sys/ioctl.h>
6#include "pager.h" 7#include "pager.h"
7#include "run-command.h" 8#include "run-command.h"
8#include "sigchain.h" 9#include "sigchain.h"
@@ -14,6 +15,7 @@
14 */ 15 */
15 16
16static int spawned_pager; 17static int spawned_pager;
18static int pager_columns;
17 19
18void pager_init(const char *pager_env) 20void pager_init(const char *pager_env)
19{ 21{
@@ -58,9 +60,12 @@ static void wait_for_pager_signal(int signo)
58void setup_pager(void) 60void setup_pager(void)
59{ 61{
60 const char *pager = getenv(subcmd_config.pager_env); 62 const char *pager = getenv(subcmd_config.pager_env);
63 struct winsize sz;
61 64
62 if (!isatty(1)) 65 if (!isatty(1))
63 return; 66 return;
67 if (ioctl(1, TIOCGWINSZ, &sz) == 0)
68 pager_columns = sz.ws_col;
64 if (!pager) 69 if (!pager)
65 pager = getenv("PAGER"); 70 pager = getenv("PAGER");
66 if (!(pager || access("/usr/bin/pager", X_OK))) 71 if (!(pager || access("/usr/bin/pager", X_OK)))
@@ -98,3 +103,14 @@ int pager_in_use(void)
98{ 103{
99 return spawned_pager; 104 return spawned_pager;
100} 105}
106
107int pager_get_columns(void)
108{
109 char *s;
110
111 s = getenv("COLUMNS");
112 if (s)
113 return atoi(s);
114
115 return (pager_columns ? pager_columns : 80) - 2;
116}
diff --git a/tools/lib/subcmd/pager.h b/tools/lib/subcmd/pager.h
index 8b83714ecf73..623f5542d05d 100644
--- a/tools/lib/subcmd/pager.h
+++ b/tools/lib/subcmd/pager.h
@@ -5,5 +5,6 @@ extern void pager_init(const char *pager_env);
5 5
6extern void setup_pager(void); 6extern void setup_pager(void);
7extern int pager_in_use(void); 7extern int pager_in_use(void);
8extern int pager_get_columns(void);
8 9
9#endif /* __SUBCMD_PAGER_H */ 10#endif /* __SUBCMD_PAGER_H */
diff --git a/tools/lib/traceevent/kbuffer-parse.c b/tools/lib/traceevent/kbuffer-parse.c
index 3bcada3ae05a..65984f1c2974 100644
--- a/tools/lib/traceevent/kbuffer-parse.c
+++ b/tools/lib/traceevent/kbuffer-parse.c
@@ -622,6 +622,7 @@ void *kbuffer_read_at_offset(struct kbuffer *kbuf, int offset,
622 622
623 /* Reset the buffer */ 623 /* Reset the buffer */
624 kbuffer_load_subbuffer(kbuf, kbuf->subbuffer); 624 kbuffer_load_subbuffer(kbuf, kbuf->subbuffer);
625 data = kbuffer_read_event(kbuf, ts);
625 626
626 while (kbuf->curr < offset) { 627 while (kbuf->curr < offset) {
627 data = kbuffer_next_event(kbuf, ts); 628 data = kbuffer_next_event(kbuf, ts);
diff --git a/tools/perf/Documentation/perf-list.txt b/tools/perf/Documentation/perf-list.txt
index a126e97a8114..41857cce5e86 100644
--- a/tools/perf/Documentation/perf-list.txt
+++ b/tools/perf/Documentation/perf-list.txt
@@ -8,13 +8,23 @@ perf-list - List all symbolic event types
8SYNOPSIS 8SYNOPSIS
9-------- 9--------
10[verse] 10[verse]
11'perf list' [hw|sw|cache|tracepoint|pmu|event_glob] 11'perf list' [--no-desc] [--long-desc] [hw|sw|cache|tracepoint|pmu|event_glob]
12 12
13DESCRIPTION 13DESCRIPTION
14----------- 14-----------
15This command displays the symbolic event types which can be selected in the 15This command displays the symbolic event types which can be selected in the
16various perf commands with the -e option. 16various perf commands with the -e option.
17 17
18OPTIONS
19-------
20--no-desc::
21Don't print descriptions.
22
23-v::
24--long-desc::
25Print longer event descriptions.
26
27
18[[EVENT_MODIFIERS]] 28[[EVENT_MODIFIERS]]
19EVENT MODIFIERS 29EVENT MODIFIERS
20--------------- 30---------------
diff --git a/tools/perf/Documentation/tips.txt b/tools/perf/Documentation/tips.txt
index 5950b5a24efd..8a6479c0eac9 100644
--- a/tools/perf/Documentation/tips.txt
+++ b/tools/perf/Documentation/tips.txt
@@ -28,3 +28,7 @@ To 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 30For hierarchical output, try: perf report --hierarchy
31Order by the overhead of source file name and line number: perf report -s srcline
32System-wide collection from all CPUs: perf record -a
33Show current config key-value pairs: perf config --list
34Show user configuration overrides: perf config --user --list
diff --git a/tools/perf/Makefile.perf b/tools/perf/Makefile.perf
index d710db16b963..982d6439bb07 100644
--- a/tools/perf/Makefile.perf
+++ b/tools/perf/Makefile.perf
@@ -144,6 +144,10 @@ $(call allow-override,LD,$(CROSS_COMPILE)ld)
144 144
145LD += $(EXTRA_LDFLAGS) 145LD += $(EXTRA_LDFLAGS)
146 146
147HOSTCC ?= gcc
148HOSTLD ?= ld
149HOSTAR ?= ar
150
147PKG_CONFIG = $(CROSS_COMPILE)pkg-config 151PKG_CONFIG = $(CROSS_COMPILE)pkg-config
148 152
149RM = rm -f 153RM = rm -f
@@ -345,8 +349,18 @@ strip: $(PROGRAMS) $(OUTPUT)perf
345PERF_IN := $(OUTPUT)perf-in.o 349PERF_IN := $(OUTPUT)perf-in.o
346 350
347export srctree OUTPUT RM CC LD AR CFLAGS V BISON FLEX AWK 351export srctree OUTPUT RM CC LD AR CFLAGS V BISON FLEX AWK
352export HOSTCC HOSTLD HOSTAR
348include $(srctree)/tools/build/Makefile.include 353include $(srctree)/tools/build/Makefile.include
349 354
355JEVENTS := $(OUTPUT)pmu-events/jevents
356JEVENTS_IN := $(OUTPUT)pmu-events/jevents-in.o
357
358PMU_EVENTS_IN := $(OUTPUT)pmu-events/pmu-events-in.o
359
360export JEVENTS
361
362build := -f $(srctree)/tools/build/Makefile.build dir=. obj
363
350$(PERF_IN): prepare FORCE 364$(PERF_IN): prepare FORCE
351 @(test -f ../../include/uapi/linux/perf_event.h && ( \ 365 @(test -f ../../include/uapi/linux/perf_event.h && ( \
352 (diff -B ../include/uapi/linux/perf_event.h ../../include/uapi/linux/perf_event.h >/dev/null) \ 366 (diff -B ../include/uapi/linux/perf_event.h ../../include/uapi/linux/perf_event.h >/dev/null) \
@@ -443,9 +457,18 @@ $(PERF_IN): prepare FORCE
443 || echo "Warning: tools/include/uapi/linux/mman.h differs from kernel" >&2 )) || true 457 || echo "Warning: tools/include/uapi/linux/mman.h differs from kernel" >&2 )) || true
444 $(Q)$(MAKE) $(build)=perf 458 $(Q)$(MAKE) $(build)=perf
445 459
446$(OUTPUT)perf: $(PERFLIBS) $(PERF_IN) $(LIBTRACEEVENT_DYNAMIC_LIST) 460$(JEVENTS_IN): FORCE
461 $(Q)$(MAKE) -f $(srctree)/tools/build/Makefile.build dir=pmu-events obj=jevents
462
463$(JEVENTS): $(JEVENTS_IN)
464 $(QUIET_LINK)$(HOSTCC) $(JEVENTS_IN) -o $@
465
466$(PMU_EVENTS_IN): $(JEVENTS) FORCE
467 $(Q)$(MAKE) -f $(srctree)/tools/build/Makefile.build dir=pmu-events obj=pmu-events
468
469$(OUTPUT)perf: $(PERFLIBS) $(PERF_IN) $(PMU_EVENTS_IN) $(LIBTRACEEVENT_DYNAMIC_LIST)
447 $(QUIET_LINK)$(CC) $(CFLAGS) $(LDFLAGS) $(LIBTRACEEVENT_DYNAMIC_LIST_LDFLAGS) \ 470 $(QUIET_LINK)$(CC) $(CFLAGS) $(LDFLAGS) $(LIBTRACEEVENT_DYNAMIC_LIST_LDFLAGS) \
448 $(PERF_IN) $(LIBS) -o $@ 471 $(PERF_IN) $(PMU_EVENTS_IN) $(LIBS) -o $@
449 472
450$(GTK_IN): fixdep FORCE 473$(GTK_IN): fixdep FORCE
451 $(Q)$(MAKE) $(build)=gtk 474 $(Q)$(MAKE) $(build)=gtk
@@ -474,6 +497,8 @@ perf.spec $(SCRIPTS) \
474ifneq ($(OUTPUT),) 497ifneq ($(OUTPUT),)
475%.o: $(OUTPUT)%.o 498%.o: $(OUTPUT)%.o
476 @echo " # Redirected target $@ => $(OUTPUT)$@" 499 @echo " # Redirected target $@ => $(OUTPUT)$@"
500pmu-events/%.o: $(OUTPUT)pmu-events/%.o
501 @echo " # Redirected target $@ => $(OUTPUT)$@"
477util/%.o: $(OUTPUT)util/%.o 502util/%.o: $(OUTPUT)util/%.o
478 @echo " # Redirected target $@ => $(OUTPUT)$@" 503 @echo " # Redirected target $@ => $(OUTPUT)$@"
479bench/%.o: $(OUTPUT)bench/%.o 504bench/%.o: $(OUTPUT)bench/%.o
@@ -729,10 +754,11 @@ clean:: $(LIBTRACEEVENT)-clean $(LIBAPI)-clean $(LIBBPF)-clean $(LIBSUBCMD)-clea
729 $(call QUIET_CLEAN, core-objs) $(RM) $(LIB_FILE) $(OUTPUT)perf-archive $(OUTPUT)perf-with-kcore $(LANG_BINDINGS) 754 $(call QUIET_CLEAN, core-objs) $(RM) $(LIB_FILE) $(OUTPUT)perf-archive $(OUTPUT)perf-with-kcore $(LANG_BINDINGS)
730 $(Q)find $(if $(OUTPUT),$(OUTPUT),.) -name '*.o' -delete -o -name '\.*.cmd' -delete -o -name '\.*.d' -delete 755 $(Q)find $(if $(OUTPUT),$(OUTPUT),.) -name '*.o' -delete -o -name '\.*.cmd' -delete -o -name '\.*.d' -delete
731 $(Q)$(RM) $(OUTPUT).config-detected 756 $(Q)$(RM) $(OUTPUT).config-detected
732 $(call QUIET_CLEAN, core-progs) $(RM) $(ALL_PROGRAMS) perf perf-read-vdso32 perf-read-vdsox32 757 $(call QUIET_CLEAN, core-progs) $(RM) $(ALL_PROGRAMS) perf perf-read-vdso32 perf-read-vdsox32 $(OUTPUT)pmu-events/jevents
733 $(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* \ 758 $(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* \
734 $(OUTPUT)util/intel-pt-decoder/inat-tables.c $(OUTPUT)fixdep \ 759 $(OUTPUT)util/intel-pt-decoder/inat-tables.c $(OUTPUT)fixdep \
735 $(OUTPUT)tests/llvm-src-{base,kbuild,prologue,relocation}.c 760 $(OUTPUT)tests/llvm-src-{base,kbuild,prologue,relocation}.c \
761 $(OUTPUT)pmu-events/pmu-events.c
736 $(QUIET_SUBDIR0)Documentation $(QUIET_SUBDIR1) clean 762 $(QUIET_SUBDIR0)Documentation $(QUIET_SUBDIR1) clean
737 $(python-clean) 763 $(python-clean)
738 764
diff --git a/tools/perf/arch/powerpc/util/header.c b/tools/perf/arch/powerpc/util/header.c
index f8ccee132867..9aaa6f5a9347 100644
--- a/tools/perf/arch/powerpc/util/header.c
+++ b/tools/perf/arch/powerpc/util/header.c
@@ -32,3 +32,14 @@ get_cpuid(char *buffer, size_t sz)
32 } 32 }
33 return -1; 33 return -1;
34} 34}
35
36char *
37get_cpuid_str(void)
38{
39 char *bufp;
40
41 if (asprintf(&bufp, "%.8lx", mfspr(SPRN_PVR)) < 0)
42 bufp = NULL;
43
44 return bufp;
45}
diff --git a/tools/perf/arch/powerpc/util/sym-handling.c b/tools/perf/arch/powerpc/util/sym-handling.c
index ed9d5d15d5b6..1030a6e504bb 100644
--- a/tools/perf/arch/powerpc/util/sym-handling.c
+++ b/tools/perf/arch/powerpc/util/sym-handling.c
@@ -82,7 +82,8 @@ void arch__fix_tev_from_maps(struct perf_probe_event *pev,
82 * 82 *
83 * In addition, we shouldn't specify an offset for kretprobes. 83 * In addition, we shouldn't specify an offset for kretprobes.
84 */ 84 */
85 if (pev->point.offset || pev->point.retprobe || !map || !sym) 85 if (pev->point.offset || (!pev->uprobes && pev->point.retprobe) ||
86 !map || !sym)
86 return; 87 return;
87 88
88 lep_offset = PPC64_LOCAL_ENTRY_OFFSET(sym->arch_sym); 89 lep_offset = PPC64_LOCAL_ENTRY_OFFSET(sym->arch_sym);
diff --git a/tools/perf/arch/x86/util/header.c b/tools/perf/arch/x86/util/header.c
index 146d12a1cec0..a74a48db26f5 100644
--- a/tools/perf/arch/x86/util/header.c
+++ b/tools/perf/arch/x86/util/header.c
@@ -19,8 +19,8 @@ cpuid(unsigned int op, unsigned int *a, unsigned int *b, unsigned int *c,
19 : "a" (op)); 19 : "a" (op));
20} 20}
21 21
22int 22static int
23get_cpuid(char *buffer, size_t sz) 23__get_cpuid(char *buffer, size_t sz, const char *fmt)
24{ 24{
25 unsigned int a, b, c, d, lvl; 25 unsigned int a, b, c, d, lvl;
26 int family = -1, model = -1, step = -1; 26 int family = -1, model = -1, step = -1;
@@ -48,7 +48,7 @@ get_cpuid(char *buffer, size_t sz)
48 if (family >= 0x6) 48 if (family >= 0x6)
49 model += ((a >> 16) & 0xf) << 4; 49 model += ((a >> 16) & 0xf) << 4;
50 } 50 }
51 nb = scnprintf(buffer, sz, "%s,%u,%u,%u$", vendor, family, model, step); 51 nb = scnprintf(buffer, sz, fmt, vendor, family, model, step);
52 52
53 /* look for end marker to ensure the entire data fit */ 53 /* look for end marker to ensure the entire data fit */
54 if (strchr(buffer, '$')) { 54 if (strchr(buffer, '$')) {
@@ -57,3 +57,21 @@ get_cpuid(char *buffer, size_t sz)
57 } 57 }
58 return -1; 58 return -1;
59} 59}
60
61int
62get_cpuid(char *buffer, size_t sz)
63{
64 return __get_cpuid(buffer, sz, "%s,%u,%u,%u$");
65}
66
67char *
68get_cpuid_str(void)
69{
70 char *buf = malloc(128);
71
72 if (__get_cpuid(buf, 128, "%s-%u-%X$") < 0) {
73 free(buf);
74 return NULL;
75 }
76 return buf;
77}
diff --git a/tools/perf/builtin-list.c b/tools/perf/builtin-list.c
index 88ee419e5189..ba9322ff858b 100644
--- a/tools/perf/builtin-list.c
+++ b/tools/perf/builtin-list.c
@@ -16,16 +16,23 @@
16#include "util/pmu.h" 16#include "util/pmu.h"
17#include <subcmd/parse-options.h> 17#include <subcmd/parse-options.h>
18 18
19static bool desc_flag = true;
20
19int cmd_list(int argc, const char **argv, const char *prefix __maybe_unused) 21int cmd_list(int argc, const char **argv, const char *prefix __maybe_unused)
20{ 22{
21 int i; 23 int i;
22 bool raw_dump = false; 24 bool raw_dump = false;
25 bool long_desc_flag = false;
23 struct option list_options[] = { 26 struct option list_options[] = {
24 OPT_BOOLEAN(0, "raw-dump", &raw_dump, "Dump raw events"), 27 OPT_BOOLEAN(0, "raw-dump", &raw_dump, "Dump raw events"),
28 OPT_BOOLEAN('d', "desc", &desc_flag,
29 "Print extra event descriptions. --no-desc to not print."),
30 OPT_BOOLEAN('v', "long-desc", &long_desc_flag,
31 "Print longer event descriptions."),
25 OPT_END() 32 OPT_END()
26 }; 33 };
27 const char * const list_usage[] = { 34 const char * const list_usage[] = {
28 "perf list [hw|sw|cache|tracepoint|pmu|sdt|event_glob]", 35 "perf list [<options>] [hw|sw|cache|tracepoint|pmu|sdt|event_glob]",
29 NULL 36 NULL
30 }; 37 };
31 38
@@ -40,7 +47,7 @@ int cmd_list(int argc, const char **argv, const char *prefix __maybe_unused)
40 printf("\nList of pre-defined events (to be used in -e):\n\n"); 47 printf("\nList of pre-defined events (to be used in -e):\n\n");
41 48
42 if (argc == 0) { 49 if (argc == 0) {
43 print_events(NULL, raw_dump); 50 print_events(NULL, raw_dump, !desc_flag, long_desc_flag);
44 return 0; 51 return 0;
45 } 52 }
46 53
@@ -61,14 +68,16 @@ int cmd_list(int argc, const char **argv, const char *prefix __maybe_unused)
61 strcmp(argv[i], "hwcache") == 0) 68 strcmp(argv[i], "hwcache") == 0)
62 print_hwcache_events(NULL, raw_dump); 69 print_hwcache_events(NULL, raw_dump);
63 else if (strcmp(argv[i], "pmu") == 0) 70 else if (strcmp(argv[i], "pmu") == 0)
64 print_pmu_events(NULL, raw_dump); 71 print_pmu_events(NULL, raw_dump, !desc_flag,
72 long_desc_flag);
65 else if (strcmp(argv[i], "sdt") == 0) 73 else if (strcmp(argv[i], "sdt") == 0)
66 print_sdt_events(NULL, NULL, raw_dump); 74 print_sdt_events(NULL, NULL, raw_dump);
67 else if ((sep = strchr(argv[i], ':')) != NULL) { 75 else if ((sep = strchr(argv[i], ':')) != NULL) {
68 int sep_idx; 76 int sep_idx;
69 77
70 if (sep == NULL) { 78 if (sep == NULL) {
71 print_events(argv[i], raw_dump); 79 print_events(argv[i], raw_dump, !desc_flag,
80 long_desc_flag);
72 continue; 81 continue;
73 } 82 }
74 sep_idx = sep - argv[i]; 83 sep_idx = sep - argv[i];
@@ -90,7 +99,8 @@ int cmd_list(int argc, const char **argv, const char *prefix __maybe_unused)
90 print_symbol_events(s, PERF_TYPE_SOFTWARE, 99 print_symbol_events(s, PERF_TYPE_SOFTWARE,
91 event_symbols_sw, PERF_COUNT_SW_MAX, raw_dump); 100 event_symbols_sw, PERF_COUNT_SW_MAX, raw_dump);
92 print_hwcache_events(s, raw_dump); 101 print_hwcache_events(s, raw_dump);
93 print_pmu_events(s, raw_dump); 102 print_pmu_events(s, raw_dump, !desc_flag,
103 long_desc_flag);
94 print_tracepoint_events(NULL, s, raw_dump); 104 print_tracepoint_events(NULL, s, raw_dump);
95 print_sdt_events(NULL, s, raw_dump); 105 print_sdt_events(NULL, s, raw_dump);
96 free(s); 106 free(s);
diff --git a/tools/perf/pmu-events/Build b/tools/perf/pmu-events/Build
new file mode 100644
index 000000000000..9213a1273697
--- /dev/null
+++ b/tools/perf/pmu-events/Build
@@ -0,0 +1,13 @@
1hostprogs := jevents
2
3jevents-y += json.o jsmn.o jevents.o
4pmu-events-y += pmu-events.o
5JDIR = pmu-events/arch/$(ARCH)
6JSON = $(shell [ -d $(JDIR) ] && \
7 find $(JDIR) -name '*.json' -o -name 'mapfile.csv')
8#
9# Locate/process JSON files in pmu-events/arch/
10# directory and create tables in pmu-events.c.
11#
12$(OUTPUT)pmu-events/pmu-events.c: $(JSON) $(JEVENTS)
13 $(Q)$(call echo-cmd,gen)$(JEVENTS) $(ARCH) pmu-events/arch $(OUTPUT)pmu-events/pmu-events.c $(V)
diff --git a/tools/perf/pmu-events/README b/tools/perf/pmu-events/README
new file mode 100644
index 000000000000..1408ade0d773
--- /dev/null
+++ b/tools/perf/pmu-events/README
@@ -0,0 +1,147 @@
1
2The contents of this directory allow users to specify PMU events in their
3CPUs by their symbolic names rather than raw event codes (see example below).
4
5The main program in this directory, is the 'jevents', which is built and
6executed _BEFORE_ the perf binary itself is built.
7
8The 'jevents' program tries to locate and process JSON files in the directory
9tree tools/perf/pmu-events/arch/foo.
10
11 - Regular files with '.json' extension in the name are assumed to be
12 JSON files, each of which describes a set of PMU events.
13
14 - Regular files with basename starting with 'mapfile.csv' are assumed
15 to be a CSV file that maps a specific CPU to its set of PMU events.
16 (see below for mapfile format)
17
18 - Directories are traversed, but all other files are ignored.
19
20The PMU events supported by a CPU model are expected to grouped into topics
21such as Pipelining, Cache, Memory, Floating-point etc. All events for a topic
22should be placed in a separate JSON file - where the file name identifies
23the topic. Eg: "Floating-point.json".
24
25All the topic JSON files for a CPU model/family should be in a separate
26sub directory. Thus for the Silvermont X86 CPU:
27
28 $ ls tools/perf/pmu-events/arch/x86/Silvermont_core
29 Cache.json Memory.json Virtual-Memory.json
30 Frontend.json Pipeline.json
31
32Using the JSON files and the mapfile, 'jevents' generates the C source file,
33'pmu-events.c', which encodes the two sets of tables:
34
35 - Set of 'PMU events tables' for all known CPUs in the architecture,
36 (one table like the following, per JSON file; table name 'pme_power8'
37 is derived from JSON file name, 'power8.json').
38
39 struct pmu_event pme_power8[] = {
40
41 ...
42
43 {
44 .name = "pm_1plus_ppc_cmpl",
45 .event = "event=0x100f2",
46 .desc = "1 or more ppc insts finished,",
47 },
48
49 ...
50 }
51
52 - A 'mapping table' that maps each CPU of the architecture, to its
53 'PMU events table'
54
55 struct pmu_events_map pmu_events_map[] = {
56 {
57 .cpuid = "004b0000",
58 .version = "1",
59 .type = "core",
60 .table = pme_power8
61 },
62 ...
63
64 };
65
66After the 'pmu-events.c' is generated, it is compiled and the resulting
67'pmu-events.o' is added to 'libperf.a' which is then used to build perf.
68
69NOTES:
70 1. Several CPUs can support same set of events and hence use a common
71 JSON file. Hence several entries in the pmu_events_map[] could map
72 to a single 'PMU events table'.
73
74 2. The 'pmu-events.h' has an extern declaration for the mapping table
75 and the generated 'pmu-events.c' defines this table.
76
77 3. _All_ known CPU tables for architecture are included in the perf
78 binary.
79
80At run time, perf determines the actual CPU it is running on, finds the
81matching events table and builds aliases for those events. This allows
82users to specify events by their name:
83
84 $ perf stat -e pm_1plus_ppc_cmpl sleep 1
85
86where 'pm_1plus_ppc_cmpl' is a Power8 PMU event.
87
88In case of errors when processing files in the tools/perf/pmu-events/arch
89directory, 'jevents' tries to create an empty mapping file to allow the perf
90build to succeed even if the PMU event aliases cannot be used.
91
92However some errors in processing may cause the perf build to fail.
93
94Mapfile format
95===============
96
97The mapfile enables multiple CPU models to share a single set of PMU events.
98It is required even if such mapping is 1:1.
99
100The mapfile.csv format is expected to be:
101
102 Header line
103 CPUID,Version,Dir/path/name,Type
104
105where:
106
107 Comma:
108 is the required field delimiter (i.e other fields cannot
109 have commas within them).
110
111 Comments:
112 Lines in which the first character is either '\n' or '#'
113 are ignored.
114
115 Header line
116 The header line is the first line in the file, which is
117 always _IGNORED_. It can empty.
118
119 CPUID:
120 CPUID is an arch-specific char string, that can be used
121 to identify CPU (and associate it with a set of PMU events
122 it supports). Multiple CPUIDS can point to the same
123 File/path/name.json.
124
125 Example:
126 CPUID == 'GenuineIntel-6-2E' (on x86).
127 CPUID == '004b0100' (PVR value in Powerpc)
128 Version:
129 is the Version of the mapfile.
130
131 Dir/path/name:
132 is the pathname to the directory containing the CPU's JSON
133 files, relative to the directory containing the mapfile.csv
134
135 Type:
136 indicates whether the events or "core" or "uncore" events.
137
138
139 Eg:
140
141 $ grep Silvermont tools/perf/pmu-events/arch/x86/mapfile.csv
142 GenuineIntel-6-37,V13,Silvermont_core,core
143 GenuineIntel-6-4D,V13,Silvermont_core,core
144 GenuineIntel-6-4C,V13,Silvermont_core,core
145
146 i.e the three CPU models use the JSON files (i.e PMU events) listed
147 in the directory 'tools/perf/pmu-events/arch/x86/Silvermont_core'.
diff --git a/tools/perf/pmu-events/jevents.c b/tools/perf/pmu-events/jevents.c
new file mode 100644
index 000000000000..41611d7f9873
--- /dev/null
+++ b/tools/perf/pmu-events/jevents.c
@@ -0,0 +1,814 @@
1#define _XOPEN_SOURCE 500 /* needed for nftw() */
2#define _GNU_SOURCE /* needed for asprintf() */
3
4/* Parse event JSON files */
5
6/*
7 * Copyright (c) 2014, Intel Corporation
8 * All rights reserved.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions are met:
12 *
13 * 1. Redistributions of source code must retain the above copyright notice,
14 * this list of conditions and the following disclaimer.
15 *
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24 * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
25 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
26 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
27 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
29 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
31 * OF THE POSSIBILITY OF SUCH DAMAGE.
32*/
33
34#include <stdio.h>
35#include <stdlib.h>
36#include <errno.h>
37#include <string.h>
38#include <ctype.h>
39#include <unistd.h>
40#include <stdarg.h>
41#include <libgen.h>
42#include <dirent.h>
43#include <sys/time.h> /* getrlimit */
44#include <sys/resource.h> /* getrlimit */
45#include <ftw.h>
46#include <sys/stat.h>
47#include "jsmn.h"
48#include "json.h"
49#include "jevents.h"
50
51#ifndef __maybe_unused
52#define __maybe_unused __attribute__((unused))
53#endif
54
55int verbose;
56char *prog;
57
58int eprintf(int level, int var, const char *fmt, ...)
59{
60
61 int ret;
62 va_list args;
63
64 if (var < level)
65 return 0;
66
67 va_start(args, fmt);
68
69 ret = vfprintf(stderr, fmt, args);
70
71 va_end(args);
72
73 return ret;
74}
75
76__attribute__((weak)) char *get_cpu_str(void)
77{
78 return NULL;
79}
80
81static void addfield(char *map, char **dst, const char *sep,
82 const char *a, jsmntok_t *bt)
83{
84 unsigned int len = strlen(a) + 1 + strlen(sep);
85 int olen = *dst ? strlen(*dst) : 0;
86 int blen = bt ? json_len(bt) : 0;
87 char *out;
88
89 out = realloc(*dst, len + olen + blen);
90 if (!out) {
91 /* Don't add field in this case */
92 return;
93 }
94 *dst = out;
95
96 if (!olen)
97 *(*dst) = 0;
98 else
99 strcat(*dst, sep);
100 strcat(*dst, a);
101 if (bt)
102 strncat(*dst, map + bt->start, blen);
103}
104
105static void fixname(char *s)
106{
107 for (; *s; s++)
108 *s = tolower(*s);
109}
110
111static void fixdesc(char *s)
112{
113 char *e = s + strlen(s);
114
115 /* Remove trailing dots that look ugly in perf list */
116 --e;
117 while (e >= s && isspace(*e))
118 --e;
119 if (*e == '.')
120 *e = 0;
121}
122
123static struct msrmap {
124 const char *num;
125 const char *pname;
126} msrmap[] = {
127 { "0x3F6", "ldlat=" },
128 { "0x1A6", "offcore_rsp=" },
129 { "0x1A7", "offcore_rsp=" },
130 { "0x3F7", "frontend=" },
131 { NULL, NULL }
132};
133
134static struct field {
135 const char *field;
136 const char *kernel;
137} fields[] = {
138 { "EventCode", "event=" },
139 { "UMask", "umask=" },
140 { "CounterMask", "cmask=" },
141 { "Invert", "inv=" },
142 { "AnyThread", "any=" },
143 { "EdgeDetect", "edge=" },
144 { "SampleAfterValue", "period=" },
145 { NULL, NULL }
146};
147
148static void cut_comma(char *map, jsmntok_t *newval)
149{
150 int i;
151
152 /* Cut off everything after comma */
153 for (i = newval->start; i < newval->end; i++) {
154 if (map[i] == ',')
155 newval->end = i;
156 }
157}
158
159static int match_field(char *map, jsmntok_t *field, int nz,
160 char **event, jsmntok_t *val)
161{
162 struct field *f;
163 jsmntok_t newval = *val;
164
165 for (f = fields; f->field; f++)
166 if (json_streq(map, field, f->field) && nz) {
167 cut_comma(map, &newval);
168 addfield(map, event, ",", f->kernel, &newval);
169 return 1;
170 }
171 return 0;
172}
173
174static struct msrmap *lookup_msr(char *map, jsmntok_t *val)
175{
176 jsmntok_t newval = *val;
177 static bool warned;
178 int i;
179
180 cut_comma(map, &newval);
181 for (i = 0; msrmap[i].num; i++)
182 if (json_streq(map, &newval, msrmap[i].num))
183 return &msrmap[i];
184 if (!warned) {
185 warned = true;
186 pr_err("%s: Unknown MSR in event file %.*s\n", prog,
187 json_len(val), map + val->start);
188 }
189 return NULL;
190}
191
192#define EXPECT(e, t, m) do { if (!(e)) { \
193 jsmntok_t *loc = (t); \
194 if (!(t)->start && (t) > tokens) \
195 loc = (t) - 1; \
196 pr_err("%s:%d: " m ", got %s\n", fn, \
197 json_line(map, loc), \
198 json_name(t)); \
199 goto out_free; \
200} } while (0)
201
202#define TOPIC_DEPTH 256
203static char *topic_array[TOPIC_DEPTH];
204static int topic_level;
205
206static char *get_topic(void)
207{
208 char *tp_old, *tp = NULL;
209 int i;
210
211 for (i = 0; i < topic_level + 1; i++) {
212 int n;
213
214 tp_old = tp;
215 n = asprintf(&tp, "%s%s", tp ?: "", topic_array[i]);
216 if (n < 0) {
217 pr_info("%s: asprintf() error %s\n", prog);
218 return NULL;
219 }
220 free(tp_old);
221 }
222
223 for (i = 0; i < (int) strlen(tp); i++) {
224 char c = tp[i];
225
226 if (c == '-')
227 tp[i] = ' ';
228 else if (c == '.') {
229 tp[i] = '\0';
230 break;
231 }
232 }
233
234 return tp;
235}
236
237static int add_topic(int level, char *bname)
238{
239 char *topic;
240
241 level -= 2;
242
243 if (level >= TOPIC_DEPTH)
244 return -EINVAL;
245
246 topic = strdup(bname);
247 if (!topic) {
248 pr_info("%s: strdup() error %s for file %s\n", prog,
249 strerror(errno), bname);
250 return -ENOMEM;
251 }
252
253 free(topic_array[topic_level]);
254 topic_array[topic_level] = topic;
255 topic_level = level;
256 return 0;
257}
258
259struct perf_entry_data {
260 FILE *outfp;
261 char *topic;
262};
263
264static int close_table;
265
266static void print_events_table_prefix(FILE *fp, const char *tblname)
267{
268 fprintf(fp, "struct pmu_event %s[] = {\n", tblname);
269 close_table = 1;
270}
271
272static int print_events_table_entry(void *data, char *name, char *event,
273 char *desc, char *long_desc)
274{
275 struct perf_entry_data *pd = data;
276 FILE *outfp = pd->outfp;
277 char *topic = pd->topic;
278
279 /*
280 * TODO: Remove formatting chars after debugging to reduce
281 * string lengths.
282 */
283 fprintf(outfp, "{\n");
284
285 fprintf(outfp, "\t.name = \"%s\",\n", name);
286 fprintf(outfp, "\t.event = \"%s\",\n", event);
287 fprintf(outfp, "\t.desc = \"%s\",\n", desc);
288 fprintf(outfp, "\t.topic = \"%s\",\n", topic);
289 if (long_desc && long_desc[0])
290 fprintf(outfp, "\t.long_desc = \"%s\",\n", long_desc);
291
292 fprintf(outfp, "},\n");
293
294 return 0;
295}
296
297static void print_events_table_suffix(FILE *outfp)
298{
299 fprintf(outfp, "{\n");
300
301 fprintf(outfp, "\t.name = 0,\n");
302 fprintf(outfp, "\t.event = 0,\n");
303 fprintf(outfp, "\t.desc = 0,\n");
304
305 fprintf(outfp, "},\n");
306 fprintf(outfp, "};\n");
307 close_table = 0;
308}
309
310static struct fixed {
311 const char *name;
312 const char *event;
313} fixed[] = {
314 { "inst_retired.any", "event=0xc0" },
315 { "inst_retired.any_p", "event=0xc0" },
316 { "cpu_clk_unhalted.ref", "event=0x0,umask=0x03" },
317 { "cpu_clk_unhalted.thread", "event=0x3c" },
318 { "cpu_clk_unhalted.thread_any", "event=0x3c,any=1" },
319 { NULL, NULL},
320};
321
322/*
323 * Handle different fixed counter encodings between JSON and perf.
324 */
325static char *real_event(const char *name, char *event)
326{
327 int i;
328
329 for (i = 0; fixed[i].name; i++)
330 if (!strcasecmp(name, fixed[i].name))
331 return (char *)fixed[i].event;
332 return event;
333}
334
335/* Call func with each event in the json file */
336int json_events(const char *fn,
337 int (*func)(void *data, char *name, char *event, char *desc,
338 char *long_desc),
339 void *data)
340{
341 int err = -EIO;
342 size_t size;
343 jsmntok_t *tokens, *tok;
344 int i, j, len;
345 char *map;
346
347 if (!fn)
348 return -ENOENT;
349
350 tokens = parse_json(fn, &map, &size, &len);
351 if (!tokens)
352 return -EIO;
353 EXPECT(tokens->type == JSMN_ARRAY, tokens, "expected top level array");
354 tok = tokens + 1;
355 for (i = 0; i < tokens->size; i++) {
356 char *event = NULL, *desc = NULL, *name = NULL;
357 char *long_desc = NULL;
358 char *extra_desc = NULL;
359 struct msrmap *msr = NULL;
360 jsmntok_t *msrval = NULL;
361 jsmntok_t *precise = NULL;
362 jsmntok_t *obj = tok++;
363
364 EXPECT(obj->type == JSMN_OBJECT, obj, "expected object");
365 for (j = 0; j < obj->size; j += 2) {
366 jsmntok_t *field, *val;
367 int nz;
368
369 field = tok + j;
370 EXPECT(field->type == JSMN_STRING, tok + j,
371 "Expected field name");
372 val = tok + j + 1;
373 EXPECT(val->type == JSMN_STRING, tok + j + 1,
374 "Expected string value");
375
376 nz = !json_streq(map, val, "0");
377 if (match_field(map, field, nz, &event, val)) {
378 /* ok */
379 } else if (json_streq(map, field, "EventName")) {
380 addfield(map, &name, "", "", val);
381 } else if (json_streq(map, field, "BriefDescription")) {
382 addfield(map, &desc, "", "", val);
383 fixdesc(desc);
384 } else if (json_streq(map, field,
385 "PublicDescription")) {
386 addfield(map, &long_desc, "", "", val);
387 fixdesc(long_desc);
388 } else if (json_streq(map, field, "PEBS") && nz) {
389 precise = val;
390 } else if (json_streq(map, field, "MSRIndex") && nz) {
391 msr = lookup_msr(map, val);
392 } else if (json_streq(map, field, "MSRValue")) {
393 msrval = val;
394 } else if (json_streq(map, field, "Errata") &&
395 !json_streq(map, val, "null")) {
396 addfield(map, &extra_desc, ". ",
397 " Spec update: ", val);
398 } else if (json_streq(map, field, "Data_LA") && nz) {
399 addfield(map, &extra_desc, ". ",
400 " Supports address when precise",
401 NULL);
402 }
403 /* ignore unknown fields */
404 }
405 if (precise && desc && !strstr(desc, "(Precise Event)")) {
406 if (json_streq(map, precise, "2"))
407 addfield(map, &extra_desc, " ",
408 "(Must be precise)", NULL);
409 else
410 addfield(map, &extra_desc, " ",
411 "(Precise event)", NULL);
412 }
413 if (desc && extra_desc)
414 addfield(map, &desc, " ", extra_desc, NULL);
415 if (long_desc && extra_desc)
416 addfield(map, &long_desc, " ", extra_desc, NULL);
417 if (msr != NULL)
418 addfield(map, &event, ",", msr->pname, msrval);
419 fixname(name);
420
421 err = func(data, name, real_event(name, event), desc, long_desc);
422 free(event);
423 free(desc);
424 free(name);
425 free(long_desc);
426 free(extra_desc);
427 if (err)
428 break;
429 tok += j;
430 }
431 EXPECT(tok - tokens == len, tok, "unexpected objects at end");
432 err = 0;
433out_free:
434 free_json(map, size, tokens);
435 return err;
436}
437
438static char *file_name_to_table_name(char *fname)
439{
440 unsigned int i;
441 int n;
442 int c;
443 char *tblname;
444
445 /*
446 * Ensure tablename starts with alphabetic character.
447 * Derive rest of table name from basename of the JSON file,
448 * replacing hyphens and stripping out .json suffix.
449 */
450 n = asprintf(&tblname, "pme_%s", basename(fname));
451 if (n < 0) {
452 pr_info("%s: asprintf() error %s for file %s\n", prog,
453 strerror(errno), fname);
454 return NULL;
455 }
456
457 for (i = 0; i < strlen(tblname); i++) {
458 c = tblname[i];
459
460 if (c == '-')
461 tblname[i] = '_';
462 else if (c == '.') {
463 tblname[i] = '\0';
464 break;
465 } else if (!isalnum(c) && c != '_') {
466 pr_err("%s: Invalid character '%c' in file name %s\n",
467 prog, c, basename(fname));
468 free(tblname);
469 tblname = NULL;
470 break;
471 }
472 }
473
474 return tblname;
475}
476
477static void print_mapping_table_prefix(FILE *outfp)
478{
479 fprintf(outfp, "struct pmu_events_map pmu_events_map[] = {\n");
480}
481
482static void print_mapping_table_suffix(FILE *outfp)
483{
484 /*
485 * Print the terminating, NULL entry.
486 */
487 fprintf(outfp, "{\n");
488 fprintf(outfp, "\t.cpuid = 0,\n");
489 fprintf(outfp, "\t.version = 0,\n");
490 fprintf(outfp, "\t.type = 0,\n");
491 fprintf(outfp, "\t.table = 0,\n");
492 fprintf(outfp, "},\n");
493
494 /* and finally, the closing curly bracket for the struct */
495 fprintf(outfp, "};\n");
496}
497
498static int process_mapfile(FILE *outfp, char *fpath)
499{
500 int n = 16384;
501 FILE *mapfp;
502 char *save = NULL;
503 char *line, *p;
504 int line_num;
505 char *tblname;
506
507 pr_info("%s: Processing mapfile %s\n", prog, fpath);
508
509 line = malloc(n);
510 if (!line)
511 return -1;
512
513 mapfp = fopen(fpath, "r");
514 if (!mapfp) {
515 pr_info("%s: Error %s opening %s\n", prog, strerror(errno),
516 fpath);
517 return -1;
518 }
519
520 print_mapping_table_prefix(outfp);
521
522 /* Skip first line (header) */
523 p = fgets(line, n, mapfp);
524 if (!p)
525 goto out;
526
527 line_num = 1;
528 while (1) {
529 char *cpuid, *version, *type, *fname;
530
531 line_num++;
532 p = fgets(line, n, mapfp);
533 if (!p)
534 break;
535
536 if (line[0] == '#' || line[0] == '\n')
537 continue;
538
539 if (line[strlen(line)-1] != '\n') {
540 /* TODO Deal with lines longer than 16K */
541 pr_info("%s: Mapfile %s: line %d too long, aborting\n",
542 prog, fpath, line_num);
543 return -1;
544 }
545 line[strlen(line)-1] = '\0';
546
547 cpuid = strtok_r(p, ",", &save);
548 version = strtok_r(NULL, ",", &save);
549 fname = strtok_r(NULL, ",", &save);
550 type = strtok_r(NULL, ",", &save);
551
552 tblname = file_name_to_table_name(fname);
553 fprintf(outfp, "{\n");
554 fprintf(outfp, "\t.cpuid = \"%s\",\n", cpuid);
555 fprintf(outfp, "\t.version = \"%s\",\n", version);
556 fprintf(outfp, "\t.type = \"%s\",\n", type);
557
558 /*
559 * CHECK: We can't use the type (eg "core") field in the
560 * table name. For us to do that, we need to somehow tweak
561 * the other caller of file_name_to_table(), process_json()
562 * to determine the type. process_json() file has no way
563 * of knowing these are "core" events unless file name has
564 * core in it. If filename has core in it, we can safely
565 * ignore the type field here also.
566 */
567 fprintf(outfp, "\t.table = %s\n", tblname);
568 fprintf(outfp, "},\n");
569 }
570
571out:
572 print_mapping_table_suffix(outfp);
573 return 0;
574}
575
576/*
577 * If we fail to locate/process JSON and map files, create a NULL mapping
578 * table. This would at least allow perf to build even if we can't find/use
579 * the aliases.
580 */
581static void create_empty_mapping(const char *output_file)
582{
583 FILE *outfp;
584
585 pr_info("%s: Creating empty pmu_events_map[] table\n", prog);
586
587 /* Truncate file to clear any partial writes to it */
588 outfp = fopen(output_file, "w");
589 if (!outfp) {
590 perror("fopen()");
591 _Exit(1);
592 }
593
594 fprintf(outfp, "#include \"../../pmu-events/pmu-events.h\"\n");
595 print_mapping_table_prefix(outfp);
596 print_mapping_table_suffix(outfp);
597 fclose(outfp);
598}
599
600static int get_maxfds(void)
601{
602 struct rlimit rlim;
603
604 if (getrlimit(RLIMIT_NOFILE, &rlim) == 0)
605 return min((int)rlim.rlim_max / 2, 512);
606
607 return 512;
608}
609
610/*
611 * nftw() doesn't let us pass an argument to the processing function,
612 * so use a global variables.
613 */
614static FILE *eventsfp;
615static char *mapfile;
616
617static int process_one_file(const char *fpath, const struct stat *sb,
618 int typeflag, struct FTW *ftwbuf)
619{
620 char *tblname, *bname = (char *) fpath + ftwbuf->base;
621 int is_dir = typeflag == FTW_D;
622 int is_file = typeflag == FTW_F;
623 int level = ftwbuf->level;
624 int err = 0;
625
626 pr_debug("%s %d %7jd %-20s %s\n",
627 is_file ? "f" : is_dir ? "d" : "x",
628 level, sb->st_size, bname, fpath);
629
630 /* base dir */
631 if (level == 0)
632 return 0;
633
634 /* model directory, reset topic */
635 if (level == 1 && is_dir) {
636 if (close_table)
637 print_events_table_suffix(eventsfp);
638
639 /*
640 * Drop file name suffix. Replace hyphens with underscores.
641 * Fail if file name contains any alphanum characters besides
642 * underscores.
643 */
644 tblname = file_name_to_table_name(bname);
645 if (!tblname) {
646 pr_info("%s: Error determining table name for %s\n", prog,
647 bname);
648 return -1;
649 }
650
651 print_events_table_prefix(eventsfp, tblname);
652 return 0;
653 }
654
655 /*
656 * Save the mapfile name for now. We will process mapfile
657 * after processing all JSON files (so we can write out the
658 * mapping table after all PMU events tables).
659 *
660 * TODO: Allow for multiple mapfiles? Punt for now.
661 */
662 if (level == 1 && is_file) {
663 if (!strncmp(bname, "mapfile.csv", 11)) {
664 if (mapfile) {
665 pr_info("%s: Many mapfiles? Using %s, ignoring %s\n",
666 prog, mapfile, fpath);
667 } else {
668 mapfile = strdup(fpath);
669 }
670 return 0;
671 }
672
673 pr_info("%s: Ignoring file %s\n", prog, fpath);
674 return 0;
675 }
676
677 /*
678 * If the file name does not have a .json extension,
679 * ignore it. It could be a readme.txt for instance.
680 */
681 if (is_file) {
682 char *suffix = bname + strlen(bname) - 5;
683
684 if (strncmp(suffix, ".json", 5)) {
685 pr_info("%s: Ignoring file without .json suffix %s\n", prog,
686 fpath);
687 return 0;
688 }
689 }
690
691 if (level > 1 && add_topic(level, bname))
692 return -ENOMEM;
693
694 /*
695 * Assume all other files are JSON files.
696 *
697 * If mapfile refers to 'power7_core.json', we create a table
698 * named 'power7_core'. Any inconsistencies between the mapfile
699 * and directory tree could result in build failure due to table
700 * names not being found.
701 *
702 * Atleast for now, be strict with processing JSON file names.
703 * i.e. if JSON file name cannot be mapped to C-style table name,
704 * fail.
705 */
706 if (is_file) {
707 struct perf_entry_data data = {
708 .topic = get_topic(),
709 .outfp = eventsfp,
710 };
711
712 err = json_events(fpath, print_events_table_entry, &data);
713
714 free(data.topic);
715 }
716
717 return err;
718}
719
720#ifndef PATH_MAX
721#define PATH_MAX 4096
722#endif
723
724/*
725 * Starting in directory 'start_dirname', find the "mapfile.csv" and
726 * the set of JSON files for the architecture 'arch'.
727 *
728 * From each JSON file, create a C-style "PMU events table" from the
729 * JSON file (see struct pmu_event).
730 *
731 * From the mapfile, create a mapping between the CPU revisions and
732 * PMU event tables (see struct pmu_events_map).
733 *
734 * Write out the PMU events tables and the mapping table to pmu-event.c.
735 *
736 * If unable to process the JSON or arch files, create an empty mapping
737 * table so we can continue to build/use perf even if we cannot use the
738 * PMU event aliases.
739 */
740int main(int argc, char *argv[])
741{
742 int rc;
743 int maxfds;
744 char ldirname[PATH_MAX];
745
746 const char *arch;
747 const char *output_file;
748 const char *start_dirname;
749
750 prog = basename(argv[0]);
751 if (argc < 4) {
752 pr_err("Usage: %s <arch> <starting_dir> <output_file>\n", prog);
753 return 1;
754 }
755
756 arch = argv[1];
757 start_dirname = argv[2];
758 output_file = argv[3];
759
760 if (argc > 4)
761 verbose = atoi(argv[4]);
762
763 eventsfp = fopen(output_file, "w");
764 if (!eventsfp) {
765 pr_err("%s Unable to create required file %s (%s)\n",
766 prog, output_file, strerror(errno));
767 return 2;
768 }
769
770 /* Include pmu-events.h first */
771 fprintf(eventsfp, "#include \"../../pmu-events/pmu-events.h\"\n");
772
773 sprintf(ldirname, "%s/%s", start_dirname, arch);
774
775 /*
776 * The mapfile allows multiple CPUids to point to the same JSON file,
777 * so, not sure if there is a need for symlinks within the pmu-events
778 * directory.
779 *
780 * For now, treat symlinks of JSON files as regular files and create
781 * separate tables for each symlink (presumably, each symlink refers
782 * to specific version of the CPU).
783 */
784
785 maxfds = get_maxfds();
786 mapfile = NULL;
787 rc = nftw(ldirname, process_one_file, maxfds, 0);
788 if (rc && verbose) {
789 pr_info("%s: Error walking file tree %s\n", prog, ldirname);
790 goto empty_map;
791 } else if (rc) {
792 goto empty_map;
793 }
794
795 if (close_table)
796 print_events_table_suffix(eventsfp);
797
798 if (!mapfile) {
799 pr_info("%s: No CPU->JSON mapping?\n", prog);
800 goto empty_map;
801 }
802
803 if (process_mapfile(eventsfp, mapfile)) {
804 pr_info("%s: Error processing mapfile %s\n", prog, mapfile);
805 goto empty_map;
806 }
807
808 return 0;
809
810empty_map:
811 fclose(eventsfp);
812 create_empty_mapping(output_file);
813 return 0;
814}
diff --git a/tools/perf/pmu-events/jevents.h b/tools/perf/pmu-events/jevents.h
new file mode 100644
index 000000000000..b0eb2744b498
--- /dev/null
+++ b/tools/perf/pmu-events/jevents.h
@@ -0,0 +1,18 @@
1#ifndef JEVENTS_H
2#define JEVENTS_H 1
3
4int json_events(const char *fn,
5 int (*func)(void *data, char *name, char *event, char *desc,
6 char *long_desc),
7 void *data);
8char *get_cpu_str(void);
9
10#ifndef min
11#define min(x, y) ({ \
12 typeof(x) _min1 = (x); \
13 typeof(y) _min2 = (y); \
14 (void) (&_min1 == &_min2); \
15 _min1 < _min2 ? _min1 : _min2; })
16#endif
17
18#endif
diff --git a/tools/perf/pmu-events/jsmn.c b/tools/perf/pmu-events/jsmn.c
new file mode 100644
index 000000000000..11d1fa18bfa5
--- /dev/null
+++ b/tools/perf/pmu-events/jsmn.c
@@ -0,0 +1,313 @@
1/*
2 * Copyright (c) 2010 Serge A. Zaitsev
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a copy
5 * of this software and associated documentation files (the "Software"), to deal
6 * in the Software without restriction, including without limitation the rights
7 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 * copies of the Software, and to permit persons to whom the Software is
9 * furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 * THE SOFTWARE.
21 *
22 * Slightly modified by AK to not assume 0 terminated input.
23 */
24
25#include <stdlib.h>
26#include "jsmn.h"
27
28/*
29 * Allocates a fresh unused token from the token pool.
30 */
31static jsmntok_t *jsmn_alloc_token(jsmn_parser *parser,
32 jsmntok_t *tokens, size_t num_tokens)
33{
34 jsmntok_t *tok;
35
36 if ((unsigned)parser->toknext >= num_tokens)
37 return NULL;
38 tok = &tokens[parser->toknext++];
39 tok->start = tok->end = -1;
40 tok->size = 0;
41 return tok;
42}
43
44/*
45 * Fills token type and boundaries.
46 */
47static void jsmn_fill_token(jsmntok_t *token, jsmntype_t type,
48 int start, int end)
49{
50 token->type = type;
51 token->start = start;
52 token->end = end;
53 token->size = 0;
54}
55
56/*
57 * Fills next available token with JSON primitive.
58 */
59static jsmnerr_t jsmn_parse_primitive(jsmn_parser *parser, const char *js,
60 size_t len,
61 jsmntok_t *tokens, size_t num_tokens)
62{
63 jsmntok_t *token;
64 int start;
65
66 start = parser->pos;
67
68 for (; parser->pos < len; parser->pos++) {
69 switch (js[parser->pos]) {
70#ifndef JSMN_STRICT
71 /*
72 * In strict mode primitive must be followed by ","
73 * or "}" or "]"
74 */
75 case ':':
76#endif
77 case '\t':
78 case '\r':
79 case '\n':
80 case ' ':
81 case ',':
82 case ']':
83 case '}':
84 goto found;
85 default:
86 break;
87 }
88 if (js[parser->pos] < 32 || js[parser->pos] >= 127) {
89 parser->pos = start;
90 return JSMN_ERROR_INVAL;
91 }
92 }
93#ifdef JSMN_STRICT
94 /*
95 * In strict mode primitive must be followed by a
96 * comma/object/array.
97 */
98 parser->pos = start;
99 return JSMN_ERROR_PART;
100#endif
101
102found:
103 token = jsmn_alloc_token(parser, tokens, num_tokens);
104 if (token == NULL) {
105 parser->pos = start;
106 return JSMN_ERROR_NOMEM;
107 }
108 jsmn_fill_token(token, JSMN_PRIMITIVE, start, parser->pos);
109 parser->pos--; /* parent sees closing brackets */
110 return JSMN_SUCCESS;
111}
112
113/*
114 * Fills next token with JSON string.
115 */
116static jsmnerr_t jsmn_parse_string(jsmn_parser *parser, const char *js,
117 size_t len,
118 jsmntok_t *tokens, size_t num_tokens)
119{
120 jsmntok_t *token;
121 int start = parser->pos;
122
123 /* Skip starting quote */
124 parser->pos++;
125
126 for (; parser->pos < len; parser->pos++) {
127 char c = js[parser->pos];
128
129 /* Quote: end of string */
130 if (c == '\"') {
131 token = jsmn_alloc_token(parser, tokens, num_tokens);
132 if (token == NULL) {
133 parser->pos = start;
134 return JSMN_ERROR_NOMEM;
135 }
136 jsmn_fill_token(token, JSMN_STRING, start+1,
137 parser->pos);
138 return JSMN_SUCCESS;
139 }
140
141 /* Backslash: Quoted symbol expected */
142 if (c == '\\') {
143 parser->pos++;
144 switch (js[parser->pos]) {
145 /* Allowed escaped symbols */
146 case '\"':
147 case '/':
148 case '\\':
149 case 'b':
150 case 'f':
151 case 'r':
152 case 'n':
153 case 't':
154 break;
155 /* Allows escaped symbol \uXXXX */
156 case 'u':
157 /* TODO */
158 break;
159 /* Unexpected symbol */
160 default:
161 parser->pos = start;
162 return JSMN_ERROR_INVAL;
163 }
164 }
165 }
166 parser->pos = start;
167 return JSMN_ERROR_PART;
168}
169
170/*
171 * Parse JSON string and fill tokens.
172 */
173jsmnerr_t jsmn_parse(jsmn_parser *parser, const char *js, size_t len,
174 jsmntok_t *tokens, unsigned int num_tokens)
175{
176 jsmnerr_t r;
177 int i;
178 jsmntok_t *token;
179
180 for (; parser->pos < len; parser->pos++) {
181 char c;
182 jsmntype_t type;
183
184 c = js[parser->pos];
185 switch (c) {
186 case '{':
187 case '[':
188 token = jsmn_alloc_token(parser, tokens, num_tokens);
189 if (token == NULL)
190 return JSMN_ERROR_NOMEM;
191 if (parser->toksuper != -1)
192 tokens[parser->toksuper].size++;
193 token->type = (c == '{' ? JSMN_OBJECT : JSMN_ARRAY);
194 token->start = parser->pos;
195 parser->toksuper = parser->toknext - 1;
196 break;
197 case '}':
198 case ']':
199 type = (c == '}' ? JSMN_OBJECT : JSMN_ARRAY);
200 for (i = parser->toknext - 1; i >= 0; i--) {
201 token = &tokens[i];
202 if (token->start != -1 && token->end == -1) {
203 if (token->type != type)
204 return JSMN_ERROR_INVAL;
205 parser->toksuper = -1;
206 token->end = parser->pos + 1;
207 break;
208 }
209 }
210 /* Error if unmatched closing bracket */
211 if (i == -1)
212 return JSMN_ERROR_INVAL;
213 for (; i >= 0; i--) {
214 token = &tokens[i];
215 if (token->start != -1 && token->end == -1) {
216 parser->toksuper = i;
217 break;
218 }
219 }
220 break;
221 case '\"':
222 r = jsmn_parse_string(parser, js, len, tokens,
223 num_tokens);
224 if (r < 0)
225 return r;
226 if (parser->toksuper != -1)
227 tokens[parser->toksuper].size++;
228 break;
229 case '\t':
230 case '\r':
231 case '\n':
232 case ':':
233 case ',':
234 case ' ':
235 break;
236#ifdef JSMN_STRICT
237 /*
238 * In strict mode primitives are:
239 * numbers and booleans.
240 */
241 case '-':
242 case '0':
243 case '1':
244 case '2':
245 case '3':
246 case '4':
247 case '5':
248 case '6':
249 case '7':
250 case '8':
251 case '9':
252 case 't':
253 case 'f':
254 case 'n':
255#else
256 /*
257 * In non-strict mode every unquoted value
258 * is a primitive.
259 */
260 /*FALL THROUGH */
261 default:
262#endif
263 r = jsmn_parse_primitive(parser, js, len, tokens,
264 num_tokens);
265 if (r < 0)
266 return r;
267 if (parser->toksuper != -1)
268 tokens[parser->toksuper].size++;
269 break;
270
271#ifdef JSMN_STRICT
272 /* Unexpected char in strict mode */
273 default:
274 return JSMN_ERROR_INVAL;
275#endif
276 }
277 }
278
279 for (i = parser->toknext - 1; i >= 0; i--) {
280 /* Unmatched opened object or array */
281 if (tokens[i].start != -1 && tokens[i].end == -1)
282 return JSMN_ERROR_PART;
283 }
284
285 return JSMN_SUCCESS;
286}
287
288/*
289 * Creates a new parser based over a given buffer with an array of tokens
290 * available.
291 */
292void jsmn_init(jsmn_parser *parser)
293{
294 parser->pos = 0;
295 parser->toknext = 0;
296 parser->toksuper = -1;
297}
298
299const char *jsmn_strerror(jsmnerr_t err)
300{
301 switch (err) {
302 case JSMN_ERROR_NOMEM:
303 return "No enough tokens";
304 case JSMN_ERROR_INVAL:
305 return "Invalid character inside JSON string";
306 case JSMN_ERROR_PART:
307 return "The string is not a full JSON packet, more bytes expected";
308 case JSMN_SUCCESS:
309 return "Success";
310 default:
311 return "Unknown json error";
312 }
313}
diff --git a/tools/perf/pmu-events/jsmn.h b/tools/perf/pmu-events/jsmn.h
new file mode 100644
index 000000000000..d666b10cf25b
--- /dev/null
+++ b/tools/perf/pmu-events/jsmn.h
@@ -0,0 +1,67 @@
1#ifndef __JSMN_H_
2#define __JSMN_H_
3
4/*
5 * JSON type identifier. Basic types are:
6 * o Object
7 * o Array
8 * o String
9 * o Other primitive: number, boolean (true/false) or null
10 */
11typedef enum {
12 JSMN_PRIMITIVE = 0,
13 JSMN_OBJECT = 1,
14 JSMN_ARRAY = 2,
15 JSMN_STRING = 3
16} jsmntype_t;
17
18typedef enum {
19 /* Not enough tokens were provided */
20 JSMN_ERROR_NOMEM = -1,
21 /* Invalid character inside JSON string */
22 JSMN_ERROR_INVAL = -2,
23 /* The string is not a full JSON packet, more bytes expected */
24 JSMN_ERROR_PART = -3,
25 /* Everything was fine */
26 JSMN_SUCCESS = 0
27} jsmnerr_t;
28
29/*
30 * JSON token description.
31 * @param type type (object, array, string etc.)
32 * @param start start position in JSON data string
33 * @param end end position in JSON data string
34 */
35typedef struct {
36 jsmntype_t type;
37 int start;
38 int end;
39 int size;
40} jsmntok_t;
41
42/*
43 * JSON parser. Contains an array of token blocks available. Also stores
44 * the string being parsed now and current position in that string
45 */
46typedef struct {
47 unsigned int pos; /* offset in the JSON string */
48 int toknext; /* next token to allocate */
49 int toksuper; /* superior token node, e.g parent object or array */
50} jsmn_parser;
51
52/*
53 * Create JSON parser over an array of tokens
54 */
55void jsmn_init(jsmn_parser *parser);
56
57/*
58 * Run JSON parser. It parses a JSON data string into and array of tokens,
59 * each describing a single JSON object.
60 */
61jsmnerr_t jsmn_parse(jsmn_parser *parser, const char *js,
62 size_t len,
63 jsmntok_t *tokens, unsigned int num_tokens);
64
65const char *jsmn_strerror(jsmnerr_t err);
66
67#endif /* __JSMN_H_ */
diff --git a/tools/perf/pmu-events/json.c b/tools/perf/pmu-events/json.c
new file mode 100644
index 000000000000..f67bbb0aa36e
--- /dev/null
+++ b/tools/perf/pmu-events/json.c
@@ -0,0 +1,162 @@
1/* Parse JSON files using the JSMN parser. */
2
3/*
4 * Copyright (c) 2014, Intel Corporation
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions are met:
9 *
10 * 1. Redistributions of source code must retain the above copyright notice,
11 * this list of conditions and the following disclaimer.
12 *
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
20 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
21 * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
22 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
26 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
28 * OF THE POSSIBILITY OF SUCH DAMAGE.
29*/
30
31#include <stdlib.h>
32#include <string.h>
33#include <sys/mman.h>
34#include <sys/stat.h>
35#include <fcntl.h>
36#include <stdio.h>
37#include <errno.h>
38#include <unistd.h>
39#include "jsmn.h"
40#include "json.h"
41#include <linux/kernel.h>
42
43
44static char *mapfile(const char *fn, size_t *size)
45{
46 unsigned ps = sysconf(_SC_PAGESIZE);
47 struct stat st;
48 char *map = NULL;
49 int err;
50 int fd = open(fn, O_RDONLY);
51
52 if (fd < 0 && verbose && fn) {
53 pr_err("Error opening events file '%s': %s\n", fn,
54 strerror(errno));
55 }
56
57 if (fd < 0)
58 return NULL;
59 err = fstat(fd, &st);
60 if (err < 0)
61 goto out;
62 *size = st.st_size;
63 map = mmap(NULL,
64 (st.st_size + ps - 1) & ~(ps - 1),
65 PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0);
66 if (map == MAP_FAILED)
67 map = NULL;
68out:
69 close(fd);
70 return map;
71}
72
73static void unmapfile(char *map, size_t size)
74{
75 unsigned ps = sysconf(_SC_PAGESIZE);
76 munmap(map, roundup(size, ps));
77}
78
79/*
80 * Parse json file using jsmn. Return array of tokens,
81 * and mapped file. Caller needs to free array.
82 */
83jsmntok_t *parse_json(const char *fn, char **map, size_t *size, int *len)
84{
85 jsmn_parser parser;
86 jsmntok_t *tokens;
87 jsmnerr_t res;
88 unsigned sz;
89
90 *map = mapfile(fn, size);
91 if (!*map)
92 return NULL;
93 /* Heuristic */
94 sz = *size * 16;
95 tokens = malloc(sz);
96 if (!tokens)
97 goto error;
98 jsmn_init(&parser);
99 res = jsmn_parse(&parser, *map, *size, tokens,
100 sz / sizeof(jsmntok_t));
101 if (res != JSMN_SUCCESS) {
102 pr_err("%s: json error %s\n", fn, jsmn_strerror(res));
103 goto error_free;
104 }
105 if (len)
106 *len = parser.toknext;
107 return tokens;
108error_free:
109 free(tokens);
110error:
111 unmapfile(*map, *size);
112 return NULL;
113}
114
115void free_json(char *map, size_t size, jsmntok_t *tokens)
116{
117 free(tokens);
118 unmapfile(map, size);
119}
120
121static int countchar(char *map, char c, int end)
122{
123 int i;
124 int count = 0;
125 for (i = 0; i < end; i++)
126 if (map[i] == c)
127 count++;
128 return count;
129}
130
131/* Return line number of a jsmn token */
132int json_line(char *map, jsmntok_t *t)
133{
134 return countchar(map, '\n', t->start) + 1;
135}
136
137static const char * const jsmn_types[] = {
138 [JSMN_PRIMITIVE] = "primitive",
139 [JSMN_ARRAY] = "array",
140 [JSMN_OBJECT] = "object",
141 [JSMN_STRING] = "string"
142};
143
144#define LOOKUP(a, i) ((i) < (sizeof(a)/sizeof(*(a))) ? ((a)[i]) : "?")
145
146/* Return type name of a jsmn token */
147const char *json_name(jsmntok_t *t)
148{
149 return LOOKUP(jsmn_types, t->type);
150}
151
152int json_len(jsmntok_t *t)
153{
154 return t->end - t->start;
155}
156
157/* Is string t equal to s? */
158int json_streq(char *map, jsmntok_t *t, const char *s)
159{
160 unsigned len = json_len(t);
161 return len == strlen(s) && !strncasecmp(map + t->start, s, len);
162}
diff --git a/tools/perf/pmu-events/json.h b/tools/perf/pmu-events/json.h
new file mode 100644
index 000000000000..278ebd32cfb6
--- /dev/null
+++ b/tools/perf/pmu-events/json.h
@@ -0,0 +1,38 @@
1#ifndef JSON_H
2#define JSON_H 1
3
4#include "jsmn.h"
5
6jsmntok_t *parse_json(const char *fn, char **map, size_t *size, int *len);
7void free_json(char *map, size_t size, jsmntok_t *tokens);
8int json_line(char *map, jsmntok_t *t);
9const char *json_name(jsmntok_t *t);
10int json_streq(char *map, jsmntok_t *t, const char *s);
11int json_len(jsmntok_t *t);
12
13extern int verbose;
14
15#include <stdbool.h>
16
17extern int eprintf(int level, int var, const char *fmt, ...);
18#define pr_fmt(fmt) fmt
19
20#define pr_err(fmt, ...) \
21 eprintf(0, verbose, pr_fmt(fmt), ##__VA_ARGS__)
22
23#define pr_info(fmt, ...) \
24 eprintf(1, verbose, pr_fmt(fmt), ##__VA_ARGS__)
25
26#define pr_debug(fmt, ...) \
27 eprintf(2, verbose, pr_fmt(fmt), ##__VA_ARGS__)
28
29#ifndef roundup
30#define roundup(x, y) ( \
31{ \
32 const typeof(y) __y = y; \
33 (((x) + (__y - 1)) / __y) * __y; \
34} \
35)
36#endif
37
38#endif
diff --git a/tools/perf/pmu-events/pmu-events.h b/tools/perf/pmu-events/pmu-events.h
new file mode 100644
index 000000000000..2eaef595d8a0
--- /dev/null
+++ b/tools/perf/pmu-events/pmu-events.h
@@ -0,0 +1,37 @@
1#ifndef PMU_EVENTS_H
2#define PMU_EVENTS_H
3
4/*
5 * Describe each PMU event. Each CPU has a table of PMU events.
6 */
7struct pmu_event {
8 const char *name;
9 const char *event;
10 const char *desc;
11 const char *topic;
12 const char *long_desc;
13};
14
15/*
16 *
17 * Map a CPU to its table of PMU events. The CPU is identified by the
18 * cpuid field, which is an arch-specific identifier for the CPU.
19 * The identifier specified in tools/perf/pmu-events/arch/xxx/mapfile
20 * must match the get_cpustr() in tools/perf/arch/xxx/util/header.c)
21 *
22 * The cpuid can contain any character other than the comma.
23 */
24struct pmu_events_map {
25 const char *cpuid;
26 const char *version;
27 const char *type; /* core, uncore etc */
28 struct pmu_event *table;
29};
30
31/*
32 * Global table mapping each known CPU for the architecture to its
33 * table of PMU events.
34 */
35extern struct pmu_events_map pmu_events_map[];
36
37#endif
diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c
index ea34c5a32c11..d92e02006fb8 100644
--- a/tools/perf/util/evlist.c
+++ b/tools/perf/util/evlist.c
@@ -384,15 +384,14 @@ void perf_evlist__toggle_enable(struct perf_evlist *evlist)
384static int perf_evlist__enable_event_cpu(struct perf_evlist *evlist, 384static int perf_evlist__enable_event_cpu(struct perf_evlist *evlist,
385 struct perf_evsel *evsel, int cpu) 385 struct perf_evsel *evsel, int cpu)
386{ 386{
387 int thread, err; 387 int thread;
388 int nr_threads = perf_evlist__nr_threads(evlist, evsel); 388 int nr_threads = perf_evlist__nr_threads(evlist, evsel);
389 389
390 if (!evsel->fd) 390 if (!evsel->fd)
391 return -EINVAL; 391 return -EINVAL;
392 392
393 for (thread = 0; thread < nr_threads; thread++) { 393 for (thread = 0; thread < nr_threads; thread++) {
394 err = ioctl(FD(evsel, cpu, thread), 394 int err = ioctl(FD(evsel, cpu, thread), PERF_EVENT_IOC_ENABLE, 0);
395 PERF_EVENT_IOC_ENABLE, 0);
396 if (err) 395 if (err)
397 return err; 396 return err;
398 } 397 }
@@ -403,14 +402,14 @@ static int perf_evlist__enable_event_thread(struct perf_evlist *evlist,
403 struct perf_evsel *evsel, 402 struct perf_evsel *evsel,
404 int thread) 403 int thread)
405{ 404{
406 int cpu, err; 405 int cpu;
407 int nr_cpus = cpu_map__nr(evlist->cpus); 406 int nr_cpus = cpu_map__nr(evlist->cpus);
408 407
409 if (!evsel->fd) 408 if (!evsel->fd)
410 return -EINVAL; 409 return -EINVAL;
411 410
412 for (cpu = 0; cpu < nr_cpus; cpu++) { 411 for (cpu = 0; cpu < nr_cpus; cpu++) {
413 err = ioctl(FD(evsel, cpu, thread), PERF_EVENT_IOC_ENABLE, 0); 412 int err = ioctl(FD(evsel, cpu, thread), PERF_EVENT_IOC_ENABLE, 0);
414 if (err) 413 if (err)
415 return err; 414 return err;
416 } 415 }
@@ -1606,10 +1605,9 @@ void perf_evlist__close(struct perf_evlist *evlist)
1606 struct perf_evsel *evsel; 1605 struct perf_evsel *evsel;
1607 int ncpus = cpu_map__nr(evlist->cpus); 1606 int ncpus = cpu_map__nr(evlist->cpus);
1608 int nthreads = thread_map__nr(evlist->threads); 1607 int nthreads = thread_map__nr(evlist->threads);
1609 int n;
1610 1608
1611 evlist__for_each_entry_reverse(evlist, evsel) { 1609 evlist__for_each_entry_reverse(evlist, evsel) {
1612 n = evsel->cpus ? evsel->cpus->nr : ncpus; 1610 int n = evsel->cpus ? evsel->cpus->nr : ncpus;
1613 perf_evsel__close(evsel, n, nthreads); 1611 perf_evsel__close(evsel, n, nthreads);
1614 } 1612 }
1615} 1613}
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c
index 380e84c3af3d..8bc271141d9d 100644
--- a/tools/perf/util/evsel.c
+++ b/tools/perf/util/evsel.c
@@ -985,14 +985,13 @@ void perf_evsel__config(struct perf_evsel *evsel, struct record_opts *opts,
985 985
986static int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads) 986static int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads)
987{ 987{
988 int cpu, thread;
989
990 if (evsel->system_wide) 988 if (evsel->system_wide)
991 nthreads = 1; 989 nthreads = 1;
992 990
993 evsel->fd = xyarray__new(ncpus, nthreads, sizeof(int)); 991 evsel->fd = xyarray__new(ncpus, nthreads, sizeof(int));
994 992
995 if (evsel->fd) { 993 if (evsel->fd) {
994 int cpu, thread;
996 for (cpu = 0; cpu < ncpus; cpu++) { 995 for (cpu = 0; cpu < ncpus; cpu++) {
997 for (thread = 0; thread < nthreads; thread++) { 996 for (thread = 0; thread < nthreads; thread++) {
998 FD(evsel, cpu, thread) = -1; 997 FD(evsel, cpu, thread) = -1;
diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h
index d306ca118449..d30109b421ee 100644
--- a/tools/perf/util/header.h
+++ b/tools/perf/util/header.h
@@ -151,4 +151,5 @@ int write_padded(int fd, const void *bf, size_t count, size_t count_aligned);
151 */ 151 */
152int get_cpuid(char *buffer, size_t sz); 152int get_cpuid(char *buffer, size_t sz);
153 153
154char *get_cpuid_str(void);
154#endif /* __PERF_HEADER_H */ 155#endif /* __PERF_HEADER_H */
diff --git a/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c b/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c
index 7591a0c37473..16c06d3ae577 100644
--- a/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c
+++ b/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c
@@ -90,6 +90,7 @@ struct intel_pt_decoder {
90 bool pge; 90 bool pge;
91 bool have_tma; 91 bool have_tma;
92 bool have_cyc; 92 bool have_cyc;
93 bool fixup_last_mtc;
93 uint64_t pos; 94 uint64_t pos;
94 uint64_t last_ip; 95 uint64_t last_ip;
95 uint64_t ip; 96 uint64_t ip;
@@ -586,10 +587,31 @@ struct intel_pt_calc_cyc_to_tsc_info {
586 uint64_t tsc_timestamp; 587 uint64_t tsc_timestamp;
587 uint64_t timestamp; 588 uint64_t timestamp;
588 bool have_tma; 589 bool have_tma;
590 bool fixup_last_mtc;
589 bool from_mtc; 591 bool from_mtc;
590 double cbr_cyc_to_tsc; 592 double cbr_cyc_to_tsc;
591}; 593};
592 594
595/*
596 * MTC provides a 8-bit slice of CTC but the TMA packet only provides the lower
597 * 16 bits of CTC. If mtc_shift > 8 then some of the MTC bits are not in the CTC
598 * provided by the TMA packet. Fix-up the last_mtc calculated from the TMA
599 * packet by copying the missing bits from the current MTC assuming the least
600 * difference between the two, and that the current MTC comes after last_mtc.
601 */
602static void intel_pt_fixup_last_mtc(uint32_t mtc, int mtc_shift,
603 uint32_t *last_mtc)
604{
605 uint32_t first_missing_bit = 1U << (16 - mtc_shift);
606 uint32_t mask = ~(first_missing_bit - 1);
607
608 *last_mtc |= mtc & mask;
609 if (*last_mtc >= mtc) {
610 *last_mtc -= first_missing_bit;
611 *last_mtc &= 0xff;
612 }
613}
614
593static int intel_pt_calc_cyc_cb(struct intel_pt_pkt_info *pkt_info) 615static int intel_pt_calc_cyc_cb(struct intel_pt_pkt_info *pkt_info)
594{ 616{
595 struct intel_pt_decoder *decoder = pkt_info->decoder; 617 struct intel_pt_decoder *decoder = pkt_info->decoder;
@@ -619,6 +641,11 @@ static int intel_pt_calc_cyc_cb(struct intel_pt_pkt_info *pkt_info)
619 return 0; 641 return 0;
620 642
621 mtc = pkt_info->packet.payload; 643 mtc = pkt_info->packet.payload;
644 if (decoder->mtc_shift > 8 && data->fixup_last_mtc) {
645 data->fixup_last_mtc = false;
646 intel_pt_fixup_last_mtc(mtc, decoder->mtc_shift,
647 &data->last_mtc);
648 }
622 if (mtc > data->last_mtc) 649 if (mtc > data->last_mtc)
623 mtc_delta = mtc - data->last_mtc; 650 mtc_delta = mtc - data->last_mtc;
624 else 651 else
@@ -687,6 +714,7 @@ static int intel_pt_calc_cyc_cb(struct intel_pt_pkt_info *pkt_info)
687 714
688 data->ctc_delta = 0; 715 data->ctc_delta = 0;
689 data->have_tma = true; 716 data->have_tma = true;
717 data->fixup_last_mtc = true;
690 718
691 return 0; 719 return 0;
692 720
@@ -753,6 +781,7 @@ static void intel_pt_calc_cyc_to_tsc(struct intel_pt_decoder *decoder,
753 .tsc_timestamp = decoder->tsc_timestamp, 781 .tsc_timestamp = decoder->tsc_timestamp,
754 .timestamp = decoder->timestamp, 782 .timestamp = decoder->timestamp,
755 .have_tma = decoder->have_tma, 783 .have_tma = decoder->have_tma,
784 .fixup_last_mtc = decoder->fixup_last_mtc,
756 .from_mtc = from_mtc, 785 .from_mtc = from_mtc,
757 .cbr_cyc_to_tsc = 0, 786 .cbr_cyc_to_tsc = 0,
758 }; 787 };
@@ -1271,6 +1300,7 @@ static void intel_pt_calc_tma(struct intel_pt_decoder *decoder)
1271 } 1300 }
1272 decoder->ctc_delta = 0; 1301 decoder->ctc_delta = 0;
1273 decoder->have_tma = true; 1302 decoder->have_tma = true;
1303 decoder->fixup_last_mtc = true;
1274 intel_pt_log("CTC timestamp " x64_fmt " last MTC %#x CTC rem %#x\n", 1304 intel_pt_log("CTC timestamp " x64_fmt " last MTC %#x CTC rem %#x\n",
1275 decoder->ctc_timestamp, decoder->last_mtc, ctc_rem); 1305 decoder->ctc_timestamp, decoder->last_mtc, ctc_rem);
1276} 1306}
@@ -1285,6 +1315,12 @@ static void intel_pt_calc_mtc_timestamp(struct intel_pt_decoder *decoder)
1285 1315
1286 mtc = decoder->packet.payload; 1316 mtc = decoder->packet.payload;
1287 1317
1318 if (decoder->mtc_shift > 8 && decoder->fixup_last_mtc) {
1319 decoder->fixup_last_mtc = false;
1320 intel_pt_fixup_last_mtc(mtc, decoder->mtc_shift,
1321 &decoder->last_mtc);
1322 }
1323
1288 if (mtc > decoder->last_mtc) 1324 if (mtc > decoder->last_mtc)
1289 mtc_delta = mtc - decoder->last_mtc; 1325 mtc_delta = mtc - decoder->last_mtc;
1290 else 1326 else
@@ -1353,6 +1389,8 @@ static void intel_pt_calc_cyc_timestamp(struct intel_pt_decoder *decoder)
1353 timestamp, decoder->timestamp); 1389 timestamp, decoder->timestamp);
1354 else 1390 else
1355 decoder->timestamp = timestamp; 1391 decoder->timestamp = timestamp;
1392
1393 decoder->timestamp_insn_cnt = 0;
1356} 1394}
1357 1395
1358/* Walk PSB+ packets when already in sync. */ 1396/* Walk PSB+ packets when already in sync. */
diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c
index 18e4519abef2..df85b9efd80f 100644
--- a/tools/perf/util/machine.c
+++ b/tools/perf/util/machine.c
@@ -1745,9 +1745,8 @@ static int resolve_lbr_callchain_sample(struct thread *thread,
1745 int max_stack) 1745 int max_stack)
1746{ 1746{
1747 struct ip_callchain *chain = sample->callchain; 1747 struct ip_callchain *chain = sample->callchain;
1748 int chain_nr = min(max_stack, (int)chain->nr); 1748 int chain_nr = min(max_stack, (int)chain->nr), i;
1749 u8 cpumode = PERF_RECORD_MISC_USER; 1749 u8 cpumode = PERF_RECORD_MISC_USER;
1750 int i, j, err;
1751 u64 ip; 1750 u64 ip;
1752 1751
1753 for (i = 0; i < chain_nr; i++) { 1752 for (i = 0; i < chain_nr; i++) {
@@ -1758,7 +1757,7 @@ static int resolve_lbr_callchain_sample(struct thread *thread,
1758 /* LBR only affects the user callchain */ 1757 /* LBR only affects the user callchain */
1759 if (i != chain_nr) { 1758 if (i != chain_nr) {
1760 struct branch_stack *lbr_stack = sample->branch_stack; 1759 struct branch_stack *lbr_stack = sample->branch_stack;
1761 int lbr_nr = lbr_stack->nr; 1760 int lbr_nr = lbr_stack->nr, j;
1762 /* 1761 /*
1763 * LBR callstack can only get user call chain. 1762 * LBR callstack can only get user call chain.
1764 * The mix_chain_nr is kernel call chain 1763 * The mix_chain_nr is kernel call chain
@@ -1772,6 +1771,7 @@ static int resolve_lbr_callchain_sample(struct thread *thread,
1772 int mix_chain_nr = i + 1 + lbr_nr + 1; 1771 int mix_chain_nr = i + 1 + lbr_nr + 1;
1773 1772
1774 for (j = 0; j < mix_chain_nr; j++) { 1773 for (j = 0; j < mix_chain_nr; j++) {
1774 int err;
1775 if (callchain_param.order == ORDER_CALLEE) { 1775 if (callchain_param.order == ORDER_CALLEE) {
1776 if (j < i + 1) 1776 if (j < i + 1)
1777 ip = chain->ips[j]; 1777 ip = chain->ips[j];
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index 33546c3ac1fe..4e778eae1510 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -924,6 +924,7 @@ config_term_avail(int term_type, struct parse_events_error *err)
924 case PARSE_EVENTS__TERM_TYPE_CONFIG1: 924 case PARSE_EVENTS__TERM_TYPE_CONFIG1:
925 case PARSE_EVENTS__TERM_TYPE_CONFIG2: 925 case PARSE_EVENTS__TERM_TYPE_CONFIG2:
926 case PARSE_EVENTS__TERM_TYPE_NAME: 926 case PARSE_EVENTS__TERM_TYPE_NAME:
927 case PARSE_EVENTS__TERM_TYPE_SAMPLE_PERIOD:
927 return true; 928 return true;
928 default: 929 default:
929 if (!err) 930 if (!err)
@@ -1458,7 +1459,7 @@ comp_pmu(const void *p1, const void *p2)
1458 struct perf_pmu_event_symbol *pmu1 = (struct perf_pmu_event_symbol *) p1; 1459 struct perf_pmu_event_symbol *pmu1 = (struct perf_pmu_event_symbol *) p1;
1459 struct perf_pmu_event_symbol *pmu2 = (struct perf_pmu_event_symbol *) p2; 1460 struct perf_pmu_event_symbol *pmu2 = (struct perf_pmu_event_symbol *) p2;
1460 1461
1461 return strcmp(pmu1->symbol, pmu2->symbol); 1462 return strcasecmp(pmu1->symbol, pmu2->symbol);
1462} 1463}
1463 1464
1464static void perf_pmu__parse_cleanup(void) 1465static void perf_pmu__parse_cleanup(void)
@@ -2263,7 +2264,8 @@ out_enomem:
2263/* 2264/*
2264 * Print the help text for the event symbols: 2265 * Print the help text for the event symbols:
2265 */ 2266 */
2266void print_events(const char *event_glob, bool name_only) 2267void print_events(const char *event_glob, bool name_only, bool quiet_flag,
2268 bool long_desc)
2267{ 2269{
2268 print_symbol_events(event_glob, PERF_TYPE_HARDWARE, 2270 print_symbol_events(event_glob, PERF_TYPE_HARDWARE,
2269 event_symbols_hw, PERF_COUNT_HW_MAX, name_only); 2271 event_symbols_hw, PERF_COUNT_HW_MAX, name_only);
@@ -2273,7 +2275,7 @@ void print_events(const char *event_glob, bool name_only)
2273 2275
2274 print_hwcache_events(event_glob, name_only); 2276 print_hwcache_events(event_glob, name_only);
2275 2277
2276 print_pmu_events(event_glob, name_only); 2278 print_pmu_events(event_glob, name_only, quiet_flag, long_desc);
2277 2279
2278 if (event_glob != NULL) 2280 if (event_glob != NULL)
2279 return; 2281 return;
diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h
index 8d09a976fca8..da246a3ddb69 100644
--- a/tools/perf/util/parse-events.h
+++ b/tools/perf/util/parse-events.h
@@ -172,7 +172,8 @@ void parse_events_update_lists(struct list_head *list_event,
172void parse_events_evlist_error(struct parse_events_evlist *data, 172void parse_events_evlist_error(struct parse_events_evlist *data,
173 int idx, const char *str); 173 int idx, const char *str);
174 174
175void print_events(const char *event_glob, bool name_only); 175void print_events(const char *event_glob, bool name_only, bool quiet,
176 bool long_desc);
176 177
177struct event_symbol { 178struct event_symbol {
178 const char *symbol; 179 const char *symbol;
diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c
index 2babcdf62839..b1474dcadfa2 100644
--- a/tools/perf/util/pmu.c
+++ b/tools/perf/util/pmu.c
@@ -12,6 +12,9 @@
12#include "pmu.h" 12#include "pmu.h"
13#include "parse-events.h" 13#include "parse-events.h"
14#include "cpumap.h" 14#include "cpumap.h"
15#include "header.h"
16#include "pmu-events/pmu-events.h"
17#include "cache.h"
15 18
16struct perf_pmu_format { 19struct perf_pmu_format {
17 char *name; 20 char *name;
@@ -220,7 +223,8 @@ static int perf_pmu__parse_snapshot(struct perf_pmu_alias *alias,
220} 223}
221 224
222static int __perf_pmu__new_alias(struct list_head *list, char *dir, char *name, 225static int __perf_pmu__new_alias(struct list_head *list, char *dir, char *name,
223 char *desc __maybe_unused, char *val) 226 char *desc, char *val, char *long_desc,
227 char *topic)
224{ 228{
225 struct perf_pmu_alias *alias; 229 struct perf_pmu_alias *alias;
226 int ret; 230 int ret;
@@ -253,6 +257,11 @@ static int __perf_pmu__new_alias(struct list_head *list, char *dir, char *name,
253 perf_pmu__parse_snapshot(alias, dir, name); 257 perf_pmu__parse_snapshot(alias, dir, name);
254 } 258 }
255 259
260 alias->desc = desc ? strdup(desc) : NULL;
261 alias->long_desc = long_desc ? strdup(long_desc) :
262 desc ? strdup(desc) : NULL;
263 alias->topic = topic ? strdup(topic) : NULL;
264
256 list_add_tail(&alias->list, list); 265 list_add_tail(&alias->list, list);
257 266
258 return 0; 267 return 0;
@@ -269,7 +278,7 @@ static int perf_pmu__new_alias(struct list_head *list, char *dir, char *name, FI
269 278
270 buf[ret] = 0; 279 buf[ret] = 0;
271 280
272 return __perf_pmu__new_alias(list, dir, name, NULL, buf); 281 return __perf_pmu__new_alias(list, dir, name, NULL, buf, NULL, NULL);
273} 282}
274 283
275static inline bool pmu_alias_info_file(char *name) 284static inline bool pmu_alias_info_file(char *name)
@@ -473,6 +482,68 @@ static struct cpu_map *pmu_cpumask(const char *name)
473 return cpus; 482 return cpus;
474} 483}
475 484
485/*
486 * Return the CPU id as a raw string.
487 *
488 * Each architecture should provide a more precise id string that
489 * can be use to match the architecture's "mapfile".
490 */
491char * __weak get_cpuid_str(void)
492{
493 return NULL;
494}
495
496/*
497 * From the pmu_events_map, find the table of PMU events that corresponds
498 * to the current running CPU. Then, add all PMU events from that table
499 * as aliases.
500 */
501static void pmu_add_cpu_aliases(struct list_head *head)
502{
503 int i;
504 struct pmu_events_map *map;
505 struct pmu_event *pe;
506 char *cpuid;
507
508 cpuid = getenv("PERF_CPUID");
509 if (cpuid)
510 cpuid = strdup(cpuid);
511 if (!cpuid)
512 cpuid = get_cpuid_str();
513 if (!cpuid)
514 return;
515
516 pr_debug("Using CPUID %s\n", cpuid);
517
518 i = 0;
519 while (1) {
520 map = &pmu_events_map[i++];
521 if (!map->table)
522 goto out;
523
524 if (!strcmp(map->cpuid, cpuid))
525 break;
526 }
527
528 /*
529 * Found a matching PMU events table. Create aliases
530 */
531 i = 0;
532 while (1) {
533 pe = &map->table[i++];
534 if (!pe->name)
535 break;
536
537 /* need type casts to override 'const' */
538 __perf_pmu__new_alias(head, NULL, (char *)pe->name,
539 (char *)pe->desc, (char *)pe->event,
540 (char *)pe->long_desc, (char *)pe->topic);
541 }
542
543out:
544 free(cpuid);
545}
546
476struct perf_event_attr * __weak 547struct perf_event_attr * __weak
477perf_pmu__get_default_config(struct perf_pmu *pmu __maybe_unused) 548perf_pmu__get_default_config(struct perf_pmu *pmu __maybe_unused)
478{ 549{
@@ -497,6 +568,9 @@ static struct perf_pmu *pmu_lookup(const char *name)
497 if (pmu_aliases(name, &aliases)) 568 if (pmu_aliases(name, &aliases))
498 return NULL; 569 return NULL;
499 570
571 if (!strcmp(name, "cpu"))
572 pmu_add_cpu_aliases(&aliases);
573
500 if (pmu_type(name, &type)) 574 if (pmu_type(name, &type))
501 return NULL; 575 return NULL;
502 576
@@ -983,21 +1057,63 @@ static char *format_alias_or(char *buf, int len, struct perf_pmu *pmu,
983 return buf; 1057 return buf;
984} 1058}
985 1059
986static int cmp_string(const void *a, const void *b) 1060struct sevent {
1061 char *name;
1062 char *desc;
1063 char *topic;
1064};
1065
1066static int cmp_sevent(const void *a, const void *b)
987{ 1067{
988 const char * const *as = a; 1068 const struct sevent *as = a;
989 const char * const *bs = b; 1069 const struct sevent *bs = b;
990 return strcmp(*as, *bs); 1070
1071 /* Put extra events last */
1072 if (!!as->desc != !!bs->desc)
1073 return !!as->desc - !!bs->desc;
1074 if (as->topic && bs->topic) {
1075 int n = strcmp(as->topic, bs->topic);
1076
1077 if (n)
1078 return n;
1079 }
1080 return strcmp(as->name, bs->name);
991} 1081}
992 1082
993void print_pmu_events(const char *event_glob, bool name_only) 1083static void wordwrap(char *s, int start, int max, int corr)
1084{
1085 int column = start;
1086 int n;
1087
1088 while (*s) {
1089 int wlen = strcspn(s, " \t");
1090
1091 if (column + wlen >= max && column > start) {
1092 printf("\n%*s", start, "");
1093 column = start + corr;
1094 }
1095 n = printf("%s%.*s", column > start ? " " : "", wlen, s);
1096 if (n <= 0)
1097 break;
1098 s += wlen;
1099 column += n;
1100 while (isspace(*s))
1101 s++;
1102 }
1103}
1104
1105void print_pmu_events(const char *event_glob, bool name_only, bool quiet_flag,
1106 bool long_desc)
994{ 1107{
995 struct perf_pmu *pmu; 1108 struct perf_pmu *pmu;
996 struct perf_pmu_alias *alias; 1109 struct perf_pmu_alias *alias;
997 char buf[1024]; 1110 char buf[1024];
998 int printed = 0; 1111 int printed = 0;
999 int len, j; 1112 int len, j;
1000 char **aliases; 1113 struct sevent *aliases;
1114 int numdesc = 0;
1115 int columns = pager_get_columns();
1116 char *topic = NULL;
1001 1117
1002 pmu = NULL; 1118 pmu = NULL;
1003 len = 0; 1119 len = 0;
@@ -1007,14 +1123,15 @@ void print_pmu_events(const char *event_glob, bool name_only)
1007 if (pmu->selectable) 1123 if (pmu->selectable)
1008 len++; 1124 len++;
1009 } 1125 }
1010 aliases = zalloc(sizeof(char *) * len); 1126 aliases = zalloc(sizeof(struct sevent) * len);
1011 if (!aliases) 1127 if (!aliases)
1012 goto out_enomem; 1128 goto out_enomem;
1013 pmu = NULL; 1129 pmu = NULL;
1014 j = 0; 1130 j = 0;
1015 while ((pmu = perf_pmu__scan(pmu)) != NULL) { 1131 while ((pmu = perf_pmu__scan(pmu)) != NULL) {
1016 list_for_each_entry(alias, &pmu->aliases, list) { 1132 list_for_each_entry(alias, &pmu->aliases, list) {
1017 char *name = format_alias(buf, sizeof(buf), pmu, alias); 1133 char *name = alias->desc ? alias->name :
1134 format_alias(buf, sizeof(buf), pmu, alias);
1018 bool is_cpu = !strcmp(pmu->name, "cpu"); 1135 bool is_cpu = !strcmp(pmu->name, "cpu");
1019 1136
1020 if (event_glob != NULL && 1137 if (event_glob != NULL &&
@@ -1023,12 +1140,21 @@ void print_pmu_events(const char *event_glob, bool name_only)
1023 event_glob)))) 1140 event_glob))))
1024 continue; 1141 continue;
1025 1142
1026 if (is_cpu && !name_only) 1143 if (is_cpu && !name_only && !alias->desc)
1027 name = format_alias_or(buf, sizeof(buf), pmu, alias); 1144 name = format_alias_or(buf, sizeof(buf), pmu, alias);
1028 1145
1029 aliases[j] = strdup(name); 1146 aliases[j].name = name;
1030 if (aliases[j] == NULL) 1147 if (is_cpu && !name_only && !alias->desc)
1148 aliases[j].name = format_alias_or(buf,
1149 sizeof(buf),
1150 pmu, alias);
1151 aliases[j].name = strdup(aliases[j].name);
1152 if (!aliases[j].name)
1031 goto out_enomem; 1153 goto out_enomem;
1154
1155 aliases[j].desc = long_desc ? alias->long_desc :
1156 alias->desc;
1157 aliases[j].topic = alias->topic;
1032 j++; 1158 j++;
1033 } 1159 }
1034 if (pmu->selectable && 1160 if (pmu->selectable &&
@@ -1036,25 +1162,39 @@ void print_pmu_events(const char *event_glob, bool name_only)
1036 char *s; 1162 char *s;
1037 if (asprintf(&s, "%s//", pmu->name) < 0) 1163 if (asprintf(&s, "%s//", pmu->name) < 0)
1038 goto out_enomem; 1164 goto out_enomem;
1039 aliases[j] = s; 1165 aliases[j].name = s;
1040 j++; 1166 j++;
1041 } 1167 }
1042 } 1168 }
1043 len = j; 1169 len = j;
1044 qsort(aliases, len, sizeof(char *), cmp_string); 1170 qsort(aliases, len, sizeof(struct sevent), cmp_sevent);
1045 for (j = 0; j < len; j++) { 1171 for (j = 0; j < len; j++) {
1046 if (name_only) { 1172 if (name_only) {
1047 printf("%s ", aliases[j]); 1173 printf("%s ", aliases[j].name);
1048 continue; 1174 continue;
1049 } 1175 }
1050 printf(" %-50s [Kernel PMU event]\n", aliases[j]); 1176 if (aliases[j].desc && !quiet_flag) {
1177 if (numdesc++ == 0)
1178 printf("\n");
1179 if (aliases[j].topic && (!topic ||
1180 strcmp(topic, aliases[j].topic))) {
1181 printf("%s%s:\n", topic ? "\n" : "",
1182 aliases[j].topic);
1183 topic = aliases[j].topic;
1184 }
1185 printf(" %-50s\n", aliases[j].name);
1186 printf("%*s", 8, "[");
1187 wordwrap(aliases[j].desc, 8, columns, 0);
1188 printf("]\n");
1189 } else
1190 printf(" %-50s [Kernel PMU event]\n", aliases[j].name);
1051 printed++; 1191 printed++;
1052 } 1192 }
1053 if (printed && pager_in_use()) 1193 if (printed && pager_in_use())
1054 printf("\n"); 1194 printf("\n");
1055out_free: 1195out_free:
1056 for (j = 0; j < len; j++) 1196 for (j = 0; j < len; j++)
1057 zfree(&aliases[j]); 1197 zfree(&aliases[j].name);
1058 zfree(&aliases); 1198 zfree(&aliases);
1059 return; 1199 return;
1060 1200
diff --git a/tools/perf/util/pmu.h b/tools/perf/util/pmu.h
index 743422ad900b..25712034c815 100644
--- a/tools/perf/util/pmu.h
+++ b/tools/perf/util/pmu.h
@@ -40,6 +40,9 @@ struct perf_pmu_info {
40 40
41struct perf_pmu_alias { 41struct perf_pmu_alias {
42 char *name; 42 char *name;
43 char *desc;
44 char *long_desc;
45 char *topic;
43 struct list_head terms; /* HEAD struct parse_events_term -> list */ 46 struct list_head terms; /* HEAD struct parse_events_term -> list */
44 struct list_head list; /* ELEM */ 47 struct list_head list; /* ELEM */
45 char unit[UNIT_MAX_LEN+1]; 48 char unit[UNIT_MAX_LEN+1];
@@ -71,7 +74,8 @@ int perf_pmu__format_parse(char *dir, struct list_head *head);
71 74
72struct perf_pmu *perf_pmu__scan(struct perf_pmu *pmu); 75struct perf_pmu *perf_pmu__scan(struct perf_pmu *pmu);
73 76
74void print_pmu_events(const char *event_glob, bool name_only); 77void print_pmu_events(const char *event_glob, bool name_only, bool quiet,
78 bool long_desc);
75bool pmu_have_event(const char *pname, const char *name); 79bool pmu_have_event(const char *pname, const char *name);
76 80
77int perf_pmu__scan_file(struct perf_pmu *pmu, const char *name, const char *fmt, 81int perf_pmu__scan_file(struct perf_pmu *pmu, const char *name, const char *fmt,
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index fcfbef07b92d..d281ae2b54e8 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -213,7 +213,7 @@ static int convert_exec_to_group(const char *exec, char **result)
213 goto out; 213 goto out;
214 } 214 }
215 215
216 for (ptr2 = ptr1; ptr2 != '\0'; ptr2++) { 216 for (ptr2 = ptr1; *ptr2 != '\0'; ptr2++) {
217 if (!isalnum(*ptr2) && *ptr2 != '_') { 217 if (!isalnum(*ptr2) && *ptr2 != '_') {
218 *ptr2 = '\0'; 218 *ptr2 = '\0';
219 break; 219 break;
diff --git a/tools/perf/util/strbuf.h b/tools/perf/util/strbuf.h
index b268a6648a5d..318424ea561d 100644
--- a/tools/perf/util/strbuf.h
+++ b/tools/perf/util/strbuf.h
@@ -66,9 +66,8 @@ static inline ssize_t strbuf_avail(const struct strbuf *sb) {
66int strbuf_grow(struct strbuf *buf, size_t); 66int strbuf_grow(struct strbuf *buf, size_t);
67 67
68static inline int strbuf_setlen(struct strbuf *sb, size_t len) { 68static inline int strbuf_setlen(struct strbuf *sb, size_t len) {
69 int ret;
70 if (!sb->alloc) { 69 if (!sb->alloc) {
71 ret = strbuf_grow(sb, 0); 70 int ret = strbuf_grow(sb, 0);
72 if (ret) 71 if (ret)
73 return ret; 72 return ret;
74 } 73 }
diff --git a/tools/perf/util/thread.c b/tools/perf/util/thread.c
index 8b10a55410a2..f5af87f66663 100644
--- a/tools/perf/util/thread.c
+++ b/tools/perf/util/thread.c
@@ -14,13 +14,12 @@
14 14
15int thread__init_map_groups(struct thread *thread, struct machine *machine) 15int thread__init_map_groups(struct thread *thread, struct machine *machine)
16{ 16{
17 struct thread *leader;
18 pid_t pid = thread->pid_; 17 pid_t pid = thread->pid_;
19 18
20 if (pid == thread->tid || pid == -1) { 19 if (pid == thread->tid || pid == -1) {
21 thread->mg = map_groups__new(machine); 20 thread->mg = map_groups__new(machine);
22 } else { 21 } else {
23 leader = __machine__findnew_thread(machine, pid, pid); 22 struct thread *leader = __machine__findnew_thread(machine, pid, pid);
24 if (leader) { 23 if (leader) {
25 thread->mg = map_groups__get(leader->mg); 24 thread->mg = map_groups__get(leader->mg);
26 thread__put(leader); 25 thread__put(leader);
@@ -130,11 +129,10 @@ int __thread__set_comm(struct thread *thread, const char *str, u64 timestamp,
130 bool exec) 129 bool exec)
131{ 130{
132 struct comm *new, *curr = thread__comm(thread); 131 struct comm *new, *curr = thread__comm(thread);
133 int err;
134 132
135 /* Override the default :tid entry */ 133 /* Override the default :tid entry */
136 if (!thread->comm_set) { 134 if (!thread->comm_set) {
137 err = comm__override(curr, str, timestamp, exec); 135 int err = comm__override(curr, str, timestamp, exec);
138 if (err) 136 if (err)
139 return err; 137 return err;
140 } else { 138 } else {
@@ -270,10 +268,9 @@ static int thread__clone_map_groups(struct thread *thread,
270 268
271int thread__fork(struct thread *thread, struct thread *parent, u64 timestamp) 269int thread__fork(struct thread *thread, struct thread *parent, u64 timestamp)
272{ 270{
273 int err;
274
275 if (parent->comm_set) { 271 if (parent->comm_set) {
276 const char *comm = thread__comm_str(parent); 272 const char *comm = thread__comm_str(parent);
273 int err;
277 if (!comm) 274 if (!comm)
278 return -ENOMEM; 275 return -ENOMEM;
279 err = thread__set_comm(thread, comm, timestamp); 276 err = thread__set_comm(thread, comm, timestamp);