aboutsummaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
authorArnd Bergmann <arnd@arndb.de>2014-06-20 04:59:05 -0400
committerArnd Bergmann <arnd@arndb.de>2014-06-20 04:59:05 -0400
commit3b3dab5f1c4997f16d3865f6a44afcdeda797881 (patch)
treea50319bac5536728c8e3ad06d2fbf504e3662fd8 /tools
parent4cc29462cfa166b83bf6840a0b3247f505374355 (diff)
parent88a1c67ff6e6fe5d8391cd87ea89744a5f2728a4 (diff)
Merge tag 'sti-fixes-for-v3.16-rc1' of git://git.stlinux.com/devel/kernel/linux-sti into fixes
Merge "STi: DT fixes for v3.16" from Maxime Coquelin: Couple of DT fixes for STi platform issues discovered on V3.16-rc1. The fixes included are: - Ethernet clocks were wrongly defined for STiH415/416 platforms - STiH416 B2020 revision E DTS file name contained uppercase, change to lowercase. * tag 'sti-fixes-for-v3.16-rc1' of git://git.stlinux.com/devel/kernel/linux-sti: (2963 commits) ARM: stih41x: Rename stih416-b2020-revE.dts to stih416-b2020e.dts ARM: STi: DT: Properly define sti-ethclk & stmmaceth for stih415/6 Signed-off-by: Arnd Bergmann <arnd@arndb.de>
Diffstat (limited to 'tools')
-rw-r--r--tools/lib/api/fs/fs.c43
-rw-r--r--tools/net/bpf_exp.l1
-rw-r--r--tools/net/bpf_exp.y11
-rw-r--r--tools/net/bpf_jit_disasm.c20
-rw-r--r--tools/perf/Documentation/perf-record.txt3
-rw-r--r--tools/perf/Documentation/perf-report.txt7
-rw-r--r--tools/perf/Documentation/perf-top.txt8
-rw-r--r--tools/perf/Makefile.perf14
-rw-r--r--tools/perf/builtin-annotate.c5
-rw-r--r--tools/perf/builtin-diff.c2
-rw-r--r--tools/perf/builtin-record.c7
-rw-r--r--tools/perf/builtin-report.c210
-rw-r--r--tools/perf/builtin-sched.c2
-rw-r--r--tools/perf/builtin-top.c90
-rw-r--r--tools/perf/config/Makefile3
-rw-r--r--tools/perf/perf.c8
-rw-r--r--tools/perf/tests/builtin-test.c4
-rw-r--r--tools/perf/tests/hists_common.c52
-rw-r--r--tools/perf/tests/hists_common.h32
-rw-r--r--tools/perf/tests/hists_cumulate.c726
-rw-r--r--tools/perf/tests/hists_filter.c39
-rw-r--r--tools/perf/tests/hists_link.c36
-rw-r--r--tools/perf/tests/hists_output.c31
-rw-r--r--tools/perf/tests/tests.h1
-rw-r--r--tools/perf/ui/browser.c2
-rw-r--r--tools/perf/ui/browsers/hists.c73
-rw-r--r--tools/perf/ui/gtk/hists.c33
-rw-r--r--tools/perf/ui/hist.c119
-rw-r--r--tools/perf/ui/stdio/hist.c8
-rw-r--r--tools/perf/util/callchain.c45
-rw-r--r--tools/perf/util/callchain.h11
-rw-r--r--tools/perf/util/hist.c481
-rw-r--r--tools/perf/util/hist.h57
-rw-r--r--tools/perf/util/sort.c107
-rw-r--r--tools/perf/util/sort.h20
-rw-r--r--tools/perf/util/symbol.c11
-rw-r--r--tools/perf/util/symbol.h1
-rw-r--r--tools/testing/selftests/net/Makefile8
-rw-r--r--tools/testing/selftests/powerpc/Makefile2
-rw-r--r--tools/testing/selftests/powerpc/harness.c15
-rw-r--r--tools/testing/selftests/powerpc/pmu/Makefile26
-rw-r--r--tools/testing/selftests/powerpc/pmu/ebb/Makefile32
-rw-r--r--tools/testing/selftests/powerpc/pmu/ebb/back_to_back_ebbs_test.c106
-rw-r--r--tools/testing/selftests/powerpc/pmu/ebb/close_clears_pmcc_test.c59
-rw-r--r--tools/testing/selftests/powerpc/pmu/ebb/cpu_event_pinned_vs_ebb_test.c93
-rw-r--r--tools/testing/selftests/powerpc/pmu/ebb/cpu_event_vs_ebb_test.c89
-rw-r--r--tools/testing/selftests/powerpc/pmu/ebb/cycles_test.c58
-rw-r--r--tools/testing/selftests/powerpc/pmu/ebb/cycles_with_freeze_test.c117
-rw-r--r--tools/testing/selftests/powerpc/pmu/ebb/ebb.c727
-rw-r--r--tools/testing/selftests/powerpc/pmu/ebb/ebb.h78
-rw-r--r--tools/testing/selftests/powerpc/pmu/ebb/ebb_handler.S365
-rw-r--r--tools/testing/selftests/powerpc/pmu/ebb/ebb_on_child_test.c86
-rw-r--r--tools/testing/selftests/powerpc/pmu/ebb/ebb_on_willing_child_test.c92
-rw-r--r--tools/testing/selftests/powerpc/pmu/ebb/ebb_vs_cpu_event_test.c86
-rw-r--r--tools/testing/selftests/powerpc/pmu/ebb/event_attributes_test.c131
-rw-r--r--tools/testing/selftests/powerpc/pmu/ebb/fixed_instruction_loop.S43
-rw-r--r--tools/testing/selftests/powerpc/pmu/ebb/fork_cleanup_test.c79
-rw-r--r--tools/testing/selftests/powerpc/pmu/ebb/instruction_count_test.c164
-rw-r--r--tools/testing/selftests/powerpc/pmu/ebb/lost_exception_test.c100
-rw-r--r--tools/testing/selftests/powerpc/pmu/ebb/multi_counter_test.c91
-rw-r--r--tools/testing/selftests/powerpc/pmu/ebb/multi_ebb_procs_test.c109
-rw-r--r--tools/testing/selftests/powerpc/pmu/ebb/no_handler_test.c61
-rw-r--r--tools/testing/selftests/powerpc/pmu/ebb/pmae_handling_test.c106
-rw-r--r--tools/testing/selftests/powerpc/pmu/ebb/pmc56_overflow_test.c93
-rw-r--r--tools/testing/selftests/powerpc/pmu/ebb/reg.h49
-rw-r--r--tools/testing/selftests/powerpc/pmu/ebb/reg_access_test.c39
-rw-r--r--tools/testing/selftests/powerpc/pmu/ebb/task_event_pinned_vs_ebb_test.c91
-rw-r--r--tools/testing/selftests/powerpc/pmu/ebb/task_event_vs_ebb_test.c83
-rw-r--r--tools/testing/selftests/powerpc/pmu/ebb/trace.c300
-rw-r--r--tools/testing/selftests/powerpc/pmu/ebb/trace.h41
-rw-r--r--tools/testing/selftests/powerpc/pmu/event.c26
-rw-r--r--tools/testing/selftests/powerpc/pmu/event.h4
-rw-r--r--tools/testing/selftests/powerpc/pmu/lib.c252
-rw-r--r--tools/testing/selftests/powerpc/pmu/lib.h41
-rw-r--r--tools/testing/selftests/powerpc/pmu/loop.S73
-rw-r--r--tools/testing/selftests/powerpc/subunit.h5
-rw-r--r--tools/testing/selftests/powerpc/tm/Makefile15
-rw-r--r--tools/testing/selftests/powerpc/tm/tm-resched-dscr.c90
-rw-r--r--tools/testing/selftests/powerpc/utils.h12
79 files changed, 6013 insertions, 447 deletions
diff --git a/tools/lib/api/fs/fs.c b/tools/lib/api/fs/fs.c
index 5b5eb788996e..c1b49c36a951 100644
--- a/tools/lib/api/fs/fs.c
+++ b/tools/lib/api/fs/fs.c
@@ -1,8 +1,10 @@
1/* TODO merge/factor in debugfs.c here */ 1/* TODO merge/factor in debugfs.c here */
2 2
3#include <ctype.h>
3#include <errno.h> 4#include <errno.h>
4#include <stdbool.h> 5#include <stdbool.h>
5#include <stdio.h> 6#include <stdio.h>
7#include <stdlib.h>
6#include <string.h> 8#include <string.h>
7#include <sys/vfs.h> 9#include <sys/vfs.h>
8 10
@@ -96,12 +98,51 @@ static bool fs__check_mounts(struct fs *fs)
96 return false; 98 return false;
97} 99}
98 100
101static void mem_toupper(char *f, size_t len)
102{
103 while (len) {
104 *f = toupper(*f);
105 f++;
106 len--;
107 }
108}
109
110/*
111 * Check for "NAME_PATH" environment variable to override fs location (for
112 * testing). This matches the recommendation in Documentation/sysfs-rules.txt
113 * for SYSFS_PATH.
114 */
115static bool fs__env_override(struct fs *fs)
116{
117 char *override_path;
118 size_t name_len = strlen(fs->name);
119 /* name + "_PATH" + '\0' */
120 char upper_name[name_len + 5 + 1];
121 memcpy(upper_name, fs->name, name_len);
122 mem_toupper(upper_name, name_len);
123 strcpy(&upper_name[name_len], "_PATH");
124
125 override_path = getenv(upper_name);
126 if (!override_path)
127 return false;
128
129 fs->found = true;
130 strncpy(fs->path, override_path, sizeof(fs->path));
131 return true;
132}
133
99static const char *fs__get_mountpoint(struct fs *fs) 134static const char *fs__get_mountpoint(struct fs *fs)
100{ 135{
136 if (fs__env_override(fs))
137 return fs->path;
138
101 if (fs__check_mounts(fs)) 139 if (fs__check_mounts(fs))
102 return fs->path; 140 return fs->path;
103 141
104 return fs__read_mounts(fs) ? fs->path : NULL; 142 if (fs__read_mounts(fs))
143 return fs->path;
144
145 return NULL;
105} 146}
106 147
107static const char *fs__mountpoint(int idx) 148static const char *fs__mountpoint(int idx)
diff --git a/tools/net/bpf_exp.l b/tools/net/bpf_exp.l
index bf7be77ddd62..833a96611da6 100644
--- a/tools/net/bpf_exp.l
+++ b/tools/net/bpf_exp.l
@@ -92,6 +92,7 @@ extern void yyerror(const char *str);
92"#"?("cpu") { return K_CPU; } 92"#"?("cpu") { return K_CPU; }
93"#"?("vlan_tci") { return K_VLANT; } 93"#"?("vlan_tci") { return K_VLANT; }
94"#"?("vlan_pr") { return K_VLANP; } 94"#"?("vlan_pr") { return K_VLANP; }
95"#"?("rand") { return K_RAND; }
95 96
96":" { return ':'; } 97":" { return ':'; }
97"," { return ','; } 98"," { return ','; }
diff --git a/tools/net/bpf_exp.y b/tools/net/bpf_exp.y
index d15efc989ef5..e6306c51c26f 100644
--- a/tools/net/bpf_exp.y
+++ b/tools/net/bpf_exp.y
@@ -56,7 +56,7 @@ static void bpf_set_jmp_label(char *label, enum jmp_type type);
56%token OP_LDXI 56%token OP_LDXI
57 57
58%token K_PKT_LEN K_PROTO K_TYPE K_NLATTR K_NLATTR_NEST K_MARK K_QUEUE K_HATYPE 58%token K_PKT_LEN K_PROTO K_TYPE K_NLATTR K_NLATTR_NEST K_MARK K_QUEUE K_HATYPE
59%token K_RXHASH K_CPU K_IFIDX K_VLANT K_VLANP K_POFF 59%token K_RXHASH K_CPU K_IFIDX K_VLANT K_VLANP K_POFF K_RAND
60 60
61%token ':' ',' '[' ']' '(' ')' 'x' 'a' '+' 'M' '*' '&' '#' '%' 61%token ':' ',' '[' ']' '(' ')' 'x' 'a' '+' 'M' '*' '&' '#' '%'
62 62
@@ -164,6 +164,9 @@ ldb
164 | OP_LDB K_POFF { 164 | OP_LDB K_POFF {
165 bpf_set_curr_instr(BPF_LD | BPF_B | BPF_ABS, 0, 0, 165 bpf_set_curr_instr(BPF_LD | BPF_B | BPF_ABS, 0, 0,
166 SKF_AD_OFF + SKF_AD_PAY_OFFSET); } 166 SKF_AD_OFF + SKF_AD_PAY_OFFSET); }
167 | OP_LDB K_RAND {
168 bpf_set_curr_instr(BPF_LD | BPF_B | BPF_ABS, 0, 0,
169 SKF_AD_OFF + SKF_AD_RANDOM); }
167 ; 170 ;
168 171
169ldh 172ldh
@@ -212,6 +215,9 @@ ldh
212 | OP_LDH K_POFF { 215 | OP_LDH K_POFF {
213 bpf_set_curr_instr(BPF_LD | BPF_H | BPF_ABS, 0, 0, 216 bpf_set_curr_instr(BPF_LD | BPF_H | BPF_ABS, 0, 0,
214 SKF_AD_OFF + SKF_AD_PAY_OFFSET); } 217 SKF_AD_OFF + SKF_AD_PAY_OFFSET); }
218 | OP_LDH K_RAND {
219 bpf_set_curr_instr(BPF_LD | BPF_H | BPF_ABS, 0, 0,
220 SKF_AD_OFF + SKF_AD_RANDOM); }
215 ; 221 ;
216 222
217ldi 223ldi
@@ -265,6 +271,9 @@ ld
265 | OP_LD K_POFF { 271 | OP_LD K_POFF {
266 bpf_set_curr_instr(BPF_LD | BPF_W | BPF_ABS, 0, 0, 272 bpf_set_curr_instr(BPF_LD | BPF_W | BPF_ABS, 0, 0,
267 SKF_AD_OFF + SKF_AD_PAY_OFFSET); } 273 SKF_AD_OFF + SKF_AD_PAY_OFFSET); }
274 | OP_LD K_RAND {
275 bpf_set_curr_instr(BPF_LD | BPF_W | BPF_ABS, 0, 0,
276 SKF_AD_OFF + SKF_AD_RANDOM); }
268 | OP_LD 'M' '[' number ']' { 277 | OP_LD 'M' '[' number ']' {
269 bpf_set_curr_instr(BPF_LD | BPF_MEM, 0, 0, $4); } 278 bpf_set_curr_instr(BPF_LD | BPF_MEM, 0, 0, $4); }
270 | OP_LD '[' 'x' '+' number ']' { 279 | OP_LD '[' 'x' '+' number ']' {
diff --git a/tools/net/bpf_jit_disasm.c b/tools/net/bpf_jit_disasm.c
index cfe0cdcda3de..c5baf9c591b7 100644
--- a/tools/net/bpf_jit_disasm.c
+++ b/tools/net/bpf_jit_disasm.c
@@ -43,8 +43,7 @@ static void get_exec_path(char *tpath, size_t size)
43 free(path); 43 free(path);
44} 44}
45 45
46static void get_asm_insns(uint8_t *image, size_t len, unsigned long base, 46static void get_asm_insns(uint8_t *image, size_t len, int opcodes)
47 int opcodes)
48{ 47{
49 int count, i, pc = 0; 48 int count, i, pc = 0;
50 char tpath[256]; 49 char tpath[256];
@@ -107,13 +106,13 @@ static void put_klog_buff(char *buff)
107} 106}
108 107
109static int get_last_jit_image(char *haystack, size_t hlen, 108static int get_last_jit_image(char *haystack, size_t hlen,
110 uint8_t *image, size_t ilen, 109 uint8_t *image, size_t ilen)
111 unsigned long *base)
112{ 110{
113 char *ptr, *pptr, *tmp; 111 char *ptr, *pptr, *tmp;
114 off_t off = 0; 112 off_t off = 0;
115 int ret, flen, proglen, pass, ulen = 0; 113 int ret, flen, proglen, pass, ulen = 0;
116 regmatch_t pmatch[1]; 114 regmatch_t pmatch[1];
115 unsigned long base;
117 regex_t regex; 116 regex_t regex;
118 117
119 if (hlen == 0) 118 if (hlen == 0)
@@ -136,7 +135,7 @@ static int get_last_jit_image(char *haystack, size_t hlen,
136 135
137 ptr = haystack + off - (pmatch[0].rm_eo - pmatch[0].rm_so); 136 ptr = haystack + off - (pmatch[0].rm_eo - pmatch[0].rm_so);
138 ret = sscanf(ptr, "flen=%d proglen=%d pass=%d image=%lx", 137 ret = sscanf(ptr, "flen=%d proglen=%d pass=%d image=%lx",
139 &flen, &proglen, &pass, base); 138 &flen, &proglen, &pass, &base);
140 if (ret != 4) 139 if (ret != 4)
141 return 0; 140 return 0;
142 141
@@ -162,7 +161,7 @@ static int get_last_jit_image(char *haystack, size_t hlen,
162 assert(ulen == proglen); 161 assert(ulen == proglen);
163 printf("%d bytes emitted from JIT compiler (pass:%d, flen:%d)\n", 162 printf("%d bytes emitted from JIT compiler (pass:%d, flen:%d)\n",
164 proglen, pass, flen); 163 proglen, pass, flen);
165 printf("%lx + <x>:\n", *base); 164 printf("%lx + <x>:\n", base);
166 165
167 regfree(&regex); 166 regfree(&regex);
168 return ulen; 167 return ulen;
@@ -172,8 +171,7 @@ int main(int argc, char **argv)
172{ 171{
173 int len, klen, opcodes = 0; 172 int len, klen, opcodes = 0;
174 char *kbuff; 173 char *kbuff;
175 unsigned long base; 174 static uint8_t image[32768];
176 uint8_t image[4096];
177 175
178 if (argc > 1) { 176 if (argc > 1) {
179 if (!strncmp("-o", argv[argc - 1], 2)) { 177 if (!strncmp("-o", argv[argc - 1], 2)) {
@@ -189,9 +187,9 @@ int main(int argc, char **argv)
189 187
190 kbuff = get_klog_buff(&klen); 188 kbuff = get_klog_buff(&klen);
191 189
192 len = get_last_jit_image(kbuff, klen, image, sizeof(image), &base); 190 len = get_last_jit_image(kbuff, klen, image, sizeof(image));
193 if (len > 0 && base > 0) 191 if (len > 0)
194 get_asm_insns(image, len, base, opcodes); 192 get_asm_insns(image, len, opcodes);
195 193
196 put_klog_buff(kbuff); 194 put_klog_buff(kbuff);
197 195
diff --git a/tools/perf/Documentation/perf-record.txt b/tools/perf/Documentation/perf-record.txt
index c71b0f36d9e8..d460049cae8e 100644
--- a/tools/perf/Documentation/perf-record.txt
+++ b/tools/perf/Documentation/perf-record.txt
@@ -184,9 +184,10 @@ following filters are defined:
184 - in_tx: only when the target is in a hardware transaction 184 - in_tx: only when the target is in a hardware transaction
185 - no_tx: only when the target is not in a hardware transaction 185 - no_tx: only when the target is not in a hardware transaction
186 - abort_tx: only when the target is a hardware transaction abort 186 - abort_tx: only when the target is a hardware transaction abort
187 - cond: conditional branches
187 188
188+ 189+
189The option requires at least one branch type among any, any_call, any_ret, ind_call. 190The option requires at least one branch type among any, any_call, any_ret, ind_call, cond.
190The privilege levels may be omitted, in which case, the privilege levels of the associated 191The privilege levels may be omitted, in which case, the privilege levels of the associated
191event are applied to the branch filter. Both kernel (k) and hypervisor (hv) privilege 192event are applied to the branch filter. Both kernel (k) and hypervisor (hv) privilege
192levels are subject to permissions. When sampling on multiple events, branch stack sampling 193levels are subject to permissions. When sampling on multiple events, branch stack sampling
diff --git a/tools/perf/Documentation/perf-report.txt b/tools/perf/Documentation/perf-report.txt
index a1b5185402d5..cefdf430d1b4 100644
--- a/tools/perf/Documentation/perf-report.txt
+++ b/tools/perf/Documentation/perf-report.txt
@@ -111,7 +111,7 @@ OPTIONS
111--fields=:: 111--fields=::
112 Specify output field - multiple keys can be specified in CSV format. 112 Specify output field - multiple keys can be specified in CSV format.
113 Following fields are available: 113 Following fields are available:
114 overhead, overhead_sys, overhead_us, sample and period. 114 overhead, overhead_sys, overhead_us, overhead_children, sample and period.
115 Also it can contain any sort key(s). 115 Also it can contain any sort key(s).
116 116
117 By default, every sort keys not specified in -F will be appended 117 By default, every sort keys not specified in -F will be appended
@@ -163,6 +163,11 @@ OPTIONS
163 163
164 Default: fractal,0.5,callee,function. 164 Default: fractal,0.5,callee,function.
165 165
166--children::
167 Accumulate callchain of children to parent entry so that then can
168 show up in the output. The output will have a new "Children" column
169 and will be sorted on the data. It requires callchains are recorded.
170
166--max-stack:: 171--max-stack::
167 Set the stack depth limit when parsing the callchain, anything 172 Set the stack depth limit when parsing the callchain, anything
168 beyond the specified depth will be ignored. This is a trade-off 173 beyond the specified depth will be ignored. This is a trade-off
diff --git a/tools/perf/Documentation/perf-top.txt b/tools/perf/Documentation/perf-top.txt
index dcfa54c851e9..180ae02137a5 100644
--- a/tools/perf/Documentation/perf-top.txt
+++ b/tools/perf/Documentation/perf-top.txt
@@ -119,7 +119,7 @@ Default is to monitor all CPUS.
119--fields=:: 119--fields=::
120 Specify output field - multiple keys can be specified in CSV format. 120 Specify output field - multiple keys can be specified in CSV format.
121 Following fields are available: 121 Following fields are available:
122 overhead, overhead_sys, overhead_us, sample and period. 122 overhead, overhead_sys, overhead_us, overhead_children, sample and period.
123 Also it can contain any sort key(s). 123 Also it can contain any sort key(s).
124 124
125 By default, every sort keys not specified in --field will be appended 125 By default, every sort keys not specified in --field will be appended
@@ -161,6 +161,12 @@ Default is to monitor all CPUS.
161 Setup and enable call-graph (stack chain/backtrace) recording, 161 Setup and enable call-graph (stack chain/backtrace) recording,
162 implies -g. 162 implies -g.
163 163
164--children::
165 Accumulate callchain of children to parent entry so that then can
166 show up in the output. The output will have a new "Children" column
167 and will be sorted on the data. It requires -g/--call-graph option
168 enabled.
169
164--max-stack:: 170--max-stack::
165 Set the stack depth limit when parsing the callchain, anything 171 Set the stack depth limit when parsing the callchain, anything
166 beyond the specified depth will be ignored. This is a trade-off 172 beyond the specified depth will be ignored. This is a trade-off
diff --git a/tools/perf/Makefile.perf b/tools/perf/Makefile.perf
index 02f0a4dd1a80..ae20edfcc3f7 100644
--- a/tools/perf/Makefile.perf
+++ b/tools/perf/Makefile.perf
@@ -400,6 +400,7 @@ LIB_OBJS += $(OUTPUT)tests/hists_common.o
400LIB_OBJS += $(OUTPUT)tests/hists_link.o 400LIB_OBJS += $(OUTPUT)tests/hists_link.o
401LIB_OBJS += $(OUTPUT)tests/hists_filter.o 401LIB_OBJS += $(OUTPUT)tests/hists_filter.o
402LIB_OBJS += $(OUTPUT)tests/hists_output.o 402LIB_OBJS += $(OUTPUT)tests/hists_output.o
403LIB_OBJS += $(OUTPUT)tests/hists_cumulate.o
403LIB_OBJS += $(OUTPUT)tests/python-use.o 404LIB_OBJS += $(OUTPUT)tests/python-use.o
404LIB_OBJS += $(OUTPUT)tests/bp_signal.o 405LIB_OBJS += $(OUTPUT)tests/bp_signal.o
405LIB_OBJS += $(OUTPUT)tests/bp_signal_overflow.o 406LIB_OBJS += $(OUTPUT)tests/bp_signal_overflow.o
@@ -788,8 +789,8 @@ help:
788 @echo '' 789 @echo ''
789 @echo 'Perf install targets:' 790 @echo 'Perf install targets:'
790 @echo ' NOTE: documentation build requires asciidoc, xmlto packages to be installed' 791 @echo ' NOTE: documentation build requires asciidoc, xmlto packages to be installed'
791 @echo ' HINT: use "make prefix=<path> <install target>" to install to a particular' 792 @echo ' HINT: use "prefix" or "DESTDIR" to install to a particular'
792 @echo ' path like make prefix=/usr/local install install-doc' 793 @echo ' path like "make prefix=/usr/local install install-doc"'
793 @echo ' install - install compiled binaries' 794 @echo ' install - install compiled binaries'
794 @echo ' install-doc - install *all* documentation' 795 @echo ' install-doc - install *all* documentation'
795 @echo ' install-man - install manpage documentation' 796 @echo ' install-man - install manpage documentation'
@@ -814,17 +815,20 @@ INSTALL_DOC_TARGETS += quick-install-doc quick-install-man quick-install-html
814$(DOC_TARGETS): 815$(DOC_TARGETS):
815 $(QUIET_SUBDIR0)Documentation $(QUIET_SUBDIR1) $(@:doc=all) 816 $(QUIET_SUBDIR0)Documentation $(QUIET_SUBDIR1) $(@:doc=all)
816 817
818TAG_FOLDERS= . ../lib/traceevent ../lib/api ../lib/symbol
819TAG_FILES= ../../include/uapi/linux/perf_event.h
820
817TAGS: 821TAGS:
818 $(RM) TAGS 822 $(RM) TAGS
819 $(FIND) . -name '*.[hcS]' -print | xargs etags -a 823 $(FIND) $(TAG_FOLDERS) -name '*.[hcS]' -print | xargs etags -a $(TAG_FILES)
820 824
821tags: 825tags:
822 $(RM) tags 826 $(RM) tags
823 $(FIND) . -name '*.[hcS]' -print | xargs ctags -a 827 $(FIND) $(TAG_FOLDERS) -name '*.[hcS]' -print | xargs ctags -a $(TAG_FILES)
824 828
825cscope: 829cscope:
826 $(RM) cscope* 830 $(RM) cscope*
827 $(FIND) . -name '*.[hcS]' -print | xargs cscope -b 831 $(FIND) $(TAG_FOLDERS) -name '*.[hcS]' -print | xargs cscope -b $(TAG_FILES)
828 832
829### Detect prefix changes 833### Detect prefix changes
830TRACK_CFLAGS = $(subst ','\'',$(CFLAGS)):\ 834TRACK_CFLAGS = $(subst ','\'',$(CFLAGS)):\
diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c
index d30d2c2e2a7a..1ec429fef2be 100644
--- a/tools/perf/builtin-annotate.c
+++ b/tools/perf/builtin-annotate.c
@@ -65,12 +65,13 @@ static int perf_evsel__add_sample(struct perf_evsel *evsel,
65 return 0; 65 return 0;
66 } 66 }
67 67
68 he = __hists__add_entry(&evsel->hists, al, NULL, NULL, NULL, 1, 1, 0); 68 he = __hists__add_entry(&evsel->hists, al, NULL, NULL, NULL, 1, 1, 0,
69 true);
69 if (he == NULL) 70 if (he == NULL)
70 return -ENOMEM; 71 return -ENOMEM;
71 72
72 ret = hist_entry__inc_addr_samples(he, evsel->idx, al->addr); 73 ret = hist_entry__inc_addr_samples(he, evsel->idx, al->addr);
73 hists__inc_nr_events(&evsel->hists, PERF_RECORD_SAMPLE); 74 hists__inc_nr_samples(&evsel->hists, true);
74 return ret; 75 return ret;
75} 76}
76 77
diff --git a/tools/perf/builtin-diff.c b/tools/perf/builtin-diff.c
index 8bff543acaab..9a5a035cb426 100644
--- a/tools/perf/builtin-diff.c
+++ b/tools/perf/builtin-diff.c
@@ -315,7 +315,7 @@ static int hists__add_entry(struct hists *hists,
315 u64 weight, u64 transaction) 315 u64 weight, u64 transaction)
316{ 316{
317 if (__hists__add_entry(hists, al, NULL, NULL, NULL, period, weight, 317 if (__hists__add_entry(hists, al, NULL, NULL, NULL, period, weight,
318 transaction) != NULL) 318 transaction, true) != NULL)
319 return 0; 319 return 0;
320 return -ENOMEM; 320 return -ENOMEM;
321} 321}
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index e4c85b8f46c2..378b85b731a7 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -454,7 +454,11 @@ static int __cmd_record(struct record *rec, int argc, const char **argv)
454 if (done) 454 if (done)
455 break; 455 break;
456 err = poll(rec->evlist->pollfd, rec->evlist->nr_fds, -1); 456 err = poll(rec->evlist->pollfd, rec->evlist->nr_fds, -1);
457 if (err < 0 && errno == EINTR) 457 /*
458 * Propagate error, only if there's any. Ignore positive
459 * number of returned events and interrupt error.
460 */
461 if (err > 0 || (err < 0 && errno == EINTR))
458 err = 0; 462 err = 0;
459 waking++; 463 waking++;
460 } 464 }
@@ -544,6 +548,7 @@ static const struct branch_mode branch_modes[] = {
544 BRANCH_OPT("abort_tx", PERF_SAMPLE_BRANCH_ABORT_TX), 548 BRANCH_OPT("abort_tx", PERF_SAMPLE_BRANCH_ABORT_TX),
545 BRANCH_OPT("in_tx", PERF_SAMPLE_BRANCH_IN_TX), 549 BRANCH_OPT("in_tx", PERF_SAMPLE_BRANCH_IN_TX),
546 BRANCH_OPT("no_tx", PERF_SAMPLE_BRANCH_NO_TX), 550 BRANCH_OPT("no_tx", PERF_SAMPLE_BRANCH_NO_TX),
551 BRANCH_OPT("cond", PERF_SAMPLE_BRANCH_COND),
547 BRANCH_END 552 BRANCH_END
548}; 553};
549 554
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
index bc0eec1ce4be..21d830bafff3 100644
--- a/tools/perf/builtin-report.c
+++ b/tools/perf/builtin-report.c
@@ -72,6 +72,10 @@ static int report__config(const char *var, const char *value, void *cb)
72 rep->min_percent = strtof(value, NULL); 72 rep->min_percent = strtof(value, NULL);
73 return 0; 73 return 0;
74 } 74 }
75 if (!strcmp(var, "report.children")) {
76 symbol_conf.cumulate_callchain = perf_config_bool(var, value);
77 return 0;
78 }
75 79
76 return perf_default_config(var, value, cb); 80 return perf_default_config(var, value, cb);
77} 81}
@@ -85,156 +89,52 @@ static void report__inc_stats(struct report *rep, struct hist_entry *he)
85 */ 89 */
86 if (he->stat.nr_events == 1) 90 if (he->stat.nr_events == 1)
87 rep->nr_entries++; 91 rep->nr_entries++;
88
89 /*
90 * Only counts number of samples at this stage as it's more
91 * natural to do it here and non-sample events are also
92 * counted in perf_session_deliver_event(). The dump_trace
93 * requires this info is ready before going to the output tree.
94 */
95 hists__inc_nr_events(he->hists, PERF_RECORD_SAMPLE);
96 if (!he->filtered)
97 he->hists->stats.nr_non_filtered_samples++;
98} 92}
99 93
100static int report__add_mem_hist_entry(struct report *rep, struct addr_location *al, 94static int hist_iter__report_callback(struct hist_entry_iter *iter,
101 struct perf_sample *sample, struct perf_evsel *evsel) 95 struct addr_location *al, bool single,
96 void *arg)
102{ 97{
103 struct symbol *parent = NULL; 98 int err = 0;
104 struct hist_entry *he; 99 struct report *rep = arg;
105 struct mem_info *mi, *mx; 100 struct hist_entry *he = iter->he;
106 uint64_t cost; 101 struct perf_evsel *evsel = iter->evsel;
107 int err = sample__resolve_callchain(sample, &parent, evsel, al, rep->max_stack); 102 struct mem_info *mi;
108 103 struct branch_info *bi;
109 if (err)
110 return err;
111 104
112 mi = sample__resolve_mem(sample, al); 105 report__inc_stats(rep, he);
113 if (!mi)
114 return -ENOMEM;
115 106
116 if (rep->hide_unresolved && !al->sym) 107 if (!ui__has_annotation())
117 return 0; 108 return 0;
118 109
119 cost = sample->weight; 110 if (sort__mode == SORT_MODE__BRANCH) {
120 if (!cost) 111 bi = he->branch_info;
121 cost = 1; 112 err = addr_map_symbol__inc_samples(&bi->from, evsel->idx);
122
123 /*
124 * must pass period=weight in order to get the correct
125 * sorting from hists__collapse_resort() which is solely
126 * based on periods. We want sorting be done on nr_events * weight
127 * and this is indirectly achieved by passing period=weight here
128 * and the he_stat__add_period() function.
129 */
130 he = __hists__add_entry(&evsel->hists, al, parent, NULL, mi,
131 cost, cost, 0);
132 if (!he)
133 return -ENOMEM;
134
135 if (ui__has_annotation()) {
136 err = hist_entry__inc_addr_samples(he, evsel->idx, al->addr);
137 if (err)
138 goto out;
139
140 mx = he->mem_info;
141 err = addr_map_symbol__inc_samples(&mx->daddr, evsel->idx);
142 if (err) 113 if (err)
143 goto out; 114 goto out;
144 }
145
146 report__inc_stats(rep, he);
147
148 err = hist_entry__append_callchain(he, sample);
149out:
150 return err;
151}
152
153static int report__add_branch_hist_entry(struct report *rep, struct addr_location *al,
154 struct perf_sample *sample, struct perf_evsel *evsel)
155{
156 struct symbol *parent = NULL;
157 unsigned i;
158 struct hist_entry *he;
159 struct branch_info *bi, *bx;
160 int err = sample__resolve_callchain(sample, &parent, evsel, al, rep->max_stack);
161 115
162 if (err) 116 err = addr_map_symbol__inc_samples(&bi->to, evsel->idx);
163 return err;
164
165 bi = sample__resolve_bstack(sample, al);
166 if (!bi)
167 return -ENOMEM;
168
169 for (i = 0; i < sample->branch_stack->nr; i++) {
170 if (rep->hide_unresolved && !(bi[i].from.sym && bi[i].to.sym))
171 continue;
172 117
173 err = -ENOMEM; 118 } else if (rep->mem_mode) {
174 119 mi = he->mem_info;
175 /* overwrite the 'al' to branch-to info */ 120 err = addr_map_symbol__inc_samples(&mi->daddr, evsel->idx);
176 al->map = bi[i].to.map; 121 if (err)
177 al->sym = bi[i].to.sym;
178 al->addr = bi[i].to.addr;
179 /*
180 * The report shows the percentage of total branches captured
181 * and not events sampled. Thus we use a pseudo period of 1.
182 */
183 he = __hists__add_entry(&evsel->hists, al, parent, &bi[i], NULL,
184 1, 1, 0);
185 if (he) {
186 if (ui__has_annotation()) {
187 bx = he->branch_info;
188 err = addr_map_symbol__inc_samples(&bx->from,
189 evsel->idx);
190 if (err)
191 goto out;
192
193 err = addr_map_symbol__inc_samples(&bx->to,
194 evsel->idx);
195 if (err)
196 goto out;
197 }
198 report__inc_stats(rep, he);
199 } else
200 goto out; 122 goto out;
201 }
202 err = 0;
203out:
204 free(bi);
205 return err;
206}
207
208static int report__add_hist_entry(struct report *rep, struct perf_evsel *evsel,
209 struct addr_location *al, struct perf_sample *sample)
210{
211 struct symbol *parent = NULL;
212 struct hist_entry *he;
213 int err = sample__resolve_callchain(sample, &parent, evsel, al, rep->max_stack);
214
215 if (err)
216 return err;
217 123
218 he = __hists__add_entry(&evsel->hists, al, parent, NULL, NULL,
219 sample->period, sample->weight,
220 sample->transaction);
221 if (he == NULL)
222 return -ENOMEM;
223
224 err = hist_entry__append_callchain(he, sample);
225 if (err)
226 goto out;
227
228 if (ui__has_annotation())
229 err = hist_entry__inc_addr_samples(he, evsel->idx, al->addr); 124 err = hist_entry__inc_addr_samples(he, evsel->idx, al->addr);
230 125
231 report__inc_stats(rep, he); 126 } else if (symbol_conf.cumulate_callchain) {
127 if (single)
128 err = hist_entry__inc_addr_samples(he, evsel->idx,
129 al->addr);
130 } else {
131 err = hist_entry__inc_addr_samples(he, evsel->idx, al->addr);
132 }
232 133
233out: 134out:
234 return err; 135 return err;
235} 136}
236 137
237
238static int process_sample_event(struct perf_tool *tool, 138static int process_sample_event(struct perf_tool *tool,
239 union perf_event *event, 139 union perf_event *event,
240 struct perf_sample *sample, 140 struct perf_sample *sample,
@@ -243,6 +143,10 @@ static int process_sample_event(struct perf_tool *tool,
243{ 143{
244 struct report *rep = container_of(tool, struct report, tool); 144 struct report *rep = container_of(tool, struct report, tool);
245 struct addr_location al; 145 struct addr_location al;
146 struct hist_entry_iter iter = {
147 .hide_unresolved = rep->hide_unresolved,
148 .add_entry_cb = hist_iter__report_callback,
149 };
246 int ret; 150 int ret;
247 151
248 if (perf_event__preprocess_sample(event, machine, &al, sample) < 0) { 152 if (perf_event__preprocess_sample(event, machine, &al, sample) < 0) {
@@ -257,22 +161,23 @@ static int process_sample_event(struct perf_tool *tool,
257 if (rep->cpu_list && !test_bit(sample->cpu, rep->cpu_bitmap)) 161 if (rep->cpu_list && !test_bit(sample->cpu, rep->cpu_bitmap))
258 return 0; 162 return 0;
259 163
260 if (sort__mode == SORT_MODE__BRANCH) { 164 if (sort__mode == SORT_MODE__BRANCH)
261 ret = report__add_branch_hist_entry(rep, &al, sample, evsel); 165 iter.ops = &hist_iter_branch;
262 if (ret < 0) 166 else if (rep->mem_mode)
263 pr_debug("problem adding lbr entry, skipping event\n"); 167 iter.ops = &hist_iter_mem;
264 } else if (rep->mem_mode == 1) { 168 else if (symbol_conf.cumulate_callchain)
265 ret = report__add_mem_hist_entry(rep, &al, sample, evsel); 169 iter.ops = &hist_iter_cumulative;
266 if (ret < 0) 170 else
267 pr_debug("problem adding mem entry, skipping event\n"); 171 iter.ops = &hist_iter_normal;
268 } else { 172
269 if (al.map != NULL) 173 if (al.map != NULL)
270 al.map->dso->hit = 1; 174 al.map->dso->hit = 1;
175
176 ret = hist_entry_iter__add(&iter, &al, evsel, sample, rep->max_stack,
177 rep);
178 if (ret < 0)
179 pr_debug("problem adding hist entry, skipping event\n");
271 180
272 ret = report__add_hist_entry(rep, evsel, &al, sample);
273 if (ret < 0)
274 pr_debug("problem incrementing symbol period, skipping event\n");
275 }
276 return ret; 181 return ret;
277} 182}
278 183
@@ -329,6 +234,14 @@ static int report__setup_sample_type(struct report *rep)
329 } 234 }
330 } 235 }
331 236
237 if (symbol_conf.cumulate_callchain) {
238 /* Silently ignore if callchain is missing */
239 if (!(sample_type & PERF_SAMPLE_CALLCHAIN)) {
240 symbol_conf.cumulate_callchain = false;
241 perf_hpp__cancel_cumulate();
242 }
243 }
244
332 if (sort__mode == SORT_MODE__BRANCH) { 245 if (sort__mode == SORT_MODE__BRANCH) {
333 if (!is_pipe && 246 if (!is_pipe &&
334 !(sample_type & PERF_SAMPLE_BRANCH_STACK)) { 247 !(sample_type & PERF_SAMPLE_BRANCH_STACK)) {
@@ -712,6 +625,8 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
712 OPT_CALLBACK_DEFAULT('g', "call-graph", &report, "output_type,min_percent[,print_limit],call_order", 625 OPT_CALLBACK_DEFAULT('g', "call-graph", &report, "output_type,min_percent[,print_limit],call_order",
713 "Display callchains using output_type (graph, flat, fractal, or none) , min percent threshold, optional print limit, callchain order, key (function or address). " 626 "Display callchains using output_type (graph, flat, fractal, or none) , min percent threshold, optional print limit, callchain order, key (function or address). "
714 "Default: fractal,0.5,callee,function", &report_parse_callchain_opt, callchain_default_opt), 627 "Default: fractal,0.5,callee,function", &report_parse_callchain_opt, callchain_default_opt),
628 OPT_BOOLEAN(0, "children", &symbol_conf.cumulate_callchain,
629 "Accumulate callchains of children and show total overhead as well"),
715 OPT_INTEGER(0, "max-stack", &report.max_stack, 630 OPT_INTEGER(0, "max-stack", &report.max_stack,
716 "Set the maximum stack depth when parsing the callchain, " 631 "Set the maximum stack depth when parsing the callchain, "
717 "anything beyond the specified depth will be ignored. " 632 "anything beyond the specified depth will be ignored. "
@@ -804,8 +719,10 @@ repeat:
804 has_br_stack = perf_header__has_feat(&session->header, 719 has_br_stack = perf_header__has_feat(&session->header,
805 HEADER_BRANCH_STACK); 720 HEADER_BRANCH_STACK);
806 721
807 if (branch_mode == -1 && has_br_stack) 722 if (branch_mode == -1 && has_br_stack) {
808 sort__mode = SORT_MODE__BRANCH; 723 sort__mode = SORT_MODE__BRANCH;
724 symbol_conf.cumulate_callchain = false;
725 }
809 726
810 if (report.mem_mode) { 727 if (report.mem_mode) {
811 if (sort__mode == SORT_MODE__BRANCH) { 728 if (sort__mode == SORT_MODE__BRANCH) {
@@ -813,6 +730,7 @@ repeat:
813 goto error; 730 goto error;
814 } 731 }
815 sort__mode = SORT_MODE__MEMORY; 732 sort__mode = SORT_MODE__MEMORY;
733 symbol_conf.cumulate_callchain = false;
816 } 734 }
817 735
818 if (setup_sorting() < 0) { 736 if (setup_sorting() < 0) {
diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c
index d7176830b9b2..c38d06c04775 100644
--- a/tools/perf/builtin-sched.c
+++ b/tools/perf/builtin-sched.c
@@ -1428,7 +1428,7 @@ static int perf_sched__process_tracepoint_sample(struct perf_tool *tool __maybe_
1428 int err = 0; 1428 int err = 0;
1429 1429
1430 evsel->hists.stats.total_period += sample->period; 1430 evsel->hists.stats.total_period += sample->period;
1431 hists__inc_nr_events(&evsel->hists, PERF_RECORD_SAMPLE); 1431 hists__inc_nr_samples(&evsel->hists, true);
1432 1432
1433 if (evsel->handler != NULL) { 1433 if (evsel->handler != NULL) {
1434 tracepoint_handler f = evsel->handler; 1434 tracepoint_handler f = evsel->handler;
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c
index 5b389ce4cd15..377971dc89a3 100644
--- a/tools/perf/builtin-top.c
+++ b/tools/perf/builtin-top.c
@@ -196,6 +196,12 @@ static void perf_top__record_precise_ip(struct perf_top *top,
196 196
197 pthread_mutex_unlock(&notes->lock); 197 pthread_mutex_unlock(&notes->lock);
198 198
199 /*
200 * This function is now called with he->hists->lock held.
201 * Release it before going to sleep.
202 */
203 pthread_mutex_unlock(&he->hists->lock);
204
199 if (err == -ERANGE && !he->ms.map->erange_warned) 205 if (err == -ERANGE && !he->ms.map->erange_warned)
200 ui__warn_map_erange(he->ms.map, sym, ip); 206 ui__warn_map_erange(he->ms.map, sym, ip);
201 else if (err == -ENOMEM) { 207 else if (err == -ENOMEM) {
@@ -203,6 +209,8 @@ static void perf_top__record_precise_ip(struct perf_top *top,
203 sym->name); 209 sym->name);
204 sleep(1); 210 sleep(1);
205 } 211 }
212
213 pthread_mutex_lock(&he->hists->lock);
206} 214}
207 215
208static void perf_top__show_details(struct perf_top *top) 216static void perf_top__show_details(struct perf_top *top)
@@ -238,27 +246,6 @@ out_unlock:
238 pthread_mutex_unlock(&notes->lock); 246 pthread_mutex_unlock(&notes->lock);
239} 247}
240 248
241static struct hist_entry *perf_evsel__add_hist_entry(struct perf_evsel *evsel,
242 struct addr_location *al,
243 struct perf_sample *sample)
244{
245 struct hist_entry *he;
246
247 pthread_mutex_lock(&evsel->hists.lock);
248 he = __hists__add_entry(&evsel->hists, al, NULL, NULL, NULL,
249 sample->period, sample->weight,
250 sample->transaction);
251 pthread_mutex_unlock(&evsel->hists.lock);
252 if (he == NULL)
253 return NULL;
254
255 hists__inc_nr_events(&evsel->hists, PERF_RECORD_SAMPLE);
256 if (!he->filtered)
257 evsel->hists.stats.nr_non_filtered_samples++;
258
259 return he;
260}
261
262static void perf_top__print_sym_table(struct perf_top *top) 249static void perf_top__print_sym_table(struct perf_top *top)
263{ 250{
264 char bf[160]; 251 char bf[160];
@@ -662,6 +649,26 @@ static int symbol_filter(struct map *map __maybe_unused, struct symbol *sym)
662 return 0; 649 return 0;
663} 650}
664 651
652static int hist_iter__top_callback(struct hist_entry_iter *iter,
653 struct addr_location *al, bool single,
654 void *arg)
655{
656 struct perf_top *top = arg;
657 struct hist_entry *he = iter->he;
658 struct perf_evsel *evsel = iter->evsel;
659
660 if (sort__has_sym && single) {
661 u64 ip = al->addr;
662
663 if (al->map)
664 ip = al->map->unmap_ip(al->map, ip);
665
666 perf_top__record_precise_ip(top, he, evsel->idx, ip);
667 }
668
669 return 0;
670}
671
665static void perf_event__process_sample(struct perf_tool *tool, 672static void perf_event__process_sample(struct perf_tool *tool,
666 const union perf_event *event, 673 const union perf_event *event,
667 struct perf_evsel *evsel, 674 struct perf_evsel *evsel,
@@ -669,8 +676,6 @@ static void perf_event__process_sample(struct perf_tool *tool,
669 struct machine *machine) 676 struct machine *machine)
670{ 677{
671 struct perf_top *top = container_of(tool, struct perf_top, tool); 678 struct perf_top *top = container_of(tool, struct perf_top, tool);
672 struct symbol *parent = NULL;
673 u64 ip = sample->ip;
674 struct addr_location al; 679 struct addr_location al;
675 int err; 680 int err;
676 681
@@ -745,25 +750,23 @@ static void perf_event__process_sample(struct perf_tool *tool,
745 } 750 }
746 751
747 if (al.sym == NULL || !al.sym->ignore) { 752 if (al.sym == NULL || !al.sym->ignore) {
748 struct hist_entry *he; 753 struct hist_entry_iter iter = {
754 .add_entry_cb = hist_iter__top_callback,
755 };
749 756
750 err = sample__resolve_callchain(sample, &parent, evsel, &al, 757 if (symbol_conf.cumulate_callchain)
751 top->max_stack); 758 iter.ops = &hist_iter_cumulative;
752 if (err) 759 else
753 return; 760 iter.ops = &hist_iter_normal;
754 761
755 he = perf_evsel__add_hist_entry(evsel, &al, sample); 762 pthread_mutex_lock(&evsel->hists.lock);
756 if (he == NULL) {
757 pr_err("Problem incrementing symbol period, skipping event\n");
758 return;
759 }
760 763
761 err = hist_entry__append_callchain(he, sample); 764 err = hist_entry_iter__add(&iter, &al, evsel, sample,
762 if (err) 765 top->max_stack, top);
763 return; 766 if (err < 0)
767 pr_err("Problem incrementing symbol period, skipping event\n");
764 768
765 if (sort__has_sym) 769 pthread_mutex_unlock(&evsel->hists.lock);
766 perf_top__record_precise_ip(top, he, evsel->idx, ip);
767 } 770 }
768 771
769 return; 772 return;
@@ -1001,6 +1004,10 @@ static int perf_top_config(const char *var, const char *value, void *cb)
1001 1004
1002 if (!strcmp(var, "top.call-graph")) 1005 if (!strcmp(var, "top.call-graph"))
1003 return record_parse_callchain(value, &top->record_opts); 1006 return record_parse_callchain(value, &top->record_opts);
1007 if (!strcmp(var, "top.children")) {
1008 symbol_conf.cumulate_callchain = perf_config_bool(var, value);
1009 return 0;
1010 }
1004 1011
1005 return perf_default_config(var, value, cb); 1012 return perf_default_config(var, value, cb);
1006} 1013}
@@ -1095,6 +1102,8 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused)
1095 OPT_CALLBACK(0, "call-graph", &top.record_opts, 1102 OPT_CALLBACK(0, "call-graph", &top.record_opts,
1096 "mode[,dump_size]", record_callchain_help, 1103 "mode[,dump_size]", record_callchain_help,
1097 &parse_callchain_opt), 1104 &parse_callchain_opt),
1105 OPT_BOOLEAN(0, "children", &symbol_conf.cumulate_callchain,
1106 "Accumulate callchains of children and show total overhead as well"),
1098 OPT_INTEGER(0, "max-stack", &top.max_stack, 1107 OPT_INTEGER(0, "max-stack", &top.max_stack,
1099 "Set the maximum stack depth when parsing the callchain. " 1108 "Set the maximum stack depth when parsing the callchain. "
1100 "Default: " __stringify(PERF_MAX_STACK_DEPTH)), 1109 "Default: " __stringify(PERF_MAX_STACK_DEPTH)),
@@ -1200,6 +1209,11 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused)
1200 1209
1201 top.sym_evsel = perf_evlist__first(top.evlist); 1210 top.sym_evsel = perf_evlist__first(top.evlist);
1202 1211
1212 if (!symbol_conf.use_callchain) {
1213 symbol_conf.cumulate_callchain = false;
1214 perf_hpp__cancel_cumulate();
1215 }
1216
1203 symbol_conf.priv_size = sizeof(struct annotation); 1217 symbol_conf.priv_size = sizeof(struct annotation);
1204 1218
1205 symbol_conf.try_vmlinux_path = (symbol_conf.vmlinux_name == NULL); 1219 symbol_conf.try_vmlinux_path = (symbol_conf.vmlinux_name == NULL);
diff --git a/tools/perf/config/Makefile b/tools/perf/config/Makefile
index 729bbdf5cec7..4f100b54ba8b 100644
--- a/tools/perf/config/Makefile
+++ b/tools/perf/config/Makefile
@@ -447,6 +447,7 @@ else
447 ifneq ($(feature-libperl), 1) 447 ifneq ($(feature-libperl), 1)
448 CFLAGS += -DNO_LIBPERL 448 CFLAGS += -DNO_LIBPERL
449 NO_LIBPERL := 1 449 NO_LIBPERL := 1
450 msg := $(warning Missing perl devel files. Disabling perl scripting support, consider installing perl-ExtUtils-Embed);
450 else 451 else
451 LDFLAGS += $(PERL_EMBED_LDFLAGS) 452 LDFLAGS += $(PERL_EMBED_LDFLAGS)
452 EXTLIBS += $(PERL_EMBED_LIBADD) 453 EXTLIBS += $(PERL_EMBED_LIBADD)
@@ -599,7 +600,7 @@ endif
599 600
600# Make the path relative to DESTDIR, not to prefix 601# Make the path relative to DESTDIR, not to prefix
601ifndef DESTDIR 602ifndef DESTDIR
602prefix = $(HOME) 603prefix ?= $(HOME)
603endif 604endif
604bindir_relative = bin 605bindir_relative = bin
605bindir = $(prefix)/$(bindir_relative) 606bindir = $(prefix)/$(bindir_relative)
diff --git a/tools/perf/perf.c b/tools/perf/perf.c
index 431798a4110d..78f7b920e548 100644
--- a/tools/perf/perf.c
+++ b/tools/perf/perf.c
@@ -481,14 +481,18 @@ int main(int argc, const char **argv)
481 fprintf(stderr, "cannot handle %s internally", cmd); 481 fprintf(stderr, "cannot handle %s internally", cmd);
482 goto out; 482 goto out;
483 } 483 }
484#ifdef HAVE_LIBAUDIT_SUPPORT
485 if (!prefixcmp(cmd, "trace")) { 484 if (!prefixcmp(cmd, "trace")) {
485#ifdef HAVE_LIBAUDIT_SUPPORT
486 set_buildid_dir(); 486 set_buildid_dir();
487 setup_path(); 487 setup_path();
488 argv[0] = "trace"; 488 argv[0] = "trace";
489 return cmd_trace(argc, argv, NULL); 489 return cmd_trace(argc, argv, NULL);
490 } 490#else
491 fprintf(stderr,
492 "trace command not available: missing audit-libs devel package at build time.\n");
493 goto out;
491#endif 494#endif
495 }
492 /* Look for flags.. */ 496 /* Look for flags.. */
493 argv++; 497 argv++;
494 argc--; 498 argc--;
diff --git a/tools/perf/tests/builtin-test.c b/tools/perf/tests/builtin-test.c
index 831f52cae197..802e3cd50f6f 100644
--- a/tools/perf/tests/builtin-test.c
+++ b/tools/perf/tests/builtin-test.c
@@ -140,6 +140,10 @@ static struct test {
140 .func = test__hists_output, 140 .func = test__hists_output,
141 }, 141 },
142 { 142 {
143 .desc = "Test cumulation of child hist entries",
144 .func = test__hists_cumulate,
145 },
146 {
143 .func = NULL, 147 .func = NULL,
144 }, 148 },
145}; 149};
diff --git a/tools/perf/tests/hists_common.c b/tools/perf/tests/hists_common.c
index e4e01aadc3be..a62c09134516 100644
--- a/tools/perf/tests/hists_common.c
+++ b/tools/perf/tests/hists_common.c
@@ -12,9 +12,9 @@ static struct {
12 u32 pid; 12 u32 pid;
13 const char *comm; 13 const char *comm;
14} fake_threads[] = { 14} fake_threads[] = {
15 { 100, "perf" }, 15 { FAKE_PID_PERF1, "perf" },
16 { 200, "perf" }, 16 { FAKE_PID_PERF2, "perf" },
17 { 300, "bash" }, 17 { FAKE_PID_BASH, "bash" },
18}; 18};
19 19
20static struct { 20static struct {
@@ -22,15 +22,15 @@ static struct {
22 u64 start; 22 u64 start;
23 const char *filename; 23 const char *filename;
24} fake_mmap_info[] = { 24} fake_mmap_info[] = {
25 { 100, 0x40000, "perf" }, 25 { FAKE_PID_PERF1, FAKE_MAP_PERF, "perf" },
26 { 100, 0x50000, "libc" }, 26 { FAKE_PID_PERF1, FAKE_MAP_LIBC, "libc" },
27 { 100, 0xf0000, "[kernel]" }, 27 { FAKE_PID_PERF1, FAKE_MAP_KERNEL, "[kernel]" },
28 { 200, 0x40000, "perf" }, 28 { FAKE_PID_PERF2, FAKE_MAP_PERF, "perf" },
29 { 200, 0x50000, "libc" }, 29 { FAKE_PID_PERF2, FAKE_MAP_LIBC, "libc" },
30 { 200, 0xf0000, "[kernel]" }, 30 { FAKE_PID_PERF2, FAKE_MAP_KERNEL, "[kernel]" },
31 { 300, 0x40000, "bash" }, 31 { FAKE_PID_BASH, FAKE_MAP_BASH, "bash" },
32 { 300, 0x50000, "libc" }, 32 { FAKE_PID_BASH, FAKE_MAP_LIBC, "libc" },
33 { 300, 0xf0000, "[kernel]" }, 33 { FAKE_PID_BASH, FAKE_MAP_KERNEL, "[kernel]" },
34}; 34};
35 35
36struct fake_sym { 36struct fake_sym {
@@ -40,27 +40,30 @@ struct fake_sym {
40}; 40};
41 41
42static struct fake_sym perf_syms[] = { 42static struct fake_sym perf_syms[] = {
43 { 700, 100, "main" }, 43 { FAKE_SYM_OFFSET1, FAKE_SYM_LENGTH, "main" },
44 { 800, 100, "run_command" }, 44 { FAKE_SYM_OFFSET2, FAKE_SYM_LENGTH, "run_command" },
45 { 900, 100, "cmd_record" }, 45 { FAKE_SYM_OFFSET3, FAKE_SYM_LENGTH, "cmd_record" },
46}; 46};
47 47
48static struct fake_sym bash_syms[] = { 48static struct fake_sym bash_syms[] = {
49 { 700, 100, "main" }, 49 { FAKE_SYM_OFFSET1, FAKE_SYM_LENGTH, "main" },
50 { 800, 100, "xmalloc" }, 50 { FAKE_SYM_OFFSET2, FAKE_SYM_LENGTH, "xmalloc" },
51 { 900, 100, "xfree" }, 51 { FAKE_SYM_OFFSET3, FAKE_SYM_LENGTH, "xfree" },
52}; 52};
53 53
54static struct fake_sym libc_syms[] = { 54static struct fake_sym libc_syms[] = {
55 { 700, 100, "malloc" }, 55 { 700, 100, "malloc" },
56 { 800, 100, "free" }, 56 { 800, 100, "free" },
57 { 900, 100, "realloc" }, 57 { 900, 100, "realloc" },
58 { FAKE_SYM_OFFSET1, FAKE_SYM_LENGTH, "malloc" },
59 { FAKE_SYM_OFFSET2, FAKE_SYM_LENGTH, "free" },
60 { FAKE_SYM_OFFSET3, FAKE_SYM_LENGTH, "realloc" },
58}; 61};
59 62
60static struct fake_sym kernel_syms[] = { 63static struct fake_sym kernel_syms[] = {
61 { 700, 100, "schedule" }, 64 { FAKE_SYM_OFFSET1, FAKE_SYM_LENGTH, "schedule" },
62 { 800, 100, "page_fault" }, 65 { FAKE_SYM_OFFSET2, FAKE_SYM_LENGTH, "page_fault" },
63 { 900, 100, "sys_perf_event_open" }, 66 { FAKE_SYM_OFFSET3, FAKE_SYM_LENGTH, "sys_perf_event_open" },
64}; 67};
65 68
66static struct { 69static struct {
@@ -102,7 +105,7 @@ struct machine *setup_fake_machine(struct machines *machines)
102 .pid = fake_mmap_info[i].pid, 105 .pid = fake_mmap_info[i].pid,
103 .tid = fake_mmap_info[i].pid, 106 .tid = fake_mmap_info[i].pid,
104 .start = fake_mmap_info[i].start, 107 .start = fake_mmap_info[i].start,
105 .len = 0x1000ULL, 108 .len = FAKE_MAP_LENGTH,
106 .pgoff = 0ULL, 109 .pgoff = 0ULL,
107 }, 110 },
108 }; 111 };
@@ -193,10 +196,11 @@ void print_hists_out(struct hists *hists)
193 he = rb_entry(node, struct hist_entry, rb_node); 196 he = rb_entry(node, struct hist_entry, rb_node);
194 197
195 if (!he->filtered) { 198 if (!he->filtered) {
196 pr_info("%2d: entry: %8s:%5d [%-8s] %20s: period = %"PRIu64"\n", 199 pr_info("%2d: entry: %8s:%5d [%-8s] %20s: period = %"PRIu64"/%"PRIu64"\n",
197 i, thread__comm_str(he->thread), he->thread->tid, 200 i, thread__comm_str(he->thread), he->thread->tid,
198 he->ms.map->dso->short_name, 201 he->ms.map->dso->short_name,
199 he->ms.sym->name, he->stat.period); 202 he->ms.sym->name, he->stat.period,
203 he->stat_acc ? he->stat_acc->period : 0);
200 } 204 }
201 205
202 i++; 206 i++;
diff --git a/tools/perf/tests/hists_common.h b/tools/perf/tests/hists_common.h
index 1415ae69d7b6..888254e8665c 100644
--- a/tools/perf/tests/hists_common.h
+++ b/tools/perf/tests/hists_common.h
@@ -4,6 +4,34 @@
4struct machine; 4struct machine;
5struct machines; 5struct machines;
6 6
7#define FAKE_PID_PERF1 100
8#define FAKE_PID_PERF2 200
9#define FAKE_PID_BASH 300
10
11#define FAKE_MAP_PERF 0x400000
12#define FAKE_MAP_BASH 0x400000
13#define FAKE_MAP_LIBC 0x500000
14#define FAKE_MAP_KERNEL 0xf00000
15#define FAKE_MAP_LENGTH 0x100000
16
17#define FAKE_SYM_OFFSET1 700
18#define FAKE_SYM_OFFSET2 800
19#define FAKE_SYM_OFFSET3 900
20#define FAKE_SYM_LENGTH 100
21
22#define FAKE_IP_PERF_MAIN FAKE_MAP_PERF + FAKE_SYM_OFFSET1
23#define FAKE_IP_PERF_RUN_COMMAND FAKE_MAP_PERF + FAKE_SYM_OFFSET2
24#define FAKE_IP_PERF_CMD_RECORD FAKE_MAP_PERF + FAKE_SYM_OFFSET3
25#define FAKE_IP_BASH_MAIN FAKE_MAP_BASH + FAKE_SYM_OFFSET1
26#define FAKE_IP_BASH_XMALLOC FAKE_MAP_BASH + FAKE_SYM_OFFSET2
27#define FAKE_IP_BASH_XFREE FAKE_MAP_BASH + FAKE_SYM_OFFSET3
28#define FAKE_IP_LIBC_MALLOC FAKE_MAP_LIBC + FAKE_SYM_OFFSET1
29#define FAKE_IP_LIBC_FREE FAKE_MAP_LIBC + FAKE_SYM_OFFSET2
30#define FAKE_IP_LIBC_REALLOC FAKE_MAP_LIBC + FAKE_SYM_OFFSET3
31#define FAKE_IP_KERNEL_SCHEDULE FAKE_MAP_KERNEL + FAKE_SYM_OFFSET1
32#define FAKE_IP_KERNEL_PAGE_FAULT FAKE_MAP_KERNEL + FAKE_SYM_OFFSET2
33#define FAKE_IP_KERNEL_SYS_PERF_EVENT_OPEN FAKE_MAP_KERNEL + FAKE_SYM_OFFSET3
34
7/* 35/*
8 * The setup_fake_machine() provides a test environment which consists 36 * The setup_fake_machine() provides a test environment which consists
9 * of 3 processes that have 3 mappings and in turn, have 3 symbols 37 * of 3 processes that have 3 mappings and in turn, have 3 symbols
@@ -13,7 +41,7 @@ struct machines;
13 * ............. ............. ................... 41 * ............. ............. ...................
14 * perf: 100 perf main 42 * perf: 100 perf main
15 * perf: 100 perf run_command 43 * perf: 100 perf run_command
16 * perf: 100 perf comd_record 44 * perf: 100 perf cmd_record
17 * perf: 100 libc malloc 45 * perf: 100 libc malloc
18 * perf: 100 libc free 46 * perf: 100 libc free
19 * perf: 100 libc realloc 47 * perf: 100 libc realloc
@@ -22,7 +50,7 @@ struct machines;
22 * perf: 100 [kernel] sys_perf_event_open 50 * perf: 100 [kernel] sys_perf_event_open
23 * perf: 200 perf main 51 * perf: 200 perf main
24 * perf: 200 perf run_command 52 * perf: 200 perf run_command
25 * perf: 200 perf comd_record 53 * perf: 200 perf cmd_record
26 * perf: 200 libc malloc 54 * perf: 200 libc malloc
27 * perf: 200 libc free 55 * perf: 200 libc free
28 * perf: 200 libc realloc 56 * perf: 200 libc realloc
diff --git a/tools/perf/tests/hists_cumulate.c b/tools/perf/tests/hists_cumulate.c
new file mode 100644
index 000000000000..0ac240db2e24
--- /dev/null
+++ b/tools/perf/tests/hists_cumulate.c
@@ -0,0 +1,726 @@
1#include "perf.h"
2#include "util/debug.h"
3#include "util/symbol.h"
4#include "util/sort.h"
5#include "util/evsel.h"
6#include "util/evlist.h"
7#include "util/machine.h"
8#include "util/thread.h"
9#include "util/parse-events.h"
10#include "tests/tests.h"
11#include "tests/hists_common.h"
12
13struct sample {
14 u32 pid;
15 u64 ip;
16 struct thread *thread;
17 struct map *map;
18 struct symbol *sym;
19};
20
21/* For the numbers, see hists_common.c */
22static struct sample fake_samples[] = {
23 /* perf [kernel] schedule() */
24 { .pid = FAKE_PID_PERF1, .ip = FAKE_IP_KERNEL_SCHEDULE, },
25 /* perf [perf] main() */
26 { .pid = FAKE_PID_PERF1, .ip = FAKE_IP_PERF_MAIN, },
27 /* perf [perf] cmd_record() */
28 { .pid = FAKE_PID_PERF1, .ip = FAKE_IP_PERF_CMD_RECORD, },
29 /* perf [libc] malloc() */
30 { .pid = FAKE_PID_PERF1, .ip = FAKE_IP_LIBC_MALLOC, },
31 /* perf [libc] free() */
32 { .pid = FAKE_PID_PERF1, .ip = FAKE_IP_LIBC_FREE, },
33 /* perf [perf] main() */
34 { .pid = FAKE_PID_PERF2, .ip = FAKE_IP_PERF_MAIN, },
35 /* perf [kernel] page_fault() */
36 { .pid = FAKE_PID_PERF2, .ip = FAKE_IP_KERNEL_PAGE_FAULT, },
37 /* bash [bash] main() */
38 { .pid = FAKE_PID_BASH, .ip = FAKE_IP_BASH_MAIN, },
39 /* bash [bash] xmalloc() */
40 { .pid = FAKE_PID_BASH, .ip = FAKE_IP_BASH_XMALLOC, },
41 /* bash [kernel] page_fault() */
42 { .pid = FAKE_PID_BASH, .ip = FAKE_IP_KERNEL_PAGE_FAULT, },
43};
44
45/*
46 * Will be casted to struct ip_callchain which has all 64 bit entries
47 * of nr and ips[].
48 */
49static u64 fake_callchains[][10] = {
50 /* schedule => run_command => main */
51 { 3, FAKE_IP_KERNEL_SCHEDULE, FAKE_IP_PERF_RUN_COMMAND, FAKE_IP_PERF_MAIN, },
52 /* main */
53 { 1, FAKE_IP_PERF_MAIN, },
54 /* cmd_record => run_command => main */
55 { 3, FAKE_IP_PERF_CMD_RECORD, FAKE_IP_PERF_RUN_COMMAND, FAKE_IP_PERF_MAIN, },
56 /* malloc => cmd_record => run_command => main */
57 { 4, FAKE_IP_LIBC_MALLOC, FAKE_IP_PERF_CMD_RECORD, FAKE_IP_PERF_RUN_COMMAND,
58 FAKE_IP_PERF_MAIN, },
59 /* free => cmd_record => run_command => main */
60 { 4, FAKE_IP_LIBC_FREE, FAKE_IP_PERF_CMD_RECORD, FAKE_IP_PERF_RUN_COMMAND,
61 FAKE_IP_PERF_MAIN, },
62 /* main */
63 { 1, FAKE_IP_PERF_MAIN, },
64 /* page_fault => sys_perf_event_open => run_command => main */
65 { 4, FAKE_IP_KERNEL_PAGE_FAULT, FAKE_IP_KERNEL_SYS_PERF_EVENT_OPEN,
66 FAKE_IP_PERF_RUN_COMMAND, FAKE_IP_PERF_MAIN, },
67 /* main */
68 { 1, FAKE_IP_BASH_MAIN, },
69 /* xmalloc => malloc => xmalloc => malloc => xmalloc => main */
70 { 6, FAKE_IP_BASH_XMALLOC, FAKE_IP_LIBC_MALLOC, FAKE_IP_BASH_XMALLOC,
71 FAKE_IP_LIBC_MALLOC, FAKE_IP_BASH_XMALLOC, FAKE_IP_BASH_MAIN, },
72 /* page_fault => malloc => main */
73 { 3, FAKE_IP_KERNEL_PAGE_FAULT, FAKE_IP_LIBC_MALLOC, FAKE_IP_BASH_MAIN, },
74};
75
76static int add_hist_entries(struct hists *hists, struct machine *machine)
77{
78 struct addr_location al;
79 struct perf_evsel *evsel = hists_to_evsel(hists);
80 struct perf_sample sample = { .period = 1000, };
81 size_t i;
82
83 for (i = 0; i < ARRAY_SIZE(fake_samples); i++) {
84 const union perf_event event = {
85 .header = {
86 .misc = PERF_RECORD_MISC_USER,
87 },
88 };
89 struct hist_entry_iter iter = {
90 .hide_unresolved = false,
91 };
92
93 if (symbol_conf.cumulate_callchain)
94 iter.ops = &hist_iter_cumulative;
95 else
96 iter.ops = &hist_iter_normal;
97
98 sample.pid = fake_samples[i].pid;
99 sample.tid = fake_samples[i].pid;
100 sample.ip = fake_samples[i].ip;
101 sample.callchain = (struct ip_callchain *)fake_callchains[i];
102
103 if (perf_event__preprocess_sample(&event, machine, &al,
104 &sample) < 0)
105 goto out;
106
107 if (hist_entry_iter__add(&iter, &al, evsel, &sample,
108 PERF_MAX_STACK_DEPTH, NULL) < 0)
109 goto out;
110
111 fake_samples[i].thread = al.thread;
112 fake_samples[i].map = al.map;
113 fake_samples[i].sym = al.sym;
114 }
115
116 return TEST_OK;
117
118out:
119 pr_debug("Not enough memory for adding a hist entry\n");
120 return TEST_FAIL;
121}
122
123static void del_hist_entries(struct hists *hists)
124{
125 struct hist_entry *he;
126 struct rb_root *root_in;
127 struct rb_root *root_out;
128 struct rb_node *node;
129
130 if (sort__need_collapse)
131 root_in = &hists->entries_collapsed;
132 else
133 root_in = hists->entries_in;
134
135 root_out = &hists->entries;
136
137 while (!RB_EMPTY_ROOT(root_out)) {
138 node = rb_first(root_out);
139
140 he = rb_entry(node, struct hist_entry, rb_node);
141 rb_erase(node, root_out);
142 rb_erase(&he->rb_node_in, root_in);
143 hist_entry__free(he);
144 }
145}
146
147typedef int (*test_fn_t)(struct perf_evsel *, struct machine *);
148
149#define COMM(he) (thread__comm_str(he->thread))
150#define DSO(he) (he->ms.map->dso->short_name)
151#define SYM(he) (he->ms.sym->name)
152#define CPU(he) (he->cpu)
153#define PID(he) (he->thread->tid)
154#define DEPTH(he) (he->callchain->max_depth)
155#define CDSO(cl) (cl->ms.map->dso->short_name)
156#define CSYM(cl) (cl->ms.sym->name)
157
158struct result {
159 u64 children;
160 u64 self;
161 const char *comm;
162 const char *dso;
163 const char *sym;
164};
165
166struct callchain_result {
167 u64 nr;
168 struct {
169 const char *dso;
170 const char *sym;
171 } node[10];
172};
173
174static int do_test(struct hists *hists, struct result *expected, size_t nr_expected,
175 struct callchain_result *expected_callchain, size_t nr_callchain)
176{
177 char buf[32];
178 size_t i, c;
179 struct hist_entry *he;
180 struct rb_root *root;
181 struct rb_node *node;
182 struct callchain_node *cnode;
183 struct callchain_list *clist;
184
185 /*
186 * adding and deleting hist entries must be done outside of this
187 * function since TEST_ASSERT_VAL() returns in case of failure.
188 */
189 hists__collapse_resort(hists, NULL);
190 hists__output_resort(hists);
191
192 if (verbose > 2) {
193 pr_info("use callchain: %d, cumulate callchain: %d\n",
194 symbol_conf.use_callchain,
195 symbol_conf.cumulate_callchain);
196 print_hists_out(hists);
197 }
198
199 root = &hists->entries;
200 for (node = rb_first(root), i = 0;
201 node && (he = rb_entry(node, struct hist_entry, rb_node));
202 node = rb_next(node), i++) {
203 scnprintf(buf, sizeof(buf), "Invalid hist entry #%zd", i);
204
205 TEST_ASSERT_VAL("Incorrect number of hist entry",
206 i < nr_expected);
207 TEST_ASSERT_VAL(buf, he->stat.period == expected[i].self &&
208 !strcmp(COMM(he), expected[i].comm) &&
209 !strcmp(DSO(he), expected[i].dso) &&
210 !strcmp(SYM(he), expected[i].sym));
211
212 if (symbol_conf.cumulate_callchain)
213 TEST_ASSERT_VAL(buf, he->stat_acc->period == expected[i].children);
214
215 if (!symbol_conf.use_callchain)
216 continue;
217
218 /* check callchain entries */
219 root = &he->callchain->node.rb_root;
220 cnode = rb_entry(rb_first(root), struct callchain_node, rb_node);
221
222 c = 0;
223 list_for_each_entry(clist, &cnode->val, list) {
224 scnprintf(buf, sizeof(buf), "Invalid callchain entry #%zd/%zd", i, c);
225
226 TEST_ASSERT_VAL("Incorrect number of callchain entry",
227 c < expected_callchain[i].nr);
228 TEST_ASSERT_VAL(buf,
229 !strcmp(CDSO(clist), expected_callchain[i].node[c].dso) &&
230 !strcmp(CSYM(clist), expected_callchain[i].node[c].sym));
231 c++;
232 }
233 /* TODO: handle multiple child nodes properly */
234 TEST_ASSERT_VAL("Incorrect number of callchain entry",
235 c <= expected_callchain[i].nr);
236 }
237 TEST_ASSERT_VAL("Incorrect number of hist entry",
238 i == nr_expected);
239 TEST_ASSERT_VAL("Incorrect number of callchain entry",
240 !symbol_conf.use_callchain || nr_expected == nr_callchain);
241 return 0;
242}
243
244/* NO callchain + NO children */
245static int test1(struct perf_evsel *evsel, struct machine *machine)
246{
247 int err;
248 struct hists *hists = &evsel->hists;
249 /*
250 * expected output:
251 *
252 * Overhead Command Shared Object Symbol
253 * ======== ======= ============= ==============
254 * 20.00% perf perf [.] main
255 * 10.00% bash [kernel] [k] page_fault
256 * 10.00% bash bash [.] main
257 * 10.00% bash bash [.] xmalloc
258 * 10.00% perf [kernel] [k] page_fault
259 * 10.00% perf [kernel] [k] schedule
260 * 10.00% perf libc [.] free
261 * 10.00% perf libc [.] malloc
262 * 10.00% perf perf [.] cmd_record
263 */
264 struct result expected[] = {
265 { 0, 2000, "perf", "perf", "main" },
266 { 0, 1000, "bash", "[kernel]", "page_fault" },
267 { 0, 1000, "bash", "bash", "main" },
268 { 0, 1000, "bash", "bash", "xmalloc" },
269 { 0, 1000, "perf", "[kernel]", "page_fault" },
270 { 0, 1000, "perf", "[kernel]", "schedule" },
271 { 0, 1000, "perf", "libc", "free" },
272 { 0, 1000, "perf", "libc", "malloc" },
273 { 0, 1000, "perf", "perf", "cmd_record" },
274 };
275
276 symbol_conf.use_callchain = false;
277 symbol_conf.cumulate_callchain = false;
278
279 setup_sorting();
280 callchain_register_param(&callchain_param);
281
282 err = add_hist_entries(hists, machine);
283 if (err < 0)
284 goto out;
285
286 err = do_test(hists, expected, ARRAY_SIZE(expected), NULL, 0);
287
288out:
289 del_hist_entries(hists);
290 reset_output_field();
291 return err;
292}
293
294/* callcain + NO children */
295static int test2(struct perf_evsel *evsel, struct machine *machine)
296{
297 int err;
298 struct hists *hists = &evsel->hists;
299 /*
300 * expected output:
301 *
302 * Overhead Command Shared Object Symbol
303 * ======== ======= ============= ==============
304 * 20.00% perf perf [.] main
305 * |
306 * --- main
307 *
308 * 10.00% bash [kernel] [k] page_fault
309 * |
310 * --- page_fault
311 * malloc
312 * main
313 *
314 * 10.00% bash bash [.] main
315 * |
316 * --- main
317 *
318 * 10.00% bash bash [.] xmalloc
319 * |
320 * --- xmalloc
321 * malloc
322 * xmalloc <--- NOTE: there's a cycle
323 * malloc
324 * xmalloc
325 * main
326 *
327 * 10.00% perf [kernel] [k] page_fault
328 * |
329 * --- page_fault
330 * sys_perf_event_open
331 * run_command
332 * main
333 *
334 * 10.00% perf [kernel] [k] schedule
335 * |
336 * --- schedule
337 * run_command
338 * main
339 *
340 * 10.00% perf libc [.] free
341 * |
342 * --- free
343 * cmd_record
344 * run_command
345 * main
346 *
347 * 10.00% perf libc [.] malloc
348 * |
349 * --- malloc
350 * cmd_record
351 * run_command
352 * main
353 *
354 * 10.00% perf perf [.] cmd_record
355 * |
356 * --- cmd_record
357 * run_command
358 * main
359 *
360 */
361 struct result expected[] = {
362 { 0, 2000, "perf", "perf", "main" },
363 { 0, 1000, "bash", "[kernel]", "page_fault" },
364 { 0, 1000, "bash", "bash", "main" },
365 { 0, 1000, "bash", "bash", "xmalloc" },
366 { 0, 1000, "perf", "[kernel]", "page_fault" },
367 { 0, 1000, "perf", "[kernel]", "schedule" },
368 { 0, 1000, "perf", "libc", "free" },
369 { 0, 1000, "perf", "libc", "malloc" },
370 { 0, 1000, "perf", "perf", "cmd_record" },
371 };
372 struct callchain_result expected_callchain[] = {
373 {
374 1, { { "perf", "main" }, },
375 },
376 {
377 3, { { "[kernel]", "page_fault" },
378 { "libc", "malloc" },
379 { "bash", "main" }, },
380 },
381 {
382 1, { { "bash", "main" }, },
383 },
384 {
385 6, { { "bash", "xmalloc" },
386 { "libc", "malloc" },
387 { "bash", "xmalloc" },
388 { "libc", "malloc" },
389 { "bash", "xmalloc" },
390 { "bash", "main" }, },
391 },
392 {
393 4, { { "[kernel]", "page_fault" },
394 { "[kernel]", "sys_perf_event_open" },
395 { "perf", "run_command" },
396 { "perf", "main" }, },
397 },
398 {
399 3, { { "[kernel]", "schedule" },
400 { "perf", "run_command" },
401 { "perf", "main" }, },
402 },
403 {
404 4, { { "libc", "free" },
405 { "perf", "cmd_record" },
406 { "perf", "run_command" },
407 { "perf", "main" }, },
408 },
409 {
410 4, { { "libc", "malloc" },
411 { "perf", "cmd_record" },
412 { "perf", "run_command" },
413 { "perf", "main" }, },
414 },
415 {
416 3, { { "perf", "cmd_record" },
417 { "perf", "run_command" },
418 { "perf", "main" }, },
419 },
420 };
421
422 symbol_conf.use_callchain = true;
423 symbol_conf.cumulate_callchain = false;
424
425 setup_sorting();
426 callchain_register_param(&callchain_param);
427
428 err = add_hist_entries(hists, machine);
429 if (err < 0)
430 goto out;
431
432 err = do_test(hists, expected, ARRAY_SIZE(expected),
433 expected_callchain, ARRAY_SIZE(expected_callchain));
434
435out:
436 del_hist_entries(hists);
437 reset_output_field();
438 return err;
439}
440
441/* NO callchain + children */
442static int test3(struct perf_evsel *evsel, struct machine *machine)
443{
444 int err;
445 struct hists *hists = &evsel->hists;
446 /*
447 * expected output:
448 *
449 * Children Self Command Shared Object Symbol
450 * ======== ======== ======= ============= =======================
451 * 70.00% 20.00% perf perf [.] main
452 * 50.00% 0.00% perf perf [.] run_command
453 * 30.00% 10.00% bash bash [.] main
454 * 30.00% 10.00% perf perf [.] cmd_record
455 * 20.00% 0.00% bash libc [.] malloc
456 * 10.00% 10.00% bash [kernel] [k] page_fault
457 * 10.00% 10.00% perf [kernel] [k] schedule
458 * 10.00% 0.00% perf [kernel] [k] sys_perf_event_open
459 * 10.00% 10.00% perf [kernel] [k] page_fault
460 * 10.00% 10.00% perf libc [.] free
461 * 10.00% 10.00% perf libc [.] malloc
462 * 10.00% 10.00% bash bash [.] xmalloc
463 */
464 struct result expected[] = {
465 { 7000, 2000, "perf", "perf", "main" },
466 { 5000, 0, "perf", "perf", "run_command" },
467 { 3000, 1000, "bash", "bash", "main" },
468 { 3000, 1000, "perf", "perf", "cmd_record" },
469 { 2000, 0, "bash", "libc", "malloc" },
470 { 1000, 1000, "bash", "[kernel]", "page_fault" },
471 { 1000, 1000, "perf", "[kernel]", "schedule" },
472 { 1000, 0, "perf", "[kernel]", "sys_perf_event_open" },
473 { 1000, 1000, "perf", "[kernel]", "page_fault" },
474 { 1000, 1000, "perf", "libc", "free" },
475 { 1000, 1000, "perf", "libc", "malloc" },
476 { 1000, 1000, "bash", "bash", "xmalloc" },
477 };
478
479 symbol_conf.use_callchain = false;
480 symbol_conf.cumulate_callchain = true;
481
482 setup_sorting();
483 callchain_register_param(&callchain_param);
484
485 err = add_hist_entries(hists, machine);
486 if (err < 0)
487 goto out;
488
489 err = do_test(hists, expected, ARRAY_SIZE(expected), NULL, 0);
490
491out:
492 del_hist_entries(hists);
493 reset_output_field();
494 return err;
495}
496
497/* callchain + children */
498static int test4(struct perf_evsel *evsel, struct machine *machine)
499{
500 int err;
501 struct hists *hists = &evsel->hists;
502 /*
503 * expected output:
504 *
505 * Children Self Command Shared Object Symbol
506 * ======== ======== ======= ============= =======================
507 * 70.00% 20.00% perf perf [.] main
508 * |
509 * --- main
510 *
511 * 50.00% 0.00% perf perf [.] run_command
512 * |
513 * --- run_command
514 * main
515 *
516 * 30.00% 10.00% bash bash [.] main
517 * |
518 * --- main
519 *
520 * 30.00% 10.00% perf perf [.] cmd_record
521 * |
522 * --- cmd_record
523 * run_command
524 * main
525 *
526 * 20.00% 0.00% bash libc [.] malloc
527 * |
528 * --- malloc
529 * |
530 * |--50.00%-- xmalloc
531 * | main
532 * --50.00%-- main
533 *
534 * 10.00% 10.00% bash [kernel] [k] page_fault
535 * |
536 * --- page_fault
537 * malloc
538 * main
539 *
540 * 10.00% 10.00% perf [kernel] [k] schedule
541 * |
542 * --- schedule
543 * run_command
544 * main
545 *
546 * 10.00% 0.00% perf [kernel] [k] sys_perf_event_open
547 * |
548 * --- sys_perf_event_open
549 * run_command
550 * main
551 *
552 * 10.00% 10.00% perf [kernel] [k] page_fault
553 * |
554 * --- page_fault
555 * sys_perf_event_open
556 * run_command
557 * main
558 *
559 * 10.00% 10.00% perf libc [.] free
560 * |
561 * --- free
562 * cmd_record
563 * run_command
564 * main
565 *
566 * 10.00% 10.00% perf libc [.] malloc
567 * |
568 * --- malloc
569 * cmd_record
570 * run_command
571 * main
572 *
573 * 10.00% 10.00% bash bash [.] xmalloc
574 * |
575 * --- xmalloc
576 * malloc
577 * xmalloc <--- NOTE: there's a cycle
578 * malloc
579 * xmalloc
580 * main
581 *
582 */
583 struct result expected[] = {
584 { 7000, 2000, "perf", "perf", "main" },
585 { 5000, 0, "perf", "perf", "run_command" },
586 { 3000, 1000, "bash", "bash", "main" },
587 { 3000, 1000, "perf", "perf", "cmd_record" },
588 { 2000, 0, "bash", "libc", "malloc" },
589 { 1000, 1000, "bash", "[kernel]", "page_fault" },
590 { 1000, 1000, "perf", "[kernel]", "schedule" },
591 { 1000, 0, "perf", "[kernel]", "sys_perf_event_open" },
592 { 1000, 1000, "perf", "[kernel]", "page_fault" },
593 { 1000, 1000, "perf", "libc", "free" },
594 { 1000, 1000, "perf", "libc", "malloc" },
595 { 1000, 1000, "bash", "bash", "xmalloc" },
596 };
597 struct callchain_result expected_callchain[] = {
598 {
599 1, { { "perf", "main" }, },
600 },
601 {
602 2, { { "perf", "run_command" },
603 { "perf", "main" }, },
604 },
605 {
606 1, { { "bash", "main" }, },
607 },
608 {
609 3, { { "perf", "cmd_record" },
610 { "perf", "run_command" },
611 { "perf", "main" }, },
612 },
613 {
614 4, { { "libc", "malloc" },
615 { "bash", "xmalloc" },
616 { "bash", "main" },
617 { "bash", "main" }, },
618 },
619 {
620 3, { { "[kernel]", "page_fault" },
621 { "libc", "malloc" },
622 { "bash", "main" }, },
623 },
624 {
625 3, { { "[kernel]", "schedule" },
626 { "perf", "run_command" },
627 { "perf", "main" }, },
628 },
629 {
630 3, { { "[kernel]", "sys_perf_event_open" },
631 { "perf", "run_command" },
632 { "perf", "main" }, },
633 },
634 {
635 4, { { "[kernel]", "page_fault" },
636 { "[kernel]", "sys_perf_event_open" },
637 { "perf", "run_command" },
638 { "perf", "main" }, },
639 },
640 {
641 4, { { "libc", "free" },
642 { "perf", "cmd_record" },
643 { "perf", "run_command" },
644 { "perf", "main" }, },
645 },
646 {
647 4, { { "libc", "malloc" },
648 { "perf", "cmd_record" },
649 { "perf", "run_command" },
650 { "perf", "main" }, },
651 },
652 {
653 6, { { "bash", "xmalloc" },
654 { "libc", "malloc" },
655 { "bash", "xmalloc" },
656 { "libc", "malloc" },
657 { "bash", "xmalloc" },
658 { "bash", "main" }, },
659 },
660 };
661
662 symbol_conf.use_callchain = true;
663 symbol_conf.cumulate_callchain = true;
664
665 setup_sorting();
666 callchain_register_param(&callchain_param);
667
668 err = add_hist_entries(hists, machine);
669 if (err < 0)
670 goto out;
671
672 err = do_test(hists, expected, ARRAY_SIZE(expected),
673 expected_callchain, ARRAY_SIZE(expected_callchain));
674
675out:
676 del_hist_entries(hists);
677 reset_output_field();
678 return err;
679}
680
681int test__hists_cumulate(void)
682{
683 int err = TEST_FAIL;
684 struct machines machines;
685 struct machine *machine;
686 struct perf_evsel *evsel;
687 struct perf_evlist *evlist = perf_evlist__new();
688 size_t i;
689 test_fn_t testcases[] = {
690 test1,
691 test2,
692 test3,
693 test4,
694 };
695
696 TEST_ASSERT_VAL("No memory", evlist);
697
698 err = parse_events(evlist, "cpu-clock");
699 if (err)
700 goto out;
701
702 machines__init(&machines);
703
704 /* setup threads/dso/map/symbols also */
705 machine = setup_fake_machine(&machines);
706 if (!machine)
707 goto out;
708
709 if (verbose > 1)
710 machine__fprintf(machine, stderr);
711
712 evsel = perf_evlist__first(evlist);
713
714 for (i = 0; i < ARRAY_SIZE(testcases); i++) {
715 err = testcases[i](evsel, machine);
716 if (err < 0)
717 break;
718 }
719
720out:
721 /* tear down everything */
722 perf_evlist__delete(evlist);
723 machines__exit(&machines);
724
725 return err;
726}
diff --git a/tools/perf/tests/hists_filter.c b/tools/perf/tests/hists_filter.c
index c5ba924a3581..821f581fd930 100644
--- a/tools/perf/tests/hists_filter.c
+++ b/tools/perf/tests/hists_filter.c
@@ -21,33 +21,33 @@ struct sample {
21/* For the numbers, see hists_common.c */ 21/* For the numbers, see hists_common.c */
22static struct sample fake_samples[] = { 22static struct sample fake_samples[] = {
23 /* perf [kernel] schedule() */ 23 /* perf [kernel] schedule() */
24 { .pid = 100, .ip = 0xf0000 + 700, }, 24 { .pid = FAKE_PID_PERF1, .ip = FAKE_IP_KERNEL_SCHEDULE, },
25 /* perf [perf] main() */ 25 /* perf [perf] main() */
26 { .pid = 100, .ip = 0x40000 + 700, }, 26 { .pid = FAKE_PID_PERF1, .ip = FAKE_IP_PERF_MAIN, },
27 /* perf [libc] malloc() */ 27 /* perf [libc] malloc() */
28 { .pid = 100, .ip = 0x50000 + 700, }, 28 { .pid = FAKE_PID_PERF1, .ip = FAKE_IP_LIBC_MALLOC, },
29 /* perf [perf] main() */ 29 /* perf [perf] main() */
30 { .pid = 200, .ip = 0x40000 + 700, }, /* will be merged */ 30 { .pid = FAKE_PID_PERF2, .ip = FAKE_IP_PERF_MAIN, }, /* will be merged */
31 /* perf [perf] cmd_record() */ 31 /* perf [perf] cmd_record() */
32 { .pid = 200, .ip = 0x40000 + 900, }, 32 { .pid = FAKE_PID_PERF2, .ip = FAKE_IP_PERF_CMD_RECORD, },
33 /* perf [kernel] page_fault() */ 33 /* perf [kernel] page_fault() */
34 { .pid = 200, .ip = 0xf0000 + 800, }, 34 { .pid = FAKE_PID_PERF2, .ip = FAKE_IP_KERNEL_PAGE_FAULT, },
35 /* bash [bash] main() */ 35 /* bash [bash] main() */
36 { .pid = 300, .ip = 0x40000 + 700, }, 36 { .pid = FAKE_PID_BASH, .ip = FAKE_IP_BASH_MAIN, },
37 /* bash [bash] xmalloc() */ 37 /* bash [bash] xmalloc() */
38 { .pid = 300, .ip = 0x40000 + 800, }, 38 { .pid = FAKE_PID_BASH, .ip = FAKE_IP_BASH_XMALLOC, },
39 /* bash [libc] malloc() */ 39 /* bash [libc] malloc() */
40 { .pid = 300, .ip = 0x50000 + 700, }, 40 { .pid = FAKE_PID_BASH, .ip = FAKE_IP_LIBC_MALLOC, },
41 /* bash [kernel] page_fault() */ 41 /* bash [kernel] page_fault() */
42 { .pid = 300, .ip = 0xf0000 + 800, }, 42 { .pid = FAKE_PID_BASH, .ip = FAKE_IP_KERNEL_PAGE_FAULT, },
43}; 43};
44 44
45static int add_hist_entries(struct perf_evlist *evlist, struct machine *machine) 45static int add_hist_entries(struct perf_evlist *evlist,
46 struct machine *machine __maybe_unused)
46{ 47{
47 struct perf_evsel *evsel; 48 struct perf_evsel *evsel;
48 struct addr_location al; 49 struct addr_location al;
49 struct hist_entry *he; 50 struct perf_sample sample = { .period = 100, };
50 struct perf_sample sample = { .cpu = 0, };
51 size_t i; 51 size_t i;
52 52
53 /* 53 /*
@@ -62,6 +62,10 @@ static int add_hist_entries(struct perf_evlist *evlist, struct machine *machine)
62 .misc = PERF_RECORD_MISC_USER, 62 .misc = PERF_RECORD_MISC_USER,
63 }, 63 },
64 }; 64 };
65 struct hist_entry_iter iter = {
66 .ops = &hist_iter_normal,
67 .hide_unresolved = false,
68 };
65 69
66 /* make sure it has no filter at first */ 70 /* make sure it has no filter at first */
67 evsel->hists.thread_filter = NULL; 71 evsel->hists.thread_filter = NULL;
@@ -76,18 +80,13 @@ static int add_hist_entries(struct perf_evlist *evlist, struct machine *machine)
76 &sample) < 0) 80 &sample) < 0)
77 goto out; 81 goto out;
78 82
79 he = __hists__add_entry(&evsel->hists, &al, NULL, 83 if (hist_entry_iter__add(&iter, &al, evsel, &sample,
80 NULL, NULL, 100, 1, 0); 84 PERF_MAX_STACK_DEPTH, NULL) < 0)
81 if (he == NULL)
82 goto out; 85 goto out;
83 86
84 fake_samples[i].thread = al.thread; 87 fake_samples[i].thread = al.thread;
85 fake_samples[i].map = al.map; 88 fake_samples[i].map = al.map;
86 fake_samples[i].sym = al.sym; 89 fake_samples[i].sym = al.sym;
87
88 hists__inc_nr_events(he->hists, PERF_RECORD_SAMPLE);
89 if (!he->filtered)
90 he->hists->stats.nr_non_filtered_samples++;
91 } 90 }
92 } 91 }
93 92
diff --git a/tools/perf/tests/hists_link.c b/tools/perf/tests/hists_link.c
index 5ffa2c3eb77d..d4b34b0f50a2 100644
--- a/tools/perf/tests/hists_link.c
+++ b/tools/perf/tests/hists_link.c
@@ -21,41 +21,41 @@ struct sample {
21/* For the numbers, see hists_common.c */ 21/* For the numbers, see hists_common.c */
22static struct sample fake_common_samples[] = { 22static struct sample fake_common_samples[] = {
23 /* perf [kernel] schedule() */ 23 /* perf [kernel] schedule() */
24 { .pid = 100, .ip = 0xf0000 + 700, }, 24 { .pid = FAKE_PID_PERF1, .ip = FAKE_IP_KERNEL_SCHEDULE, },
25 /* perf [perf] main() */ 25 /* perf [perf] main() */
26 { .pid = 200, .ip = 0x40000 + 700, }, 26 { .pid = FAKE_PID_PERF2, .ip = FAKE_IP_PERF_MAIN, },
27 /* perf [perf] cmd_record() */ 27 /* perf [perf] cmd_record() */
28 { .pid = 200, .ip = 0x40000 + 900, }, 28 { .pid = FAKE_PID_PERF2, .ip = FAKE_IP_PERF_CMD_RECORD, },
29 /* bash [bash] xmalloc() */ 29 /* bash [bash] xmalloc() */
30 { .pid = 300, .ip = 0x40000 + 800, }, 30 { .pid = FAKE_PID_BASH, .ip = FAKE_IP_BASH_XMALLOC, },
31 /* bash [libc] malloc() */ 31 /* bash [libc] malloc() */
32 { .pid = 300, .ip = 0x50000 + 700, }, 32 { .pid = FAKE_PID_BASH, .ip = FAKE_IP_LIBC_MALLOC, },
33}; 33};
34 34
35static struct sample fake_samples[][5] = { 35static struct sample fake_samples[][5] = {
36 { 36 {
37 /* perf [perf] run_command() */ 37 /* perf [perf] run_command() */
38 { .pid = 100, .ip = 0x40000 + 800, }, 38 { .pid = FAKE_PID_PERF1, .ip = FAKE_IP_PERF_RUN_COMMAND, },
39 /* perf [libc] malloc() */ 39 /* perf [libc] malloc() */
40 { .pid = 100, .ip = 0x50000 + 700, }, 40 { .pid = FAKE_PID_PERF1, .ip = FAKE_IP_LIBC_MALLOC, },
41 /* perf [kernel] page_fault() */ 41 /* perf [kernel] page_fault() */
42 { .pid = 100, .ip = 0xf0000 + 800, }, 42 { .pid = FAKE_PID_PERF1, .ip = FAKE_IP_KERNEL_PAGE_FAULT, },
43 /* perf [kernel] sys_perf_event_open() */ 43 /* perf [kernel] sys_perf_event_open() */
44 { .pid = 200, .ip = 0xf0000 + 900, }, 44 { .pid = FAKE_PID_PERF2, .ip = FAKE_IP_KERNEL_SYS_PERF_EVENT_OPEN, },
45 /* bash [libc] free() */ 45 /* bash [libc] free() */
46 { .pid = 300, .ip = 0x50000 + 800, }, 46 { .pid = FAKE_PID_BASH, .ip = FAKE_IP_LIBC_FREE, },
47 }, 47 },
48 { 48 {
49 /* perf [libc] free() */ 49 /* perf [libc] free() */
50 { .pid = 200, .ip = 0x50000 + 800, }, 50 { .pid = FAKE_PID_PERF2, .ip = FAKE_IP_LIBC_FREE, },
51 /* bash [libc] malloc() */ 51 /* bash [libc] malloc() */
52 { .pid = 300, .ip = 0x50000 + 700, }, /* will be merged */ 52 { .pid = FAKE_PID_BASH, .ip = FAKE_IP_LIBC_MALLOC, }, /* will be merged */
53 /* bash [bash] xfee() */ 53 /* bash [bash] xfee() */
54 { .pid = 300, .ip = 0x40000 + 900, }, 54 { .pid = FAKE_PID_BASH, .ip = FAKE_IP_BASH_XFREE, },
55 /* bash [libc] realloc() */ 55 /* bash [libc] realloc() */
56 { .pid = 300, .ip = 0x50000 + 900, }, 56 { .pid = FAKE_PID_BASH, .ip = FAKE_IP_LIBC_REALLOC, },
57 /* bash [kernel] page_fault() */ 57 /* bash [kernel] page_fault() */
58 { .pid = 300, .ip = 0xf0000 + 800, }, 58 { .pid = FAKE_PID_BASH, .ip = FAKE_IP_KERNEL_PAGE_FAULT, },
59 }, 59 },
60}; 60};
61 61
@@ -64,7 +64,7 @@ static int add_hist_entries(struct perf_evlist *evlist, struct machine *machine)
64 struct perf_evsel *evsel; 64 struct perf_evsel *evsel;
65 struct addr_location al; 65 struct addr_location al;
66 struct hist_entry *he; 66 struct hist_entry *he;
67 struct perf_sample sample = { .cpu = 0, }; 67 struct perf_sample sample = { .period = 1, };
68 size_t i = 0, k; 68 size_t i = 0, k;
69 69
70 /* 70 /*
@@ -88,7 +88,7 @@ static int add_hist_entries(struct perf_evlist *evlist, struct machine *machine)
88 goto out; 88 goto out;
89 89
90 he = __hists__add_entry(&evsel->hists, &al, NULL, 90 he = __hists__add_entry(&evsel->hists, &al, NULL,
91 NULL, NULL, 1, 1, 0); 91 NULL, NULL, 1, 1, 0, true);
92 if (he == NULL) 92 if (he == NULL)
93 goto out; 93 goto out;
94 94
@@ -112,7 +112,7 @@ static int add_hist_entries(struct perf_evlist *evlist, struct machine *machine)
112 goto out; 112 goto out;
113 113
114 he = __hists__add_entry(&evsel->hists, &al, NULL, 114 he = __hists__add_entry(&evsel->hists, &al, NULL,
115 NULL, NULL, 1, 1, 0); 115 NULL, NULL, 1, 1, 0, true);
116 if (he == NULL) 116 if (he == NULL)
117 goto out; 117 goto out;
118 118
diff --git a/tools/perf/tests/hists_output.c b/tools/perf/tests/hists_output.c
index a16850551797..e3bbd6c54c1b 100644
--- a/tools/perf/tests/hists_output.c
+++ b/tools/perf/tests/hists_output.c
@@ -22,31 +22,31 @@ struct sample {
22/* For the numbers, see hists_common.c */ 22/* For the numbers, see hists_common.c */
23static struct sample fake_samples[] = { 23static struct sample fake_samples[] = {
24 /* perf [kernel] schedule() */ 24 /* perf [kernel] schedule() */
25 { .cpu = 0, .pid = 100, .ip = 0xf0000 + 700, }, 25 { .cpu = 0, .pid = FAKE_PID_PERF1, .ip = FAKE_IP_KERNEL_SCHEDULE, },
26 /* perf [perf] main() */ 26 /* perf [perf] main() */
27 { .cpu = 1, .pid = 100, .ip = 0x40000 + 700, }, 27 { .cpu = 1, .pid = FAKE_PID_PERF1, .ip = FAKE_IP_PERF_MAIN, },
28 /* perf [perf] cmd_record() */ 28 /* perf [perf] cmd_record() */
29 { .cpu = 1, .pid = 100, .ip = 0x40000 + 900, }, 29 { .cpu = 1, .pid = FAKE_PID_PERF1, .ip = FAKE_IP_PERF_CMD_RECORD, },
30 /* perf [libc] malloc() */ 30 /* perf [libc] malloc() */
31 { .cpu = 1, .pid = 100, .ip = 0x50000 + 700, }, 31 { .cpu = 1, .pid = FAKE_PID_PERF1, .ip = FAKE_IP_LIBC_MALLOC, },
32 /* perf [libc] free() */ 32 /* perf [libc] free() */
33 { .cpu = 2, .pid = 100, .ip = 0x50000 + 800, }, 33 { .cpu = 2, .pid = FAKE_PID_PERF1, .ip = FAKE_IP_LIBC_FREE, },
34 /* perf [perf] main() */ 34 /* perf [perf] main() */
35 { .cpu = 2, .pid = 200, .ip = 0x40000 + 700, }, 35 { .cpu = 2, .pid = FAKE_PID_PERF2, .ip = FAKE_IP_PERF_MAIN, },
36 /* perf [kernel] page_fault() */ 36 /* perf [kernel] page_fault() */
37 { .cpu = 2, .pid = 200, .ip = 0xf0000 + 800, }, 37 { .cpu = 2, .pid = FAKE_PID_PERF2, .ip = FAKE_IP_KERNEL_PAGE_FAULT, },
38 /* bash [bash] main() */ 38 /* bash [bash] main() */
39 { .cpu = 3, .pid = 300, .ip = 0x40000 + 700, }, 39 { .cpu = 3, .pid = FAKE_PID_BASH, .ip = FAKE_IP_BASH_MAIN, },
40 /* bash [bash] xmalloc() */ 40 /* bash [bash] xmalloc() */
41 { .cpu = 0, .pid = 300, .ip = 0x40000 + 800, }, 41 { .cpu = 0, .pid = FAKE_PID_BASH, .ip = FAKE_IP_BASH_XMALLOC, },
42 /* bash [kernel] page_fault() */ 42 /* bash [kernel] page_fault() */
43 { .cpu = 1, .pid = 300, .ip = 0xf0000 + 800, }, 43 { .cpu = 1, .pid = FAKE_PID_BASH, .ip = FAKE_IP_KERNEL_PAGE_FAULT, },
44}; 44};
45 45
46static int add_hist_entries(struct hists *hists, struct machine *machine) 46static int add_hist_entries(struct hists *hists, struct machine *machine)
47{ 47{
48 struct addr_location al; 48 struct addr_location al;
49 struct hist_entry *he; 49 struct perf_evsel *evsel = hists_to_evsel(hists);
50 struct perf_sample sample = { .period = 100, }; 50 struct perf_sample sample = { .period = 100, };
51 size_t i; 51 size_t i;
52 52
@@ -56,6 +56,10 @@ static int add_hist_entries(struct hists *hists, struct machine *machine)
56 .misc = PERF_RECORD_MISC_USER, 56 .misc = PERF_RECORD_MISC_USER,
57 }, 57 },
58 }; 58 };
59 struct hist_entry_iter iter = {
60 .ops = &hist_iter_normal,
61 .hide_unresolved = false,
62 };
59 63
60 sample.cpu = fake_samples[i].cpu; 64 sample.cpu = fake_samples[i].cpu;
61 sample.pid = fake_samples[i].pid; 65 sample.pid = fake_samples[i].pid;
@@ -66,9 +70,8 @@ static int add_hist_entries(struct hists *hists, struct machine *machine)
66 &sample) < 0) 70 &sample) < 0)
67 goto out; 71 goto out;
68 72
69 he = __hists__add_entry(hists, &al, NULL, NULL, NULL, 73 if (hist_entry_iter__add(&iter, &al, evsel, &sample,
70 sample.period, 1, 0); 74 PERF_MAX_STACK_DEPTH, NULL) < 0)
71 if (he == NULL)
72 goto out; 75 goto out;
73 76
74 fake_samples[i].thread = al.thread; 77 fake_samples[i].thread = al.thread;
diff --git a/tools/perf/tests/tests.h b/tools/perf/tests/tests.h
index d76c0e2e6635..022bb68fd9c7 100644
--- a/tools/perf/tests/tests.h
+++ b/tools/perf/tests/tests.h
@@ -45,6 +45,7 @@ int test__hists_filter(void);
45int test__mmap_thread_lookup(void); 45int test__mmap_thread_lookup(void);
46int test__thread_mg_share(void); 46int test__thread_mg_share(void);
47int test__hists_output(void); 47int test__hists_output(void);
48int test__hists_cumulate(void);
48 49
49#if defined(__x86_64__) || defined(__i386__) || defined(__arm__) 50#if defined(__x86_64__) || defined(__i386__) || defined(__arm__)
50#ifdef HAVE_DWARF_UNWIND_SUPPORT 51#ifdef HAVE_DWARF_UNWIND_SUPPORT
diff --git a/tools/perf/ui/browser.c b/tools/perf/ui/browser.c
index d11541d4d7d7..3ccf6e14f89b 100644
--- a/tools/perf/ui/browser.c
+++ b/tools/perf/ui/browser.c
@@ -194,7 +194,7 @@ int ui_browser__warning(struct ui_browser *browser, int timeout,
194 ui_helpline__vpush(format, args); 194 ui_helpline__vpush(format, args);
195 va_end(args); 195 va_end(args);
196 } else { 196 } else {
197 while ((key == ui__question_window("Warning!", text, 197 while ((key = ui__question_window("Warning!", text,
198 "Press any key...", 198 "Press any key...",
199 timeout)) == K_RESIZE) 199 timeout)) == K_RESIZE)
200 ui_browser__handle_resize(browser); 200 ui_browser__handle_resize(browser);
diff --git a/tools/perf/ui/browsers/hists.c b/tools/perf/ui/browsers/hists.c
index 1c331b934ffc..52c03fbbba17 100644
--- a/tools/perf/ui/browsers/hists.c
+++ b/tools/perf/ui/browsers/hists.c
@@ -37,7 +37,6 @@ static int hists__browser_title(struct hists *hists, char *bf, size_t size,
37static void hist_browser__update_nr_entries(struct hist_browser *hb); 37static void hist_browser__update_nr_entries(struct hist_browser *hb);
38 38
39static struct rb_node *hists__filter_entries(struct rb_node *nd, 39static struct rb_node *hists__filter_entries(struct rb_node *nd,
40 struct hists *hists,
41 float min_pcnt); 40 float min_pcnt);
42 41
43static bool hist_browser__has_filter(struct hist_browser *hb) 42static bool hist_browser__has_filter(struct hist_browser *hb)
@@ -319,7 +318,7 @@ __hist_browser__set_folding(struct hist_browser *browser, bool unfold)
319 struct hists *hists = browser->hists; 318 struct hists *hists = browser->hists;
320 319
321 for (nd = rb_first(&hists->entries); 320 for (nd = rb_first(&hists->entries);
322 (nd = hists__filter_entries(nd, hists, browser->min_pcnt)) != NULL; 321 (nd = hists__filter_entries(nd, browser->min_pcnt)) != NULL;
323 nd = rb_next(nd)) { 322 nd = rb_next(nd)) {
324 struct hist_entry *he = rb_entry(nd, struct hist_entry, rb_node); 323 struct hist_entry *he = rb_entry(nd, struct hist_entry, rb_node);
325 hist_entry__set_folding(he, unfold); 324 hist_entry__set_folding(he, unfold);
@@ -651,13 +650,36 @@ hist_browser__hpp_color_##_type(struct perf_hpp_fmt *fmt __maybe_unused,\
651 __hpp__slsmg_color_printf, true); \ 650 __hpp__slsmg_color_printf, true); \
652} 651}
653 652
653#define __HPP_COLOR_ACC_PERCENT_FN(_type, _field) \
654static u64 __hpp_get_acc_##_field(struct hist_entry *he) \
655{ \
656 return he->stat_acc->_field; \
657} \
658 \
659static int \
660hist_browser__hpp_color_##_type(struct perf_hpp_fmt *fmt __maybe_unused,\
661 struct perf_hpp *hpp, \
662 struct hist_entry *he) \
663{ \
664 if (!symbol_conf.cumulate_callchain) { \
665 int ret = scnprintf(hpp->buf, hpp->size, "%8s", "N/A"); \
666 slsmg_printf("%s", hpp->buf); \
667 \
668 return ret; \
669 } \
670 return __hpp__fmt(hpp, he, __hpp_get_acc_##_field, " %6.2f%%", \
671 __hpp__slsmg_color_printf, true); \
672}
673
654__HPP_COLOR_PERCENT_FN(overhead, period) 674__HPP_COLOR_PERCENT_FN(overhead, period)
655__HPP_COLOR_PERCENT_FN(overhead_sys, period_sys) 675__HPP_COLOR_PERCENT_FN(overhead_sys, period_sys)
656__HPP_COLOR_PERCENT_FN(overhead_us, period_us) 676__HPP_COLOR_PERCENT_FN(overhead_us, period_us)
657__HPP_COLOR_PERCENT_FN(overhead_guest_sys, period_guest_sys) 677__HPP_COLOR_PERCENT_FN(overhead_guest_sys, period_guest_sys)
658__HPP_COLOR_PERCENT_FN(overhead_guest_us, period_guest_us) 678__HPP_COLOR_PERCENT_FN(overhead_guest_us, period_guest_us)
679__HPP_COLOR_ACC_PERCENT_FN(overhead_acc, period)
659 680
660#undef __HPP_COLOR_PERCENT_FN 681#undef __HPP_COLOR_PERCENT_FN
682#undef __HPP_COLOR_ACC_PERCENT_FN
661 683
662void hist_browser__init_hpp(void) 684void hist_browser__init_hpp(void)
663{ 685{
@@ -671,6 +693,8 @@ void hist_browser__init_hpp(void)
671 hist_browser__hpp_color_overhead_guest_sys; 693 hist_browser__hpp_color_overhead_guest_sys;
672 perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_US].color = 694 perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_US].color =
673 hist_browser__hpp_color_overhead_guest_us; 695 hist_browser__hpp_color_overhead_guest_us;
696 perf_hpp__format[PERF_HPP__OVERHEAD_ACC].color =
697 hist_browser__hpp_color_overhead_acc;
674} 698}
675 699
676static int hist_browser__show_entry(struct hist_browser *browser, 700static int hist_browser__show_entry(struct hist_browser *browser,
@@ -783,15 +807,12 @@ static unsigned int hist_browser__refresh(struct ui_browser *browser)
783 807
784 for (nd = browser->top; nd; nd = rb_next(nd)) { 808 for (nd = browser->top; nd; nd = rb_next(nd)) {
785 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); 809 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
786 u64 total = hists__total_period(h->hists); 810 float percent;
787 float percent = 0.0;
788 811
789 if (h->filtered) 812 if (h->filtered)
790 continue; 813 continue;
791 814
792 if (total) 815 percent = hist_entry__get_percent_limit(h);
793 percent = h->stat.period * 100.0 / total;
794
795 if (percent < hb->min_pcnt) 816 if (percent < hb->min_pcnt)
796 continue; 817 continue;
797 818
@@ -804,16 +825,11 @@ static unsigned int hist_browser__refresh(struct ui_browser *browser)
804} 825}
805 826
806static struct rb_node *hists__filter_entries(struct rb_node *nd, 827static struct rb_node *hists__filter_entries(struct rb_node *nd,
807 struct hists *hists,
808 float min_pcnt) 828 float min_pcnt)
809{ 829{
810 while (nd != NULL) { 830 while (nd != NULL) {
811 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); 831 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
812 u64 total = hists__total_period(hists); 832 float percent = hist_entry__get_percent_limit(h);
813 float percent = 0.0;
814
815 if (total)
816 percent = h->stat.period * 100.0 / total;
817 833
818 if (!h->filtered && percent >= min_pcnt) 834 if (!h->filtered && percent >= min_pcnt)
819 return nd; 835 return nd;
@@ -825,16 +841,11 @@ static struct rb_node *hists__filter_entries(struct rb_node *nd,
825} 841}
826 842
827static struct rb_node *hists__filter_prev_entries(struct rb_node *nd, 843static struct rb_node *hists__filter_prev_entries(struct rb_node *nd,
828 struct hists *hists,
829 float min_pcnt) 844 float min_pcnt)
830{ 845{
831 while (nd != NULL) { 846 while (nd != NULL) {
832 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); 847 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
833 u64 total = hists__total_period(hists); 848 float percent = hist_entry__get_percent_limit(h);
834 float percent = 0.0;
835
836 if (total)
837 percent = h->stat.period * 100.0 / total;
838 849
839 if (!h->filtered && percent >= min_pcnt) 850 if (!h->filtered && percent >= min_pcnt)
840 return nd; 851 return nd;
@@ -863,14 +874,14 @@ static void ui_browser__hists_seek(struct ui_browser *browser,
863 switch (whence) { 874 switch (whence) {
864 case SEEK_SET: 875 case SEEK_SET:
865 nd = hists__filter_entries(rb_first(browser->entries), 876 nd = hists__filter_entries(rb_first(browser->entries),
866 hb->hists, hb->min_pcnt); 877 hb->min_pcnt);
867 break; 878 break;
868 case SEEK_CUR: 879 case SEEK_CUR:
869 nd = browser->top; 880 nd = browser->top;
870 goto do_offset; 881 goto do_offset;
871 case SEEK_END: 882 case SEEK_END:
872 nd = hists__filter_prev_entries(rb_last(browser->entries), 883 nd = hists__filter_prev_entries(rb_last(browser->entries),
873 hb->hists, hb->min_pcnt); 884 hb->min_pcnt);
874 first = false; 885 first = false;
875 break; 886 break;
876 default: 887 default:
@@ -913,8 +924,7 @@ do_offset:
913 break; 924 break;
914 } 925 }
915 } 926 }
916 nd = hists__filter_entries(rb_next(nd), hb->hists, 927 nd = hists__filter_entries(rb_next(nd), hb->min_pcnt);
917 hb->min_pcnt);
918 if (nd == NULL) 928 if (nd == NULL)
919 break; 929 break;
920 --offset; 930 --offset;
@@ -947,7 +957,7 @@ do_offset:
947 } 957 }
948 } 958 }
949 959
950 nd = hists__filter_prev_entries(rb_prev(nd), hb->hists, 960 nd = hists__filter_prev_entries(rb_prev(nd),
951 hb->min_pcnt); 961 hb->min_pcnt);
952 if (nd == NULL) 962 if (nd == NULL)
953 break; 963 break;
@@ -1126,7 +1136,6 @@ static int hist_browser__fprintf_entry(struct hist_browser *browser,
1126static int hist_browser__fprintf(struct hist_browser *browser, FILE *fp) 1136static int hist_browser__fprintf(struct hist_browser *browser, FILE *fp)
1127{ 1137{
1128 struct rb_node *nd = hists__filter_entries(rb_first(browser->b.entries), 1138 struct rb_node *nd = hists__filter_entries(rb_first(browser->b.entries),
1129 browser->hists,
1130 browser->min_pcnt); 1139 browser->min_pcnt);
1131 int printed = 0; 1140 int printed = 0;
1132 1141
@@ -1134,8 +1143,7 @@ static int hist_browser__fprintf(struct hist_browser *browser, FILE *fp)
1134 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); 1143 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
1135 1144
1136 printed += hist_browser__fprintf_entry(browser, h, fp); 1145 printed += hist_browser__fprintf_entry(browser, h, fp);
1137 nd = hists__filter_entries(rb_next(nd), browser->hists, 1146 nd = hists__filter_entries(rb_next(nd), browser->min_pcnt);
1138 browser->min_pcnt);
1139 } 1147 }
1140 1148
1141 return printed; 1149 return printed;
@@ -1372,8 +1380,7 @@ static void hist_browser__update_nr_entries(struct hist_browser *hb)
1372 return; 1380 return;
1373 } 1381 }
1374 1382
1375 while ((nd = hists__filter_entries(nd, hb->hists, 1383 while ((nd = hists__filter_entries(nd, hb->min_pcnt)) != NULL) {
1376 hb->min_pcnt)) != NULL) {
1377 nr_entries++; 1384 nr_entries++;
1378 nd = rb_next(nd); 1385 nd = rb_next(nd);
1379 } 1386 }
@@ -1699,14 +1706,14 @@ zoom_dso:
1699zoom_out_dso: 1706zoom_out_dso:
1700 ui_helpline__pop(); 1707 ui_helpline__pop();
1701 browser->hists->dso_filter = NULL; 1708 browser->hists->dso_filter = NULL;
1702 sort_dso.elide = false; 1709 perf_hpp__set_elide(HISTC_DSO, false);
1703 } else { 1710 } else {
1704 if (dso == NULL) 1711 if (dso == NULL)
1705 continue; 1712 continue;
1706 ui_helpline__fpush("To zoom out press <- or -> + \"Zoom out of %s DSO\"", 1713 ui_helpline__fpush("To zoom out press <- or -> + \"Zoom out of %s DSO\"",
1707 dso->kernel ? "the Kernel" : dso->short_name); 1714 dso->kernel ? "the Kernel" : dso->short_name);
1708 browser->hists->dso_filter = dso; 1715 browser->hists->dso_filter = dso;
1709 sort_dso.elide = true; 1716 perf_hpp__set_elide(HISTC_DSO, true);
1710 pstack__push(fstack, &browser->hists->dso_filter); 1717 pstack__push(fstack, &browser->hists->dso_filter);
1711 } 1718 }
1712 hists__filter_by_dso(hists); 1719 hists__filter_by_dso(hists);
@@ -1718,13 +1725,13 @@ zoom_thread:
1718zoom_out_thread: 1725zoom_out_thread:
1719 ui_helpline__pop(); 1726 ui_helpline__pop();
1720 browser->hists->thread_filter = NULL; 1727 browser->hists->thread_filter = NULL;
1721 sort_thread.elide = false; 1728 perf_hpp__set_elide(HISTC_THREAD, false);
1722 } else { 1729 } else {
1723 ui_helpline__fpush("To zoom out press <- or -> + \"Zoom out of %s(%d) thread\"", 1730 ui_helpline__fpush("To zoom out press <- or -> + \"Zoom out of %s(%d) thread\"",
1724 thread->comm_set ? thread__comm_str(thread) : "", 1731 thread->comm_set ? thread__comm_str(thread) : "",
1725 thread->tid); 1732 thread->tid);
1726 browser->hists->thread_filter = thread; 1733 browser->hists->thread_filter = thread;
1727 sort_thread.elide = true; 1734 perf_hpp__set_elide(HISTC_THREAD, false);
1728 pstack__push(fstack, &browser->hists->thread_filter); 1735 pstack__push(fstack, &browser->hists->thread_filter);
1729 } 1736 }
1730 hists__filter_by_thread(hists); 1737 hists__filter_by_thread(hists);
diff --git a/tools/perf/ui/gtk/hists.c b/tools/perf/ui/gtk/hists.c
index 9d90683914d4..6ca60e482cdc 100644
--- a/tools/perf/ui/gtk/hists.c
+++ b/tools/perf/ui/gtk/hists.c
@@ -47,11 +47,26 @@ static int perf_gtk__hpp_color_##_type(struct perf_hpp_fmt *fmt __maybe_unused,
47 __percent_color_snprintf, true); \ 47 __percent_color_snprintf, true); \
48} 48}
49 49
50#define __HPP_COLOR_ACC_PERCENT_FN(_type, _field) \
51static u64 he_get_acc_##_field(struct hist_entry *he) \
52{ \
53 return he->stat_acc->_field; \
54} \
55 \
56static int perf_gtk__hpp_color_##_type(struct perf_hpp_fmt *fmt __maybe_unused, \
57 struct perf_hpp *hpp, \
58 struct hist_entry *he) \
59{ \
60 return __hpp__fmt_acc(hpp, he, he_get_acc_##_field, " %6.2f%%", \
61 __percent_color_snprintf, true); \
62}
63
50__HPP_COLOR_PERCENT_FN(overhead, period) 64__HPP_COLOR_PERCENT_FN(overhead, period)
51__HPP_COLOR_PERCENT_FN(overhead_sys, period_sys) 65__HPP_COLOR_PERCENT_FN(overhead_sys, period_sys)
52__HPP_COLOR_PERCENT_FN(overhead_us, period_us) 66__HPP_COLOR_PERCENT_FN(overhead_us, period_us)
53__HPP_COLOR_PERCENT_FN(overhead_guest_sys, period_guest_sys) 67__HPP_COLOR_PERCENT_FN(overhead_guest_sys, period_guest_sys)
54__HPP_COLOR_PERCENT_FN(overhead_guest_us, period_guest_us) 68__HPP_COLOR_PERCENT_FN(overhead_guest_us, period_guest_us)
69__HPP_COLOR_ACC_PERCENT_FN(overhead_acc, period)
55 70
56#undef __HPP_COLOR_PERCENT_FN 71#undef __HPP_COLOR_PERCENT_FN
57 72
@@ -68,6 +83,8 @@ void perf_gtk__init_hpp(void)
68 perf_gtk__hpp_color_overhead_guest_sys; 83 perf_gtk__hpp_color_overhead_guest_sys;
69 perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_US].color = 84 perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_US].color =
70 perf_gtk__hpp_color_overhead_guest_us; 85 perf_gtk__hpp_color_overhead_guest_us;
86 perf_hpp__format[PERF_HPP__OVERHEAD_ACC].color =
87 perf_gtk__hpp_color_overhead_acc;
71} 88}
72 89
73static void callchain_list__sym_name(struct callchain_list *cl, 90static void callchain_list__sym_name(struct callchain_list *cl,
@@ -181,6 +198,13 @@ static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists,
181 if (perf_hpp__should_skip(fmt)) 198 if (perf_hpp__should_skip(fmt))
182 continue; 199 continue;
183 200
201 /*
202 * XXX no way to determine where symcol column is..
203 * Just use last column for now.
204 */
205 if (perf_hpp__is_sort_entry(fmt))
206 sym_col = col_idx;
207
184 fmt->header(fmt, &hpp, hists_to_evsel(hists)); 208 fmt->header(fmt, &hpp, hists_to_evsel(hists));
185 209
186 gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view), 210 gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view),
@@ -209,14 +233,12 @@ static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists,
209 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); 233 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
210 GtkTreeIter iter; 234 GtkTreeIter iter;
211 u64 total = hists__total_period(h->hists); 235 u64 total = hists__total_period(h->hists);
212 float percent = 0.0; 236 float percent;
213 237
214 if (h->filtered) 238 if (h->filtered)
215 continue; 239 continue;
216 240
217 if (total) 241 percent = hist_entry__get_percent_limit(h);
218 percent = h->stat.period * 100.0 / total;
219
220 if (percent < min_pcnt) 242 if (percent < min_pcnt)
221 continue; 243 continue;
222 244
@@ -238,7 +260,8 @@ static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists,
238 260
239 if (symbol_conf.use_callchain && sort__has_sym) { 261 if (symbol_conf.use_callchain && sort__has_sym) {
240 if (callchain_param.mode == CHAIN_GRAPH_REL) 262 if (callchain_param.mode == CHAIN_GRAPH_REL)
241 total = h->stat.period; 263 total = symbol_conf.cumulate_callchain ?
264 h->stat_acc->period : h->stat.period;
242 265
243 perf_gtk__add_callchain(&h->sorted_chain, store, &iter, 266 perf_gtk__add_callchain(&h->sorted_chain, store, &iter,
244 sym_col, total); 267 sym_col, total);
diff --git a/tools/perf/ui/hist.c b/tools/perf/ui/hist.c
index 4484f5bd1b14..498adb23c02e 100644
--- a/tools/perf/ui/hist.c
+++ b/tools/perf/ui/hist.c
@@ -104,6 +104,18 @@ int __hpp__fmt(struct perf_hpp *hpp, struct hist_entry *he,
104 return ret; 104 return ret;
105} 105}
106 106
107int __hpp__fmt_acc(struct perf_hpp *hpp, struct hist_entry *he,
108 hpp_field_fn get_field, const char *fmt,
109 hpp_snprint_fn print_fn, bool fmt_percent)
110{
111 if (!symbol_conf.cumulate_callchain) {
112 return snprintf(hpp->buf, hpp->size, "%*s",
113 fmt_percent ? 8 : 12, "N/A");
114 }
115
116 return __hpp__fmt(hpp, he, get_field, fmt, print_fn, fmt_percent);
117}
118
107static int field_cmp(u64 field_a, u64 field_b) 119static int field_cmp(u64 field_a, u64 field_b)
108{ 120{
109 if (field_a > field_b) 121 if (field_a > field_b)
@@ -160,6 +172,24 @@ out:
160 return ret; 172 return ret;
161} 173}
162 174
175static int __hpp__sort_acc(struct hist_entry *a, struct hist_entry *b,
176 hpp_field_fn get_field)
177{
178 s64 ret = 0;
179
180 if (symbol_conf.cumulate_callchain) {
181 /*
182 * Put caller above callee when they have equal period.
183 */
184 ret = field_cmp(get_field(a), get_field(b));
185 if (ret)
186 return ret;
187
188 ret = b->callchain->max_depth - a->callchain->max_depth;
189 }
190 return ret;
191}
192
163#define __HPP_HEADER_FN(_type, _str, _min_width, _unit_width) \ 193#define __HPP_HEADER_FN(_type, _str, _min_width, _unit_width) \
164static int hpp__header_##_type(struct perf_hpp_fmt *fmt __maybe_unused, \ 194static int hpp__header_##_type(struct perf_hpp_fmt *fmt __maybe_unused, \
165 struct perf_hpp *hpp, \ 195 struct perf_hpp *hpp, \
@@ -242,6 +272,34 @@ static int64_t hpp__sort_##_type(struct hist_entry *a, struct hist_entry *b) \
242 return __hpp__sort(a, b, he_get_##_field); \ 272 return __hpp__sort(a, b, he_get_##_field); \
243} 273}
244 274
275#define __HPP_COLOR_ACC_PERCENT_FN(_type, _field) \
276static u64 he_get_acc_##_field(struct hist_entry *he) \
277{ \
278 return he->stat_acc->_field; \
279} \
280 \
281static int hpp__color_##_type(struct perf_hpp_fmt *fmt __maybe_unused, \
282 struct perf_hpp *hpp, struct hist_entry *he) \
283{ \
284 return __hpp__fmt_acc(hpp, he, he_get_acc_##_field, " %6.2f%%", \
285 hpp_color_scnprintf, true); \
286}
287
288#define __HPP_ENTRY_ACC_PERCENT_FN(_type, _field) \
289static int hpp__entry_##_type(struct perf_hpp_fmt *_fmt __maybe_unused, \
290 struct perf_hpp *hpp, struct hist_entry *he) \
291{ \
292 const char *fmt = symbol_conf.field_sep ? " %.2f" : " %6.2f%%"; \
293 return __hpp__fmt_acc(hpp, he, he_get_acc_##_field, fmt, \
294 hpp_entry_scnprintf, true); \
295}
296
297#define __HPP_SORT_ACC_FN(_type, _field) \
298static int64_t hpp__sort_##_type(struct hist_entry *a, struct hist_entry *b) \
299{ \
300 return __hpp__sort_acc(a, b, he_get_acc_##_field); \
301}
302
245#define __HPP_ENTRY_RAW_FN(_type, _field) \ 303#define __HPP_ENTRY_RAW_FN(_type, _field) \
246static u64 he_get_raw_##_field(struct hist_entry *he) \ 304static u64 he_get_raw_##_field(struct hist_entry *he) \
247{ \ 305{ \
@@ -270,18 +328,27 @@ __HPP_COLOR_PERCENT_FN(_type, _field) \
270__HPP_ENTRY_PERCENT_FN(_type, _field) \ 328__HPP_ENTRY_PERCENT_FN(_type, _field) \
271__HPP_SORT_FN(_type, _field) 329__HPP_SORT_FN(_type, _field)
272 330
331#define HPP_PERCENT_ACC_FNS(_type, _str, _field, _min_width, _unit_width)\
332__HPP_HEADER_FN(_type, _str, _min_width, _unit_width) \
333__HPP_WIDTH_FN(_type, _min_width, _unit_width) \
334__HPP_COLOR_ACC_PERCENT_FN(_type, _field) \
335__HPP_ENTRY_ACC_PERCENT_FN(_type, _field) \
336__HPP_SORT_ACC_FN(_type, _field)
337
273#define HPP_RAW_FNS(_type, _str, _field, _min_width, _unit_width) \ 338#define HPP_RAW_FNS(_type, _str, _field, _min_width, _unit_width) \
274__HPP_HEADER_FN(_type, _str, _min_width, _unit_width) \ 339__HPP_HEADER_FN(_type, _str, _min_width, _unit_width) \
275__HPP_WIDTH_FN(_type, _min_width, _unit_width) \ 340__HPP_WIDTH_FN(_type, _min_width, _unit_width) \
276__HPP_ENTRY_RAW_FN(_type, _field) \ 341__HPP_ENTRY_RAW_FN(_type, _field) \
277__HPP_SORT_RAW_FN(_type, _field) 342__HPP_SORT_RAW_FN(_type, _field)
278 343
344__HPP_HEADER_FN(overhead_self, "Self", 8, 8)
279 345
280HPP_PERCENT_FNS(overhead, "Overhead", period, 8, 8) 346HPP_PERCENT_FNS(overhead, "Overhead", period, 8, 8)
281HPP_PERCENT_FNS(overhead_sys, "sys", period_sys, 8, 8) 347HPP_PERCENT_FNS(overhead_sys, "sys", period_sys, 8, 8)
282HPP_PERCENT_FNS(overhead_us, "usr", period_us, 8, 8) 348HPP_PERCENT_FNS(overhead_us, "usr", period_us, 8, 8)
283HPP_PERCENT_FNS(overhead_guest_sys, "guest sys", period_guest_sys, 9, 8) 349HPP_PERCENT_FNS(overhead_guest_sys, "guest sys", period_guest_sys, 9, 8)
284HPP_PERCENT_FNS(overhead_guest_us, "guest usr", period_guest_us, 9, 8) 350HPP_PERCENT_FNS(overhead_guest_us, "guest usr", period_guest_us, 9, 8)
351HPP_PERCENT_ACC_FNS(overhead_acc, "Children", period, 8, 8)
285 352
286HPP_RAW_FNS(samples, "Samples", nr_events, 12, 12) 353HPP_RAW_FNS(samples, "Samples", nr_events, 12, 12)
287HPP_RAW_FNS(period, "Period", period, 12, 12) 354HPP_RAW_FNS(period, "Period", period, 12, 12)
@@ -303,6 +370,17 @@ static int64_t hpp__nop_cmp(struct hist_entry *a __maybe_unused,
303 .sort = hpp__sort_ ## _name, \ 370 .sort = hpp__sort_ ## _name, \
304 } 371 }
305 372
373#define HPP__COLOR_ACC_PRINT_FNS(_name) \
374 { \
375 .header = hpp__header_ ## _name, \
376 .width = hpp__width_ ## _name, \
377 .color = hpp__color_ ## _name, \
378 .entry = hpp__entry_ ## _name, \
379 .cmp = hpp__nop_cmp, \
380 .collapse = hpp__nop_cmp, \
381 .sort = hpp__sort_ ## _name, \
382 }
383
306#define HPP__PRINT_FNS(_name) \ 384#define HPP__PRINT_FNS(_name) \
307 { \ 385 { \
308 .header = hpp__header_ ## _name, \ 386 .header = hpp__header_ ## _name, \
@@ -319,6 +397,7 @@ struct perf_hpp_fmt perf_hpp__format[] = {
319 HPP__COLOR_PRINT_FNS(overhead_us), 397 HPP__COLOR_PRINT_FNS(overhead_us),
320 HPP__COLOR_PRINT_FNS(overhead_guest_sys), 398 HPP__COLOR_PRINT_FNS(overhead_guest_sys),
321 HPP__COLOR_PRINT_FNS(overhead_guest_us), 399 HPP__COLOR_PRINT_FNS(overhead_guest_us),
400 HPP__COLOR_ACC_PRINT_FNS(overhead_acc),
322 HPP__PRINT_FNS(samples), 401 HPP__PRINT_FNS(samples),
323 HPP__PRINT_FNS(period) 402 HPP__PRINT_FNS(period)
324}; 403};
@@ -328,16 +407,23 @@ LIST_HEAD(perf_hpp__sort_list);
328 407
329 408
330#undef HPP__COLOR_PRINT_FNS 409#undef HPP__COLOR_PRINT_FNS
410#undef HPP__COLOR_ACC_PRINT_FNS
331#undef HPP__PRINT_FNS 411#undef HPP__PRINT_FNS
332 412
333#undef HPP_PERCENT_FNS 413#undef HPP_PERCENT_FNS
414#undef HPP_PERCENT_ACC_FNS
334#undef HPP_RAW_FNS 415#undef HPP_RAW_FNS
335 416
336#undef __HPP_HEADER_FN 417#undef __HPP_HEADER_FN
337#undef __HPP_WIDTH_FN 418#undef __HPP_WIDTH_FN
338#undef __HPP_COLOR_PERCENT_FN 419#undef __HPP_COLOR_PERCENT_FN
339#undef __HPP_ENTRY_PERCENT_FN 420#undef __HPP_ENTRY_PERCENT_FN
421#undef __HPP_COLOR_ACC_PERCENT_FN
422#undef __HPP_ENTRY_ACC_PERCENT_FN
340#undef __HPP_ENTRY_RAW_FN 423#undef __HPP_ENTRY_RAW_FN
424#undef __HPP_SORT_FN
425#undef __HPP_SORT_ACC_FN
426#undef __HPP_SORT_RAW_FN
341 427
342 428
343void perf_hpp__init(void) 429void perf_hpp__init(void)
@@ -361,6 +447,13 @@ void perf_hpp__init(void)
361 if (field_order) 447 if (field_order)
362 return; 448 return;
363 449
450 if (symbol_conf.cumulate_callchain) {
451 perf_hpp__column_enable(PERF_HPP__OVERHEAD_ACC);
452
453 perf_hpp__format[PERF_HPP__OVERHEAD].header =
454 hpp__header_overhead_self;
455 }
456
364 perf_hpp__column_enable(PERF_HPP__OVERHEAD); 457 perf_hpp__column_enable(PERF_HPP__OVERHEAD);
365 458
366 if (symbol_conf.show_cpu_utilization) { 459 if (symbol_conf.show_cpu_utilization) {
@@ -383,6 +476,12 @@ void perf_hpp__init(void)
383 list = &perf_hpp__format[PERF_HPP__OVERHEAD].sort_list; 476 list = &perf_hpp__format[PERF_HPP__OVERHEAD].sort_list;
384 if (list_empty(list)) 477 if (list_empty(list))
385 list_add(list, &perf_hpp__sort_list); 478 list_add(list, &perf_hpp__sort_list);
479
480 if (symbol_conf.cumulate_callchain) {
481 list = &perf_hpp__format[PERF_HPP__OVERHEAD_ACC].sort_list;
482 if (list_empty(list))
483 list_add(list, &perf_hpp__sort_list);
484 }
386} 485}
387 486
388void perf_hpp__column_register(struct perf_hpp_fmt *format) 487void perf_hpp__column_register(struct perf_hpp_fmt *format)
@@ -390,6 +489,11 @@ void perf_hpp__column_register(struct perf_hpp_fmt *format)
390 list_add_tail(&format->list, &perf_hpp__list); 489 list_add_tail(&format->list, &perf_hpp__list);
391} 490}
392 491
492void perf_hpp__column_unregister(struct perf_hpp_fmt *format)
493{
494 list_del(&format->list);
495}
496
393void perf_hpp__register_sort_field(struct perf_hpp_fmt *format) 497void perf_hpp__register_sort_field(struct perf_hpp_fmt *format)
394{ 498{
395 list_add_tail(&format->sort_list, &perf_hpp__sort_list); 499 list_add_tail(&format->sort_list, &perf_hpp__sort_list);
@@ -401,6 +505,21 @@ void perf_hpp__column_enable(unsigned col)
401 perf_hpp__column_register(&perf_hpp__format[col]); 505 perf_hpp__column_register(&perf_hpp__format[col]);
402} 506}
403 507
508void perf_hpp__column_disable(unsigned col)
509{
510 BUG_ON(col >= PERF_HPP__MAX_INDEX);
511 perf_hpp__column_unregister(&perf_hpp__format[col]);
512}
513
514void perf_hpp__cancel_cumulate(void)
515{
516 if (field_order)
517 return;
518
519 perf_hpp__column_disable(PERF_HPP__OVERHEAD_ACC);
520 perf_hpp__format[PERF_HPP__OVERHEAD].header = hpp__header_overhead;
521}
522
404void perf_hpp__setup_output_field(void) 523void perf_hpp__setup_output_field(void)
405{ 524{
406 struct perf_hpp_fmt *fmt; 525 struct perf_hpp_fmt *fmt;
diff --git a/tools/perf/ui/stdio/hist.c b/tools/perf/ui/stdio/hist.c
index 9f57991025a9..90122abd3721 100644
--- a/tools/perf/ui/stdio/hist.c
+++ b/tools/perf/ui/stdio/hist.c
@@ -271,7 +271,9 @@ static size_t hist_entry_callchain__fprintf(struct hist_entry *he,
271{ 271{
272 switch (callchain_param.mode) { 272 switch (callchain_param.mode) {
273 case CHAIN_GRAPH_REL: 273 case CHAIN_GRAPH_REL:
274 return callchain__fprintf_graph(fp, &he->sorted_chain, he->stat.period, 274 return callchain__fprintf_graph(fp, &he->sorted_chain,
275 symbol_conf.cumulate_callchain ?
276 he->stat_acc->period : he->stat.period,
275 left_margin); 277 left_margin);
276 break; 278 break;
277 case CHAIN_GRAPH_ABS: 279 case CHAIN_GRAPH_ABS:
@@ -461,12 +463,12 @@ print_entries:
461 463
462 for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) { 464 for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) {
463 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); 465 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
464 float percent = h->stat.period * 100.0 / 466 float percent;
465 hists->stats.total_period;
466 467
467 if (h->filtered) 468 if (h->filtered)
468 continue; 469 continue;
469 470
471 percent = hist_entry__get_percent_limit(h);
470 if (percent < min_pcnt) 472 if (percent < min_pcnt)
471 continue; 473 continue;
472 474
diff --git a/tools/perf/util/callchain.c b/tools/perf/util/callchain.c
index 9a42382b3921..48b6d3f50012 100644
--- a/tools/perf/util/callchain.c
+++ b/tools/perf/util/callchain.c
@@ -616,7 +616,8 @@ int sample__resolve_callchain(struct perf_sample *sample, struct symbol **parent
616 if (sample->callchain == NULL) 616 if (sample->callchain == NULL)
617 return 0; 617 return 0;
618 618
619 if (symbol_conf.use_callchain || sort__has_parent) { 619 if (symbol_conf.use_callchain || symbol_conf.cumulate_callchain ||
620 sort__has_parent) {
620 return machine__resolve_callchain(al->machine, evsel, al->thread, 621 return machine__resolve_callchain(al->machine, evsel, al->thread,
621 sample, parent, al, max_stack); 622 sample, parent, al, max_stack);
622 } 623 }
@@ -629,3 +630,45 @@ int hist_entry__append_callchain(struct hist_entry *he, struct perf_sample *samp
629 return 0; 630 return 0;
630 return callchain_append(he->callchain, &callchain_cursor, sample->period); 631 return callchain_append(he->callchain, &callchain_cursor, sample->period);
631} 632}
633
634int fill_callchain_info(struct addr_location *al, struct callchain_cursor_node *node,
635 bool hide_unresolved)
636{
637 al->map = node->map;
638 al->sym = node->sym;
639 if (node->map)
640 al->addr = node->map->map_ip(node->map, node->ip);
641 else
642 al->addr = node->ip;
643
644 if (al->sym == NULL) {
645 if (hide_unresolved)
646 return 0;
647 if (al->map == NULL)
648 goto out;
649 }
650
651 if (al->map->groups == &al->machine->kmaps) {
652 if (machine__is_host(al->machine)) {
653 al->cpumode = PERF_RECORD_MISC_KERNEL;
654 al->level = 'k';
655 } else {
656 al->cpumode = PERF_RECORD_MISC_GUEST_KERNEL;
657 al->level = 'g';
658 }
659 } else {
660 if (machine__is_host(al->machine)) {
661 al->cpumode = PERF_RECORD_MISC_USER;
662 al->level = '.';
663 } else if (perf_guest) {
664 al->cpumode = PERF_RECORD_MISC_GUEST_USER;
665 al->level = 'u';
666 } else {
667 al->cpumode = PERF_RECORD_MISC_HYPERVISOR;
668 al->level = 'H';
669 }
670 }
671
672out:
673 return 1;
674}
diff --git a/tools/perf/util/callchain.h b/tools/perf/util/callchain.h
index bde2b0cc24cf..8f84423a75da 100644
--- a/tools/perf/util/callchain.h
+++ b/tools/perf/util/callchain.h
@@ -162,7 +162,18 @@ int sample__resolve_callchain(struct perf_sample *sample, struct symbol **parent
162 struct perf_evsel *evsel, struct addr_location *al, 162 struct perf_evsel *evsel, struct addr_location *al,
163 int max_stack); 163 int max_stack);
164int hist_entry__append_callchain(struct hist_entry *he, struct perf_sample *sample); 164int hist_entry__append_callchain(struct hist_entry *he, struct perf_sample *sample);
165int fill_callchain_info(struct addr_location *al, struct callchain_cursor_node *node,
166 bool hide_unresolved);
165 167
166extern const char record_callchain_help[]; 168extern const char record_callchain_help[];
167int parse_callchain_report_opt(const char *arg); 169int parse_callchain_report_opt(const char *arg);
170
171static inline void callchain_cursor_snapshot(struct callchain_cursor *dest,
172 struct callchain_cursor *src)
173{
174 *dest = *src;
175
176 dest->first = src->curr;
177 dest->nr -= src->pos;
178}
168#endif /* __PERF_CALLCHAIN_H */ 179#endif /* __PERF_CALLCHAIN_H */
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c
index b262b44b7a65..5a0a4b2cadc4 100644
--- a/tools/perf/util/hist.c
+++ b/tools/perf/util/hist.c
@@ -4,6 +4,7 @@
4#include "session.h" 4#include "session.h"
5#include "sort.h" 5#include "sort.h"
6#include "evsel.h" 6#include "evsel.h"
7#include "annotate.h"
7#include <math.h> 8#include <math.h>
8 9
9static bool hists__filter_entry_by_dso(struct hists *hists, 10static bool hists__filter_entry_by_dso(struct hists *hists,
@@ -231,6 +232,8 @@ static bool hists__decay_entry(struct hists *hists, struct hist_entry *he)
231 return true; 232 return true;
232 233
233 he_stat__decay(&he->stat); 234 he_stat__decay(&he->stat);
235 if (symbol_conf.cumulate_callchain)
236 he_stat__decay(he->stat_acc);
234 237
235 diff = prev_period - he->stat.period; 238 diff = prev_period - he->stat.period;
236 239
@@ -276,14 +279,31 @@ void hists__decay_entries(struct hists *hists, bool zap_user, bool zap_kernel)
276 * histogram, sorted on item, collects periods 279 * histogram, sorted on item, collects periods
277 */ 280 */
278 281
279static struct hist_entry *hist_entry__new(struct hist_entry *template) 282static struct hist_entry *hist_entry__new(struct hist_entry *template,
283 bool sample_self)
280{ 284{
281 size_t callchain_size = symbol_conf.use_callchain ? sizeof(struct callchain_root) : 0; 285 size_t callchain_size = 0;
282 struct hist_entry *he = zalloc(sizeof(*he) + callchain_size); 286 struct hist_entry *he;
287
288 if (symbol_conf.use_callchain || symbol_conf.cumulate_callchain)
289 callchain_size = sizeof(struct callchain_root);
290
291 he = zalloc(sizeof(*he) + callchain_size);
283 292
284 if (he != NULL) { 293 if (he != NULL) {
285 *he = *template; 294 *he = *template;
286 295
296 if (symbol_conf.cumulate_callchain) {
297 he->stat_acc = malloc(sizeof(he->stat));
298 if (he->stat_acc == NULL) {
299 free(he);
300 return NULL;
301 }
302 memcpy(he->stat_acc, &he->stat, sizeof(he->stat));
303 if (!sample_self)
304 memset(&he->stat, 0, sizeof(he->stat));
305 }
306
287 if (he->ms.map) 307 if (he->ms.map)
288 he->ms.map->referenced = true; 308 he->ms.map->referenced = true;
289 309
@@ -295,6 +315,7 @@ static struct hist_entry *hist_entry__new(struct hist_entry *template)
295 */ 315 */
296 he->branch_info = malloc(sizeof(*he->branch_info)); 316 he->branch_info = malloc(sizeof(*he->branch_info));
297 if (he->branch_info == NULL) { 317 if (he->branch_info == NULL) {
318 free(he->stat_acc);
298 free(he); 319 free(he);
299 return NULL; 320 return NULL;
300 } 321 }
@@ -333,7 +354,8 @@ static u8 symbol__parent_filter(const struct symbol *parent)
333 354
334static struct hist_entry *add_hist_entry(struct hists *hists, 355static struct hist_entry *add_hist_entry(struct hists *hists,
335 struct hist_entry *entry, 356 struct hist_entry *entry,
336 struct addr_location *al) 357 struct addr_location *al,
358 bool sample_self)
337{ 359{
338 struct rb_node **p; 360 struct rb_node **p;
339 struct rb_node *parent = NULL; 361 struct rb_node *parent = NULL;
@@ -357,7 +379,10 @@ static struct hist_entry *add_hist_entry(struct hists *hists,
357 cmp = hist_entry__cmp(he, entry); 379 cmp = hist_entry__cmp(he, entry);
358 380
359 if (!cmp) { 381 if (!cmp) {
360 he_stat__add_period(&he->stat, period, weight); 382 if (sample_self)
383 he_stat__add_period(&he->stat, period, weight);
384 if (symbol_conf.cumulate_callchain)
385 he_stat__add_period(he->stat_acc, period, weight);
361 386
362 /* 387 /*
363 * This mem info was allocated from sample__resolve_mem 388 * This mem info was allocated from sample__resolve_mem
@@ -385,14 +410,17 @@ static struct hist_entry *add_hist_entry(struct hists *hists,
385 p = &(*p)->rb_right; 410 p = &(*p)->rb_right;
386 } 411 }
387 412
388 he = hist_entry__new(entry); 413 he = hist_entry__new(entry, sample_self);
389 if (!he) 414 if (!he)
390 return NULL; 415 return NULL;
391 416
392 rb_link_node(&he->rb_node_in, parent, p); 417 rb_link_node(&he->rb_node_in, parent, p);
393 rb_insert_color(&he->rb_node_in, hists->entries_in); 418 rb_insert_color(&he->rb_node_in, hists->entries_in);
394out: 419out:
395 he_stat__add_cpumode_period(&he->stat, al->cpumode, period); 420 if (sample_self)
421 he_stat__add_cpumode_period(&he->stat, al->cpumode, period);
422 if (symbol_conf.cumulate_callchain)
423 he_stat__add_cpumode_period(he->stat_acc, al->cpumode, period);
396 return he; 424 return he;
397} 425}
398 426
@@ -401,7 +429,8 @@ struct hist_entry *__hists__add_entry(struct hists *hists,
401 struct symbol *sym_parent, 429 struct symbol *sym_parent,
402 struct branch_info *bi, 430 struct branch_info *bi,
403 struct mem_info *mi, 431 struct mem_info *mi,
404 u64 period, u64 weight, u64 transaction) 432 u64 period, u64 weight, u64 transaction,
433 bool sample_self)
405{ 434{
406 struct hist_entry entry = { 435 struct hist_entry entry = {
407 .thread = al->thread, 436 .thread = al->thread,
@@ -426,7 +455,429 @@ struct hist_entry *__hists__add_entry(struct hists *hists,
426 .transaction = transaction, 455 .transaction = transaction,
427 }; 456 };
428 457
429 return add_hist_entry(hists, &entry, al); 458 return add_hist_entry(hists, &entry, al, sample_self);
459}
460
461static int
462iter_next_nop_entry(struct hist_entry_iter *iter __maybe_unused,
463 struct addr_location *al __maybe_unused)
464{
465 return 0;
466}
467
468static int
469iter_add_next_nop_entry(struct hist_entry_iter *iter __maybe_unused,
470 struct addr_location *al __maybe_unused)
471{
472 return 0;
473}
474
475static int
476iter_prepare_mem_entry(struct hist_entry_iter *iter, struct addr_location *al)
477{
478 struct perf_sample *sample = iter->sample;
479 struct mem_info *mi;
480
481 mi = sample__resolve_mem(sample, al);
482 if (mi == NULL)
483 return -ENOMEM;
484
485 iter->priv = mi;
486 return 0;
487}
488
489static int
490iter_add_single_mem_entry(struct hist_entry_iter *iter, struct addr_location *al)
491{
492 u64 cost;
493 struct mem_info *mi = iter->priv;
494 struct hist_entry *he;
495
496 if (mi == NULL)
497 return -EINVAL;
498
499 cost = iter->sample->weight;
500 if (!cost)
501 cost = 1;
502
503 /*
504 * must pass period=weight in order to get the correct
505 * sorting from hists__collapse_resort() which is solely
506 * based on periods. We want sorting be done on nr_events * weight
507 * and this is indirectly achieved by passing period=weight here
508 * and the he_stat__add_period() function.
509 */
510 he = __hists__add_entry(&iter->evsel->hists, al, iter->parent, NULL, mi,
511 cost, cost, 0, true);
512 if (!he)
513 return -ENOMEM;
514
515 iter->he = he;
516 return 0;
517}
518
519static int
520iter_finish_mem_entry(struct hist_entry_iter *iter,
521 struct addr_location *al __maybe_unused)
522{
523 struct perf_evsel *evsel = iter->evsel;
524 struct hist_entry *he = iter->he;
525 int err = -EINVAL;
526
527 if (he == NULL)
528 goto out;
529
530 hists__inc_nr_samples(&evsel->hists, he->filtered);
531
532 err = hist_entry__append_callchain(he, iter->sample);
533
534out:
535 /*
536 * We don't need to free iter->priv (mem_info) here since
537 * the mem info was either already freed in add_hist_entry() or
538 * passed to a new hist entry by hist_entry__new().
539 */
540 iter->priv = NULL;
541
542 iter->he = NULL;
543 return err;
544}
545
546static int
547iter_prepare_branch_entry(struct hist_entry_iter *iter, struct addr_location *al)
548{
549 struct branch_info *bi;
550 struct perf_sample *sample = iter->sample;
551
552 bi = sample__resolve_bstack(sample, al);
553 if (!bi)
554 return -ENOMEM;
555
556 iter->curr = 0;
557 iter->total = sample->branch_stack->nr;
558
559 iter->priv = bi;
560 return 0;
561}
562
563static int
564iter_add_single_branch_entry(struct hist_entry_iter *iter __maybe_unused,
565 struct addr_location *al __maybe_unused)
566{
567 /* to avoid calling callback function */
568 iter->he = NULL;
569
570 return 0;
571}
572
573static int
574iter_next_branch_entry(struct hist_entry_iter *iter, struct addr_location *al)
575{
576 struct branch_info *bi = iter->priv;
577 int i = iter->curr;
578
579 if (bi == NULL)
580 return 0;
581
582 if (iter->curr >= iter->total)
583 return 0;
584
585 al->map = bi[i].to.map;
586 al->sym = bi[i].to.sym;
587 al->addr = bi[i].to.addr;
588 return 1;
589}
590
591static int
592iter_add_next_branch_entry(struct hist_entry_iter *iter, struct addr_location *al)
593{
594 struct branch_info *bi;
595 struct perf_evsel *evsel = iter->evsel;
596 struct hist_entry *he = NULL;
597 int i = iter->curr;
598 int err = 0;
599
600 bi = iter->priv;
601
602 if (iter->hide_unresolved && !(bi[i].from.sym && bi[i].to.sym))
603 goto out;
604
605 /*
606 * The report shows the percentage of total branches captured
607 * and not events sampled. Thus we use a pseudo period of 1.
608 */
609 he = __hists__add_entry(&evsel->hists, al, iter->parent, &bi[i], NULL,
610 1, 1, 0, true);
611 if (he == NULL)
612 return -ENOMEM;
613
614 hists__inc_nr_samples(&evsel->hists, he->filtered);
615
616out:
617 iter->he = he;
618 iter->curr++;
619 return err;
620}
621
622static int
623iter_finish_branch_entry(struct hist_entry_iter *iter,
624 struct addr_location *al __maybe_unused)
625{
626 zfree(&iter->priv);
627 iter->he = NULL;
628
629 return iter->curr >= iter->total ? 0 : -1;
630}
631
632static int
633iter_prepare_normal_entry(struct hist_entry_iter *iter __maybe_unused,
634 struct addr_location *al __maybe_unused)
635{
636 return 0;
637}
638
639static int
640iter_add_single_normal_entry(struct hist_entry_iter *iter, struct addr_location *al)
641{
642 struct perf_evsel *evsel = iter->evsel;
643 struct perf_sample *sample = iter->sample;
644 struct hist_entry *he;
645
646 he = __hists__add_entry(&evsel->hists, al, iter->parent, NULL, NULL,
647 sample->period, sample->weight,
648 sample->transaction, true);
649 if (he == NULL)
650 return -ENOMEM;
651
652 iter->he = he;
653 return 0;
654}
655
656static int
657iter_finish_normal_entry(struct hist_entry_iter *iter,
658 struct addr_location *al __maybe_unused)
659{
660 struct hist_entry *he = iter->he;
661 struct perf_evsel *evsel = iter->evsel;
662 struct perf_sample *sample = iter->sample;
663
664 if (he == NULL)
665 return 0;
666
667 iter->he = NULL;
668
669 hists__inc_nr_samples(&evsel->hists, he->filtered);
670
671 return hist_entry__append_callchain(he, sample);
672}
673
674static int
675iter_prepare_cumulative_entry(struct hist_entry_iter *iter __maybe_unused,
676 struct addr_location *al __maybe_unused)
677{
678 struct hist_entry **he_cache;
679
680 callchain_cursor_commit(&callchain_cursor);
681
682 /*
683 * This is for detecting cycles or recursions so that they're
684 * cumulated only one time to prevent entries more than 100%
685 * overhead.
686 */
687 he_cache = malloc(sizeof(*he_cache) * (PERF_MAX_STACK_DEPTH + 1));
688 if (he_cache == NULL)
689 return -ENOMEM;
690
691 iter->priv = he_cache;
692 iter->curr = 0;
693
694 return 0;
695}
696
697static int
698iter_add_single_cumulative_entry(struct hist_entry_iter *iter,
699 struct addr_location *al)
700{
701 struct perf_evsel *evsel = iter->evsel;
702 struct perf_sample *sample = iter->sample;
703 struct hist_entry **he_cache = iter->priv;
704 struct hist_entry *he;
705 int err = 0;
706
707 he = __hists__add_entry(&evsel->hists, al, iter->parent, NULL, NULL,
708 sample->period, sample->weight,
709 sample->transaction, true);
710 if (he == NULL)
711 return -ENOMEM;
712
713 iter->he = he;
714 he_cache[iter->curr++] = he;
715
716 callchain_append(he->callchain, &callchain_cursor, sample->period);
717
718 /*
719 * We need to re-initialize the cursor since callchain_append()
720 * advanced the cursor to the end.
721 */
722 callchain_cursor_commit(&callchain_cursor);
723
724 hists__inc_nr_samples(&evsel->hists, he->filtered);
725
726 return err;
727}
728
729static int
730iter_next_cumulative_entry(struct hist_entry_iter *iter,
731 struct addr_location *al)
732{
733 struct callchain_cursor_node *node;
734
735 node = callchain_cursor_current(&callchain_cursor);
736 if (node == NULL)
737 return 0;
738
739 return fill_callchain_info(al, node, iter->hide_unresolved);
740}
741
742static int
743iter_add_next_cumulative_entry(struct hist_entry_iter *iter,
744 struct addr_location *al)
745{
746 struct perf_evsel *evsel = iter->evsel;
747 struct perf_sample *sample = iter->sample;
748 struct hist_entry **he_cache = iter->priv;
749 struct hist_entry *he;
750 struct hist_entry he_tmp = {
751 .cpu = al->cpu,
752 .thread = al->thread,
753 .comm = thread__comm(al->thread),
754 .ip = al->addr,
755 .ms = {
756 .map = al->map,
757 .sym = al->sym,
758 },
759 .parent = iter->parent,
760 };
761 int i;
762 struct callchain_cursor cursor;
763
764 callchain_cursor_snapshot(&cursor, &callchain_cursor);
765
766 callchain_cursor_advance(&callchain_cursor);
767
768 /*
769 * Check if there's duplicate entries in the callchain.
770 * It's possible that it has cycles or recursive calls.
771 */
772 for (i = 0; i < iter->curr; i++) {
773 if (hist_entry__cmp(he_cache[i], &he_tmp) == 0) {
774 /* to avoid calling callback function */
775 iter->he = NULL;
776 return 0;
777 }
778 }
779
780 he = __hists__add_entry(&evsel->hists, al, iter->parent, NULL, NULL,
781 sample->period, sample->weight,
782 sample->transaction, false);
783 if (he == NULL)
784 return -ENOMEM;
785
786 iter->he = he;
787 he_cache[iter->curr++] = he;
788
789 callchain_append(he->callchain, &cursor, sample->period);
790 return 0;
791}
792
793static int
794iter_finish_cumulative_entry(struct hist_entry_iter *iter,
795 struct addr_location *al __maybe_unused)
796{
797 zfree(&iter->priv);
798 iter->he = NULL;
799
800 return 0;
801}
802
803const struct hist_iter_ops hist_iter_mem = {
804 .prepare_entry = iter_prepare_mem_entry,
805 .add_single_entry = iter_add_single_mem_entry,
806 .next_entry = iter_next_nop_entry,
807 .add_next_entry = iter_add_next_nop_entry,
808 .finish_entry = iter_finish_mem_entry,
809};
810
811const struct hist_iter_ops hist_iter_branch = {
812 .prepare_entry = iter_prepare_branch_entry,
813 .add_single_entry = iter_add_single_branch_entry,
814 .next_entry = iter_next_branch_entry,
815 .add_next_entry = iter_add_next_branch_entry,
816 .finish_entry = iter_finish_branch_entry,
817};
818
819const struct hist_iter_ops hist_iter_normal = {
820 .prepare_entry = iter_prepare_normal_entry,
821 .add_single_entry = iter_add_single_normal_entry,
822 .next_entry = iter_next_nop_entry,
823 .add_next_entry = iter_add_next_nop_entry,
824 .finish_entry = iter_finish_normal_entry,
825};
826
827const struct hist_iter_ops hist_iter_cumulative = {
828 .prepare_entry = iter_prepare_cumulative_entry,
829 .add_single_entry = iter_add_single_cumulative_entry,
830 .next_entry = iter_next_cumulative_entry,
831 .add_next_entry = iter_add_next_cumulative_entry,
832 .finish_entry = iter_finish_cumulative_entry,
833};
834
835int hist_entry_iter__add(struct hist_entry_iter *iter, struct addr_location *al,
836 struct perf_evsel *evsel, struct perf_sample *sample,
837 int max_stack_depth, void *arg)
838{
839 int err, err2;
840
841 err = sample__resolve_callchain(sample, &iter->parent, evsel, al,
842 max_stack_depth);
843 if (err)
844 return err;
845
846 iter->evsel = evsel;
847 iter->sample = sample;
848
849 err = iter->ops->prepare_entry(iter, al);
850 if (err)
851 goto out;
852
853 err = iter->ops->add_single_entry(iter, al);
854 if (err)
855 goto out;
856
857 if (iter->he && iter->add_entry_cb) {
858 err = iter->add_entry_cb(iter, al, true, arg);
859 if (err)
860 goto out;
861 }
862
863 while (iter->ops->next_entry(iter, al)) {
864 err = iter->ops->add_next_entry(iter, al);
865 if (err)
866 break;
867
868 if (iter->he && iter->add_entry_cb) {
869 err = iter->add_entry_cb(iter, al, false, arg);
870 if (err)
871 goto out;
872 }
873 }
874
875out:
876 err2 = iter->ops->finish_entry(iter, al);
877 if (!err)
878 err = err2;
879
880 return err;
430} 881}
431 882
432int64_t 883int64_t
@@ -469,6 +920,7 @@ void hist_entry__free(struct hist_entry *he)
469{ 920{
470 zfree(&he->branch_info); 921 zfree(&he->branch_info);
471 zfree(&he->mem_info); 922 zfree(&he->mem_info);
923 zfree(&he->stat_acc);
472 free_srcline(he->srcline); 924 free_srcline(he->srcline);
473 free(he); 925 free(he);
474} 926}
@@ -494,6 +946,8 @@ static bool hists__collapse_insert_entry(struct hists *hists __maybe_unused,
494 946
495 if (!cmp) { 947 if (!cmp) {
496 he_stat__add_stat(&iter->stat, &he->stat); 948 he_stat__add_stat(&iter->stat, &he->stat);
949 if (symbol_conf.cumulate_callchain)
950 he_stat__add_stat(iter->stat_acc, he->stat_acc);
497 951
498 if (symbol_conf.use_callchain) { 952 if (symbol_conf.use_callchain) {
499 callchain_cursor_reset(&callchain_cursor); 953 callchain_cursor_reset(&callchain_cursor);
@@ -800,6 +1254,13 @@ void hists__inc_nr_events(struct hists *hists, u32 type)
800 events_stats__inc(&hists->stats, type); 1254 events_stats__inc(&hists->stats, type);
801} 1255}
802 1256
1257void hists__inc_nr_samples(struct hists *hists, bool filtered)
1258{
1259 events_stats__inc(&hists->stats, PERF_RECORD_SAMPLE);
1260 if (!filtered)
1261 hists->stats.nr_non_filtered_samples++;
1262}
1263
803static struct hist_entry *hists__add_dummy_entry(struct hists *hists, 1264static struct hist_entry *hists__add_dummy_entry(struct hists *hists,
804 struct hist_entry *pair) 1265 struct hist_entry *pair)
805{ 1266{
@@ -831,7 +1292,7 @@ static struct hist_entry *hists__add_dummy_entry(struct hists *hists,
831 p = &(*p)->rb_right; 1292 p = &(*p)->rb_right;
832 } 1293 }
833 1294
834 he = hist_entry__new(pair); 1295 he = hist_entry__new(pair, true);
835 if (he) { 1296 if (he) {
836 memset(&he->stat, 0, sizeof(he->stat)); 1297 memset(&he->stat, 0, sizeof(he->stat));
837 he->hists = hists; 1298 he->hists = hists;
diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h
index a8418d19808d..d2bf03575d5f 100644
--- a/tools/perf/util/hist.h
+++ b/tools/perf/util/hist.h
@@ -96,12 +96,50 @@ struct hists {
96 u16 col_len[HISTC_NR_COLS]; 96 u16 col_len[HISTC_NR_COLS];
97}; 97};
98 98
99struct hist_entry_iter;
100
101struct hist_iter_ops {
102 int (*prepare_entry)(struct hist_entry_iter *, struct addr_location *);
103 int (*add_single_entry)(struct hist_entry_iter *, struct addr_location *);
104 int (*next_entry)(struct hist_entry_iter *, struct addr_location *);
105 int (*add_next_entry)(struct hist_entry_iter *, struct addr_location *);
106 int (*finish_entry)(struct hist_entry_iter *, struct addr_location *);
107};
108
109struct hist_entry_iter {
110 int total;
111 int curr;
112
113 bool hide_unresolved;
114
115 struct perf_evsel *evsel;
116 struct perf_sample *sample;
117 struct hist_entry *he;
118 struct symbol *parent;
119 void *priv;
120
121 const struct hist_iter_ops *ops;
122 /* user-defined callback function (optional) */
123 int (*add_entry_cb)(struct hist_entry_iter *iter,
124 struct addr_location *al, bool single, void *arg);
125};
126
127extern const struct hist_iter_ops hist_iter_normal;
128extern const struct hist_iter_ops hist_iter_branch;
129extern const struct hist_iter_ops hist_iter_mem;
130extern const struct hist_iter_ops hist_iter_cumulative;
131
99struct hist_entry *__hists__add_entry(struct hists *hists, 132struct hist_entry *__hists__add_entry(struct hists *hists,
100 struct addr_location *al, 133 struct addr_location *al,
101 struct symbol *parent, 134 struct symbol *parent,
102 struct branch_info *bi, 135 struct branch_info *bi,
103 struct mem_info *mi, u64 period, 136 struct mem_info *mi, u64 period,
104 u64 weight, u64 transaction); 137 u64 weight, u64 transaction,
138 bool sample_self);
139int hist_entry_iter__add(struct hist_entry_iter *iter, struct addr_location *al,
140 struct perf_evsel *evsel, struct perf_sample *sample,
141 int max_stack_depth, void *arg);
142
105int64_t hist_entry__cmp(struct hist_entry *left, struct hist_entry *right); 143int64_t hist_entry__cmp(struct hist_entry *left, struct hist_entry *right);
106int64_t hist_entry__collapse(struct hist_entry *left, struct hist_entry *right); 144int64_t hist_entry__collapse(struct hist_entry *left, struct hist_entry *right);
107int hist_entry__transaction_len(void); 145int hist_entry__transaction_len(void);
@@ -119,6 +157,7 @@ u64 hists__total_period(struct hists *hists);
119void hists__reset_stats(struct hists *hists); 157void hists__reset_stats(struct hists *hists);
120void hists__inc_stats(struct hists *hists, struct hist_entry *h); 158void hists__inc_stats(struct hists *hists, struct hist_entry *h);
121void hists__inc_nr_events(struct hists *hists, u32 type); 159void hists__inc_nr_events(struct hists *hists, u32 type);
160void hists__inc_nr_samples(struct hists *hists, bool filtered);
122void events_stats__inc(struct events_stats *stats, u32 type); 161void events_stats__inc(struct events_stats *stats, u32 type);
123size_t events_stats__fprintf(struct events_stats *stats, FILE *fp); 162size_t events_stats__fprintf(struct events_stats *stats, FILE *fp);
124 163
@@ -166,6 +205,7 @@ struct perf_hpp_fmt {
166 205
167 struct list_head list; 206 struct list_head list;
168 struct list_head sort_list; 207 struct list_head sort_list;
208 bool elide;
169}; 209};
170 210
171extern struct list_head perf_hpp__list; 211extern struct list_head perf_hpp__list;
@@ -192,6 +232,7 @@ enum {
192 PERF_HPP__OVERHEAD_US, 232 PERF_HPP__OVERHEAD_US,
193 PERF_HPP__OVERHEAD_GUEST_SYS, 233 PERF_HPP__OVERHEAD_GUEST_SYS,
194 PERF_HPP__OVERHEAD_GUEST_US, 234 PERF_HPP__OVERHEAD_GUEST_US,
235 PERF_HPP__OVERHEAD_ACC,
195 PERF_HPP__SAMPLES, 236 PERF_HPP__SAMPLES,
196 PERF_HPP__PERIOD, 237 PERF_HPP__PERIOD,
197 238
@@ -200,7 +241,11 @@ enum {
200 241
201void perf_hpp__init(void); 242void perf_hpp__init(void);
202void perf_hpp__column_register(struct perf_hpp_fmt *format); 243void perf_hpp__column_register(struct perf_hpp_fmt *format);
244void perf_hpp__column_unregister(struct perf_hpp_fmt *format);
203void perf_hpp__column_enable(unsigned col); 245void perf_hpp__column_enable(unsigned col);
246void perf_hpp__column_disable(unsigned col);
247void perf_hpp__cancel_cumulate(void);
248
204void perf_hpp__register_sort_field(struct perf_hpp_fmt *format); 249void perf_hpp__register_sort_field(struct perf_hpp_fmt *format);
205void perf_hpp__setup_output_field(void); 250void perf_hpp__setup_output_field(void);
206void perf_hpp__reset_output_field(void); 251void perf_hpp__reset_output_field(void);
@@ -208,7 +253,12 @@ void perf_hpp__append_sort_keys(void);
208 253
209bool perf_hpp__is_sort_entry(struct perf_hpp_fmt *format); 254bool perf_hpp__is_sort_entry(struct perf_hpp_fmt *format);
210bool perf_hpp__same_sort_entry(struct perf_hpp_fmt *a, struct perf_hpp_fmt *b); 255bool perf_hpp__same_sort_entry(struct perf_hpp_fmt *a, struct perf_hpp_fmt *b);
211bool perf_hpp__should_skip(struct perf_hpp_fmt *format); 256
257static inline bool perf_hpp__should_skip(struct perf_hpp_fmt *format)
258{
259 return format->elide;
260}
261
212void perf_hpp__reset_width(struct perf_hpp_fmt *fmt, struct hists *hists); 262void perf_hpp__reset_width(struct perf_hpp_fmt *fmt, struct hists *hists);
213 263
214typedef u64 (*hpp_field_fn)(struct hist_entry *he); 264typedef u64 (*hpp_field_fn)(struct hist_entry *he);
@@ -218,6 +268,9 @@ typedef int (*hpp_snprint_fn)(struct perf_hpp *hpp, const char *fmt, ...);
218int __hpp__fmt(struct perf_hpp *hpp, struct hist_entry *he, 268int __hpp__fmt(struct perf_hpp *hpp, struct hist_entry *he,
219 hpp_field_fn get_field, const char *fmt, 269 hpp_field_fn get_field, const char *fmt,
220 hpp_snprint_fn print_fn, bool fmt_percent); 270 hpp_snprint_fn print_fn, bool fmt_percent);
271int __hpp__fmt_acc(struct perf_hpp *hpp, struct hist_entry *he,
272 hpp_field_fn get_field, const char *fmt,
273 hpp_snprint_fn print_fn, bool fmt_percent);
221 274
222static inline void advance_hpp(struct perf_hpp *hpp, int inc) 275static inline void advance_hpp(struct perf_hpp *hpp, int inc)
223{ 276{
diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c
index 901b9bece2ee..45512baaab67 100644
--- a/tools/perf/util/sort.c
+++ b/tools/perf/util/sort.c
@@ -1061,6 +1061,7 @@ static struct hpp_dimension hpp_sort_dimensions[] = {
1061 DIM(PERF_HPP__OVERHEAD_US, "overhead_us"), 1061 DIM(PERF_HPP__OVERHEAD_US, "overhead_us"),
1062 DIM(PERF_HPP__OVERHEAD_GUEST_SYS, "overhead_guest_sys"), 1062 DIM(PERF_HPP__OVERHEAD_GUEST_SYS, "overhead_guest_sys"),
1063 DIM(PERF_HPP__OVERHEAD_GUEST_US, "overhead_guest_us"), 1063 DIM(PERF_HPP__OVERHEAD_GUEST_US, "overhead_guest_us"),
1064 DIM(PERF_HPP__OVERHEAD_ACC, "overhead_children"),
1064 DIM(PERF_HPP__SAMPLES, "sample"), 1065 DIM(PERF_HPP__SAMPLES, "sample"),
1065 DIM(PERF_HPP__PERIOD, "period"), 1066 DIM(PERF_HPP__PERIOD, "period"),
1066}; 1067};
@@ -1156,6 +1157,7 @@ __sort_dimension__alloc_hpp(struct sort_dimension *sd)
1156 1157
1157 INIT_LIST_HEAD(&hse->hpp.list); 1158 INIT_LIST_HEAD(&hse->hpp.list);
1158 INIT_LIST_HEAD(&hse->hpp.sort_list); 1159 INIT_LIST_HEAD(&hse->hpp.sort_list);
1160 hse->hpp.elide = false;
1159 1161
1160 return hse; 1162 return hse;
1161} 1163}
@@ -1363,27 +1365,64 @@ static int __setup_sorting(void)
1363 return ret; 1365 return ret;
1364} 1366}
1365 1367
1366bool perf_hpp__should_skip(struct perf_hpp_fmt *format) 1368void perf_hpp__set_elide(int idx, bool elide)
1367{ 1369{
1368 if (perf_hpp__is_sort_entry(format)) { 1370 struct perf_hpp_fmt *fmt;
1369 struct hpp_sort_entry *hse; 1371 struct hpp_sort_entry *hse;
1372
1373 perf_hpp__for_each_format(fmt) {
1374 if (!perf_hpp__is_sort_entry(fmt))
1375 continue;
1370 1376
1371 hse = container_of(format, struct hpp_sort_entry, hpp); 1377 hse = container_of(fmt, struct hpp_sort_entry, hpp);
1372 return hse->se->elide; 1378 if (hse->se->se_width_idx == idx) {
1379 fmt->elide = elide;
1380 break;
1381 }
1373 } 1382 }
1374 return false;
1375} 1383}
1376 1384
1377static void sort_entry__setup_elide(struct sort_entry *se, 1385static bool __get_elide(struct strlist *list, const char *list_name, FILE *fp)
1378 struct strlist *list,
1379 const char *list_name, FILE *fp)
1380{ 1386{
1381 if (list && strlist__nr_entries(list) == 1) { 1387 if (list && strlist__nr_entries(list) == 1) {
1382 if (fp != NULL) 1388 if (fp != NULL)
1383 fprintf(fp, "# %s: %s\n", list_name, 1389 fprintf(fp, "# %s: %s\n", list_name,
1384 strlist__entry(list, 0)->s); 1390 strlist__entry(list, 0)->s);
1385 se->elide = true; 1391 return true;
1386 } 1392 }
1393 return false;
1394}
1395
1396static bool get_elide(int idx, FILE *output)
1397{
1398 switch (idx) {
1399 case HISTC_SYMBOL:
1400 return __get_elide(symbol_conf.sym_list, "symbol", output);
1401 case HISTC_DSO:
1402 return __get_elide(symbol_conf.dso_list, "dso", output);
1403 case HISTC_COMM:
1404 return __get_elide(symbol_conf.comm_list, "comm", output);
1405 default:
1406 break;
1407 }
1408
1409 if (sort__mode != SORT_MODE__BRANCH)
1410 return false;
1411
1412 switch (idx) {
1413 case HISTC_SYMBOL_FROM:
1414 return __get_elide(symbol_conf.sym_from_list, "sym_from", output);
1415 case HISTC_SYMBOL_TO:
1416 return __get_elide(symbol_conf.sym_to_list, "sym_to", output);
1417 case HISTC_DSO_FROM:
1418 return __get_elide(symbol_conf.dso_from_list, "dso_from", output);
1419 case HISTC_DSO_TO:
1420 return __get_elide(symbol_conf.dso_to_list, "dso_to", output);
1421 default:
1422 break;
1423 }
1424
1425 return false;
1387} 1426}
1388 1427
1389void sort__setup_elide(FILE *output) 1428void sort__setup_elide(FILE *output)
@@ -1391,39 +1430,12 @@ void sort__setup_elide(FILE *output)
1391 struct perf_hpp_fmt *fmt; 1430 struct perf_hpp_fmt *fmt;
1392 struct hpp_sort_entry *hse; 1431 struct hpp_sort_entry *hse;
1393 1432
1394 sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list, 1433 perf_hpp__for_each_format(fmt) {
1395 "dso", output); 1434 if (!perf_hpp__is_sort_entry(fmt))
1396 sort_entry__setup_elide(&sort_comm, symbol_conf.comm_list, 1435 continue;
1397 "comm", output); 1436
1398 sort_entry__setup_elide(&sort_sym, symbol_conf.sym_list, 1437 hse = container_of(fmt, struct hpp_sort_entry, hpp);
1399 "symbol", output); 1438 fmt->elide = get_elide(hse->se->se_width_idx, output);
1400
1401 if (sort__mode == SORT_MODE__BRANCH) {
1402 sort_entry__setup_elide(&sort_dso_from,
1403 symbol_conf.dso_from_list,
1404 "dso_from", output);
1405 sort_entry__setup_elide(&sort_dso_to,
1406 symbol_conf.dso_to_list,
1407 "dso_to", output);
1408 sort_entry__setup_elide(&sort_sym_from,
1409 symbol_conf.sym_from_list,
1410 "sym_from", output);
1411 sort_entry__setup_elide(&sort_sym_to,
1412 symbol_conf.sym_to_list,
1413 "sym_to", output);
1414 } else if (sort__mode == SORT_MODE__MEMORY) {
1415 sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list,
1416 "symbol_daddr", output);
1417 sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list,
1418 "dso_daddr", output);
1419 sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list,
1420 "mem", output);
1421 sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list,
1422 "local_weight", output);
1423 sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list,
1424 "tlb", output);
1425 sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list,
1426 "snoop", output);
1427 } 1439 }
1428 1440
1429 /* 1441 /*
@@ -1434,8 +1446,7 @@ void sort__setup_elide(FILE *output)
1434 if (!perf_hpp__is_sort_entry(fmt)) 1446 if (!perf_hpp__is_sort_entry(fmt))
1435 continue; 1447 continue;
1436 1448
1437 hse = container_of(fmt, struct hpp_sort_entry, hpp); 1449 if (!fmt->elide)
1438 if (!hse->se->elide)
1439 return; 1450 return;
1440 } 1451 }
1441 1452
@@ -1443,8 +1454,7 @@ void sort__setup_elide(FILE *output)
1443 if (!perf_hpp__is_sort_entry(fmt)) 1454 if (!perf_hpp__is_sort_entry(fmt))
1444 continue; 1455 continue;
1445 1456
1446 hse = container_of(fmt, struct hpp_sort_entry, hpp); 1457 fmt->elide = false;
1447 hse->se->elide = false;
1448 } 1458 }
1449} 1459}
1450 1460
@@ -1581,6 +1591,9 @@ void reset_output_field(void)
1581 sort__has_sym = 0; 1591 sort__has_sym = 0;
1582 sort__has_dso = 0; 1592 sort__has_dso = 0;
1583 1593
1594 field_order = NULL;
1595 sort_order = NULL;
1596
1584 reset_dimensions(); 1597 reset_dimensions();
1585 perf_hpp__reset_output_field(); 1598 perf_hpp__reset_output_field();
1586} 1599}
diff --git a/tools/perf/util/sort.h b/tools/perf/util/sort.h
index 5f38d925e92f..5bf0098d6b06 100644
--- a/tools/perf/util/sort.h
+++ b/tools/perf/util/sort.h
@@ -20,7 +20,7 @@
20 20
21#include "parse-options.h" 21#include "parse-options.h"
22#include "parse-events.h" 22#include "parse-events.h"
23 23#include "hist.h"
24#include "thread.h" 24#include "thread.h"
25 25
26extern regex_t parent_regex; 26extern regex_t parent_regex;
@@ -82,6 +82,7 @@ struct hist_entry {
82 struct list_head head; 82 struct list_head head;
83 } pairs; 83 } pairs;
84 struct he_stat stat; 84 struct he_stat stat;
85 struct he_stat *stat_acc;
85 struct map_symbol ms; 86 struct map_symbol ms;
86 struct thread *thread; 87 struct thread *thread;
87 struct comm *comm; 88 struct comm *comm;
@@ -130,6 +131,21 @@ static inline void hist_entry__add_pair(struct hist_entry *pair,
130 list_add_tail(&pair->pairs.node, &he->pairs.head); 131 list_add_tail(&pair->pairs.node, &he->pairs.head);
131} 132}
132 133
134static inline float hist_entry__get_percent_limit(struct hist_entry *he)
135{
136 u64 period = he->stat.period;
137 u64 total_period = hists__total_period(he->hists);
138
139 if (unlikely(total_period == 0))
140 return 0;
141
142 if (symbol_conf.cumulate_callchain)
143 period = he->stat_acc->period;
144
145 return period * 100.0 / total_period;
146}
147
148
133enum sort_mode { 149enum sort_mode {
134 SORT_MODE__NORMAL, 150 SORT_MODE__NORMAL,
135 SORT_MODE__BRANCH, 151 SORT_MODE__BRANCH,
@@ -186,7 +202,6 @@ struct sort_entry {
186 int (*se_snprintf)(struct hist_entry *he, char *bf, size_t size, 202 int (*se_snprintf)(struct hist_entry *he, char *bf, size_t size,
187 unsigned int width); 203 unsigned int width);
188 u8 se_width_idx; 204 u8 se_width_idx;
189 bool elide;
190}; 205};
191 206
192extern struct sort_entry sort_thread; 207extern struct sort_entry sort_thread;
@@ -197,6 +212,7 @@ int setup_output_field(void);
197void reset_output_field(void); 212void reset_output_field(void);
198extern int sort_dimension__add(const char *); 213extern int sort_dimension__add(const char *);
199void sort__setup_elide(FILE *fp); 214void sort__setup_elide(FILE *fp);
215void perf_hpp__set_elide(int idx, bool elide);
200 216
201int report_parse_ignore_callees_opt(const struct option *opt, const char *arg, int unset); 217int report_parse_ignore_callees_opt(const struct option *opt, const char *arg, int unset);
202 218
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
index 95e249779931..7b9096f29cdb 100644
--- a/tools/perf/util/symbol.c
+++ b/tools/perf/util/symbol.c
@@ -29,11 +29,12 @@ int vmlinux_path__nr_entries;
29char **vmlinux_path; 29char **vmlinux_path;
30 30
31struct symbol_conf symbol_conf = { 31struct symbol_conf symbol_conf = {
32 .use_modules = true, 32 .use_modules = true,
33 .try_vmlinux_path = true, 33 .try_vmlinux_path = true,
34 .annotate_src = true, 34 .annotate_src = true,
35 .demangle = true, 35 .demangle = true,
36 .symfs = "", 36 .cumulate_callchain = true,
37 .symfs = "",
37}; 38};
38 39
39static enum dso_binary_type binary_type_symtab[] = { 40static enum dso_binary_type binary_type_symtab[] = {
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h
index 33ede53fa6b9..615c752dd767 100644
--- a/tools/perf/util/symbol.h
+++ b/tools/perf/util/symbol.h
@@ -109,6 +109,7 @@ struct symbol_conf {
109 show_nr_samples, 109 show_nr_samples,
110 show_total_period, 110 show_total_period,
111 use_callchain, 111 use_callchain,
112 cumulate_callchain,
112 exclude_other, 113 exclude_other,
113 show_cpu_utilization, 114 show_cpu_utilization,
114 initialized, 115 initialized,
diff --git a/tools/testing/selftests/net/Makefile b/tools/testing/selftests/net/Makefile
index 750512ba2c88..c7493b8f9b0e 100644
--- a/tools/testing/selftests/net/Makefile
+++ b/tools/testing/selftests/net/Makefile
@@ -14,6 +14,12 @@ all: $(NET_PROGS)
14run_tests: all 14run_tests: all
15 @/bin/sh ./run_netsocktests || echo "sockettests: [FAIL]" 15 @/bin/sh ./run_netsocktests || echo "sockettests: [FAIL]"
16 @/bin/sh ./run_afpackettests || echo "afpackettests: [FAIL]" 16 @/bin/sh ./run_afpackettests || echo "afpackettests: [FAIL]"
17 17 @if /sbin/modprobe test_bpf ; then \
18 /sbin/rmmod test_bpf; \
19 echo "test_bpf: ok"; \
20 else \
21 echo "test_bpf: [FAIL]"; \
22 exit 1; \
23 fi
18clean: 24clean:
19 $(RM) $(NET_PROGS) 25 $(RM) $(NET_PROGS)
diff --git a/tools/testing/selftests/powerpc/Makefile b/tools/testing/selftests/powerpc/Makefile
index b3dbe9ef1a40..54833a791a44 100644
--- a/tools/testing/selftests/powerpc/Makefile
+++ b/tools/testing/selftests/powerpc/Makefile
@@ -13,7 +13,7 @@ CFLAGS := -Wall -O2 -flto -Wall -Werror -DGIT_VERSION='"$(GIT_VERSION)"' -I$(CUR
13 13
14export CC CFLAGS 14export CC CFLAGS
15 15
16TARGETS = pmu copyloops mm 16TARGETS = pmu copyloops mm tm
17 17
18endif 18endif
19 19
diff --git a/tools/testing/selftests/powerpc/harness.c b/tools/testing/selftests/powerpc/harness.c
index e80c42a584fe..8ebc58a09311 100644
--- a/tools/testing/selftests/powerpc/harness.c
+++ b/tools/testing/selftests/powerpc/harness.c
@@ -30,12 +30,15 @@ int run_test(int (test_function)(void), char *name)
30 30
31 pid = fork(); 31 pid = fork();
32 if (pid == 0) { 32 if (pid == 0) {
33 setpgid(0, 0);
33 exit(test_function()); 34 exit(test_function());
34 } else if (pid == -1) { 35 } else if (pid == -1) {
35 perror("fork"); 36 perror("fork");
36 return 1; 37 return 1;
37 } 38 }
38 39
40 setpgid(pid, pid);
41
39 /* Wake us up in timeout seconds */ 42 /* Wake us up in timeout seconds */
40 alarm(TIMEOUT); 43 alarm(TIMEOUT);
41 terminated = false; 44 terminated = false;
@@ -50,17 +53,20 @@ wait:
50 53
51 if (terminated) { 54 if (terminated) {
52 printf("!! force killing %s\n", name); 55 printf("!! force killing %s\n", name);
53 kill(pid, SIGKILL); 56 kill(-pid, SIGKILL);
54 return 1; 57 return 1;
55 } else { 58 } else {
56 printf("!! killing %s\n", name); 59 printf("!! killing %s\n", name);
57 kill(pid, SIGTERM); 60 kill(-pid, SIGTERM);
58 terminated = true; 61 terminated = true;
59 alarm(KILL_TIMEOUT); 62 alarm(KILL_TIMEOUT);
60 goto wait; 63 goto wait;
61 } 64 }
62 } 65 }
63 66
67 /* Kill anything else in the process group that is still running */
68 kill(-pid, SIGTERM);
69
64 if (WIFEXITED(status)) 70 if (WIFEXITED(status))
65 status = WEXITSTATUS(status); 71 status = WEXITSTATUS(status);
66 else { 72 else {
@@ -99,7 +105,10 @@ int test_harness(int (test_function)(void), char *name)
99 105
100 rc = run_test(test_function, name); 106 rc = run_test(test_function, name);
101 107
102 test_finish(name, rc); 108 if (rc == MAGIC_SKIP_RETURN_VALUE)
109 test_skip(name);
110 else
111 test_finish(name, rc);
103 112
104 return rc; 113 return rc;
105} 114}
diff --git a/tools/testing/selftests/powerpc/pmu/Makefile b/tools/testing/selftests/powerpc/pmu/Makefile
index 7216f0091655..b9ff0db42c79 100644
--- a/tools/testing/selftests/powerpc/pmu/Makefile
+++ b/tools/testing/selftests/powerpc/pmu/Makefile
@@ -4,7 +4,7 @@ noarg:
4PROGS := count_instructions 4PROGS := count_instructions
5EXTRA_SOURCES := ../harness.c event.c 5EXTRA_SOURCES := ../harness.c event.c
6 6
7all: $(PROGS) 7all: $(PROGS) sub_all
8 8
9$(PROGS): $(EXTRA_SOURCES) 9$(PROGS): $(EXTRA_SOURCES)
10 10
@@ -12,12 +12,30 @@ $(PROGS): $(EXTRA_SOURCES)
12count_instructions: loop.S count_instructions.c $(EXTRA_SOURCES) 12count_instructions: loop.S count_instructions.c $(EXTRA_SOURCES)
13 $(CC) $(CFLAGS) -m64 -o $@ $^ 13 $(CC) $(CFLAGS) -m64 -o $@ $^
14 14
15run_tests: all 15run_tests: all sub_run_tests
16 @-for PROG in $(PROGS); do \ 16 @-for PROG in $(PROGS); do \
17 ./$$PROG; \ 17 ./$$PROG; \
18 done; 18 done;
19 19
20clean: 20clean: sub_clean
21 rm -f $(PROGS) loop.o 21 rm -f $(PROGS) loop.o
22 22
23.PHONY: all run_tests clean 23
24SUB_TARGETS = ebb
25
26sub_all:
27 @for TARGET in $(SUB_TARGETS); do \
28 $(MAKE) -C $$TARGET all; \
29 done;
30
31sub_run_tests: all
32 @for TARGET in $(SUB_TARGETS); do \
33 $(MAKE) -C $$TARGET run_tests; \
34 done;
35
36sub_clean:
37 @for TARGET in $(SUB_TARGETS); do \
38 $(MAKE) -C $$TARGET clean; \
39 done;
40
41.PHONY: all run_tests clean sub_all sub_run_tests sub_clean
diff --git a/tools/testing/selftests/powerpc/pmu/ebb/Makefile b/tools/testing/selftests/powerpc/pmu/ebb/Makefile
new file mode 100644
index 000000000000..edbba2affc2c
--- /dev/null
+++ b/tools/testing/selftests/powerpc/pmu/ebb/Makefile
@@ -0,0 +1,32 @@
1noarg:
2 $(MAKE) -C ../../
3
4# The EBB handler is 64-bit code and everything links against it
5CFLAGS += -m64
6
7PROGS := reg_access_test event_attributes_test cycles_test \
8 cycles_with_freeze_test pmc56_overflow_test \
9 ebb_vs_cpu_event_test cpu_event_vs_ebb_test \
10 cpu_event_pinned_vs_ebb_test task_event_vs_ebb_test \
11 task_event_pinned_vs_ebb_test multi_ebb_procs_test \
12 multi_counter_test pmae_handling_test \
13 close_clears_pmcc_test instruction_count_test \
14 fork_cleanup_test ebb_on_child_test \
15 ebb_on_willing_child_test back_to_back_ebbs_test \
16 lost_exception_test no_handler_test
17
18all: $(PROGS)
19
20$(PROGS): ../../harness.c ../event.c ../lib.c ebb.c ebb_handler.S trace.c
21
22instruction_count_test: ../loop.S
23
24lost_exception_test: ../lib.c
25
26run_tests: all
27 @-for PROG in $(PROGS); do \
28 ./$$PROG; \
29 done;
30
31clean:
32 rm -f $(PROGS)
diff --git a/tools/testing/selftests/powerpc/pmu/ebb/back_to_back_ebbs_test.c b/tools/testing/selftests/powerpc/pmu/ebb/back_to_back_ebbs_test.c
new file mode 100644
index 000000000000..66ea765c0e72
--- /dev/null
+++ b/tools/testing/selftests/powerpc/pmu/ebb/back_to_back_ebbs_test.c
@@ -0,0 +1,106 @@
1/*
2 * Copyright 2014, Michael Ellerman, IBM Corp.
3 * Licensed under GPLv2.
4 */
5
6#include <stdbool.h>
7#include <stdio.h>
8#include <stdlib.h>
9
10#include "ebb.h"
11
12
13#define NUMBER_OF_EBBS 50
14
15/*
16 * Test that if we overflow the counter while in the EBB handler, we take
17 * another EBB on exiting from the handler.
18 *
19 * We do this by counting with a stupidly low sample period, causing us to
20 * overflow the PMU while we're still in the EBB handler, leading to another
21 * EBB.
22 *
23 * We get out of what would otherwise be an infinite loop by leaving the
24 * counter frozen once we've taken enough EBBs.
25 */
26
27static void ebb_callee(void)
28{
29 uint64_t siar, val;
30
31 val = mfspr(SPRN_BESCR);
32 if (!(val & BESCR_PMEO)) {
33 ebb_state.stats.spurious++;
34 goto out;
35 }
36
37 ebb_state.stats.ebb_count++;
38 trace_log_counter(ebb_state.trace, ebb_state.stats.ebb_count);
39
40 /* Resets the PMC */
41 count_pmc(1, sample_period);
42
43out:
44 if (ebb_state.stats.ebb_count == NUMBER_OF_EBBS)
45 /* Reset but leave counters frozen */
46 reset_ebb_with_clear_mask(MMCR0_PMAO);
47 else
48 /* Unfreezes */
49 reset_ebb();
50
51 /* Do some stuff to chew some cycles and pop the counter */
52 siar = mfspr(SPRN_SIAR);
53 trace_log_reg(ebb_state.trace, SPRN_SIAR, siar);
54
55 val = mfspr(SPRN_PMC1);
56 trace_log_reg(ebb_state.trace, SPRN_PMC1, val);
57
58 val = mfspr(SPRN_MMCR0);
59 trace_log_reg(ebb_state.trace, SPRN_MMCR0, val);
60}
61
62int back_to_back_ebbs(void)
63{
64 struct event event;
65
66 event_init_named(&event, 0x1001e, "cycles");
67 event_leader_ebb_init(&event);
68
69 event.attr.exclude_kernel = 1;
70 event.attr.exclude_hv = 1;
71 event.attr.exclude_idle = 1;
72
73 FAIL_IF(event_open(&event));
74
75 setup_ebb_handler(ebb_callee);
76
77 FAIL_IF(ebb_event_enable(&event));
78
79 sample_period = 5;
80
81 ebb_freeze_pmcs();
82 mtspr(SPRN_PMC1, pmc_sample_period(sample_period));
83 ebb_global_enable();
84 ebb_unfreeze_pmcs();
85
86 while (ebb_state.stats.ebb_count < NUMBER_OF_EBBS)
87 FAIL_IF(core_busy_loop());
88
89 ebb_global_disable();
90 ebb_freeze_pmcs();
91
92 count_pmc(1, sample_period);
93
94 dump_ebb_state();
95
96 event_close(&event);
97
98 FAIL_IF(ebb_state.stats.ebb_count != NUMBER_OF_EBBS);
99
100 return 0;
101}
102
103int main(void)
104{
105 return test_harness(back_to_back_ebbs, "back_to_back_ebbs");
106}
diff --git a/tools/testing/selftests/powerpc/pmu/ebb/close_clears_pmcc_test.c b/tools/testing/selftests/powerpc/pmu/ebb/close_clears_pmcc_test.c
new file mode 100644
index 000000000000..0f0423dba18b
--- /dev/null
+++ b/tools/testing/selftests/powerpc/pmu/ebb/close_clears_pmcc_test.c
@@ -0,0 +1,59 @@
1/*
2 * Copyright 2014, Michael Ellerman, IBM Corp.
3 * Licensed under GPLv2.
4 */
5
6#include <stdio.h>
7#include <stdlib.h>
8#include <setjmp.h>
9#include <signal.h>
10
11#include "ebb.h"
12
13
14/*
15 * Test that closing the EBB event clears MMCR0_PMCC, preventing further access
16 * by userspace to the PMU hardware.
17 */
18
19int close_clears_pmcc(void)
20{
21 struct event event;
22
23 event_init_named(&event, 0x1001e, "cycles");
24 event_leader_ebb_init(&event);
25
26 FAIL_IF(event_open(&event));
27
28 ebb_enable_pmc_counting(1);
29 setup_ebb_handler(standard_ebb_callee);
30 ebb_global_enable();
31 FAIL_IF(ebb_event_enable(&event));
32
33 mtspr(SPRN_PMC1, pmc_sample_period(sample_period));
34
35 while (ebb_state.stats.ebb_count < 1)
36 FAIL_IF(core_busy_loop());
37
38 ebb_global_disable();
39 event_close(&event);
40
41 FAIL_IF(ebb_state.stats.ebb_count == 0);
42
43 /* The real test is here, do we take a SIGILL when writing PMU regs now
44 * that we have closed the event. We expect that we will. */
45
46 FAIL_IF(catch_sigill(write_pmc1));
47
48 /* We should still be able to read EBB regs though */
49 mfspr(SPRN_EBBHR);
50 mfspr(SPRN_EBBRR);
51 mfspr(SPRN_BESCR);
52
53 return 0;
54}
55
56int main(void)
57{
58 return test_harness(close_clears_pmcc, "close_clears_pmcc");
59}
diff --git a/tools/testing/selftests/powerpc/pmu/ebb/cpu_event_pinned_vs_ebb_test.c b/tools/testing/selftests/powerpc/pmu/ebb/cpu_event_pinned_vs_ebb_test.c
new file mode 100644
index 000000000000..d3ed64d5d6c0
--- /dev/null
+++ b/tools/testing/selftests/powerpc/pmu/ebb/cpu_event_pinned_vs_ebb_test.c
@@ -0,0 +1,93 @@
1/*
2 * Copyright 2014, Michael Ellerman, IBM Corp.
3 * Licensed under GPLv2.
4 */
5
6#include <signal.h>
7#include <stdio.h>
8#include <stdlib.h>
9#include <stdbool.h>
10#include <sys/types.h>
11#include <sys/wait.h>
12#include <unistd.h>
13
14#include "ebb.h"
15
16
17/*
18 * Tests a pinned cpu event vs an EBB - in that order. The pinned cpu event
19 * should remain and the EBB event should fail to enable.
20 */
21
22static int setup_cpu_event(struct event *event, int cpu)
23{
24 event_init_named(event, 0x400FA, "PM_RUN_INST_CMPL");
25
26 event->attr.pinned = 1;
27
28 event->attr.exclude_kernel = 1;
29 event->attr.exclude_hv = 1;
30 event->attr.exclude_idle = 1;
31
32 SKIP_IF(require_paranoia_below(1));
33 FAIL_IF(event_open_with_cpu(event, cpu));
34 FAIL_IF(event_enable(event));
35
36 return 0;
37}
38
39int cpu_event_pinned_vs_ebb(void)
40{
41 union pipe read_pipe, write_pipe;
42 struct event event;
43 int cpu, rc;
44 pid_t pid;
45
46 cpu = pick_online_cpu();
47 FAIL_IF(cpu < 0);
48 FAIL_IF(bind_to_cpu(cpu));
49
50 FAIL_IF(pipe(read_pipe.fds) == -1);
51 FAIL_IF(pipe(write_pipe.fds) == -1);
52
53 pid = fork();
54 if (pid == 0) {
55 /* NB order of pipes looks reversed */
56 exit(ebb_child(write_pipe, read_pipe));
57 }
58
59 /* We setup the cpu event first */
60 rc = setup_cpu_event(&event, cpu);
61 if (rc) {
62 kill_child_and_wait(pid);
63 return rc;
64 }
65
66 /* Signal the child to install its EBB event and wait */
67 if (sync_with_child(read_pipe, write_pipe))
68 /* If it fails, wait for it to exit */
69 goto wait;
70
71 /* Signal the child to run */
72 FAIL_IF(sync_with_child(read_pipe, write_pipe));
73
74wait:
75 /* We expect it to fail to read the event */
76 FAIL_IF(wait_for_child(pid) != 2);
77
78 FAIL_IF(event_disable(&event));
79 FAIL_IF(event_read(&event));
80
81 event_report(&event);
82
83 /* The cpu event should have run */
84 FAIL_IF(event.result.value == 0);
85 FAIL_IF(event.result.enabled != event.result.running);
86
87 return 0;
88}
89
90int main(void)
91{
92 return test_harness(cpu_event_pinned_vs_ebb, "cpu_event_pinned_vs_ebb");
93}
diff --git a/tools/testing/selftests/powerpc/pmu/ebb/cpu_event_vs_ebb_test.c b/tools/testing/selftests/powerpc/pmu/ebb/cpu_event_vs_ebb_test.c
new file mode 100644
index 000000000000..8b972c2aa392
--- /dev/null
+++ b/tools/testing/selftests/powerpc/pmu/ebb/cpu_event_vs_ebb_test.c
@@ -0,0 +1,89 @@
1/*
2 * Copyright 2014, Michael Ellerman, IBM Corp.
3 * Licensed under GPLv2.
4 */
5
6#include <signal.h>
7#include <stdio.h>
8#include <stdlib.h>
9#include <stdbool.h>
10#include <sys/types.h>
11#include <sys/wait.h>
12#include <unistd.h>
13
14#include "ebb.h"
15
16
17/*
18 * Tests a cpu event vs an EBB - in that order. The EBB should force the cpu
19 * event off the PMU.
20 */
21
22static int setup_cpu_event(struct event *event, int cpu)
23{
24 event_init_named(event, 0x400FA, "PM_RUN_INST_CMPL");
25
26 event->attr.exclude_kernel = 1;
27 event->attr.exclude_hv = 1;
28 event->attr.exclude_idle = 1;
29
30 SKIP_IF(require_paranoia_below(1));
31 FAIL_IF(event_open_with_cpu(event, cpu));
32 FAIL_IF(event_enable(event));
33
34 return 0;
35}
36
37int cpu_event_vs_ebb(void)
38{
39 union pipe read_pipe, write_pipe;
40 struct event event;
41 int cpu, rc;
42 pid_t pid;
43
44 cpu = pick_online_cpu();
45 FAIL_IF(cpu < 0);
46 FAIL_IF(bind_to_cpu(cpu));
47
48 FAIL_IF(pipe(read_pipe.fds) == -1);
49 FAIL_IF(pipe(write_pipe.fds) == -1);
50
51 pid = fork();
52 if (pid == 0) {
53 /* NB order of pipes looks reversed */
54 exit(ebb_child(write_pipe, read_pipe));
55 }
56
57 /* We setup the cpu event first */
58 rc = setup_cpu_event(&event, cpu);
59 if (rc) {
60 kill_child_and_wait(pid);
61 return rc;
62 }
63
64 /* Signal the child to install its EBB event and wait */
65 if (sync_with_child(read_pipe, write_pipe))
66 /* If it fails, wait for it to exit */
67 goto wait;
68
69 /* Signal the child to run */
70 FAIL_IF(sync_with_child(read_pipe, write_pipe));
71
72wait:
73 /* We expect the child to succeed */
74 FAIL_IF(wait_for_child(pid));
75
76 FAIL_IF(event_disable(&event));
77 FAIL_IF(event_read(&event));
78
79 event_report(&event);
80
81 /* The cpu event may have run */
82
83 return 0;
84}
85
86int main(void)
87{
88 return test_harness(cpu_event_vs_ebb, "cpu_event_vs_ebb");
89}
diff --git a/tools/testing/selftests/powerpc/pmu/ebb/cycles_test.c b/tools/testing/selftests/powerpc/pmu/ebb/cycles_test.c
new file mode 100644
index 000000000000..8590fc1bfc0d
--- /dev/null
+++ b/tools/testing/selftests/powerpc/pmu/ebb/cycles_test.c
@@ -0,0 +1,58 @@
1/*
2 * Copyright 2014, Michael Ellerman, IBM Corp.
3 * Licensed under GPLv2.
4 */
5
6#include <stdio.h>
7#include <stdlib.h>
8
9#include "ebb.h"
10
11
12/*
13 * Basic test that counts user cycles and takes EBBs.
14 */
15int cycles(void)
16{
17 struct event event;
18
19 event_init_named(&event, 0x1001e, "cycles");
20 event_leader_ebb_init(&event);
21
22 event.attr.exclude_kernel = 1;
23 event.attr.exclude_hv = 1;
24 event.attr.exclude_idle = 1;
25
26 FAIL_IF(event_open(&event));
27
28 ebb_enable_pmc_counting(1);
29 setup_ebb_handler(standard_ebb_callee);
30 ebb_global_enable();
31 FAIL_IF(ebb_event_enable(&event));
32
33 mtspr(SPRN_PMC1, pmc_sample_period(sample_period));
34
35 while (ebb_state.stats.ebb_count < 10) {
36 FAIL_IF(core_busy_loop());
37 FAIL_IF(ebb_check_mmcr0());
38 }
39
40 ebb_global_disable();
41 ebb_freeze_pmcs();
42
43 count_pmc(1, sample_period);
44
45 dump_ebb_state();
46
47 event_close(&event);
48
49 FAIL_IF(ebb_state.stats.ebb_count == 0);
50 FAIL_IF(!ebb_check_count(1, sample_period, 100));
51
52 return 0;
53}
54
55int main(void)
56{
57 return test_harness(cycles, "cycles");
58}
diff --git a/tools/testing/selftests/powerpc/pmu/ebb/cycles_with_freeze_test.c b/tools/testing/selftests/powerpc/pmu/ebb/cycles_with_freeze_test.c
new file mode 100644
index 000000000000..754b3f2008d3
--- /dev/null
+++ b/tools/testing/selftests/powerpc/pmu/ebb/cycles_with_freeze_test.c
@@ -0,0 +1,117 @@
1/*
2 * Copyright 2014, Michael Ellerman, IBM Corp.
3 * Licensed under GPLv2.
4 */
5
6#include <stdio.h>
7#include <stdlib.h>
8#include <stdbool.h>
9
10#include "ebb.h"
11
12
13/*
14 * Test of counting cycles while using MMCR0_FC (freeze counters) to only count
15 * parts of the code. This is complicated by the fact that FC is set by the
16 * hardware when the event overflows. We may take the EBB after we have set FC,
17 * so we have to be careful about whether we clear FC at the end of the EBB
18 * handler or not.
19 */
20
21static bool counters_frozen = false;
22static int ebbs_while_frozen = 0;
23
24static void ebb_callee(void)
25{
26 uint64_t mask, val;
27
28 mask = MMCR0_PMAO | MMCR0_FC;
29
30 val = mfspr(SPRN_BESCR);
31 if (!(val & BESCR_PMEO)) {
32 ebb_state.stats.spurious++;
33 goto out;
34 }
35
36 ebb_state.stats.ebb_count++;
37 trace_log_counter(ebb_state.trace, ebb_state.stats.ebb_count);
38
39 val = mfspr(SPRN_MMCR0);
40 trace_log_reg(ebb_state.trace, SPRN_MMCR0, val);
41
42 if (counters_frozen) {
43 trace_log_string(ebb_state.trace, "frozen");
44 ebbs_while_frozen++;
45 mask &= ~MMCR0_FC;
46 }
47
48 count_pmc(1, sample_period);
49out:
50 reset_ebb_with_clear_mask(mask);
51}
52
53int cycles_with_freeze(void)
54{
55 struct event event;
56 uint64_t val;
57 bool fc_cleared;
58
59 event_init_named(&event, 0x1001e, "cycles");
60 event_leader_ebb_init(&event);
61
62 event.attr.exclude_kernel = 1;
63 event.attr.exclude_hv = 1;
64 event.attr.exclude_idle = 1;
65
66 FAIL_IF(event_open(&event));
67
68 setup_ebb_handler(ebb_callee);
69 ebb_global_enable();
70 FAIL_IF(ebb_event_enable(&event));
71
72 mtspr(SPRN_PMC1, pmc_sample_period(sample_period));
73
74 fc_cleared = false;
75
76 /* Make sure we loop until we take at least one EBB */
77 while ((ebb_state.stats.ebb_count < 20 && !fc_cleared) ||
78 ebb_state.stats.ebb_count < 1)
79 {
80 counters_frozen = false;
81 mb();
82 mtspr(SPRN_MMCR0, mfspr(SPRN_MMCR0) & ~MMCR0_FC);
83
84 FAIL_IF(core_busy_loop());
85
86 counters_frozen = true;
87 mb();
88 mtspr(SPRN_MMCR0, mfspr(SPRN_MMCR0) | MMCR0_FC);
89
90 val = mfspr(SPRN_MMCR0);
91 if (! (val & MMCR0_FC)) {
92 printf("Outside of loop, FC NOT set MMCR0 0x%lx\n", val);
93 fc_cleared = true;
94 }
95 }
96
97 ebb_global_disable();
98 ebb_freeze_pmcs();
99
100 count_pmc(1, sample_period);
101
102 dump_ebb_state();
103
104 printf("EBBs while frozen %d\n", ebbs_while_frozen);
105
106 event_close(&event);
107
108 FAIL_IF(ebb_state.stats.ebb_count == 0);
109 FAIL_IF(fc_cleared);
110
111 return 0;
112}
113
114int main(void)
115{
116 return test_harness(cycles_with_freeze, "cycles_with_freeze");
117}
diff --git a/tools/testing/selftests/powerpc/pmu/ebb/ebb.c b/tools/testing/selftests/powerpc/pmu/ebb/ebb.c
new file mode 100644
index 000000000000..1b46be94b64c
--- /dev/null
+++ b/tools/testing/selftests/powerpc/pmu/ebb/ebb.c
@@ -0,0 +1,727 @@
1/*
2 * Copyright 2014, Michael Ellerman, IBM Corp.
3 * Licensed under GPLv2.
4 */
5
6#define _GNU_SOURCE /* For CPU_ZERO etc. */
7
8#include <sched.h>
9#include <sys/wait.h>
10#include <setjmp.h>
11#include <signal.h>
12#include <stdio.h>
13#include <stdlib.h>
14#include <string.h>
15#include <sys/ioctl.h>
16
17#include "trace.h"
18#include "reg.h"
19#include "ebb.h"
20
21
22void (*ebb_user_func)(void);
23
24void ebb_hook(void)
25{
26 if (ebb_user_func)
27 ebb_user_func();
28}
29
30struct ebb_state ebb_state;
31
32u64 sample_period = 0x40000000ull;
33
34void reset_ebb_with_clear_mask(unsigned long mmcr0_clear_mask)
35{
36 u64 val;
37
38 /* 2) clear MMCR0[PMAO] - docs say BESCR[PMEO] should do this */
39 /* 3) set MMCR0[PMAE] - docs say BESCR[PME] should do this */
40 val = mfspr(SPRN_MMCR0);
41 mtspr(SPRN_MMCR0, (val & ~mmcr0_clear_mask) | MMCR0_PMAE);
42
43 /* 4) clear BESCR[PMEO] */
44 mtspr(SPRN_BESCRR, BESCR_PMEO);
45
46 /* 5) set BESCR[PME] */
47 mtspr(SPRN_BESCRS, BESCR_PME);
48
49 /* 6) rfebb 1 - done in our caller */
50}
51
52void reset_ebb(void)
53{
54 reset_ebb_with_clear_mask(MMCR0_PMAO | MMCR0_FC);
55}
56
57/* Called outside of the EBB handler to check MMCR0 is sane */
58int ebb_check_mmcr0(void)
59{
60 u64 val;
61
62 val = mfspr(SPRN_MMCR0);
63 if ((val & (MMCR0_FC | MMCR0_PMAO)) == MMCR0_FC) {
64 /* It's OK if we see FC & PMAO, but not FC by itself */
65 printf("Outside of loop, only FC set 0x%llx\n", val);
66 return 1;
67 }
68
69 return 0;
70}
71
72bool ebb_check_count(int pmc, u64 sample_period, int fudge)
73{
74 u64 count, upper, lower;
75
76 count = ebb_state.stats.pmc_count[PMC_INDEX(pmc)];
77
78 lower = ebb_state.stats.ebb_count * (sample_period - fudge);
79
80 if (count < lower) {
81 printf("PMC%d count (0x%llx) below lower limit 0x%llx (-0x%llx)\n",
82 pmc, count, lower, lower - count);
83 return false;
84 }
85
86 upper = ebb_state.stats.ebb_count * (sample_period + fudge);
87
88 if (count > upper) {
89 printf("PMC%d count (0x%llx) above upper limit 0x%llx (+0x%llx)\n",
90 pmc, count, upper, count - upper);
91 return false;
92 }
93
94 printf("PMC%d count (0x%llx) is between 0x%llx and 0x%llx delta +0x%llx/-0x%llx\n",
95 pmc, count, lower, upper, count - lower, upper - count);
96
97 return true;
98}
99
100void standard_ebb_callee(void)
101{
102 int found, i;
103 u64 val;
104
105 val = mfspr(SPRN_BESCR);
106 if (!(val & BESCR_PMEO)) {
107 ebb_state.stats.spurious++;
108 goto out;
109 }
110
111 ebb_state.stats.ebb_count++;
112 trace_log_counter(ebb_state.trace, ebb_state.stats.ebb_count);
113
114 val = mfspr(SPRN_MMCR0);
115 trace_log_reg(ebb_state.trace, SPRN_MMCR0, val);
116
117 found = 0;
118 for (i = 1; i <= 6; i++) {
119 if (ebb_state.pmc_enable[PMC_INDEX(i)])
120 found += count_pmc(i, sample_period);
121 }
122
123 if (!found)
124 ebb_state.stats.no_overflow++;
125
126out:
127 reset_ebb();
128}
129
130extern void ebb_handler(void);
131
132void setup_ebb_handler(void (*callee)(void))
133{
134 u64 entry;
135
136#if defined(_CALL_ELF) && _CALL_ELF == 2
137 entry = (u64)ebb_handler;
138#else
139 struct opd
140 {
141 u64 entry;
142 u64 toc;
143 } *opd;
144
145 opd = (struct opd *)ebb_handler;
146 entry = opd->entry;
147#endif
148 printf("EBB Handler is at %#llx\n", entry);
149
150 ebb_user_func = callee;
151
152 /* Ensure ebb_user_func is set before we set the handler */
153 mb();
154 mtspr(SPRN_EBBHR, entry);
155
156 /* Make sure the handler is set before we return */
157 mb();
158}
159
160void clear_ebb_stats(void)
161{
162 memset(&ebb_state.stats, 0, sizeof(ebb_state.stats));
163}
164
165void dump_summary_ebb_state(void)
166{
167 printf("ebb_state:\n" \
168 " ebb_count = %d\n" \
169 " spurious = %d\n" \
170 " negative = %d\n" \
171 " no_overflow = %d\n" \
172 " pmc[1] count = 0x%llx\n" \
173 " pmc[2] count = 0x%llx\n" \
174 " pmc[3] count = 0x%llx\n" \
175 " pmc[4] count = 0x%llx\n" \
176 " pmc[5] count = 0x%llx\n" \
177 " pmc[6] count = 0x%llx\n",
178 ebb_state.stats.ebb_count, ebb_state.stats.spurious,
179 ebb_state.stats.negative, ebb_state.stats.no_overflow,
180 ebb_state.stats.pmc_count[0], ebb_state.stats.pmc_count[1],
181 ebb_state.stats.pmc_count[2], ebb_state.stats.pmc_count[3],
182 ebb_state.stats.pmc_count[4], ebb_state.stats.pmc_count[5]);
183}
184
185static char *decode_mmcr0(u32 value)
186{
187 static char buf[16];
188
189 buf[0] = '\0';
190
191 if (value & (1 << 31))
192 strcat(buf, "FC ");
193 if (value & (1 << 26))
194 strcat(buf, "PMAE ");
195 if (value & (1 << 7))
196 strcat(buf, "PMAO ");
197
198 return buf;
199}
200
201static char *decode_bescr(u64 value)
202{
203 static char buf[16];
204
205 buf[0] = '\0';
206
207 if (value & (1ull << 63))
208 strcat(buf, "GE ");
209 if (value & (1ull << 32))
210 strcat(buf, "PMAE ");
211 if (value & 1)
212 strcat(buf, "PMAO ");
213
214 return buf;
215}
216
217void dump_ebb_hw_state(void)
218{
219 u64 bescr;
220 u32 mmcr0;
221
222 mmcr0 = mfspr(SPRN_MMCR0);
223 bescr = mfspr(SPRN_BESCR);
224
225 printf("HW state:\n" \
226 "MMCR0 0x%016x %s\n" \
227 "EBBHR 0x%016lx\n" \
228 "BESCR 0x%016llx %s\n" \
229 "PMC1 0x%016lx\n" \
230 "PMC2 0x%016lx\n" \
231 "PMC3 0x%016lx\n" \
232 "PMC4 0x%016lx\n" \
233 "PMC5 0x%016lx\n" \
234 "PMC6 0x%016lx\n" \
235 "SIAR 0x%016lx\n",
236 mmcr0, decode_mmcr0(mmcr0), mfspr(SPRN_EBBHR), bescr,
237 decode_bescr(bescr), mfspr(SPRN_PMC1), mfspr(SPRN_PMC2),
238 mfspr(SPRN_PMC3), mfspr(SPRN_PMC4), mfspr(SPRN_PMC5),
239 mfspr(SPRN_PMC6), mfspr(SPRN_SIAR));
240}
241
242void dump_ebb_state(void)
243{
244 dump_summary_ebb_state();
245
246 dump_ebb_hw_state();
247
248 trace_buffer_print(ebb_state.trace);
249}
250
251int count_pmc(int pmc, uint32_t sample_period)
252{
253 uint32_t start_value;
254 u64 val;
255
256 /* 0) Read PMC */
257 start_value = pmc_sample_period(sample_period);
258
259 val = read_pmc(pmc);
260 if (val < start_value)
261 ebb_state.stats.negative++;
262 else
263 ebb_state.stats.pmc_count[PMC_INDEX(pmc)] += val - start_value;
264
265 trace_log_reg(ebb_state.trace, SPRN_PMC1 + pmc - 1, val);
266
267 /* 1) Reset PMC */
268 write_pmc(pmc, start_value);
269
270 /* Report if we overflowed */
271 return val >= COUNTER_OVERFLOW;
272}
273
274int ebb_event_enable(struct event *e)
275{
276 int rc;
277
278 /* Ensure any SPR writes are ordered vs us */
279 mb();
280
281 rc = ioctl(e->fd, PERF_EVENT_IOC_ENABLE);
282 if (rc)
283 return rc;
284
285 rc = event_read(e);
286
287 /* Ditto */
288 mb();
289
290 return rc;
291}
292
293void ebb_freeze_pmcs(void)
294{
295 mtspr(SPRN_MMCR0, mfspr(SPRN_MMCR0) | MMCR0_FC);
296 mb();
297}
298
299void ebb_unfreeze_pmcs(void)
300{
301 /* Unfreeze counters */
302 mtspr(SPRN_MMCR0, mfspr(SPRN_MMCR0) & ~MMCR0_FC);
303 mb();
304}
305
306void ebb_global_enable(void)
307{
308 /* Enable EBBs globally and PMU EBBs */
309 mtspr(SPRN_BESCR, 0x8000000100000000ull);
310 mb();
311}
312
313void ebb_global_disable(void)
314{
315 /* Disable EBBs & freeze counters, events are still scheduled */
316 mtspr(SPRN_BESCRR, BESCR_PME);
317 mb();
318}
319
320void event_ebb_init(struct event *e)
321{
322 e->attr.config |= (1ull << 63);
323}
324
325void event_bhrb_init(struct event *e, unsigned ifm)
326{
327 e->attr.config |= (1ull << 62) | ((u64)ifm << 60);
328}
329
330void event_leader_ebb_init(struct event *e)
331{
332 event_ebb_init(e);
333
334 e->attr.exclusive = 1;
335 e->attr.pinned = 1;
336}
337
338int core_busy_loop(void)
339{
340 int rc;
341
342 asm volatile (
343 "li 3, 0x3030\n"
344 "std 3, -96(1)\n"
345 "li 4, 0x4040\n"
346 "std 4, -104(1)\n"
347 "li 5, 0x5050\n"
348 "std 5, -112(1)\n"
349 "li 6, 0x6060\n"
350 "std 6, -120(1)\n"
351 "li 7, 0x7070\n"
352 "std 7, -128(1)\n"
353 "li 8, 0x0808\n"
354 "std 8, -136(1)\n"
355 "li 9, 0x0909\n"
356 "std 9, -144(1)\n"
357 "li 10, 0x1010\n"
358 "std 10, -152(1)\n"
359 "li 11, 0x1111\n"
360 "std 11, -160(1)\n"
361 "li 14, 0x1414\n"
362 "std 14, -168(1)\n"
363 "li 15, 0x1515\n"
364 "std 15, -176(1)\n"
365 "li 16, 0x1616\n"
366 "std 16, -184(1)\n"
367 "li 17, 0x1717\n"
368 "std 17, -192(1)\n"
369 "li 18, 0x1818\n"
370 "std 18, -200(1)\n"
371 "li 19, 0x1919\n"
372 "std 19, -208(1)\n"
373 "li 20, 0x2020\n"
374 "std 20, -216(1)\n"
375 "li 21, 0x2121\n"
376 "std 21, -224(1)\n"
377 "li 22, 0x2222\n"
378 "std 22, -232(1)\n"
379 "li 23, 0x2323\n"
380 "std 23, -240(1)\n"
381 "li 24, 0x2424\n"
382 "std 24, -248(1)\n"
383 "li 25, 0x2525\n"
384 "std 25, -256(1)\n"
385 "li 26, 0x2626\n"
386 "std 26, -264(1)\n"
387 "li 27, 0x2727\n"
388 "std 27, -272(1)\n"
389 "li 28, 0x2828\n"
390 "std 28, -280(1)\n"
391 "li 29, 0x2929\n"
392 "std 29, -288(1)\n"
393 "li 30, 0x3030\n"
394 "li 31, 0x3131\n"
395
396 "li 3, 0\n"
397 "0: "
398 "addi 3, 3, 1\n"
399 "cmpwi 3, 100\n"
400 "blt 0b\n"
401
402 /* Return 1 (fail) unless we get through all the checks */
403 "li 0, 1\n"
404
405 /* Check none of our registers have been corrupted */
406 "cmpwi 4, 0x4040\n"
407 "bne 1f\n"
408 "cmpwi 5, 0x5050\n"
409 "bne 1f\n"
410 "cmpwi 6, 0x6060\n"
411 "bne 1f\n"
412 "cmpwi 7, 0x7070\n"
413 "bne 1f\n"
414 "cmpwi 8, 0x0808\n"
415 "bne 1f\n"
416 "cmpwi 9, 0x0909\n"
417 "bne 1f\n"
418 "cmpwi 10, 0x1010\n"
419 "bne 1f\n"
420 "cmpwi 11, 0x1111\n"
421 "bne 1f\n"
422 "cmpwi 14, 0x1414\n"
423 "bne 1f\n"
424 "cmpwi 15, 0x1515\n"
425 "bne 1f\n"
426 "cmpwi 16, 0x1616\n"
427 "bne 1f\n"
428 "cmpwi 17, 0x1717\n"
429 "bne 1f\n"
430 "cmpwi 18, 0x1818\n"
431 "bne 1f\n"
432 "cmpwi 19, 0x1919\n"
433 "bne 1f\n"
434 "cmpwi 20, 0x2020\n"
435 "bne 1f\n"
436 "cmpwi 21, 0x2121\n"
437 "bne 1f\n"
438 "cmpwi 22, 0x2222\n"
439 "bne 1f\n"
440 "cmpwi 23, 0x2323\n"
441 "bne 1f\n"
442 "cmpwi 24, 0x2424\n"
443 "bne 1f\n"
444 "cmpwi 25, 0x2525\n"
445 "bne 1f\n"
446 "cmpwi 26, 0x2626\n"
447 "bne 1f\n"
448 "cmpwi 27, 0x2727\n"
449 "bne 1f\n"
450 "cmpwi 28, 0x2828\n"
451 "bne 1f\n"
452 "cmpwi 29, 0x2929\n"
453 "bne 1f\n"
454 "cmpwi 30, 0x3030\n"
455 "bne 1f\n"
456 "cmpwi 31, 0x3131\n"
457 "bne 1f\n"
458
459 /* Load junk into all our registers before we reload them from the stack. */
460 "li 3, 0xde\n"
461 "li 4, 0xad\n"
462 "li 5, 0xbe\n"
463 "li 6, 0xef\n"
464 "li 7, 0xde\n"
465 "li 8, 0xad\n"
466 "li 9, 0xbe\n"
467 "li 10, 0xef\n"
468 "li 11, 0xde\n"
469 "li 14, 0xad\n"
470 "li 15, 0xbe\n"
471 "li 16, 0xef\n"
472 "li 17, 0xde\n"
473 "li 18, 0xad\n"
474 "li 19, 0xbe\n"
475 "li 20, 0xef\n"
476 "li 21, 0xde\n"
477 "li 22, 0xad\n"
478 "li 23, 0xbe\n"
479 "li 24, 0xef\n"
480 "li 25, 0xde\n"
481 "li 26, 0xad\n"
482 "li 27, 0xbe\n"
483 "li 28, 0xef\n"
484 "li 29, 0xdd\n"
485
486 "ld 3, -96(1)\n"
487 "cmpwi 3, 0x3030\n"
488 "bne 1f\n"
489 "ld 4, -104(1)\n"
490 "cmpwi 4, 0x4040\n"
491 "bne 1f\n"
492 "ld 5, -112(1)\n"
493 "cmpwi 5, 0x5050\n"
494 "bne 1f\n"
495 "ld 6, -120(1)\n"
496 "cmpwi 6, 0x6060\n"
497 "bne 1f\n"
498 "ld 7, -128(1)\n"
499 "cmpwi 7, 0x7070\n"
500 "bne 1f\n"
501 "ld 8, -136(1)\n"
502 "cmpwi 8, 0x0808\n"
503 "bne 1f\n"
504 "ld 9, -144(1)\n"
505 "cmpwi 9, 0x0909\n"
506 "bne 1f\n"
507 "ld 10, -152(1)\n"
508 "cmpwi 10, 0x1010\n"
509 "bne 1f\n"
510 "ld 11, -160(1)\n"
511 "cmpwi 11, 0x1111\n"
512 "bne 1f\n"
513 "ld 14, -168(1)\n"
514 "cmpwi 14, 0x1414\n"
515 "bne 1f\n"
516 "ld 15, -176(1)\n"
517 "cmpwi 15, 0x1515\n"
518 "bne 1f\n"
519 "ld 16, -184(1)\n"
520 "cmpwi 16, 0x1616\n"
521 "bne 1f\n"
522 "ld 17, -192(1)\n"
523 "cmpwi 17, 0x1717\n"
524 "bne 1f\n"
525 "ld 18, -200(1)\n"
526 "cmpwi 18, 0x1818\n"
527 "bne 1f\n"
528 "ld 19, -208(1)\n"
529 "cmpwi 19, 0x1919\n"
530 "bne 1f\n"
531 "ld 20, -216(1)\n"
532 "cmpwi 20, 0x2020\n"
533 "bne 1f\n"
534 "ld 21, -224(1)\n"
535 "cmpwi 21, 0x2121\n"
536 "bne 1f\n"
537 "ld 22, -232(1)\n"
538 "cmpwi 22, 0x2222\n"
539 "bne 1f\n"
540 "ld 23, -240(1)\n"
541 "cmpwi 23, 0x2323\n"
542 "bne 1f\n"
543 "ld 24, -248(1)\n"
544 "cmpwi 24, 0x2424\n"
545 "bne 1f\n"
546 "ld 25, -256(1)\n"
547 "cmpwi 25, 0x2525\n"
548 "bne 1f\n"
549 "ld 26, -264(1)\n"
550 "cmpwi 26, 0x2626\n"
551 "bne 1f\n"
552 "ld 27, -272(1)\n"
553 "cmpwi 27, 0x2727\n"
554 "bne 1f\n"
555 "ld 28, -280(1)\n"
556 "cmpwi 28, 0x2828\n"
557 "bne 1f\n"
558 "ld 29, -288(1)\n"
559 "cmpwi 29, 0x2929\n"
560 "bne 1f\n"
561
562 /* Load 0 (success) to return */
563 "li 0, 0\n"
564
565 "1: mr %0, 0\n"
566
567 : "=r" (rc)
568 : /* no inputs */
569 : "3", "4", "5", "6", "7", "8", "9", "10", "11", "14",
570 "15", "16", "17", "18", "19", "20", "21", "22", "23",
571 "24", "25", "26", "27", "28", "29", "30", "31",
572 "memory"
573 );
574
575 return rc;
576}
577
578int core_busy_loop_with_freeze(void)
579{
580 int rc;
581
582 mtspr(SPRN_MMCR0, mfspr(SPRN_MMCR0) & ~MMCR0_FC);
583 rc = core_busy_loop();
584 mtspr(SPRN_MMCR0, mfspr(SPRN_MMCR0) | MMCR0_FC);
585
586 return rc;
587}
588
589int ebb_child(union pipe read_pipe, union pipe write_pipe)
590{
591 struct event event;
592 uint64_t val;
593
594 FAIL_IF(wait_for_parent(read_pipe));
595
596 event_init_named(&event, 0x1001e, "cycles");
597 event_leader_ebb_init(&event);
598
599 event.attr.exclude_kernel = 1;
600 event.attr.exclude_hv = 1;
601 event.attr.exclude_idle = 1;
602
603 FAIL_IF(event_open(&event));
604
605 ebb_enable_pmc_counting(1);
606 setup_ebb_handler(standard_ebb_callee);
607 ebb_global_enable();
608
609 FAIL_IF(event_enable(&event));
610
611 if (event_read(&event)) {
612 /*
613 * Some tests expect to fail here, so don't report an error on
614 * this line, and return a distinguisable error code. Tell the
615 * parent an error happened.
616 */
617 notify_parent_of_error(write_pipe);
618 return 2;
619 }
620
621 mtspr(SPRN_PMC1, pmc_sample_period(sample_period));
622
623 FAIL_IF(notify_parent(write_pipe));
624 FAIL_IF(wait_for_parent(read_pipe));
625 FAIL_IF(notify_parent(write_pipe));
626
627 while (ebb_state.stats.ebb_count < 20) {
628 FAIL_IF(core_busy_loop());
629
630 /* To try and hit SIGILL case */
631 val = mfspr(SPRN_MMCRA);
632 val |= mfspr(SPRN_MMCR2);
633 val |= mfspr(SPRN_MMCR0);
634 }
635
636 ebb_global_disable();
637 ebb_freeze_pmcs();
638
639 count_pmc(1, sample_period);
640
641 dump_ebb_state();
642
643 event_close(&event);
644
645 FAIL_IF(ebb_state.stats.ebb_count == 0);
646
647 return 0;
648}
649
650static jmp_buf setjmp_env;
651
652static void sigill_handler(int signal)
653{
654 printf("Took sigill\n");
655 longjmp(setjmp_env, 1);
656}
657
658static struct sigaction sigill_action = {
659 .sa_handler = sigill_handler,
660};
661
662int catch_sigill(void (*func)(void))
663{
664 if (sigaction(SIGILL, &sigill_action, NULL)) {
665 perror("sigaction");
666 return 1;
667 }
668
669 if (setjmp(setjmp_env) == 0) {
670 func();
671 return 1;
672 }
673
674 return 0;
675}
676
677void write_pmc1(void)
678{
679 mtspr(SPRN_PMC1, 0);
680}
681
682void write_pmc(int pmc, u64 value)
683{
684 switch (pmc) {
685 case 1: mtspr(SPRN_PMC1, value); break;
686 case 2: mtspr(SPRN_PMC2, value); break;
687 case 3: mtspr(SPRN_PMC3, value); break;
688 case 4: mtspr(SPRN_PMC4, value); break;
689 case 5: mtspr(SPRN_PMC5, value); break;
690 case 6: mtspr(SPRN_PMC6, value); break;
691 }
692}
693
694u64 read_pmc(int pmc)
695{
696 switch (pmc) {
697 case 1: return mfspr(SPRN_PMC1);
698 case 2: return mfspr(SPRN_PMC2);
699 case 3: return mfspr(SPRN_PMC3);
700 case 4: return mfspr(SPRN_PMC4);
701 case 5: return mfspr(SPRN_PMC5);
702 case 6: return mfspr(SPRN_PMC6);
703 }
704
705 return 0;
706}
707
708static void term_handler(int signal)
709{
710 dump_summary_ebb_state();
711 dump_ebb_hw_state();
712 abort();
713}
714
715struct sigaction term_action = {
716 .sa_handler = term_handler,
717};
718
719static void __attribute__((constructor)) ebb_init(void)
720{
721 clear_ebb_stats();
722
723 if (sigaction(SIGTERM, &term_action, NULL))
724 perror("sigaction");
725
726 ebb_state.trace = trace_buffer_allocate(1 * 1024 * 1024);
727}
diff --git a/tools/testing/selftests/powerpc/pmu/ebb/ebb.h b/tools/testing/selftests/powerpc/pmu/ebb/ebb.h
new file mode 100644
index 000000000000..e62bde05bf78
--- /dev/null
+++ b/tools/testing/selftests/powerpc/pmu/ebb/ebb.h
@@ -0,0 +1,78 @@
1/*
2 * Copyright 2014, Michael Ellerman, IBM Corp.
3 * Licensed under GPLv2.
4 */
5
6#ifndef _SELFTESTS_POWERPC_PMU_EBB_EBB_H
7#define _SELFTESTS_POWERPC_PMU_EBB_EBB_H
8
9#include "../event.h"
10#include "../lib.h"
11#include "trace.h"
12#include "reg.h"
13
14#define PMC_INDEX(pmc) ((pmc)-1)
15
16#define NUM_PMC_VALUES 128
17
18struct ebb_state
19{
20 struct {
21 u64 pmc_count[6];
22 volatile int ebb_count;
23 int spurious;
24 int negative;
25 int no_overflow;
26 } stats;
27
28 bool pmc_enable[6];
29 struct trace_buffer *trace;
30};
31
32extern struct ebb_state ebb_state;
33
34#define COUNTER_OVERFLOW 0x80000000ull
35
36static inline uint32_t pmc_sample_period(uint32_t value)
37{
38 return COUNTER_OVERFLOW - value;
39}
40
41static inline void ebb_enable_pmc_counting(int pmc)
42{
43 ebb_state.pmc_enable[PMC_INDEX(pmc)] = true;
44}
45
46bool ebb_check_count(int pmc, u64 sample_period, int fudge);
47void event_leader_ebb_init(struct event *e);
48void event_ebb_init(struct event *e);
49void event_bhrb_init(struct event *e, unsigned ifm);
50void setup_ebb_handler(void (*callee)(void));
51void standard_ebb_callee(void);
52int ebb_event_enable(struct event *e);
53void ebb_global_enable(void);
54void ebb_global_disable(void);
55void ebb_freeze_pmcs(void);
56void ebb_unfreeze_pmcs(void);
57void event_ebb_init(struct event *e);
58void event_leader_ebb_init(struct event *e);
59int count_pmc(int pmc, uint32_t sample_period);
60void dump_ebb_state(void);
61void dump_summary_ebb_state(void);
62void dump_ebb_hw_state(void);
63void clear_ebb_stats(void);
64void write_pmc(int pmc, u64 value);
65u64 read_pmc(int pmc);
66void reset_ebb_with_clear_mask(unsigned long mmcr0_clear_mask);
67void reset_ebb(void);
68int ebb_check_mmcr0(void);
69
70extern u64 sample_period;
71
72int core_busy_loop(void);
73int core_busy_loop_with_freeze(void);
74int ebb_child(union pipe read_pipe, union pipe write_pipe);
75int catch_sigill(void (*func)(void));
76void write_pmc1(void);
77
78#endif /* _SELFTESTS_POWERPC_PMU_EBB_EBB_H */
diff --git a/tools/testing/selftests/powerpc/pmu/ebb/ebb_handler.S b/tools/testing/selftests/powerpc/pmu/ebb/ebb_handler.S
new file mode 100644
index 000000000000..14274ea206e5
--- /dev/null
+++ b/tools/testing/selftests/powerpc/pmu/ebb/ebb_handler.S
@@ -0,0 +1,365 @@
1/*
2 * Copyright 2014, Michael Ellerman, IBM Corp.
3 * Licensed under GPLv2.
4 */
5
6#include <ppc-asm.h>
7#include "reg.h"
8
9
10/* ppc-asm.h defines most of the reg aliases, but not r1/r2. */
11#define r1 1
12#define r2 2
13
14#define RFEBB .long 0x4c000924
15
16/* Stack layout:
17 *
18 * ^
19 * User stack |
20 * Back chain ------+ <- r1 <-------+
21 * ... |
22 * Red zone / ABI Gap |
23 * ... |
24 * vr63 <+ |
25 * vr0 | |
26 * VSCR | |
27 * FSCR | |
28 * r31 | Save area |
29 * r0 | |
30 * XER | |
31 * CTR | |
32 * LR | |
33 * CCR <+ |
34 * ... <+ |
35 * LR | Caller frame |
36 * CCR | |
37 * Back chain <+ <- updated r1 --------+
38 *
39 */
40
41#if defined(_CALL_ELF) && _CALL_ELF == 2
42#define ABIGAP 512
43#else
44#define ABIGAP 288
45#endif
46
47#define NR_GPR 32
48#define NR_SPR 6
49#define NR_VSR 64
50
51#define SAVE_AREA ((NR_GPR + NR_SPR) * 8 + (NR_VSR * 16))
52#define CALLER_FRAME 112
53
54#define STACK_FRAME (ABIGAP + SAVE_AREA + CALLER_FRAME)
55
56#define CCR_SAVE (CALLER_FRAME)
57#define LR_SAVE (CCR_SAVE + 8)
58#define CTR_SAVE (LR_SAVE + 8)
59#define XER_SAVE (CTR_SAVE + 8)
60#define GPR_SAVE(n) (XER_SAVE + 8 + (8 * n))
61#define FSCR_SAVE (GPR_SAVE(31) + 8)
62#define VSCR_SAVE (FSCR_SAVE + 8)
63#define VSR_SAVE(n) (VSCR_SAVE + 8 + (16 * n))
64
65#define SAVE_GPR(n) std n,GPR_SAVE(n)(r1)
66#define REST_GPR(n) ld n,GPR_SAVE(n)(r1)
67#define TRASH_GPR(n) lis n,0xaaaa
68
69#define SAVE_VSR(n, b) li b, VSR_SAVE(n); stxvd2x n,b,r1
70#define LOAD_VSR(n, b) li b, VSR_SAVE(n); lxvd2x n,b,r1
71
72#define LOAD_REG_IMMEDIATE(reg,expr) \
73 lis reg,(expr)@highest; \
74 ori reg,reg,(expr)@higher; \
75 rldicr reg,reg,32,31; \
76 oris reg,reg,(expr)@h; \
77 ori reg,reg,(expr)@l;
78
79
80#if defined(_CALL_ELF) && _CALL_ELF == 2
81#define ENTRY_POINT(name) \
82 .type FUNC_NAME(name),@function; \
83 .globl FUNC_NAME(name); \
84 FUNC_NAME(name):
85
86#define RESTORE_TOC(name) \
87 /* Restore our TOC pointer using our entry point */ \
88 LOAD_REG_IMMEDIATE(r12, name) \
890: addis r2,r12,(.TOC.-0b)@ha; \
90 addi r2,r2,(.TOC.-0b)@l;
91
92#else
93#define ENTRY_POINT(name) FUNC_START(name)
94#define RESTORE_TOC(name) \
95 /* Restore our TOC pointer via our opd entry */ \
96 LOAD_REG_IMMEDIATE(r2, name) \
97 ld r2,8(r2);
98#endif
99
100 .text
101
102ENTRY_POINT(ebb_handler)
103 stdu r1,-STACK_FRAME(r1)
104 SAVE_GPR(0)
105 mflr r0
106 std r0,LR_SAVE(r1)
107 mfcr r0
108 std r0,CCR_SAVE(r1)
109 mfctr r0
110 std r0,CTR_SAVE(r1)
111 mfxer r0
112 std r0,XER_SAVE(r1)
113 SAVE_GPR(2)
114 SAVE_GPR(3)
115 SAVE_GPR(4)
116 SAVE_GPR(5)
117 SAVE_GPR(6)
118 SAVE_GPR(7)
119 SAVE_GPR(8)
120 SAVE_GPR(9)
121 SAVE_GPR(10)
122 SAVE_GPR(11)
123 SAVE_GPR(12)
124 SAVE_GPR(13)
125 SAVE_GPR(14)
126 SAVE_GPR(15)
127 SAVE_GPR(16)
128 SAVE_GPR(17)
129 SAVE_GPR(18)
130 SAVE_GPR(19)
131 SAVE_GPR(20)
132 SAVE_GPR(21)
133 SAVE_GPR(22)
134 SAVE_GPR(23)
135 SAVE_GPR(24)
136 SAVE_GPR(25)
137 SAVE_GPR(26)
138 SAVE_GPR(27)
139 SAVE_GPR(28)
140 SAVE_GPR(29)
141 SAVE_GPR(30)
142 SAVE_GPR(31)
143 SAVE_VSR(0, r3)
144 mffs f0
145 stfd f0, FSCR_SAVE(r1)
146 mfvscr f0
147 stfd f0, VSCR_SAVE(r1)
148 SAVE_VSR(1, r3)
149 SAVE_VSR(2, r3)
150 SAVE_VSR(3, r3)
151 SAVE_VSR(4, r3)
152 SAVE_VSR(5, r3)
153 SAVE_VSR(6, r3)
154 SAVE_VSR(7, r3)
155 SAVE_VSR(8, r3)
156 SAVE_VSR(9, r3)
157 SAVE_VSR(10, r3)
158 SAVE_VSR(11, r3)
159 SAVE_VSR(12, r3)
160 SAVE_VSR(13, r3)
161 SAVE_VSR(14, r3)
162 SAVE_VSR(15, r3)
163 SAVE_VSR(16, r3)
164 SAVE_VSR(17, r3)
165 SAVE_VSR(18, r3)
166 SAVE_VSR(19, r3)
167 SAVE_VSR(20, r3)
168 SAVE_VSR(21, r3)
169 SAVE_VSR(22, r3)
170 SAVE_VSR(23, r3)
171 SAVE_VSR(24, r3)
172 SAVE_VSR(25, r3)
173 SAVE_VSR(26, r3)
174 SAVE_VSR(27, r3)
175 SAVE_VSR(28, r3)
176 SAVE_VSR(29, r3)
177 SAVE_VSR(30, r3)
178 SAVE_VSR(31, r3)
179 SAVE_VSR(32, r3)
180 SAVE_VSR(33, r3)
181 SAVE_VSR(34, r3)
182 SAVE_VSR(35, r3)
183 SAVE_VSR(36, r3)
184 SAVE_VSR(37, r3)
185 SAVE_VSR(38, r3)
186 SAVE_VSR(39, r3)
187 SAVE_VSR(40, r3)
188 SAVE_VSR(41, r3)
189 SAVE_VSR(42, r3)
190 SAVE_VSR(43, r3)
191 SAVE_VSR(44, r3)
192 SAVE_VSR(45, r3)
193 SAVE_VSR(46, r3)
194 SAVE_VSR(47, r3)
195 SAVE_VSR(48, r3)
196 SAVE_VSR(49, r3)
197 SAVE_VSR(50, r3)
198 SAVE_VSR(51, r3)
199 SAVE_VSR(52, r3)
200 SAVE_VSR(53, r3)
201 SAVE_VSR(54, r3)
202 SAVE_VSR(55, r3)
203 SAVE_VSR(56, r3)
204 SAVE_VSR(57, r3)
205 SAVE_VSR(58, r3)
206 SAVE_VSR(59, r3)
207 SAVE_VSR(60, r3)
208 SAVE_VSR(61, r3)
209 SAVE_VSR(62, r3)
210 SAVE_VSR(63, r3)
211
212 TRASH_GPR(2)
213 TRASH_GPR(3)
214 TRASH_GPR(4)
215 TRASH_GPR(5)
216 TRASH_GPR(6)
217 TRASH_GPR(7)
218 TRASH_GPR(8)
219 TRASH_GPR(9)
220 TRASH_GPR(10)
221 TRASH_GPR(11)
222 TRASH_GPR(12)
223 TRASH_GPR(14)
224 TRASH_GPR(15)
225 TRASH_GPR(16)
226 TRASH_GPR(17)
227 TRASH_GPR(18)
228 TRASH_GPR(19)
229 TRASH_GPR(20)
230 TRASH_GPR(21)
231 TRASH_GPR(22)
232 TRASH_GPR(23)
233 TRASH_GPR(24)
234 TRASH_GPR(25)
235 TRASH_GPR(26)
236 TRASH_GPR(27)
237 TRASH_GPR(28)
238 TRASH_GPR(29)
239 TRASH_GPR(30)
240 TRASH_GPR(31)
241
242 RESTORE_TOC(ebb_handler)
243
244 /*
245 * r13 is our TLS pointer. We leave whatever value was in there when the
246 * EBB fired. That seems to be OK because once set the TLS pointer is not
247 * changed - but presumably that could change in future.
248 */
249
250 bl ebb_hook
251 nop
252
253 /* r2 may be changed here but we don't care */
254
255 lfd f0, FSCR_SAVE(r1)
256 mtfsf 0xff,f0
257 lfd f0, VSCR_SAVE(r1)
258 mtvscr f0
259 LOAD_VSR(0, r3)
260 LOAD_VSR(1, r3)
261 LOAD_VSR(2, r3)
262 LOAD_VSR(3, r3)
263 LOAD_VSR(4, r3)
264 LOAD_VSR(5, r3)
265 LOAD_VSR(6, r3)
266 LOAD_VSR(7, r3)
267 LOAD_VSR(8, r3)
268 LOAD_VSR(9, r3)
269 LOAD_VSR(10, r3)
270 LOAD_VSR(11, r3)
271 LOAD_VSR(12, r3)
272 LOAD_VSR(13, r3)
273 LOAD_VSR(14, r3)
274 LOAD_VSR(15, r3)
275 LOAD_VSR(16, r3)
276 LOAD_VSR(17, r3)
277 LOAD_VSR(18, r3)
278 LOAD_VSR(19, r3)
279 LOAD_VSR(20, r3)
280 LOAD_VSR(21, r3)
281 LOAD_VSR(22, r3)
282 LOAD_VSR(23, r3)
283 LOAD_VSR(24, r3)
284 LOAD_VSR(25, r3)
285 LOAD_VSR(26, r3)
286 LOAD_VSR(27, r3)
287 LOAD_VSR(28, r3)
288 LOAD_VSR(29, r3)
289 LOAD_VSR(30, r3)
290 LOAD_VSR(31, r3)
291 LOAD_VSR(32, r3)
292 LOAD_VSR(33, r3)
293 LOAD_VSR(34, r3)
294 LOAD_VSR(35, r3)
295 LOAD_VSR(36, r3)
296 LOAD_VSR(37, r3)
297 LOAD_VSR(38, r3)
298 LOAD_VSR(39, r3)
299 LOAD_VSR(40, r3)
300 LOAD_VSR(41, r3)
301 LOAD_VSR(42, r3)
302 LOAD_VSR(43, r3)
303 LOAD_VSR(44, r3)
304 LOAD_VSR(45, r3)
305 LOAD_VSR(46, r3)
306 LOAD_VSR(47, r3)
307 LOAD_VSR(48, r3)
308 LOAD_VSR(49, r3)
309 LOAD_VSR(50, r3)
310 LOAD_VSR(51, r3)
311 LOAD_VSR(52, r3)
312 LOAD_VSR(53, r3)
313 LOAD_VSR(54, r3)
314 LOAD_VSR(55, r3)
315 LOAD_VSR(56, r3)
316 LOAD_VSR(57, r3)
317 LOAD_VSR(58, r3)
318 LOAD_VSR(59, r3)
319 LOAD_VSR(60, r3)
320 LOAD_VSR(61, r3)
321 LOAD_VSR(62, r3)
322 LOAD_VSR(63, r3)
323
324 ld r0,XER_SAVE(r1)
325 mtxer r0
326 ld r0,CTR_SAVE(r1)
327 mtctr r0
328 ld r0,LR_SAVE(r1)
329 mtlr r0
330 ld r0,CCR_SAVE(r1)
331 mtcr r0
332 REST_GPR(0)
333 REST_GPR(2)
334 REST_GPR(3)
335 REST_GPR(4)
336 REST_GPR(5)
337 REST_GPR(6)
338 REST_GPR(7)
339 REST_GPR(8)
340 REST_GPR(9)
341 REST_GPR(10)
342 REST_GPR(11)
343 REST_GPR(12)
344 REST_GPR(13)
345 REST_GPR(14)
346 REST_GPR(15)
347 REST_GPR(16)
348 REST_GPR(17)
349 REST_GPR(18)
350 REST_GPR(19)
351 REST_GPR(20)
352 REST_GPR(21)
353 REST_GPR(22)
354 REST_GPR(23)
355 REST_GPR(24)
356 REST_GPR(25)
357 REST_GPR(26)
358 REST_GPR(27)
359 REST_GPR(28)
360 REST_GPR(29)
361 REST_GPR(30)
362 REST_GPR(31)
363 addi r1,r1,STACK_FRAME
364 RFEBB
365FUNC_END(ebb_handler)
diff --git a/tools/testing/selftests/powerpc/pmu/ebb/ebb_on_child_test.c b/tools/testing/selftests/powerpc/pmu/ebb/ebb_on_child_test.c
new file mode 100644
index 000000000000..c45f948148e1
--- /dev/null
+++ b/tools/testing/selftests/powerpc/pmu/ebb/ebb_on_child_test.c
@@ -0,0 +1,86 @@
1/*
2 * Copyright 2014, Michael Ellerman, IBM Corp.
3 * Licensed under GPLv2.
4 */
5
6#include <signal.h>
7#include <stdio.h>
8#include <stdlib.h>
9#include <stdbool.h>
10#include <sys/types.h>
11#include <sys/wait.h>
12#include <unistd.h>
13
14#include "ebb.h"
15
16
17/*
18 * Tests we can setup an EBB on our child. Nothing interesting happens, because
19 * even though the event is enabled and running the child hasn't enabled the
20 * actual delivery of the EBBs.
21 */
22
23static int victim_child(union pipe read_pipe, union pipe write_pipe)
24{
25 int i;
26
27 FAIL_IF(wait_for_parent(read_pipe));
28 FAIL_IF(notify_parent(write_pipe));
29
30 /* Parent creates EBB event */
31
32 FAIL_IF(wait_for_parent(read_pipe));
33 FAIL_IF(notify_parent(write_pipe));
34
35 /* Check the EBB is enabled by writing PMC1 */
36 write_pmc1();
37
38 /* EBB event is enabled here */
39 for (i = 0; i < 1000000; i++) ;
40
41 return 0;
42}
43
44int ebb_on_child(void)
45{
46 union pipe read_pipe, write_pipe;
47 struct event event;
48 pid_t pid;
49
50 FAIL_IF(pipe(read_pipe.fds) == -1);
51 FAIL_IF(pipe(write_pipe.fds) == -1);
52
53 pid = fork();
54 if (pid == 0) {
55 /* NB order of pipes looks reversed */
56 exit(victim_child(write_pipe, read_pipe));
57 }
58
59 FAIL_IF(sync_with_child(read_pipe, write_pipe));
60
61 /* Child is running now */
62
63 event_init_named(&event, 0x1001e, "cycles");
64 event_leader_ebb_init(&event);
65
66 event.attr.exclude_kernel = 1;
67 event.attr.exclude_hv = 1;
68 event.attr.exclude_idle = 1;
69
70 FAIL_IF(event_open_with_pid(&event, pid));
71 FAIL_IF(ebb_event_enable(&event));
72
73 FAIL_IF(sync_with_child(read_pipe, write_pipe));
74
75 /* Child should just exit happily */
76 FAIL_IF(wait_for_child(pid));
77
78 event_close(&event);
79
80 return 0;
81}
82
83int main(void)
84{
85 return test_harness(ebb_on_child, "ebb_on_child");
86}
diff --git a/tools/testing/selftests/powerpc/pmu/ebb/ebb_on_willing_child_test.c b/tools/testing/selftests/powerpc/pmu/ebb/ebb_on_willing_child_test.c
new file mode 100644
index 000000000000..11acf1d55f8d
--- /dev/null
+++ b/tools/testing/selftests/powerpc/pmu/ebb/ebb_on_willing_child_test.c
@@ -0,0 +1,92 @@
1/*
2 * Copyright 2014, Michael Ellerman, IBM Corp.
3 * Licensed under GPLv2.
4 */
5
6#include <signal.h>
7#include <stdio.h>
8#include <stdlib.h>
9#include <stdbool.h>
10#include <sys/types.h>
11#include <sys/wait.h>
12#include <unistd.h>
13
14#include "ebb.h"
15
16
17/*
18 * Tests we can setup an EBB on our child. The child expects this and enables
19 * EBBs, which are then delivered to the child, even though the event is
20 * created by the parent.
21 */
22
23static int victim_child(union pipe read_pipe, union pipe write_pipe)
24{
25 FAIL_IF(wait_for_parent(read_pipe));
26
27 /* Setup our EBB handler, before the EBB event is created */
28 ebb_enable_pmc_counting(1);
29 setup_ebb_handler(standard_ebb_callee);
30 ebb_global_enable();
31
32 FAIL_IF(notify_parent(write_pipe));
33
34 while (ebb_state.stats.ebb_count < 20) {
35 FAIL_IF(core_busy_loop());
36 }
37
38 ebb_global_disable();
39 ebb_freeze_pmcs();
40
41 count_pmc(1, sample_period);
42
43 dump_ebb_state();
44
45 FAIL_IF(ebb_state.stats.ebb_count == 0);
46
47 return 0;
48}
49
50/* Tests we can setup an EBB on our child - if it's expecting it */
51int ebb_on_willing_child(void)
52{
53 union pipe read_pipe, write_pipe;
54 struct event event;
55 pid_t pid;
56
57 FAIL_IF(pipe(read_pipe.fds) == -1);
58 FAIL_IF(pipe(write_pipe.fds) == -1);
59
60 pid = fork();
61 if (pid == 0) {
62 /* NB order of pipes looks reversed */
63 exit(victim_child(write_pipe, read_pipe));
64 }
65
66 /* Signal the child to setup its EBB handler */
67 FAIL_IF(sync_with_child(read_pipe, write_pipe));
68
69 /* Child is running now */
70
71 event_init_named(&event, 0x1001e, "cycles");
72 event_leader_ebb_init(&event);
73
74 event.attr.exclude_kernel = 1;
75 event.attr.exclude_hv = 1;
76 event.attr.exclude_idle = 1;
77
78 FAIL_IF(event_open_with_pid(&event, pid));
79 FAIL_IF(ebb_event_enable(&event));
80
81 /* Child show now take EBBs and then exit */
82 FAIL_IF(wait_for_child(pid));
83
84 event_close(&event);
85
86 return 0;
87}
88
89int main(void)
90{
91 return test_harness(ebb_on_willing_child, "ebb_on_willing_child");
92}
diff --git a/tools/testing/selftests/powerpc/pmu/ebb/ebb_vs_cpu_event_test.c b/tools/testing/selftests/powerpc/pmu/ebb/ebb_vs_cpu_event_test.c
new file mode 100644
index 000000000000..be4dd5a4e98e
--- /dev/null
+++ b/tools/testing/selftests/powerpc/pmu/ebb/ebb_vs_cpu_event_test.c
@@ -0,0 +1,86 @@
1/*
2 * Copyright 2014, Michael Ellerman, IBM Corp.
3 * Licensed under GPLv2.
4 */
5
6#include <signal.h>
7#include <stdio.h>
8#include <stdlib.h>
9#include <stdbool.h>
10#include <sys/types.h>
11#include <sys/wait.h>
12#include <unistd.h>
13
14#include "ebb.h"
15
16
17/*
18 * Tests an EBB vs a cpu event - in that order. The EBB should force the cpu
19 * event off the PMU.
20 */
21
22static int setup_cpu_event(struct event *event, int cpu)
23{
24 event_init_named(event, 0x400FA, "PM_RUN_INST_CMPL");
25
26 event->attr.exclude_kernel = 1;
27 event->attr.exclude_hv = 1;
28 event->attr.exclude_idle = 1;
29
30 SKIP_IF(require_paranoia_below(1));
31 FAIL_IF(event_open_with_cpu(event, cpu));
32 FAIL_IF(event_enable(event));
33
34 return 0;
35}
36
37int ebb_vs_cpu_event(void)
38{
39 union pipe read_pipe, write_pipe;
40 struct event event;
41 int cpu, rc;
42 pid_t pid;
43
44 cpu = pick_online_cpu();
45 FAIL_IF(cpu < 0);
46 FAIL_IF(bind_to_cpu(cpu));
47
48 FAIL_IF(pipe(read_pipe.fds) == -1);
49 FAIL_IF(pipe(write_pipe.fds) == -1);
50
51 pid = fork();
52 if (pid == 0) {
53 /* NB order of pipes looks reversed */
54 exit(ebb_child(write_pipe, read_pipe));
55 }
56
57 /* Signal the child to install its EBB event and wait */
58 FAIL_IF(sync_with_child(read_pipe, write_pipe));
59
60 /* Now try to install our CPU event */
61 rc = setup_cpu_event(&event, cpu);
62 if (rc) {
63 kill_child_and_wait(pid);
64 return rc;
65 }
66
67 /* Signal the child to run */
68 FAIL_IF(sync_with_child(read_pipe, write_pipe));
69
70 /* .. and wait for it to complete */
71 FAIL_IF(wait_for_child(pid));
72 FAIL_IF(event_disable(&event));
73 FAIL_IF(event_read(&event));
74
75 event_report(&event);
76
77 /* The cpu event may have run, but we don't expect 100% */
78 FAIL_IF(event.result.enabled >= event.result.running);
79
80 return 0;
81}
82
83int main(void)
84{
85 return test_harness(ebb_vs_cpu_event, "ebb_vs_cpu_event");
86}
diff --git a/tools/testing/selftests/powerpc/pmu/ebb/event_attributes_test.c b/tools/testing/selftests/powerpc/pmu/ebb/event_attributes_test.c
new file mode 100644
index 000000000000..7e78153f08eb
--- /dev/null
+++ b/tools/testing/selftests/powerpc/pmu/ebb/event_attributes_test.c
@@ -0,0 +1,131 @@
1/*
2 * Copyright 2014, Michael Ellerman, IBM Corp.
3 * Licensed under GPLv2.
4 */
5
6#include <stdio.h>
7#include <stdlib.h>
8
9#include "ebb.h"
10
11
12/*
13 * Test various attributes of the EBB event are enforced.
14 */
15int event_attributes(void)
16{
17 struct event event, leader;
18
19 event_init(&event, 0x1001e);
20 event_leader_ebb_init(&event);
21 /* Expected to succeed */
22 FAIL_IF(event_open(&event));
23 event_close(&event);
24
25
26 event_init(&event, 0x001e); /* CYCLES - no PMC specified */
27 event_leader_ebb_init(&event);
28 /* Expected to fail, no PMC specified */
29 FAIL_IF(event_open(&event) == 0);
30
31
32 event_init(&event, 0x2001e);
33 event_leader_ebb_init(&event);
34 event.attr.exclusive = 0;
35 /* Expected to fail, not exclusive */
36 FAIL_IF(event_open(&event) == 0);
37
38
39 event_init(&event, 0x3001e);
40 event_leader_ebb_init(&event);
41 event.attr.freq = 1;
42 /* Expected to fail, sets freq */
43 FAIL_IF(event_open(&event) == 0);
44
45
46 event_init(&event, 0x4001e);
47 event_leader_ebb_init(&event);
48 event.attr.sample_period = 1;
49 /* Expected to fail, sets sample_period */
50 FAIL_IF(event_open(&event) == 0);
51
52
53 event_init(&event, 0x1001e);
54 event_leader_ebb_init(&event);
55 event.attr.enable_on_exec = 1;
56 /* Expected to fail, sets enable_on_exec */
57 FAIL_IF(event_open(&event) == 0);
58
59
60 event_init(&event, 0x1001e);
61 event_leader_ebb_init(&event);
62 event.attr.inherit = 1;
63 /* Expected to fail, sets inherit */
64 FAIL_IF(event_open(&event) == 0);
65
66
67 event_init(&leader, 0x1001e);
68 event_leader_ebb_init(&leader);
69 FAIL_IF(event_open(&leader));
70
71 event_init(&event, 0x20002);
72 event_ebb_init(&event);
73
74 /* Expected to succeed */
75 FAIL_IF(event_open_with_group(&event, leader.fd));
76 event_close(&leader);
77 event_close(&event);
78
79
80 event_init(&leader, 0x1001e);
81 event_leader_ebb_init(&leader);
82 FAIL_IF(event_open(&leader));
83
84 event_init(&event, 0x20002);
85
86 /* Expected to fail, event doesn't request EBB, leader does */
87 FAIL_IF(event_open_with_group(&event, leader.fd) == 0);
88 event_close(&leader);
89
90
91 event_init(&leader, 0x1001e);
92 event_leader_ebb_init(&leader);
93 /* Clear the EBB flag */
94 leader.attr.config &= ~(1ull << 63);
95
96 FAIL_IF(event_open(&leader));
97
98 event_init(&event, 0x20002);
99 event_ebb_init(&event);
100
101 /* Expected to fail, leader doesn't request EBB */
102 FAIL_IF(event_open_with_group(&event, leader.fd) == 0);
103 event_close(&leader);
104
105
106 event_init(&leader, 0x1001e);
107 event_leader_ebb_init(&leader);
108 leader.attr.exclusive = 0;
109 /* Expected to fail, leader isn't exclusive */
110 FAIL_IF(event_open(&leader) == 0);
111
112
113 event_init(&leader, 0x1001e);
114 event_leader_ebb_init(&leader);
115 leader.attr.pinned = 0;
116 /* Expected to fail, leader isn't pinned */
117 FAIL_IF(event_open(&leader) == 0);
118
119 event_init(&event, 0x1001e);
120 event_leader_ebb_init(&event);
121 /* Expected to fail, not a task event */
122 SKIP_IF(require_paranoia_below(1));
123 FAIL_IF(event_open_with_cpu(&event, 0) == 0);
124
125 return 0;
126}
127
128int main(void)
129{
130 return test_harness(event_attributes, "event_attributes");
131}
diff --git a/tools/testing/selftests/powerpc/pmu/ebb/fixed_instruction_loop.S b/tools/testing/selftests/powerpc/pmu/ebb/fixed_instruction_loop.S
new file mode 100644
index 000000000000..b866a0581d32
--- /dev/null
+++ b/tools/testing/selftests/powerpc/pmu/ebb/fixed_instruction_loop.S
@@ -0,0 +1,43 @@
1/*
2 * Copyright 2014, Michael Ellerman, IBM Corp.
3 * Licensed under GPLv2.
4 */
5
6#include <ppc-asm.h>
7
8 .text
9
10FUNC_START(thirty_two_instruction_loop)
11 cmpwi r3,0
12 beqlr
13 addi r4,r3,1
14 addi r4,r4,1
15 addi r4,r4,1
16 addi r4,r4,1
17 addi r4,r4,1
18 addi r4,r4,1
19 addi r4,r4,1
20 addi r4,r4,1
21 addi r4,r4,1
22 addi r4,r4,1
23 addi r4,r4,1
24 addi r4,r4,1
25 addi r4,r4,1
26 addi r4,r4,1
27 addi r4,r4,1
28 addi r4,r4,1
29 addi r4,r4,1
30 addi r4,r4,1
31 addi r4,r4,1
32 addi r4,r4,1
33 addi r4,r4,1
34 addi r4,r4,1
35 addi r4,r4,1
36 addi r4,r4,1
37 addi r4,r4,1
38 addi r4,r4,1
39 addi r4,r4,1
40 addi r4,r4,1 # 28 addi's
41 subi r3,r3,1
42 b FUNC_NAME(thirty_two_instruction_loop)
43FUNC_END(thirty_two_instruction_loop)
diff --git a/tools/testing/selftests/powerpc/pmu/ebb/fork_cleanup_test.c b/tools/testing/selftests/powerpc/pmu/ebb/fork_cleanup_test.c
new file mode 100644
index 000000000000..9e7af6e76622
--- /dev/null
+++ b/tools/testing/selftests/powerpc/pmu/ebb/fork_cleanup_test.c
@@ -0,0 +1,79 @@
1/*
2 * Copyright 2014, Michael Ellerman, IBM Corp.
3 * Licensed under GPLv2.
4 */
5
6#include <signal.h>
7#include <stdio.h>
8#include <stdlib.h>
9#include <stdbool.h>
10#include <sys/types.h>
11#include <sys/wait.h>
12#include <unistd.h>
13#include <setjmp.h>
14#include <signal.h>
15
16#include "ebb.h"
17
18
19/*
20 * Test that a fork clears the PMU state of the child. eg. BESCR/EBBHR/EBBRR
21 * are cleared, and MMCR0_PMCC is reset, preventing the child from accessing
22 * the PMU.
23 */
24
25static struct event event;
26
27static int child(void)
28{
29 /* Even though we have EBE=0 we can still see the EBB regs */
30 FAIL_IF(mfspr(SPRN_BESCR) != 0);
31 FAIL_IF(mfspr(SPRN_EBBHR) != 0);
32 FAIL_IF(mfspr(SPRN_EBBRR) != 0);
33
34 FAIL_IF(catch_sigill(write_pmc1));
35
36 /* We can still read from the event, though it is on our parent */
37 FAIL_IF(event_read(&event));
38
39 return 0;
40}
41
42/* Tests that fork clears EBB state */
43int fork_cleanup(void)
44{
45 pid_t pid;
46
47 event_init_named(&event, 0x1001e, "cycles");
48 event_leader_ebb_init(&event);
49
50 FAIL_IF(event_open(&event));
51
52 ebb_enable_pmc_counting(1);
53 setup_ebb_handler(standard_ebb_callee);
54 ebb_global_enable();
55
56 FAIL_IF(ebb_event_enable(&event));
57
58 mtspr(SPRN_MMCR0, MMCR0_FC);
59 mtspr(SPRN_PMC1, pmc_sample_period(sample_period));
60
61 /* Don't need to actually take any EBBs */
62
63 pid = fork();
64 if (pid == 0)
65 exit(child());
66
67 /* Child does the actual testing */
68 FAIL_IF(wait_for_child(pid));
69
70 /* After fork */
71 event_close(&event);
72
73 return 0;
74}
75
76int main(void)
77{
78 return test_harness(fork_cleanup, "fork_cleanup");
79}
diff --git a/tools/testing/selftests/powerpc/pmu/ebb/instruction_count_test.c b/tools/testing/selftests/powerpc/pmu/ebb/instruction_count_test.c
new file mode 100644
index 000000000000..f8190fa29592
--- /dev/null
+++ b/tools/testing/selftests/powerpc/pmu/ebb/instruction_count_test.c
@@ -0,0 +1,164 @@
1/*
2 * Copyright 2014, Michael Ellerman, IBM Corp.
3 * Licensed under GPLv2.
4 */
5
6#define _GNU_SOURCE
7
8#include <stdio.h>
9#include <stdbool.h>
10#include <string.h>
11#include <sys/prctl.h>
12
13#include "ebb.h"
14
15
16/*
17 * Run a calibrated instruction loop and count instructions executed using
18 * EBBs. Make sure the counts look right.
19 */
20
21extern void thirty_two_instruction_loop(uint64_t loops);
22
23static bool counters_frozen = true;
24
25static int do_count_loop(struct event *event, uint64_t instructions,
26 uint64_t overhead, bool report)
27{
28 int64_t difference, expected;
29 double percentage;
30
31 clear_ebb_stats();
32
33 counters_frozen = false;
34 mb();
35 mtspr(SPRN_MMCR0, mfspr(SPRN_MMCR0) & ~MMCR0_FC);
36
37 thirty_two_instruction_loop(instructions >> 5);
38
39 counters_frozen = true;
40 mb();
41 mtspr(SPRN_MMCR0, mfspr(SPRN_MMCR0) | MMCR0_FC);
42
43 count_pmc(4, sample_period);
44
45 event->result.value = ebb_state.stats.pmc_count[4-1];
46 expected = instructions + overhead;
47 difference = event->result.value - expected;
48 percentage = (double)difference / event->result.value * 100;
49
50 if (report) {
51 printf("Looped for %lu instructions, overhead %lu\n", instructions, overhead);
52 printf("Expected %lu\n", expected);
53 printf("Actual %llu\n", event->result.value);
54 printf("Error %ld, %f%%\n", difference, percentage);
55 printf("Took %d EBBs\n", ebb_state.stats.ebb_count);
56 }
57
58 if (difference < 0)
59 difference = -difference;
60
61 /* Tolerate a difference of up to 0.0001 % */
62 difference *= 10000 * 100;
63 if (difference / event->result.value)
64 return -1;
65
66 return 0;
67}
68
69/* Count how many instructions it takes to do a null loop */
70static uint64_t determine_overhead(struct event *event)
71{
72 uint64_t current, overhead;
73 int i;
74
75 do_count_loop(event, 0, 0, false);
76 overhead = event->result.value;
77
78 for (i = 0; i < 100; i++) {
79 do_count_loop(event, 0, 0, false);
80 current = event->result.value;
81 if (current < overhead) {
82 printf("Replacing overhead %lu with %lu\n", overhead, current);
83 overhead = current;
84 }
85 }
86
87 return overhead;
88}
89
90static void pmc4_ebb_callee(void)
91{
92 uint64_t val;
93
94 val = mfspr(SPRN_BESCR);
95 if (!(val & BESCR_PMEO)) {
96 ebb_state.stats.spurious++;
97 goto out;
98 }
99
100 ebb_state.stats.ebb_count++;
101 count_pmc(4, sample_period);
102out:
103 if (counters_frozen)
104 reset_ebb_with_clear_mask(MMCR0_PMAO);
105 else
106 reset_ebb();
107}
108
109int instruction_count(void)
110{
111 struct event event;
112 uint64_t overhead;
113
114 event_init_named(&event, 0x400FA, "PM_RUN_INST_CMPL");
115 event_leader_ebb_init(&event);
116 event.attr.exclude_kernel = 1;
117 event.attr.exclude_hv = 1;
118 event.attr.exclude_idle = 1;
119
120 FAIL_IF(event_open(&event));
121 FAIL_IF(ebb_event_enable(&event));
122
123 sample_period = COUNTER_OVERFLOW;
124
125 setup_ebb_handler(pmc4_ebb_callee);
126 mtspr(SPRN_MMCR0, mfspr(SPRN_MMCR0) & ~MMCR0_FC);
127 ebb_global_enable();
128
129 overhead = determine_overhead(&event);
130 printf("Overhead of null loop: %lu instructions\n", overhead);
131
132 /* Run for 1M instructions */
133 FAIL_IF(do_count_loop(&event, 0x100000, overhead, true));
134
135 /* Run for 10M instructions */
136 FAIL_IF(do_count_loop(&event, 0xa00000, overhead, true));
137
138 /* Run for 100M instructions */
139 FAIL_IF(do_count_loop(&event, 0x6400000, overhead, true));
140
141 /* Run for 1G instructions */
142 FAIL_IF(do_count_loop(&event, 0x40000000, overhead, true));
143
144 /* Run for 16G instructions */
145 FAIL_IF(do_count_loop(&event, 0x400000000, overhead, true));
146
147 /* Run for 64G instructions */
148 FAIL_IF(do_count_loop(&event, 0x1000000000, overhead, true));
149
150 /* Run for 128G instructions */
151 FAIL_IF(do_count_loop(&event, 0x2000000000, overhead, true));
152
153 ebb_global_disable();
154 event_close(&event);
155
156 printf("Finished OK\n");
157
158 return 0;
159}
160
161int main(void)
162{
163 return test_harness(instruction_count, "instruction_count");
164}
diff --git a/tools/testing/selftests/powerpc/pmu/ebb/lost_exception_test.c b/tools/testing/selftests/powerpc/pmu/ebb/lost_exception_test.c
new file mode 100644
index 000000000000..0c9dd9b2e39d
--- /dev/null
+++ b/tools/testing/selftests/powerpc/pmu/ebb/lost_exception_test.c
@@ -0,0 +1,100 @@
1/*
2 * Copyright 2014, Michael Ellerman, IBM Corp.
3 * Licensed under GPLv2.
4 */
5
6#include <sched.h>
7#include <signal.h>
8#include <stdio.h>
9#include <stdlib.h>
10#include <sys/mman.h>
11
12#include "ebb.h"
13
14
15/*
16 * Test that tries to trigger CPU_FTR_PMAO_BUG. Which is a hardware defect
17 * where an exception triggers but we context switch before it is delivered and
18 * lose the exception.
19 */
20
21static int test_body(void)
22{
23 int i, orig_period, max_period;
24 struct event event;
25
26 /* We use PMC4 to make sure the kernel switches all counters correctly */
27 event_init_named(&event, 0x40002, "instructions");
28 event_leader_ebb_init(&event);
29
30 event.attr.exclude_kernel = 1;
31 event.attr.exclude_hv = 1;
32 event.attr.exclude_idle = 1;
33
34 FAIL_IF(event_open(&event));
35
36 ebb_enable_pmc_counting(4);
37 setup_ebb_handler(standard_ebb_callee);
38 ebb_global_enable();
39 FAIL_IF(ebb_event_enable(&event));
40
41 /*
42 * We want a low sample period, but we also want to get out of the EBB
43 * handler without tripping up again.
44 *
45 * This value picked after much experimentation.
46 */
47 orig_period = max_period = sample_period = 400;
48
49 mtspr(SPRN_PMC4, pmc_sample_period(sample_period));
50
51 while (ebb_state.stats.ebb_count < 1000000) {
52 /*
53 * We are trying to get the EBB exception to race exactly with
54 * us entering the kernel to do the syscall. We then need the
55 * kernel to decide our timeslice is up and context switch to
56 * the other thread. When we come back our EBB will have been
57 * lost and we'll spin in this while loop forever.
58 */
59
60 for (i = 0; i < 100000; i++)
61 sched_yield();
62
63 /* Change the sample period slightly to try and hit the race */
64 if (sample_period >= (orig_period + 200))
65 sample_period = orig_period;
66 else
67 sample_period++;
68
69 if (sample_period > max_period)
70 max_period = sample_period;
71 }
72
73 ebb_freeze_pmcs();
74 ebb_global_disable();
75
76 count_pmc(4, sample_period);
77 mtspr(SPRN_PMC4, 0xdead);
78
79 dump_summary_ebb_state();
80 dump_ebb_hw_state();
81
82 event_close(&event);
83
84 FAIL_IF(ebb_state.stats.ebb_count == 0);
85
86 /* We vary our sample period so we need extra fudge here */
87 FAIL_IF(!ebb_check_count(4, orig_period, 2 * (max_period - orig_period)));
88
89 return 0;
90}
91
92static int lost_exception(void)
93{
94 return eat_cpu(test_body);
95}
96
97int main(void)
98{
99 return test_harness(lost_exception, "lost_exception");
100}
diff --git a/tools/testing/selftests/powerpc/pmu/ebb/multi_counter_test.c b/tools/testing/selftests/powerpc/pmu/ebb/multi_counter_test.c
new file mode 100644
index 000000000000..67d78af3284c
--- /dev/null
+++ b/tools/testing/selftests/powerpc/pmu/ebb/multi_counter_test.c
@@ -0,0 +1,91 @@
1/*
2 * Copyright 2014, Michael Ellerman, IBM Corp.
3 * Licensed under GPLv2.
4 */
5
6#include <stdio.h>
7#include <stdlib.h>
8#include <sys/ioctl.h>
9
10#include "ebb.h"
11
12
13/*
14 * Test counting multiple events using EBBs.
15 */
16int multi_counter(void)
17{
18 struct event events[6];
19 int i, group_fd;
20
21 event_init_named(&events[0], 0x1001C, "PM_CMPLU_STALL_THRD");
22 event_init_named(&events[1], 0x2D016, "PM_CMPLU_STALL_FXU");
23 event_init_named(&events[2], 0x30006, "PM_CMPLU_STALL_OTHER_CMPL");
24 event_init_named(&events[3], 0x4000A, "PM_CMPLU_STALL");
25 event_init_named(&events[4], 0x600f4, "PM_RUN_CYC");
26 event_init_named(&events[5], 0x500fa, "PM_RUN_INST_CMPL");
27
28 event_leader_ebb_init(&events[0]);
29 for (i = 1; i < 6; i++)
30 event_ebb_init(&events[i]);
31
32 group_fd = -1;
33 for (i = 0; i < 6; i++) {
34 events[i].attr.exclude_kernel = 1;
35 events[i].attr.exclude_hv = 1;
36 events[i].attr.exclude_idle = 1;
37
38 FAIL_IF(event_open_with_group(&events[i], group_fd));
39 if (group_fd == -1)
40 group_fd = events[0].fd;
41 }
42
43 ebb_enable_pmc_counting(1);
44 ebb_enable_pmc_counting(2);
45 ebb_enable_pmc_counting(3);
46 ebb_enable_pmc_counting(4);
47 ebb_enable_pmc_counting(5);
48 ebb_enable_pmc_counting(6);
49 setup_ebb_handler(standard_ebb_callee);
50
51 FAIL_IF(ioctl(events[0].fd, PERF_EVENT_IOC_ENABLE, PERF_IOC_FLAG_GROUP));
52 FAIL_IF(event_read(&events[0]));
53
54 ebb_global_enable();
55
56 mtspr(SPRN_PMC1, pmc_sample_period(sample_period));
57 mtspr(SPRN_PMC2, pmc_sample_period(sample_period));
58 mtspr(SPRN_PMC3, pmc_sample_period(sample_period));
59 mtspr(SPRN_PMC4, pmc_sample_period(sample_period));
60 mtspr(SPRN_PMC5, pmc_sample_period(sample_period));
61 mtspr(SPRN_PMC6, pmc_sample_period(sample_period));
62
63 while (ebb_state.stats.ebb_count < 50) {
64 FAIL_IF(core_busy_loop());
65 FAIL_IF(ebb_check_mmcr0());
66 }
67
68 ebb_global_disable();
69 ebb_freeze_pmcs();
70
71 count_pmc(1, sample_period);
72 count_pmc(2, sample_period);
73 count_pmc(3, sample_period);
74 count_pmc(4, sample_period);
75 count_pmc(5, sample_period);
76 count_pmc(6, sample_period);
77
78 dump_ebb_state();
79
80 for (i = 0; i < 6; i++)
81 event_close(&events[i]);
82
83 FAIL_IF(ebb_state.stats.ebb_count == 0);
84
85 return 0;
86}
87
88int main(void)
89{
90 return test_harness(multi_counter, "multi_counter");
91}
diff --git a/tools/testing/selftests/powerpc/pmu/ebb/multi_ebb_procs_test.c b/tools/testing/selftests/powerpc/pmu/ebb/multi_ebb_procs_test.c
new file mode 100644
index 000000000000..b8dc371f9338
--- /dev/null
+++ b/tools/testing/selftests/powerpc/pmu/ebb/multi_ebb_procs_test.c
@@ -0,0 +1,109 @@
1/*
2 * Copyright 2014, Michael Ellerman, IBM Corp.
3 * Licensed under GPLv2.
4 */
5
6#include <stdbool.h>
7#include <stdio.h>
8#include <stdlib.h>
9#include <signal.h>
10
11#include "ebb.h"
12
13
14/*
15 * Test running multiple EBB using processes at once on a single CPU. They
16 * should all run happily without interfering with each other.
17 */
18
19static bool child_should_exit;
20
21static void sigint_handler(int signal)
22{
23 child_should_exit = true;
24}
25
26struct sigaction sigint_action = {
27 .sa_handler = sigint_handler,
28};
29
30static int cycles_child(void)
31{
32 struct event event;
33
34 if (sigaction(SIGINT, &sigint_action, NULL)) {
35 perror("sigaction");
36 return 1;
37 }
38
39 event_init_named(&event, 0x1001e, "cycles");
40 event_leader_ebb_init(&event);
41
42 event.attr.exclude_kernel = 1;
43 event.attr.exclude_hv = 1;
44 event.attr.exclude_idle = 1;
45
46 FAIL_IF(event_open(&event));
47
48 ebb_enable_pmc_counting(1);
49 setup_ebb_handler(standard_ebb_callee);
50 ebb_global_enable();
51
52 FAIL_IF(ebb_event_enable(&event));
53
54 mtspr(SPRN_PMC1, pmc_sample_period(sample_period));
55
56 while (!child_should_exit) {
57 FAIL_IF(core_busy_loop());
58 FAIL_IF(ebb_check_mmcr0());
59 }
60
61 ebb_global_disable();
62 ebb_freeze_pmcs();
63
64 count_pmc(1, sample_period);
65
66 dump_summary_ebb_state();
67
68 event_close(&event);
69
70 FAIL_IF(ebb_state.stats.ebb_count == 0);
71
72 return 0;
73}
74
75#define NR_CHILDREN 4
76
77int multi_ebb_procs(void)
78{
79 pid_t pids[NR_CHILDREN];
80 int cpu, rc, i;
81
82 cpu = pick_online_cpu();
83 FAIL_IF(cpu < 0);
84 FAIL_IF(bind_to_cpu(cpu));
85
86 for (i = 0; i < NR_CHILDREN; i++) {
87 pids[i] = fork();
88 if (pids[i] == 0)
89 exit(cycles_child());
90 }
91
92 /* Have them all run for "a while" */
93 sleep(10);
94
95 rc = 0;
96 for (i = 0; i < NR_CHILDREN; i++) {
97 /* Tell them to stop */
98 kill(pids[i], SIGINT);
99 /* And wait */
100 rc |= wait_for_child(pids[i]);
101 }
102
103 return rc;
104}
105
106int main(void)
107{
108 return test_harness(multi_ebb_procs, "multi_ebb_procs");
109}
diff --git a/tools/testing/selftests/powerpc/pmu/ebb/no_handler_test.c b/tools/testing/selftests/powerpc/pmu/ebb/no_handler_test.c
new file mode 100644
index 000000000000..2f9bf8edfa60
--- /dev/null
+++ b/tools/testing/selftests/powerpc/pmu/ebb/no_handler_test.c
@@ -0,0 +1,61 @@
1/*
2 * Copyright 2014, Michael Ellerman, IBM Corp.
3 * Licensed under GPLv2.
4 */
5
6#include <stdio.h>
7#include <stdlib.h>
8#include <setjmp.h>
9#include <signal.h>
10
11#include "ebb.h"
12
13
14/* Test that things work sanely if we have no handler */
15
16static int no_handler_test(void)
17{
18 struct event event;
19 u64 val;
20 int i;
21
22 event_init_named(&event, 0x1001e, "cycles");
23 event_leader_ebb_init(&event);
24
25 event.attr.exclude_kernel = 1;
26 event.attr.exclude_hv = 1;
27 event.attr.exclude_idle = 1;
28
29 FAIL_IF(event_open(&event));
30 FAIL_IF(ebb_event_enable(&event));
31
32 val = mfspr(SPRN_EBBHR);
33 FAIL_IF(val != 0);
34
35 /* Make sure it overflows quickly */
36 sample_period = 1000;
37 mtspr(SPRN_PMC1, pmc_sample_period(sample_period));
38
39 /* Spin to make sure the event has time to overflow */
40 for (i = 0; i < 1000; i++)
41 mb();
42
43 dump_ebb_state();
44
45 /* We expect to see the PMU frozen & PMAO set */
46 val = mfspr(SPRN_MMCR0);
47 FAIL_IF(val != 0x0000000080000080);
48
49 event_close(&event);
50
51 dump_ebb_state();
52
53 /* The real test is that we never took an EBB at 0x0 */
54
55 return 0;
56}
57
58int main(void)
59{
60 return test_harness(no_handler_test,"no_handler_test");
61}
diff --git a/tools/testing/selftests/powerpc/pmu/ebb/pmae_handling_test.c b/tools/testing/selftests/powerpc/pmu/ebb/pmae_handling_test.c
new file mode 100644
index 000000000000..986500fd2131
--- /dev/null
+++ b/tools/testing/selftests/powerpc/pmu/ebb/pmae_handling_test.c
@@ -0,0 +1,106 @@
1/*
2 * Copyright 2014, Michael Ellerman, IBM Corp.
3 * Licensed under GPLv2.
4 */
5
6#include <sched.h>
7#include <signal.h>
8#include <stdbool.h>
9#include <stdio.h>
10#include <stdlib.h>
11
12#include "ebb.h"
13
14
15/*
16 * Test that the kernel properly handles PMAE across context switches.
17 *
18 * We test this by calling into the kernel inside our EBB handler, where PMAE
19 * is clear. A cpu eater companion thread is running on the same CPU as us to
20 * encourage the scheduler to switch us.
21 *
22 * The kernel must make sure that when it context switches us back in, it
23 * honours the fact that we had PMAE clear.
24 *
25 * Observed to hit the failing case on the first EBB with a broken kernel.
26 */
27
28static bool mmcr0_mismatch;
29static uint64_t before, after;
30
31static void syscall_ebb_callee(void)
32{
33 uint64_t val;
34
35 val = mfspr(SPRN_BESCR);
36 if (!(val & BESCR_PMEO)) {
37 ebb_state.stats.spurious++;
38 goto out;
39 }
40
41 ebb_state.stats.ebb_count++;
42 count_pmc(1, sample_period);
43
44 before = mfspr(SPRN_MMCR0);
45
46 /* Try and get ourselves scheduled, to force a PMU context switch */
47 sched_yield();
48
49 after = mfspr(SPRN_MMCR0);
50 if (before != after)
51 mmcr0_mismatch = true;
52
53out:
54 reset_ebb();
55}
56
57static int test_body(void)
58{
59 struct event event;
60
61 event_init_named(&event, 0x1001e, "cycles");
62 event_leader_ebb_init(&event);
63
64 event.attr.exclude_kernel = 1;
65 event.attr.exclude_hv = 1;
66 event.attr.exclude_idle = 1;
67
68 FAIL_IF(event_open(&event));
69
70 setup_ebb_handler(syscall_ebb_callee);
71 ebb_global_enable();
72
73 FAIL_IF(ebb_event_enable(&event));
74
75 mtspr(SPRN_PMC1, pmc_sample_period(sample_period));
76
77 while (ebb_state.stats.ebb_count < 20 && !mmcr0_mismatch)
78 FAIL_IF(core_busy_loop());
79
80 ebb_global_disable();
81 ebb_freeze_pmcs();
82
83 count_pmc(1, sample_period);
84
85 dump_ebb_state();
86
87 if (mmcr0_mismatch)
88 printf("Saw MMCR0 before 0x%lx after 0x%lx\n", before, after);
89
90 event_close(&event);
91
92 FAIL_IF(ebb_state.stats.ebb_count == 0);
93 FAIL_IF(mmcr0_mismatch);
94
95 return 0;
96}
97
98int pmae_handling(void)
99{
100 return eat_cpu(test_body);
101}
102
103int main(void)
104{
105 return test_harness(pmae_handling, "pmae_handling");
106}
diff --git a/tools/testing/selftests/powerpc/pmu/ebb/pmc56_overflow_test.c b/tools/testing/selftests/powerpc/pmu/ebb/pmc56_overflow_test.c
new file mode 100644
index 000000000000..a503fa70c950
--- /dev/null
+++ b/tools/testing/selftests/powerpc/pmu/ebb/pmc56_overflow_test.c
@@ -0,0 +1,93 @@
1/*
2 * Copyright 2014, Michael Ellerman, IBM Corp.
3 * Licensed under GPLv2.
4 */
5
6#include <stdio.h>
7#include <stdlib.h>
8
9#include "ebb.h"
10
11
12/*
13 * Test that PMC5 & 6 are frozen (ie. don't overflow) when they are not being
14 * used. Tests the MMCR0_FC56 logic in the kernel.
15 */
16
17static int pmc56_overflowed;
18
19static void ebb_callee(void)
20{
21 uint64_t val;
22
23 val = mfspr(SPRN_BESCR);
24 if (!(val & BESCR_PMEO)) {
25 ebb_state.stats.spurious++;
26 goto out;
27 }
28
29 ebb_state.stats.ebb_count++;
30 count_pmc(2, sample_period);
31
32 val = mfspr(SPRN_PMC5);
33 if (val >= COUNTER_OVERFLOW)
34 pmc56_overflowed++;
35
36 count_pmc(5, COUNTER_OVERFLOW);
37
38 val = mfspr(SPRN_PMC6);
39 if (val >= COUNTER_OVERFLOW)
40 pmc56_overflowed++;
41
42 count_pmc(6, COUNTER_OVERFLOW);
43
44out:
45 reset_ebb();
46}
47
48int pmc56_overflow(void)
49{
50 struct event event;
51
52 /* Use PMC2 so we set PMCjCE, which enables PMC5/6 */
53 event_init(&event, 0x2001e);
54 event_leader_ebb_init(&event);
55
56 event.attr.exclude_kernel = 1;
57 event.attr.exclude_hv = 1;
58 event.attr.exclude_idle = 1;
59
60 FAIL_IF(event_open(&event));
61
62 setup_ebb_handler(ebb_callee);
63 ebb_global_enable();
64
65 FAIL_IF(ebb_event_enable(&event));
66
67 mtspr(SPRN_PMC1, pmc_sample_period(sample_period));
68 mtspr(SPRN_PMC5, 0);
69 mtspr(SPRN_PMC6, 0);
70
71 while (ebb_state.stats.ebb_count < 10)
72 FAIL_IF(core_busy_loop());
73
74 ebb_global_disable();
75 ebb_freeze_pmcs();
76
77 count_pmc(2, sample_period);
78
79 dump_ebb_state();
80
81 printf("PMC5/6 overflow %d\n", pmc56_overflowed);
82
83 event_close(&event);
84
85 FAIL_IF(ebb_state.stats.ebb_count == 0 || pmc56_overflowed != 0);
86
87 return 0;
88}
89
90int main(void)
91{
92 return test_harness(pmc56_overflow, "pmc56_overflow");
93}
diff --git a/tools/testing/selftests/powerpc/pmu/ebb/reg.h b/tools/testing/selftests/powerpc/pmu/ebb/reg.h
new file mode 100644
index 000000000000..5921b0dfe2e9
--- /dev/null
+++ b/tools/testing/selftests/powerpc/pmu/ebb/reg.h
@@ -0,0 +1,49 @@
1/*
2 * Copyright 2014, Michael Ellerman, IBM Corp.
3 * Licensed under GPLv2.
4 */
5
6#ifndef _SELFTESTS_POWERPC_REG_H
7#define _SELFTESTS_POWERPC_REG_H
8
9#define __stringify_1(x) #x
10#define __stringify(x) __stringify_1(x)
11
12#define mfspr(rn) ({unsigned long rval; \
13 asm volatile("mfspr %0," __stringify(rn) \
14 : "=r" (rval)); rval; })
15#define mtspr(rn, v) asm volatile("mtspr " __stringify(rn) ",%0" : \
16 : "r" ((unsigned long)(v)) \
17 : "memory")
18
19#define mb() asm volatile("sync" : : : "memory");
20
21#define SPRN_MMCR2 769
22#define SPRN_MMCRA 770
23#define SPRN_MMCR0 779
24#define MMCR0_PMAO 0x00000080
25#define MMCR0_PMAE 0x04000000
26#define MMCR0_FC 0x80000000
27#define SPRN_EBBHR 804
28#define SPRN_EBBRR 805
29#define SPRN_BESCR 806 /* Branch event status & control register */
30#define SPRN_BESCRS 800 /* Branch event status & control set (1 bits set to 1) */
31#define SPRN_BESCRSU 801 /* Branch event status & control set upper */
32#define SPRN_BESCRR 802 /* Branch event status & control REset (1 bits set to 0) */
33#define SPRN_BESCRRU 803 /* Branch event status & control REset upper */
34
35#define BESCR_PMEO 0x1 /* PMU Event-based exception Occurred */
36#define BESCR_PME (0x1ul << 32) /* PMU Event-based exception Enable */
37
38#define SPRN_PMC1 771
39#define SPRN_PMC2 772
40#define SPRN_PMC3 773
41#define SPRN_PMC4 774
42#define SPRN_PMC5 775
43#define SPRN_PMC6 776
44
45#define SPRN_SIAR 780
46#define SPRN_SDAR 781
47#define SPRN_SIER 768
48
49#endif /* _SELFTESTS_POWERPC_REG_H */
diff --git a/tools/testing/selftests/powerpc/pmu/ebb/reg_access_test.c b/tools/testing/selftests/powerpc/pmu/ebb/reg_access_test.c
new file mode 100644
index 000000000000..0cae66f659a3
--- /dev/null
+++ b/tools/testing/selftests/powerpc/pmu/ebb/reg_access_test.c
@@ -0,0 +1,39 @@
1/*
2 * Copyright 2014, Michael Ellerman, IBM Corp.
3 * Licensed under GPLv2.
4 */
5
6#include <stdio.h>
7#include <stdlib.h>
8
9#include "ebb.h"
10#include "reg.h"
11
12
13/*
14 * Test basic access to the EBB regs, they should be user accessible with no
15 * kernel interaction required.
16 */
17int reg_access(void)
18{
19 uint64_t val, expected;
20
21 expected = 0x8000000100000000ull;
22 mtspr(SPRN_BESCR, expected);
23 val = mfspr(SPRN_BESCR);
24
25 FAIL_IF(val != expected);
26
27 expected = 0x0000000001000000ull;
28 mtspr(SPRN_EBBHR, expected);
29 val = mfspr(SPRN_EBBHR);
30
31 FAIL_IF(val != expected);
32
33 return 0;
34}
35
36int main(void)
37{
38 return test_harness(reg_access, "reg_access");
39}
diff --git a/tools/testing/selftests/powerpc/pmu/ebb/task_event_pinned_vs_ebb_test.c b/tools/testing/selftests/powerpc/pmu/ebb/task_event_pinned_vs_ebb_test.c
new file mode 100644
index 000000000000..d56607e4ffab
--- /dev/null
+++ b/tools/testing/selftests/powerpc/pmu/ebb/task_event_pinned_vs_ebb_test.c
@@ -0,0 +1,91 @@
1/*
2 * Copyright 2014, Michael Ellerman, IBM Corp.
3 * Licensed under GPLv2.
4 */
5
6#include <signal.h>
7#include <stdio.h>
8#include <stdlib.h>
9#include <stdbool.h>
10#include <sys/types.h>
11#include <sys/wait.h>
12#include <unistd.h>
13
14#include "ebb.h"
15
16
17/*
18 * Tests a pinned per-task event vs an EBB - in that order. The pinned per-task
19 * event should prevent the EBB event from being enabled.
20 */
21
22static int setup_child_event(struct event *event, pid_t child_pid)
23{
24 event_init_named(event, 0x400FA, "PM_RUN_INST_CMPL");
25
26 event->attr.pinned = 1;
27
28 event->attr.exclude_kernel = 1;
29 event->attr.exclude_hv = 1;
30 event->attr.exclude_idle = 1;
31
32 FAIL_IF(event_open_with_pid(event, child_pid));
33 FAIL_IF(event_enable(event));
34
35 return 0;
36}
37
38int task_event_pinned_vs_ebb(void)
39{
40 union pipe read_pipe, write_pipe;
41 struct event event;
42 pid_t pid;
43 int rc;
44
45 FAIL_IF(pipe(read_pipe.fds) == -1);
46 FAIL_IF(pipe(write_pipe.fds) == -1);
47
48 pid = fork();
49 if (pid == 0) {
50 /* NB order of pipes looks reversed */
51 exit(ebb_child(write_pipe, read_pipe));
52 }
53
54 /* We setup the task event first */
55 rc = setup_child_event(&event, pid);
56 if (rc) {
57 kill_child_and_wait(pid);
58 return rc;
59 }
60
61 /* Signal the child to install its EBB event and wait */
62 if (sync_with_child(read_pipe, write_pipe))
63 /* If it fails, wait for it to exit */
64 goto wait;
65
66 /* Signal the child to run */
67 FAIL_IF(sync_with_child(read_pipe, write_pipe));
68
69wait:
70 /* We expect it to fail to read the event */
71 FAIL_IF(wait_for_child(pid) != 2);
72 FAIL_IF(event_disable(&event));
73 FAIL_IF(event_read(&event));
74
75 event_report(&event);
76
77 FAIL_IF(event.result.value == 0);
78 /*
79 * For reasons I don't understand enabled is usually just slightly
80 * lower than running. Would be good to confirm why.
81 */
82 FAIL_IF(event.result.enabled == 0);
83 FAIL_IF(event.result.running == 0);
84
85 return 0;
86}
87
88int main(void)
89{
90 return test_harness(task_event_pinned_vs_ebb, "task_event_pinned_vs_ebb");
91}
diff --git a/tools/testing/selftests/powerpc/pmu/ebb/task_event_vs_ebb_test.c b/tools/testing/selftests/powerpc/pmu/ebb/task_event_vs_ebb_test.c
new file mode 100644
index 000000000000..eba32196dbbf
--- /dev/null
+++ b/tools/testing/selftests/powerpc/pmu/ebb/task_event_vs_ebb_test.c
@@ -0,0 +1,83 @@
1/*
2 * Copyright 2014, Michael Ellerman, IBM Corp.
3 * Licensed under GPLv2.
4 */
5
6#include <signal.h>
7#include <stdio.h>
8#include <stdlib.h>
9#include <stdbool.h>
10#include <sys/types.h>
11#include <sys/wait.h>
12#include <unistd.h>
13
14#include "ebb.h"
15
16
17/*
18 * Tests a per-task event vs an EBB - in that order. The EBB should push the
19 * per-task event off the PMU.
20 */
21
22static int setup_child_event(struct event *event, pid_t child_pid)
23{
24 event_init_named(event, 0x400FA, "PM_RUN_INST_CMPL");
25
26 event->attr.exclude_kernel = 1;
27 event->attr.exclude_hv = 1;
28 event->attr.exclude_idle = 1;
29
30 FAIL_IF(event_open_with_pid(event, child_pid));
31 FAIL_IF(event_enable(event));
32
33 return 0;
34}
35
36int task_event_vs_ebb(void)
37{
38 union pipe read_pipe, write_pipe;
39 struct event event;
40 pid_t pid;
41 int rc;
42
43 FAIL_IF(pipe(read_pipe.fds) == -1);
44 FAIL_IF(pipe(write_pipe.fds) == -1);
45
46 pid = fork();
47 if (pid == 0) {
48 /* NB order of pipes looks reversed */
49 exit(ebb_child(write_pipe, read_pipe));
50 }
51
52 /* We setup the task event first */
53 rc = setup_child_event(&event, pid);
54 if (rc) {
55 kill_child_and_wait(pid);
56 return rc;
57 }
58
59 /* Signal the child to install its EBB event and wait */
60 if (sync_with_child(read_pipe, write_pipe))
61 /* If it fails, wait for it to exit */
62 goto wait;
63
64 /* Signal the child to run */
65 FAIL_IF(sync_with_child(read_pipe, write_pipe));
66
67wait:
68 /* The EBB event should push the task event off so the child should succeed */
69 FAIL_IF(wait_for_child(pid));
70 FAIL_IF(event_disable(&event));
71 FAIL_IF(event_read(&event));
72
73 event_report(&event);
74
75 /* The task event may have run, or not so we can't assert anything about it */
76
77 return 0;
78}
79
80int main(void)
81{
82 return test_harness(task_event_vs_ebb, "task_event_vs_ebb");
83}
diff --git a/tools/testing/selftests/powerpc/pmu/ebb/trace.c b/tools/testing/selftests/powerpc/pmu/ebb/trace.c
new file mode 100644
index 000000000000..251e66ab2aa7
--- /dev/null
+++ b/tools/testing/selftests/powerpc/pmu/ebb/trace.c
@@ -0,0 +1,300 @@
1/*
2 * Copyright 2014, Michael Ellerman, IBM Corp.
3 * Licensed under GPLv2.
4 */
5
6#include <errno.h>
7#include <stdio.h>
8#include <stdlib.h>
9#include <string.h>
10#include <sys/mman.h>
11
12#include "trace.h"
13
14
15struct trace_buffer *trace_buffer_allocate(u64 size)
16{
17 struct trace_buffer *tb;
18
19 if (size < sizeof(*tb)) {
20 fprintf(stderr, "Error: trace buffer too small\n");
21 return NULL;
22 }
23
24 tb = mmap(NULL, size, PROT_READ | PROT_WRITE,
25 MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
26 if (tb == MAP_FAILED) {
27 perror("mmap");
28 return NULL;
29 }
30
31 tb->size = size;
32 tb->tail = tb->data;
33 tb->overflow = false;
34
35 return tb;
36}
37
38static bool trace_check_bounds(struct trace_buffer *tb, void *p)
39{
40 return p < ((void *)tb + tb->size);
41}
42
43static bool trace_check_alloc(struct trace_buffer *tb, void *p)
44{
45 /*
46 * If we ever overflowed don't allow any more input. This prevents us
47 * from dropping a large item and then later logging a small one. The
48 * buffer should just stop when overflow happened, not be patchy. If
49 * you're overflowing, make your buffer bigger.
50 */
51 if (tb->overflow)
52 return false;
53
54 if (!trace_check_bounds(tb, p)) {
55 tb->overflow = true;
56 return false;
57 }
58
59 return true;
60}
61
62static void *trace_alloc(struct trace_buffer *tb, int bytes)
63{
64 void *p, *newtail;
65
66 p = tb->tail;
67 newtail = tb->tail + bytes;
68 if (!trace_check_alloc(tb, newtail))
69 return NULL;
70
71 tb->tail = newtail;
72
73 return p;
74}
75
76static struct trace_entry *trace_alloc_entry(struct trace_buffer *tb, int payload_size)
77{
78 struct trace_entry *e;
79
80 e = trace_alloc(tb, sizeof(*e) + payload_size);
81 if (e)
82 e->length = payload_size;
83
84 return e;
85}
86
87int trace_log_reg(struct trace_buffer *tb, u64 reg, u64 value)
88{
89 struct trace_entry *e;
90 u64 *p;
91
92 e = trace_alloc_entry(tb, sizeof(reg) + sizeof(value));
93 if (!e)
94 return -ENOSPC;
95
96 e->type = TRACE_TYPE_REG;
97 p = (u64 *)e->data;
98 *p++ = reg;
99 *p++ = value;
100
101 return 0;
102}
103
104int trace_log_counter(struct trace_buffer *tb, u64 value)
105{
106 struct trace_entry *e;
107 u64 *p;
108
109 e = trace_alloc_entry(tb, sizeof(value));
110 if (!e)
111 return -ENOSPC;
112
113 e->type = TRACE_TYPE_COUNTER;
114 p = (u64 *)e->data;
115 *p++ = value;
116
117 return 0;
118}
119
120int trace_log_string(struct trace_buffer *tb, char *str)
121{
122 struct trace_entry *e;
123 char *p;
124 int len;
125
126 len = strlen(str);
127
128 /* We NULL terminate to make printing easier */
129 e = trace_alloc_entry(tb, len + 1);
130 if (!e)
131 return -ENOSPC;
132
133 e->type = TRACE_TYPE_STRING;
134 p = (char *)e->data;
135 memcpy(p, str, len);
136 p += len;
137 *p = '\0';
138
139 return 0;
140}
141
142int trace_log_indent(struct trace_buffer *tb)
143{
144 struct trace_entry *e;
145
146 e = trace_alloc_entry(tb, 0);
147 if (!e)
148 return -ENOSPC;
149
150 e->type = TRACE_TYPE_INDENT;
151
152 return 0;
153}
154
155int trace_log_outdent(struct trace_buffer *tb)
156{
157 struct trace_entry *e;
158
159 e = trace_alloc_entry(tb, 0);
160 if (!e)
161 return -ENOSPC;
162
163 e->type = TRACE_TYPE_OUTDENT;
164
165 return 0;
166}
167
168static void trace_print_header(int seq, int prefix)
169{
170 printf("%*s[%d]: ", prefix, "", seq);
171}
172
173static char *trace_decode_reg(int reg)
174{
175 switch (reg) {
176 case 769: return "SPRN_MMCR2"; break;
177 case 770: return "SPRN_MMCRA"; break;
178 case 779: return "SPRN_MMCR0"; break;
179 case 804: return "SPRN_EBBHR"; break;
180 case 805: return "SPRN_EBBRR"; break;
181 case 806: return "SPRN_BESCR"; break;
182 case 800: return "SPRN_BESCRS"; break;
183 case 801: return "SPRN_BESCRSU"; break;
184 case 802: return "SPRN_BESCRR"; break;
185 case 803: return "SPRN_BESCRRU"; break;
186 case 771: return "SPRN_PMC1"; break;
187 case 772: return "SPRN_PMC2"; break;
188 case 773: return "SPRN_PMC3"; break;
189 case 774: return "SPRN_PMC4"; break;
190 case 775: return "SPRN_PMC5"; break;
191 case 776: return "SPRN_PMC6"; break;
192 case 780: return "SPRN_SIAR"; break;
193 case 781: return "SPRN_SDAR"; break;
194 case 768: return "SPRN_SIER"; break;
195 }
196
197 return NULL;
198}
199
200static void trace_print_reg(struct trace_entry *e)
201{
202 u64 *p, *reg, *value;
203 char *name;
204
205 p = (u64 *)e->data;
206 reg = p++;
207 value = p;
208
209 name = trace_decode_reg(*reg);
210 if (name)
211 printf("register %-10s = 0x%016llx\n", name, *value);
212 else
213 printf("register %lld = 0x%016llx\n", *reg, *value);
214}
215
216static void trace_print_counter(struct trace_entry *e)
217{
218 u64 *value;
219
220 value = (u64 *)e->data;
221 printf("counter = %lld\n", *value);
222}
223
224static void trace_print_string(struct trace_entry *e)
225{
226 char *str;
227
228 str = (char *)e->data;
229 puts(str);
230}
231
232#define BASE_PREFIX 2
233#define PREFIX_DELTA 8
234
235static void trace_print_entry(struct trace_entry *e, int seq, int *prefix)
236{
237 switch (e->type) {
238 case TRACE_TYPE_REG:
239 trace_print_header(seq, *prefix);
240 trace_print_reg(e);
241 break;
242 case TRACE_TYPE_COUNTER:
243 trace_print_header(seq, *prefix);
244 trace_print_counter(e);
245 break;
246 case TRACE_TYPE_STRING:
247 trace_print_header(seq, *prefix);
248 trace_print_string(e);
249 break;
250 case TRACE_TYPE_INDENT:
251 trace_print_header(seq, *prefix);
252 puts("{");
253 *prefix += PREFIX_DELTA;
254 break;
255 case TRACE_TYPE_OUTDENT:
256 *prefix -= PREFIX_DELTA;
257 if (*prefix < BASE_PREFIX)
258 *prefix = BASE_PREFIX;
259 trace_print_header(seq, *prefix);
260 puts("}");
261 break;
262 default:
263 trace_print_header(seq, *prefix);
264 printf("entry @ %p type %d\n", e, e->type);
265 break;
266 }
267}
268
269void trace_buffer_print(struct trace_buffer *tb)
270{
271 struct trace_entry *e;
272 int i, prefix;
273 void *p;
274
275 printf("Trace buffer dump:\n");
276 printf(" address %p \n", tb);
277 printf(" tail %p\n", tb->tail);
278 printf(" size %llu\n", tb->size);
279 printf(" overflow %s\n", tb->overflow ? "TRUE" : "false");
280 printf(" Content:\n");
281
282 p = tb->data;
283
284 i = 0;
285 prefix = BASE_PREFIX;
286
287 while (trace_check_bounds(tb, p) && p < tb->tail) {
288 e = p;
289
290 trace_print_entry(e, i, &prefix);
291
292 i++;
293 p = (void *)e + sizeof(*e) + e->length;
294 }
295}
296
297void trace_print_location(struct trace_buffer *tb)
298{
299 printf("Trace buffer 0x%llx bytes @ %p\n", tb->size, tb);
300}
diff --git a/tools/testing/selftests/powerpc/pmu/ebb/trace.h b/tools/testing/selftests/powerpc/pmu/ebb/trace.h
new file mode 100644
index 000000000000..926458e28c8b
--- /dev/null
+++ b/tools/testing/selftests/powerpc/pmu/ebb/trace.h
@@ -0,0 +1,41 @@
1/*
2 * Copyright 2014, Michael Ellerman, IBM Corp.
3 * Licensed under GPLv2.
4 */
5
6#ifndef _SELFTESTS_POWERPC_PMU_EBB_TRACE_H
7#define _SELFTESTS_POWERPC_PMU_EBB_TRACE_H
8
9#include "utils.h"
10
11#define TRACE_TYPE_REG 1
12#define TRACE_TYPE_COUNTER 2
13#define TRACE_TYPE_STRING 3
14#define TRACE_TYPE_INDENT 4
15#define TRACE_TYPE_OUTDENT 5
16
17struct trace_entry
18{
19 u8 type;
20 u8 length;
21 u8 data[0];
22};
23
24struct trace_buffer
25{
26 u64 size;
27 bool overflow;
28 void *tail;
29 u8 data[0];
30};
31
32struct trace_buffer *trace_buffer_allocate(u64 size);
33int trace_log_reg(struct trace_buffer *tb, u64 reg, u64 value);
34int trace_log_counter(struct trace_buffer *tb, u64 value);
35int trace_log_string(struct trace_buffer *tb, char *str);
36int trace_log_indent(struct trace_buffer *tb);
37int trace_log_outdent(struct trace_buffer *tb);
38void trace_buffer_print(struct trace_buffer *tb);
39void trace_print_location(struct trace_buffer *tb);
40
41#endif /* _SELFTESTS_POWERPC_PMU_EBB_TRACE_H */
diff --git a/tools/testing/selftests/powerpc/pmu/event.c b/tools/testing/selftests/powerpc/pmu/event.c
index 2b2d11df2450..184b36807d48 100644
--- a/tools/testing/selftests/powerpc/pmu/event.c
+++ b/tools/testing/selftests/powerpc/pmu/event.c
@@ -39,7 +39,13 @@ void event_init_named(struct event *e, u64 config, char *name)
39 event_init_opts(e, config, PERF_TYPE_RAW, name); 39 event_init_opts(e, config, PERF_TYPE_RAW, name);
40} 40}
41 41
42void event_init(struct event *e, u64 config)
43{
44 event_init_opts(e, config, PERF_TYPE_RAW, "event");
45}
46
42#define PERF_CURRENT_PID 0 47#define PERF_CURRENT_PID 0
48#define PERF_NO_PID -1
43#define PERF_NO_CPU -1 49#define PERF_NO_CPU -1
44#define PERF_NO_GROUP -1 50#define PERF_NO_GROUP -1
45 51
@@ -59,6 +65,16 @@ int event_open_with_group(struct event *e, int group_fd)
59 return event_open_with_options(e, PERF_CURRENT_PID, PERF_NO_CPU, group_fd); 65 return event_open_with_options(e, PERF_CURRENT_PID, PERF_NO_CPU, group_fd);
60} 66}
61 67
68int event_open_with_pid(struct event *e, pid_t pid)
69{
70 return event_open_with_options(e, pid, PERF_NO_CPU, PERF_NO_GROUP);
71}
72
73int event_open_with_cpu(struct event *e, int cpu)
74{
75 return event_open_with_options(e, PERF_NO_PID, cpu, PERF_NO_GROUP);
76}
77
62int event_open(struct event *e) 78int event_open(struct event *e)
63{ 79{
64 return event_open_with_options(e, PERF_CURRENT_PID, PERF_NO_CPU, PERF_NO_GROUP); 80 return event_open_with_options(e, PERF_CURRENT_PID, PERF_NO_CPU, PERF_NO_GROUP);
@@ -69,6 +85,16 @@ void event_close(struct event *e)
69 close(e->fd); 85 close(e->fd);
70} 86}
71 87
88int event_enable(struct event *e)
89{
90 return ioctl(e->fd, PERF_EVENT_IOC_ENABLE);
91}
92
93int event_disable(struct event *e)
94{
95 return ioctl(e->fd, PERF_EVENT_IOC_DISABLE);
96}
97
72int event_reset(struct event *e) 98int event_reset(struct event *e)
73{ 99{
74 return ioctl(e->fd, PERF_EVENT_IOC_RESET); 100 return ioctl(e->fd, PERF_EVENT_IOC_RESET);
diff --git a/tools/testing/selftests/powerpc/pmu/event.h b/tools/testing/selftests/powerpc/pmu/event.h
index e6993192ff34..a0ea6b1eef73 100644
--- a/tools/testing/selftests/powerpc/pmu/event.h
+++ b/tools/testing/selftests/powerpc/pmu/event.h
@@ -29,8 +29,12 @@ void event_init_named(struct event *e, u64 config, char *name);
29void event_init_opts(struct event *e, u64 config, int type, char *name); 29void event_init_opts(struct event *e, u64 config, int type, char *name);
30int event_open_with_options(struct event *e, pid_t pid, int cpu, int group_fd); 30int event_open_with_options(struct event *e, pid_t pid, int cpu, int group_fd);
31int event_open_with_group(struct event *e, int group_fd); 31int event_open_with_group(struct event *e, int group_fd);
32int event_open_with_pid(struct event *e, pid_t pid);
33int event_open_with_cpu(struct event *e, int cpu);
32int event_open(struct event *e); 34int event_open(struct event *e);
33void event_close(struct event *e); 35void event_close(struct event *e);
36int event_enable(struct event *e);
37int event_disable(struct event *e);
34int event_reset(struct event *e); 38int event_reset(struct event *e);
35int event_read(struct event *e); 39int event_read(struct event *e);
36void event_report_justified(struct event *e, int name_width, int result_width); 40void event_report_justified(struct event *e, int name_width, int result_width);
diff --git a/tools/testing/selftests/powerpc/pmu/lib.c b/tools/testing/selftests/powerpc/pmu/lib.c
new file mode 100644
index 000000000000..0f6a4731d546
--- /dev/null
+++ b/tools/testing/selftests/powerpc/pmu/lib.c
@@ -0,0 +1,252 @@
1/*
2 * Copyright 2014, Michael Ellerman, IBM Corp.
3 * Licensed under GPLv2.
4 */
5
6#define _GNU_SOURCE /* For CPU_ZERO etc. */
7
8#include <errno.h>
9#include <sched.h>
10#include <setjmp.h>
11#include <stdlib.h>
12#include <sys/wait.h>
13
14#include "utils.h"
15#include "lib.h"
16
17
18int pick_online_cpu(void)
19{
20 cpu_set_t mask;
21 int cpu;
22
23 CPU_ZERO(&mask);
24
25 if (sched_getaffinity(0, sizeof(mask), &mask)) {
26 perror("sched_getaffinity");
27 return -1;
28 }
29
30 /* We prefer a primary thread, but skip 0 */
31 for (cpu = 8; cpu < CPU_SETSIZE; cpu += 8)
32 if (CPU_ISSET(cpu, &mask))
33 return cpu;
34
35 /* Search for anything, but in reverse */
36 for (cpu = CPU_SETSIZE - 1; cpu >= 0; cpu--)
37 if (CPU_ISSET(cpu, &mask))
38 return cpu;
39
40 printf("No cpus in affinity mask?!\n");
41 return -1;
42}
43
44int bind_to_cpu(int cpu)
45{
46 cpu_set_t mask;
47
48 printf("Binding to cpu %d\n", cpu);
49
50 CPU_ZERO(&mask);
51 CPU_SET(cpu, &mask);
52
53 return sched_setaffinity(0, sizeof(mask), &mask);
54}
55
56#define PARENT_TOKEN 0xAA
57#define CHILD_TOKEN 0x55
58
59int sync_with_child(union pipe read_pipe, union pipe write_pipe)
60{
61 char c = PARENT_TOKEN;
62
63 FAIL_IF(write(write_pipe.write_fd, &c, 1) != 1);
64 FAIL_IF(read(read_pipe.read_fd, &c, 1) != 1);
65 if (c != CHILD_TOKEN) /* sometimes expected */
66 return 1;
67
68 return 0;
69}
70
71int wait_for_parent(union pipe read_pipe)
72{
73 char c;
74
75 FAIL_IF(read(read_pipe.read_fd, &c, 1) != 1);
76 FAIL_IF(c != PARENT_TOKEN);
77
78 return 0;
79}
80
81int notify_parent(union pipe write_pipe)
82{
83 char c = CHILD_TOKEN;
84
85 FAIL_IF(write(write_pipe.write_fd, &c, 1) != 1);
86
87 return 0;
88}
89
90int notify_parent_of_error(union pipe write_pipe)
91{
92 char c = ~CHILD_TOKEN;
93
94 FAIL_IF(write(write_pipe.write_fd, &c, 1) != 1);
95
96 return 0;
97}
98
99int wait_for_child(pid_t child_pid)
100{
101 int rc;
102
103 if (waitpid(child_pid, &rc, 0) == -1) {
104 perror("waitpid");
105 return 1;
106 }
107
108 if (WIFEXITED(rc))
109 rc = WEXITSTATUS(rc);
110 else
111 rc = 1; /* Signal or other */
112
113 return rc;
114}
115
116int kill_child_and_wait(pid_t child_pid)
117{
118 kill(child_pid, SIGTERM);
119
120 return wait_for_child(child_pid);
121}
122
123static int eat_cpu_child(union pipe read_pipe, union pipe write_pipe)
124{
125 volatile int i = 0;
126
127 /*
128 * We are just here to eat cpu and die. So make sure we can be killed,
129 * and also don't do any custom SIGTERM handling.
130 */
131 signal(SIGTERM, SIG_DFL);
132
133 notify_parent(write_pipe);
134 wait_for_parent(read_pipe);
135
136 /* Soak up cpu forever */
137 while (1) i++;
138
139 return 0;
140}
141
142pid_t eat_cpu(int (test_function)(void))
143{
144 union pipe read_pipe, write_pipe;
145 int cpu, rc;
146 pid_t pid;
147
148 cpu = pick_online_cpu();
149 FAIL_IF(cpu < 0);
150 FAIL_IF(bind_to_cpu(cpu));
151
152 if (pipe(read_pipe.fds) == -1)
153 return -1;
154
155 if (pipe(write_pipe.fds) == -1)
156 return -1;
157
158 pid = fork();
159 if (pid == 0)
160 exit(eat_cpu_child(write_pipe, read_pipe));
161
162 if (sync_with_child(read_pipe, write_pipe)) {
163 rc = -1;
164 goto out;
165 }
166
167 printf("main test running as pid %d\n", getpid());
168
169 rc = test_function();
170out:
171 kill(pid, SIGKILL);
172
173 return rc;
174}
175
176struct addr_range libc, vdso;
177
178int parse_proc_maps(void)
179{
180 char execute, name[128];
181 uint64_t start, end;
182 FILE *f;
183 int rc;
184
185 f = fopen("/proc/self/maps", "r");
186 if (!f) {
187 perror("fopen");
188 return -1;
189 }
190
191 do {
192 /* This skips line with no executable which is what we want */
193 rc = fscanf(f, "%lx-%lx %*c%*c%c%*c %*x %*d:%*d %*d %127s\n",
194 &start, &end, &execute, name);
195 if (rc <= 0)
196 break;
197
198 if (execute != 'x')
199 continue;
200
201 if (strstr(name, "libc")) {
202 libc.first = start;
203 libc.last = end - 1;
204 } else if (strstr(name, "[vdso]")) {
205 vdso.first = start;
206 vdso.last = end - 1;
207 }
208 } while(1);
209
210 fclose(f);
211
212 return 0;
213}
214
215#define PARANOID_PATH "/proc/sys/kernel/perf_event_paranoid"
216
217bool require_paranoia_below(int level)
218{
219 unsigned long current;
220 char *end, buf[16];
221 FILE *f;
222 int rc;
223
224 rc = -1;
225
226 f = fopen(PARANOID_PATH, "r");
227 if (!f) {
228 perror("fopen");
229 goto out;
230 }
231
232 if (!fgets(buf, sizeof(buf), f)) {
233 printf("Couldn't read " PARANOID_PATH "?\n");
234 goto out_close;
235 }
236
237 current = strtoul(buf, &end, 10);
238
239 if (end == buf) {
240 printf("Couldn't parse " PARANOID_PATH "?\n");
241 goto out_close;
242 }
243
244 if (current >= level)
245 goto out;
246
247 rc = 0;
248out_close:
249 fclose(f);
250out:
251 return rc;
252}
diff --git a/tools/testing/selftests/powerpc/pmu/lib.h b/tools/testing/selftests/powerpc/pmu/lib.h
new file mode 100644
index 000000000000..ca5d72ae3be6
--- /dev/null
+++ b/tools/testing/selftests/powerpc/pmu/lib.h
@@ -0,0 +1,41 @@
1/*
2 * Copyright 2014, Michael Ellerman, IBM Corp.
3 * Licensed under GPLv2.
4 */
5
6#ifndef __SELFTESTS_POWERPC_PMU_LIB_H
7#define __SELFTESTS_POWERPC_PMU_LIB_H
8
9#include <stdio.h>
10#include <stdint.h>
11#include <string.h>
12#include <unistd.h>
13
14union pipe {
15 struct {
16 int read_fd;
17 int write_fd;
18 };
19 int fds[2];
20};
21
22extern int pick_online_cpu(void);
23extern int bind_to_cpu(int cpu);
24extern int kill_child_and_wait(pid_t child_pid);
25extern int wait_for_child(pid_t child_pid);
26extern int sync_with_child(union pipe read_pipe, union pipe write_pipe);
27extern int wait_for_parent(union pipe read_pipe);
28extern int notify_parent(union pipe write_pipe);
29extern int notify_parent_of_error(union pipe write_pipe);
30extern pid_t eat_cpu(int (test_function)(void));
31extern bool require_paranoia_below(int level);
32
33struct addr_range {
34 uint64_t first, last;
35};
36
37extern struct addr_range libc, vdso;
38
39int parse_proc_maps(void);
40
41#endif /* __SELFTESTS_POWERPC_PMU_LIB_H */
diff --git a/tools/testing/selftests/powerpc/pmu/loop.S b/tools/testing/selftests/powerpc/pmu/loop.S
index 8820e3df1444..20c1f0876c47 100644
--- a/tools/testing/selftests/powerpc/pmu/loop.S
+++ b/tools/testing/selftests/powerpc/pmu/loop.S
@@ -3,44 +3,41 @@
3 * Licensed under GPLv2. 3 * Licensed under GPLv2.
4 */ 4 */
5 5
6#include <ppc-asm.h>
7
6 .text 8 .text
7 9
8 .global thirty_two_instruction_loop 10FUNC_START(thirty_two_instruction_loop)
9 .type .thirty_two_instruction_loop,@function 11 cmpdi r3,0
10 .section ".opd","aw",@progbits
11thirty_two_instruction_loop:
12 .quad .thirty_two_instruction_loop, .TOC.@tocbase, 0
13 .previous
14.thirty_two_instruction_loop:
15 cmpwi %r3,0
16 beqlr 12 beqlr
17 addi %r4,%r3,1 13 addi r4,r3,1
18 addi %r4,%r4,1 14 addi r4,r4,1
19 addi %r4,%r4,1 15 addi r4,r4,1
20 addi %r4,%r4,1 16 addi r4,r4,1
21 addi %r4,%r4,1 17 addi r4,r4,1
22 addi %r4,%r4,1 18 addi r4,r4,1
23 addi %r4,%r4,1 19 addi r4,r4,1
24 addi %r4,%r4,1 20 addi r4,r4,1
25 addi %r4,%r4,1 21 addi r4,r4,1
26 addi %r4,%r4,1 22 addi r4,r4,1
27 addi %r4,%r4,1 23 addi r4,r4,1
28 addi %r4,%r4,1 24 addi r4,r4,1
29 addi %r4,%r4,1 25 addi r4,r4,1
30 addi %r4,%r4,1 26 addi r4,r4,1
31 addi %r4,%r4,1 27 addi r4,r4,1
32 addi %r4,%r4,1 28 addi r4,r4,1
33 addi %r4,%r4,1 29 addi r4,r4,1
34 addi %r4,%r4,1 30 addi r4,r4,1
35 addi %r4,%r4,1 31 addi r4,r4,1
36 addi %r4,%r4,1 32 addi r4,r4,1
37 addi %r4,%r4,1 33 addi r4,r4,1
38 addi %r4,%r4,1 34 addi r4,r4,1
39 addi %r4,%r4,1 35 addi r4,r4,1
40 addi %r4,%r4,1 36 addi r4,r4,1
41 addi %r4,%r4,1 37 addi r4,r4,1
42 addi %r4,%r4,1 38 addi r4,r4,1
43 addi %r4,%r4,1 39 addi r4,r4,1
44 addi %r4,%r4,1 # 28 addi's 40 addi r4,r4,1 # 28 addi's
45 subi %r3,%r3,1 41 subi r3,r3,1
46 b .thirty_two_instruction_loop 42 b FUNC_NAME(thirty_two_instruction_loop)
43FUNC_END(thirty_two_instruction_loop)
diff --git a/tools/testing/selftests/powerpc/subunit.h b/tools/testing/selftests/powerpc/subunit.h
index 98a22920792d..9c6c4e901ab6 100644
--- a/tools/testing/selftests/powerpc/subunit.h
+++ b/tools/testing/selftests/powerpc/subunit.h
@@ -26,6 +26,11 @@ static inline void test_error(char *name)
26 printf("error: %s\n", name); 26 printf("error: %s\n", name);
27} 27}
28 28
29static inline void test_skip(char *name)
30{
31 printf("skip: %s\n", name);
32}
33
29static inline void test_success(char *name) 34static inline void test_success(char *name)
30{ 35{
31 printf("success: %s\n", name); 36 printf("success: %s\n", name);
diff --git a/tools/testing/selftests/powerpc/tm/Makefile b/tools/testing/selftests/powerpc/tm/Makefile
new file mode 100644
index 000000000000..51267f4184a6
--- /dev/null
+++ b/tools/testing/selftests/powerpc/tm/Makefile
@@ -0,0 +1,15 @@
1PROGS := tm-resched-dscr
2
3all: $(PROGS)
4
5$(PROGS):
6
7run_tests: all
8 @-for PROG in $(PROGS); do \
9 ./$$PROG; \
10 done;
11
12clean:
13 rm -f $(PROGS) *.o
14
15.PHONY: all run_tests clean
diff --git a/tools/testing/selftests/powerpc/tm/tm-resched-dscr.c b/tools/testing/selftests/powerpc/tm/tm-resched-dscr.c
new file mode 100644
index 000000000000..ee98e3886af2
--- /dev/null
+++ b/tools/testing/selftests/powerpc/tm/tm-resched-dscr.c
@@ -0,0 +1,90 @@
1/* Test context switching to see if the DSCR SPR is correctly preserved
2 * when within a transaction.
3 *
4 * Note: We assume that the DSCR has been left at the default value (0)
5 * for all CPUs.
6 *
7 * Method:
8 *
9 * Set a value into the DSCR.
10 *
11 * Start a transaction, and suspend it (*).
12 *
13 * Hard loop checking to see if the transaction has become doomed.
14 *
15 * Now that we *may* have been preempted, record the DSCR and TEXASR SPRS.
16 *
17 * If the abort was because of a context switch, check the DSCR value.
18 * Otherwise, try again.
19 *
20 * (*) If the transaction is not suspended we can't see the problem because
21 * the transaction abort handler will restore the DSCR to it's checkpointed
22 * value before we regain control.
23 */
24
25#include <inttypes.h>
26#include <stdio.h>
27#include <stdlib.h>
28#include <assert.h>
29#include <asm/tm.h>
30
31#define TBEGIN ".long 0x7C00051D ;"
32#define TEND ".long 0x7C00055D ;"
33#define TCHECK ".long 0x7C00059C ;"
34#define TSUSPEND ".long 0x7C0005DD ;"
35#define TRESUME ".long 0x7C2005DD ;"
36#define SPRN_TEXASR 0x82
37#define SPRN_DSCR 0x03
38
39int main(void) {
40 uint64_t rv, dscr1 = 1, dscr2, texasr;
41
42 printf("Check DSCR TM context switch: ");
43 fflush(stdout);
44 for (;;) {
45 rv = 1;
46 asm __volatile__ (
47 /* set a known value into the DSCR */
48 "ld 3, %[dscr1];"
49 "mtspr %[sprn_dscr], 3;"
50
51 /* start and suspend a transaction */
52 TBEGIN
53 "beq 1f;"
54 TSUSPEND
55
56 /* hard loop until the transaction becomes doomed */
57 "2: ;"
58 TCHECK
59 "bc 4, 0, 2b;"
60
61 /* record DSCR and TEXASR */
62 "mfspr 3, %[sprn_dscr];"
63 "std 3, %[dscr2];"
64 "mfspr 3, %[sprn_texasr];"
65 "std 3, %[texasr];"
66
67 TRESUME
68 TEND
69 "li %[rv], 0;"
70 "1: ;"
71 : [rv]"=r"(rv), [dscr2]"=m"(dscr2), [texasr]"=m"(texasr)
72 : [dscr1]"m"(dscr1)
73 , [sprn_dscr]"i"(SPRN_DSCR), [sprn_texasr]"i"(SPRN_TEXASR)
74 : "memory", "r3"
75 );
76 assert(rv); /* make sure the transaction aborted */
77 if ((texasr >> 56) != TM_CAUSE_RESCHED) {
78 putchar('.');
79 fflush(stdout);
80 continue;
81 }
82 if (dscr2 != dscr1) {
83 printf(" FAIL\n");
84 exit(EXIT_FAILURE);
85 } else {
86 printf(" OK\n");
87 exit(EXIT_SUCCESS);
88 }
89 }
90}
diff --git a/tools/testing/selftests/powerpc/utils.h b/tools/testing/selftests/powerpc/utils.h
index 0de064406dab..a93777ae0684 100644
--- a/tools/testing/selftests/powerpc/utils.h
+++ b/tools/testing/selftests/powerpc/utils.h
@@ -31,6 +31,18 @@ do { \
31 } \ 31 } \
32} while (0) 32} while (0)
33 33
34/* The test harness uses this, yes it's gross */
35#define MAGIC_SKIP_RETURN_VALUE 99
36
37#define SKIP_IF(x) \
38do { \
39 if ((x)) { \
40 fprintf(stderr, \
41 "[SKIP] Test skipped on line %d\n", __LINE__); \
42 return MAGIC_SKIP_RETURN_VALUE; \
43 } \
44} while (0)
45
34#define _str(s) #s 46#define _str(s) #s
35#define str(s) _str(s) 47#define str(s) _str(s)
36 48