diff options
author | Stephane Eranian <eranian@google.com> | 2013-02-14 07:57:27 -0500 |
---|---|---|
committer | Arnaldo Carvalho de Melo <acme@redhat.com> | 2013-03-25 14:29:53 -0400 |
commit | 86ee6e18f6cb43ab0cb67347bda5b6f5b016121d (patch) | |
tree | 414e785b0ba86fc602ad286846cdfd9266568df6 /tools | |
parent | ebf3c675d7e4ba97568dd6daaa43b1af10046b29 (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')
-rw-r--r-- | tools/perf/builtin-stat.c | 207 | ||||
-rw-r--r-- | tools/perf/util/cpumap.c | 40 |
2 files changed, 147 insertions, 100 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 @@ | |||
68 | static void print_stat(int argc, const char **argv); | 68 | static void print_stat(int argc, const char **argv); |
69 | static void print_counter_aggr(struct perf_evsel *counter, char *prefix); | 69 | static void print_counter_aggr(struct perf_evsel *counter, char *prefix); |
70 | static void print_counter(struct perf_evsel *counter, char *prefix); | 70 | static void print_counter(struct perf_evsel *counter, char *prefix); |
71 | static void print_aggr_socket(char *prefix); | 71 | static void print_aggr(char *prefix); |
72 | 72 | ||
73 | static struct perf_evlist *evsel_list; | 73 | static 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 | ||
79 | enum aggr_mode { | ||
80 | AGGR_NONE, | ||
81 | AGGR_GLOBAL, | ||
82 | AGGR_SOCKET, | ||
83 | }; | ||
84 | |||
79 | static int run_count = 1; | 85 | static int run_count = 1; |
80 | static bool no_inherit = false; | 86 | static bool no_inherit = false; |
81 | static bool scale = true; | 87 | static bool scale = true; |
82 | static bool no_aggr = false; | 88 | static enum aggr_mode aggr_mode = AGGR_GLOBAL; |
83 | static bool aggr_socket = false; | ||
84 | static pid_t child_pid = -1; | 89 | static pid_t child_pid = -1; |
85 | static bool null_run = false; | 90 | static bool null_run = false; |
86 | static int detailed_run = 0; | 91 | static int detailed_run = 0; |
@@ -96,7 +101,8 @@ static bool sync_run = false; | |||
96 | static unsigned int interval = 0; | 101 | static unsigned int interval = 0; |
97 | static bool forever = false; | 102 | static bool forever = false; |
98 | static struct timespec ref_time; | 103 | static struct timespec ref_time; |
99 | static struct cpu_map *sock_map; | 104 | static struct cpu_map *aggr_map; |
105 | static int (*aggr_get_id)(struct cpu_map *m, int cpu); | ||
100 | 106 | ||
101 | static volatile int done = 0; | 107 | static 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 | ||
559 | static void nsec_printout(int cpu, int nr, struct perf_evsel *evsel, double avg) | 569 | static 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 | |||
592 | static 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, | |||
772 | static void abs_printout(int cpu, int nr, struct perf_evsel *evsel, double avg) | 793 | static 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 | ||
899 | static void print_aggr_socket(char *prefix) | 909 | static 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 | ||
1156 | static 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. |
diff --git a/tools/perf/util/cpumap.c b/tools/perf/util/cpumap.c index f817046e22b1..7bb8e87a5847 100644 --- a/tools/perf/util/cpumap.c +++ b/tools/perf/util/cpumap.c | |||
@@ -4,6 +4,7 @@ | |||
4 | #include "cpumap.h" | 4 | #include "cpumap.h" |
5 | #include <assert.h> | 5 | #include <assert.h> |
6 | #include <stdio.h> | 6 | #include <stdio.h> |
7 | #include <stdlib.h> | ||
7 | 8 | ||
8 | static struct cpu_map *cpu_map__default_new(void) | 9 | static struct cpu_map *cpu_map__default_new(void) |
9 | { | 10 | { |
@@ -219,7 +220,7 @@ int cpu_map__get_socket(struct cpu_map *map, int idx) | |||
219 | if (!mnt) | 220 | if (!mnt) |
220 | return -1; | 221 | return -1; |
221 | 222 | ||
222 | sprintf(path, | 223 | snprintf(path, PATH_MAX, |
223 | "%s/devices/system/cpu/cpu%d/topology/physical_package_id", | 224 | "%s/devices/system/cpu/cpu%d/topology/physical_package_id", |
224 | mnt, cpu); | 225 | mnt, cpu); |
225 | 226 | ||
@@ -231,27 +232,42 @@ int cpu_map__get_socket(struct cpu_map *map, int idx) | |||
231 | return ret == 1 ? cpu : -1; | 232 | return ret == 1 ? cpu : -1; |
232 | } | 233 | } |
233 | 234 | ||
234 | int cpu_map__build_socket_map(struct cpu_map *cpus, struct cpu_map **sockp) | 235 | static int cmp_ids(const void *a, const void *b) |
235 | { | 236 | { |
236 | struct cpu_map *sock; | 237 | return *(int *)a - *(int *)b; |
238 | } | ||
239 | |||
240 | static int cpu_map__build_map(struct cpu_map *cpus, struct cpu_map **res, | ||
241 | int (*f)(struct cpu_map *map, int cpu)) | ||
242 | { | ||
243 | struct cpu_map *c; | ||
237 | int nr = cpus->nr; | 244 | int nr = cpus->nr; |
238 | int cpu, s1, s2; | 245 | int cpu, s1, s2; |
239 | 246 | ||
240 | sock = calloc(1, sizeof(*sock) + nr * sizeof(int)); | 247 | /* allocate as much as possible */ |
241 | if (!sock) | 248 | c = calloc(1, sizeof(*c) + nr * sizeof(int)); |
249 | if (!c) | ||
242 | return -1; | 250 | return -1; |
243 | 251 | ||
244 | for (cpu = 0; cpu < nr; cpu++) { | 252 | for (cpu = 0; cpu < nr; cpu++) { |
245 | s1 = cpu_map__get_socket(cpus, cpu); | 253 | s1 = f(cpus, cpu); |
246 | for (s2 = 0; s2 < sock->nr; s2++) { | 254 | for (s2 = 0; s2 < c->nr; s2++) { |
247 | if (s1 == sock->map[s2]) | 255 | if (s1 == c->map[s2]) |
248 | break; | 256 | break; |
249 | } | 257 | } |
250 | if (s2 == sock->nr) { | 258 | if (s2 == c->nr) { |
251 | sock->map[sock->nr] = s1; | 259 | c->map[c->nr] = s1; |
252 | sock->nr++; | 260 | c->nr++; |
253 | } | 261 | } |
254 | } | 262 | } |
255 | *sockp = sock; | 263 | /* ensure we process id in increasing order */ |
264 | qsort(c->map, c->nr, sizeof(int), cmp_ids); | ||
265 | |||
266 | *res = c; | ||
256 | return 0; | 267 | return 0; |
257 | } | 268 | } |
269 | |||
270 | int cpu_map__build_socket_map(struct cpu_map *cpus, struct cpu_map **sockp) | ||
271 | { | ||
272 | return cpu_map__build_map(cpus, sockp, cpu_map__get_socket); | ||
273 | } | ||