diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2015-07-04 11:17:29 -0400 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2015-07-04 11:17:29 -0400 |
| commit | c1776a18e3b5a3559f3dff5df0ecce570abd3a9f (patch) | |
| tree | 5b97defe199f434f5d9829bf7d8df6124e6ce5f1 | |
| parent | 91cca0f0ffa3e485ad9d5b44744f23318c8f99ab (diff) | |
| parent | b9df84fd7c05cc300d6d14f022b8a00773ebcf8c (diff) | |
Merge branch 'perf-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull perf updates from Ingo Molnar:
"This tree includes an x86 PMU scheduling fix, but most changes are
late breaking tooling fixes and updates:
User visible fixes:
- Create config.detected into OUTPUT directory, fixing parallel
builds sharing the same source directory (Aaro Kiskinen)
- Allow to specify custom linker command, fixing some MIPS64 builds.
(Aaro Kiskinen)
- Fix to show proper convergence stats in 'perf bench numa' (Srikar
Dronamraju)
User visible changes:
- Validate syscall list passed via -e argument to 'perf trace'.
(Arnaldo Carvalho de Melo)
- Introduce 'perf stat --per-thread' (Jiri Olsa)
- Check access permission for --kallsyms and --vmlinux (Li Zhang)
- Move toggling event logic from 'perf top' and into hists browser,
allowing freeze/unfreeze with event lists with more than one entry
(Namhyung Kim)
- Add missing newlines when dumping PERF_RECORD_FINISHED_ROUND and
showing the Aggregated stats in 'perf report -D' (Adrian Hunter)
Infrastructure fixes:
- Add missing break for PERF_RECORD_ITRACE_START, which caused those
events samples to be parsed as well as PERF_RECORD_LOST_SAMPLES.
ITRACE_START only appears when Intel PT or BTS are present, so..
(Jiri Olsa)
- Call the perf_session destructor when bailing out in the inject,
kmem, report, kvm and mem tools (Taeung Song)
Infrastructure changes:
- Move stuff out of 'perf stat' and into the lib for further use
(Jiri Olsa)
- Reference count the cpu_map and thread_map classes (Jiri Olsa)
- Set evsel->{cpus,threads} from the evlist, if not set, allowing the
generalization of some 'perf stat' functions that previously were
accessing private static evlist variable (Jiri Olsa)
- Delete an unnecessary check before the calling free_event_desc()
(Markus Elfring)
- Allow auxtrace data alignment (Adrian Hunter)
- Allow events with dot (Andi Kleen)
- Fix failure to 'perf probe' events on arm (He Kuang)
- Add testing for Makefile.perf (Jiri Olsa)
- Add test for make install with prefix (Jiri Olsa)
- Fix single target build dependency check (Jiri Olsa)
- Access thread_map entries via accessors, prep patch to hold more
info per entry, for ongoing 'perf stat --per-thread' work (Jiri
Olsa)
- Use __weak definition from compiler.h (Sukadev Bhattiprolu)
- Split perf_pmu__new_alias() (Sukadev Bhattiprolu)"
* 'perf-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (54 commits)
perf tools: Allow to specify custom linker command
perf tools: Create config.detected into OUTPUT directory
perf mem: Fill in the missing session freeing after an error occurs
perf kvm: Fill in the missing session freeing after an error occurs
perf report: Fill in the missing session freeing after an error occurs
perf kmem: Fill in the missing session freeing after an error occurs
perf inject: Fill in the missing session freeing after an error occurs
perf tools: Add missing break for PERF_RECORD_ITRACE_START
perf/x86: Fix 'active_events' imbalance
perf symbols: Check access permission when reading symbol files
perf stat: Introduce --per-thread option
perf stat: Introduce print_counters function
perf stat: Using init_stats instead of memset
perf stat: Rename print_interval to process_interval
perf stat: Remove perf_evsel__read_cb function
perf stat: Move perf_stat initialization counter process code
perf stat: Move zero_per_pkg into counter process code
perf stat: Separate counters reading and processing
perf stat: Introduce read_counters function
perf stat: Introduce perf_evsel__read function
...
54 files changed, 885 insertions, 422 deletions
diff --git a/arch/x86/kernel/cpu/perf_event.c b/arch/x86/kernel/cpu/perf_event.c index 5801a14f7524..3658de47900f 100644 --- a/arch/x86/kernel/cpu/perf_event.c +++ b/arch/x86/kernel/cpu/perf_event.c | |||
| @@ -357,34 +357,24 @@ void x86_release_hardware(void) | |||
| 357 | */ | 357 | */ |
| 358 | int x86_add_exclusive(unsigned int what) | 358 | int x86_add_exclusive(unsigned int what) |
| 359 | { | 359 | { |
| 360 | int ret = -EBUSY, i; | 360 | int i; |
| 361 | |||
| 362 | if (atomic_inc_not_zero(&x86_pmu.lbr_exclusive[what])) | ||
| 363 | return 0; | ||
| 364 | 361 | ||
| 365 | mutex_lock(&pmc_reserve_mutex); | 362 | if (!atomic_inc_not_zero(&x86_pmu.lbr_exclusive[what])) { |
| 366 | for (i = 0; i < ARRAY_SIZE(x86_pmu.lbr_exclusive); i++) { | 363 | mutex_lock(&pmc_reserve_mutex); |
| 367 | if (i != what && atomic_read(&x86_pmu.lbr_exclusive[i])) | 364 | for (i = 0; i < ARRAY_SIZE(x86_pmu.lbr_exclusive); i++) { |
| 368 | goto out; | 365 | if (i != what && atomic_read(&x86_pmu.lbr_exclusive[i])) |
| 366 | goto fail_unlock; | ||
| 367 | } | ||
| 368 | atomic_inc(&x86_pmu.lbr_exclusive[what]); | ||
| 369 | mutex_unlock(&pmc_reserve_mutex); | ||
| 369 | } | 370 | } |
| 370 | 371 | ||
| 371 | atomic_inc(&x86_pmu.lbr_exclusive[what]); | 372 | atomic_inc(&active_events); |
| 372 | ret = 0; | 373 | return 0; |
| 373 | 374 | ||
| 374 | out: | 375 | fail_unlock: |
| 375 | mutex_unlock(&pmc_reserve_mutex); | 376 | mutex_unlock(&pmc_reserve_mutex); |
| 376 | 377 | return -EBUSY; | |
| 377 | /* | ||
| 378 | * Assuming that all exclusive events will share the PMI handler | ||
| 379 | * (which checks active_events for whether there is work to do), | ||
| 380 | * we can bump active_events counter right here, except for | ||
| 381 | * x86_lbr_exclusive_lbr events that go through x86_pmu_event_init() | ||
| 382 | * path, which already bumps active_events for them. | ||
| 383 | */ | ||
| 384 | if (!ret && what != x86_lbr_exclusive_lbr) | ||
| 385 | atomic_inc(&active_events); | ||
| 386 | |||
| 387 | return ret; | ||
| 388 | } | 378 | } |
| 389 | 379 | ||
| 390 | void x86_del_exclusive(unsigned int what) | 380 | void x86_del_exclusive(unsigned int what) |
diff --git a/tools/build/Makefile.build b/tools/build/Makefile.build index a51244a8022f..faca2bf6a430 100644 --- a/tools/build/Makefile.build +++ b/tools/build/Makefile.build | |||
| @@ -25,7 +25,7 @@ build-dir := $(srctree)/tools/build | |||
| 25 | include $(build-dir)/Build.include | 25 | include $(build-dir)/Build.include |
| 26 | 26 | ||
| 27 | # do not force detected configuration | 27 | # do not force detected configuration |
| 28 | -include .config-detected | 28 | -include $(OUTPUT).config-detected |
| 29 | 29 | ||
| 30 | # Init all relevant variables used in build files so | 30 | # Init all relevant variables used in build files so |
| 31 | # 1) they have correct type | 31 | # 1) they have correct type |
diff --git a/tools/perf/Documentation/perf-stat.txt b/tools/perf/Documentation/perf-stat.txt index 04e150d83e7d..47469abdcc1c 100644 --- a/tools/perf/Documentation/perf-stat.txt +++ b/tools/perf/Documentation/perf-stat.txt | |||
| @@ -144,6 +144,10 @@ is a useful mode to detect imbalance between physical cores. To enable this mod | |||
| 144 | use --per-core in addition to -a. (system-wide). The output includes the | 144 | use --per-core in addition to -a. (system-wide). The output includes the |
| 145 | core number and the number of online logical processors on that physical processor. | 145 | core number and the number of online logical processors on that physical processor. |
| 146 | 146 | ||
| 147 | --per-thread:: | ||
| 148 | Aggregate counts per monitored threads, when monitoring threads (-t option) | ||
| 149 | or processes (-p option). | ||
| 150 | |||
| 147 | -D msecs:: | 151 | -D msecs:: |
| 148 | --delay msecs:: | 152 | --delay msecs:: |
| 149 | After starting the program, wait msecs before measuring. This is useful to | 153 | After starting the program, wait msecs before measuring. This is useful to |
diff --git a/tools/perf/Makefile b/tools/perf/Makefile index d31a7bbd7cee..480546d5f13b 100644 --- a/tools/perf/Makefile +++ b/tools/perf/Makefile | |||
| @@ -83,8 +83,8 @@ build-test: | |||
| 83 | # | 83 | # |
| 84 | # All other targets get passed through: | 84 | # All other targets get passed through: |
| 85 | # | 85 | # |
| 86 | %: | 86 | %: FORCE |
| 87 | $(print_msg) | 87 | $(print_msg) |
| 88 | $(make) | 88 | $(make) |
| 89 | 89 | ||
| 90 | .PHONY: tags TAGS | 90 | .PHONY: tags TAGS FORCE Makefile |
diff --git a/tools/perf/Makefile.perf b/tools/perf/Makefile.perf index 1af0cfeb7a57..7a4b549214e3 100644 --- a/tools/perf/Makefile.perf +++ b/tools/perf/Makefile.perf | |||
| @@ -110,7 +110,7 @@ $(OUTPUT)PERF-VERSION-FILE: ../../.git/HEAD | |||
| 110 | $(Q)touch $(OUTPUT)PERF-VERSION-FILE | 110 | $(Q)touch $(OUTPUT)PERF-VERSION-FILE |
| 111 | 111 | ||
| 112 | CC = $(CROSS_COMPILE)gcc | 112 | CC = $(CROSS_COMPILE)gcc |
| 113 | LD = $(CROSS_COMPILE)ld | 113 | LD ?= $(CROSS_COMPILE)ld |
| 114 | AR = $(CROSS_COMPILE)ar | 114 | AR = $(CROSS_COMPILE)ar |
| 115 | PKG_CONFIG = $(CROSS_COMPILE)pkg-config | 115 | PKG_CONFIG = $(CROSS_COMPILE)pkg-config |
| 116 | 116 | ||
| @@ -545,7 +545,7 @@ config-clean: | |||
| 545 | clean: $(LIBTRACEEVENT)-clean $(LIBAPI)-clean config-clean | 545 | clean: $(LIBTRACEEVENT)-clean $(LIBAPI)-clean config-clean |
| 546 | $(call QUIET_CLEAN, core-objs) $(RM) $(LIB_FILE) $(OUTPUT)perf-archive $(OUTPUT)perf-with-kcore $(LANG_BINDINGS) | 546 | $(call QUIET_CLEAN, core-objs) $(RM) $(LIB_FILE) $(OUTPUT)perf-archive $(OUTPUT)perf-with-kcore $(LANG_BINDINGS) |
| 547 | $(Q)find . -name '*.o' -delete -o -name '\.*.cmd' -delete -o -name '\.*.d' -delete | 547 | $(Q)find . -name '*.o' -delete -o -name '\.*.cmd' -delete -o -name '\.*.d' -delete |
| 548 | $(Q)$(RM) .config-detected | 548 | $(Q)$(RM) $(OUTPUT).config-detected |
| 549 | $(call QUIET_CLEAN, core-progs) $(RM) $(ALL_PROGRAMS) perf perf-read-vdso32 perf-read-vdsox32 | 549 | $(call QUIET_CLEAN, core-progs) $(RM) $(ALL_PROGRAMS) perf perf-read-vdso32 perf-read-vdsox32 |
| 550 | $(call QUIET_CLEAN, core-gen) $(RM) *.spec *.pyc *.pyo */*.pyc */*.pyo $(OUTPUT)common-cmds.h TAGS tags cscope* $(OUTPUT)PERF-VERSION-FILE $(OUTPUT)FEATURE-DUMP $(OUTPUT)util/*-bison* $(OUTPUT)util/*-flex* | 550 | $(call QUIET_CLEAN, core-gen) $(RM) *.spec *.pyc *.pyo */*.pyc */*.pyo $(OUTPUT)common-cmds.h TAGS tags cscope* $(OUTPUT)PERF-VERSION-FILE $(OUTPUT)FEATURE-DUMP $(OUTPUT)util/*-bison* $(OUTPUT)util/*-flex* |
| 551 | $(QUIET_SUBDIR0)Documentation $(QUIET_SUBDIR1) clean | 551 | $(QUIET_SUBDIR0)Documentation $(QUIET_SUBDIR1) clean |
diff --git a/tools/perf/builtin-inject.c b/tools/perf/builtin-inject.c index 52ec66b23607..01b06492bd6a 100644 --- a/tools/perf/builtin-inject.c +++ b/tools/perf/builtin-inject.c | |||
| @@ -630,12 +630,13 @@ int cmd_inject(int argc, const char **argv, const char *prefix __maybe_unused) | |||
| 630 | if (inject.session == NULL) | 630 | if (inject.session == NULL) |
| 631 | return -1; | 631 | return -1; |
| 632 | 632 | ||
| 633 | if (symbol__init(&inject.session->header.env) < 0) | 633 | ret = symbol__init(&inject.session->header.env); |
| 634 | return -1; | 634 | if (ret < 0) |
| 635 | goto out_delete; | ||
| 635 | 636 | ||
| 636 | ret = __cmd_inject(&inject); | 637 | ret = __cmd_inject(&inject); |
| 637 | 638 | ||
| 639 | out_delete: | ||
| 638 | perf_session__delete(inject.session); | 640 | perf_session__delete(inject.session); |
| 639 | |||
| 640 | return ret; | 641 | return ret; |
| 641 | } | 642 | } |
diff --git a/tools/perf/builtin-kmem.c b/tools/perf/builtin-kmem.c index 950f296dfcf7..23b1faaaa4cc 100644 --- a/tools/perf/builtin-kmem.c +++ b/tools/perf/builtin-kmem.c | |||
| @@ -1916,7 +1916,7 @@ int cmd_kmem(int argc, const char **argv, const char *prefix __maybe_unused) | |||
| 1916 | if (!perf_evlist__find_tracepoint_by_name(session->evlist, | 1916 | if (!perf_evlist__find_tracepoint_by_name(session->evlist, |
| 1917 | "kmem:kmalloc")) { | 1917 | "kmem:kmalloc")) { |
| 1918 | pr_err(errmsg, "slab", "slab"); | 1918 | pr_err(errmsg, "slab", "slab"); |
| 1919 | return -1; | 1919 | goto out_delete; |
| 1920 | } | 1920 | } |
| 1921 | } | 1921 | } |
| 1922 | 1922 | ||
| @@ -1927,7 +1927,7 @@ int cmd_kmem(int argc, const char **argv, const char *prefix __maybe_unused) | |||
| 1927 | "kmem:mm_page_alloc"); | 1927 | "kmem:mm_page_alloc"); |
| 1928 | if (evsel == NULL) { | 1928 | if (evsel == NULL) { |
| 1929 | pr_err(errmsg, "page", "page"); | 1929 | pr_err(errmsg, "page", "page"); |
| 1930 | return -1; | 1930 | goto out_delete; |
| 1931 | } | 1931 | } |
| 1932 | 1932 | ||
| 1933 | kmem_page_size = pevent_get_page_size(evsel->tp_format->pevent); | 1933 | kmem_page_size = pevent_get_page_size(evsel->tp_format->pevent); |
diff --git a/tools/perf/builtin-kvm.c b/tools/perf/builtin-kvm.c index 74878cd75078..fc1cffb1b7a2 100644 --- a/tools/perf/builtin-kvm.c +++ b/tools/perf/builtin-kvm.c | |||
| @@ -1061,8 +1061,10 @@ static int read_events(struct perf_kvm_stat *kvm) | |||
| 1061 | 1061 | ||
| 1062 | symbol__init(&kvm->session->header.env); | 1062 | symbol__init(&kvm->session->header.env); |
| 1063 | 1063 | ||
| 1064 | if (!perf_session__has_traces(kvm->session, "kvm record")) | 1064 | if (!perf_session__has_traces(kvm->session, "kvm record")) { |
| 1065 | return -EINVAL; | 1065 | ret = -EINVAL; |
| 1066 | goto out_delete; | ||
| 1067 | } | ||
| 1066 | 1068 | ||
| 1067 | /* | 1069 | /* |
| 1068 | * Do not use 'isa' recorded in kvm_exit tracepoint since it is not | 1070 | * Do not use 'isa' recorded in kvm_exit tracepoint since it is not |
| @@ -1070,9 +1072,13 @@ static int read_events(struct perf_kvm_stat *kvm) | |||
| 1070 | */ | 1072 | */ |
| 1071 | ret = cpu_isa_config(kvm); | 1073 | ret = cpu_isa_config(kvm); |
| 1072 | if (ret < 0) | 1074 | if (ret < 0) |
| 1073 | return ret; | 1075 | goto out_delete; |
| 1074 | 1076 | ||
| 1075 | return perf_session__process_events(kvm->session); | 1077 | ret = perf_session__process_events(kvm->session); |
| 1078 | |||
| 1079 | out_delete: | ||
| 1080 | perf_session__delete(kvm->session); | ||
| 1081 | return ret; | ||
| 1076 | } | 1082 | } |
| 1077 | 1083 | ||
| 1078 | static int parse_target_str(struct perf_kvm_stat *kvm) | 1084 | static int parse_target_str(struct perf_kvm_stat *kvm) |
diff --git a/tools/perf/builtin-mem.c b/tools/perf/builtin-mem.c index da2ec06f0742..80170aace5d4 100644 --- a/tools/perf/builtin-mem.c +++ b/tools/perf/builtin-mem.c | |||
| @@ -124,7 +124,6 @@ static int report_raw_events(struct perf_mem *mem) | |||
| 124 | .mode = PERF_DATA_MODE_READ, | 124 | .mode = PERF_DATA_MODE_READ, |
| 125 | .force = mem->force, | 125 | .force = mem->force, |
| 126 | }; | 126 | }; |
| 127 | int err = -EINVAL; | ||
| 128 | int ret; | 127 | int ret; |
| 129 | struct perf_session *session = perf_session__new(&file, false, | 128 | struct perf_session *session = perf_session__new(&file, false, |
| 130 | &mem->tool); | 129 | &mem->tool); |
| @@ -135,24 +134,21 @@ static int report_raw_events(struct perf_mem *mem) | |||
| 135 | if (mem->cpu_list) { | 134 | if (mem->cpu_list) { |
| 136 | ret = perf_session__cpu_bitmap(session, mem->cpu_list, | 135 | ret = perf_session__cpu_bitmap(session, mem->cpu_list, |
| 137 | mem->cpu_bitmap); | 136 | mem->cpu_bitmap); |
| 138 | if (ret) | 137 | if (ret < 0) |
| 139 | goto out_delete; | 138 | goto out_delete; |
| 140 | } | 139 | } |
| 141 | 140 | ||
| 142 | if (symbol__init(&session->header.env) < 0) | 141 | ret = symbol__init(&session->header.env); |
| 143 | return -1; | 142 | if (ret < 0) |
| 143 | goto out_delete; | ||
| 144 | 144 | ||
| 145 | printf("# PID, TID, IP, ADDR, LOCAL WEIGHT, DSRC, SYMBOL\n"); | 145 | printf("# PID, TID, IP, ADDR, LOCAL WEIGHT, DSRC, SYMBOL\n"); |
| 146 | 146 | ||
| 147 | err = perf_session__process_events(session); | 147 | ret = perf_session__process_events(session); |
| 148 | if (err) | ||
| 149 | return err; | ||
| 150 | |||
| 151 | return 0; | ||
| 152 | 148 | ||
| 153 | out_delete: | 149 | out_delete: |
| 154 | perf_session__delete(session); | 150 | perf_session__delete(session); |
| 155 | return err; | 151 | return ret; |
| 156 | } | 152 | } |
| 157 | 153 | ||
| 158 | static int report_events(int argc, const char **argv, struct perf_mem *mem) | 154 | static int report_events(int argc, const char **argv, struct perf_mem *mem) |
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index 32626ea3e227..95a47719aec3 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c | |||
| @@ -742,6 +742,17 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused) | |||
| 742 | 742 | ||
| 743 | argc = parse_options(argc, argv, options, report_usage, 0); | 743 | argc = parse_options(argc, argv, options, report_usage, 0); |
| 744 | 744 | ||
| 745 | if (symbol_conf.vmlinux_name && | ||
| 746 | access(symbol_conf.vmlinux_name, R_OK)) { | ||
| 747 | pr_err("Invalid file: %s\n", symbol_conf.vmlinux_name); | ||
| 748 | return -EINVAL; | ||
| 749 | } | ||
| 750 | if (symbol_conf.kallsyms_name && | ||
| 751 | access(symbol_conf.kallsyms_name, R_OK)) { | ||
| 752 | pr_err("Invalid file: %s\n", symbol_conf.kallsyms_name); | ||
| 753 | return -EINVAL; | ||
| 754 | } | ||
| 755 | |||
| 745 | if (report.use_stdio) | 756 | if (report.use_stdio) |
| 746 | use_browser = 0; | 757 | use_browser = 0; |
| 747 | else if (report.use_tui) | 758 | else if (report.use_tui) |
| @@ -828,8 +839,10 @@ repeat: | |||
| 828 | if (report.header || report.header_only) { | 839 | if (report.header || report.header_only) { |
| 829 | perf_session__fprintf_info(session, stdout, | 840 | perf_session__fprintf_info(session, stdout, |
| 830 | report.show_full_info); | 841 | report.show_full_info); |
| 831 | if (report.header_only) | 842 | if (report.header_only) { |
| 832 | return 0; | 843 | ret = 0; |
| 844 | goto error; | ||
| 845 | } | ||
| 833 | } else if (use_browser == 0) { | 846 | } else if (use_browser == 0) { |
| 834 | fputs("# To display the perf.data header info, please use --header/--header-only options.\n#\n", | 847 | fputs("# To display the perf.data header info, please use --header/--header-only options.\n#\n", |
| 835 | stdout); | 848 | stdout); |
diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index fcf99bdeb19e..37e301a32f43 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c | |||
| @@ -67,10 +67,7 @@ | |||
| 67 | #define CNTR_NOT_SUPPORTED "<not supported>" | 67 | #define CNTR_NOT_SUPPORTED "<not supported>" |
| 68 | #define CNTR_NOT_COUNTED "<not counted>" | 68 | #define CNTR_NOT_COUNTED "<not counted>" |
| 69 | 69 | ||
| 70 | static void print_stat(int argc, const char **argv); | 70 | static void print_counters(struct timespec *ts, int argc, const char **argv); |
| 71 | static void print_counter_aggr(struct perf_evsel *counter, char *prefix); | ||
| 72 | static void print_counter(struct perf_evsel *counter, char *prefix); | ||
| 73 | static void print_aggr(char *prefix); | ||
| 74 | 71 | ||
| 75 | /* Default events used for perf stat -T */ | 72 | /* Default events used for perf stat -T */ |
| 76 | static const char *transaction_attrs = { | 73 | static const char *transaction_attrs = { |
| @@ -141,96 +138,9 @@ static inline void diff_timespec(struct timespec *r, struct timespec *a, | |||
| 141 | } | 138 | } |
| 142 | } | 139 | } |
| 143 | 140 | ||
| 144 | static inline struct cpu_map *perf_evsel__cpus(struct perf_evsel *evsel) | 141 | static void perf_stat__reset_stats(void) |
| 145 | { | 142 | { |
| 146 | return (evsel->cpus && !target.cpu_list) ? evsel->cpus : evsel_list->cpus; | 143 | perf_evlist__reset_stats(evsel_list); |
| 147 | } | ||
| 148 | |||
| 149 | static inline int perf_evsel__nr_cpus(struct perf_evsel *evsel) | ||
| 150 | { | ||
| 151 | return perf_evsel__cpus(evsel)->nr; | ||
| 152 | } | ||
| 153 | |||
| 154 | static void perf_evsel__reset_stat_priv(struct perf_evsel *evsel) | ||
| 155 | { | ||
| 156 | int i; | ||
| 157 | struct perf_stat *ps = evsel->priv; | ||
| 158 | |||
| 159 | for (i = 0; i < 3; i++) | ||
| 160 | init_stats(&ps->res_stats[i]); | ||
| 161 | |||
| 162 | perf_stat_evsel_id_init(evsel); | ||
| 163 | } | ||
| 164 | |||
| 165 | static int perf_evsel__alloc_stat_priv(struct perf_evsel *evsel) | ||
| 166 | { | ||
| 167 | evsel->priv = zalloc(sizeof(struct perf_stat)); | ||
| 168 | if (evsel->priv == NULL) | ||
| 169 | return -ENOMEM; | ||
| 170 | perf_evsel__reset_stat_priv(evsel); | ||
| 171 | return 0; | ||
| 172 | } | ||
| 173 | |||
| 174 | static void perf_evsel__free_stat_priv(struct perf_evsel *evsel) | ||
| 175 | { | ||
| 176 | zfree(&evsel->priv); | ||
| 177 | } | ||
| 178 | |||
| 179 | static int perf_evsel__alloc_prev_raw_counts(struct perf_evsel *evsel) | ||
| 180 | { | ||
| 181 | struct perf_counts *counts; | ||
| 182 | |||
| 183 | counts = perf_counts__new(perf_evsel__nr_cpus(evsel)); | ||
| 184 | if (counts) | ||
| 185 | evsel->prev_raw_counts = counts; | ||
| 186 | |||
| 187 | return counts ? 0 : -ENOMEM; | ||
| 188 | } | ||
| 189 | |||
| 190 | static void perf_evsel__free_prev_raw_counts(struct perf_evsel *evsel) | ||
| 191 | { | ||
| 192 | perf_counts__delete(evsel->prev_raw_counts); | ||
| 193 | evsel->prev_raw_counts = NULL; | ||
| 194 | } | ||
| 195 | |||
| 196 | static void perf_evlist__free_stats(struct perf_evlist *evlist) | ||
| 197 | { | ||
| 198 | struct perf_evsel *evsel; | ||
| 199 | |||
| 200 | evlist__for_each(evlist, evsel) { | ||
| 201 | perf_evsel__free_stat_priv(evsel); | ||
| 202 | perf_evsel__free_counts(evsel); | ||
| 203 | perf_evsel__free_prev_raw_counts(evsel); | ||
| 204 | } | ||
| 205 | } | ||
| 206 | |||
| 207 | static int perf_evlist__alloc_stats(struct perf_evlist *evlist, bool alloc_raw) | ||
| 208 | { | ||
| 209 | struct perf_evsel *evsel; | ||
| 210 | |||
| 211 | evlist__for_each(evlist, evsel) { | ||
| 212 | if (perf_evsel__alloc_stat_priv(evsel) < 0 || | ||
| 213 | perf_evsel__alloc_counts(evsel, perf_evsel__nr_cpus(evsel)) < 0 || | ||
| 214 | (alloc_raw && perf_evsel__alloc_prev_raw_counts(evsel) < 0)) | ||
| 215 | goto out_free; | ||
| 216 | } | ||
| 217 | |||
| 218 | return 0; | ||
| 219 | |||
| 220 | out_free: | ||
| 221 | perf_evlist__free_stats(evlist); | ||
| 222 | return -1; | ||
| 223 | } | ||
| 224 | |||
| 225 | static void perf_stat__reset_stats(struct perf_evlist *evlist) | ||
| 226 | { | ||
| 227 | struct perf_evsel *evsel; | ||
| 228 | |||
| 229 | evlist__for_each(evlist, evsel) { | ||
| 230 | perf_evsel__reset_stat_priv(evsel); | ||
| 231 | perf_evsel__reset_counts(evsel, perf_evsel__nr_cpus(evsel)); | ||
| 232 | } | ||
| 233 | |||
| 234 | perf_stat__reset_shadow_stats(); | 144 | perf_stat__reset_shadow_stats(); |
| 235 | } | 145 | } |
| 236 | 146 | ||
| @@ -304,8 +214,9 @@ static int check_per_pkg(struct perf_evsel *counter, int cpu, bool *skip) | |||
| 304 | return 0; | 214 | return 0; |
| 305 | } | 215 | } |
| 306 | 216 | ||
| 307 | static int read_cb(struct perf_evsel *evsel, int cpu, int thread __maybe_unused, | 217 | static int |
| 308 | struct perf_counts_values *count) | 218 | process_counter_values(struct perf_evsel *evsel, int cpu, int thread, |
| 219 | struct perf_counts_values *count) | ||
| 309 | { | 220 | { |
| 310 | struct perf_counts_values *aggr = &evsel->counts->aggr; | 221 | struct perf_counts_values *aggr = &evsel->counts->aggr; |
| 311 | static struct perf_counts_values zero; | 222 | static struct perf_counts_values zero; |
| @@ -320,13 +231,13 @@ static int read_cb(struct perf_evsel *evsel, int cpu, int thread __maybe_unused, | |||
| 320 | count = &zero; | 231 | count = &zero; |
| 321 | 232 | ||
| 322 | switch (aggr_mode) { | 233 | switch (aggr_mode) { |
| 234 | case AGGR_THREAD: | ||
| 323 | case AGGR_CORE: | 235 | case AGGR_CORE: |
| 324 | case AGGR_SOCKET: | 236 | case AGGR_SOCKET: |
| 325 | case AGGR_NONE: | 237 | case AGGR_NONE: |
| 326 | if (!evsel->snapshot) | 238 | if (!evsel->snapshot) |
| 327 | perf_evsel__compute_deltas(evsel, cpu, count); | 239 | perf_evsel__compute_deltas(evsel, cpu, thread, count); |
| 328 | perf_counts_values__scale(count, scale, NULL); | 240 | perf_counts_values__scale(count, scale, NULL); |
| 329 | evsel->counts->cpu[cpu] = *count; | ||
| 330 | if (aggr_mode == AGGR_NONE) | 241 | if (aggr_mode == AGGR_NONE) |
| 331 | perf_stat__update_shadow_stats(evsel, count->values, cpu); | 242 | perf_stat__update_shadow_stats(evsel, count->values, cpu); |
| 332 | break; | 243 | break; |
| @@ -343,26 +254,48 @@ static int read_cb(struct perf_evsel *evsel, int cpu, int thread __maybe_unused, | |||
| 343 | return 0; | 254 | return 0; |
| 344 | } | 255 | } |
| 345 | 256 | ||
| 346 | static int read_counter(struct perf_evsel *counter); | 257 | static int process_counter_maps(struct perf_evsel *counter) |
| 258 | { | ||
| 259 | int nthreads = thread_map__nr(counter->threads); | ||
| 260 | int ncpus = perf_evsel__nr_cpus(counter); | ||
| 261 | int cpu, thread; | ||
| 347 | 262 | ||
| 348 | /* | 263 | if (counter->system_wide) |
| 349 | * Read out the results of a single counter: | 264 | nthreads = 1; |
| 350 | * aggregate counts across CPUs in system-wide mode | 265 | |
| 351 | */ | 266 | for (thread = 0; thread < nthreads; thread++) { |
| 352 | static int read_counter_aggr(struct perf_evsel *counter) | 267 | for (cpu = 0; cpu < ncpus; cpu++) { |
| 268 | if (process_counter_values(counter, cpu, thread, | ||
| 269 | perf_counts(counter->counts, cpu, thread))) | ||
| 270 | return -1; | ||
| 271 | } | ||
| 272 | } | ||
| 273 | |||
| 274 | return 0; | ||
| 275 | } | ||
| 276 | |||
| 277 | static int process_counter(struct perf_evsel *counter) | ||
| 353 | { | 278 | { |
| 354 | struct perf_counts_values *aggr = &counter->counts->aggr; | 279 | struct perf_counts_values *aggr = &counter->counts->aggr; |
| 355 | struct perf_stat *ps = counter->priv; | 280 | struct perf_stat *ps = counter->priv; |
| 356 | u64 *count = counter->counts->aggr.values; | 281 | u64 *count = counter->counts->aggr.values; |
| 357 | int i; | 282 | int i, ret; |
| 358 | 283 | ||
| 359 | aggr->val = aggr->ena = aggr->run = 0; | 284 | aggr->val = aggr->ena = aggr->run = 0; |
| 285 | init_stats(ps->res_stats); | ||
| 360 | 286 | ||
| 361 | if (read_counter(counter)) | 287 | if (counter->per_pkg) |
| 362 | return -1; | 288 | zero_per_pkg(counter); |
| 289 | |||
| 290 | ret = process_counter_maps(counter); | ||
| 291 | if (ret) | ||
| 292 | return ret; | ||
| 293 | |||
| 294 | if (aggr_mode != AGGR_GLOBAL) | ||
| 295 | return 0; | ||
| 363 | 296 | ||
| 364 | if (!counter->snapshot) | 297 | if (!counter->snapshot) |
| 365 | perf_evsel__compute_deltas(counter, -1, aggr); | 298 | perf_evsel__compute_deltas(counter, -1, -1, aggr); |
| 366 | perf_counts_values__scale(aggr, scale, &counter->counts->scaled); | 299 | perf_counts_values__scale(aggr, scale, &counter->counts->scaled); |
| 367 | 300 | ||
| 368 | for (i = 0; i < 3; i++) | 301 | for (i = 0; i < 3; i++) |
| @@ -397,12 +330,12 @@ static int read_counter(struct perf_evsel *counter) | |||
| 397 | if (counter->system_wide) | 330 | if (counter->system_wide) |
| 398 | nthreads = 1; | 331 | nthreads = 1; |
| 399 | 332 | ||
| 400 | if (counter->per_pkg) | ||
| 401 | zero_per_pkg(counter); | ||
| 402 | |||
| 403 | for (thread = 0; thread < nthreads; thread++) { | 333 | for (thread = 0; thread < nthreads; thread++) { |
| 404 | for (cpu = 0; cpu < ncpus; cpu++) { | 334 | for (cpu = 0; cpu < ncpus; cpu++) { |
| 405 | if (perf_evsel__read_cb(counter, cpu, thread, read_cb)) | 335 | struct perf_counts_values *count; |
| 336 | |||
| 337 | count = perf_counts(counter->counts, cpu, thread); | ||
| 338 | if (perf_evsel__read(counter, cpu, thread, count)) | ||
| 406 | return -1; | 339 | return -1; |
| 407 | } | 340 | } |
| 408 | } | 341 | } |
| @@ -410,68 +343,34 @@ static int read_counter(struct perf_evsel *counter) | |||
| 410 | return 0; | 343 | return 0; |
| 411 | } | 344 | } |
| 412 | 345 | ||
| 413 | static void print_interval(void) | 346 | static void read_counters(bool close) |
| 414 | { | 347 | { |
| 415 | static int num_print_interval; | ||
| 416 | struct perf_evsel *counter; | 348 | struct perf_evsel *counter; |
| 417 | struct perf_stat *ps; | ||
| 418 | struct timespec ts, rs; | ||
| 419 | char prefix[64]; | ||
| 420 | 349 | ||
| 421 | if (aggr_mode == AGGR_GLOBAL) { | 350 | evlist__for_each(evsel_list, counter) { |
| 422 | evlist__for_each(evsel_list, counter) { | 351 | if (read_counter(counter)) |
| 423 | ps = counter->priv; | 352 | pr_warning("failed to read counter %s\n", counter->name); |
| 424 | memset(ps->res_stats, 0, sizeof(ps->res_stats)); | ||
| 425 | read_counter_aggr(counter); | ||
| 426 | } | ||
| 427 | } else { | ||
| 428 | evlist__for_each(evsel_list, counter) { | ||
| 429 | ps = counter->priv; | ||
| 430 | memset(ps->res_stats, 0, sizeof(ps->res_stats)); | ||
| 431 | read_counter(counter); | ||
| 432 | } | ||
| 433 | } | ||
| 434 | 353 | ||
| 435 | clock_gettime(CLOCK_MONOTONIC, &ts); | 354 | if (process_counter(counter)) |
| 436 | diff_timespec(&rs, &ts, &ref_time); | 355 | pr_warning("failed to process counter %s\n", counter->name); |
| 437 | sprintf(prefix, "%6lu.%09lu%s", rs.tv_sec, rs.tv_nsec, csv_sep); | ||
| 438 | 356 | ||
| 439 | if (num_print_interval == 0 && !csv_output) { | 357 | if (close) { |
| 440 | switch (aggr_mode) { | 358 | perf_evsel__close_fd(counter, perf_evsel__nr_cpus(counter), |
| 441 | case AGGR_SOCKET: | 359 | thread_map__nr(evsel_list->threads)); |
| 442 | fprintf(output, "# time socket cpus counts %*s events\n", unit_width, "unit"); | ||
| 443 | break; | ||
| 444 | case AGGR_CORE: | ||
| 445 | fprintf(output, "# time core cpus counts %*s events\n", unit_width, "unit"); | ||
| 446 | break; | ||
| 447 | case AGGR_NONE: | ||
| 448 | fprintf(output, "# time CPU counts %*s events\n", unit_width, "unit"); | ||
| 449 | break; | ||
| 450 | case AGGR_GLOBAL: | ||
| 451 | default: | ||
| 452 | fprintf(output, "# time counts %*s events\n", unit_width, "unit"); | ||
| 453 | } | 360 | } |
| 454 | } | 361 | } |
| 362 | } | ||
| 455 | 363 | ||
| 456 | if (++num_print_interval == 25) | 364 | static void process_interval(void) |
| 457 | num_print_interval = 0; | 365 | { |
| 366 | struct timespec ts, rs; | ||
| 458 | 367 | ||
| 459 | switch (aggr_mode) { | 368 | read_counters(false); |
| 460 | case AGGR_CORE: | ||
| 461 | case AGGR_SOCKET: | ||
| 462 | print_aggr(prefix); | ||
| 463 | break; | ||
| 464 | case AGGR_NONE: | ||
| 465 | evlist__for_each(evsel_list, counter) | ||
| 466 | print_counter(counter, prefix); | ||
| 467 | break; | ||
| 468 | case AGGR_GLOBAL: | ||
| 469 | default: | ||
| 470 | evlist__for_each(evsel_list, counter) | ||
| 471 | print_counter_aggr(counter, prefix); | ||
| 472 | } | ||
| 473 | 369 | ||
| 474 | fflush(output); | 370 | clock_gettime(CLOCK_MONOTONIC, &ts); |
| 371 | diff_timespec(&rs, &ts, &ref_time); | ||
| 372 | |||
| 373 | print_counters(&rs, 0, NULL); | ||
| 475 | } | 374 | } |
| 476 | 375 | ||
| 477 | static void handle_initial_delay(void) | 376 | static void handle_initial_delay(void) |
| @@ -586,7 +485,7 @@ static int __run_perf_stat(int argc, const char **argv) | |||
| 586 | if (interval) { | 485 | if (interval) { |
| 587 | while (!waitpid(child_pid, &status, WNOHANG)) { | 486 | while (!waitpid(child_pid, &status, WNOHANG)) { |
| 588 | nanosleep(&ts, NULL); | 487 | nanosleep(&ts, NULL); |
| 589 | print_interval(); | 488 | process_interval(); |
| 590 | } | 489 | } |
| 591 | } | 490 | } |
| 592 | wait(&status); | 491 | wait(&status); |
| @@ -604,7 +503,7 @@ static int __run_perf_stat(int argc, const char **argv) | |||
| 604 | while (!done) { | 503 | while (!done) { |
| 605 | nanosleep(&ts, NULL); | 504 | nanosleep(&ts, NULL); |
| 606 | if (interval) | 505 | if (interval) |
| 607 | print_interval(); | 506 | process_interval(); |
| 608 | } | 507 | } |
| 609 | } | 508 | } |
| 610 | 509 | ||
| @@ -612,18 +511,7 @@ static int __run_perf_stat(int argc, const char **argv) | |||
| 612 | 511 | ||
| 613 | update_stats(&walltime_nsecs_stats, t1 - t0); | 512 | update_stats(&walltime_nsecs_stats, t1 - t0); |
| 614 | 513 | ||
| 615 | if (aggr_mode == AGGR_GLOBAL) { | 514 | read_counters(true); |
| 616 | evlist__for_each(evsel_list, counter) { | ||
| 617 | read_counter_aggr(counter); | ||
| 618 | perf_evsel__close_fd(counter, perf_evsel__nr_cpus(counter), | ||
| 619 | thread_map__nr(evsel_list->threads)); | ||
| 620 | } | ||
| 621 | } else { | ||
| 622 | evlist__for_each(evsel_list, counter) { | ||
| 623 | read_counter(counter); | ||
| 624 | perf_evsel__close_fd(counter, perf_evsel__nr_cpus(counter), 1); | ||
| 625 | } | ||
| 626 | } | ||
| 627 | 515 | ||
| 628 | return WEXITSTATUS(status); | 516 | return WEXITSTATUS(status); |
| 629 | } | 517 | } |
| @@ -715,6 +603,14 @@ static void aggr_printout(struct perf_evsel *evsel, int id, int nr) | |||
| 715 | csv_output ? 0 : -4, | 603 | csv_output ? 0 : -4, |
| 716 | perf_evsel__cpus(evsel)->map[id], csv_sep); | 604 | perf_evsel__cpus(evsel)->map[id], csv_sep); |
| 717 | break; | 605 | break; |
| 606 | case AGGR_THREAD: | ||
| 607 | fprintf(output, "%*s-%*d%s", | ||
| 608 | csv_output ? 0 : 16, | ||
| 609 | thread_map__comm(evsel->threads, id), | ||
| 610 | csv_output ? 0 : -8, | ||
| 611 | thread_map__pid(evsel->threads, id), | ||
| 612 | csv_sep); | ||
| 613 | break; | ||
| 718 | case AGGR_GLOBAL: | 614 | case AGGR_GLOBAL: |
| 719 | default: | 615 | default: |
| 720 | break; | 616 | break; |
| @@ -815,9 +711,9 @@ static void print_aggr(char *prefix) | |||
| 815 | s2 = aggr_get_id(evsel_list->cpus, cpu2); | 711 | s2 = aggr_get_id(evsel_list->cpus, cpu2); |
| 816 | if (s2 != id) | 712 | if (s2 != id) |
| 817 | continue; | 713 | continue; |
| 818 | val += counter->counts->cpu[cpu].val; | 714 | val += perf_counts(counter->counts, cpu, 0)->val; |
| 819 | ena += counter->counts->cpu[cpu].ena; | 715 | ena += perf_counts(counter->counts, cpu, 0)->ena; |
| 820 | run += counter->counts->cpu[cpu].run; | 716 | run += perf_counts(counter->counts, cpu, 0)->run; |
| 821 | nr++; | 717 | nr++; |
| 822 | } | 718 | } |
| 823 | if (prefix) | 719 | if (prefix) |
| @@ -863,6 +759,40 @@ static void print_aggr(char *prefix) | |||
| 863 | } | 759 | } |
| 864 | } | 760 | } |
| 865 | 761 | ||
| 762 | static void print_aggr_thread(struct perf_evsel *counter, char *prefix) | ||
| 763 | { | ||
| 764 | int nthreads = thread_map__nr(counter->threads); | ||
| 765 | int ncpus = cpu_map__nr(counter->cpus); | ||
| 766 | int cpu, thread; | ||
| 767 | double uval; | ||
| 768 | |||
| 769 | for (thread = 0; thread < nthreads; thread++) { | ||
| 770 | u64 ena = 0, run = 0, val = 0; | ||
| 771 | |||
| 772 | for (cpu = 0; cpu < ncpus; cpu++) { | ||
| 773 | val += perf_counts(counter->counts, cpu, thread)->val; | ||
| 774 | ena += perf_counts(counter->counts, cpu, thread)->ena; | ||
| 775 | run += perf_counts(counter->counts, cpu, thread)->run; | ||
| 776 | } | ||
| 777 | |||
| 778 | if (prefix) | ||
| 779 | fprintf(output, "%s", prefix); | ||
| 780 | |||
| 781 | uval = val * counter->scale; | ||
| 782 | |||
| 783 | if (nsec_counter(counter)) | ||
| 784 | nsec_printout(thread, 0, counter, uval); | ||
| 785 | else | ||
| 786 | abs_printout(thread, 0, counter, uval); | ||
| 787 | |||
| 788 | if (!csv_output) | ||
| 789 | print_noise(counter, 1.0); | ||
| 790 | |||
| 791 | print_running(run, ena); | ||
| 792 | fputc('\n', output); | ||
| 793 | } | ||
| 794 | } | ||
| 795 | |||
| 866 | /* | 796 | /* |
| 867 | * Print out the results of a single counter: | 797 | * Print out the results of a single counter: |
| 868 | * aggregated counts in system-wide mode | 798 | * aggregated counts in system-wide mode |
| @@ -925,9 +855,9 @@ static void print_counter(struct perf_evsel *counter, char *prefix) | |||
| 925 | int cpu; | 855 | int cpu; |
| 926 | 856 | ||
| 927 | for (cpu = 0; cpu < perf_evsel__nr_cpus(counter); cpu++) { | 857 | for (cpu = 0; cpu < perf_evsel__nr_cpus(counter); cpu++) { |
| 928 | val = counter->counts->cpu[cpu].val; | 858 | val = perf_counts(counter->counts, cpu, 0)->val; |
| 929 | ena = counter->counts->cpu[cpu].ena; | 859 | ena = perf_counts(counter->counts, cpu, 0)->ena; |
| 930 | run = counter->counts->cpu[cpu].run; | 860 | run = perf_counts(counter->counts, cpu, 0)->run; |
| 931 | 861 | ||
| 932 | if (prefix) | 862 | if (prefix) |
| 933 | fprintf(output, "%s", prefix); | 863 | fprintf(output, "%s", prefix); |
| @@ -972,9 +902,38 @@ static void print_counter(struct perf_evsel *counter, char *prefix) | |||
| 972 | } | 902 | } |
| 973 | } | 903 | } |
| 974 | 904 | ||
| 975 | static void print_stat(int argc, const char **argv) | 905 | static void print_interval(char *prefix, struct timespec *ts) |
| 906 | { | ||
| 907 | static int num_print_interval; | ||
| 908 | |||
| 909 | sprintf(prefix, "%6lu.%09lu%s", ts->tv_sec, ts->tv_nsec, csv_sep); | ||
| 910 | |||
| 911 | if (num_print_interval == 0 && !csv_output) { | ||
| 912 | switch (aggr_mode) { | ||
| 913 | case AGGR_SOCKET: | ||
| 914 | fprintf(output, "# time socket cpus counts %*s events\n", unit_width, "unit"); | ||
| 915 | break; | ||
| 916 | case AGGR_CORE: | ||
| 917 | fprintf(output, "# time core cpus counts %*s events\n", unit_width, "unit"); | ||
| 918 | break; | ||
| 919 | case AGGR_NONE: | ||
| 920 | fprintf(output, "# time CPU counts %*s events\n", unit_width, "unit"); | ||
| 921 | break; | ||
| 922 | case AGGR_THREAD: | ||
| 923 | fprintf(output, "# time comm-pid counts %*s events\n", unit_width, "unit"); | ||
| 924 | break; | ||
| 925 | case AGGR_GLOBAL: | ||
| 926 | default: | ||
| 927 | fprintf(output, "# time counts %*s events\n", unit_width, "unit"); | ||
| 928 | } | ||
| 929 | } | ||
| 930 | |||
| 931 | if (++num_print_interval == 25) | ||
| 932 | num_print_interval = 0; | ||
| 933 | } | ||
| 934 | |||
| 935 | static void print_header(int argc, const char **argv) | ||
| 976 | { | 936 | { |
| 977 | struct perf_evsel *counter; | ||
| 978 | int i; | 937 | int i; |
| 979 | 938 | ||
| 980 | fflush(stdout); | 939 | fflush(stdout); |
| @@ -1000,36 +959,57 @@ static void print_stat(int argc, const char **argv) | |||
| 1000 | fprintf(output, " (%d runs)", run_count); | 959 | fprintf(output, " (%d runs)", run_count); |
| 1001 | fprintf(output, ":\n\n"); | 960 | fprintf(output, ":\n\n"); |
| 1002 | } | 961 | } |
| 962 | } | ||
| 963 | |||
| 964 | static void print_footer(void) | ||
| 965 | { | ||
| 966 | if (!null_run) | ||
| 967 | fprintf(output, "\n"); | ||
| 968 | fprintf(output, " %17.9f seconds time elapsed", | ||
| 969 | avg_stats(&walltime_nsecs_stats)/1e9); | ||
| 970 | if (run_count > 1) { | ||
| 971 | fprintf(output, " "); | ||
| 972 | print_noise_pct(stddev_stats(&walltime_nsecs_stats), | ||
| 973 | avg_stats(&walltime_nsecs_stats)); | ||
| 974 | } | ||
| 975 | fprintf(output, "\n\n"); | ||
| 976 | } | ||
| 977 | |||
| 978 | static void print_counters(struct timespec *ts, int argc, const char **argv) | ||
| 979 | { | ||
| 980 | struct perf_evsel *counter; | ||
| 981 | char buf[64], *prefix = NULL; | ||
| 982 | |||
| 983 | if (interval) | ||
| 984 | print_interval(prefix = buf, ts); | ||
| 985 | else | ||
| 986 | print_header(argc, argv); | ||
| 1003 | 987 | ||
| 1004 | switch (aggr_mode) { | 988 | switch (aggr_mode) { |
| 1005 | case AGGR_CORE: | 989 | case AGGR_CORE: |
| 1006 | case AGGR_SOCKET: | 990 | case AGGR_SOCKET: |
| 1007 | print_aggr(NULL); | 991 | print_aggr(prefix); |
| 992 | break; | ||
| 993 | case AGGR_THREAD: | ||
| 994 | evlist__for_each(evsel_list, counter) | ||
| 995 | print_aggr_thread(counter, prefix); | ||
| 1008 | break; | 996 | break; |
| 1009 | case AGGR_GLOBAL: | 997 | case AGGR_GLOBAL: |
| 1010 | evlist__for_each(evsel_list, counter) | 998 | evlist__for_each(evsel_list, counter) |
| 1011 | print_counter_aggr(counter, NULL); | 999 | print_counter_aggr(counter, prefix); |
| 1012 | break; | 1000 | break; |
| 1013 | case AGGR_NONE: | 1001 | case AGGR_NONE: |
| 1014 | evlist__for_each(evsel_list, counter) | 1002 | evlist__for_each(evsel_list, counter) |
| 1015 | print_counter(counter, NULL); | 1003 | print_counter(counter, prefix); |
| 1016 | break; | 1004 | break; |
| 1017 | default: | 1005 | default: |
| 1018 | break; | 1006 | break; |
| 1019 | } | 1007 | } |
| 1020 | 1008 | ||
| 1021 | if (!csv_output) { | 1009 | if (!interval && !csv_output) |
| 1022 | if (!null_run) | 1010 | print_footer(); |
| 1023 | fprintf(output, "\n"); | 1011 | |
| 1024 | fprintf(output, " %17.9f seconds time elapsed", | 1012 | fflush(output); |
| 1025 | avg_stats(&walltime_nsecs_stats)/1e9); | ||
| 1026 | if (run_count > 1) { | ||
| 1027 | fprintf(output, " "); | ||
| 1028 | print_noise_pct(stddev_stats(&walltime_nsecs_stats), | ||
| 1029 | avg_stats(&walltime_nsecs_stats)); | ||
| 1030 | } | ||
| 1031 | fprintf(output, "\n\n"); | ||
| 1032 | } | ||
| 1033 | } | 1013 | } |
| 1034 | 1014 | ||
| 1035 | static volatile int signr = -1; | 1015 | static volatile int signr = -1; |
| @@ -1101,6 +1081,7 @@ static int perf_stat_init_aggr_mode(void) | |||
| 1101 | break; | 1081 | break; |
| 1102 | case AGGR_NONE: | 1082 | case AGGR_NONE: |
| 1103 | case AGGR_GLOBAL: | 1083 | case AGGR_GLOBAL: |
| 1084 | case AGGR_THREAD: | ||
| 1104 | default: | 1085 | default: |
| 1105 | break; | 1086 | break; |
| 1106 | } | 1087 | } |
| @@ -1325,6 +1306,8 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused) | |||
| 1325 | "aggregate counts per processor socket", AGGR_SOCKET), | 1306 | "aggregate counts per processor socket", AGGR_SOCKET), |
| 1326 | OPT_SET_UINT(0, "per-core", &aggr_mode, | 1307 | OPT_SET_UINT(0, "per-core", &aggr_mode, |
| 1327 | "aggregate counts per physical processor core", AGGR_CORE), | 1308 | "aggregate counts per physical processor core", AGGR_CORE), |
| 1309 | OPT_SET_UINT(0, "per-thread", &aggr_mode, | ||
| 1310 | "aggregate counts per thread", AGGR_THREAD), | ||
| 1328 | OPT_UINTEGER('D', "delay", &initial_delay, | 1311 | OPT_UINTEGER('D', "delay", &initial_delay, |
| 1329 | "ms to wait before starting measurement after program start"), | 1312 | "ms to wait before starting measurement after program start"), |
| 1330 | OPT_END() | 1313 | OPT_END() |
| @@ -1416,8 +1399,19 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused) | |||
| 1416 | run_count = 1; | 1399 | run_count = 1; |
| 1417 | } | 1400 | } |
| 1418 | 1401 | ||
| 1419 | /* no_aggr, cgroup are for system-wide only */ | 1402 | if ((aggr_mode == AGGR_THREAD) && !target__has_task(&target)) { |
| 1420 | if ((aggr_mode != AGGR_GLOBAL || nr_cgroups) && | 1403 | fprintf(stderr, "The --per-thread option is only available " |
| 1404 | "when monitoring via -p -t options.\n"); | ||
| 1405 | parse_options_usage(NULL, options, "p", 1); | ||
| 1406 | parse_options_usage(NULL, options, "t", 1); | ||
| 1407 | goto out; | ||
| 1408 | } | ||
| 1409 | |||
| 1410 | /* | ||
| 1411 | * no_aggr, cgroup are for system-wide only | ||
| 1412 | * --per-thread is aggregated per thread, we dont mix it with cpu mode | ||
| 1413 | */ | ||
| 1414 | if (((aggr_mode != AGGR_GLOBAL && aggr_mode != AGGR_THREAD) || nr_cgroups) && | ||
| 1421 | !target__has_cpu(&target)) { | 1415 | !target__has_cpu(&target)) { |
| 1422 | fprintf(stderr, "both cgroup and no-aggregation " | 1416 | fprintf(stderr, "both cgroup and no-aggregation " |
| 1423 | "modes only available in system-wide mode\n"); | 1417 | "modes only available in system-wide mode\n"); |
| @@ -1445,6 +1439,14 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused) | |||
| 1445 | } | 1439 | } |
| 1446 | goto out; | 1440 | goto out; |
| 1447 | } | 1441 | } |
| 1442 | |||
| 1443 | /* | ||
| 1444 | * Initialize thread_map with comm names, | ||
| 1445 | * so we could print it out on output. | ||
| 1446 | */ | ||
| 1447 | if (aggr_mode == AGGR_THREAD) | ||
| 1448 | thread_map__read_comms(evsel_list->threads); | ||
| 1449 | |||
| 1448 | if (interval && interval < 100) { | 1450 | if (interval && interval < 100) { |
| 1449 | pr_err("print interval must be >= 100ms\n"); | 1451 | pr_err("print interval must be >= 100ms\n"); |
| 1450 | parse_options_usage(stat_usage, options, "I", 1); | 1452 | parse_options_usage(stat_usage, options, "I", 1); |
| @@ -1478,13 +1480,13 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused) | |||
| 1478 | 1480 | ||
| 1479 | status = run_perf_stat(argc, argv); | 1481 | status = run_perf_stat(argc, argv); |
| 1480 | if (forever && status != -1) { | 1482 | if (forever && status != -1) { |
| 1481 | print_stat(argc, argv); | 1483 | print_counters(NULL, argc, argv); |
| 1482 | perf_stat__reset_stats(evsel_list); | 1484 | perf_stat__reset_stats(); |
| 1483 | } | 1485 | } |
| 1484 | } | 1486 | } |
| 1485 | 1487 | ||
| 1486 | if (!forever && status != -1 && !interval) | 1488 | if (!forever && status != -1 && !interval) |
| 1487 | print_stat(argc, argv); | 1489 | print_counters(NULL, argc, argv); |
| 1488 | 1490 | ||
| 1489 | perf_evlist__free_stats(evsel_list); | 1491 | perf_evlist__free_stats(evsel_list); |
| 1490 | out: | 1492 | out: |
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index 619a8696fda7..ecf319728f25 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c | |||
| @@ -586,27 +586,9 @@ static void *display_thread_tui(void *arg) | |||
| 586 | hists->uid_filter_str = top->record_opts.target.uid_str; | 586 | hists->uid_filter_str = top->record_opts.target.uid_str; |
| 587 | } | 587 | } |
| 588 | 588 | ||
| 589 | while (true) { | 589 | perf_evlist__tui_browse_hists(top->evlist, help, &hbt, |
| 590 | int key = perf_evlist__tui_browse_hists(top->evlist, help, &hbt, | 590 | top->min_percent, |
| 591 | top->min_percent, | 591 | &top->session->header.env); |
| 592 | &top->session->header.env); | ||
| 593 | |||
| 594 | if (key != 'f') | ||
| 595 | break; | ||
| 596 | |||
| 597 | perf_evlist__toggle_enable(top->evlist); | ||
| 598 | /* | ||
| 599 | * No need to refresh, resort/decay histogram entries | ||
| 600 | * if we are not collecting samples: | ||
| 601 | */ | ||
| 602 | if (top->evlist->enabled) { | ||
| 603 | hbt.refresh = top->delay_secs; | ||
| 604 | help = "Press 'f' to disable the events or 'h' to see other hotkeys"; | ||
| 605 | } else { | ||
| 606 | help = "Press 'f' again to re-enable the events"; | ||
| 607 | hbt.refresh = 0; | ||
| 608 | } | ||
| 609 | } | ||
| 610 | 592 | ||
| 611 | done = 1; | 593 | done = 1; |
| 612 | return NULL; | 594 | return NULL; |
diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c index de5d277d1ad7..39ad4d0ca884 100644 --- a/tools/perf/builtin-trace.c +++ b/tools/perf/builtin-trace.c | |||
| @@ -1617,6 +1617,34 @@ static int trace__read_syscall_info(struct trace *trace, int id) | |||
| 1617 | return syscall__set_arg_fmts(sc); | 1617 | return syscall__set_arg_fmts(sc); |
| 1618 | } | 1618 | } |
| 1619 | 1619 | ||
| 1620 | static int trace__validate_ev_qualifier(struct trace *trace) | ||
| 1621 | { | ||
| 1622 | int err = 0; | ||
| 1623 | struct str_node *pos; | ||
| 1624 | |||
| 1625 | strlist__for_each(pos, trace->ev_qualifier) { | ||
| 1626 | const char *sc = pos->s; | ||
| 1627 | |||
| 1628 | if (audit_name_to_syscall(sc, trace->audit.machine) < 0) { | ||
| 1629 | if (err == 0) { | ||
| 1630 | fputs("Error:\tInvalid syscall ", trace->output); | ||
| 1631 | err = -EINVAL; | ||
| 1632 | } else { | ||
| 1633 | fputs(", ", trace->output); | ||
| 1634 | } | ||
| 1635 | |||
| 1636 | fputs(sc, trace->output); | ||
| 1637 | } | ||
| 1638 | } | ||
| 1639 | |||
| 1640 | if (err < 0) { | ||
| 1641 | fputs("\nHint:\ttry 'perf list syscalls:sys_enter_*'" | ||
| 1642 | "\nHint:\tand: 'man syscalls'\n", trace->output); | ||
| 1643 | } | ||
| 1644 | |||
| 1645 | return err; | ||
| 1646 | } | ||
| 1647 | |||
| 1620 | /* | 1648 | /* |
| 1621 | * args is to be interpreted as a series of longs but we need to handle | 1649 | * args is to be interpreted as a series of longs but we need to handle |
| 1622 | * 8-byte unaligned accesses. args points to raw_data within the event | 1650 | * 8-byte unaligned accesses. args points to raw_data within the event |
| @@ -2325,7 +2353,7 @@ static int trace__run(struct trace *trace, int argc, const char **argv) | |||
| 2325 | */ | 2353 | */ |
| 2326 | if (trace->filter_pids.nr > 0) | 2354 | if (trace->filter_pids.nr > 0) |
| 2327 | err = perf_evlist__set_filter_pids(evlist, trace->filter_pids.nr, trace->filter_pids.entries); | 2355 | err = perf_evlist__set_filter_pids(evlist, trace->filter_pids.nr, trace->filter_pids.entries); |
| 2328 | else if (evlist->threads->map[0] == -1) | 2356 | else if (thread_map__pid(evlist->threads, 0) == -1) |
| 2329 | err = perf_evlist__set_filter_pid(evlist, getpid()); | 2357 | err = perf_evlist__set_filter_pid(evlist, getpid()); |
| 2330 | 2358 | ||
| 2331 | if (err < 0) { | 2359 | if (err < 0) { |
| @@ -2343,7 +2371,7 @@ static int trace__run(struct trace *trace, int argc, const char **argv) | |||
| 2343 | if (forks) | 2371 | if (forks) |
| 2344 | perf_evlist__start_workload(evlist); | 2372 | perf_evlist__start_workload(evlist); |
| 2345 | 2373 | ||
| 2346 | trace->multiple_threads = evlist->threads->map[0] == -1 || | 2374 | trace->multiple_threads = thread_map__pid(evlist->threads, 0) == -1 || |
| 2347 | evlist->threads->nr > 1 || | 2375 | evlist->threads->nr > 1 || |
| 2348 | perf_evlist__first(evlist)->attr.inherit; | 2376 | perf_evlist__first(evlist)->attr.inherit; |
| 2349 | again: | 2377 | again: |
| @@ -2862,6 +2890,10 @@ int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused) | |||
| 2862 | err = -ENOMEM; | 2890 | err = -ENOMEM; |
| 2863 | goto out_close; | 2891 | goto out_close; |
| 2864 | } | 2892 | } |
| 2893 | |||
| 2894 | err = trace__validate_ev_qualifier(&trace); | ||
| 2895 | if (err) | ||
| 2896 | goto out_close; | ||
| 2865 | } | 2897 | } |
| 2866 | 2898 | ||
| 2867 | err = target__validate(&trace.opts.target); | 2899 | err = target__validate(&trace.opts.target); |
diff --git a/tools/perf/config/Makefile b/tools/perf/config/Makefile index 317001c94660..094ddaee104c 100644 --- a/tools/perf/config/Makefile +++ b/tools/perf/config/Makefile | |||
| @@ -11,9 +11,9 @@ ifneq ($(obj-perf),) | |||
| 11 | obj-perf := $(abspath $(obj-perf))/ | 11 | obj-perf := $(abspath $(obj-perf))/ |
| 12 | endif | 12 | endif |
| 13 | 13 | ||
| 14 | $(shell echo -n > .config-detected) | 14 | $(shell echo -n > $(OUTPUT).config-detected) |
| 15 | detected = $(shell echo "$(1)=y" >> .config-detected) | 15 | detected = $(shell echo "$(1)=y" >> $(OUTPUT).config-detected) |
| 16 | detected_var = $(shell echo "$(1)=$($(1))" >> .config-detected) | 16 | detected_var = $(shell echo "$(1)=$($(1))" >> $(OUTPUT).config-detected) |
| 17 | 17 | ||
| 18 | CFLAGS := $(EXTRA_CFLAGS) $(EXTRA_WARNINGS) | 18 | CFLAGS := $(EXTRA_CFLAGS) $(EXTRA_WARNINGS) |
| 19 | 19 | ||
diff --git a/tools/perf/tests/Build b/tools/perf/tests/Build index ee41e705b2eb..d20d6e6ab65b 100644 --- a/tools/perf/tests/Build +++ b/tools/perf/tests/Build | |||
| @@ -31,6 +31,7 @@ perf-y += code-reading.o | |||
| 31 | perf-y += sample-parsing.o | 31 | perf-y += sample-parsing.o |
| 32 | perf-y += parse-no-sample-id-all.o | 32 | perf-y += parse-no-sample-id-all.o |
| 33 | perf-y += kmod-path.o | 33 | perf-y += kmod-path.o |
| 34 | perf-y += thread-map.o | ||
| 34 | 35 | ||
| 35 | perf-$(CONFIG_X86) += perf-time-to-tsc.o | 36 | perf-$(CONFIG_X86) += perf-time-to-tsc.o |
| 36 | 37 | ||
diff --git a/tools/perf/tests/builtin-test.c b/tools/perf/tests/builtin-test.c index 87b9961646e4..c1dde733c3a6 100644 --- a/tools/perf/tests/builtin-test.c +++ b/tools/perf/tests/builtin-test.c | |||
| @@ -171,6 +171,10 @@ static struct test { | |||
| 171 | .func = test__kmod_path__parse, | 171 | .func = test__kmod_path__parse, |
| 172 | }, | 172 | }, |
| 173 | { | 173 | { |
| 174 | .desc = "Test thread map", | ||
| 175 | .func = test__thread_map, | ||
| 176 | }, | ||
| 177 | { | ||
| 174 | .func = NULL, | 178 | .func = NULL, |
| 175 | }, | 179 | }, |
| 176 | }; | 180 | }; |
diff --git a/tools/perf/tests/code-reading.c b/tools/perf/tests/code-reading.c index 22f8a00446e1..39c784a100a9 100644 --- a/tools/perf/tests/code-reading.c +++ b/tools/perf/tests/code-reading.c | |||
| @@ -545,8 +545,8 @@ out_err: | |||
| 545 | if (evlist) { | 545 | if (evlist) { |
| 546 | perf_evlist__delete(evlist); | 546 | perf_evlist__delete(evlist); |
| 547 | } else { | 547 | } else { |
| 548 | cpu_map__delete(cpus); | 548 | cpu_map__put(cpus); |
| 549 | thread_map__delete(threads); | 549 | thread_map__put(threads); |
| 550 | } | 550 | } |
| 551 | machines__destroy_kernel_maps(&machines); | 551 | machines__destroy_kernel_maps(&machines); |
| 552 | machine__delete_threads(machine); | 552 | machine__delete_threads(machine); |
diff --git a/tools/perf/tests/keep-tracking.c b/tools/perf/tests/keep-tracking.c index 5b171d1e338b..4d4b9837b630 100644 --- a/tools/perf/tests/keep-tracking.c +++ b/tools/perf/tests/keep-tracking.c | |||
| @@ -144,8 +144,8 @@ out_err: | |||
| 144 | perf_evlist__disable(evlist); | 144 | perf_evlist__disable(evlist); |
| 145 | perf_evlist__delete(evlist); | 145 | perf_evlist__delete(evlist); |
| 146 | } else { | 146 | } else { |
| 147 | cpu_map__delete(cpus); | 147 | cpu_map__put(cpus); |
| 148 | thread_map__delete(threads); | 148 | thread_map__put(threads); |
| 149 | } | 149 | } |
| 150 | 150 | ||
| 151 | return err; | 151 | return err; |
diff --git a/tools/perf/tests/make b/tools/perf/tests/make index 65280d28662e..729112f4cfaa 100644 --- a/tools/perf/tests/make +++ b/tools/perf/tests/make | |||
| @@ -1,5 +1,16 @@ | |||
| 1 | ifndef MK | ||
| 2 | ifeq ($(MAKECMDGOALS),) | ||
| 3 | # no target specified, trigger the whole suite | ||
| 4 | all: | ||
| 5 | @echo "Testing Makefile"; $(MAKE) -sf tests/make MK=Makefile | ||
| 6 | @echo "Testing Makefile.perf"; $(MAKE) -sf tests/make MK=Makefile.perf | ||
| 7 | else | ||
| 8 | # run only specific test over 'Makefile' | ||
| 9 | %: | ||
| 10 | @echo "Testing Makefile"; $(MAKE) -sf tests/make MK=Makefile $@ | ||
| 11 | endif | ||
| 12 | else | ||
| 1 | PERF := . | 13 | PERF := . |
| 2 | MK := Makefile | ||
| 3 | 14 | ||
| 4 | include config/Makefile.arch | 15 | include config/Makefile.arch |
| 5 | 16 | ||
| @@ -47,6 +58,7 @@ make_install_man := install-man | |||
| 47 | make_install_html := install-html | 58 | make_install_html := install-html |
| 48 | make_install_info := install-info | 59 | make_install_info := install-info |
| 49 | make_install_pdf := install-pdf | 60 | make_install_pdf := install-pdf |
| 61 | make_install_prefix := install prefix=/tmp/krava | ||
| 50 | make_static := LDFLAGS=-static | 62 | make_static := LDFLAGS=-static |
| 51 | 63 | ||
| 52 | # all the NO_* variable combined | 64 | # all the NO_* variable combined |
| @@ -57,7 +69,12 @@ make_minimal += NO_LIBDW_DWARF_UNWIND=1 NO_AUXTRACE=1 | |||
| 57 | 69 | ||
| 58 | # $(run) contains all available tests | 70 | # $(run) contains all available tests |
| 59 | run := make_pure | 71 | run := make_pure |
| 72 | # Targets 'clean all' can be run together only through top level | ||
| 73 | # Makefile because we detect clean target in Makefile.perf and | ||
| 74 | # disable features detection | ||
| 75 | ifeq ($(MK),Makefile) | ||
| 60 | run += make_clean_all | 76 | run += make_clean_all |
| 77 | endif | ||
| 61 | run += make_python_perf_so | 78 | run += make_python_perf_so |
| 62 | run += make_debug | 79 | run += make_debug |
| 63 | run += make_no_libperl | 80 | run += make_no_libperl |
| @@ -83,6 +100,7 @@ run += make_util_map_o | |||
| 83 | run += make_util_pmu_bison_o | 100 | run += make_util_pmu_bison_o |
| 84 | run += make_install | 101 | run += make_install |
| 85 | run += make_install_bin | 102 | run += make_install_bin |
| 103 | run += make_install_prefix | ||
| 86 | # FIXME 'install-*' commented out till they're fixed | 104 | # FIXME 'install-*' commented out till they're fixed |
| 87 | # run += make_install_doc | 105 | # run += make_install_doc |
| 88 | # run += make_install_man | 106 | # run += make_install_man |
| @@ -157,6 +175,12 @@ test_make_install_O := $(call test_dest_files,$(installed_files_all)) | |||
| 157 | test_make_install_bin := $(call test_dest_files,$(installed_files_bin)) | 175 | test_make_install_bin := $(call test_dest_files,$(installed_files_bin)) |
| 158 | test_make_install_bin_O := $(call test_dest_files,$(installed_files_bin)) | 176 | test_make_install_bin_O := $(call test_dest_files,$(installed_files_bin)) |
| 159 | 177 | ||
| 178 | # We prefix all installed files for make_install_prefix | ||
| 179 | # with '/tmp/krava' to match installed/prefix-ed files. | ||
| 180 | installed_files_all_prefix := $(addprefix /tmp/krava/,$(installed_files_all)) | ||
| 181 | test_make_install_prefix := $(call test_dest_files,$(installed_files_all_prefix)) | ||
| 182 | test_make_install_prefix_O := $(call test_dest_files,$(installed_files_all_prefix)) | ||
| 183 | |||
| 160 | # FIXME nothing gets installed | 184 | # FIXME nothing gets installed |
| 161 | test_make_install_man := test -f $$TMP_DEST/share/man/man1/perf.1 | 185 | test_make_install_man := test -f $$TMP_DEST/share/man/man1/perf.1 |
| 162 | test_make_install_man_O := $(test_make_install_man) | 186 | test_make_install_man_O := $(test_make_install_man) |
| @@ -226,13 +250,13 @@ tarpkg: | |||
| 226 | ( eval $$cmd ) >> $@ 2>&1 | 250 | ( eval $$cmd ) >> $@ 2>&1 |
| 227 | 251 | ||
| 228 | make_kernelsrc: | 252 | make_kernelsrc: |
| 229 | @echo " - make -C <kernelsrc> tools/perf" | 253 | @echo "- make -C <kernelsrc> tools/perf" |
| 230 | $(call clean); \ | 254 | $(call clean); \ |
| 231 | (make -C ../.. tools/perf) > $@ 2>&1 && \ | 255 | (make -C ../.. tools/perf) > $@ 2>&1 && \ |
| 232 | test -x perf && rm -f $@ || (cat $@ ; false) | 256 | test -x perf && rm -f $@ || (cat $@ ; false) |
| 233 | 257 | ||
| 234 | make_kernelsrc_tools: | 258 | make_kernelsrc_tools: |
| 235 | @echo " - make -C <kernelsrc>/tools perf" | 259 | @echo "- make -C <kernelsrc>/tools perf" |
| 236 | $(call clean); \ | 260 | $(call clean); \ |
| 237 | (make -C ../../tools perf) > $@ 2>&1 && \ | 261 | (make -C ../../tools perf) > $@ 2>&1 && \ |
| 238 | test -x perf && rm -f $@ || (cat $@ ; false) | 262 | test -x perf && rm -f $@ || (cat $@ ; false) |
| @@ -244,3 +268,4 @@ out: $(run_O) | |||
| 244 | @echo OK | 268 | @echo OK |
| 245 | 269 | ||
| 246 | .PHONY: all $(run) $(run_O) tarpkg clean | 270 | .PHONY: all $(run) $(run_O) tarpkg clean |
| 271 | endif # ifndef MK | ||
diff --git a/tools/perf/tests/mmap-basic.c b/tools/perf/tests/mmap-basic.c index 5855cf471210..666b67a4df9d 100644 --- a/tools/perf/tests/mmap-basic.c +++ b/tools/perf/tests/mmap-basic.c | |||
| @@ -140,8 +140,8 @@ out_delete_evlist: | |||
| 140 | cpus = NULL; | 140 | cpus = NULL; |
| 141 | threads = NULL; | 141 | threads = NULL; |
| 142 | out_free_cpus: | 142 | out_free_cpus: |
| 143 | cpu_map__delete(cpus); | 143 | cpu_map__put(cpus); |
| 144 | out_free_threads: | 144 | out_free_threads: |
| 145 | thread_map__delete(threads); | 145 | thread_map__put(threads); |
| 146 | return err; | 146 | return err; |
| 147 | } | 147 | } |
diff --git a/tools/perf/tests/mmap-thread-lookup.c b/tools/perf/tests/mmap-thread-lookup.c index 7f48efa7e295..145050e2e544 100644 --- a/tools/perf/tests/mmap-thread-lookup.c +++ b/tools/perf/tests/mmap-thread-lookup.c | |||
| @@ -143,7 +143,7 @@ static int synth_process(struct machine *machine) | |||
| 143 | perf_event__process, | 143 | perf_event__process, |
| 144 | machine, 0, 500); | 144 | machine, 0, 500); |
| 145 | 145 | ||
| 146 | thread_map__delete(map); | 146 | thread_map__put(map); |
| 147 | return err; | 147 | return err; |
| 148 | } | 148 | } |
| 149 | 149 | ||
diff --git a/tools/perf/tests/openat-syscall-all-cpus.c b/tools/perf/tests/openat-syscall-all-cpus.c index 9a7a116e09b8..a572f87e9c8d 100644 --- a/tools/perf/tests/openat-syscall-all-cpus.c +++ b/tools/perf/tests/openat-syscall-all-cpus.c | |||
| @@ -78,7 +78,7 @@ int test__openat_syscall_event_on_all_cpus(void) | |||
| 78 | * we use the auto allocation it will allocate just for 1 cpu, | 78 | * we use the auto allocation it will allocate just for 1 cpu, |
| 79 | * as we start by cpu 0. | 79 | * as we start by cpu 0. |
| 80 | */ | 80 | */ |
| 81 | if (perf_evsel__alloc_counts(evsel, cpus->nr) < 0) { | 81 | if (perf_evsel__alloc_counts(evsel, cpus->nr, 1) < 0) { |
| 82 | pr_debug("perf_evsel__alloc_counts(ncpus=%d)\n", cpus->nr); | 82 | pr_debug("perf_evsel__alloc_counts(ncpus=%d)\n", cpus->nr); |
| 83 | goto out_close_fd; | 83 | goto out_close_fd; |
| 84 | } | 84 | } |
| @@ -98,9 +98,9 @@ int test__openat_syscall_event_on_all_cpus(void) | |||
| 98 | } | 98 | } |
| 99 | 99 | ||
| 100 | expected = nr_openat_calls + cpu; | 100 | expected = nr_openat_calls + cpu; |
| 101 | if (evsel->counts->cpu[cpu].val != expected) { | 101 | if (perf_counts(evsel->counts, cpu, 0)->val != expected) { |
| 102 | pr_debug("perf_evsel__read_on_cpu: expected to intercept %d calls on cpu %d, got %" PRIu64 "\n", | 102 | pr_debug("perf_evsel__read_on_cpu: expected to intercept %d calls on cpu %d, got %" PRIu64 "\n", |
| 103 | expected, cpus->map[cpu], evsel->counts->cpu[cpu].val); | 103 | expected, cpus->map[cpu], perf_counts(evsel->counts, cpu, 0)->val); |
| 104 | err = -1; | 104 | err = -1; |
| 105 | } | 105 | } |
| 106 | } | 106 | } |
| @@ -111,6 +111,6 @@ out_close_fd: | |||
| 111 | out_evsel_delete: | 111 | out_evsel_delete: |
| 112 | perf_evsel__delete(evsel); | 112 | perf_evsel__delete(evsel); |
| 113 | out_thread_map_delete: | 113 | out_thread_map_delete: |
| 114 | thread_map__delete(threads); | 114 | thread_map__put(threads); |
| 115 | return err; | 115 | return err; |
| 116 | } | 116 | } |
diff --git a/tools/perf/tests/openat-syscall-tp-fields.c b/tools/perf/tests/openat-syscall-tp-fields.c index 6245221479d7..01a19626c846 100644 --- a/tools/perf/tests/openat-syscall-tp-fields.c +++ b/tools/perf/tests/openat-syscall-tp-fields.c | |||
| @@ -45,7 +45,7 @@ int test__syscall_openat_tp_fields(void) | |||
| 45 | 45 | ||
| 46 | perf_evsel__config(evsel, &opts); | 46 | perf_evsel__config(evsel, &opts); |
| 47 | 47 | ||
| 48 | evlist->threads->map[0] = getpid(); | 48 | thread_map__set_pid(evlist->threads, 0, getpid()); |
| 49 | 49 | ||
| 50 | err = perf_evlist__open(evlist); | 50 | err = perf_evlist__open(evlist); |
| 51 | if (err < 0) { | 51 | if (err < 0) { |
diff --git a/tools/perf/tests/openat-syscall.c b/tools/perf/tests/openat-syscall.c index 9f9491bb8e48..c9a37bc6b33a 100644 --- a/tools/perf/tests/openat-syscall.c +++ b/tools/perf/tests/openat-syscall.c | |||
| @@ -44,9 +44,9 @@ int test__openat_syscall_event(void) | |||
| 44 | goto out_close_fd; | 44 | goto out_close_fd; |
| 45 | } | 45 | } |
| 46 | 46 | ||
| 47 | if (evsel->counts->cpu[0].val != nr_openat_calls) { | 47 | if (perf_counts(evsel->counts, 0, 0)->val != nr_openat_calls) { |
| 48 | pr_debug("perf_evsel__read_on_cpu: expected to intercept %d calls, got %" PRIu64 "\n", | 48 | pr_debug("perf_evsel__read_on_cpu: expected to intercept %d calls, got %" PRIu64 "\n", |
| 49 | nr_openat_calls, evsel->counts->cpu[0].val); | 49 | nr_openat_calls, perf_counts(evsel->counts, 0, 0)->val); |
| 50 | goto out_close_fd; | 50 | goto out_close_fd; |
| 51 | } | 51 | } |
| 52 | 52 | ||
| @@ -56,6 +56,6 @@ out_close_fd: | |||
| 56 | out_evsel_delete: | 56 | out_evsel_delete: |
| 57 | perf_evsel__delete(evsel); | 57 | perf_evsel__delete(evsel); |
| 58 | out_thread_map_delete: | 58 | out_thread_map_delete: |
| 59 | thread_map__delete(threads); | 59 | thread_map__put(threads); |
| 60 | return err; | 60 | return err; |
| 61 | } | 61 | } |
diff --git a/tools/perf/tests/switch-tracking.c b/tools/perf/tests/switch-tracking.c index 0d31403ea593..e698742d4fec 100644 --- a/tools/perf/tests/switch-tracking.c +++ b/tools/perf/tests/switch-tracking.c | |||
| @@ -560,8 +560,8 @@ out: | |||
| 560 | perf_evlist__disable(evlist); | 560 | perf_evlist__disable(evlist); |
| 561 | perf_evlist__delete(evlist); | 561 | perf_evlist__delete(evlist); |
| 562 | } else { | 562 | } else { |
| 563 | cpu_map__delete(cpus); | 563 | cpu_map__put(cpus); |
| 564 | thread_map__delete(threads); | 564 | thread_map__put(threads); |
| 565 | } | 565 | } |
| 566 | 566 | ||
| 567 | return err; | 567 | return err; |
diff --git a/tools/perf/tests/tests.h b/tools/perf/tests/tests.h index 8e5038b48ba8..ebb47d96bc0b 100644 --- a/tools/perf/tests/tests.h +++ b/tools/perf/tests/tests.h | |||
| @@ -61,6 +61,7 @@ int test__switch_tracking(void); | |||
| 61 | int test__fdarray__filter(void); | 61 | int test__fdarray__filter(void); |
| 62 | int test__fdarray__add(void); | 62 | int test__fdarray__add(void); |
| 63 | int test__kmod_path__parse(void); | 63 | int test__kmod_path__parse(void); |
| 64 | int test__thread_map(void); | ||
| 64 | 65 | ||
| 65 | #if defined(__x86_64__) || defined(__i386__) || defined(__arm__) || defined(__aarch64__) | 66 | #if defined(__x86_64__) || defined(__i386__) || defined(__arm__) || defined(__aarch64__) |
| 66 | #ifdef HAVE_DWARF_UNWIND_SUPPORT | 67 | #ifdef HAVE_DWARF_UNWIND_SUPPORT |
diff --git a/tools/perf/tests/thread-map.c b/tools/perf/tests/thread-map.c new file mode 100644 index 000000000000..5acf000939ea --- /dev/null +++ b/tools/perf/tests/thread-map.c | |||
| @@ -0,0 +1,38 @@ | |||
| 1 | #include <sys/types.h> | ||
| 2 | #include <unistd.h> | ||
| 3 | #include "tests.h" | ||
| 4 | #include "thread_map.h" | ||
| 5 | #include "debug.h" | ||
| 6 | |||
| 7 | int test__thread_map(void) | ||
| 8 | { | ||
| 9 | struct thread_map *map; | ||
| 10 | |||
| 11 | /* test map on current pid */ | ||
| 12 | map = thread_map__new_by_pid(getpid()); | ||
| 13 | TEST_ASSERT_VAL("failed to alloc map", map); | ||
| 14 | |||
| 15 | thread_map__read_comms(map); | ||
| 16 | |||
| 17 | TEST_ASSERT_VAL("wrong nr", map->nr == 1); | ||
| 18 | TEST_ASSERT_VAL("wrong pid", | ||
| 19 | thread_map__pid(map, 0) == getpid()); | ||
| 20 | TEST_ASSERT_VAL("wrong comm", | ||
| 21 | thread_map__comm(map, 0) && | ||
| 22 | !strcmp(thread_map__comm(map, 0), "perf")); | ||
| 23 | thread_map__put(map); | ||
| 24 | |||
| 25 | /* test dummy pid */ | ||
| 26 | map = thread_map__new_dummy(); | ||
| 27 | TEST_ASSERT_VAL("failed to alloc map", map); | ||
| 28 | |||
| 29 | thread_map__read_comms(map); | ||
| 30 | |||
| 31 | TEST_ASSERT_VAL("wrong nr", map->nr == 1); | ||
| 32 | TEST_ASSERT_VAL("wrong pid", thread_map__pid(map, 0) == -1); | ||
| 33 | TEST_ASSERT_VAL("wrong comm", | ||
| 34 | thread_map__comm(map, 0) && | ||
| 35 | !strcmp(thread_map__comm(map, 0), "dummy")); | ||
| 36 | thread_map__put(map); | ||
| 37 | return 0; | ||
| 38 | } | ||
diff --git a/tools/perf/ui/browsers/hists.c b/tools/perf/ui/browsers/hists.c index c42adb600091..7629bef2fd79 100644 --- a/tools/perf/ui/browsers/hists.c +++ b/tools/perf/ui/browsers/hists.c | |||
| @@ -1902,8 +1902,23 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events, | |||
| 1902 | case CTRL('c'): | 1902 | case CTRL('c'): |
| 1903 | goto out_free_stack; | 1903 | goto out_free_stack; |
| 1904 | case 'f': | 1904 | case 'f': |
| 1905 | if (!is_report_browser(hbt)) | 1905 | if (!is_report_browser(hbt)) { |
| 1906 | goto out_free_stack; | 1906 | struct perf_top *top = hbt->arg; |
| 1907 | |||
| 1908 | perf_evlist__toggle_enable(top->evlist); | ||
| 1909 | /* | ||
| 1910 | * No need to refresh, resort/decay histogram | ||
| 1911 | * entries if we are not collecting samples: | ||
| 1912 | */ | ||
| 1913 | if (top->evlist->enabled) { | ||
| 1914 | helpline = "Press 'f' to disable the events or 'h' to see other hotkeys"; | ||
| 1915 | hbt->refresh = delay_secs; | ||
| 1916 | } else { | ||
| 1917 | helpline = "Press 'f' again to re-enable the events"; | ||
| 1918 | hbt->refresh = 0; | ||
| 1919 | } | ||
| 1920 | continue; | ||
| 1921 | } | ||
| 1907 | /* Fall thru */ | 1922 | /* Fall thru */ |
| 1908 | default: | 1923 | default: |
| 1909 | helpline = "Press '?' for help on key bindings"; | 1924 | helpline = "Press '?' for help on key bindings"; |
diff --git a/tools/perf/util/auxtrace.c b/tools/perf/util/auxtrace.c index df66966cfde7..7e7405c9b936 100644 --- a/tools/perf/util/auxtrace.c +++ b/tools/perf/util/auxtrace.c | |||
| @@ -119,12 +119,12 @@ void auxtrace_mmap_params__set_idx(struct auxtrace_mmap_params *mp, | |||
| 119 | if (per_cpu) { | 119 | if (per_cpu) { |
| 120 | mp->cpu = evlist->cpus->map[idx]; | 120 | mp->cpu = evlist->cpus->map[idx]; |
| 121 | if (evlist->threads) | 121 | if (evlist->threads) |
| 122 | mp->tid = evlist->threads->map[0]; | 122 | mp->tid = thread_map__pid(evlist->threads, 0); |
| 123 | else | 123 | else |
| 124 | mp->tid = -1; | 124 | mp->tid = -1; |
| 125 | } else { | 125 | } else { |
| 126 | mp->cpu = -1; | 126 | mp->cpu = -1; |
| 127 | mp->tid = evlist->threads->map[idx]; | 127 | mp->tid = thread_map__pid(evlist->threads, idx); |
| 128 | } | 128 | } |
| 129 | } | 129 | } |
| 130 | 130 | ||
| @@ -1182,6 +1182,13 @@ static int __auxtrace_mmap__read(struct auxtrace_mmap *mm, | |||
| 1182 | data2 = NULL; | 1182 | data2 = NULL; |
| 1183 | } | 1183 | } |
| 1184 | 1184 | ||
| 1185 | if (itr->alignment) { | ||
| 1186 | unsigned int unwanted = len1 % itr->alignment; | ||
| 1187 | |||
| 1188 | len1 -= unwanted; | ||
| 1189 | size -= unwanted; | ||
| 1190 | } | ||
| 1191 | |||
| 1185 | /* padding must be written by fn() e.g. record__process_auxtrace() */ | 1192 | /* padding must be written by fn() e.g. record__process_auxtrace() */ |
| 1186 | padding = size & 7; | 1193 | padding = size & 7; |
| 1187 | if (padding) | 1194 | if (padding) |
diff --git a/tools/perf/util/auxtrace.h b/tools/perf/util/auxtrace.h index a171abbe7301..471aecbc4d68 100644 --- a/tools/perf/util/auxtrace.h +++ b/tools/perf/util/auxtrace.h | |||
| @@ -303,6 +303,7 @@ struct auxtrace_record { | |||
| 303 | const char *str); | 303 | const char *str); |
| 304 | u64 (*reference)(struct auxtrace_record *itr); | 304 | u64 (*reference)(struct auxtrace_record *itr); |
| 305 | int (*read_finish)(struct auxtrace_record *itr, int idx); | 305 | int (*read_finish)(struct auxtrace_record *itr, int idx); |
| 306 | unsigned int alignment; | ||
| 306 | }; | 307 | }; |
| 307 | 308 | ||
| 308 | #ifdef HAVE_AUXTRACE_SUPPORT | 309 | #ifdef HAVE_AUXTRACE_SUPPORT |
diff --git a/tools/perf/util/cloexec.c b/tools/perf/util/cloexec.c index 85b523885f9d..2babddaa2481 100644 --- a/tools/perf/util/cloexec.c +++ b/tools/perf/util/cloexec.c | |||
| @@ -7,11 +7,15 @@ | |||
| 7 | 7 | ||
| 8 | static unsigned long flag = PERF_FLAG_FD_CLOEXEC; | 8 | static unsigned long flag = PERF_FLAG_FD_CLOEXEC; |
| 9 | 9 | ||
| 10 | #ifdef __GLIBC_PREREQ | ||
| 11 | #if !__GLIBC_PREREQ(2, 6) | ||
| 10 | int __weak sched_getcpu(void) | 12 | int __weak sched_getcpu(void) |
| 11 | { | 13 | { |
| 12 | errno = ENOSYS; | 14 | errno = ENOSYS; |
| 13 | return -1; | 15 | return -1; |
| 14 | } | 16 | } |
| 17 | #endif | ||
| 18 | #endif | ||
| 15 | 19 | ||
| 16 | static int perf_flag_probe(void) | 20 | static int perf_flag_probe(void) |
| 17 | { | 21 | { |
diff --git a/tools/perf/util/cpumap.c b/tools/perf/util/cpumap.c index c4e55b71010c..3667e2123e5b 100644 --- a/tools/perf/util/cpumap.c +++ b/tools/perf/util/cpumap.c | |||
| @@ -5,6 +5,7 @@ | |||
| 5 | #include <assert.h> | 5 | #include <assert.h> |
| 6 | #include <stdio.h> | 6 | #include <stdio.h> |
| 7 | #include <stdlib.h> | 7 | #include <stdlib.h> |
| 8 | #include "asm/bug.h" | ||
| 8 | 9 | ||
| 9 | static struct cpu_map *cpu_map__default_new(void) | 10 | static struct cpu_map *cpu_map__default_new(void) |
| 10 | { | 11 | { |
| @@ -22,6 +23,7 @@ static struct cpu_map *cpu_map__default_new(void) | |||
| 22 | cpus->map[i] = i; | 23 | cpus->map[i] = i; |
| 23 | 24 | ||
| 24 | cpus->nr = nr_cpus; | 25 | cpus->nr = nr_cpus; |
| 26 | atomic_set(&cpus->refcnt, 1); | ||
| 25 | } | 27 | } |
| 26 | 28 | ||
| 27 | return cpus; | 29 | return cpus; |
| @@ -35,6 +37,7 @@ static struct cpu_map *cpu_map__trim_new(int nr_cpus, int *tmp_cpus) | |||
| 35 | if (cpus != NULL) { | 37 | if (cpus != NULL) { |
| 36 | cpus->nr = nr_cpus; | 38 | cpus->nr = nr_cpus; |
| 37 | memcpy(cpus->map, tmp_cpus, payload_size); | 39 | memcpy(cpus->map, tmp_cpus, payload_size); |
| 40 | atomic_set(&cpus->refcnt, 1); | ||
| 38 | } | 41 | } |
| 39 | 42 | ||
| 40 | return cpus; | 43 | return cpus; |
| @@ -194,14 +197,32 @@ struct cpu_map *cpu_map__dummy_new(void) | |||
| 194 | if (cpus != NULL) { | 197 | if (cpus != NULL) { |
| 195 | cpus->nr = 1; | 198 | cpus->nr = 1; |
| 196 | cpus->map[0] = -1; | 199 | cpus->map[0] = -1; |
| 200 | atomic_set(&cpus->refcnt, 1); | ||
| 197 | } | 201 | } |
| 198 | 202 | ||
| 199 | return cpus; | 203 | return cpus; |
| 200 | } | 204 | } |
| 201 | 205 | ||
| 202 | void cpu_map__delete(struct cpu_map *map) | 206 | static void cpu_map__delete(struct cpu_map *map) |
| 203 | { | 207 | { |
| 204 | free(map); | 208 | if (map) { |
| 209 | WARN_ONCE(atomic_read(&map->refcnt) != 0, | ||
| 210 | "cpu_map refcnt unbalanced\n"); | ||
| 211 | free(map); | ||
| 212 | } | ||
| 213 | } | ||
| 214 | |||
| 215 | struct cpu_map *cpu_map__get(struct cpu_map *map) | ||
| 216 | { | ||
| 217 | if (map) | ||
| 218 | atomic_inc(&map->refcnt); | ||
| 219 | return map; | ||
| 220 | } | ||
| 221 | |||
| 222 | void cpu_map__put(struct cpu_map *map) | ||
| 223 | { | ||
| 224 | if (map && atomic_dec_and_test(&map->refcnt)) | ||
| 225 | cpu_map__delete(map); | ||
| 205 | } | 226 | } |
| 206 | 227 | ||
| 207 | int cpu_map__get_socket(struct cpu_map *map, int idx) | 228 | int cpu_map__get_socket(struct cpu_map *map, int idx) |
| @@ -263,6 +284,7 @@ static int cpu_map__build_map(struct cpu_map *cpus, struct cpu_map **res, | |||
| 263 | /* ensure we process id in increasing order */ | 284 | /* ensure we process id in increasing order */ |
| 264 | qsort(c->map, c->nr, sizeof(int), cmp_ids); | 285 | qsort(c->map, c->nr, sizeof(int), cmp_ids); |
| 265 | 286 | ||
| 287 | atomic_set(&cpus->refcnt, 1); | ||
| 266 | *res = c; | 288 | *res = c; |
| 267 | return 0; | 289 | return 0; |
| 268 | } | 290 | } |
diff --git a/tools/perf/util/cpumap.h b/tools/perf/util/cpumap.h index 61a654849002..0af9cecb4c51 100644 --- a/tools/perf/util/cpumap.h +++ b/tools/perf/util/cpumap.h | |||
| @@ -3,18 +3,19 @@ | |||
| 3 | 3 | ||
| 4 | #include <stdio.h> | 4 | #include <stdio.h> |
| 5 | #include <stdbool.h> | 5 | #include <stdbool.h> |
| 6 | #include <linux/atomic.h> | ||
| 6 | 7 | ||
| 7 | #include "perf.h" | 8 | #include "perf.h" |
| 8 | #include "util/debug.h" | 9 | #include "util/debug.h" |
| 9 | 10 | ||
| 10 | struct cpu_map { | 11 | struct cpu_map { |
| 12 | atomic_t refcnt; | ||
| 11 | int nr; | 13 | int nr; |
| 12 | int map[]; | 14 | int map[]; |
| 13 | }; | 15 | }; |
| 14 | 16 | ||
| 15 | struct cpu_map *cpu_map__new(const char *cpu_list); | 17 | struct cpu_map *cpu_map__new(const char *cpu_list); |
| 16 | struct cpu_map *cpu_map__dummy_new(void); | 18 | struct cpu_map *cpu_map__dummy_new(void); |
| 17 | void cpu_map__delete(struct cpu_map *map); | ||
| 18 | struct cpu_map *cpu_map__read(FILE *file); | 19 | struct cpu_map *cpu_map__read(FILE *file); |
| 19 | size_t cpu_map__fprintf(struct cpu_map *map, FILE *fp); | 20 | size_t cpu_map__fprintf(struct cpu_map *map, FILE *fp); |
| 20 | int cpu_map__get_socket(struct cpu_map *map, int idx); | 21 | int cpu_map__get_socket(struct cpu_map *map, int idx); |
| @@ -22,6 +23,9 @@ int cpu_map__get_core(struct cpu_map *map, int idx); | |||
| 22 | int cpu_map__build_socket_map(struct cpu_map *cpus, struct cpu_map **sockp); | 23 | int cpu_map__build_socket_map(struct cpu_map *cpus, struct cpu_map **sockp); |
| 23 | int cpu_map__build_core_map(struct cpu_map *cpus, struct cpu_map **corep); | 24 | int cpu_map__build_core_map(struct cpu_map *cpus, struct cpu_map **corep); |
| 24 | 25 | ||
| 26 | struct cpu_map *cpu_map__get(struct cpu_map *map); | ||
| 27 | void cpu_map__put(struct cpu_map *map); | ||
| 28 | |||
| 25 | static inline int cpu_map__socket(struct cpu_map *sock, int s) | 29 | static inline int cpu_map__socket(struct cpu_map *sock, int s) |
| 26 | { | 30 | { |
| 27 | if (!sock || s > sock->nr || s < 0) | 31 | if (!sock || s > sock->nr || s < 0) |
diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c index d7d986d8f23e..67a977e5d0ab 100644 --- a/tools/perf/util/event.c +++ b/tools/perf/util/event.c | |||
| @@ -504,7 +504,7 @@ int perf_event__synthesize_thread_map(struct perf_tool *tool, | |||
| 504 | for (thread = 0; thread < threads->nr; ++thread) { | 504 | for (thread = 0; thread < threads->nr; ++thread) { |
| 505 | if (__event__synthesize_thread(comm_event, mmap_event, | 505 | if (__event__synthesize_thread(comm_event, mmap_event, |
| 506 | fork_event, | 506 | fork_event, |
| 507 | threads->map[thread], 0, | 507 | thread_map__pid(threads, thread), 0, |
| 508 | process, tool, machine, | 508 | process, tool, machine, |
| 509 | mmap_data, proc_map_timeout)) { | 509 | mmap_data, proc_map_timeout)) { |
| 510 | err = -1; | 510 | err = -1; |
| @@ -515,12 +515,12 @@ int perf_event__synthesize_thread_map(struct perf_tool *tool, | |||
| 515 | * comm.pid is set to thread group id by | 515 | * comm.pid is set to thread group id by |
| 516 | * perf_event__synthesize_comm | 516 | * perf_event__synthesize_comm |
| 517 | */ | 517 | */ |
| 518 | if ((int) comm_event->comm.pid != threads->map[thread]) { | 518 | if ((int) comm_event->comm.pid != thread_map__pid(threads, thread)) { |
| 519 | bool need_leader = true; | 519 | bool need_leader = true; |
| 520 | 520 | ||
| 521 | /* is thread group leader in thread_map? */ | 521 | /* is thread group leader in thread_map? */ |
| 522 | for (j = 0; j < threads->nr; ++j) { | 522 | for (j = 0; j < threads->nr; ++j) { |
| 523 | if ((int) comm_event->comm.pid == threads->map[j]) { | 523 | if ((int) comm_event->comm.pid == thread_map__pid(threads, j)) { |
| 524 | need_leader = false; | 524 | need_leader = false; |
| 525 | break; | 525 | break; |
| 526 | } | 526 | } |
diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c index 8366511b45f8..6cfdee68e763 100644 --- a/tools/perf/util/evlist.c +++ b/tools/perf/util/evlist.c | |||
| @@ -114,8 +114,8 @@ void perf_evlist__delete(struct perf_evlist *evlist) | |||
| 114 | { | 114 | { |
| 115 | perf_evlist__munmap(evlist); | 115 | perf_evlist__munmap(evlist); |
| 116 | perf_evlist__close(evlist); | 116 | perf_evlist__close(evlist); |
| 117 | cpu_map__delete(evlist->cpus); | 117 | cpu_map__put(evlist->cpus); |
| 118 | thread_map__delete(evlist->threads); | 118 | thread_map__put(evlist->threads); |
| 119 | evlist->cpus = NULL; | 119 | evlist->cpus = NULL; |
| 120 | evlist->threads = NULL; | 120 | evlist->threads = NULL; |
| 121 | perf_evlist__purge(evlist); | 121 | perf_evlist__purge(evlist); |
| @@ -548,7 +548,7 @@ static void perf_evlist__set_sid_idx(struct perf_evlist *evlist, | |||
| 548 | else | 548 | else |
| 549 | sid->cpu = -1; | 549 | sid->cpu = -1; |
| 550 | if (!evsel->system_wide && evlist->threads && thread >= 0) | 550 | if (!evsel->system_wide && evlist->threads && thread >= 0) |
| 551 | sid->tid = evlist->threads->map[thread]; | 551 | sid->tid = thread_map__pid(evlist->threads, thread); |
| 552 | else | 552 | else |
| 553 | sid->tid = -1; | 553 | sid->tid = -1; |
| 554 | } | 554 | } |
| @@ -1101,6 +1101,31 @@ int perf_evlist__mmap(struct perf_evlist *evlist, unsigned int pages, | |||
| 1101 | return perf_evlist__mmap_ex(evlist, pages, overwrite, 0, false); | 1101 | return perf_evlist__mmap_ex(evlist, pages, overwrite, 0, false); |
| 1102 | } | 1102 | } |
| 1103 | 1103 | ||
| 1104 | static int perf_evlist__propagate_maps(struct perf_evlist *evlist, | ||
| 1105 | struct target *target) | ||
| 1106 | { | ||
| 1107 | struct perf_evsel *evsel; | ||
| 1108 | |||
| 1109 | evlist__for_each(evlist, evsel) { | ||
| 1110 | /* | ||
| 1111 | * We already have cpus for evsel (via PMU sysfs) so | ||
| 1112 | * keep it, if there's no target cpu list defined. | ||
| 1113 | */ | ||
| 1114 | if (evsel->cpus && target->cpu_list) | ||
| 1115 | cpu_map__put(evsel->cpus); | ||
| 1116 | |||
| 1117 | if (!evsel->cpus || target->cpu_list) | ||
| 1118 | evsel->cpus = cpu_map__get(evlist->cpus); | ||
| 1119 | |||
| 1120 | evsel->threads = thread_map__get(evlist->threads); | ||
| 1121 | |||
| 1122 | if (!evsel->cpus || !evsel->threads) | ||
| 1123 | return -ENOMEM; | ||
| 1124 | } | ||
| 1125 | |||
| 1126 | return 0; | ||
| 1127 | } | ||
| 1128 | |||
| 1104 | int perf_evlist__create_maps(struct perf_evlist *evlist, struct target *target) | 1129 | int perf_evlist__create_maps(struct perf_evlist *evlist, struct target *target) |
| 1105 | { | 1130 | { |
| 1106 | evlist->threads = thread_map__new_str(target->pid, target->tid, | 1131 | evlist->threads = thread_map__new_str(target->pid, target->tid, |
| @@ -1117,10 +1142,10 @@ int perf_evlist__create_maps(struct perf_evlist *evlist, struct target *target) | |||
| 1117 | if (evlist->cpus == NULL) | 1142 | if (evlist->cpus == NULL) |
| 1118 | goto out_delete_threads; | 1143 | goto out_delete_threads; |
| 1119 | 1144 | ||
| 1120 | return 0; | 1145 | return perf_evlist__propagate_maps(evlist, target); |
| 1121 | 1146 | ||
| 1122 | out_delete_threads: | 1147 | out_delete_threads: |
| 1123 | thread_map__delete(evlist->threads); | 1148 | thread_map__put(evlist->threads); |
| 1124 | evlist->threads = NULL; | 1149 | evlist->threads = NULL; |
| 1125 | return -1; | 1150 | return -1; |
| 1126 | } | 1151 | } |
| @@ -1353,7 +1378,7 @@ static int perf_evlist__create_syswide_maps(struct perf_evlist *evlist) | |||
| 1353 | out: | 1378 | out: |
| 1354 | return err; | 1379 | return err; |
| 1355 | out_free_cpus: | 1380 | out_free_cpus: |
| 1356 | cpu_map__delete(evlist->cpus); | 1381 | cpu_map__put(evlist->cpus); |
| 1357 | evlist->cpus = NULL; | 1382 | evlist->cpus = NULL; |
| 1358 | goto out; | 1383 | goto out; |
| 1359 | } | 1384 | } |
| @@ -1475,7 +1500,7 @@ int perf_evlist__prepare_workload(struct perf_evlist *evlist, struct target *tar | |||
| 1475 | __func__, __LINE__); | 1500 | __func__, __LINE__); |
| 1476 | goto out_close_pipes; | 1501 | goto out_close_pipes; |
| 1477 | } | 1502 | } |
| 1478 | evlist->threads->map[0] = evlist->workload.pid; | 1503 | thread_map__set_pid(evlist->threads, 0, evlist->workload.pid); |
| 1479 | } | 1504 | } |
| 1480 | 1505 | ||
| 1481 | close(child_ready_pipe[1]); | 1506 | close(child_ready_pipe[1]); |
diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h index a8489b9d2812..037633c1da9d 100644 --- a/tools/perf/util/evlist.h +++ b/tools/perf/util/evlist.h | |||
| @@ -289,5 +289,4 @@ void perf_evlist__to_front(struct perf_evlist *evlist, | |||
| 289 | 289 | ||
| 290 | void perf_evlist__set_tracking_event(struct perf_evlist *evlist, | 290 | void perf_evlist__set_tracking_event(struct perf_evlist *evlist, |
| 291 | struct perf_evsel *tracking_evsel); | 291 | struct perf_evsel *tracking_evsel); |
| 292 | |||
| 293 | #endif /* __PERF_EVLIST_H */ | 292 | #endif /* __PERF_EVLIST_H */ |
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index 33449decf7bd..2936b3080722 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c | |||
| @@ -885,6 +885,8 @@ void perf_evsel__exit(struct perf_evsel *evsel) | |||
| 885 | perf_evsel__free_fd(evsel); | 885 | perf_evsel__free_fd(evsel); |
| 886 | perf_evsel__free_id(evsel); | 886 | perf_evsel__free_id(evsel); |
| 887 | close_cgroup(evsel->cgrp); | 887 | close_cgroup(evsel->cgrp); |
| 888 | cpu_map__put(evsel->cpus); | ||
| 889 | thread_map__put(evsel->threads); | ||
| 888 | zfree(&evsel->group_name); | 890 | zfree(&evsel->group_name); |
| 889 | zfree(&evsel->name); | 891 | zfree(&evsel->name); |
| 890 | perf_evsel__object.fini(evsel); | 892 | perf_evsel__object.fini(evsel); |
| @@ -896,7 +898,7 @@ void perf_evsel__delete(struct perf_evsel *evsel) | |||
| 896 | free(evsel); | 898 | free(evsel); |
| 897 | } | 899 | } |
| 898 | 900 | ||
| 899 | void perf_evsel__compute_deltas(struct perf_evsel *evsel, int cpu, | 901 | void perf_evsel__compute_deltas(struct perf_evsel *evsel, int cpu, int thread, |
| 900 | struct perf_counts_values *count) | 902 | struct perf_counts_values *count) |
| 901 | { | 903 | { |
| 902 | struct perf_counts_values tmp; | 904 | struct perf_counts_values tmp; |
| @@ -908,8 +910,8 @@ void perf_evsel__compute_deltas(struct perf_evsel *evsel, int cpu, | |||
| 908 | tmp = evsel->prev_raw_counts->aggr; | 910 | tmp = evsel->prev_raw_counts->aggr; |
| 909 | evsel->prev_raw_counts->aggr = *count; | 911 | evsel->prev_raw_counts->aggr = *count; |
| 910 | } else { | 912 | } else { |
| 911 | tmp = evsel->prev_raw_counts->cpu[cpu]; | 913 | tmp = *perf_counts(evsel->prev_raw_counts, cpu, thread); |
| 912 | evsel->prev_raw_counts->cpu[cpu] = *count; | 914 | *perf_counts(evsel->prev_raw_counts, cpu, thread) = *count; |
| 913 | } | 915 | } |
| 914 | 916 | ||
| 915 | count->val = count->val - tmp.val; | 917 | count->val = count->val - tmp.val; |
| @@ -937,20 +939,18 @@ void perf_counts_values__scale(struct perf_counts_values *count, | |||
| 937 | *pscaled = scaled; | 939 | *pscaled = scaled; |
| 938 | } | 940 | } |
| 939 | 941 | ||
| 940 | int perf_evsel__read_cb(struct perf_evsel *evsel, int cpu, int thread, | 942 | int perf_evsel__read(struct perf_evsel *evsel, int cpu, int thread, |
| 941 | perf_evsel__read_cb_t cb) | 943 | struct perf_counts_values *count) |
| 942 | { | 944 | { |
| 943 | struct perf_counts_values count; | 945 | memset(count, 0, sizeof(*count)); |
| 944 | |||
| 945 | memset(&count, 0, sizeof(count)); | ||
| 946 | 946 | ||
| 947 | if (FD(evsel, cpu, thread) < 0) | 947 | if (FD(evsel, cpu, thread) < 0) |
| 948 | return -EINVAL; | 948 | return -EINVAL; |
| 949 | 949 | ||
| 950 | if (readn(FD(evsel, cpu, thread), &count, sizeof(count)) < 0) | 950 | if (readn(FD(evsel, cpu, thread), count, sizeof(*count)) < 0) |
| 951 | return -errno; | 951 | return -errno; |
| 952 | 952 | ||
| 953 | return cb(evsel, cpu, thread, &count); | 953 | return 0; |
| 954 | } | 954 | } |
| 955 | 955 | ||
| 956 | int __perf_evsel__read_on_cpu(struct perf_evsel *evsel, | 956 | int __perf_evsel__read_on_cpu(struct perf_evsel *evsel, |
| @@ -962,15 +962,15 @@ int __perf_evsel__read_on_cpu(struct perf_evsel *evsel, | |||
| 962 | if (FD(evsel, cpu, thread) < 0) | 962 | if (FD(evsel, cpu, thread) < 0) |
| 963 | return -EINVAL; | 963 | return -EINVAL; |
| 964 | 964 | ||
| 965 | if (evsel->counts == NULL && perf_evsel__alloc_counts(evsel, cpu + 1) < 0) | 965 | if (evsel->counts == NULL && perf_evsel__alloc_counts(evsel, cpu + 1, thread + 1) < 0) |
| 966 | return -ENOMEM; | 966 | return -ENOMEM; |
| 967 | 967 | ||
| 968 | if (readn(FD(evsel, cpu, thread), &count, nv * sizeof(u64)) < 0) | 968 | if (readn(FD(evsel, cpu, thread), &count, nv * sizeof(u64)) < 0) |
| 969 | return -errno; | 969 | return -errno; |
| 970 | 970 | ||
| 971 | perf_evsel__compute_deltas(evsel, cpu, &count); | 971 | perf_evsel__compute_deltas(evsel, cpu, thread, &count); |
| 972 | perf_counts_values__scale(&count, scale, NULL); | 972 | perf_counts_values__scale(&count, scale, NULL); |
| 973 | evsel->counts->cpu[cpu] = count; | 973 | *perf_counts(evsel->counts, cpu, thread) = count; |
| 974 | return 0; | 974 | return 0; |
| 975 | } | 975 | } |
| 976 | 976 | ||
| @@ -1167,7 +1167,7 @@ retry_sample_id: | |||
| 1167 | int group_fd; | 1167 | int group_fd; |
| 1168 | 1168 | ||
| 1169 | if (!evsel->cgrp && !evsel->system_wide) | 1169 | if (!evsel->cgrp && !evsel->system_wide) |
| 1170 | pid = threads->map[thread]; | 1170 | pid = thread_map__pid(threads, thread); |
| 1171 | 1171 | ||
| 1172 | group_fd = get_group_fd(evsel, cpu, thread); | 1172 | group_fd = get_group_fd(evsel, cpu, thread); |
| 1173 | retry_open: | 1173 | retry_open: |
diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h index bb0579e8a10a..4a7ed5656cf0 100644 --- a/tools/perf/util/evsel.h +++ b/tools/perf/util/evsel.h | |||
| @@ -8,23 +8,8 @@ | |||
| 8 | #include <linux/types.h> | 8 | #include <linux/types.h> |
| 9 | #include "xyarray.h" | 9 | #include "xyarray.h" |
| 10 | #include "symbol.h" | 10 | #include "symbol.h" |
| 11 | 11 | #include "cpumap.h" | |
| 12 | struct perf_counts_values { | 12 | #include "stat.h" |
| 13 | union { | ||
| 14 | struct { | ||
| 15 | u64 val; | ||
| 16 | u64 ena; | ||
| 17 | u64 run; | ||
| 18 | }; | ||
| 19 | u64 values[3]; | ||
| 20 | }; | ||
| 21 | }; | ||
| 22 | |||
| 23 | struct perf_counts { | ||
| 24 | s8 scaled; | ||
| 25 | struct perf_counts_values aggr; | ||
| 26 | struct perf_counts_values cpu[]; | ||
| 27 | }; | ||
| 28 | 13 | ||
| 29 | struct perf_evsel; | 14 | struct perf_evsel; |
| 30 | 15 | ||
| @@ -82,6 +67,7 @@ struct perf_evsel { | |||
| 82 | struct cgroup_sel *cgrp; | 67 | struct cgroup_sel *cgrp; |
| 83 | void *handler; | 68 | void *handler; |
| 84 | struct cpu_map *cpus; | 69 | struct cpu_map *cpus; |
| 70 | struct thread_map *threads; | ||
| 85 | unsigned int sample_size; | 71 | unsigned int sample_size; |
| 86 | int id_pos; | 72 | int id_pos; |
| 87 | int is_pos; | 73 | int is_pos; |
| @@ -113,10 +99,20 @@ struct thread_map; | |||
| 113 | struct perf_evlist; | 99 | struct perf_evlist; |
| 114 | struct record_opts; | 100 | struct record_opts; |
| 115 | 101 | ||
| 102 | static inline struct cpu_map *perf_evsel__cpus(struct perf_evsel *evsel) | ||
| 103 | { | ||
| 104 | return evsel->cpus; | ||
| 105 | } | ||
| 106 | |||
| 107 | static inline int perf_evsel__nr_cpus(struct perf_evsel *evsel) | ||
| 108 | { | ||
| 109 | return perf_evsel__cpus(evsel)->nr; | ||
| 110 | } | ||
| 111 | |||
| 116 | void perf_counts_values__scale(struct perf_counts_values *count, | 112 | void perf_counts_values__scale(struct perf_counts_values *count, |
| 117 | bool scale, s8 *pscaled); | 113 | bool scale, s8 *pscaled); |
| 118 | 114 | ||
| 119 | void perf_evsel__compute_deltas(struct perf_evsel *evsel, int cpu, | 115 | void perf_evsel__compute_deltas(struct perf_evsel *evsel, int cpu, int thread, |
| 120 | struct perf_counts_values *count); | 116 | struct perf_counts_values *count); |
| 121 | 117 | ||
| 122 | int perf_evsel__object_config(size_t object_size, | 118 | int perf_evsel__object_config(size_t object_size, |
| @@ -233,12 +229,8 @@ static inline bool perf_evsel__match2(struct perf_evsel *e1, | |||
| 233 | (a)->attr.type == (b)->attr.type && \ | 229 | (a)->attr.type == (b)->attr.type && \ |
| 234 | (a)->attr.config == (b)->attr.config) | 230 | (a)->attr.config == (b)->attr.config) |
| 235 | 231 | ||
| 236 | typedef int (perf_evsel__read_cb_t)(struct perf_evsel *evsel, | 232 | int perf_evsel__read(struct perf_evsel *evsel, int cpu, int thread, |
| 237 | int cpu, int thread, | 233 | struct perf_counts_values *count); |
| 238 | struct perf_counts_values *count); | ||
| 239 | |||
| 240 | int perf_evsel__read_cb(struct perf_evsel *evsel, int cpu, int thread, | ||
| 241 | perf_evsel__read_cb_t cb); | ||
| 242 | 234 | ||
| 243 | int __perf_evsel__read_on_cpu(struct perf_evsel *evsel, | 235 | int __perf_evsel__read_on_cpu(struct perf_evsel *evsel, |
| 244 | int cpu, int thread, bool scale); | 236 | int cpu, int thread, bool scale); |
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index 21a77e7a171e..03ace57a800c 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c | |||
| @@ -1063,8 +1063,7 @@ out: | |||
| 1063 | free(buf); | 1063 | free(buf); |
| 1064 | return events; | 1064 | return events; |
| 1065 | error: | 1065 | error: |
| 1066 | if (events) | 1066 | free_event_desc(events); |
| 1067 | free_event_desc(events); | ||
| 1068 | events = NULL; | 1067 | events = NULL; |
| 1069 | goto out; | 1068 | goto out; |
| 1070 | } | 1069 | } |
diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c index 4744673aff1b..7ff682770fdb 100644 --- a/tools/perf/util/machine.c +++ b/tools/perf/util/machine.c | |||
| @@ -1448,10 +1448,9 @@ int machine__process_event(struct machine *machine, union perf_event *event, | |||
| 1448 | case PERF_RECORD_AUX: | 1448 | case PERF_RECORD_AUX: |
| 1449 | ret = machine__process_aux_event(machine, event); break; | 1449 | ret = machine__process_aux_event(machine, event); break; |
| 1450 | case PERF_RECORD_ITRACE_START: | 1450 | case PERF_RECORD_ITRACE_START: |
| 1451 | ret = machine__process_itrace_start_event(machine, event); | 1451 | ret = machine__process_itrace_start_event(machine, event); break; |
| 1452 | case PERF_RECORD_LOST_SAMPLES: | 1452 | case PERF_RECORD_LOST_SAMPLES: |
| 1453 | ret = machine__process_lost_samples_event(machine, event, sample); break; | 1453 | ret = machine__process_lost_samples_event(machine, event, sample); break; |
| 1454 | break; | ||
| 1455 | default: | 1454 | default: |
| 1456 | ret = -1; | 1455 | ret = -1; |
| 1457 | break; | 1456 | break; |
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index 2a4d1ec02846..09f8d2357108 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c | |||
| @@ -17,6 +17,7 @@ | |||
| 17 | #include "parse-events-flex.h" | 17 | #include "parse-events-flex.h" |
| 18 | #include "pmu.h" | 18 | #include "pmu.h" |
| 19 | #include "thread_map.h" | 19 | #include "thread_map.h" |
| 20 | #include "cpumap.h" | ||
| 20 | #include "asm/bug.h" | 21 | #include "asm/bug.h" |
| 21 | 22 | ||
| 22 | #define MAX_NAME_LEN 100 | 23 | #define MAX_NAME_LEN 100 |
| @@ -285,7 +286,9 @@ __add_event(struct list_head *list, int *idx, | |||
| 285 | if (!evsel) | 286 | if (!evsel) |
| 286 | return NULL; | 287 | return NULL; |
| 287 | 288 | ||
| 288 | evsel->cpus = cpus; | 289 | if (cpus) |
| 290 | evsel->cpus = cpu_map__get(cpus); | ||
| 291 | |||
| 289 | if (name) | 292 | if (name) |
| 290 | evsel->name = strdup(name); | 293 | evsel->name = strdup(name); |
| 291 | list_add_tail(&evsel->node, list); | 294 | list_add_tail(&evsel->node, list); |
diff --git a/tools/perf/util/parse-events.l b/tools/perf/util/parse-events.l index 09e738fe9ea2..13cef3c65565 100644 --- a/tools/perf/util/parse-events.l +++ b/tools/perf/util/parse-events.l | |||
| @@ -119,8 +119,8 @@ event [^,{}/]+ | |||
| 119 | num_dec [0-9]+ | 119 | num_dec [0-9]+ |
| 120 | num_hex 0x[a-fA-F0-9]+ | 120 | num_hex 0x[a-fA-F0-9]+ |
| 121 | num_raw_hex [a-fA-F0-9]+ | 121 | num_raw_hex [a-fA-F0-9]+ |
| 122 | name [a-zA-Z_*?][a-zA-Z0-9_*?]* | 122 | name [a-zA-Z_*?][a-zA-Z0-9_*?.]* |
| 123 | name_minus [a-zA-Z_*?][a-zA-Z0-9\-_*?]* | 123 | name_minus [a-zA-Z_*?][a-zA-Z0-9\-_*?.]* |
| 124 | /* If you add a modifier you need to update check_modifier() */ | 124 | /* If you add a modifier you need to update check_modifier() */ |
| 125 | modifier_event [ukhpGHSDI]+ | 125 | modifier_event [ukhpGHSDI]+ |
| 126 | modifier_bp [rwx]{1,3} | 126 | modifier_bp [rwx]{1,3} |
| @@ -165,7 +165,6 @@ modifier_bp [rwx]{1,3} | |||
| 165 | return PE_EVENT_NAME; | 165 | return PE_EVENT_NAME; |
| 166 | } | 166 | } |
| 167 | 167 | ||
| 168 | . | | ||
| 169 | <<EOF>> { | 168 | <<EOF>> { |
| 170 | BEGIN(INITIAL); | 169 | BEGIN(INITIAL); |
| 171 | REWIND(0); | 170 | REWIND(0); |
diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c index 0fcc624eb767..7bcb8c315615 100644 --- a/tools/perf/util/pmu.c +++ b/tools/perf/util/pmu.c | |||
| @@ -1,4 +1,5 @@ | |||
| 1 | #include <linux/list.h> | 1 | #include <linux/list.h> |
| 2 | #include <linux/compiler.h> | ||
| 2 | #include <sys/types.h> | 3 | #include <sys/types.h> |
| 3 | #include <unistd.h> | 4 | #include <unistd.h> |
| 4 | #include <stdio.h> | 5 | #include <stdio.h> |
| @@ -205,17 +206,12 @@ static int perf_pmu__parse_snapshot(struct perf_pmu_alias *alias, | |||
| 205 | return 0; | 206 | return 0; |
| 206 | } | 207 | } |
| 207 | 208 | ||
| 208 | static int perf_pmu__new_alias(struct list_head *list, char *dir, char *name, FILE *file) | 209 | static int __perf_pmu__new_alias(struct list_head *list, char *dir, char *name, |
| 210 | char *desc __maybe_unused, char *val) | ||
| 209 | { | 211 | { |
| 210 | struct perf_pmu_alias *alias; | 212 | struct perf_pmu_alias *alias; |
| 211 | char buf[256]; | ||
| 212 | int ret; | 213 | int ret; |
| 213 | 214 | ||
| 214 | ret = fread(buf, 1, sizeof(buf), file); | ||
| 215 | if (ret == 0) | ||
| 216 | return -EINVAL; | ||
| 217 | buf[ret] = 0; | ||
| 218 | |||
| 219 | alias = malloc(sizeof(*alias)); | 215 | alias = malloc(sizeof(*alias)); |
| 220 | if (!alias) | 216 | if (!alias) |
| 221 | return -ENOMEM; | 217 | return -ENOMEM; |
| @@ -225,26 +221,43 @@ static int perf_pmu__new_alias(struct list_head *list, char *dir, char *name, FI | |||
| 225 | alias->unit[0] = '\0'; | 221 | alias->unit[0] = '\0'; |
| 226 | alias->per_pkg = false; | 222 | alias->per_pkg = false; |
| 227 | 223 | ||
| 228 | ret = parse_events_terms(&alias->terms, buf); | 224 | ret = parse_events_terms(&alias->terms, val); |
| 229 | if (ret) { | 225 | if (ret) { |
| 226 | pr_err("Cannot parse alias %s: %d\n", val, ret); | ||
| 230 | free(alias); | 227 | free(alias); |
| 231 | return ret; | 228 | return ret; |
| 232 | } | 229 | } |
| 233 | 230 | ||
| 234 | alias->name = strdup(name); | 231 | alias->name = strdup(name); |
| 235 | /* | 232 | if (dir) { |
| 236 | * load unit name and scale if available | 233 | /* |
| 237 | */ | 234 | * load unit name and scale if available |
| 238 | perf_pmu__parse_unit(alias, dir, name); | 235 | */ |
| 239 | perf_pmu__parse_scale(alias, dir, name); | 236 | perf_pmu__parse_unit(alias, dir, name); |
| 240 | perf_pmu__parse_per_pkg(alias, dir, name); | 237 | perf_pmu__parse_scale(alias, dir, name); |
| 241 | perf_pmu__parse_snapshot(alias, dir, name); | 238 | perf_pmu__parse_per_pkg(alias, dir, name); |
| 239 | perf_pmu__parse_snapshot(alias, dir, name); | ||
| 240 | } | ||
| 242 | 241 | ||
| 243 | list_add_tail(&alias->list, list); | 242 | list_add_tail(&alias->list, list); |
| 244 | 243 | ||
| 245 | return 0; | 244 | return 0; |
| 246 | } | 245 | } |
| 247 | 246 | ||
| 247 | static int perf_pmu__new_alias(struct list_head *list, char *dir, char *name, FILE *file) | ||
| 248 | { | ||
| 249 | char buf[256]; | ||
| 250 | int ret; | ||
| 251 | |||
| 252 | ret = fread(buf, 1, sizeof(buf), file); | ||
| 253 | if (ret == 0) | ||
| 254 | return -EINVAL; | ||
| 255 | |||
| 256 | buf[ret] = 0; | ||
| 257 | |||
| 258 | return __perf_pmu__new_alias(list, dir, name, NULL, buf); | ||
| 259 | } | ||
| 260 | |||
| 248 | static inline bool pmu_alias_info_file(char *name) | 261 | static inline bool pmu_alias_info_file(char *name) |
| 249 | { | 262 | { |
| 250 | size_t len; | 263 | size_t len; |
| @@ -436,7 +449,7 @@ static struct cpu_map *pmu_cpumask(const char *name) | |||
| 436 | return cpus; | 449 | return cpus; |
| 437 | } | 450 | } |
| 438 | 451 | ||
| 439 | struct perf_event_attr *__attribute__((weak)) | 452 | struct perf_event_attr * __weak |
| 440 | perf_pmu__get_default_config(struct perf_pmu *pmu __maybe_unused) | 453 | perf_pmu__get_default_config(struct perf_pmu *pmu __maybe_unused) |
| 441 | { | 454 | { |
| 442 | return NULL; | 455 | return NULL; |
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c index 076527b639bd..381f23a443c7 100644 --- a/tools/perf/util/probe-event.c +++ b/tools/perf/util/probe-event.c | |||
| @@ -249,8 +249,12 @@ static void clear_probe_trace_events(struct probe_trace_event *tevs, int ntevs) | |||
| 249 | static bool kprobe_blacklist__listed(unsigned long address); | 249 | static bool kprobe_blacklist__listed(unsigned long address); |
| 250 | static bool kprobe_warn_out_range(const char *symbol, unsigned long address) | 250 | static bool kprobe_warn_out_range(const char *symbol, unsigned long address) |
| 251 | { | 251 | { |
| 252 | u64 etext_addr; | ||
| 253 | |||
| 252 | /* Get the address of _etext for checking non-probable text symbol */ | 254 | /* Get the address of _etext for checking non-probable text symbol */ |
| 253 | if (kernel_get_symbol_address_by_name("_etext", false) < address) | 255 | etext_addr = kernel_get_symbol_address_by_name("_etext", false); |
| 256 | |||
| 257 | if (etext_addr != 0 && etext_addr < address) | ||
| 254 | pr_warning("%s is out of .text, skip it.\n", symbol); | 258 | pr_warning("%s is out of .text, skip it.\n", symbol); |
| 255 | else if (kprobe_blacklist__listed(address)) | 259 | else if (kprobe_blacklist__listed(address)) |
| 256 | pr_warning("%s is blacklisted function, skip it.\n", symbol); | 260 | pr_warning("%s is blacklisted function, skip it.\n", symbol); |
diff --git a/tools/perf/util/python-ext-sources b/tools/perf/util/python-ext-sources index 5925fec90562..e23ded40c79e 100644 --- a/tools/perf/util/python-ext-sources +++ b/tools/perf/util/python-ext-sources | |||
| @@ -20,3 +20,4 @@ util/stat.c | |||
| 20 | util/strlist.c | 20 | util/strlist.c |
| 21 | util/trace-event.c | 21 | util/trace-event.c |
| 22 | ../../lib/rbtree.c | 22 | ../../lib/rbtree.c |
| 23 | util/string.c | ||
diff --git a/tools/perf/util/python.c b/tools/perf/util/python.c index d906d0ad5d40..626422eda727 100644 --- a/tools/perf/util/python.c +++ b/tools/perf/util/python.c | |||
| @@ -384,7 +384,7 @@ static int pyrf_cpu_map__init(struct pyrf_cpu_map *pcpus, | |||
| 384 | 384 | ||
| 385 | static void pyrf_cpu_map__delete(struct pyrf_cpu_map *pcpus) | 385 | static void pyrf_cpu_map__delete(struct pyrf_cpu_map *pcpus) |
| 386 | { | 386 | { |
| 387 | cpu_map__delete(pcpus->cpus); | 387 | cpu_map__put(pcpus->cpus); |
| 388 | pcpus->ob_type->tp_free((PyObject*)pcpus); | 388 | pcpus->ob_type->tp_free((PyObject*)pcpus); |
| 389 | } | 389 | } |
| 390 | 390 | ||
| @@ -453,7 +453,7 @@ static int pyrf_thread_map__init(struct pyrf_thread_map *pthreads, | |||
| 453 | 453 | ||
| 454 | static void pyrf_thread_map__delete(struct pyrf_thread_map *pthreads) | 454 | static void pyrf_thread_map__delete(struct pyrf_thread_map *pthreads) |
| 455 | { | 455 | { |
| 456 | thread_map__delete(pthreads->threads); | 456 | thread_map__put(pthreads->threads); |
| 457 | pthreads->ob_type->tp_free((PyObject*)pthreads); | 457 | pthreads->ob_type->tp_free((PyObject*)pthreads); |
| 458 | } | 458 | } |
| 459 | 459 | ||
diff --git a/tools/perf/util/record.c b/tools/perf/util/record.c index d457c523a33d..1f7becbe5e18 100644 --- a/tools/perf/util/record.c +++ b/tools/perf/util/record.c | |||
| @@ -64,7 +64,7 @@ static bool perf_probe_api(setup_probe_fn_t fn) | |||
| 64 | if (!cpus) | 64 | if (!cpus) |
| 65 | return false; | 65 | return false; |
| 66 | cpu = cpus->map[0]; | 66 | cpu = cpus->map[0]; |
| 67 | cpu_map__delete(cpus); | 67 | cpu_map__put(cpus); |
| 68 | 68 | ||
| 69 | do { | 69 | do { |
| 70 | ret = perf_do_probe_api(fn, cpu, try[i++]); | 70 | ret = perf_do_probe_api(fn, cpu, try[i++]); |
| @@ -226,7 +226,7 @@ bool perf_evlist__can_select_event(struct perf_evlist *evlist, const char *str) | |||
| 226 | struct cpu_map *cpus = cpu_map__new(NULL); | 226 | struct cpu_map *cpus = cpu_map__new(NULL); |
| 227 | 227 | ||
| 228 | cpu = cpus ? cpus->map[0] : 0; | 228 | cpu = cpus ? cpus->map[0] : 0; |
| 229 | cpu_map__delete(cpus); | 229 | cpu_map__put(cpus); |
| 230 | } else { | 230 | } else { |
| 231 | cpu = evlist->cpus->map[0]; | 231 | cpu = evlist->cpus->map[0]; |
| 232 | } | 232 | } |
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index aa482c10469d..ed9dc2555ec7 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c | |||
| @@ -686,6 +686,8 @@ static int process_finished_round(struct perf_tool *tool __maybe_unused, | |||
| 686 | union perf_event *event __maybe_unused, | 686 | union perf_event *event __maybe_unused, |
| 687 | struct ordered_events *oe) | 687 | struct ordered_events *oe) |
| 688 | { | 688 | { |
| 689 | if (dump_trace) | ||
| 690 | fprintf(stdout, "\n"); | ||
| 689 | return ordered_events__flush(oe, OE_FLUSH__ROUND); | 691 | return ordered_events__flush(oe, OE_FLUSH__ROUND); |
| 690 | } | 692 | } |
| 691 | 693 | ||
| @@ -1726,7 +1728,7 @@ size_t perf_session__fprintf_nr_events(struct perf_session *session, FILE *fp) | |||
| 1726 | if (perf_header__has_feat(&session->header, HEADER_AUXTRACE)) | 1728 | if (perf_header__has_feat(&session->header, HEADER_AUXTRACE)) |
| 1727 | msg = " (excludes AUX area (e.g. instruction trace) decoded / synthesized events)"; | 1729 | msg = " (excludes AUX area (e.g. instruction trace) decoded / synthesized events)"; |
| 1728 | 1730 | ||
| 1729 | ret = fprintf(fp, "Aggregated stats:%s\n", msg); | 1731 | ret = fprintf(fp, "\nAggregated stats:%s\n", msg); |
| 1730 | 1732 | ||
| 1731 | ret += events_stats__fprintf(&session->evlist->stats, fp); | 1733 | ret += events_stats__fprintf(&session->evlist->stats, fp); |
| 1732 | return ret; | 1734 | return ret; |
| @@ -1893,7 +1895,7 @@ int perf_session__cpu_bitmap(struct perf_session *session, | |||
| 1893 | err = 0; | 1895 | err = 0; |
| 1894 | 1896 | ||
| 1895 | out_delete_map: | 1897 | out_delete_map: |
| 1896 | cpu_map__delete(map); | 1898 | cpu_map__put(map); |
| 1897 | return err; | 1899 | return err; |
| 1898 | } | 1900 | } |
| 1899 | 1901 | ||
diff --git a/tools/perf/util/stat.c b/tools/perf/util/stat.c index 4014b709f956..f2a0d1521e26 100644 --- a/tools/perf/util/stat.c +++ b/tools/perf/util/stat.c | |||
| @@ -1,6 +1,8 @@ | |||
| 1 | #include <math.h> | 1 | #include <math.h> |
| 2 | #include "stat.h" | 2 | #include "stat.h" |
| 3 | #include "evlist.h" | ||
| 3 | #include "evsel.h" | 4 | #include "evsel.h" |
| 5 | #include "thread_map.h" | ||
| 4 | 6 | ||
| 5 | void update_stats(struct stats *stats, u64 val) | 7 | void update_stats(struct stats *stats, u64 val) |
| 6 | { | 8 | { |
| @@ -95,33 +97,46 @@ void perf_stat_evsel_id_init(struct perf_evsel *evsel) | |||
| 95 | } | 97 | } |
| 96 | } | 98 | } |
| 97 | 99 | ||
| 98 | struct perf_counts *perf_counts__new(int ncpus) | 100 | struct perf_counts *perf_counts__new(int ncpus, int nthreads) |
| 99 | { | 101 | { |
| 100 | int size = sizeof(struct perf_counts) + | 102 | struct perf_counts *counts = zalloc(sizeof(*counts)); |
| 101 | ncpus * sizeof(struct perf_counts_values); | ||
| 102 | 103 | ||
| 103 | return zalloc(size); | 104 | if (counts) { |
| 105 | struct xyarray *values; | ||
| 106 | |||
| 107 | values = xyarray__new(ncpus, nthreads, sizeof(struct perf_counts_values)); | ||
| 108 | if (!values) { | ||
| 109 | free(counts); | ||
| 110 | return NULL; | ||
| 111 | } | ||
| 112 | |||
| 113 | counts->values = values; | ||
| 114 | } | ||
| 115 | |||
| 116 | return counts; | ||
| 104 | } | 117 | } |
| 105 | 118 | ||
| 106 | void perf_counts__delete(struct perf_counts *counts) | 119 | void perf_counts__delete(struct perf_counts *counts) |
| 107 | { | 120 | { |
| 108 | free(counts); | 121 | if (counts) { |
| 122 | xyarray__delete(counts->values); | ||
| 123 | free(counts); | ||
| 124 | } | ||
| 109 | } | 125 | } |
| 110 | 126 | ||
| 111 | static void perf_counts__reset(struct perf_counts *counts, int ncpus) | 127 | static void perf_counts__reset(struct perf_counts *counts) |
| 112 | { | 128 | { |
| 113 | memset(counts, 0, (sizeof(*counts) + | 129 | xyarray__reset(counts->values); |
| 114 | (ncpus * sizeof(struct perf_counts_values)))); | ||
| 115 | } | 130 | } |
| 116 | 131 | ||
| 117 | void perf_evsel__reset_counts(struct perf_evsel *evsel, int ncpus) | 132 | void perf_evsel__reset_counts(struct perf_evsel *evsel) |
| 118 | { | 133 | { |
| 119 | perf_counts__reset(evsel->counts, ncpus); | 134 | perf_counts__reset(evsel->counts); |
| 120 | } | 135 | } |
| 121 | 136 | ||
| 122 | int perf_evsel__alloc_counts(struct perf_evsel *evsel, int ncpus) | 137 | int perf_evsel__alloc_counts(struct perf_evsel *evsel, int ncpus, int nthreads) |
| 123 | { | 138 | { |
| 124 | evsel->counts = perf_counts__new(ncpus); | 139 | evsel->counts = perf_counts__new(ncpus, nthreads); |
| 125 | return evsel->counts != NULL ? 0 : -ENOMEM; | 140 | return evsel->counts != NULL ? 0 : -ENOMEM; |
| 126 | } | 141 | } |
| 127 | 142 | ||
| @@ -130,3 +145,96 @@ void perf_evsel__free_counts(struct perf_evsel *evsel) | |||
| 130 | perf_counts__delete(evsel->counts); | 145 | perf_counts__delete(evsel->counts); |
| 131 | evsel->counts = NULL; | 146 | evsel->counts = NULL; |
| 132 | } | 147 | } |
| 148 | |||
| 149 | void perf_evsel__reset_stat_priv(struct perf_evsel *evsel) | ||
| 150 | { | ||
| 151 | int i; | ||
| 152 | struct perf_stat *ps = evsel->priv; | ||
| 153 | |||
| 154 | for (i = 0; i < 3; i++) | ||
| 155 | init_stats(&ps->res_stats[i]); | ||
| 156 | |||
| 157 | perf_stat_evsel_id_init(evsel); | ||
| 158 | } | ||
| 159 | |||
| 160 | int perf_evsel__alloc_stat_priv(struct perf_evsel *evsel) | ||
| 161 | { | ||
| 162 | evsel->priv = zalloc(sizeof(struct perf_stat)); | ||
| 163 | if (evsel->priv == NULL) | ||
| 164 | return -ENOMEM; | ||
| 165 | perf_evsel__reset_stat_priv(evsel); | ||
| 166 | return 0; | ||
| 167 | } | ||
| 168 | |||
| 169 | void perf_evsel__free_stat_priv(struct perf_evsel *evsel) | ||
| 170 | { | ||
| 171 | zfree(&evsel->priv); | ||
| 172 | } | ||
| 173 | |||
| 174 | int perf_evsel__alloc_prev_raw_counts(struct perf_evsel *evsel, | ||
| 175 | int ncpus, int nthreads) | ||
| 176 | { | ||
| 177 | struct perf_counts *counts; | ||
| 178 | |||
| 179 | counts = perf_counts__new(ncpus, nthreads); | ||
| 180 | if (counts) | ||
| 181 | evsel->prev_raw_counts = counts; | ||
| 182 | |||
| 183 | return counts ? 0 : -ENOMEM; | ||
| 184 | } | ||
| 185 | |||
| 186 | void perf_evsel__free_prev_raw_counts(struct perf_evsel *evsel) | ||
| 187 | { | ||
| 188 | perf_counts__delete(evsel->prev_raw_counts); | ||
| 189 | evsel->prev_raw_counts = NULL; | ||
| 190 | } | ||
| 191 | |||
| 192 | int perf_evsel__alloc_stats(struct perf_evsel *evsel, bool alloc_raw) | ||
| 193 | { | ||
| 194 | int ncpus = perf_evsel__nr_cpus(evsel); | ||
| 195 | int nthreads = thread_map__nr(evsel->threads); | ||
| 196 | |||
| 197 | if (perf_evsel__alloc_stat_priv(evsel) < 0 || | ||
| 198 | perf_evsel__alloc_counts(evsel, ncpus, nthreads) < 0 || | ||
| 199 | (alloc_raw && perf_evsel__alloc_prev_raw_counts(evsel, ncpus, nthreads) < 0)) | ||
| 200 | return -ENOMEM; | ||
| 201 | |||
| 202 | return 0; | ||
| 203 | } | ||
| 204 | |||
| 205 | int perf_evlist__alloc_stats(struct perf_evlist *evlist, bool alloc_raw) | ||
| 206 | { | ||
| 207 | struct perf_evsel *evsel; | ||
| 208 | |||
| 209 | evlist__for_each(evlist, evsel) { | ||
| 210 | if (perf_evsel__alloc_stats(evsel, alloc_raw)) | ||
| 211 | goto out_free; | ||
| 212 | } | ||
| 213 | |||
| 214 | return 0; | ||
| 215 | |||
| 216 | out_free: | ||
| 217 | perf_evlist__free_stats(evlist); | ||
| 218 | return -1; | ||
| 219 | } | ||
| 220 | |||
| 221 | void perf_evlist__free_stats(struct perf_evlist *evlist) | ||
| 222 | { | ||
| 223 | struct perf_evsel *evsel; | ||
| 224 | |||
| 225 | evlist__for_each(evlist, evsel) { | ||
| 226 | perf_evsel__free_stat_priv(evsel); | ||
| 227 | perf_evsel__free_counts(evsel); | ||
| 228 | perf_evsel__free_prev_raw_counts(evsel); | ||
| 229 | } | ||
| 230 | } | ||
| 231 | |||
| 232 | void perf_evlist__reset_stats(struct perf_evlist *evlist) | ||
| 233 | { | ||
| 234 | struct perf_evsel *evsel; | ||
| 235 | |||
| 236 | evlist__for_each(evlist, evsel) { | ||
| 237 | perf_evsel__reset_stat_priv(evsel); | ||
| 238 | perf_evsel__reset_counts(evsel); | ||
| 239 | } | ||
| 240 | } | ||
diff --git a/tools/perf/util/stat.h b/tools/perf/util/stat.h index 093dc3cb28dd..1cfbe0a980ac 100644 --- a/tools/perf/util/stat.h +++ b/tools/perf/util/stat.h | |||
| @@ -3,6 +3,7 @@ | |||
| 3 | 3 | ||
| 4 | #include <linux/types.h> | 4 | #include <linux/types.h> |
| 5 | #include <stdio.h> | 5 | #include <stdio.h> |
| 6 | #include "xyarray.h" | ||
| 6 | 7 | ||
| 7 | struct stats | 8 | struct stats |
| 8 | { | 9 | { |
| @@ -29,8 +30,32 @@ enum aggr_mode { | |||
| 29 | AGGR_GLOBAL, | 30 | AGGR_GLOBAL, |
| 30 | AGGR_SOCKET, | 31 | AGGR_SOCKET, |
| 31 | AGGR_CORE, | 32 | AGGR_CORE, |
| 33 | AGGR_THREAD, | ||
| 32 | }; | 34 | }; |
| 33 | 35 | ||
| 36 | struct perf_counts_values { | ||
| 37 | union { | ||
| 38 | struct { | ||
| 39 | u64 val; | ||
| 40 | u64 ena; | ||
| 41 | u64 run; | ||
| 42 | }; | ||
| 43 | u64 values[3]; | ||
| 44 | }; | ||
| 45 | }; | ||
| 46 | |||
| 47 | struct perf_counts { | ||
| 48 | s8 scaled; | ||
| 49 | struct perf_counts_values aggr; | ||
| 50 | struct xyarray *values; | ||
| 51 | }; | ||
| 52 | |||
| 53 | static inline struct perf_counts_values* | ||
| 54 | perf_counts(struct perf_counts *counts, int cpu, int thread) | ||
| 55 | { | ||
| 56 | return xyarray__entry(counts->values, cpu, thread); | ||
| 57 | } | ||
| 58 | |||
| 34 | void update_stats(struct stats *stats, u64 val); | 59 | void update_stats(struct stats *stats, u64 val); |
| 35 | double avg_stats(struct stats *stats); | 60 | double avg_stats(struct stats *stats); |
| 36 | double stddev_stats(struct stats *stats); | 61 | double stddev_stats(struct stats *stats); |
| @@ -46,6 +71,8 @@ static inline void init_stats(struct stats *stats) | |||
| 46 | } | 71 | } |
| 47 | 72 | ||
| 48 | struct perf_evsel; | 73 | struct perf_evsel; |
| 74 | struct perf_evlist; | ||
| 75 | |||
| 49 | bool __perf_evsel_stat__is(struct perf_evsel *evsel, | 76 | bool __perf_evsel_stat__is(struct perf_evsel *evsel, |
| 50 | enum perf_stat_evsel_id id); | 77 | enum perf_stat_evsel_id id); |
| 51 | 78 | ||
| @@ -62,10 +89,24 @@ void perf_stat__update_shadow_stats(struct perf_evsel *counter, u64 *count, | |||
| 62 | void perf_stat__print_shadow_stats(FILE *out, struct perf_evsel *evsel, | 89 | void perf_stat__print_shadow_stats(FILE *out, struct perf_evsel *evsel, |
| 63 | double avg, int cpu, enum aggr_mode aggr); | 90 | double avg, int cpu, enum aggr_mode aggr); |
| 64 | 91 | ||
| 65 | struct perf_counts *perf_counts__new(int ncpus); | 92 | struct perf_counts *perf_counts__new(int ncpus, int nthreads); |
| 66 | void perf_counts__delete(struct perf_counts *counts); | 93 | void perf_counts__delete(struct perf_counts *counts); |
| 67 | 94 | ||
| 68 | void perf_evsel__reset_counts(struct perf_evsel *evsel, int ncpus); | 95 | void perf_evsel__reset_counts(struct perf_evsel *evsel); |
| 69 | int perf_evsel__alloc_counts(struct perf_evsel *evsel, int ncpus); | 96 | int perf_evsel__alloc_counts(struct perf_evsel *evsel, int ncpus, int nthreads); |
| 70 | void perf_evsel__free_counts(struct perf_evsel *evsel); | 97 | void perf_evsel__free_counts(struct perf_evsel *evsel); |
| 98 | |||
| 99 | void perf_evsel__reset_stat_priv(struct perf_evsel *evsel); | ||
| 100 | int perf_evsel__alloc_stat_priv(struct perf_evsel *evsel); | ||
| 101 | void perf_evsel__free_stat_priv(struct perf_evsel *evsel); | ||
| 102 | |||
| 103 | int perf_evsel__alloc_prev_raw_counts(struct perf_evsel *evsel, | ||
| 104 | int ncpus, int nthreads); | ||
| 105 | void perf_evsel__free_prev_raw_counts(struct perf_evsel *evsel); | ||
| 106 | |||
| 107 | int perf_evsel__alloc_stats(struct perf_evsel *evsel, bool alloc_raw); | ||
| 108 | |||
| 109 | int perf_evlist__alloc_stats(struct perf_evlist *evlist, bool alloc_raw); | ||
| 110 | void perf_evlist__free_stats(struct perf_evlist *evlist); | ||
| 111 | void perf_evlist__reset_stats(struct perf_evlist *evlist); | ||
| 71 | #endif | 112 | #endif |
diff --git a/tools/perf/util/svghelper.c b/tools/perf/util/svghelper.c index 283d3e73e2f2..eec6c1149f44 100644 --- a/tools/perf/util/svghelper.c +++ b/tools/perf/util/svghelper.c | |||
| @@ -748,7 +748,7 @@ static int str_to_bitmap(char *s, cpumask_t *b) | |||
| 748 | set_bit(c, cpumask_bits(b)); | 748 | set_bit(c, cpumask_bits(b)); |
| 749 | } | 749 | } |
| 750 | 750 | ||
| 751 | cpu_map__delete(m); | 751 | cpu_map__put(m); |
| 752 | 752 | ||
| 753 | return ret; | 753 | return ret; |
| 754 | } | 754 | } |
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index 504f2d73b7ee..48b588c6951a 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c | |||
| @@ -1132,8 +1132,11 @@ static int dso__load_kcore(struct dso *dso, struct map *map, | |||
| 1132 | INIT_LIST_HEAD(&md.maps); | 1132 | INIT_LIST_HEAD(&md.maps); |
| 1133 | 1133 | ||
| 1134 | fd = open(kcore_filename, O_RDONLY); | 1134 | fd = open(kcore_filename, O_RDONLY); |
| 1135 | if (fd < 0) | 1135 | if (fd < 0) { |
| 1136 | pr_err("%s requires CAP_SYS_RAWIO capability to access.\n", | ||
| 1137 | kcore_filename); | ||
| 1136 | return -EINVAL; | 1138 | return -EINVAL; |
| 1139 | } | ||
| 1137 | 1140 | ||
| 1138 | /* Read new maps into temporary lists */ | 1141 | /* Read new maps into temporary lists */ |
| 1139 | err = file__read_maps(fd, md.type == MAP__FUNCTION, kcore_mapfn, &md, | 1142 | err = file__read_maps(fd, md.type == MAP__FUNCTION, kcore_mapfn, &md, |
diff --git a/tools/perf/util/thread_map.c b/tools/perf/util/thread_map.c index f4822bd03709..da7646d767fe 100644 --- a/tools/perf/util/thread_map.c +++ b/tools/perf/util/thread_map.c | |||
| @@ -8,8 +8,11 @@ | |||
| 8 | #include <unistd.h> | 8 | #include <unistd.h> |
| 9 | #include "strlist.h" | 9 | #include "strlist.h" |
| 10 | #include <string.h> | 10 | #include <string.h> |
| 11 | #include <api/fs/fs.h> | ||
| 12 | #include "asm/bug.h" | ||
| 11 | #include "thread_map.h" | 13 | #include "thread_map.h" |
| 12 | #include "util.h" | 14 | #include "util.h" |
| 15 | #include "debug.h" | ||
| 13 | 16 | ||
| 14 | /* Skip "." and ".." directories */ | 17 | /* Skip "." and ".." directories */ |
| 15 | static int filter(const struct dirent *dir) | 18 | static int filter(const struct dirent *dir) |
| @@ -20,11 +23,26 @@ static int filter(const struct dirent *dir) | |||
| 20 | return 1; | 23 | return 1; |
| 21 | } | 24 | } |
| 22 | 25 | ||
| 26 | static void thread_map__reset(struct thread_map *map, int start, int nr) | ||
| 27 | { | ||
| 28 | size_t size = (nr - start) * sizeof(map->map[0]); | ||
| 29 | |||
| 30 | memset(&map->map[start], 0, size); | ||
| 31 | } | ||
| 32 | |||
| 23 | static struct thread_map *thread_map__realloc(struct thread_map *map, int nr) | 33 | static struct thread_map *thread_map__realloc(struct thread_map *map, int nr) |
| 24 | { | 34 | { |
| 25 | size_t size = sizeof(*map) + sizeof(pid_t) * nr; | 35 | size_t size = sizeof(*map) + sizeof(map->map[0]) * nr; |
| 36 | int start = map ? map->nr : 0; | ||
| 37 | |||
| 38 | map = realloc(map, size); | ||
| 39 | /* | ||
| 40 | * We only realloc to add more items, let's reset new items. | ||
| 41 | */ | ||
| 42 | if (map) | ||
| 43 | thread_map__reset(map, start, nr); | ||
| 26 | 44 | ||
| 27 | return realloc(map, size); | 45 | return map; |
| 28 | } | 46 | } |
| 29 | 47 | ||
| 30 | #define thread_map__alloc(__nr) thread_map__realloc(NULL, __nr) | 48 | #define thread_map__alloc(__nr) thread_map__realloc(NULL, __nr) |
| @@ -45,8 +63,9 @@ struct thread_map *thread_map__new_by_pid(pid_t pid) | |||
| 45 | threads = thread_map__alloc(items); | 63 | threads = thread_map__alloc(items); |
| 46 | if (threads != NULL) { | 64 | if (threads != NULL) { |
| 47 | for (i = 0; i < items; i++) | 65 | for (i = 0; i < items; i++) |
| 48 | threads->map[i] = atoi(namelist[i]->d_name); | 66 | thread_map__set_pid(threads, i, atoi(namelist[i]->d_name)); |
| 49 | threads->nr = items; | 67 | threads->nr = items; |
| 68 | atomic_set(&threads->refcnt, 1); | ||
| 50 | } | 69 | } |
| 51 | 70 | ||
| 52 | for (i=0; i<items; i++) | 71 | for (i=0; i<items; i++) |
| @@ -61,8 +80,9 @@ struct thread_map *thread_map__new_by_tid(pid_t tid) | |||
| 61 | struct thread_map *threads = thread_map__alloc(1); | 80 | struct thread_map *threads = thread_map__alloc(1); |
| 62 | 81 | ||
| 63 | if (threads != NULL) { | 82 | if (threads != NULL) { |
| 64 | threads->map[0] = tid; | 83 | thread_map__set_pid(threads, 0, tid); |
| 65 | threads->nr = 1; | 84 | threads->nr = 1; |
| 85 | atomic_set(&threads->refcnt, 1); | ||
| 66 | } | 86 | } |
| 67 | 87 | ||
| 68 | return threads; | 88 | return threads; |
| @@ -84,6 +104,7 @@ struct thread_map *thread_map__new_by_uid(uid_t uid) | |||
| 84 | goto out_free_threads; | 104 | goto out_free_threads; |
| 85 | 105 | ||
| 86 | threads->nr = 0; | 106 | threads->nr = 0; |
| 107 | atomic_set(&threads->refcnt, 1); | ||
| 87 | 108 | ||
| 88 | while (!readdir_r(proc, &dirent, &next) && next) { | 109 | while (!readdir_r(proc, &dirent, &next) && next) { |
| 89 | char *end; | 110 | char *end; |
| @@ -123,8 +144,10 @@ struct thread_map *thread_map__new_by_uid(uid_t uid) | |||
| 123 | threads = tmp; | 144 | threads = tmp; |
| 124 | } | 145 | } |
| 125 | 146 | ||
| 126 | for (i = 0; i < items; i++) | 147 | for (i = 0; i < items; i++) { |
| 127 | threads->map[threads->nr + i] = atoi(namelist[i]->d_name); | 148 | thread_map__set_pid(threads, threads->nr + i, |
| 149 | atoi(namelist[i]->d_name)); | ||
| 150 | } | ||
| 128 | 151 | ||
| 129 | for (i = 0; i < items; i++) | 152 | for (i = 0; i < items; i++) |
| 130 | zfree(&namelist[i]); | 153 | zfree(&namelist[i]); |
| @@ -201,7 +224,7 @@ static struct thread_map *thread_map__new_by_pid_str(const char *pid_str) | |||
| 201 | threads = nt; | 224 | threads = nt; |
| 202 | 225 | ||
| 203 | for (i = 0; i < items; i++) { | 226 | for (i = 0; i < items; i++) { |
| 204 | threads->map[j++] = atoi(namelist[i]->d_name); | 227 | thread_map__set_pid(threads, j++, atoi(namelist[i]->d_name)); |
| 205 | zfree(&namelist[i]); | 228 | zfree(&namelist[i]); |
| 206 | } | 229 | } |
| 207 | threads->nr = total_tasks; | 230 | threads->nr = total_tasks; |
| @@ -210,6 +233,8 @@ static struct thread_map *thread_map__new_by_pid_str(const char *pid_str) | |||
| 210 | 233 | ||
| 211 | out: | 234 | out: |
| 212 | strlist__delete(slist); | 235 | strlist__delete(slist); |
| 236 | if (threads) | ||
| 237 | atomic_set(&threads->refcnt, 1); | ||
| 213 | return threads; | 238 | return threads; |
| 214 | 239 | ||
| 215 | out_free_namelist: | 240 | out_free_namelist: |
| @@ -227,8 +252,9 @@ struct thread_map *thread_map__new_dummy(void) | |||
| 227 | struct thread_map *threads = thread_map__alloc(1); | 252 | struct thread_map *threads = thread_map__alloc(1); |
| 228 | 253 | ||
| 229 | if (threads != NULL) { | 254 | if (threads != NULL) { |
| 230 | threads->map[0] = -1; | 255 | thread_map__set_pid(threads, 0, -1); |
| 231 | threads->nr = 1; | 256 | threads->nr = 1; |
| 257 | atomic_set(&threads->refcnt, 1); | ||
| 232 | } | 258 | } |
| 233 | return threads; | 259 | return threads; |
| 234 | } | 260 | } |
| @@ -267,10 +293,12 @@ static struct thread_map *thread_map__new_by_tid_str(const char *tid_str) | |||
| 267 | goto out_free_threads; | 293 | goto out_free_threads; |
| 268 | 294 | ||
| 269 | threads = nt; | 295 | threads = nt; |
| 270 | threads->map[ntasks - 1] = tid; | 296 | thread_map__set_pid(threads, ntasks - 1, tid); |
| 271 | threads->nr = ntasks; | 297 | threads->nr = ntasks; |
| 272 | } | 298 | } |
| 273 | out: | 299 | out: |
| 300 | if (threads) | ||
| 301 | atomic_set(&threads->refcnt, 1); | ||
| 274 | return threads; | 302 | return threads; |
| 275 | 303 | ||
| 276 | out_free_threads: | 304 | out_free_threads: |
| @@ -290,9 +318,30 @@ struct thread_map *thread_map__new_str(const char *pid, const char *tid, | |||
| 290 | return thread_map__new_by_tid_str(tid); | 318 | return thread_map__new_by_tid_str(tid); |
| 291 | } | 319 | } |
| 292 | 320 | ||
| 293 | void thread_map__delete(struct thread_map *threads) | 321 | static void thread_map__delete(struct thread_map *threads) |
| 294 | { | 322 | { |
| 295 | free(threads); | 323 | if (threads) { |
| 324 | int i; | ||
| 325 | |||
| 326 | WARN_ONCE(atomic_read(&threads->refcnt) != 0, | ||
| 327 | "thread map refcnt unbalanced\n"); | ||
| 328 | for (i = 0; i < threads->nr; i++) | ||
| 329 | free(thread_map__comm(threads, i)); | ||
| 330 | free(threads); | ||
| 331 | } | ||
| 332 | } | ||
| 333 | |||
| 334 | struct thread_map *thread_map__get(struct thread_map *map) | ||
| 335 | { | ||
| 336 | if (map) | ||
| 337 | atomic_inc(&map->refcnt); | ||
| 338 | return map; | ||
| 339 | } | ||
| 340 | |||
| 341 | void thread_map__put(struct thread_map *map) | ||
| 342 | { | ||
| 343 | if (map && atomic_dec_and_test(&map->refcnt)) | ||
| 344 | thread_map__delete(map); | ||
| 296 | } | 345 | } |
| 297 | 346 | ||
| 298 | size_t thread_map__fprintf(struct thread_map *threads, FILE *fp) | 347 | size_t thread_map__fprintf(struct thread_map *threads, FILE *fp) |
| @@ -301,7 +350,60 @@ size_t thread_map__fprintf(struct thread_map *threads, FILE *fp) | |||
| 301 | size_t printed = fprintf(fp, "%d thread%s: ", | 350 | size_t printed = fprintf(fp, "%d thread%s: ", |
| 302 | threads->nr, threads->nr > 1 ? "s" : ""); | 351 | threads->nr, threads->nr > 1 ? "s" : ""); |
| 303 | for (i = 0; i < threads->nr; ++i) | 352 | for (i = 0; i < threads->nr; ++i) |
| 304 | printed += fprintf(fp, "%s%d", i ? ", " : "", threads->map[i]); | 353 | printed += fprintf(fp, "%s%d", i ? ", " : "", thread_map__pid(threads, i)); |
| 305 | 354 | ||
| 306 | return printed + fprintf(fp, "\n"); | 355 | return printed + fprintf(fp, "\n"); |
| 307 | } | 356 | } |
| 357 | |||
| 358 | static int get_comm(char **comm, pid_t pid) | ||
| 359 | { | ||
| 360 | char *path; | ||
| 361 | size_t size; | ||
| 362 | int err; | ||
| 363 | |||
| 364 | if (asprintf(&path, "%s/%d/comm", procfs__mountpoint(), pid) == -1) | ||
| 365 | return -ENOMEM; | ||
| 366 | |||
| 367 | err = filename__read_str(path, comm, &size); | ||
| 368 | if (!err) { | ||
| 369 | /* | ||
| 370 | * We're reading 16 bytes, while filename__read_str | ||
| 371 | * allocates data per BUFSIZ bytes, so we can safely | ||
| 372 | * mark the end of the string. | ||
| 373 | */ | ||
| 374 | (*comm)[size] = 0; | ||
| 375 | rtrim(*comm); | ||
| 376 | } | ||
| 377 | |||
| 378 | free(path); | ||
| 379 | return err; | ||
| 380 | } | ||
| 381 | |||
| 382 | static void comm_init(struct thread_map *map, int i) | ||
| 383 | { | ||
| 384 | pid_t pid = thread_map__pid(map, i); | ||
| 385 | char *comm = NULL; | ||
| 386 | |||
| 387 | /* dummy pid comm initialization */ | ||
| 388 | if (pid == -1) { | ||
| 389 | map->map[i].comm = strdup("dummy"); | ||
| 390 | return; | ||
| 391 | } | ||
| 392 | |||
| 393 | /* | ||
| 394 | * The comm name is like extra bonus ;-), | ||
| 395 | * so just warn if we fail for any reason. | ||
| 396 | */ | ||
| 397 | if (get_comm(&comm, pid)) | ||
| 398 | pr_warning("Couldn't resolve comm name for pid %d\n", pid); | ||
| 399 | |||
| 400 | map->map[i].comm = comm; | ||
| 401 | } | ||
| 402 | |||
| 403 | void thread_map__read_comms(struct thread_map *threads) | ||
| 404 | { | ||
| 405 | int i; | ||
| 406 | |||
| 407 | for (i = 0; i < threads->nr; ++i) | ||
| 408 | comm_init(threads, i); | ||
| 409 | } | ||
diff --git a/tools/perf/util/thread_map.h b/tools/perf/util/thread_map.h index 95313f43cc0f..af679d8a50f8 100644 --- a/tools/perf/util/thread_map.h +++ b/tools/perf/util/thread_map.h | |||
| @@ -3,10 +3,17 @@ | |||
| 3 | 3 | ||
| 4 | #include <sys/types.h> | 4 | #include <sys/types.h> |
| 5 | #include <stdio.h> | 5 | #include <stdio.h> |
| 6 | #include <linux/atomic.h> | ||
| 7 | |||
| 8 | struct thread_map_data { | ||
| 9 | pid_t pid; | ||
| 10 | char *comm; | ||
| 11 | }; | ||
| 6 | 12 | ||
| 7 | struct thread_map { | 13 | struct thread_map { |
| 14 | atomic_t refcnt; | ||
| 8 | int nr; | 15 | int nr; |
| 9 | pid_t map[]; | 16 | struct thread_map_data map[]; |
| 10 | }; | 17 | }; |
| 11 | 18 | ||
| 12 | struct thread_map *thread_map__new_dummy(void); | 19 | struct thread_map *thread_map__new_dummy(void); |
| @@ -15,11 +22,12 @@ struct thread_map *thread_map__new_by_tid(pid_t tid); | |||
| 15 | struct thread_map *thread_map__new_by_uid(uid_t uid); | 22 | struct thread_map *thread_map__new_by_uid(uid_t uid); |
| 16 | struct thread_map *thread_map__new(pid_t pid, pid_t tid, uid_t uid); | 23 | struct thread_map *thread_map__new(pid_t pid, pid_t tid, uid_t uid); |
| 17 | 24 | ||
| 25 | struct thread_map *thread_map__get(struct thread_map *map); | ||
| 26 | void thread_map__put(struct thread_map *map); | ||
| 27 | |||
| 18 | struct thread_map *thread_map__new_str(const char *pid, | 28 | struct thread_map *thread_map__new_str(const char *pid, |
| 19 | const char *tid, uid_t uid); | 29 | const char *tid, uid_t uid); |
| 20 | 30 | ||
| 21 | void thread_map__delete(struct thread_map *threads); | ||
| 22 | |||
| 23 | size_t thread_map__fprintf(struct thread_map *threads, FILE *fp); | 31 | size_t thread_map__fprintf(struct thread_map *threads, FILE *fp); |
| 24 | 32 | ||
| 25 | static inline int thread_map__nr(struct thread_map *threads) | 33 | static inline int thread_map__nr(struct thread_map *threads) |
| @@ -27,4 +35,21 @@ static inline int thread_map__nr(struct thread_map *threads) | |||
| 27 | return threads ? threads->nr : 1; | 35 | return threads ? threads->nr : 1; |
| 28 | } | 36 | } |
| 29 | 37 | ||
| 38 | static inline pid_t thread_map__pid(struct thread_map *map, int thread) | ||
| 39 | { | ||
| 40 | return map->map[thread].pid; | ||
| 41 | } | ||
| 42 | |||
| 43 | static inline void | ||
| 44 | thread_map__set_pid(struct thread_map *map, int thread, pid_t pid) | ||
| 45 | { | ||
| 46 | map->map[thread].pid = pid; | ||
| 47 | } | ||
| 48 | |||
| 49 | static inline char *thread_map__comm(struct thread_map *map, int thread) | ||
| 50 | { | ||
| 51 | return map->map[thread].comm; | ||
| 52 | } | ||
| 53 | |||
| 54 | void thread_map__read_comms(struct thread_map *threads); | ||
| 30 | #endif /* __PERF_THREAD_MAP_H */ | 55 | #endif /* __PERF_THREAD_MAP_H */ |
