diff options
27 files changed, 611 insertions, 128 deletions
diff --git a/tools/perf/Documentation/perf-stat.txt b/tools/perf/Documentation/perf-stat.txt index 5289da3344e9..faf4f4feebcc 100644 --- a/tools/perf/Documentation/perf-stat.txt +++ b/tools/perf/Documentation/perf-stat.txt | |||
@@ -116,9 +116,16 @@ perf stat --repeat 10 --null --sync --pre 'make -s O=defconfig-build/clean' -- m | |||
116 | 116 | ||
117 | -I msecs:: | 117 | -I msecs:: |
118 | --interval-print msecs:: | 118 | --interval-print msecs:: |
119 | print count deltas every N milliseconds (minimum: 100ms) | 119 | Print count deltas every N milliseconds (minimum: 100ms) |
120 | example: perf stat -I 1000 -e cycles -a sleep 5 | 120 | example: perf stat -I 1000 -e cycles -a sleep 5 |
121 | 121 | ||
122 | --aggr-socket:: | ||
123 | Aggregate counts per processor socket for system-wide mode measurements. This | ||
124 | is a useful mode to detect imbalance between sockets. To enable this mode, | ||
125 | use --aggr-socket in addition to -a. (system-wide). The output includes the | ||
126 | socket number and the number of online processors on that socket. This is | ||
127 | useful to gauge the amount of aggregation. | ||
128 | |||
122 | EXAMPLES | 129 | EXAMPLES |
123 | -------- | 130 | -------- |
124 | 131 | ||
diff --git a/tools/perf/Makefile b/tools/perf/Makefile index 4b1044cbd84c..a158309a65ef 100644 --- a/tools/perf/Makefile +++ b/tools/perf/Makefile | |||
@@ -149,6 +149,8 @@ RM = rm -f | |||
149 | MKDIR = mkdir | 149 | MKDIR = mkdir |
150 | FIND = find | 150 | FIND = find |
151 | INSTALL = install | 151 | INSTALL = install |
152 | FLEX = flex | ||
153 | BISON= bison | ||
152 | 154 | ||
153 | # sparse is architecture-neutral, which means that we need to tell it | 155 | # sparse is architecture-neutral, which means that we need to tell it |
154 | # explicitly what architecture to check for. Fix this up for yours.. | 156 | # explicitly what architecture to check for. Fix this up for yours.. |
@@ -158,6 +160,14 @@ ifneq ($(MAKECMDGOALS),clean) | |||
158 | ifneq ($(MAKECMDGOALS),tags) | 160 | ifneq ($(MAKECMDGOALS),tags) |
159 | -include config/feature-tests.mak | 161 | -include config/feature-tests.mak |
160 | 162 | ||
163 | ifeq ($(call get-executable,$(FLEX)),) | ||
164 | dummy := $(error Error: $(FLEX) is missing on this system, please install it) | ||
165 | endif | ||
166 | |||
167 | ifeq ($(call get-executable,$(BISON)),) | ||
168 | dummy := $(error Error: $(BISON) is missing on this system, please install it) | ||
169 | endif | ||
170 | |||
161 | ifeq ($(call try-cc,$(SOURCE_HELLO),$(CFLAGS) -Werror -fstack-protector-all,-fstack-protector-all),y) | 171 | ifeq ($(call try-cc,$(SOURCE_HELLO),$(CFLAGS) -Werror -fstack-protector-all,-fstack-protector-all),y) |
162 | CFLAGS := $(CFLAGS) -fstack-protector-all | 172 | CFLAGS := $(CFLAGS) -fstack-protector-all |
163 | endif | 173 | endif |
@@ -282,9 +292,6 @@ endif | |||
282 | 292 | ||
283 | export PERL_PATH | 293 | export PERL_PATH |
284 | 294 | ||
285 | FLEX = flex | ||
286 | BISON= bison | ||
287 | |||
288 | $(OUTPUT)util/parse-events-flex.c: util/parse-events.l $(OUTPUT)util/parse-events-bison.c | 295 | $(OUTPUT)util/parse-events-flex.c: util/parse-events.l $(OUTPUT)util/parse-events-bison.c |
289 | $(QUIET_FLEX)$(FLEX) --header-file=$(OUTPUT)util/parse-events-flex.h $(PARSER_DEBUG_FLEX) -t util/parse-events.l > $(OUTPUT)util/parse-events-flex.c | 296 | $(QUIET_FLEX)$(FLEX) --header-file=$(OUTPUT)util/parse-events-flex.h $(PARSER_DEBUG_FLEX) -t util/parse-events.l > $(OUTPUT)util/parse-events-flex.c |
290 | 297 | ||
diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c index dc870cf31b79..95a2ad3f043e 100644 --- a/tools/perf/builtin-annotate.c +++ b/tools/perf/builtin-annotate.c | |||
@@ -309,7 +309,8 @@ int cmd_annotate(int argc, const char **argv, const char *prefix __maybe_unused) | |||
309 | if (symbol__init() < 0) | 309 | if (symbol__init() < 0) |
310 | return -1; | 310 | return -1; |
311 | 311 | ||
312 | setup_sorting(annotate_usage, options); | 312 | if (setup_sorting() < 0) |
313 | usage_with_options(annotate_usage, options); | ||
313 | 314 | ||
314 | if (argc) { | 315 | if (argc) { |
315 | /* | 316 | /* |
diff --git a/tools/perf/builtin-diff.c b/tools/perf/builtin-diff.c index 4af0b580b046..d207a97a2db1 100644 --- a/tools/perf/builtin-diff.c +++ b/tools/perf/builtin-diff.c | |||
@@ -605,7 +605,9 @@ int cmd_diff(int argc, const char **argv, const char *prefix __maybe_unused) | |||
605 | 605 | ||
606 | ui_init(); | 606 | ui_init(); |
607 | 607 | ||
608 | setup_sorting(diff_usage, options); | 608 | if (setup_sorting() < 0) |
609 | usage_with_options(diff_usage, options); | ||
610 | |||
609 | setup_pager(); | 611 | setup_pager(); |
610 | 612 | ||
611 | sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list, "dso", NULL); | 613 | sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list, "dso", NULL); |
diff --git a/tools/perf/builtin-evlist.c b/tools/perf/builtin-evlist.c index 85a5e35dd147..05bd9dfe875c 100644 --- a/tools/perf/builtin-evlist.c +++ b/tools/perf/builtin-evlist.c | |||
@@ -39,7 +39,7 @@ int cmd_evlist(int argc, const char **argv, const char *prefix __maybe_unused) | |||
39 | OPT_BOOLEAN('F', "freq", &details.freq, "Show the sample frequency"), | 39 | OPT_BOOLEAN('F', "freq", &details.freq, "Show the sample frequency"), |
40 | OPT_BOOLEAN('v', "verbose", &details.verbose, | 40 | OPT_BOOLEAN('v', "verbose", &details.verbose, |
41 | "Show all event attr details"), | 41 | "Show all event attr details"), |
42 | OPT_BOOLEAN('g', "group", &symbol_conf.event_group, | 42 | OPT_BOOLEAN('g', "group", &details.event_group, |
43 | "Show event group information"), | 43 | "Show event group information"), |
44 | OPT_END() | 44 | OPT_END() |
45 | }; | 45 | }; |
@@ -52,7 +52,7 @@ int cmd_evlist(int argc, const char **argv, const char *prefix __maybe_unused) | |||
52 | if (argc) | 52 | if (argc) |
53 | usage_with_options(evlist_usage, options); | 53 | usage_with_options(evlist_usage, options); |
54 | 54 | ||
55 | if (symbol_conf.event_group && (details.verbose || details.freq)) { | 55 | if (details.event_group && (details.verbose || details.freq)) { |
56 | pr_err("--group option is not compatible with other options\n"); | 56 | pr_err("--group option is not compatible with other options\n"); |
57 | usage_with_options(evlist_usage, options); | 57 | usage_with_options(evlist_usage, options); |
58 | } | 58 | } |
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index 0d221870561a..96b5a7fee4bb 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c | |||
@@ -468,9 +468,17 @@ static int __cmd_report(struct perf_report *rep) | |||
468 | 468 | ||
469 | if (use_browser > 0) { | 469 | if (use_browser > 0) { |
470 | if (use_browser == 1) { | 470 | if (use_browser == 1) { |
471 | perf_evlist__tui_browse_hists(session->evlist, help, | 471 | ret = perf_evlist__tui_browse_hists(session->evlist, |
472 | NULL, | 472 | help, |
473 | &session->header.env); | 473 | NULL, |
474 | &session->header.env); | ||
475 | /* | ||
476 | * Usually "ret" is the last pressed key, and we only | ||
477 | * care if the key notifies us to switch data file. | ||
478 | */ | ||
479 | if (ret != K_SWITCH_INPUT_DATA) | ||
480 | ret = 0; | ||
481 | |||
474 | } else if (use_browser == 2) { | 482 | } else if (use_browser == 2) { |
475 | perf_evlist__gtk_browse_hists(session->evlist, help, | 483 | perf_evlist__gtk_browse_hists(session->evlist, help, |
476 | NULL); | 484 | NULL); |
@@ -708,6 +716,16 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused) | |||
708 | else | 716 | else |
709 | input_name = "perf.data"; | 717 | input_name = "perf.data"; |
710 | } | 718 | } |
719 | |||
720 | if (strcmp(input_name, "-") != 0) | ||
721 | setup_browser(true); | ||
722 | else { | ||
723 | use_browser = 0; | ||
724 | perf_hpp__column_enable(PERF_HPP__OVERHEAD); | ||
725 | perf_hpp__init(); | ||
726 | } | ||
727 | |||
728 | repeat: | ||
711 | session = perf_session__new(input_name, O_RDONLY, | 729 | session = perf_session__new(input_name, O_RDONLY, |
712 | report.force, false, &report.tool); | 730 | report.force, false, &report.tool); |
713 | if (session == NULL) | 731 | if (session == NULL) |
@@ -733,15 +751,8 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused) | |||
733 | 751 | ||
734 | } | 752 | } |
735 | 753 | ||
736 | if (strcmp(input_name, "-") != 0) | 754 | if (setup_sorting() < 0) |
737 | setup_browser(true); | 755 | usage_with_options(report_usage, options); |
738 | else { | ||
739 | use_browser = 0; | ||
740 | perf_hpp__column_enable(PERF_HPP__OVERHEAD); | ||
741 | perf_hpp__init(); | ||
742 | } | ||
743 | |||
744 | setup_sorting(report_usage, options); | ||
745 | 756 | ||
746 | /* | 757 | /* |
747 | * Only in the newt browser we are doing integrated annotation, | 758 | * Only in the newt browser we are doing integrated annotation, |
@@ -809,6 +820,12 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused) | |||
809 | } | 820 | } |
810 | 821 | ||
811 | ret = __cmd_report(&report); | 822 | ret = __cmd_report(&report); |
823 | if (ret == K_SWITCH_INPUT_DATA) { | ||
824 | perf_session__delete(session); | ||
825 | goto repeat; | ||
826 | } else | ||
827 | ret = 0; | ||
828 | |||
812 | error: | 829 | error: |
813 | perf_session__delete(session); | 830 | perf_session__delete(session); |
814 | return ret; | 831 | return ret; |
diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index 0368a1036ad6..99848761f573 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c | |||
@@ -68,6 +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 | 72 | ||
72 | static struct perf_evlist *evsel_list; | 73 | static struct perf_evlist *evsel_list; |
73 | 74 | ||
@@ -79,6 +80,7 @@ static int run_count = 1; | |||
79 | static bool no_inherit = false; | 80 | static bool no_inherit = false; |
80 | static bool scale = true; | 81 | static bool scale = true; |
81 | static bool no_aggr = false; | 82 | static bool no_aggr = false; |
83 | static bool aggr_socket = false; | ||
82 | static pid_t child_pid = -1; | 84 | static pid_t child_pid = -1; |
83 | static bool null_run = false; | 85 | static bool null_run = false; |
84 | static int detailed_run = 0; | 86 | static int detailed_run = 0; |
@@ -93,6 +95,7 @@ static const char *post_cmd = NULL; | |||
93 | static bool sync_run = false; | 95 | static bool sync_run = false; |
94 | static unsigned int interval = 0; | 96 | static unsigned int interval = 0; |
95 | static struct timespec ref_time; | 97 | static struct timespec ref_time; |
98 | static struct cpu_map *sock_map; | ||
96 | 99 | ||
97 | static volatile int done = 0; | 100 | static volatile int done = 0; |
98 | 101 | ||
@@ -312,7 +315,9 @@ static void print_interval(void) | |||
312 | sprintf(prefix, "%6lu.%09lu%s", rs.tv_sec, rs.tv_nsec, csv_sep); | 315 | sprintf(prefix, "%6lu.%09lu%s", rs.tv_sec, rs.tv_nsec, csv_sep); |
313 | 316 | ||
314 | if (num_print_interval == 0 && !csv_output) { | 317 | if (num_print_interval == 0 && !csv_output) { |
315 | if (no_aggr) | 318 | if (aggr_socket) |
319 | fprintf(output, "# time socket cpus counts events\n"); | ||
320 | else if (no_aggr) | ||
316 | fprintf(output, "# time CPU counts events\n"); | 321 | fprintf(output, "# time CPU counts events\n"); |
317 | else | 322 | else |
318 | fprintf(output, "# time counts events\n"); | 323 | fprintf(output, "# time counts events\n"); |
@@ -321,7 +326,9 @@ static void print_interval(void) | |||
321 | if (++num_print_interval == 25) | 326 | if (++num_print_interval == 25) |
322 | num_print_interval = 0; | 327 | num_print_interval = 0; |
323 | 328 | ||
324 | if (no_aggr) { | 329 | if (aggr_socket) |
330 | print_aggr_socket(prefix); | ||
331 | else if (no_aggr) { | ||
325 | list_for_each_entry(counter, &evsel_list->entries, node) | 332 | list_for_each_entry(counter, &evsel_list->entries, node) |
326 | print_counter(counter, prefix); | 333 | print_counter(counter, prefix); |
327 | } else { | 334 | } else { |
@@ -349,6 +356,12 @@ static int __run_perf_stat(int argc __maybe_unused, const char **argv) | |||
349 | ts.tv_nsec = 0; | 356 | ts.tv_nsec = 0; |
350 | } | 357 | } |
351 | 358 | ||
359 | if (aggr_socket | ||
360 | && cpu_map__build_socket_map(evsel_list->cpus, &sock_map)) { | ||
361 | perror("cannot build socket map"); | ||
362 | return -1; | ||
363 | } | ||
364 | |||
352 | if (forks && (pipe(child_ready_pipe) < 0 || pipe(go_pipe) < 0)) { | 365 | if (forks && (pipe(child_ready_pipe) < 0 || pipe(go_pipe) < 0)) { |
353 | perror("failed to create pipes"); | 366 | perror("failed to create pipes"); |
354 | return -1; | 367 | return -1; |
@@ -529,13 +542,21 @@ static void print_noise(struct perf_evsel *evsel, double avg) | |||
529 | print_noise_pct(stddev_stats(&ps->res_stats[0]), avg); | 542 | print_noise_pct(stddev_stats(&ps->res_stats[0]), avg); |
530 | } | 543 | } |
531 | 544 | ||
532 | static void nsec_printout(int cpu, struct perf_evsel *evsel, double avg) | 545 | static void nsec_printout(int cpu, int nr, struct perf_evsel *evsel, double avg) |
533 | { | 546 | { |
534 | double msecs = avg / 1e6; | 547 | double msecs = avg / 1e6; |
535 | char cpustr[16] = { '\0', }; | 548 | char cpustr[16] = { '\0', }; |
536 | const char *fmt = csv_output ? "%s%.6f%s%s" : "%s%18.6f%s%-25s"; | 549 | const char *fmt = csv_output ? "%s%.6f%s%s" : "%s%18.6f%s%-25s"; |
537 | 550 | ||
538 | if (no_aggr) | 551 | if (aggr_socket) |
552 | sprintf(cpustr, "S%*d%s%*d%s", | ||
553 | csv_output ? 0 : -5, | ||
554 | cpu, | ||
555 | csv_sep, | ||
556 | csv_output ? 0 : 4, | ||
557 | nr, | ||
558 | csv_sep); | ||
559 | else if (no_aggr) | ||
539 | sprintf(cpustr, "CPU%*d%s", | 560 | sprintf(cpustr, "CPU%*d%s", |
540 | csv_output ? 0 : -4, | 561 | csv_output ? 0 : -4, |
541 | perf_evsel__cpus(evsel)->map[cpu], csv_sep); | 562 | perf_evsel__cpus(evsel)->map[cpu], csv_sep); |
@@ -734,7 +755,7 @@ static void print_ll_cache_misses(int cpu, | |||
734 | fprintf(output, " of all LL-cache hits "); | 755 | fprintf(output, " of all LL-cache hits "); |
735 | } | 756 | } |
736 | 757 | ||
737 | static void abs_printout(int cpu, struct perf_evsel *evsel, double avg) | 758 | static void abs_printout(int cpu, int nr, struct perf_evsel *evsel, double avg) |
738 | { | 759 | { |
739 | double total, ratio = 0.0; | 760 | double total, ratio = 0.0; |
740 | char cpustr[16] = { '\0', }; | 761 | char cpustr[16] = { '\0', }; |
@@ -747,7 +768,15 @@ static void abs_printout(int cpu, struct perf_evsel *evsel, double avg) | |||
747 | else | 768 | else |
748 | fmt = "%s%18.0f%s%-25s"; | 769 | fmt = "%s%18.0f%s%-25s"; |
749 | 770 | ||
750 | if (no_aggr) | 771 | if (aggr_socket) |
772 | sprintf(cpustr, "S%*d%s%*d%s", | ||
773 | csv_output ? 0 : -5, | ||
774 | cpu, | ||
775 | csv_sep, | ||
776 | csv_output ? 0 : 4, | ||
777 | nr, | ||
778 | csv_sep); | ||
779 | else if (no_aggr) | ||
751 | sprintf(cpustr, "CPU%*d%s", | 780 | sprintf(cpustr, "CPU%*d%s", |
752 | csv_output ? 0 : -4, | 781 | csv_output ? 0 : -4, |
753 | perf_evsel__cpus(evsel)->map[cpu], csv_sep); | 782 | perf_evsel__cpus(evsel)->map[cpu], csv_sep); |
@@ -853,6 +882,70 @@ static void abs_printout(int cpu, struct perf_evsel *evsel, double avg) | |||
853 | } | 882 | } |
854 | } | 883 | } |
855 | 884 | ||
885 | static void print_aggr_socket(char *prefix) | ||
886 | { | ||
887 | struct perf_evsel *counter; | ||
888 | u64 ena, run, val; | ||
889 | int cpu, s, s2, sock, nr; | ||
890 | |||
891 | if (!sock_map) | ||
892 | return; | ||
893 | |||
894 | for (s = 0; s < sock_map->nr; s++) { | ||
895 | sock = cpu_map__socket(sock_map, s); | ||
896 | list_for_each_entry(counter, &evsel_list->entries, node) { | ||
897 | val = ena = run = 0; | ||
898 | nr = 0; | ||
899 | for (cpu = 0; cpu < perf_evsel__nr_cpus(counter); cpu++) { | ||
900 | s2 = cpu_map__get_socket(evsel_list->cpus, cpu); | ||
901 | if (s2 != sock) | ||
902 | continue; | ||
903 | val += counter->counts->cpu[cpu].val; | ||
904 | ena += counter->counts->cpu[cpu].ena; | ||
905 | run += counter->counts->cpu[cpu].run; | ||
906 | nr++; | ||
907 | } | ||
908 | if (prefix) | ||
909 | fprintf(output, "%s", prefix); | ||
910 | |||
911 | if (run == 0 || ena == 0) { | ||
912 | fprintf(output, "S%*d%s%*d%s%*s%s%*s", | ||
913 | csv_output ? 0 : -5, | ||
914 | s, | ||
915 | csv_sep, | ||
916 | csv_output ? 0 : 4, | ||
917 | nr, | ||
918 | csv_sep, | ||
919 | csv_output ? 0 : 18, | ||
920 | counter->supported ? CNTR_NOT_COUNTED : CNTR_NOT_SUPPORTED, | ||
921 | csv_sep, | ||
922 | csv_output ? 0 : -24, | ||
923 | perf_evsel__name(counter)); | ||
924 | if (counter->cgrp) | ||
925 | fprintf(output, "%s%s", | ||
926 | csv_sep, counter->cgrp->name); | ||
927 | |||
928 | fputc('\n', output); | ||
929 | continue; | ||
930 | } | ||
931 | |||
932 | if (nsec_counter(counter)) | ||
933 | nsec_printout(sock, nr, counter, val); | ||
934 | else | ||
935 | abs_printout(sock, nr, counter, val); | ||
936 | |||
937 | if (!csv_output) { | ||
938 | print_noise(counter, 1.0); | ||
939 | |||
940 | if (run != ena) | ||
941 | fprintf(output, " (%.2f%%)", | ||
942 | 100.0 * run / ena); | ||
943 | } | ||
944 | fputc('\n', output); | ||
945 | } | ||
946 | } | ||
947 | } | ||
948 | |||
856 | /* | 949 | /* |
857 | * Print out the results of a single counter: | 950 | * Print out the results of a single counter: |
858 | * aggregated counts in system-wide mode | 951 | * aggregated counts in system-wide mode |
@@ -882,9 +975,9 @@ static void print_counter_aggr(struct perf_evsel *counter, char *prefix) | |||
882 | } | 975 | } |
883 | 976 | ||
884 | if (nsec_counter(counter)) | 977 | if (nsec_counter(counter)) |
885 | nsec_printout(-1, counter, avg); | 978 | nsec_printout(-1, 0, counter, avg); |
886 | else | 979 | else |
887 | abs_printout(-1, counter, avg); | 980 | abs_printout(-1, 0, counter, avg); |
888 | 981 | ||
889 | print_noise(counter, avg); | 982 | print_noise(counter, avg); |
890 | 983 | ||
@@ -940,9 +1033,9 @@ static void print_counter(struct perf_evsel *counter, char *prefix) | |||
940 | } | 1033 | } |
941 | 1034 | ||
942 | if (nsec_counter(counter)) | 1035 | if (nsec_counter(counter)) |
943 | nsec_printout(cpu, counter, val); | 1036 | nsec_printout(cpu, 0, counter, val); |
944 | else | 1037 | else |
945 | abs_printout(cpu, counter, val); | 1038 | abs_printout(cpu, 0, counter, val); |
946 | 1039 | ||
947 | if (!csv_output) { | 1040 | if (!csv_output) { |
948 | print_noise(counter, 1.0); | 1041 | print_noise(counter, 1.0); |
@@ -980,7 +1073,9 @@ static void print_stat(int argc, const char **argv) | |||
980 | fprintf(output, ":\n\n"); | 1073 | fprintf(output, ":\n\n"); |
981 | } | 1074 | } |
982 | 1075 | ||
983 | if (no_aggr) { | 1076 | if (aggr_socket) |
1077 | print_aggr_socket(NULL); | ||
1078 | else if (no_aggr) { | ||
984 | list_for_each_entry(counter, &evsel_list->entries, node) | 1079 | list_for_each_entry(counter, &evsel_list->entries, node) |
985 | print_counter(counter, NULL); | 1080 | print_counter(counter, NULL); |
986 | } else { | 1081 | } else { |
@@ -1228,6 +1323,7 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused) | |||
1228 | "command to run after to the measured command"), | 1323 | "command to run after to the measured command"), |
1229 | OPT_UINTEGER('I', "interval-print", &interval, | 1324 | OPT_UINTEGER('I', "interval-print", &interval, |
1230 | "print counts at regular interval in ms (>= 100)"), | 1325 | "print counts at regular interval in ms (>= 100)"), |
1326 | OPT_BOOLEAN(0, "aggr-socket", &aggr_socket, "aggregate counts per processor socket"), | ||
1231 | OPT_END() | 1327 | OPT_END() |
1232 | }; | 1328 | }; |
1233 | const char * const stat_usage[] = { | 1329 | const char * const stat_usage[] = { |
@@ -1314,6 +1410,14 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused) | |||
1314 | usage_with_options(stat_usage, options); | 1410 | usage_with_options(stat_usage, options); |
1315 | } | 1411 | } |
1316 | 1412 | ||
1413 | if (aggr_socket) { | ||
1414 | if (!perf_target__has_cpu(&target)) { | ||
1415 | fprintf(stderr, "--aggr-socket only available in system-wide mode (-a)\n"); | ||
1416 | usage_with_options(stat_usage, options); | ||
1417 | } | ||
1418 | no_aggr = true; | ||
1419 | } | ||
1420 | |||
1317 | if (add_default_attributes()) | 1421 | if (add_default_attributes()) |
1318 | goto out; | 1422 | goto out; |
1319 | 1423 | ||
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index f561757b1bfa..72f6eb7b4173 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c | |||
@@ -1129,7 +1129,8 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused) | |||
1129 | if (sort_order == default_sort_order) | 1129 | if (sort_order == default_sort_order) |
1130 | sort_order = "dso,symbol"; | 1130 | sort_order = "dso,symbol"; |
1131 | 1131 | ||
1132 | setup_sorting(top_usage, options); | 1132 | if (setup_sorting() < 0) |
1133 | usage_with_options(top_usage, options); | ||
1133 | 1134 | ||
1134 | if (top.use_stdio) | 1135 | if (top.use_stdio) |
1135 | use_browser = 0; | 1136 | use_browser = 0; |
diff --git a/tools/perf/perf.h b/tools/perf/perf.h index 8f3bf388e414..c2206c87fc9f 100644 --- a/tools/perf/perf.h +++ b/tools/perf/perf.h | |||
@@ -103,32 +103,6 @@ | |||
103 | #include "util/types.h" | 103 | #include "util/types.h" |
104 | #include <stdbool.h> | 104 | #include <stdbool.h> |
105 | 105 | ||
106 | struct perf_mmap { | ||
107 | void *base; | ||
108 | int mask; | ||
109 | unsigned int prev; | ||
110 | }; | ||
111 | |||
112 | static inline unsigned int perf_mmap__read_head(struct perf_mmap *mm) | ||
113 | { | ||
114 | struct perf_event_mmap_page *pc = mm->base; | ||
115 | int head = pc->data_head; | ||
116 | rmb(); | ||
117 | return head; | ||
118 | } | ||
119 | |||
120 | static inline void perf_mmap__write_tail(struct perf_mmap *md, | ||
121 | unsigned long tail) | ||
122 | { | ||
123 | struct perf_event_mmap_page *pc = md->base; | ||
124 | |||
125 | /* | ||
126 | * ensure all reads are done before we write the tail out. | ||
127 | */ | ||
128 | /* mb(); */ | ||
129 | pc->data_tail = tail; | ||
130 | } | ||
131 | |||
132 | /* | 106 | /* |
133 | * prctl(PR_TASK_PERF_EVENTS_DISABLE) will (cheaply) disable all | 107 | * prctl(PR_TASK_PERF_EVENTS_DISABLE) will (cheaply) disable all |
134 | * counters in the current task. | 108 | * counters in the current task. |
diff --git a/tools/perf/scripts/perl/rwtop.pl b/tools/perf/scripts/perl/rwtop.pl index 4bb3ecd33472..8b20787021c1 100644 --- a/tools/perf/scripts/perl/rwtop.pl +++ b/tools/perf/scripts/perl/rwtop.pl | |||
@@ -17,6 +17,7 @@ use lib "$ENV{'PERF_EXEC_PATH'}/scripts/perl/Perf-Trace-Util/lib"; | |||
17 | use lib "./Perf-Trace-Util/lib"; | 17 | use lib "./Perf-Trace-Util/lib"; |
18 | use Perf::Trace::Core; | 18 | use Perf::Trace::Core; |
19 | use Perf::Trace::Util; | 19 | use Perf::Trace::Util; |
20 | use POSIX qw/SIGALRM SA_RESTART/; | ||
20 | 21 | ||
21 | my $default_interval = 3; | 22 | my $default_interval = 3; |
22 | my $nlines = 20; | 23 | my $nlines = 20; |
@@ -90,7 +91,10 @@ sub syscalls::sys_enter_write | |||
90 | 91 | ||
91 | sub trace_begin | 92 | sub trace_begin |
92 | { | 93 | { |
93 | $SIG{ALRM} = \&set_print_pending; | 94 | my $sa = POSIX::SigAction->new(\&set_print_pending); |
95 | $sa->flags(SA_RESTART); | ||
96 | $sa->safe(1); | ||
97 | POSIX::sigaction(SIGALRM, $sa) or die "Can't set SIGALRM handler: $!\n"; | ||
94 | alarm 1; | 98 | alarm 1; |
95 | } | 99 | } |
96 | 100 | ||
diff --git a/tools/perf/tests/hists_link.c b/tools/perf/tests/hists_link.c index 0afd9223bde7..1be64a6c5daf 100644 --- a/tools/perf/tests/hists_link.c +++ b/tools/perf/tests/hists_link.c | |||
@@ -449,7 +449,8 @@ int test__hists_link(void) | |||
449 | goto out; | 449 | goto out; |
450 | 450 | ||
451 | /* default sort order (comm,dso,sym) will be used */ | 451 | /* default sort order (comm,dso,sym) will be used */ |
452 | setup_sorting(NULL, NULL); | 452 | if (setup_sorting() < 0) |
453 | goto out; | ||
453 | 454 | ||
454 | machines__init(&machines); | 455 | machines__init(&machines); |
455 | 456 | ||
diff --git a/tools/perf/tests/parse-events.c b/tools/perf/tests/parse-events.c index 80a8daf54a63..c5636f36fe31 100644 --- a/tools/perf/tests/parse-events.c +++ b/tools/perf/tests/parse-events.c | |||
@@ -577,7 +577,7 @@ static int test__group2(struct perf_evlist *evlist) | |||
577 | TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user); | 577 | TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user); |
578 | TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel); | 578 | TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel); |
579 | TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv); | 579 | TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv); |
580 | TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest); | 580 | TEST_ASSERT_VAL("wrong exclude guest", evsel->attr.exclude_guest); |
581 | TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host); | 581 | TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host); |
582 | TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); | 582 | TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); |
583 | TEST_ASSERT_VAL("wrong leader", evsel->leader == leader); | 583 | TEST_ASSERT_VAL("wrong leader", evsel->leader == leader); |
@@ -811,6 +811,166 @@ static int test__group5(struct perf_evlist *evlist __maybe_unused) | |||
811 | return 0; | 811 | return 0; |
812 | } | 812 | } |
813 | 813 | ||
814 | static int test__group_gh1(struct perf_evlist *evlist) | ||
815 | { | ||
816 | struct perf_evsel *evsel, *leader; | ||
817 | |||
818 | TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->nr_entries); | ||
819 | TEST_ASSERT_VAL("wrong number of groups", 1 == evlist->nr_groups); | ||
820 | |||
821 | /* cycles + :H group modifier */ | ||
822 | evsel = leader = perf_evlist__first(evlist); | ||
823 | TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->attr.type); | ||
824 | TEST_ASSERT_VAL("wrong config", | ||
825 | PERF_COUNT_HW_CPU_CYCLES == evsel->attr.config); | ||
826 | TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user); | ||
827 | TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel); | ||
828 | TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv); | ||
829 | TEST_ASSERT_VAL("wrong exclude guest", evsel->attr.exclude_guest); | ||
830 | TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host); | ||
831 | TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); | ||
832 | TEST_ASSERT_VAL("wrong group name", !evsel->group_name); | ||
833 | TEST_ASSERT_VAL("wrong leader", perf_evsel__is_group_leader(evsel)); | ||
834 | TEST_ASSERT_VAL("wrong nr_members", evsel->nr_members == 2); | ||
835 | TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 0); | ||
836 | |||
837 | /* cache-misses:G + :H group modifier */ | ||
838 | evsel = perf_evsel__next(evsel); | ||
839 | TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->attr.type); | ||
840 | TEST_ASSERT_VAL("wrong config", | ||
841 | PERF_COUNT_HW_CACHE_MISSES == evsel->attr.config); | ||
842 | TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user); | ||
843 | TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel); | ||
844 | TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv); | ||
845 | TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest); | ||
846 | TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host); | ||
847 | TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); | ||
848 | TEST_ASSERT_VAL("wrong leader", evsel->leader == leader); | ||
849 | TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 1); | ||
850 | |||
851 | return 0; | ||
852 | } | ||
853 | |||
854 | static int test__group_gh2(struct perf_evlist *evlist) | ||
855 | { | ||
856 | struct perf_evsel *evsel, *leader; | ||
857 | |||
858 | TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->nr_entries); | ||
859 | TEST_ASSERT_VAL("wrong number of groups", 1 == evlist->nr_groups); | ||
860 | |||
861 | /* cycles + :G group modifier */ | ||
862 | evsel = leader = perf_evlist__first(evlist); | ||
863 | TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->attr.type); | ||
864 | TEST_ASSERT_VAL("wrong config", | ||
865 | PERF_COUNT_HW_CPU_CYCLES == evsel->attr.config); | ||
866 | TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user); | ||
867 | TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel); | ||
868 | TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv); | ||
869 | TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest); | ||
870 | TEST_ASSERT_VAL("wrong exclude host", evsel->attr.exclude_host); | ||
871 | TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); | ||
872 | TEST_ASSERT_VAL("wrong group name", !evsel->group_name); | ||
873 | TEST_ASSERT_VAL("wrong leader", perf_evsel__is_group_leader(evsel)); | ||
874 | TEST_ASSERT_VAL("wrong nr_members", evsel->nr_members == 2); | ||
875 | TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 0); | ||
876 | |||
877 | /* cache-misses:H + :G group modifier */ | ||
878 | evsel = perf_evsel__next(evsel); | ||
879 | TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->attr.type); | ||
880 | TEST_ASSERT_VAL("wrong config", | ||
881 | PERF_COUNT_HW_CACHE_MISSES == evsel->attr.config); | ||
882 | TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user); | ||
883 | TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel); | ||
884 | TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv); | ||
885 | TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest); | ||
886 | TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host); | ||
887 | TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); | ||
888 | TEST_ASSERT_VAL("wrong leader", evsel->leader == leader); | ||
889 | TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 1); | ||
890 | |||
891 | return 0; | ||
892 | } | ||
893 | |||
894 | static int test__group_gh3(struct perf_evlist *evlist) | ||
895 | { | ||
896 | struct perf_evsel *evsel, *leader; | ||
897 | |||
898 | TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->nr_entries); | ||
899 | TEST_ASSERT_VAL("wrong number of groups", 1 == evlist->nr_groups); | ||
900 | |||
901 | /* cycles:G + :u group modifier */ | ||
902 | evsel = leader = perf_evlist__first(evlist); | ||
903 | TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->attr.type); | ||
904 | TEST_ASSERT_VAL("wrong config", | ||
905 | PERF_COUNT_HW_CPU_CYCLES == evsel->attr.config); | ||
906 | TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user); | ||
907 | TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel); | ||
908 | TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv); | ||
909 | TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest); | ||
910 | TEST_ASSERT_VAL("wrong exclude host", evsel->attr.exclude_host); | ||
911 | TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); | ||
912 | TEST_ASSERT_VAL("wrong group name", !evsel->group_name); | ||
913 | TEST_ASSERT_VAL("wrong leader", perf_evsel__is_group_leader(evsel)); | ||
914 | TEST_ASSERT_VAL("wrong nr_members", evsel->nr_members == 2); | ||
915 | TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 0); | ||
916 | |||
917 | /* cache-misses:H + :u group modifier */ | ||
918 | evsel = perf_evsel__next(evsel); | ||
919 | TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->attr.type); | ||
920 | TEST_ASSERT_VAL("wrong config", | ||
921 | PERF_COUNT_HW_CACHE_MISSES == evsel->attr.config); | ||
922 | TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user); | ||
923 | TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel); | ||
924 | TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv); | ||
925 | TEST_ASSERT_VAL("wrong exclude guest", evsel->attr.exclude_guest); | ||
926 | TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host); | ||
927 | TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); | ||
928 | TEST_ASSERT_VAL("wrong leader", evsel->leader == leader); | ||
929 | TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 1); | ||
930 | |||
931 | return 0; | ||
932 | } | ||
933 | |||
934 | static int test__group_gh4(struct perf_evlist *evlist) | ||
935 | { | ||
936 | struct perf_evsel *evsel, *leader; | ||
937 | |||
938 | TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->nr_entries); | ||
939 | TEST_ASSERT_VAL("wrong number of groups", 1 == evlist->nr_groups); | ||
940 | |||
941 | /* cycles:G + :uG group modifier */ | ||
942 | evsel = leader = perf_evlist__first(evlist); | ||
943 | TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->attr.type); | ||
944 | TEST_ASSERT_VAL("wrong config", | ||
945 | PERF_COUNT_HW_CPU_CYCLES == evsel->attr.config); | ||
946 | TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user); | ||
947 | TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel); | ||
948 | TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv); | ||
949 | TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest); | ||
950 | TEST_ASSERT_VAL("wrong exclude host", evsel->attr.exclude_host); | ||
951 | TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); | ||
952 | TEST_ASSERT_VAL("wrong group name", !evsel->group_name); | ||
953 | TEST_ASSERT_VAL("wrong leader", perf_evsel__is_group_leader(evsel)); | ||
954 | TEST_ASSERT_VAL("wrong nr_members", evsel->nr_members == 2); | ||
955 | TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 0); | ||
956 | |||
957 | /* cache-misses:H + :uG group modifier */ | ||
958 | evsel = perf_evsel__next(evsel); | ||
959 | TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->attr.type); | ||
960 | TEST_ASSERT_VAL("wrong config", | ||
961 | PERF_COUNT_HW_CACHE_MISSES == evsel->attr.config); | ||
962 | TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user); | ||
963 | TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel); | ||
964 | TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv); | ||
965 | TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest); | ||
966 | TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host); | ||
967 | TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); | ||
968 | TEST_ASSERT_VAL("wrong leader", evsel->leader == leader); | ||
969 | TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 1); | ||
970 | |||
971 | return 0; | ||
972 | } | ||
973 | |||
814 | static int count_tracepoints(void) | 974 | static int count_tracepoints(void) |
815 | { | 975 | { |
816 | char events_path[PATH_MAX]; | 976 | char events_path[PATH_MAX]; |
@@ -1011,6 +1171,22 @@ static struct evlist_test test__events[] = { | |||
1011 | .name = "*:*", | 1171 | .name = "*:*", |
1012 | .check = test__all_tracepoints, | 1172 | .check = test__all_tracepoints, |
1013 | }, | 1173 | }, |
1174 | [34] = { | ||
1175 | .name = "{cycles,cache-misses:G}:H", | ||
1176 | .check = test__group_gh1, | ||
1177 | }, | ||
1178 | [35] = { | ||
1179 | .name = "{cycles,cache-misses:H}:G", | ||
1180 | .check = test__group_gh2, | ||
1181 | }, | ||
1182 | [36] = { | ||
1183 | .name = "{cycles:G,cache-misses:H}:u", | ||
1184 | .check = test__group_gh3, | ||
1185 | }, | ||
1186 | [37] = { | ||
1187 | .name = "{cycles:G,cache-misses:H}:uG", | ||
1188 | .check = test__group_gh4, | ||
1189 | }, | ||
1014 | }; | 1190 | }; |
1015 | 1191 | ||
1016 | static struct evlist_test test__events_pmu[] = { | 1192 | static struct evlist_test test__events_pmu[] = { |
diff --git a/tools/perf/ui/browsers/hists.c b/tools/perf/ui/browsers/hists.c index 20ccd57753f7..aa22704047d6 100644 --- a/tools/perf/ui/browsers/hists.c +++ b/tools/perf/ui/browsers/hists.c | |||
@@ -1241,6 +1241,96 @@ static inline bool is_report_browser(void *timer) | |||
1241 | return timer == NULL; | 1241 | return timer == NULL; |
1242 | } | 1242 | } |
1243 | 1243 | ||
1244 | /* | ||
1245 | * Only runtime switching of perf data file will make "input_name" point | ||
1246 | * to a malloced buffer. So add "is_input_name_malloced" flag to decide | ||
1247 | * whether we need to call free() for current "input_name" during the switch. | ||
1248 | */ | ||
1249 | static bool is_input_name_malloced = false; | ||
1250 | |||
1251 | static int switch_data_file(void) | ||
1252 | { | ||
1253 | char *pwd, *options[32], *abs_path[32], *tmp; | ||
1254 | DIR *pwd_dir; | ||
1255 | int nr_options = 0, choice = -1, ret = -1; | ||
1256 | struct dirent *dent; | ||
1257 | |||
1258 | pwd = getenv("PWD"); | ||
1259 | if (!pwd) | ||
1260 | return ret; | ||
1261 | |||
1262 | pwd_dir = opendir(pwd); | ||
1263 | if (!pwd_dir) | ||
1264 | return ret; | ||
1265 | |||
1266 | memset(options, 0, sizeof(options)); | ||
1267 | memset(options, 0, sizeof(abs_path)); | ||
1268 | |||
1269 | while ((dent = readdir(pwd_dir))) { | ||
1270 | char path[PATH_MAX]; | ||
1271 | u64 magic; | ||
1272 | char *name = dent->d_name; | ||
1273 | FILE *file; | ||
1274 | |||
1275 | if (!(dent->d_type == DT_REG)) | ||
1276 | continue; | ||
1277 | |||
1278 | snprintf(path, sizeof(path), "%s/%s", pwd, name); | ||
1279 | |||
1280 | file = fopen(path, "r"); | ||
1281 | if (!file) | ||
1282 | continue; | ||
1283 | |||
1284 | if (fread(&magic, 1, 8, file) < 8) | ||
1285 | goto close_file_and_continue; | ||
1286 | |||
1287 | if (is_perf_magic(magic)) { | ||
1288 | options[nr_options] = strdup(name); | ||
1289 | if (!options[nr_options]) | ||
1290 | goto close_file_and_continue; | ||
1291 | |||
1292 | abs_path[nr_options] = strdup(path); | ||
1293 | if (!abs_path[nr_options]) { | ||
1294 | free(options[nr_options]); | ||
1295 | ui__warning("Can't search all data files due to memory shortage.\n"); | ||
1296 | fclose(file); | ||
1297 | break; | ||
1298 | } | ||
1299 | |||
1300 | nr_options++; | ||
1301 | } | ||
1302 | |||
1303 | close_file_and_continue: | ||
1304 | fclose(file); | ||
1305 | if (nr_options >= 32) { | ||
1306 | ui__warning("Too many perf data files in PWD!\n" | ||
1307 | "Only the first 32 files will be listed.\n"); | ||
1308 | break; | ||
1309 | } | ||
1310 | } | ||
1311 | closedir(pwd_dir); | ||
1312 | |||
1313 | if (nr_options) { | ||
1314 | choice = ui__popup_menu(nr_options, options); | ||
1315 | if (choice < nr_options && choice >= 0) { | ||
1316 | tmp = strdup(abs_path[choice]); | ||
1317 | if (tmp) { | ||
1318 | if (is_input_name_malloced) | ||
1319 | free((void *)input_name); | ||
1320 | input_name = tmp; | ||
1321 | is_input_name_malloced = true; | ||
1322 | ret = 0; | ||
1323 | } else | ||
1324 | ui__warning("Data switch failed due to memory shortage!\n"); | ||
1325 | } | ||
1326 | } | ||
1327 | |||
1328 | free_popup_options(options, nr_options); | ||
1329 | free_popup_options(abs_path, nr_options); | ||
1330 | return ret; | ||
1331 | } | ||
1332 | |||
1333 | |||
1244 | static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events, | 1334 | static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events, |
1245 | const char *helpline, const char *ev_name, | 1335 | const char *helpline, const char *ev_name, |
1246 | bool left_exits, | 1336 | bool left_exits, |
@@ -1275,7 +1365,8 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events, | |||
1275 | int choice = 0, | 1365 | int choice = 0, |
1276 | annotate = -2, zoom_dso = -2, zoom_thread = -2, | 1366 | annotate = -2, zoom_dso = -2, zoom_thread = -2, |
1277 | annotate_f = -2, annotate_t = -2, browse_map = -2; | 1367 | annotate_f = -2, annotate_t = -2, browse_map = -2; |
1278 | int scripts_comm = -2, scripts_symbol = -2, scripts_all = -2; | 1368 | int scripts_comm = -2, scripts_symbol = -2, |
1369 | scripts_all = -2, switch_data = -2; | ||
1279 | 1370 | ||
1280 | nr_options = 0; | 1371 | nr_options = 0; |
1281 | 1372 | ||
@@ -1332,6 +1423,10 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events, | |||
1332 | if (is_report_browser(hbt)) | 1423 | if (is_report_browser(hbt)) |
1333 | goto do_scripts; | 1424 | goto do_scripts; |
1334 | continue; | 1425 | continue; |
1426 | case 's': | ||
1427 | if (is_report_browser(hbt)) | ||
1428 | goto do_data_switch; | ||
1429 | continue; | ||
1335 | case K_F1: | 1430 | case K_F1: |
1336 | case 'h': | 1431 | case 'h': |
1337 | case '?': | 1432 | case '?': |
@@ -1351,6 +1446,7 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events, | |||
1351 | "d Zoom into current DSO\n" | 1446 | "d Zoom into current DSO\n" |
1352 | "t Zoom into current Thread\n" | 1447 | "t Zoom into current Thread\n" |
1353 | "r Run available scripts('perf report' only)\n" | 1448 | "r Run available scripts('perf report' only)\n" |
1449 | "s Switch to another data file in PWD ('perf report' only)\n" | ||
1354 | "P Print histograms to perf.hist.N\n" | 1450 | "P Print histograms to perf.hist.N\n" |
1355 | "V Verbose (DSO names in callchains, etc)\n" | 1451 | "V Verbose (DSO names in callchains, etc)\n" |
1356 | "/ Filter symbol by name"); | 1452 | "/ Filter symbol by name"); |
@@ -1458,6 +1554,9 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events, | |||
1458 | if (asprintf(&options[nr_options], "Run scripts for all samples") > 0) | 1554 | if (asprintf(&options[nr_options], "Run scripts for all samples") > 0) |
1459 | scripts_all = nr_options++; | 1555 | scripts_all = nr_options++; |
1460 | 1556 | ||
1557 | if (is_report_browser(hbt) && asprintf(&options[nr_options], | ||
1558 | "Switch to another data file in PWD") > 0) | ||
1559 | switch_data = nr_options++; | ||
1461 | add_exit_option: | 1560 | add_exit_option: |
1462 | options[nr_options++] = (char *)"Exit"; | 1561 | options[nr_options++] = (char *)"Exit"; |
1463 | retry_popup_menu: | 1562 | retry_popup_menu: |
@@ -1568,6 +1667,16 @@ do_scripts: | |||
1568 | 1667 | ||
1569 | script_browse(script_opt); | 1668 | script_browse(script_opt); |
1570 | } | 1669 | } |
1670 | /* Switch to another data file */ | ||
1671 | else if (choice == switch_data) { | ||
1672 | do_data_switch: | ||
1673 | if (!switch_data_file()) { | ||
1674 | key = K_SWITCH_INPUT_DATA; | ||
1675 | break; | ||
1676 | } else | ||
1677 | ui__warning("Won't switch the data files due to\n" | ||
1678 | "no valid data file get selected!\n"); | ||
1679 | } | ||
1571 | } | 1680 | } |
1572 | out_free_stack: | 1681 | out_free_stack: |
1573 | pstack__delete(fstack); | 1682 | pstack__delete(fstack); |
@@ -1694,6 +1803,7 @@ browse_hists: | |||
1694 | "Do you really want to exit?")) | 1803 | "Do you really want to exit?")) |
1695 | continue; | 1804 | continue; |
1696 | /* Fall thru */ | 1805 | /* Fall thru */ |
1806 | case K_SWITCH_INPUT_DATA: | ||
1697 | case 'q': | 1807 | case 'q': |
1698 | case CTRL('c'): | 1808 | case CTRL('c'): |
1699 | goto out; | 1809 | goto out; |
diff --git a/tools/perf/ui/hist.c b/tools/perf/ui/hist.c index a47ce98c2cb1..d671e63aa351 100644 --- a/tools/perf/ui/hist.c +++ b/tools/perf/ui/hist.c | |||
@@ -9,18 +9,24 @@ | |||
9 | 9 | ||
10 | typedef int (*hpp_snprint_fn)(char *buf, size_t size, const char *fmt, ...); | 10 | typedef int (*hpp_snprint_fn)(char *buf, size_t size, const char *fmt, ...); |
11 | 11 | ||
12 | static int __hpp__percent_fmt(struct perf_hpp *hpp, struct hist_entry *he, | 12 | static int __hpp__fmt(struct perf_hpp *hpp, struct hist_entry *he, |
13 | u64 (*get_field)(struct hist_entry *), | 13 | u64 (*get_field)(struct hist_entry *), |
14 | const char *fmt, hpp_snprint_fn print_fn) | 14 | const char *fmt, hpp_snprint_fn print_fn, |
15 | bool fmt_percent) | ||
15 | { | 16 | { |
16 | int ret; | 17 | int ret; |
17 | double percent = 0.0; | ||
18 | struct hists *hists = he->hists; | 18 | struct hists *hists = he->hists; |
19 | 19 | ||
20 | if (hists->stats.total_period) | 20 | if (fmt_percent) { |
21 | percent = 100.0 * get_field(he) / hists->stats.total_period; | 21 | double percent = 0.0; |
22 | |||
23 | if (hists->stats.total_period) | ||
24 | percent = 100.0 * get_field(he) / | ||
25 | hists->stats.total_period; | ||
22 | 26 | ||
23 | ret = print_fn(hpp->buf, hpp->size, fmt, percent); | 27 | ret = print_fn(hpp->buf, hpp->size, fmt, percent); |
28 | } else | ||
29 | ret = print_fn(hpp->buf, hpp->size, fmt, get_field(he)); | ||
24 | 30 | ||
25 | if (symbol_conf.event_group) { | 31 | if (symbol_conf.event_group) { |
26 | int prev_idx, idx_delta; | 32 | int prev_idx, idx_delta; |
@@ -49,11 +55,15 @@ static int __hpp__percent_fmt(struct perf_hpp *hpp, struct hist_entry *he, | |||
49 | * have no sample | 55 | * have no sample |
50 | */ | 56 | */ |
51 | ret += print_fn(hpp->buf + ret, hpp->size - ret, | 57 | ret += print_fn(hpp->buf + ret, hpp->size - ret, |
52 | fmt, 0.0); | 58 | fmt, 0); |
53 | } | 59 | } |
54 | 60 | ||
55 | ret += print_fn(hpp->buf + ret, hpp->size - ret, | 61 | if (fmt_percent) |
56 | fmt, 100.0 * period / total); | 62 | ret += print_fn(hpp->buf + ret, hpp->size - ret, |
63 | fmt, 100.0 * period / total); | ||
64 | else | ||
65 | ret += print_fn(hpp->buf + ret, hpp->size - ret, | ||
66 | fmt, period); | ||
57 | 67 | ||
58 | prev_idx = perf_evsel__group_idx(evsel); | 68 | prev_idx = perf_evsel__group_idx(evsel); |
59 | } | 69 | } |
@@ -65,23 +75,12 @@ static int __hpp__percent_fmt(struct perf_hpp *hpp, struct hist_entry *he, | |||
65 | * zero-fill group members at last which have no sample | 75 | * zero-fill group members at last which have no sample |
66 | */ | 76 | */ |
67 | ret += print_fn(hpp->buf + ret, hpp->size - ret, | 77 | ret += print_fn(hpp->buf + ret, hpp->size - ret, |
68 | fmt, 0.0); | 78 | fmt, 0); |
69 | } | 79 | } |
70 | } | 80 | } |
71 | return ret; | 81 | return ret; |
72 | } | 82 | } |
73 | 83 | ||
74 | static int __hpp__raw_fmt(struct perf_hpp *hpp, struct hist_entry *he, | ||
75 | u64 (*get_field)(struct hist_entry *), | ||
76 | const char *fmt, hpp_snprint_fn print_fn) | ||
77 | { | ||
78 | int ret; | ||
79 | |||
80 | ret = print_fn(hpp->buf, hpp->size, fmt, get_field(he)); | ||
81 | return ret; | ||
82 | } | ||
83 | |||
84 | |||
85 | #define __HPP_HEADER_FN(_type, _str, _min_width, _unit_width) \ | 84 | #define __HPP_HEADER_FN(_type, _str, _min_width, _unit_width) \ |
86 | static int hpp__header_##_type(struct perf_hpp *hpp) \ | 85 | static int hpp__header_##_type(struct perf_hpp *hpp) \ |
87 | { \ | 86 | { \ |
@@ -116,16 +115,16 @@ static u64 he_get_##_field(struct hist_entry *he) \ | |||
116 | \ | 115 | \ |
117 | static int hpp__color_##_type(struct perf_hpp *hpp, struct hist_entry *he) \ | 116 | static int hpp__color_##_type(struct perf_hpp *hpp, struct hist_entry *he) \ |
118 | { \ | 117 | { \ |
119 | return __hpp__percent_fmt(hpp, he, he_get_##_field, " %6.2f%%", \ | 118 | return __hpp__fmt(hpp, he, he_get_##_field, " %6.2f%%", \ |
120 | (hpp_snprint_fn)percent_color_snprintf); \ | 119 | (hpp_snprint_fn)percent_color_snprintf, true); \ |
121 | } | 120 | } |
122 | 121 | ||
123 | #define __HPP_ENTRY_PERCENT_FN(_type, _field) \ | 122 | #define __HPP_ENTRY_PERCENT_FN(_type, _field) \ |
124 | static int hpp__entry_##_type(struct perf_hpp *hpp, struct hist_entry *he) \ | 123 | static int hpp__entry_##_type(struct perf_hpp *hpp, struct hist_entry *he) \ |
125 | { \ | 124 | { \ |
126 | const char *fmt = symbol_conf.field_sep ? " %.2f" : " %6.2f%%"; \ | 125 | const char *fmt = symbol_conf.field_sep ? " %.2f" : " %6.2f%%"; \ |
127 | return __hpp__percent_fmt(hpp, he, he_get_##_field, fmt, \ | 126 | return __hpp__fmt(hpp, he, he_get_##_field, fmt, \ |
128 | scnprintf); \ | 127 | scnprintf, true); \ |
129 | } | 128 | } |
130 | 129 | ||
131 | #define __HPP_ENTRY_RAW_FN(_type, _field) \ | 130 | #define __HPP_ENTRY_RAW_FN(_type, _field) \ |
@@ -137,7 +136,7 @@ static u64 he_get_raw_##_field(struct hist_entry *he) \ | |||
137 | static int hpp__entry_##_type(struct perf_hpp *hpp, struct hist_entry *he) \ | 136 | static int hpp__entry_##_type(struct perf_hpp *hpp, struct hist_entry *he) \ |
138 | { \ | 137 | { \ |
139 | const char *fmt = symbol_conf.field_sep ? " %"PRIu64 : " %11"PRIu64; \ | 138 | const char *fmt = symbol_conf.field_sep ? " %"PRIu64 : " %11"PRIu64; \ |
140 | return __hpp__raw_fmt(hpp, he, he_get_raw_##_field, fmt, scnprintf); \ | 139 | return __hpp__fmt(hpp, he, he_get_raw_##_field, fmt, scnprintf, false); \ |
141 | } | 140 | } |
142 | 141 | ||
143 | #define HPP_PERCENT_FNS(_type, _str, _field, _min_width, _unit_width) \ | 142 | #define HPP_PERCENT_FNS(_type, _str, _field, _min_width, _unit_width) \ |
diff --git a/tools/perf/ui/keysyms.h b/tools/perf/ui/keysyms.h index 809eca5707fa..65092d576b4e 100644 --- a/tools/perf/ui/keysyms.h +++ b/tools/perf/ui/keysyms.h | |||
@@ -23,5 +23,6 @@ | |||
23 | #define K_TIMER -1 | 23 | #define K_TIMER -1 |
24 | #define K_ERROR -2 | 24 | #define K_ERROR -2 |
25 | #define K_RESIZE -3 | 25 | #define K_RESIZE -3 |
26 | #define K_SWITCH_INPUT_DATA -4 | ||
26 | 27 | ||
27 | #endif /* _PERF_KEYSYMS_H_ */ | 28 | #endif /* _PERF_KEYSYMS_H_ */ |
diff --git a/tools/perf/util/callchain.c b/tools/perf/util/callchain.c index d3b3f5d82137..42b6a632fe7b 100644 --- a/tools/perf/util/callchain.c +++ b/tools/perf/util/callchain.c | |||
@@ -444,7 +444,7 @@ int callchain_cursor_append(struct callchain_cursor *cursor, | |||
444 | struct callchain_cursor_node *node = *cursor->last; | 444 | struct callchain_cursor_node *node = *cursor->last; |
445 | 445 | ||
446 | if (!node) { | 446 | if (!node) { |
447 | node = calloc(sizeof(*node), 1); | 447 | node = calloc(1, sizeof(*node)); |
448 | if (!node) | 448 | if (!node) |
449 | return -ENOMEM; | 449 | return -ENOMEM; |
450 | 450 | ||
diff --git a/tools/perf/util/cpumap.c b/tools/perf/util/cpumap.c index 2b32ffa9ebdb..f817046e22b1 100644 --- a/tools/perf/util/cpumap.c +++ b/tools/perf/util/cpumap.c | |||
@@ -1,4 +1,5 @@ | |||
1 | #include "util.h" | 1 | #include "util.h" |
2 | #include "sysfs.h" | ||
2 | #include "../perf.h" | 3 | #include "../perf.h" |
3 | #include "cpumap.h" | 4 | #include "cpumap.h" |
4 | #include <assert.h> | 5 | #include <assert.h> |
@@ -201,3 +202,56 @@ void cpu_map__delete(struct cpu_map *map) | |||
201 | { | 202 | { |
202 | free(map); | 203 | free(map); |
203 | } | 204 | } |
205 | |||
206 | int cpu_map__get_socket(struct cpu_map *map, int idx) | ||
207 | { | ||
208 | FILE *fp; | ||
209 | const char *mnt; | ||
210 | char path[PATH_MAX]; | ||
211 | int cpu, ret; | ||
212 | |||
213 | if (idx > map->nr) | ||
214 | return -1; | ||
215 | |||
216 | cpu = map->map[idx]; | ||
217 | |||
218 | mnt = sysfs_find_mountpoint(); | ||
219 | if (!mnt) | ||
220 | return -1; | ||
221 | |||
222 | sprintf(path, | ||
223 | "%s/devices/system/cpu/cpu%d/topology/physical_package_id", | ||
224 | mnt, cpu); | ||
225 | |||
226 | fp = fopen(path, "r"); | ||
227 | if (!fp) | ||
228 | return -1; | ||
229 | ret = fscanf(fp, "%d", &cpu); | ||
230 | fclose(fp); | ||
231 | return ret == 1 ? cpu : -1; | ||
232 | } | ||
233 | |||
234 | int cpu_map__build_socket_map(struct cpu_map *cpus, struct cpu_map **sockp) | ||
235 | { | ||
236 | struct cpu_map *sock; | ||
237 | int nr = cpus->nr; | ||
238 | int cpu, s1, s2; | ||
239 | |||
240 | sock = calloc(1, sizeof(*sock) + nr * sizeof(int)); | ||
241 | if (!sock) | ||
242 | return -1; | ||
243 | |||
244 | for (cpu = 0; cpu < nr; cpu++) { | ||
245 | s1 = cpu_map__get_socket(cpus, cpu); | ||
246 | for (s2 = 0; s2 < sock->nr; s2++) { | ||
247 | if (s1 == sock->map[s2]) | ||
248 | break; | ||
249 | } | ||
250 | if (s2 == sock->nr) { | ||
251 | sock->map[sock->nr] = s1; | ||
252 | sock->nr++; | ||
253 | } | ||
254 | } | ||
255 | *sockp = sock; | ||
256 | return 0; | ||
257 | } | ||
diff --git a/tools/perf/util/cpumap.h b/tools/perf/util/cpumap.h index 2f68a3b8c285..161b00756a12 100644 --- a/tools/perf/util/cpumap.h +++ b/tools/perf/util/cpumap.h | |||
@@ -14,6 +14,15 @@ struct cpu_map *cpu_map__dummy_new(void); | |||
14 | void cpu_map__delete(struct cpu_map *map); | 14 | void cpu_map__delete(struct cpu_map *map); |
15 | struct cpu_map *cpu_map__read(FILE *file); | 15 | struct cpu_map *cpu_map__read(FILE *file); |
16 | size_t cpu_map__fprintf(struct cpu_map *map, FILE *fp); | 16 | size_t cpu_map__fprintf(struct cpu_map *map, FILE *fp); |
17 | int cpu_map__get_socket(struct cpu_map *map, int idx); | ||
18 | int cpu_map__build_socket_map(struct cpu_map *cpus, struct cpu_map **sockp); | ||
19 | |||
20 | static inline int cpu_map__socket(struct cpu_map *sock, int s) | ||
21 | { | ||
22 | if (!sock || s > sock->nr || s < 0) | ||
23 | return 0; | ||
24 | return sock->map[s]; | ||
25 | } | ||
17 | 26 | ||
18 | static inline int cpu_map__nr(const struct cpu_map *map) | 27 | static inline int cpu_map__nr(const struct cpu_map *map) |
19 | { | 28 | { |
diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c index eddd5ebcd690..bc4ad7977438 100644 --- a/tools/perf/util/evlist.c +++ b/tools/perf/util/evlist.c | |||
@@ -122,8 +122,7 @@ void __perf_evlist__set_leader(struct list_head *list) | |||
122 | leader->nr_members = evsel->idx - leader->idx + 1; | 122 | leader->nr_members = evsel->idx - leader->idx + 1; |
123 | 123 | ||
124 | list_for_each_entry(evsel, list, node) { | 124 | list_for_each_entry(evsel, list, node) { |
125 | if (evsel != leader) | 125 | evsel->leader = leader; |
126 | evsel->leader = leader; | ||
127 | } | 126 | } |
128 | } | 127 | } |
129 | 128 | ||
@@ -376,7 +375,7 @@ union perf_event *perf_evlist__mmap_read(struct perf_evlist *evlist, int idx) | |||
376 | if ((old & md->mask) + size != ((old + size) & md->mask)) { | 375 | if ((old & md->mask) + size != ((old + size) & md->mask)) { |
377 | unsigned int offset = old; | 376 | unsigned int offset = old; |
378 | unsigned int len = min(sizeof(*event), size), cpy; | 377 | unsigned int len = min(sizeof(*event), size), cpy; |
379 | void *dst = &evlist->event_copy; | 378 | void *dst = &md->event_copy; |
380 | 379 | ||
381 | do { | 380 | do { |
382 | cpy = min(md->mask + 1 - (offset & md->mask), len); | 381 | cpy = min(md->mask + 1 - (offset & md->mask), len); |
@@ -386,7 +385,7 @@ union perf_event *perf_evlist__mmap_read(struct perf_evlist *evlist, int idx) | |||
386 | len -= cpy; | 385 | len -= cpy; |
387 | } while (len); | 386 | } while (len); |
388 | 387 | ||
389 | event = &evlist->event_copy; | 388 | event = &md->event_copy; |
390 | } | 389 | } |
391 | 390 | ||
392 | old += size; | 391 | old += size; |
diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h index 73579a25a93e..2dd07bd60b4f 100644 --- a/tools/perf/util/evlist.h +++ b/tools/perf/util/evlist.h | |||
@@ -17,6 +17,13 @@ struct perf_record_opts; | |||
17 | #define PERF_EVLIST__HLIST_BITS 8 | 17 | #define PERF_EVLIST__HLIST_BITS 8 |
18 | #define PERF_EVLIST__HLIST_SIZE (1 << PERF_EVLIST__HLIST_BITS) | 18 | #define PERF_EVLIST__HLIST_SIZE (1 << PERF_EVLIST__HLIST_BITS) |
19 | 19 | ||
20 | struct perf_mmap { | ||
21 | void *base; | ||
22 | int mask; | ||
23 | unsigned int prev; | ||
24 | union perf_event event_copy; | ||
25 | }; | ||
26 | |||
20 | struct perf_evlist { | 27 | struct perf_evlist { |
21 | struct list_head entries; | 28 | struct list_head entries; |
22 | struct hlist_head heads[PERF_EVLIST__HLIST_SIZE]; | 29 | struct hlist_head heads[PERF_EVLIST__HLIST_SIZE]; |
@@ -30,7 +37,6 @@ struct perf_evlist { | |||
30 | pid_t pid; | 37 | pid_t pid; |
31 | } workload; | 38 | } workload; |
32 | bool overwrite; | 39 | bool overwrite; |
33 | union perf_event event_copy; | ||
34 | struct perf_mmap *mmap; | 40 | struct perf_mmap *mmap; |
35 | struct pollfd *pollfd; | 41 | struct pollfd *pollfd; |
36 | struct thread_map *threads; | 42 | struct thread_map *threads; |
@@ -136,4 +142,25 @@ static inline struct perf_evsel *perf_evlist__last(struct perf_evlist *evlist) | |||
136 | } | 142 | } |
137 | 143 | ||
138 | size_t perf_evlist__fprintf(struct perf_evlist *evlist, FILE *fp); | 144 | size_t perf_evlist__fprintf(struct perf_evlist *evlist, FILE *fp); |
145 | |||
146 | static inline unsigned int perf_mmap__read_head(struct perf_mmap *mm) | ||
147 | { | ||
148 | struct perf_event_mmap_page *pc = mm->base; | ||
149 | int head = pc->data_head; | ||
150 | rmb(); | ||
151 | return head; | ||
152 | } | ||
153 | |||
154 | static inline void perf_mmap__write_tail(struct perf_mmap *md, | ||
155 | unsigned long tail) | ||
156 | { | ||
157 | struct perf_event_mmap_page *pc = md->base; | ||
158 | |||
159 | /* | ||
160 | * ensure all reads are done before we write the tail out. | ||
161 | */ | ||
162 | /* mb(); */ | ||
163 | pc->data_tail = tail; | ||
164 | } | ||
165 | |||
139 | #endif /* __PERF_EVLIST_H */ | 166 | #endif /* __PERF_EVLIST_H */ |
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index a54701504606..9c82f98f26de 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c | |||
@@ -1391,7 +1391,7 @@ int perf_evsel__fprintf(struct perf_evsel *evsel, | |||
1391 | bool first = true; | 1391 | bool first = true; |
1392 | int printed = 0; | 1392 | int printed = 0; |
1393 | 1393 | ||
1394 | if (symbol_conf.event_group) { | 1394 | if (details->event_group) { |
1395 | struct perf_evsel *pos; | 1395 | struct perf_evsel *pos; |
1396 | 1396 | ||
1397 | if (!perf_evsel__is_group_leader(evsel)) | 1397 | if (!perf_evsel__is_group_leader(evsel)) |
diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h index 8512f6a8a6ea..52021c3087df 100644 --- a/tools/perf/util/evsel.h +++ b/tools/perf/util/evsel.h | |||
@@ -254,6 +254,7 @@ static inline bool perf_evsel__is_group_leader(const struct perf_evsel *evsel) | |||
254 | struct perf_attr_details { | 254 | struct perf_attr_details { |
255 | bool freq; | 255 | bool freq; |
256 | bool verbose; | 256 | bool verbose; |
257 | bool event_group; | ||
257 | }; | 258 | }; |
258 | 259 | ||
259 | int perf_evsel__fprintf(struct perf_evsel *evsel, | 260 | int perf_evsel__fprintf(struct perf_evsel *evsel, |
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index 8022b5254f75..f4bfd79ef6a7 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c | |||
@@ -2253,7 +2253,7 @@ static int perf_header__adds_write(struct perf_header *header, | |||
2253 | if (!nr_sections) | 2253 | if (!nr_sections) |
2254 | return 0; | 2254 | return 0; |
2255 | 2255 | ||
2256 | feat_sec = p = calloc(sizeof(*feat_sec), nr_sections); | 2256 | feat_sec = p = calloc(nr_sections, sizeof(*feat_sec)); |
2257 | if (feat_sec == NULL) | 2257 | if (feat_sec == NULL) |
2258 | return -ENOMEM; | 2258 | return -ENOMEM; |
2259 | 2259 | ||
@@ -2425,7 +2425,7 @@ int perf_header__process_sections(struct perf_header *header, int fd, | |||
2425 | if (!nr_sections) | 2425 | if (!nr_sections) |
2426 | return 0; | 2426 | return 0; |
2427 | 2427 | ||
2428 | feat_sec = sec = calloc(sizeof(*feat_sec), nr_sections); | 2428 | feat_sec = sec = calloc(nr_sections, sizeof(*feat_sec)); |
2429 | if (!feat_sec) | 2429 | if (!feat_sec) |
2430 | return -1; | 2430 | return -1; |
2431 | 2431 | ||
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index 4e0f5c2a9fda..c84f48cf9678 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c | |||
@@ -699,14 +699,6 @@ static int get_event_modifier(struct event_modifier *mod, char *str, | |||
699 | int exclude = eu | ek | eh; | 699 | int exclude = eu | ek | eh; |
700 | int exclude_GH = evsel ? evsel->exclude_GH : 0; | 700 | int exclude_GH = evsel ? evsel->exclude_GH : 0; |
701 | 701 | ||
702 | /* | ||
703 | * We are here for group and 'GH' was not set as event | ||
704 | * modifier and whatever event/group modifier override | ||
705 | * default 'GH' setup. | ||
706 | */ | ||
707 | if (evsel && !exclude_GH) | ||
708 | eH = eG = 0; | ||
709 | |||
710 | memset(mod, 0, sizeof(*mod)); | 702 | memset(mod, 0, sizeof(*mod)); |
711 | 703 | ||
712 | while (*str) { | 704 | while (*str) { |
diff --git a/tools/perf/util/python-ext-sources b/tools/perf/util/python-ext-sources index c40c2d33199e..64536a993f4a 100644 --- a/tools/perf/util/python-ext-sources +++ b/tools/perf/util/python-ext-sources | |||
@@ -18,4 +18,5 @@ util/cgroup.c | |||
18 | util/debugfs.c | 18 | util/debugfs.c |
19 | util/rblist.c | 19 | util/rblist.c |
20 | util/strlist.c | 20 | util/strlist.c |
21 | util/sysfs.c | ||
21 | ../../lib/rbtree.c | 22 | ../../lib/rbtree.c |
diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c index 83336610faa9..d41926cb9e3f 100644 --- a/tools/perf/util/sort.c +++ b/tools/perf/util/sort.c | |||
@@ -160,9 +160,10 @@ struct sort_entry sort_dso = { | |||
160 | 160 | ||
161 | /* --sort symbol */ | 161 | /* --sort symbol */ |
162 | 162 | ||
163 | static int64_t _sort__sym_cmp(struct symbol *sym_l, struct symbol *sym_r, | 163 | static int64_t _sort__sym_cmp(struct symbol *sym_l, struct symbol *sym_r) |
164 | u64 ip_l, u64 ip_r) | ||
165 | { | 164 | { |
165 | u64 ip_l, ip_r; | ||
166 | |||
166 | if (!sym_l || !sym_r) | 167 | if (!sym_l || !sym_r) |
167 | return cmp_null(sym_l, sym_r); | 168 | return cmp_null(sym_l, sym_r); |
168 | 169 | ||
@@ -178,21 +179,10 @@ static int64_t _sort__sym_cmp(struct symbol *sym_l, struct symbol *sym_r, | |||
178 | static int64_t | 179 | static int64_t |
179 | sort__sym_cmp(struct hist_entry *left, struct hist_entry *right) | 180 | sort__sym_cmp(struct hist_entry *left, struct hist_entry *right) |
180 | { | 181 | { |
181 | u64 ip_l, ip_r; | ||
182 | |||
183 | if (!left->ms.sym && !right->ms.sym) | 182 | if (!left->ms.sym && !right->ms.sym) |
184 | return right->level - left->level; | 183 | return right->level - left->level; |
185 | 184 | ||
186 | if (!left->ms.sym || !right->ms.sym) | 185 | return _sort__sym_cmp(left->ms.sym, right->ms.sym); |
187 | return cmp_null(left->ms.sym, right->ms.sym); | ||
188 | |||
189 | if (left->ms.sym == right->ms.sym) | ||
190 | return 0; | ||
191 | |||
192 | ip_l = left->ms.sym->start; | ||
193 | ip_r = right->ms.sym->start; | ||
194 | |||
195 | return _sort__sym_cmp(left->ms.sym, right->ms.sym, ip_l, ip_r); | ||
196 | } | 186 | } |
197 | 187 | ||
198 | static int _hist_entry__sym_snprintf(struct map *map, struct symbol *sym, | 188 | static int _hist_entry__sym_snprintf(struct map *map, struct symbol *sym, |
@@ -383,8 +373,7 @@ sort__sym_from_cmp(struct hist_entry *left, struct hist_entry *right) | |||
383 | if (!from_l->sym && !from_r->sym) | 373 | if (!from_l->sym && !from_r->sym) |
384 | return right->level - left->level; | 374 | return right->level - left->level; |
385 | 375 | ||
386 | return _sort__sym_cmp(from_l->sym, from_r->sym, from_l->addr, | 376 | return _sort__sym_cmp(from_l->sym, from_r->sym); |
387 | from_r->addr); | ||
388 | } | 377 | } |
389 | 378 | ||
390 | static int64_t | 379 | static int64_t |
@@ -396,7 +385,7 @@ sort__sym_to_cmp(struct hist_entry *left, struct hist_entry *right) | |||
396 | if (!to_l->sym && !to_r->sym) | 385 | if (!to_l->sym && !to_r->sym) |
397 | return right->level - left->level; | 386 | return right->level - left->level; |
398 | 387 | ||
399 | return _sort__sym_cmp(to_l->sym, to_r->sym, to_l->addr, to_r->addr); | 388 | return _sort__sym_cmp(to_l->sym, to_r->sym); |
400 | } | 389 | } |
401 | 390 | ||
402 | static int hist_entry__sym_from_snprintf(struct hist_entry *self, char *bf, | 391 | static int hist_entry__sym_from_snprintf(struct hist_entry *self, char *bf, |
@@ -576,23 +565,30 @@ int sort_dimension__add(const char *tok) | |||
576 | return -ESRCH; | 565 | return -ESRCH; |
577 | } | 566 | } |
578 | 567 | ||
579 | void setup_sorting(const char * const usagestr[], const struct option *opts) | 568 | int setup_sorting(void) |
580 | { | 569 | { |
581 | char *tmp, *tok, *str = strdup(sort_order); | 570 | char *tmp, *tok, *str = strdup(sort_order); |
571 | int ret = 0; | ||
572 | |||
573 | if (str == NULL) { | ||
574 | error("Not enough memory to setup sort keys"); | ||
575 | return -ENOMEM; | ||
576 | } | ||
582 | 577 | ||
583 | for (tok = strtok_r(str, ", ", &tmp); | 578 | for (tok = strtok_r(str, ", ", &tmp); |
584 | tok; tok = strtok_r(NULL, ", ", &tmp)) { | 579 | tok; tok = strtok_r(NULL, ", ", &tmp)) { |
585 | int ret = sort_dimension__add(tok); | 580 | ret = sort_dimension__add(tok); |
586 | if (ret == -EINVAL) { | 581 | if (ret == -EINVAL) { |
587 | error("Invalid --sort key: `%s'", tok); | 582 | error("Invalid --sort key: `%s'", tok); |
588 | usage_with_options(usagestr, opts); | 583 | break; |
589 | } else if (ret == -ESRCH) { | 584 | } else if (ret == -ESRCH) { |
590 | error("Unknown --sort key: `%s'", tok); | 585 | error("Unknown --sort key: `%s'", tok); |
591 | usage_with_options(usagestr, opts); | 586 | break; |
592 | } | 587 | } |
593 | } | 588 | } |
594 | 589 | ||
595 | free(str); | 590 | free(str); |
591 | return ret; | ||
596 | } | 592 | } |
597 | 593 | ||
598 | void sort_entry__setup_elide(struct sort_entry *self, struct strlist *list, | 594 | void sort_entry__setup_elide(struct sort_entry *self, struct strlist *list, |
diff --git a/tools/perf/util/sort.h b/tools/perf/util/sort.h index e994ad3e9897..b13e56f6ccbe 100644 --- a/tools/perf/util/sort.h +++ b/tools/perf/util/sort.h | |||
@@ -160,7 +160,7 @@ struct sort_entry { | |||
160 | extern struct sort_entry sort_thread; | 160 | extern struct sort_entry sort_thread; |
161 | extern struct list_head hist_entry__sort_list; | 161 | extern struct list_head hist_entry__sort_list; |
162 | 162 | ||
163 | void setup_sorting(const char * const usagestr[], const struct option *opts); | 163 | int setup_sorting(void); |
164 | extern int sort_dimension__add(const char *); | 164 | extern int sort_dimension__add(const char *); |
165 | void sort_entry__setup_elide(struct sort_entry *self, struct strlist *list, | 165 | void sort_entry__setup_elide(struct sort_entry *self, struct strlist *list, |
166 | const char *list_name, FILE *fp); | 166 | const char *list_name, FILE *fp); |