aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2015-07-04 11:17:29 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2015-07-04 11:17:29 -0400
commitc1776a18e3b5a3559f3dff5df0ecce570abd3a9f (patch)
tree5b97defe199f434f5d9829bf7d8df6124e6ce5f1
parent91cca0f0ffa3e485ad9d5b44744f23318c8f99ab (diff)
parentb9df84fd7c05cc300d6d14f022b8a00773ebcf8c (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 ...
-rw-r--r--arch/x86/kernel/cpu/perf_event.c36
-rw-r--r--tools/build/Makefile.build2
-rw-r--r--tools/perf/Documentation/perf-stat.txt4
-rw-r--r--tools/perf/Makefile4
-rw-r--r--tools/perf/Makefile.perf4
-rw-r--r--tools/perf/builtin-inject.c7
-rw-r--r--tools/perf/builtin-kmem.c4
-rw-r--r--tools/perf/builtin-kvm.c14
-rw-r--r--tools/perf/builtin-mem.c16
-rw-r--r--tools/perf/builtin-report.c17
-rw-r--r--tools/perf/builtin-stat.c412
-rw-r--r--tools/perf/builtin-top.c24
-rw-r--r--tools/perf/builtin-trace.c36
-rw-r--r--tools/perf/config/Makefile6
-rw-r--r--tools/perf/tests/Build1
-rw-r--r--tools/perf/tests/builtin-test.c4
-rw-r--r--tools/perf/tests/code-reading.c4
-rw-r--r--tools/perf/tests/keep-tracking.c4
-rw-r--r--tools/perf/tests/make31
-rw-r--r--tools/perf/tests/mmap-basic.c4
-rw-r--r--tools/perf/tests/mmap-thread-lookup.c2
-rw-r--r--tools/perf/tests/openat-syscall-all-cpus.c8
-rw-r--r--tools/perf/tests/openat-syscall-tp-fields.c2
-rw-r--r--tools/perf/tests/openat-syscall.c6
-rw-r--r--tools/perf/tests/switch-tracking.c4
-rw-r--r--tools/perf/tests/tests.h1
-rw-r--r--tools/perf/tests/thread-map.c38
-rw-r--r--tools/perf/ui/browsers/hists.c19
-rw-r--r--tools/perf/util/auxtrace.c11
-rw-r--r--tools/perf/util/auxtrace.h1
-rw-r--r--tools/perf/util/cloexec.c4
-rw-r--r--tools/perf/util/cpumap.c26
-rw-r--r--tools/perf/util/cpumap.h6
-rw-r--r--tools/perf/util/event.c6
-rw-r--r--tools/perf/util/evlist.c39
-rw-r--r--tools/perf/util/evlist.h1
-rw-r--r--tools/perf/util/evsel.c28
-rw-r--r--tools/perf/util/evsel.h40
-rw-r--r--tools/perf/util/header.c3
-rw-r--r--tools/perf/util/machine.c3
-rw-r--r--tools/perf/util/parse-events.c5
-rw-r--r--tools/perf/util/parse-events.l5
-rw-r--r--tools/perf/util/pmu.c45
-rw-r--r--tools/perf/util/probe-event.c6
-rw-r--r--tools/perf/util/python-ext-sources1
-rw-r--r--tools/perf/util/python.c4
-rw-r--r--tools/perf/util/record.c4
-rw-r--r--tools/perf/util/session.c6
-rw-r--r--tools/perf/util/stat.c132
-rw-r--r--tools/perf/util/stat.h47
-rw-r--r--tools/perf/util/svghelper.c2
-rw-r--r--tools/perf/util/symbol.c5
-rw-r--r--tools/perf/util/thread_map.c132
-rw-r--r--tools/perf/util/thread_map.h31
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 */
358int x86_add_exclusive(unsigned int what) 358int 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
374out: 375fail_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
390void x86_del_exclusive(unsigned int what) 380void 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
25include $(build-dir)/Build.include 25include $(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
144use --per-core in addition to -a. (system-wide). The output includes the 144use --per-core in addition to -a. (system-wide). The output includes the
145core number and the number of online logical processors on that physical processor. 145core number and the number of online logical processors on that physical processor.
146 146
147--per-thread::
148Aggregate counts per monitored threads, when monitoring threads (-t option)
149or processes (-p option).
150
147-D msecs:: 151-D msecs::
148--delay msecs:: 152--delay msecs::
149After starting the program, wait msecs before measuring. This is useful to 153After 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
112CC = $(CROSS_COMPILE)gcc 112CC = $(CROSS_COMPILE)gcc
113LD = $(CROSS_COMPILE)ld 113LD ?= $(CROSS_COMPILE)ld
114AR = $(CROSS_COMPILE)ar 114AR = $(CROSS_COMPILE)ar
115PKG_CONFIG = $(CROSS_COMPILE)pkg-config 115PKG_CONFIG = $(CROSS_COMPILE)pkg-config
116 116
@@ -545,7 +545,7 @@ config-clean:
545clean: $(LIBTRACEEVENT)-clean $(LIBAPI)-clean config-clean 545clean: $(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
639out_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
1079out_delete:
1080 perf_session__delete(kvm->session);
1081 return ret;
1076} 1082}
1077 1083
1078static int parse_target_str(struct perf_kvm_stat *kvm) 1084static 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
153out_delete: 149out_delete:
154 perf_session__delete(session); 150 perf_session__delete(session);
155 return err; 151 return ret;
156} 152}
157 153
158static int report_events(int argc, const char **argv, struct perf_mem *mem) 154static 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
70static void print_stat(int argc, const char **argv); 70static void print_counters(struct timespec *ts, int argc, const char **argv);
71static void print_counter_aggr(struct perf_evsel *counter, char *prefix);
72static void print_counter(struct perf_evsel *counter, char *prefix);
73static void print_aggr(char *prefix);
74 71
75/* Default events used for perf stat -T */ 72/* Default events used for perf stat -T */
76static const char *transaction_attrs = { 73static 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
144static inline struct cpu_map *perf_evsel__cpus(struct perf_evsel *evsel) 141static 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
149static inline int perf_evsel__nr_cpus(struct perf_evsel *evsel)
150{
151 return perf_evsel__cpus(evsel)->nr;
152}
153
154static 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
165static 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
174static void perf_evsel__free_stat_priv(struct perf_evsel *evsel)
175{
176 zfree(&evsel->priv);
177}
178
179static 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
190static 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
196static 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
207static 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
220out_free:
221 perf_evlist__free_stats(evlist);
222 return -1;
223}
224
225static 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
307static int read_cb(struct perf_evsel *evsel, int cpu, int thread __maybe_unused, 217static int
308 struct perf_counts_values *count) 218process_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
346static int read_counter(struct perf_evsel *counter); 257static 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++) {
352static 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
277static 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
413static void print_interval(void) 346static 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) 364static 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
477static void handle_initial_delay(void) 376static 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
762static 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
975static void print_stat(int argc, const char **argv) 905static 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
935static 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
964static 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
978static 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
1035static volatile int signr = -1; 1015static 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);
1490out: 1492out:
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
1620static 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;
2349again: 2377again:
@@ -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),)
11obj-perf := $(abspath $(obj-perf))/ 11obj-perf := $(abspath $(obj-perf))/
12endif 12endif
13 13
14$(shell echo -n > .config-detected) 14$(shell echo -n > $(OUTPUT).config-detected)
15detected = $(shell echo "$(1)=y" >> .config-detected) 15detected = $(shell echo "$(1)=y" >> $(OUTPUT).config-detected)
16detected_var = $(shell echo "$(1)=$($(1))" >> .config-detected) 16detected_var = $(shell echo "$(1)=$($(1))" >> $(OUTPUT).config-detected)
17 17
18CFLAGS := $(EXTRA_CFLAGS) $(EXTRA_WARNINGS) 18CFLAGS := $(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
31perf-y += sample-parsing.o 31perf-y += sample-parsing.o
32perf-y += parse-no-sample-id-all.o 32perf-y += parse-no-sample-id-all.o
33perf-y += kmod-path.o 33perf-y += kmod-path.o
34perf-y += thread-map.o
34 35
35perf-$(CONFIG_X86) += perf-time-to-tsc.o 36perf-$(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 @@
1ifndef MK
2ifeq ($(MAKECMDGOALS),)
3# no target specified, trigger the whole suite
4all:
5 @echo "Testing Makefile"; $(MAKE) -sf tests/make MK=Makefile
6 @echo "Testing Makefile.perf"; $(MAKE) -sf tests/make MK=Makefile.perf
7else
8# run only specific test over 'Makefile'
9%:
10 @echo "Testing Makefile"; $(MAKE) -sf tests/make MK=Makefile $@
11endif
12else
1PERF := . 13PERF := .
2MK := Makefile
3 14
4include config/Makefile.arch 15include config/Makefile.arch
5 16
@@ -47,6 +58,7 @@ make_install_man := install-man
47make_install_html := install-html 58make_install_html := install-html
48make_install_info := install-info 59make_install_info := install-info
49make_install_pdf := install-pdf 60make_install_pdf := install-pdf
61make_install_prefix := install prefix=/tmp/krava
50make_static := LDFLAGS=-static 62make_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
59run := make_pure 71run := 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
75ifeq ($(MK),Makefile)
60run += make_clean_all 76run += make_clean_all
77endif
61run += make_python_perf_so 78run += make_python_perf_so
62run += make_debug 79run += make_debug
63run += make_no_libperl 80run += make_no_libperl
@@ -83,6 +100,7 @@ run += make_util_map_o
83run += make_util_pmu_bison_o 100run += make_util_pmu_bison_o
84run += make_install 101run += make_install
85run += make_install_bin 102run += make_install_bin
103run += 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))
157test_make_install_bin := $(call test_dest_files,$(installed_files_bin)) 175test_make_install_bin := $(call test_dest_files,$(installed_files_bin))
158test_make_install_bin_O := $(call test_dest_files,$(installed_files_bin)) 176test_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.
180installed_files_all_prefix := $(addprefix /tmp/krava/,$(installed_files_all))
181test_make_install_prefix := $(call test_dest_files,$(installed_files_all_prefix))
182test_make_install_prefix_O := $(call test_dest_files,$(installed_files_all_prefix))
183
160# FIXME nothing gets installed 184# FIXME nothing gets installed
161test_make_install_man := test -f $$TMP_DEST/share/man/man1/perf.1 185test_make_install_man := test -f $$TMP_DEST/share/man/man1/perf.1
162test_make_install_man_O := $(test_make_install_man) 186test_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
228make_kernelsrc: 252make_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
234make_kernelsrc_tools: 258make_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
271endif # 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;
142out_free_cpus: 142out_free_cpus:
143 cpu_map__delete(cpus); 143 cpu_map__put(cpus);
144out_free_threads: 144out_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:
111out_evsel_delete: 111out_evsel_delete:
112 perf_evsel__delete(evsel); 112 perf_evsel__delete(evsel);
113out_thread_map_delete: 113out_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:
56out_evsel_delete: 56out_evsel_delete:
57 perf_evsel__delete(evsel); 57 perf_evsel__delete(evsel);
58out_thread_map_delete: 58out_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);
61int test__fdarray__filter(void); 61int test__fdarray__filter(void);
62int test__fdarray__add(void); 62int test__fdarray__add(void);
63int test__kmod_path__parse(void); 63int test__kmod_path__parse(void);
64int 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
7int 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
8static unsigned long flag = PERF_FLAG_FD_CLOEXEC; 8static unsigned long flag = PERF_FLAG_FD_CLOEXEC;
9 9
10#ifdef __GLIBC_PREREQ
11#if !__GLIBC_PREREQ(2, 6)
10int __weak sched_getcpu(void) 12int __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
16static int perf_flag_probe(void) 20static 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
9static struct cpu_map *cpu_map__default_new(void) 10static 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
202void cpu_map__delete(struct cpu_map *map) 206static 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
215struct cpu_map *cpu_map__get(struct cpu_map *map)
216{
217 if (map)
218 atomic_inc(&map->refcnt);
219 return map;
220}
221
222void 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
207int cpu_map__get_socket(struct cpu_map *map, int idx) 228int 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
10struct cpu_map { 11struct cpu_map {
12 atomic_t refcnt;
11 int nr; 13 int nr;
12 int map[]; 14 int map[];
13}; 15};
14 16
15struct cpu_map *cpu_map__new(const char *cpu_list); 17struct cpu_map *cpu_map__new(const char *cpu_list);
16struct cpu_map *cpu_map__dummy_new(void); 18struct cpu_map *cpu_map__dummy_new(void);
17void cpu_map__delete(struct cpu_map *map);
18struct cpu_map *cpu_map__read(FILE *file); 19struct cpu_map *cpu_map__read(FILE *file);
19size_t cpu_map__fprintf(struct cpu_map *map, FILE *fp); 20size_t cpu_map__fprintf(struct cpu_map *map, FILE *fp);
20int cpu_map__get_socket(struct cpu_map *map, int idx); 21int 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);
22int cpu_map__build_socket_map(struct cpu_map *cpus, struct cpu_map **sockp); 23int cpu_map__build_socket_map(struct cpu_map *cpus, struct cpu_map **sockp);
23int cpu_map__build_core_map(struct cpu_map *cpus, struct cpu_map **corep); 24int cpu_map__build_core_map(struct cpu_map *cpus, struct cpu_map **corep);
24 25
26struct cpu_map *cpu_map__get(struct cpu_map *map);
27void cpu_map__put(struct cpu_map *map);
28
25static inline int cpu_map__socket(struct cpu_map *sock, int s) 29static 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
1104static 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
1104int perf_evlist__create_maps(struct perf_evlist *evlist, struct target *target) 1129int 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
1122out_delete_threads: 1147out_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)
1353out: 1378out:
1354 return err; 1379 return err;
1355out_free_cpus: 1380out_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
290void perf_evlist__set_tracking_event(struct perf_evlist *evlist, 290void 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
899void perf_evsel__compute_deltas(struct perf_evsel *evsel, int cpu, 901void 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
940int perf_evsel__read_cb(struct perf_evsel *evsel, int cpu, int thread, 942int 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
956int __perf_evsel__read_on_cpu(struct perf_evsel *evsel, 956int __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);
1173retry_open: 1173retry_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"
12struct 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
23struct perf_counts {
24 s8 scaled;
25 struct perf_counts_values aggr;
26 struct perf_counts_values cpu[];
27};
28 13
29struct perf_evsel; 14struct 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;
113struct perf_evlist; 99struct perf_evlist;
114struct record_opts; 100struct record_opts;
115 101
102static inline struct cpu_map *perf_evsel__cpus(struct perf_evsel *evsel)
103{
104 return evsel->cpus;
105}
106
107static inline int perf_evsel__nr_cpus(struct perf_evsel *evsel)
108{
109 return perf_evsel__cpus(evsel)->nr;
110}
111
116void perf_counts_values__scale(struct perf_counts_values *count, 112void perf_counts_values__scale(struct perf_counts_values *count,
117 bool scale, s8 *pscaled); 113 bool scale, s8 *pscaled);
118 114
119void perf_evsel__compute_deltas(struct perf_evsel *evsel, int cpu, 115void 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
122int perf_evsel__object_config(size_t object_size, 118int 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
236typedef int (perf_evsel__read_cb_t)(struct perf_evsel *evsel, 232int 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
240int perf_evsel__read_cb(struct perf_evsel *evsel, int cpu, int thread,
241 perf_evsel__read_cb_t cb);
242 234
243int __perf_evsel__read_on_cpu(struct perf_evsel *evsel, 235int __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;
1065error: 1065error:
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 [^,{}/]+
119num_dec [0-9]+ 119num_dec [0-9]+
120num_hex 0x[a-fA-F0-9]+ 120num_hex 0x[a-fA-F0-9]+
121num_raw_hex [a-fA-F0-9]+ 121num_raw_hex [a-fA-F0-9]+
122name [a-zA-Z_*?][a-zA-Z0-9_*?]* 122name [a-zA-Z_*?][a-zA-Z0-9_*?.]*
123name_minus [a-zA-Z_*?][a-zA-Z0-9\-_*?]* 123name_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() */
125modifier_event [ukhpGHSDI]+ 125modifier_event [ukhpGHSDI]+
126modifier_bp [rwx]{1,3} 126modifier_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
208static int perf_pmu__new_alias(struct list_head *list, char *dir, char *name, FILE *file) 209static 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
247static 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
248static inline bool pmu_alias_info_file(char *name) 261static 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
439struct perf_event_attr *__attribute__((weak)) 452struct perf_event_attr * __weak
440perf_pmu__get_default_config(struct perf_pmu *pmu __maybe_unused) 453perf_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)
249static bool kprobe_blacklist__listed(unsigned long address); 249static bool kprobe_blacklist__listed(unsigned long address);
250static bool kprobe_warn_out_range(const char *symbol, unsigned long address) 250static 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
20util/strlist.c 20util/strlist.c
21util/trace-event.c 21util/trace-event.c
22../../lib/rbtree.c 22../../lib/rbtree.c
23util/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
385static void pyrf_cpu_map__delete(struct pyrf_cpu_map *pcpus) 385static 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
454static void pyrf_thread_map__delete(struct pyrf_thread_map *pthreads) 454static 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
1895out_delete_map: 1897out_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
5void update_stats(struct stats *stats, u64 val) 7void 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
98struct perf_counts *perf_counts__new(int ncpus) 100struct 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
106void perf_counts__delete(struct perf_counts *counts) 119void 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
111static void perf_counts__reset(struct perf_counts *counts, int ncpus) 127static 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
117void perf_evsel__reset_counts(struct perf_evsel *evsel, int ncpus) 132void 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
122int perf_evsel__alloc_counts(struct perf_evsel *evsel, int ncpus) 137int 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
149void 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
160int 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
169void perf_evsel__free_stat_priv(struct perf_evsel *evsel)
170{
171 zfree(&evsel->priv);
172}
173
174int 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
186void 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
192int 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
205int 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
216out_free:
217 perf_evlist__free_stats(evlist);
218 return -1;
219}
220
221void 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
232void 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
7struct stats 8struct 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
36struct perf_counts_values {
37 union {
38 struct {
39 u64 val;
40 u64 ena;
41 u64 run;
42 };
43 u64 values[3];
44 };
45};
46
47struct perf_counts {
48 s8 scaled;
49 struct perf_counts_values aggr;
50 struct xyarray *values;
51};
52
53static inline struct perf_counts_values*
54perf_counts(struct perf_counts *counts, int cpu, int thread)
55{
56 return xyarray__entry(counts->values, cpu, thread);
57}
58
34void update_stats(struct stats *stats, u64 val); 59void update_stats(struct stats *stats, u64 val);
35double avg_stats(struct stats *stats); 60double avg_stats(struct stats *stats);
36double stddev_stats(struct stats *stats); 61double stddev_stats(struct stats *stats);
@@ -46,6 +71,8 @@ static inline void init_stats(struct stats *stats)
46} 71}
47 72
48struct perf_evsel; 73struct perf_evsel;
74struct perf_evlist;
75
49bool __perf_evsel_stat__is(struct perf_evsel *evsel, 76bool __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,
62void perf_stat__print_shadow_stats(FILE *out, struct perf_evsel *evsel, 89void 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
65struct perf_counts *perf_counts__new(int ncpus); 92struct perf_counts *perf_counts__new(int ncpus, int nthreads);
66void perf_counts__delete(struct perf_counts *counts); 93void perf_counts__delete(struct perf_counts *counts);
67 94
68void perf_evsel__reset_counts(struct perf_evsel *evsel, int ncpus); 95void perf_evsel__reset_counts(struct perf_evsel *evsel);
69int perf_evsel__alloc_counts(struct perf_evsel *evsel, int ncpus); 96int perf_evsel__alloc_counts(struct perf_evsel *evsel, int ncpus, int nthreads);
70void perf_evsel__free_counts(struct perf_evsel *evsel); 97void perf_evsel__free_counts(struct perf_evsel *evsel);
98
99void perf_evsel__reset_stat_priv(struct perf_evsel *evsel);
100int perf_evsel__alloc_stat_priv(struct perf_evsel *evsel);
101void perf_evsel__free_stat_priv(struct perf_evsel *evsel);
102
103int perf_evsel__alloc_prev_raw_counts(struct perf_evsel *evsel,
104 int ncpus, int nthreads);
105void perf_evsel__free_prev_raw_counts(struct perf_evsel *evsel);
106
107int perf_evsel__alloc_stats(struct perf_evsel *evsel, bool alloc_raw);
108
109int perf_evlist__alloc_stats(struct perf_evlist *evlist, bool alloc_raw);
110void perf_evlist__free_stats(struct perf_evlist *evlist);
111void 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 */
15static int filter(const struct dirent *dir) 18static 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
26static 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
23static struct thread_map *thread_map__realloc(struct thread_map *map, int nr) 33static 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
211out: 234out:
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
215out_free_namelist: 240out_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 }
273out: 299out:
300 if (threads)
301 atomic_set(&threads->refcnt, 1);
274 return threads; 302 return threads;
275 303
276out_free_threads: 304out_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
293void thread_map__delete(struct thread_map *threads) 321static 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
334struct thread_map *thread_map__get(struct thread_map *map)
335{
336 if (map)
337 atomic_inc(&map->refcnt);
338 return map;
339}
340
341void 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
298size_t thread_map__fprintf(struct thread_map *threads, FILE *fp) 347size_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
358static 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
382static 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
403void 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
8struct thread_map_data {
9 pid_t pid;
10 char *comm;
11};
6 12
7struct thread_map { 13struct 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
12struct thread_map *thread_map__new_dummy(void); 19struct thread_map *thread_map__new_dummy(void);
@@ -15,11 +22,12 @@ struct thread_map *thread_map__new_by_tid(pid_t tid);
15struct thread_map *thread_map__new_by_uid(uid_t uid); 22struct thread_map *thread_map__new_by_uid(uid_t uid);
16struct thread_map *thread_map__new(pid_t pid, pid_t tid, uid_t uid); 23struct thread_map *thread_map__new(pid_t pid, pid_t tid, uid_t uid);
17 24
25struct thread_map *thread_map__get(struct thread_map *map);
26void thread_map__put(struct thread_map *map);
27
18struct thread_map *thread_map__new_str(const char *pid, 28struct 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
21void thread_map__delete(struct thread_map *threads);
22
23size_t thread_map__fprintf(struct thread_map *threads, FILE *fp); 31size_t thread_map__fprintf(struct thread_map *threads, FILE *fp);
24 32
25static inline int thread_map__nr(struct thread_map *threads) 33static 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
38static inline pid_t thread_map__pid(struct thread_map *map, int thread)
39{
40 return map->map[thread].pid;
41}
42
43static inline void
44thread_map__set_pid(struct thread_map *map, int thread, pid_t pid)
45{
46 map->map[thread].pid = pid;
47}
48
49static inline char *thread_map__comm(struct thread_map *map, int thread)
50{
51 return map->map[thread].comm;
52}
53
54void thread_map__read_comms(struct thread_map *threads);
30#endif /* __PERF_THREAD_MAP_H */ 55#endif /* __PERF_THREAD_MAP_H */