aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf/builtin-stat.c
diff options
context:
space:
mode:
authorArnaldo Carvalho de Melo <acme@redhat.com>2011-01-03 13:39:04 -0500
committerArnaldo Carvalho de Melo <acme@redhat.com>2011-01-03 13:39:04 -0500
commit69aad6f1ee69546dea8535ab8f3da9f445d57328 (patch)
treeb328ec140a6a90703a049fcc661d623025d7e81f /tools/perf/builtin-stat.c
parent56f4c400349157289b474a3fd49ee96acab0a4d7 (diff)
perf tools: Introduce event selectors
Out of ad-hoc code and global arrays with hard coded sizes. This is the first step on having a library that will be first used on regression tests in the 'perf test' tool. [acme@felicio linux]$ size /tmp/perf.before text data bss dec hex filename 1273776 97384 5104416 6475576 62cf38 /tmp/perf.before [acme@felicio linux]$ size /tmp/perf.new text data bss dec hex filename 1275422 97416 1392416 2765254 2a31c6 /tmp/perf.new Cc: Frederic Weisbecker <fweisbec@gmail.com> Cc: Ingo Molnar <mingo@elte.hu> Cc: Mike Galbraith <efault@gmx.de> Cc: Paul Mackerras <paulus@samba.org> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Stephane Eranian <eranian@google.com> Cc: Tom Zanussi <tzanussi@gmail.com> LKML-Reference: <new-submission> Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Diffstat (limited to 'tools/perf/builtin-stat.c')
-rw-r--r--tools/perf/builtin-stat.c175
1 files changed, 107 insertions, 68 deletions
diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c
index 7ff746da7e6c..511ebaff9a66 100644
--- a/tools/perf/builtin-stat.c
+++ b/tools/perf/builtin-stat.c
@@ -43,6 +43,7 @@
43#include "util/parse-options.h" 43#include "util/parse-options.h"
44#include "util/parse-events.h" 44#include "util/parse-events.h"
45#include "util/event.h" 45#include "util/event.h"
46#include "util/evsel.h"
46#include "util/debug.h" 47#include "util/debug.h"
47#include "util/header.h" 48#include "util/header.h"
48#include "util/cpumap.h" 49#include "util/cpumap.h"
@@ -52,6 +53,8 @@
52#include <math.h> 53#include <math.h>
53#include <locale.h> 54#include <locale.h>
54 55
56#define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y))
57
55#define DEFAULT_SEPARATOR " " 58#define DEFAULT_SEPARATOR " "
56 59
57static struct perf_event_attr default_attrs[] = { 60static struct perf_event_attr default_attrs[] = {
@@ -90,16 +93,11 @@ static const char *cpu_list;
90static const char *csv_sep = NULL; 93static const char *csv_sep = NULL;
91static bool csv_output = false; 94static bool csv_output = false;
92 95
93 96struct cpu_counts {
94static int *fd[MAX_NR_CPUS][MAX_COUNTERS];
95
96static int event_scaled[MAX_COUNTERS];
97
98static struct {
99 u64 val; 97 u64 val;
100 u64 ena; 98 u64 ena;
101 u64 run; 99 u64 run;
102} cpu_counts[MAX_NR_CPUS][MAX_COUNTERS]; 100};
103 101
104static volatile int done = 0; 102static volatile int done = 0;
105 103
@@ -108,6 +106,26 @@ struct stats
108 double n, mean, M2; 106 double n, mean, M2;
109}; 107};
110 108
109struct perf_stat {
110 struct stats res_stats[3];
111 int scaled;
112 struct cpu_counts cpu_counts[];
113};
114
115static int perf_evsel__alloc_stat_priv(struct perf_evsel *evsel, int ncpus)
116{
117 size_t priv_size = (sizeof(struct perf_stat) +
118 (ncpus * sizeof(struct cpu_counts)));
119 evsel->priv = zalloc(priv_size);
120 return evsel->priv == NULL ? -ENOMEM : 0;
121}
122
123static void perf_evsel__free_stat_priv(struct perf_evsel *evsel)
124{
125 free(evsel->priv);
126 evsel->priv = NULL;
127}
128
111static void update_stats(struct stats *stats, u64 val) 129static void update_stats(struct stats *stats, u64 val)
112{ 130{
113 double delta; 131 double delta;
@@ -147,22 +165,21 @@ static double stddev_stats(struct stats *stats)
147 return sqrt(variance_mean); 165 return sqrt(variance_mean);
148} 166}
149 167
150struct stats event_res_stats[MAX_COUNTERS][3];
151struct stats runtime_nsecs_stats[MAX_NR_CPUS]; 168struct stats runtime_nsecs_stats[MAX_NR_CPUS];
152struct stats runtime_cycles_stats[MAX_NR_CPUS]; 169struct stats runtime_cycles_stats[MAX_NR_CPUS];
153struct stats runtime_branches_stats[MAX_NR_CPUS]; 170struct stats runtime_branches_stats[MAX_NR_CPUS];
154struct stats walltime_nsecs_stats; 171struct stats walltime_nsecs_stats;
155 172
156#define MATCH_EVENT(t, c, counter) \ 173#define MATCH_EVENT(t, c, evsel) \
157 (attrs[counter].type == PERF_TYPE_##t && \ 174 (evsel->attr.type == PERF_TYPE_##t && \
158 attrs[counter].config == PERF_COUNT_##c) 175 evsel->attr.config == PERF_COUNT_##c)
159 176
160#define ERR_PERF_OPEN \ 177#define ERR_PERF_OPEN \
161"counter %d, sys_perf_event_open() syscall returned with %d (%s). /bin/dmesg may provide additional information." 178"counter %d, sys_perf_event_open() syscall returned with %d (%s). /bin/dmesg may provide additional information."
162 179
163static int create_perf_stat_counter(int counter, bool *perm_err) 180static int create_perf_stat_counter(struct perf_evsel *evsel, bool *perm_err)
164{ 181{
165 struct perf_event_attr *attr = attrs + counter; 182 struct perf_event_attr *attr = &evsel->attr;
166 int thread; 183 int thread;
167 int ncreated = 0; 184 int ncreated = 0;
168 185
@@ -174,13 +191,13 @@ static int create_perf_stat_counter(int counter, bool *perm_err)
174 int cpu; 191 int cpu;
175 192
176 for (cpu = 0; cpu < nr_cpus; cpu++) { 193 for (cpu = 0; cpu < nr_cpus; cpu++) {
177 fd[cpu][counter][0] = sys_perf_event_open(attr, 194 FD(evsel, cpu, 0) = sys_perf_event_open(attr,
178 -1, cpumap[cpu], -1, 0); 195 -1, cpumap[cpu], -1, 0);
179 if (fd[cpu][counter][0] < 0) { 196 if (FD(evsel, cpu, 0) < 0) {
180 if (errno == EPERM || errno == EACCES) 197 if (errno == EPERM || errno == EACCES)
181 *perm_err = true; 198 *perm_err = true;
182 error(ERR_PERF_OPEN, counter, 199 error(ERR_PERF_OPEN, evsel->idx,
183 fd[cpu][counter][0], strerror(errno)); 200 FD(evsel, cpu, 0), strerror(errno));
184 } else { 201 } else {
185 ++ncreated; 202 ++ncreated;
186 } 203 }
@@ -192,13 +209,13 @@ static int create_perf_stat_counter(int counter, bool *perm_err)
192 attr->enable_on_exec = 1; 209 attr->enable_on_exec = 1;
193 } 210 }
194 for (thread = 0; thread < thread_num; thread++) { 211 for (thread = 0; thread < thread_num; thread++) {
195 fd[0][counter][thread] = sys_perf_event_open(attr, 212 FD(evsel, 0, thread) = sys_perf_event_open(attr,
196 all_tids[thread], -1, -1, 0); 213 all_tids[thread], -1, -1, 0);
197 if (fd[0][counter][thread] < 0) { 214 if (FD(evsel, 0, thread) < 0) {
198 if (errno == EPERM || errno == EACCES) 215 if (errno == EPERM || errno == EACCES)
199 *perm_err = true; 216 *perm_err = true;
200 error(ERR_PERF_OPEN, counter, 217 error(ERR_PERF_OPEN, evsel->idx,
201 fd[0][counter][thread], 218 FD(evsel, 0, thread),
202 strerror(errno)); 219 strerror(errno));
203 } else { 220 } else {
204 ++ncreated; 221 ++ncreated;
@@ -212,7 +229,7 @@ static int create_perf_stat_counter(int counter, bool *perm_err)
212/* 229/*
213 * Does the counter have nsecs as a unit? 230 * Does the counter have nsecs as a unit?
214 */ 231 */
215static inline int nsec_counter(int counter) 232static inline int nsec_counter(struct perf_evsel *counter)
216{ 233{
217 if (MATCH_EVENT(SOFTWARE, SW_CPU_CLOCK, counter) || 234 if (MATCH_EVENT(SOFTWARE, SW_CPU_CLOCK, counter) ||
218 MATCH_EVENT(SOFTWARE, SW_TASK_CLOCK, counter)) 235 MATCH_EVENT(SOFTWARE, SW_TASK_CLOCK, counter))
@@ -225,8 +242,9 @@ static inline int nsec_counter(int counter)
225 * Read out the results of a single counter: 242 * Read out the results of a single counter:
226 * aggregate counts across CPUs in system-wide mode 243 * aggregate counts across CPUs in system-wide mode
227 */ 244 */
228static void read_counter_aggr(int counter) 245static void read_counter_aggr(struct perf_evsel *counter)
229{ 246{
247 struct perf_stat *ps = counter->priv;
230 u64 count[3], single_count[3]; 248 u64 count[3], single_count[3];
231 int cpu; 249 int cpu;
232 size_t res, nv; 250 size_t res, nv;
@@ -238,15 +256,15 @@ static void read_counter_aggr(int counter)
238 nv = scale ? 3 : 1; 256 nv = scale ? 3 : 1;
239 for (cpu = 0; cpu < nr_cpus; cpu++) { 257 for (cpu = 0; cpu < nr_cpus; cpu++) {
240 for (thread = 0; thread < thread_num; thread++) { 258 for (thread = 0; thread < thread_num; thread++) {
241 if (fd[cpu][counter][thread] < 0) 259 if (FD(counter, cpu, thread) < 0)
242 continue; 260 continue;
243 261
244 res = read(fd[cpu][counter][thread], 262 res = read(FD(counter, cpu, thread),
245 single_count, nv * sizeof(u64)); 263 single_count, nv * sizeof(u64));
246 assert(res == nv * sizeof(u64)); 264 assert(res == nv * sizeof(u64));
247 265
248 close(fd[cpu][counter][thread]); 266 close(FD(counter, cpu, thread));
249 fd[cpu][counter][thread] = -1; 267 FD(counter, cpu, thread) = -1;
250 268
251 count[0] += single_count[0]; 269 count[0] += single_count[0];
252 if (scale) { 270 if (scale) {
@@ -259,20 +277,20 @@ static void read_counter_aggr(int counter)
259 scaled = 0; 277 scaled = 0;
260 if (scale) { 278 if (scale) {
261 if (count[2] == 0) { 279 if (count[2] == 0) {
262 event_scaled[counter] = -1; 280 ps->scaled = -1;
263 count[0] = 0; 281 count[0] = 0;
264 return; 282 return;
265 } 283 }
266 284
267 if (count[2] < count[1]) { 285 if (count[2] < count[1]) {
268 event_scaled[counter] = 1; 286 ps->scaled = 1;
269 count[0] = (unsigned long long) 287 count[0] = (unsigned long long)
270 ((double)count[0] * count[1] / count[2] + 0.5); 288 ((double)count[0] * count[1] / count[2] + 0.5);
271 } 289 }
272 } 290 }
273 291
274 for (i = 0; i < 3; i++) 292 for (i = 0; i < 3; i++)
275 update_stats(&event_res_stats[counter][i], count[i]); 293 update_stats(&ps->res_stats[i], count[i]);
276 294
277 if (verbose) { 295 if (verbose) {
278 fprintf(stderr, "%s: %Ld %Ld %Ld\n", event_name(counter), 296 fprintf(stderr, "%s: %Ld %Ld %Ld\n", event_name(counter),
@@ -294,8 +312,9 @@ static void read_counter_aggr(int counter)
294 * Read out the results of a single counter: 312 * Read out the results of a single counter:
295 * do not aggregate counts across CPUs in system-wide mode 313 * do not aggregate counts across CPUs in system-wide mode
296 */ 314 */
297static void read_counter(int counter) 315static void read_counter(struct perf_evsel *counter)
298{ 316{
317 struct cpu_counts *cpu_counts = counter->priv;
299 u64 count[3]; 318 u64 count[3];
300 int cpu; 319 int cpu;
301 size_t res, nv; 320 size_t res, nv;
@@ -306,15 +325,15 @@ static void read_counter(int counter)
306 325
307 for (cpu = 0; cpu < nr_cpus; cpu++) { 326 for (cpu = 0; cpu < nr_cpus; cpu++) {
308 327
309 if (fd[cpu][counter][0] < 0) 328 if (FD(counter, cpu, 0) < 0)
310 continue; 329 continue;
311 330
312 res = read(fd[cpu][counter][0], count, nv * sizeof(u64)); 331 res = read(FD(counter, cpu, 0), count, nv * sizeof(u64));
313 332
314 assert(res == nv * sizeof(u64)); 333 assert(res == nv * sizeof(u64));
315 334
316 close(fd[cpu][counter][0]); 335 close(FD(counter, cpu, 0));
317 fd[cpu][counter][0] = -1; 336 FD(counter, cpu, 0) = -1;
318 337
319 if (scale) { 338 if (scale) {
320 if (count[2] == 0) { 339 if (count[2] == 0) {
@@ -324,9 +343,9 @@ static void read_counter(int counter)
324 ((double)count[0] * count[1] / count[2] + 0.5); 343 ((double)count[0] * count[1] / count[2] + 0.5);
325 } 344 }
326 } 345 }
327 cpu_counts[cpu][counter].val = count[0]; /* scaled count */ 346 cpu_counts[cpu].val = count[0]; /* scaled count */
328 cpu_counts[cpu][counter].ena = count[1]; 347 cpu_counts[cpu].ena = count[1];
329 cpu_counts[cpu][counter].run = count[2]; 348 cpu_counts[cpu].run = count[2];
330 349
331 if (MATCH_EVENT(SOFTWARE, SW_TASK_CLOCK, counter)) 350 if (MATCH_EVENT(SOFTWARE, SW_TASK_CLOCK, counter))
332 update_stats(&runtime_nsecs_stats[cpu], count[0]); 351 update_stats(&runtime_nsecs_stats[cpu], count[0]);
@@ -340,8 +359,9 @@ static void read_counter(int counter)
340static int run_perf_stat(int argc __used, const char **argv) 359static int run_perf_stat(int argc __used, const char **argv)
341{ 360{
342 unsigned long long t0, t1; 361 unsigned long long t0, t1;
362 struct perf_evsel *counter;
343 int status = 0; 363 int status = 0;
344 int counter, ncreated = 0; 364 int ncreated = 0;
345 int child_ready_pipe[2], go_pipe[2]; 365 int child_ready_pipe[2], go_pipe[2];
346 bool perm_err = false; 366 bool perm_err = false;
347 const bool forks = (argc > 0); 367 const bool forks = (argc > 0);
@@ -401,7 +421,7 @@ static int run_perf_stat(int argc __used, const char **argv)
401 close(child_ready_pipe[0]); 421 close(child_ready_pipe[0]);
402 } 422 }
403 423
404 for (counter = 0; counter < nr_counters; counter++) 424 list_for_each_entry(counter, &evsel_list, node)
405 ncreated += create_perf_stat_counter(counter, &perm_err); 425 ncreated += create_perf_stat_counter(counter, &perm_err);
406 426
407 if (ncreated < nr_counters) { 427 if (ncreated < nr_counters) {
@@ -433,25 +453,28 @@ static int run_perf_stat(int argc __used, const char **argv)
433 update_stats(&walltime_nsecs_stats, t1 - t0); 453 update_stats(&walltime_nsecs_stats, t1 - t0);
434 454
435 if (no_aggr) { 455 if (no_aggr) {
436 for (counter = 0; counter < nr_counters; counter++) 456 list_for_each_entry(counter, &evsel_list, node)
437 read_counter(counter); 457 read_counter(counter);
438 } else { 458 } else {
439 for (counter = 0; counter < nr_counters; counter++) 459 list_for_each_entry(counter, &evsel_list, node)
440 read_counter_aggr(counter); 460 read_counter_aggr(counter);
441 } 461 }
442 return WEXITSTATUS(status); 462 return WEXITSTATUS(status);
443} 463}
444 464
445static void print_noise(int counter, double avg) 465static void print_noise(struct perf_evsel *evsel, double avg)
446{ 466{
467 struct perf_stat *ps;
468
447 if (run_count == 1) 469 if (run_count == 1)
448 return; 470 return;
449 471
472 ps = evsel->priv;
450 fprintf(stderr, " ( +- %7.3f%% )", 473 fprintf(stderr, " ( +- %7.3f%% )",
451 100 * stddev_stats(&event_res_stats[counter][0]) / avg); 474 100 * stddev_stats(&ps->res_stats[0]) / avg);
452} 475}
453 476
454static void nsec_printout(int cpu, int counter, double avg) 477static void nsec_printout(int cpu, struct perf_evsel *counter, double avg)
455{ 478{
456 double msecs = avg / 1e6; 479 double msecs = avg / 1e6;
457 char cpustr[16] = { '\0', }; 480 char cpustr[16] = { '\0', };
@@ -473,7 +496,7 @@ static void nsec_printout(int cpu, int counter, double avg)
473 } 496 }
474} 497}
475 498
476static void abs_printout(int cpu, int counter, double avg) 499static void abs_printout(int cpu, struct perf_evsel *counter, double avg)
477{ 500{
478 double total, ratio = 0.0; 501 double total, ratio = 0.0;
479 char cpustr[16] = { '\0', }; 502 char cpustr[16] = { '\0', };
@@ -528,10 +551,11 @@ static void abs_printout(int cpu, int counter, double avg)
528 * Print out the results of a single counter: 551 * Print out the results of a single counter:
529 * aggregated counts in system-wide mode 552 * aggregated counts in system-wide mode
530 */ 553 */
531static void print_counter_aggr(int counter) 554static void print_counter_aggr(struct perf_evsel *counter)
532{ 555{
533 double avg = avg_stats(&event_res_stats[counter][0]); 556 struct perf_stat *ps = counter->priv;
534 int scaled = event_scaled[counter]; 557 double avg = avg_stats(&ps->res_stats[0]);
558 int scaled = ps->scaled;
535 559
536 if (scaled == -1) { 560 if (scaled == -1) {
537 fprintf(stderr, "%*s%s%-24s\n", 561 fprintf(stderr, "%*s%s%-24s\n",
@@ -555,8 +579,8 @@ static void print_counter_aggr(int counter)
555 if (scaled) { 579 if (scaled) {
556 double avg_enabled, avg_running; 580 double avg_enabled, avg_running;
557 581
558 avg_enabled = avg_stats(&event_res_stats[counter][1]); 582 avg_enabled = avg_stats(&ps->res_stats[1]);
559 avg_running = avg_stats(&event_res_stats[counter][2]); 583 avg_running = avg_stats(&ps->res_stats[2]);
560 584
561 fprintf(stderr, " (scaled from %.2f%%)", 585 fprintf(stderr, " (scaled from %.2f%%)",
562 100 * avg_running / avg_enabled); 586 100 * avg_running / avg_enabled);
@@ -569,15 +593,16 @@ static void print_counter_aggr(int counter)
569 * Print out the results of a single counter: 593 * Print out the results of a single counter:
570 * does not use aggregated count in system-wide 594 * does not use aggregated count in system-wide
571 */ 595 */
572static void print_counter(int counter) 596static void print_counter(struct perf_evsel *counter)
573{ 597{
598 struct perf_stat *ps = counter->priv;
574 u64 ena, run, val; 599 u64 ena, run, val;
575 int cpu; 600 int cpu;
576 601
577 for (cpu = 0; cpu < nr_cpus; cpu++) { 602 for (cpu = 0; cpu < nr_cpus; cpu++) {
578 val = cpu_counts[cpu][counter].val; 603 val = ps->cpu_counts[cpu].val;
579 ena = cpu_counts[cpu][counter].ena; 604 ena = ps->cpu_counts[cpu].ena;
580 run = cpu_counts[cpu][counter].run; 605 run = ps->cpu_counts[cpu].run;
581 if (run == 0 || ena == 0) { 606 if (run == 0 || ena == 0) {
582 fprintf(stderr, "CPU%*d%s%*s%s%-24s", 607 fprintf(stderr, "CPU%*d%s%*s%s%-24s",
583 csv_output ? 0 : -4, 608 csv_output ? 0 : -4,
@@ -609,7 +634,8 @@ static void print_counter(int counter)
609 634
610static void print_stat(int argc, const char **argv) 635static void print_stat(int argc, const char **argv)
611{ 636{
612 int i, counter; 637 struct perf_evsel *counter;
638 int i;
613 639
614 fflush(stdout); 640 fflush(stdout);
615 641
@@ -632,10 +658,10 @@ static void print_stat(int argc, const char **argv)
632 } 658 }
633 659
634 if (no_aggr) { 660 if (no_aggr) {
635 for (counter = 0; counter < nr_counters; counter++) 661 list_for_each_entry(counter, &evsel_list, node)
636 print_counter(counter); 662 print_counter(counter);
637 } else { 663 } else {
638 for (counter = 0; counter < nr_counters; counter++) 664 list_for_each_entry(counter, &evsel_list, node)
639 print_counter_aggr(counter); 665 print_counter_aggr(counter);
640 } 666 }
641 667
@@ -720,8 +746,8 @@ static const struct option options[] = {
720 746
721int cmd_stat(int argc, const char **argv, const char *prefix __used) 747int cmd_stat(int argc, const char **argv, const char *prefix __used)
722{ 748{
723 int status; 749 struct perf_evsel *pos;
724 int i,j; 750 int status = -ENOMEM;
725 751
726 setlocale(LC_ALL, ""); 752 setlocale(LC_ALL, "");
727 753
@@ -757,8 +783,18 @@ int cmd_stat(int argc, const char **argv, const char *prefix __used)
757 783
758 /* Set attrs and nr_counters if no event is selected and !null_run */ 784 /* Set attrs and nr_counters if no event is selected and !null_run */
759 if (!null_run && !nr_counters) { 785 if (!null_run && !nr_counters) {
760 memcpy(attrs, default_attrs, sizeof(default_attrs)); 786 size_t c;
787
761 nr_counters = ARRAY_SIZE(default_attrs); 788 nr_counters = ARRAY_SIZE(default_attrs);
789
790 for (c = 0; c < ARRAY_SIZE(default_attrs); ++c) {
791 pos = perf_evsel__new(default_attrs[c].type,
792 default_attrs[c].config,
793 nr_counters);
794 if (pos == NULL)
795 goto out;
796 list_add(&pos->node, &evsel_list);
797 }
762 } 798 }
763 799
764 if (system_wide) 800 if (system_wide)
@@ -786,12 +822,10 @@ int cmd_stat(int argc, const char **argv, const char *prefix __used)
786 thread_num = 1; 822 thread_num = 1;
787 } 823 }
788 824
789 for (i = 0; i < MAX_NR_CPUS; i++) { 825 list_for_each_entry(pos, &evsel_list, node) {
790 for (j = 0; j < MAX_COUNTERS; j++) { 826 if (perf_evsel__alloc_stat_priv(pos, nr_cpus) < 0 ||
791 fd[i][j] = malloc(sizeof(int)*thread_num); 827 perf_evsel__alloc_fd(pos, nr_cpus, thread_num) < 0)
792 if (!fd[i][j]) 828 goto out_free_fd;
793 return -ENOMEM;
794 }
795 } 829 }
796 830
797 /* 831 /*
@@ -814,6 +848,11 @@ int cmd_stat(int argc, const char **argv, const char *prefix __used)
814 848
815 if (status != -1) 849 if (status != -1)
816 print_stat(argc, argv); 850 print_stat(argc, argv);
817 851out_free_fd:
852 list_for_each_entry(pos, &evsel_list, node) {
853 perf_evsel__free_fd(pos);
854 perf_evsel__free_stat_priv(pos);
855 }
856out:
818 return status; 857 return status;
819} 858}