aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf/builtin-stat.c
diff options
context:
space:
mode:
authorStephane Eranian <eranian@google.com>2013-02-14 07:57:27 -0500
committerArnaldo Carvalho de Melo <acme@redhat.com>2013-03-25 14:29:53 -0400
commit86ee6e18f6cb43ab0cb67347bda5b6f5b016121d (patch)
tree414e785b0ba86fc602ad286846cdfd9266568df6 /tools/perf/builtin-stat.c
parentebf3c675d7e4ba97568dd6daaa43b1af10046b29 (diff)
perf stat: Refactor aggregation code
Refactor aggregation code by introducing a single aggr_mode variable and an enum for aggregation. Also refactor cpumap code having to do with cpu to socket mappings. All in preparation for extended modes, such as cpu -> core. Also fix socket aggregation and ensure that sockets are printed in increasing order. Signed-off-by: Stephane Eranian <eranian@google.com> Cc: Andi Kleen <ak@linux.intel.com> Cc: Ingo Molnar <mingo@elte.hu> Cc: Jiri Olsa <jolsa@redhat.com> Cc: Namhyung Kim <namhyung.kim@lge.com> Cc: Peter Zijlstra <peterz@infradead.org> Link: http://lkml.kernel.org/r/1360846649-6411-2-git-send-email-eranian@google.com [ committer note: Fixup conflicts with a7e191c "--repeat forever" and acf2892 "Use perf_evlist__prepare/start_workload()" ] 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.c207
1 files changed, 119 insertions, 88 deletions
diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c
index ba0bdd87c279..ded34fc4df4f 100644
--- a/tools/perf/builtin-stat.c
+++ b/tools/perf/builtin-stat.c
@@ -68,7 +68,7 @@
68static void print_stat(int argc, const char **argv); 68static void print_stat(int argc, const char **argv);
69static void print_counter_aggr(struct perf_evsel *counter, char *prefix); 69static void print_counter_aggr(struct perf_evsel *counter, char *prefix);
70static void print_counter(struct perf_evsel *counter, char *prefix); 70static void print_counter(struct perf_evsel *counter, char *prefix);
71static void print_aggr_socket(char *prefix); 71static void print_aggr(char *prefix);
72 72
73static struct perf_evlist *evsel_list; 73static struct perf_evlist *evsel_list;
74 74
@@ -76,11 +76,16 @@ static struct perf_target target = {
76 .uid = UINT_MAX, 76 .uid = UINT_MAX,
77}; 77};
78 78
79enum aggr_mode {
80 AGGR_NONE,
81 AGGR_GLOBAL,
82 AGGR_SOCKET,
83};
84
79static int run_count = 1; 85static int run_count = 1;
80static bool no_inherit = false; 86static bool no_inherit = false;
81static bool scale = true; 87static bool scale = true;
82static bool no_aggr = false; 88static enum aggr_mode aggr_mode = AGGR_GLOBAL;
83static bool aggr_socket = false;
84static pid_t child_pid = -1; 89static pid_t child_pid = -1;
85static bool null_run = false; 90static bool null_run = false;
86static int detailed_run = 0; 91static int detailed_run = 0;
@@ -96,7 +101,8 @@ static bool sync_run = false;
96static unsigned int interval = 0; 101static unsigned int interval = 0;
97static bool forever = false; 102static bool forever = false;
98static struct timespec ref_time; 103static struct timespec ref_time;
99static struct cpu_map *sock_map; 104static struct cpu_map *aggr_map;
105static int (*aggr_get_id)(struct cpu_map *m, int cpu);
100 106
101static volatile int done = 0; 107static volatile int done = 0;
102 108
@@ -355,41 +361,51 @@ static void print_interval(void)
355 struct timespec ts, rs; 361 struct timespec ts, rs;
356 char prefix[64]; 362 char prefix[64];
357 363
358 if (no_aggr) { 364 if (aggr_mode == AGGR_GLOBAL) {
359 list_for_each_entry(counter, &evsel_list->entries, node) { 365 list_for_each_entry(counter, &evsel_list->entries, node) {
360 ps = counter->priv; 366 ps = counter->priv;
361 memset(ps->res_stats, 0, sizeof(ps->res_stats)); 367 memset(ps->res_stats, 0, sizeof(ps->res_stats));
362 read_counter(counter); 368 read_counter_aggr(counter);
363 } 369 }
364 } else { 370 } else {
365 list_for_each_entry(counter, &evsel_list->entries, node) { 371 list_for_each_entry(counter, &evsel_list->entries, node) {
366 ps = counter->priv; 372 ps = counter->priv;
367 memset(ps->res_stats, 0, sizeof(ps->res_stats)); 373 memset(ps->res_stats, 0, sizeof(ps->res_stats));
368 read_counter_aggr(counter); 374 read_counter(counter);
369 } 375 }
370 } 376 }
377
371 clock_gettime(CLOCK_MONOTONIC, &ts); 378 clock_gettime(CLOCK_MONOTONIC, &ts);
372 diff_timespec(&rs, &ts, &ref_time); 379 diff_timespec(&rs, &ts, &ref_time);
373 sprintf(prefix, "%6lu.%09lu%s", rs.tv_sec, rs.tv_nsec, csv_sep); 380 sprintf(prefix, "%6lu.%09lu%s", rs.tv_sec, rs.tv_nsec, csv_sep);
374 381
375 if (num_print_interval == 0 && !csv_output) { 382 if (num_print_interval == 0 && !csv_output) {
376 if (aggr_socket) 383 switch (aggr_mode) {
384 case AGGR_SOCKET:
377 fprintf(output, "# time socket cpus counts events\n"); 385 fprintf(output, "# time socket cpus counts events\n");
378 else if (no_aggr) 386 break;
387 case AGGR_NONE:
379 fprintf(output, "# time CPU counts events\n"); 388 fprintf(output, "# time CPU counts events\n");
380 else 389 break;
390 case AGGR_GLOBAL:
391 default:
381 fprintf(output, "# time counts events\n"); 392 fprintf(output, "# time counts events\n");
393 }
382 } 394 }
383 395
384 if (++num_print_interval == 25) 396 if (++num_print_interval == 25)
385 num_print_interval = 0; 397 num_print_interval = 0;
386 398
387 if (aggr_socket) 399 switch (aggr_mode) {
388 print_aggr_socket(prefix); 400 case AGGR_SOCKET:
389 else if (no_aggr) { 401 print_aggr(prefix);
402 break;
403 case AGGR_NONE:
390 list_for_each_entry(counter, &evsel_list->entries, node) 404 list_for_each_entry(counter, &evsel_list->entries, node)
391 print_counter(counter, prefix); 405 print_counter(counter, prefix);
392 } else { 406 break;
407 case AGGR_GLOBAL:
408 default:
393 list_for_each_entry(counter, &evsel_list->entries, node) 409 list_for_each_entry(counter, &evsel_list->entries, node)
394 print_counter_aggr(counter, prefix); 410 print_counter_aggr(counter, prefix);
395 } 411 }
@@ -412,12 +428,6 @@ static int __run_perf_stat(int argc, const char **argv)
412 ts.tv_nsec = 0; 428 ts.tv_nsec = 0;
413 } 429 }
414 430
415 if (aggr_socket
416 && cpu_map__build_socket_map(evsel_list->cpus, &sock_map)) {
417 perror("cannot build socket map");
418 return -1;
419 }
420
421 if (forks) { 431 if (forks) {
422 if (perf_evlist__prepare_workload(evsel_list, &target, argv, 432 if (perf_evlist__prepare_workload(evsel_list, &target, argv,
423 false, false) < 0) { 433 false, false) < 0) {
@@ -493,17 +503,17 @@ static int __run_perf_stat(int argc, const char **argv)
493 503
494 update_stats(&walltime_nsecs_stats, t1 - t0); 504 update_stats(&walltime_nsecs_stats, t1 - t0);
495 505
496 if (no_aggr) { 506 if (aggr_mode == AGGR_GLOBAL) {
497 list_for_each_entry(counter, &evsel_list->entries, node) {
498 read_counter(counter);
499 perf_evsel__close_fd(counter, perf_evsel__nr_cpus(counter), 1);
500 }
501 } else {
502 list_for_each_entry(counter, &evsel_list->entries, node) { 507 list_for_each_entry(counter, &evsel_list->entries, node) {
503 read_counter_aggr(counter); 508 read_counter_aggr(counter);
504 perf_evsel__close_fd(counter, perf_evsel__nr_cpus(counter), 509 perf_evsel__close_fd(counter, perf_evsel__nr_cpus(counter),
505 thread_map__nr(evsel_list->threads)); 510 thread_map__nr(evsel_list->threads));
506 } 511 }
512 } else {
513 list_for_each_entry(counter, &evsel_list->entries, node) {
514 read_counter(counter);
515 perf_evsel__close_fd(counter, perf_evsel__nr_cpus(counter), 1);
516 }
507 } 517 }
508 518
509 return WEXITSTATUS(status); 519 return WEXITSTATUS(status);
@@ -556,26 +566,37 @@ static void print_noise(struct perf_evsel *evsel, double avg)
556 print_noise_pct(stddev_stats(&ps->res_stats[0]), avg); 566 print_noise_pct(stddev_stats(&ps->res_stats[0]), avg);
557} 567}
558 568
559static void nsec_printout(int cpu, int nr, struct perf_evsel *evsel, double avg) 569static void aggr_printout(struct perf_evsel *evsel, int cpu, int nr)
560{ 570{
561 double msecs = avg / 1e6; 571 switch (aggr_mode) {
562 char cpustr[16] = { '\0', }; 572 case AGGR_SOCKET:
563 const char *fmt = csv_output ? "%s%.6f%s%s" : "%s%18.6f%s%-25s"; 573 fprintf(output, "S%*d%s%*d%s",
564
565 if (aggr_socket)
566 sprintf(cpustr, "S%*d%s%*d%s",
567 csv_output ? 0 : -5, 574 csv_output ? 0 : -5,
568 cpu, 575 cpu,
569 csv_sep, 576 csv_sep,
570 csv_output ? 0 : 4, 577 csv_output ? 0 : 4,
571 nr, 578 nr,
572 csv_sep); 579 csv_sep);
573 else if (no_aggr) 580 break;
574 sprintf(cpustr, "CPU%*d%s", 581 case AGGR_NONE:
582 fprintf(output, "CPU%*d%s",
575 csv_output ? 0 : -4, 583 csv_output ? 0 : -4,
576 perf_evsel__cpus(evsel)->map[cpu], csv_sep); 584 perf_evsel__cpus(evsel)->map[cpu], csv_sep);
585 break;
586 case AGGR_GLOBAL:
587 default:
588 break;
589 }
590}
591
592static void nsec_printout(int cpu, int nr, struct perf_evsel *evsel, double avg)
593{
594 double msecs = avg / 1e6;
595 const char *fmt = csv_output ? "%.6f%s%s" : "%18.6f%s%-25s";
596
597 aggr_printout(evsel, cpu, nr);
577 598
578 fprintf(output, fmt, cpustr, msecs, csv_sep, perf_evsel__name(evsel)); 599 fprintf(output, fmt, msecs, csv_sep, perf_evsel__name(evsel));
579 600
580 if (evsel->cgrp) 601 if (evsel->cgrp)
581 fprintf(output, "%s%s", csv_sep, evsel->cgrp->name); 602 fprintf(output, "%s%s", csv_sep, evsel->cgrp->name);
@@ -772,32 +793,21 @@ static void print_ll_cache_misses(int cpu,
772static void abs_printout(int cpu, int nr, struct perf_evsel *evsel, double avg) 793static void abs_printout(int cpu, int nr, struct perf_evsel *evsel, double avg)
773{ 794{
774 double total, ratio = 0.0; 795 double total, ratio = 0.0;
775 char cpustr[16] = { '\0', };
776 const char *fmt; 796 const char *fmt;
777 797
778 if (csv_output) 798 if (csv_output)
779 fmt = "%s%.0f%s%s"; 799 fmt = "%.0f%s%s";
780 else if (big_num) 800 else if (big_num)
781 fmt = "%s%'18.0f%s%-25s"; 801 fmt = "%'18.0f%s%-25s";
782 else 802 else
783 fmt = "%s%18.0f%s%-25s"; 803 fmt = "%18.0f%s%-25s";
784 804
785 if (aggr_socket) 805 aggr_printout(evsel, cpu, nr);
786 sprintf(cpustr, "S%*d%s%*d%s", 806
787 csv_output ? 0 : -5, 807 if (aggr_mode == AGGR_GLOBAL)
788 cpu,
789 csv_sep,
790 csv_output ? 0 : 4,
791 nr,
792 csv_sep);
793 else if (no_aggr)
794 sprintf(cpustr, "CPU%*d%s",
795 csv_output ? 0 : -4,
796 perf_evsel__cpus(evsel)->map[cpu], csv_sep);
797 else
798 cpu = 0; 808 cpu = 0;
799 809
800 fprintf(output, fmt, cpustr, avg, csv_sep, perf_evsel__name(evsel)); 810 fprintf(output, fmt, avg, csv_sep, perf_evsel__name(evsel));
801 811
802 if (evsel->cgrp) 812 if (evsel->cgrp)
803 fprintf(output, "%s%s", csv_sep, evsel->cgrp->name); 813 fprintf(output, "%s%s", csv_sep, evsel->cgrp->name);
@@ -896,23 +906,23 @@ static void abs_printout(int cpu, int nr, struct perf_evsel *evsel, double avg)
896 } 906 }
897} 907}
898 908
899static void print_aggr_socket(char *prefix) 909static void print_aggr(char *prefix)
900{ 910{
901 struct perf_evsel *counter; 911 struct perf_evsel *counter;
912 int cpu, s, s2, id, nr;
902 u64 ena, run, val; 913 u64 ena, run, val;
903 int cpu, s, s2, sock, nr;
904 914
905 if (!sock_map) 915 if (!(aggr_map || aggr_get_id))
906 return; 916 return;
907 917
908 for (s = 0; s < sock_map->nr; s++) { 918 for (s = 0; s < aggr_map->nr; s++) {
909 sock = cpu_map__socket(sock_map, s); 919 id = aggr_map->map[s];
910 list_for_each_entry(counter, &evsel_list->entries, node) { 920 list_for_each_entry(counter, &evsel_list->entries, node) {
911 val = ena = run = 0; 921 val = ena = run = 0;
912 nr = 0; 922 nr = 0;
913 for (cpu = 0; cpu < perf_evsel__nr_cpus(counter); cpu++) { 923 for (cpu = 0; cpu < perf_evsel__nr_cpus(counter); cpu++) {
914 s2 = cpu_map__get_socket(evsel_list->cpus, cpu); 924 s2 = aggr_get_id(evsel_list->cpus, cpu);
915 if (s2 != sock) 925 if (s2 != id)
916 continue; 926 continue;
917 val += counter->counts->cpu[cpu].val; 927 val += counter->counts->cpu[cpu].val;
918 ena += counter->counts->cpu[cpu].ena; 928 ena += counter->counts->cpu[cpu].ena;
@@ -923,18 +933,15 @@ static void print_aggr_socket(char *prefix)
923 fprintf(output, "%s", prefix); 933 fprintf(output, "%s", prefix);
924 934
925 if (run == 0 || ena == 0) { 935 if (run == 0 || ena == 0) {
926 fprintf(output, "S%*d%s%*d%s%*s%s%*s", 936 aggr_printout(counter, cpu, nr);
927 csv_output ? 0 : -5, 937
928 s, 938 fprintf(output, "%*s%s%*s",
929 csv_sep,
930 csv_output ? 0 : 4,
931 nr,
932 csv_sep,
933 csv_output ? 0 : 18, 939 csv_output ? 0 : 18,
934 counter->supported ? CNTR_NOT_COUNTED : CNTR_NOT_SUPPORTED, 940 counter->supported ? CNTR_NOT_COUNTED : CNTR_NOT_SUPPORTED,
935 csv_sep, 941 csv_sep,
936 csv_output ? 0 : -24, 942 csv_output ? 0 : -24,
937 perf_evsel__name(counter)); 943 perf_evsel__name(counter));
944
938 if (counter->cgrp) 945 if (counter->cgrp)
939 fprintf(output, "%s%s", 946 fprintf(output, "%s%s",
940 csv_sep, counter->cgrp->name); 947 csv_sep, counter->cgrp->name);
@@ -944,9 +951,9 @@ static void print_aggr_socket(char *prefix)
944 } 951 }
945 952
946 if (nsec_counter(counter)) 953 if (nsec_counter(counter))
947 nsec_printout(sock, nr, counter, val); 954 nsec_printout(id, nr, counter, val);
948 else 955 else
949 abs_printout(sock, nr, counter, val); 956 abs_printout(id, nr, counter, val);
950 957
951 if (!csv_output) { 958 if (!csv_output) {
952 print_noise(counter, 1.0); 959 print_noise(counter, 1.0);
@@ -1087,14 +1094,20 @@ static void print_stat(int argc, const char **argv)
1087 fprintf(output, ":\n\n"); 1094 fprintf(output, ":\n\n");
1088 } 1095 }
1089 1096
1090 if (aggr_socket) 1097 switch (aggr_mode) {
1091 print_aggr_socket(NULL); 1098 case AGGR_SOCKET:
1092 else if (no_aggr) { 1099 print_aggr(NULL);
1093 list_for_each_entry(counter, &evsel_list->entries, node) 1100 break;
1094 print_counter(counter, NULL); 1101 case AGGR_GLOBAL:
1095 } else {
1096 list_for_each_entry(counter, &evsel_list->entries, node) 1102 list_for_each_entry(counter, &evsel_list->entries, node)
1097 print_counter_aggr(counter, NULL); 1103 print_counter_aggr(counter, NULL);
1104 break;
1105 case AGGR_NONE:
1106 list_for_each_entry(counter, &evsel_list->entries, node)
1107 print_counter(counter, NULL);
1108 break;
1109 default:
1110 break;
1098 } 1111 }
1099 1112
1100 if (!csv_output) { 1113 if (!csv_output) {
@@ -1140,6 +1153,25 @@ static int stat__set_big_num(const struct option *opt __maybe_unused,
1140 return 0; 1153 return 0;
1141} 1154}
1142 1155
1156static int perf_stat_init_aggr_mode(void)
1157{
1158 switch (aggr_mode) {
1159 case AGGR_SOCKET:
1160 if (cpu_map__build_socket_map(evsel_list->cpus, &aggr_map)) {
1161 perror("cannot build socket map");
1162 return -1;
1163 }
1164 aggr_get_id = cpu_map__get_socket;
1165 break;
1166 case AGGR_NONE:
1167 case AGGR_GLOBAL:
1168 default:
1169 break;
1170 }
1171 return 0;
1172}
1173
1174
1143/* 1175/*
1144 * Add default attributes, if there were no attributes specified or 1176 * Add default attributes, if there were no attributes specified or
1145 * if -d/--detailed, -d -d or -d -d -d is used: 1177 * if -d/--detailed, -d -d or -d -d -d is used:
@@ -1322,7 +1354,8 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
1322 stat__set_big_num), 1354 stat__set_big_num),
1323 OPT_STRING('C', "cpu", &target.cpu_list, "cpu", 1355 OPT_STRING('C', "cpu", &target.cpu_list, "cpu",
1324 "list of cpus to monitor in system-wide"), 1356 "list of cpus to monitor in system-wide"),
1325 OPT_BOOLEAN('A', "no-aggr", &no_aggr, "disable CPU count aggregation"), 1357 OPT_SET_UINT('A', "no-aggr", &aggr_mode,
1358 "disable CPU count aggregation", AGGR_NONE),
1326 OPT_STRING('x', "field-separator", &csv_sep, "separator", 1359 OPT_STRING('x', "field-separator", &csv_sep, "separator",
1327 "print counts with custom separator"), 1360 "print counts with custom separator"),
1328 OPT_CALLBACK('G', "cgroup", &evsel_list, "name", 1361 OPT_CALLBACK('G', "cgroup", &evsel_list, "name",
@@ -1337,7 +1370,8 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
1337 "command to run after to the measured command"), 1370 "command to run after to the measured command"),
1338 OPT_UINTEGER('I', "interval-print", &interval, 1371 OPT_UINTEGER('I', "interval-print", &interval,
1339 "print counts at regular interval in ms (>= 100)"), 1372 "print counts at regular interval in ms (>= 100)"),
1340 OPT_BOOLEAN(0, "aggr-socket", &aggr_socket, "aggregate counts per processor socket"), 1373 OPT_SET_UINT(0, "aggr-socket", &aggr_mode,
1374 "aggregate counts per processor socket", AGGR_SOCKET),
1341 OPT_END() 1375 OPT_END()
1342 }; 1376 };
1343 const char * const stat_usage[] = { 1377 const char * const stat_usage[] = {
@@ -1420,19 +1454,13 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
1420 } 1454 }
1421 1455
1422 /* no_aggr, cgroup are for system-wide only */ 1456 /* no_aggr, cgroup are for system-wide only */
1423 if ((no_aggr || nr_cgroups) && !perf_target__has_cpu(&target)) { 1457 if ((aggr_mode != AGGR_GLOBAL || nr_cgroups)
1458 && !perf_target__has_cpu(&target)) {
1424 fprintf(stderr, "both cgroup and no-aggregation " 1459 fprintf(stderr, "both cgroup and no-aggregation "
1425 "modes only available in system-wide mode\n"); 1460 "modes only available in system-wide mode\n");
1426 1461
1427 usage_with_options(stat_usage, options); 1462 usage_with_options(stat_usage, options);
1428 } 1463 return -1;
1429
1430 if (aggr_socket) {
1431 if (!perf_target__has_cpu(&target)) {
1432 fprintf(stderr, "--aggr-socket only available in system-wide mode (-a)\n");
1433 usage_with_options(stat_usage, options);
1434 }
1435 no_aggr = true;
1436 } 1464 }
1437 1465
1438 if (add_default_attributes()) 1466 if (add_default_attributes())
@@ -1458,6 +1486,9 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
1458 if (perf_evlist__alloc_stats(evsel_list, interval)) 1486 if (perf_evlist__alloc_stats(evsel_list, interval))
1459 goto out_free_maps; 1487 goto out_free_maps;
1460 1488
1489 if (perf_stat_init_aggr_mode())
1490 goto out;
1491
1461 /* 1492 /*
1462 * We dont want to block the signals - that would cause 1493 * We dont want to block the signals - that would cause
1463 * child tasks to inherit that and Ctrl-C would not work. 1494 * child tasks to inherit that and Ctrl-C would not work.