aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf/builtin-stat.c
diff options
context:
space:
mode:
Diffstat (limited to 'tools/perf/builtin-stat.c')
-rw-r--r--tools/perf/builtin-stat.c118
1 files changed, 73 insertions, 45 deletions
diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c
index a482a191a0c..21c02522249 100644
--- a/tools/perf/builtin-stat.c
+++ b/tools/perf/builtin-stat.c
@@ -43,11 +43,13 @@
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/evlist.h"
46#include "util/evsel.h" 47#include "util/evsel.h"
47#include "util/debug.h" 48#include "util/debug.h"
48#include "util/header.h" 49#include "util/header.h"
49#include "util/cpumap.h" 50#include "util/cpumap.h"
50#include "util/thread.h" 51#include "util/thread.h"
52#include "util/thread_map.h"
51 53
52#include <sys/prctl.h> 54#include <sys/prctl.h>
53#include <math.h> 55#include <math.h>
@@ -71,8 +73,9 @@ static struct perf_event_attr default_attrs[] = {
71 73
72}; 74};
73 75
76struct perf_evlist *evsel_list;
77
74static bool system_wide = false; 78static bool system_wide = false;
75static struct cpu_map *cpus;
76static int run_idx = 0; 79static int run_idx = 0;
77 80
78static int run_count = 1; 81static int run_count = 1;
@@ -81,7 +84,6 @@ static bool scale = true;
81static bool no_aggr = false; 84static bool no_aggr = false;
82static pid_t target_pid = -1; 85static pid_t target_pid = -1;
83static pid_t target_tid = -1; 86static pid_t target_tid = -1;
84static struct thread_map *threads;
85static pid_t child_pid = -1; 87static pid_t child_pid = -1;
86static bool null_run = false; 88static bool null_run = false;
87static bool big_num = true; 89static bool big_num = true;
@@ -166,7 +168,7 @@ static int create_perf_stat_counter(struct perf_evsel *evsel)
166 PERF_FORMAT_TOTAL_TIME_RUNNING; 168 PERF_FORMAT_TOTAL_TIME_RUNNING;
167 169
168 if (system_wide) 170 if (system_wide)
169 return perf_evsel__open_per_cpu(evsel, cpus); 171 return perf_evsel__open_per_cpu(evsel, evsel_list->cpus, false, false);
170 172
171 attr->inherit = !no_inherit; 173 attr->inherit = !no_inherit;
172 if (target_pid == -1 && target_tid == -1) { 174 if (target_pid == -1 && target_tid == -1) {
@@ -174,7 +176,7 @@ static int create_perf_stat_counter(struct perf_evsel *evsel)
174 attr->enable_on_exec = 1; 176 attr->enable_on_exec = 1;
175 } 177 }
176 178
177 return perf_evsel__open_per_thread(evsel, threads); 179 return perf_evsel__open_per_thread(evsel, evsel_list->threads, false, false);
178} 180}
179 181
180/* 182/*
@@ -199,7 +201,8 @@ static int read_counter_aggr(struct perf_evsel *counter)
199 u64 *count = counter->counts->aggr.values; 201 u64 *count = counter->counts->aggr.values;
200 int i; 202 int i;
201 203
202 if (__perf_evsel__read(counter, cpus->nr, threads->nr, scale) < 0) 204 if (__perf_evsel__read(counter, evsel_list->cpus->nr,
205 evsel_list->threads->nr, scale) < 0)
203 return -1; 206 return -1;
204 207
205 for (i = 0; i < 3; i++) 208 for (i = 0; i < 3; i++)
@@ -232,7 +235,7 @@ static int read_counter(struct perf_evsel *counter)
232 u64 *count; 235 u64 *count;
233 int cpu; 236 int cpu;
234 237
235 for (cpu = 0; cpu < cpus->nr; cpu++) { 238 for (cpu = 0; cpu < evsel_list->cpus->nr; cpu++) {
236 if (__perf_evsel__read_on_cpu(counter, cpu, 0, scale) < 0) 239 if (__perf_evsel__read_on_cpu(counter, cpu, 0, scale) < 0)
237 return -1; 240 return -1;
238 241
@@ -297,7 +300,7 @@ static int run_perf_stat(int argc __used, const char **argv)
297 } 300 }
298 301
299 if (target_tid == -1 && target_pid == -1 && !system_wide) 302 if (target_tid == -1 && target_pid == -1 && !system_wide)
300 threads->map[0] = child_pid; 303 evsel_list->threads->map[0] = child_pid;
301 304
302 /* 305 /*
303 * Wait for the child to be ready to exec. 306 * Wait for the child to be ready to exec.
@@ -309,7 +312,7 @@ static int run_perf_stat(int argc __used, const char **argv)
309 close(child_ready_pipe[0]); 312 close(child_ready_pipe[0]);
310 } 313 }
311 314
312 list_for_each_entry(counter, &evsel_list, node) { 315 list_for_each_entry(counter, &evsel_list->entries, node) {
313 if (create_perf_stat_counter(counter) < 0) { 316 if (create_perf_stat_counter(counter) < 0) {
314 if (errno == -EPERM || errno == -EACCES) { 317 if (errno == -EPERM || errno == -EACCES) {
315 error("You may not have permission to collect %sstats.\n" 318 error("You may not have permission to collect %sstats.\n"
@@ -347,14 +350,15 @@ static int run_perf_stat(int argc __used, const char **argv)
347 update_stats(&walltime_nsecs_stats, t1 - t0); 350 update_stats(&walltime_nsecs_stats, t1 - t0);
348 351
349 if (no_aggr) { 352 if (no_aggr) {
350 list_for_each_entry(counter, &evsel_list, node) { 353 list_for_each_entry(counter, &evsel_list->entries, node) {
351 read_counter(counter); 354 read_counter(counter);
352 perf_evsel__close_fd(counter, cpus->nr, 1); 355 perf_evsel__close_fd(counter, evsel_list->cpus->nr, 1);
353 } 356 }
354 } else { 357 } else {
355 list_for_each_entry(counter, &evsel_list, node) { 358 list_for_each_entry(counter, &evsel_list->entries, node) {
356 read_counter_aggr(counter); 359 read_counter_aggr(counter);
357 perf_evsel__close_fd(counter, cpus->nr, threads->nr); 360 perf_evsel__close_fd(counter, evsel_list->cpus->nr,
361 evsel_list->threads->nr);
358 } 362 }
359 } 363 }
360 364
@@ -382,10 +386,13 @@ static void nsec_printout(int cpu, struct perf_evsel *evsel, double avg)
382 if (no_aggr) 386 if (no_aggr)
383 sprintf(cpustr, "CPU%*d%s", 387 sprintf(cpustr, "CPU%*d%s",
384 csv_output ? 0 : -4, 388 csv_output ? 0 : -4,
385 cpus->map[cpu], csv_sep); 389 evsel_list->cpus->map[cpu], csv_sep);
386 390
387 fprintf(stderr, fmt, cpustr, msecs, csv_sep, event_name(evsel)); 391 fprintf(stderr, fmt, cpustr, msecs, csv_sep, event_name(evsel));
388 392
393 if (evsel->cgrp)
394 fprintf(stderr, "%s%s", csv_sep, evsel->cgrp->name);
395
389 if (csv_output) 396 if (csv_output)
390 return; 397 return;
391 398
@@ -410,12 +417,15 @@ static void abs_printout(int cpu, struct perf_evsel *evsel, double avg)
410 if (no_aggr) 417 if (no_aggr)
411 sprintf(cpustr, "CPU%*d%s", 418 sprintf(cpustr, "CPU%*d%s",
412 csv_output ? 0 : -4, 419 csv_output ? 0 : -4,
413 cpus->map[cpu], csv_sep); 420 evsel_list->cpus->map[cpu], csv_sep);
414 else 421 else
415 cpu = 0; 422 cpu = 0;
416 423
417 fprintf(stderr, fmt, cpustr, avg, csv_sep, event_name(evsel)); 424 fprintf(stderr, fmt, cpustr, avg, csv_sep, event_name(evsel));
418 425
426 if (evsel->cgrp)
427 fprintf(stderr, "%s%s", csv_sep, evsel->cgrp->name);
428
419 if (csv_output) 429 if (csv_output)
420 return; 430 return;
421 431
@@ -456,9 +466,17 @@ static void print_counter_aggr(struct perf_evsel *counter)
456 int scaled = counter->counts->scaled; 466 int scaled = counter->counts->scaled;
457 467
458 if (scaled == -1) { 468 if (scaled == -1) {
459 fprintf(stderr, "%*s%s%-24s\n", 469 fprintf(stderr, "%*s%s%*s",
460 csv_output ? 0 : 18, 470 csv_output ? 0 : 18,
461 "<not counted>", csv_sep, event_name(counter)); 471 "<not counted>",
472 csv_sep,
473 csv_output ? 0 : -24,
474 event_name(counter));
475
476 if (counter->cgrp)
477 fprintf(stderr, "%s%s", csv_sep, counter->cgrp->name);
478
479 fputc('\n', stderr);
462 return; 480 return;
463 } 481 }
464 482
@@ -483,7 +501,6 @@ static void print_counter_aggr(struct perf_evsel *counter)
483 fprintf(stderr, " (scaled from %.2f%%)", 501 fprintf(stderr, " (scaled from %.2f%%)",
484 100 * avg_running / avg_enabled); 502 100 * avg_running / avg_enabled);
485 } 503 }
486
487 fprintf(stderr, "\n"); 504 fprintf(stderr, "\n");
488} 505}
489 506
@@ -496,19 +513,23 @@ static void print_counter(struct perf_evsel *counter)
496 u64 ena, run, val; 513 u64 ena, run, val;
497 int cpu; 514 int cpu;
498 515
499 for (cpu = 0; cpu < cpus->nr; cpu++) { 516 for (cpu = 0; cpu < evsel_list->cpus->nr; cpu++) {
500 val = counter->counts->cpu[cpu].val; 517 val = counter->counts->cpu[cpu].val;
501 ena = counter->counts->cpu[cpu].ena; 518 ena = counter->counts->cpu[cpu].ena;
502 run = counter->counts->cpu[cpu].run; 519 run = counter->counts->cpu[cpu].run;
503 if (run == 0 || ena == 0) { 520 if (run == 0 || ena == 0) {
504 fprintf(stderr, "CPU%*d%s%*s%s%-24s", 521 fprintf(stderr, "CPU%*d%s%*s%s%*s",
505 csv_output ? 0 : -4, 522 csv_output ? 0 : -4,
506 cpus->map[cpu], csv_sep, 523 evsel_list->cpus->map[cpu], csv_sep,
507 csv_output ? 0 : 18, 524 csv_output ? 0 : 18,
508 "<not counted>", csv_sep, 525 "<not counted>", csv_sep,
526 csv_output ? 0 : -24,
509 event_name(counter)); 527 event_name(counter));
510 528
511 fprintf(stderr, "\n"); 529 if (counter->cgrp)
530 fprintf(stderr, "%s%s", csv_sep, counter->cgrp->name);
531
532 fputc('\n', stderr);
512 continue; 533 continue;
513 } 534 }
514 535
@@ -525,7 +546,7 @@ static void print_counter(struct perf_evsel *counter)
525 100.0 * run / ena); 546 100.0 * run / ena);
526 } 547 }
527 } 548 }
528 fprintf(stderr, "\n"); 549 fputc('\n', stderr);
529 } 550 }
530} 551}
531 552
@@ -555,10 +576,10 @@ static void print_stat(int argc, const char **argv)
555 } 576 }
556 577
557 if (no_aggr) { 578 if (no_aggr) {
558 list_for_each_entry(counter, &evsel_list, node) 579 list_for_each_entry(counter, &evsel_list->entries, node)
559 print_counter(counter); 580 print_counter(counter);
560 } else { 581 } else {
561 list_for_each_entry(counter, &evsel_list, node) 582 list_for_each_entry(counter, &evsel_list->entries, node)
562 print_counter_aggr(counter); 583 print_counter_aggr(counter);
563 } 584 }
564 585
@@ -610,7 +631,7 @@ static int stat__set_big_num(const struct option *opt __used,
610} 631}
611 632
612static const struct option options[] = { 633static const struct option options[] = {
613 OPT_CALLBACK('e', "event", NULL, "event", 634 OPT_CALLBACK('e', "event", &evsel_list, "event",
614 "event selector. use 'perf list' to list available events", 635 "event selector. use 'perf list' to list available events",
615 parse_events), 636 parse_events),
616 OPT_BOOLEAN('i', "no-inherit", &no_inherit, 637 OPT_BOOLEAN('i', "no-inherit", &no_inherit,
@@ -638,6 +659,9 @@ static const struct option options[] = {
638 "disable CPU count aggregation"), 659 "disable CPU count aggregation"),
639 OPT_STRING('x', "field-separator", &csv_sep, "separator", 660 OPT_STRING('x', "field-separator", &csv_sep, "separator",
640 "print counts with custom separator"), 661 "print counts with custom separator"),
662 OPT_CALLBACK('G', "cgroup", &evsel_list, "name",
663 "monitor event in cgroup name only",
664 parse_cgroups),
641 OPT_END() 665 OPT_END()
642}; 666};
643 667
@@ -648,6 +672,10 @@ int cmd_stat(int argc, const char **argv, const char *prefix __used)
648 672
649 setlocale(LC_ALL, ""); 673 setlocale(LC_ALL, "");
650 674
675 evsel_list = perf_evlist__new(NULL, NULL);
676 if (evsel_list == NULL)
677 return -ENOMEM;
678
651 argc = parse_options(argc, argv, options, stat_usage, 679 argc = parse_options(argc, argv, options, stat_usage,
652 PARSE_OPT_STOP_AT_NON_OPTION); 680 PARSE_OPT_STOP_AT_NON_OPTION);
653 681
@@ -674,49 +702,50 @@ int cmd_stat(int argc, const char **argv, const char *prefix __used)
674 if (run_count <= 0) 702 if (run_count <= 0)
675 usage_with_options(stat_usage, options); 703 usage_with_options(stat_usage, options);
676 704
677 /* no_aggr is for system-wide only */ 705 /* no_aggr, cgroup are for system-wide only */
678 if (no_aggr && !system_wide) 706 if ((no_aggr || nr_cgroups) && !system_wide) {
707 fprintf(stderr, "both cgroup and no-aggregation "
708 "modes only available in system-wide mode\n");
709
679 usage_with_options(stat_usage, options); 710 usage_with_options(stat_usage, options);
711 }
680 712
681 /* Set attrs and nr_counters if no event is selected and !null_run */ 713 /* Set attrs and nr_counters if no event is selected and !null_run */
682 if (!null_run && !nr_counters) { 714 if (!null_run && !evsel_list->nr_entries) {
683 size_t c; 715 size_t c;
684 716
685 nr_counters = ARRAY_SIZE(default_attrs);
686
687 for (c = 0; c < ARRAY_SIZE(default_attrs); ++c) { 717 for (c = 0; c < ARRAY_SIZE(default_attrs); ++c) {
688 pos = perf_evsel__new(&default_attrs[c], 718 pos = perf_evsel__new(&default_attrs[c], c);
689 nr_counters);
690 if (pos == NULL) 719 if (pos == NULL)
691 goto out; 720 goto out;
692 list_add(&pos->node, &evsel_list); 721 perf_evlist__add(evsel_list, pos);
693 } 722 }
694 } 723 }
695 724
696 if (target_pid != -1) 725 if (target_pid != -1)
697 target_tid = target_pid; 726 target_tid = target_pid;
698 727
699 threads = thread_map__new(target_pid, target_tid); 728 evsel_list->threads = thread_map__new(target_pid, target_tid);
700 if (threads == NULL) { 729 if (evsel_list->threads == NULL) {
701 pr_err("Problems finding threads of monitor\n"); 730 pr_err("Problems finding threads of monitor\n");
702 usage_with_options(stat_usage, options); 731 usage_with_options(stat_usage, options);
703 } 732 }
704 733
705 if (system_wide) 734 if (system_wide)
706 cpus = cpu_map__new(cpu_list); 735 evsel_list->cpus = cpu_map__new(cpu_list);
707 else 736 else
708 cpus = cpu_map__dummy_new(); 737 evsel_list->cpus = cpu_map__dummy_new();
709 738
710 if (cpus == NULL) { 739 if (evsel_list->cpus == NULL) {
711 perror("failed to parse CPUs map"); 740 perror("failed to parse CPUs map");
712 usage_with_options(stat_usage, options); 741 usage_with_options(stat_usage, options);
713 return -1; 742 return -1;
714 } 743 }
715 744
716 list_for_each_entry(pos, &evsel_list, node) { 745 list_for_each_entry(pos, &evsel_list->entries, node) {
717 if (perf_evsel__alloc_stat_priv(pos) < 0 || 746 if (perf_evsel__alloc_stat_priv(pos) < 0 ||
718 perf_evsel__alloc_counts(pos, cpus->nr) < 0 || 747 perf_evsel__alloc_counts(pos, evsel_list->cpus->nr) < 0 ||
719 perf_evsel__alloc_fd(pos, cpus->nr, threads->nr) < 0) 748 perf_evsel__alloc_fd(pos, evsel_list->cpus->nr, evsel_list->threads->nr) < 0)
720 goto out_free_fd; 749 goto out_free_fd;
721 } 750 }
722 751
@@ -741,11 +770,10 @@ int cmd_stat(int argc, const char **argv, const char *prefix __used)
741 if (status != -1) 770 if (status != -1)
742 print_stat(argc, argv); 771 print_stat(argc, argv);
743out_free_fd: 772out_free_fd:
744 list_for_each_entry(pos, &evsel_list, node) 773 list_for_each_entry(pos, &evsel_list->entries, node)
745 perf_evsel__free_stat_priv(pos); 774 perf_evsel__free_stat_priv(pos);
746 perf_evsel_list__delete(); 775 perf_evlist__delete_maps(evsel_list);
747out: 776out:
748 thread_map__delete(threads); 777 perf_evlist__delete(evsel_list);
749 threads = NULL;
750 return status; 778 return status;
751} 779}