diff options
Diffstat (limited to 'tools/perf')
114 files changed, 3906 insertions, 1461 deletions
diff --git a/tools/perf/.gitignore b/tools/perf/.gitignore index 782d86e961b9..717221e98450 100644 --- a/tools/perf/.gitignore +++ b/tools/perf/.gitignore | |||
@@ -15,6 +15,7 @@ perf.data | |||
15 | perf.data.old | 15 | perf.data.old |
16 | output.svg | 16 | output.svg |
17 | perf-archive | 17 | perf-archive |
18 | perf-with-kcore | ||
18 | tags | 19 | tags |
19 | TAGS | 20 | TAGS |
20 | cscope* | 21 | cscope* |
diff --git a/tools/perf/Documentation/perf-probe.txt b/tools/perf/Documentation/perf-probe.txt index 1513935c399b..aaa869be3dc1 100644 --- a/tools/perf/Documentation/perf-probe.txt +++ b/tools/perf/Documentation/perf-probe.txt | |||
@@ -104,6 +104,9 @@ OPTIONS | |||
104 | Specify path to the executable or shared library file for user | 104 | Specify path to the executable or shared library file for user |
105 | space tracing. Can also be used with --funcs option. | 105 | space tracing. Can also be used with --funcs option. |
106 | 106 | ||
107 | --demangle-kernel:: | ||
108 | Demangle kernel symbols. | ||
109 | |||
107 | In absence of -m/-x options, perf probe checks if the first argument after | 110 | In absence of -m/-x options, perf probe checks if the first argument after |
108 | the options is an absolute path name. If its an absolute path, perf probe | 111 | the options is an absolute path name. If its an absolute path, perf probe |
109 | uses it as a target module/target user space binary to probe. | 112 | uses it as a target module/target user space binary to probe. |
diff --git a/tools/perf/Documentation/perf-report.txt b/tools/perf/Documentation/perf-report.txt index d2b59af62bc0..0927bf4e6c2a 100644 --- a/tools/perf/Documentation/perf-report.txt +++ b/tools/perf/Documentation/perf-report.txt | |||
@@ -147,7 +147,7 @@ OPTIONS | |||
147 | -w:: | 147 | -w:: |
148 | --column-widths=<width[,width...]>:: | 148 | --column-widths=<width[,width...]>:: |
149 | Force each column width to the provided list, for large terminal | 149 | Force each column width to the provided list, for large terminal |
150 | readability. | 150 | readability. 0 means no limit (default behavior). |
151 | 151 | ||
152 | -t:: | 152 | -t:: |
153 | --field-separator=:: | 153 | --field-separator=:: |
@@ -276,6 +276,9 @@ OPTIONS | |||
276 | Demangle symbol names to human readable form. It's enabled by default, | 276 | Demangle symbol names to human readable form. It's enabled by default, |
277 | disable with --no-demangle. | 277 | disable with --no-demangle. |
278 | 278 | ||
279 | --demangle-kernel:: | ||
280 | Demangle kernel symbol names to human readable form (for C++ kernels). | ||
281 | |||
279 | --mem-mode:: | 282 | --mem-mode:: |
280 | Use the data addresses of samples in addition to instruction addresses | 283 | Use the data addresses of samples in addition to instruction addresses |
281 | to build the histograms. To generate meaningful output, the perf.data | 284 | to build the histograms. To generate meaningful output, the perf.data |
diff --git a/tools/perf/Documentation/perf-top.txt b/tools/perf/Documentation/perf-top.txt index 180ae02137a5..3265b1070518 100644 --- a/tools/perf/Documentation/perf-top.txt +++ b/tools/perf/Documentation/perf-top.txt | |||
@@ -98,6 +98,9 @@ Default is to monitor all CPUS. | |||
98 | --hide_user_symbols:: | 98 | --hide_user_symbols:: |
99 | Hide user symbols. | 99 | Hide user symbols. |
100 | 100 | ||
101 | --demangle-kernel:: | ||
102 | Demangle kernel symbols. | ||
103 | |||
101 | -D:: | 104 | -D:: |
102 | --dump-symtab:: | 105 | --dump-symtab:: |
103 | Dump the symbol table used for profiling. | 106 | Dump the symbol table used for profiling. |
@@ -193,6 +196,12 @@ Default is to monitor all CPUS. | |||
193 | sum of shown entries will be always 100%. "absolute" means it retains | 196 | sum of shown entries will be always 100%. "absolute" means it retains |
194 | the original value before and after the filter is applied. | 197 | the original value before and after the filter is applied. |
195 | 198 | ||
199 | -w:: | ||
200 | --column-widths=<width[,width...]>:: | ||
201 | Force each column width to the provided list, for large terminal | ||
202 | readability. 0 means no limit (default behavior). | ||
203 | |||
204 | |||
196 | INTERACTIVE PROMPTING KEYS | 205 | INTERACTIVE PROMPTING KEYS |
197 | -------------------------- | 206 | -------------------------- |
198 | 207 | ||
diff --git a/tools/perf/Makefile.perf b/tools/perf/Makefile.perf index 2240974b7745..262916f4a377 100644 --- a/tools/perf/Makefile.perf +++ b/tools/perf/Makefile.perf | |||
@@ -126,6 +126,7 @@ PYRF_OBJS = | |||
126 | SCRIPT_SH = | 126 | SCRIPT_SH = |
127 | 127 | ||
128 | SCRIPT_SH += perf-archive.sh | 128 | SCRIPT_SH += perf-archive.sh |
129 | SCRIPT_SH += perf-with-kcore.sh | ||
129 | 130 | ||
130 | grep-libs = $(filter -l%,$(1)) | 131 | grep-libs = $(filter -l%,$(1)) |
131 | strip-libs = $(filter-out -l%,$(1)) | 132 | strip-libs = $(filter-out -l%,$(1)) |
@@ -263,6 +264,7 @@ LIB_H += util/xyarray.h | |||
263 | LIB_H += util/header.h | 264 | LIB_H += util/header.h |
264 | LIB_H += util/help.h | 265 | LIB_H += util/help.h |
265 | LIB_H += util/session.h | 266 | LIB_H += util/session.h |
267 | LIB_H += util/ordered-events.h | ||
266 | LIB_H += util/strbuf.h | 268 | LIB_H += util/strbuf.h |
267 | LIB_H += util/strlist.h | 269 | LIB_H += util/strlist.h |
268 | LIB_H += util/strfilter.h | 270 | LIB_H += util/strfilter.h |
@@ -347,6 +349,7 @@ LIB_OBJS += $(OUTPUT)util/machine.o | |||
347 | LIB_OBJS += $(OUTPUT)util/map.o | 349 | LIB_OBJS += $(OUTPUT)util/map.o |
348 | LIB_OBJS += $(OUTPUT)util/pstack.o | 350 | LIB_OBJS += $(OUTPUT)util/pstack.o |
349 | LIB_OBJS += $(OUTPUT)util/session.o | 351 | LIB_OBJS += $(OUTPUT)util/session.o |
352 | LIB_OBJS += $(OUTPUT)util/ordered-events.o | ||
350 | LIB_OBJS += $(OUTPUT)util/comm.o | 353 | LIB_OBJS += $(OUTPUT)util/comm.o |
351 | LIB_OBJS += $(OUTPUT)util/thread.o | 354 | LIB_OBJS += $(OUTPUT)util/thread.o |
352 | LIB_OBJS += $(OUTPUT)util/thread_map.o | 355 | LIB_OBJS += $(OUTPUT)util/thread_map.o |
@@ -399,6 +402,7 @@ LIB_OBJS += $(OUTPUT)tests/perf-record.o | |||
399 | LIB_OBJS += $(OUTPUT)tests/rdpmc.o | 402 | LIB_OBJS += $(OUTPUT)tests/rdpmc.o |
400 | LIB_OBJS += $(OUTPUT)tests/evsel-roundtrip-name.o | 403 | LIB_OBJS += $(OUTPUT)tests/evsel-roundtrip-name.o |
401 | LIB_OBJS += $(OUTPUT)tests/evsel-tp-sched.o | 404 | LIB_OBJS += $(OUTPUT)tests/evsel-tp-sched.o |
405 | LIB_OBJS += $(OUTPUT)tests/fdarray.o | ||
402 | LIB_OBJS += $(OUTPUT)tests/pmu.o | 406 | LIB_OBJS += $(OUTPUT)tests/pmu.o |
403 | LIB_OBJS += $(OUTPUT)tests/hists_common.o | 407 | LIB_OBJS += $(OUTPUT)tests/hists_common.o |
404 | LIB_OBJS += $(OUTPUT)tests/hists_link.o | 408 | LIB_OBJS += $(OUTPUT)tests/hists_link.o |
@@ -423,6 +427,7 @@ endif | |||
423 | endif | 427 | endif |
424 | LIB_OBJS += $(OUTPUT)tests/mmap-thread-lookup.o | 428 | LIB_OBJS += $(OUTPUT)tests/mmap-thread-lookup.o |
425 | LIB_OBJS += $(OUTPUT)tests/thread-mg-share.o | 429 | LIB_OBJS += $(OUTPUT)tests/thread-mg-share.o |
430 | LIB_OBJS += $(OUTPUT)tests/switch-tracking.o | ||
426 | 431 | ||
427 | BUILTIN_OBJS += $(OUTPUT)builtin-annotate.o | 432 | BUILTIN_OBJS += $(OUTPUT)builtin-annotate.o |
428 | BUILTIN_OBJS += $(OUTPUT)builtin-bench.o | 433 | BUILTIN_OBJS += $(OUTPUT)builtin-bench.o |
@@ -765,7 +770,7 @@ $(LIBTRACEEVENT)-clean: | |||
765 | install-traceevent-plugins: $(LIBTRACEEVENT) | 770 | install-traceevent-plugins: $(LIBTRACEEVENT) |
766 | $(QUIET_SUBDIR0)$(TRACE_EVENT_DIR) $(LIBTRACEEVENT_FLAGS) install_plugins | 771 | $(QUIET_SUBDIR0)$(TRACE_EVENT_DIR) $(LIBTRACEEVENT_FLAGS) install_plugins |
767 | 772 | ||
768 | LIBAPIKFS_SOURCES = $(wildcard $(LIB_PATH)fs/*.[ch]) | 773 | LIBAPIKFS_SOURCES = $(wildcard $(LIB_PATH)fs/*.[ch] $(LIB_PATH)fd/*.[ch]) |
769 | 774 | ||
770 | # if subdir is set, we've been called from above so target has been built | 775 | # if subdir is set, we've been called from above so target has been built |
771 | # already | 776 | # already |
@@ -875,6 +880,8 @@ install-bin: all install-gtk | |||
875 | $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)' | 880 | $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)' |
876 | $(call QUIET_INSTALL, perf-archive) \ | 881 | $(call QUIET_INSTALL, perf-archive) \ |
877 | $(INSTALL) $(OUTPUT)perf-archive -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)' | 882 | $(INSTALL) $(OUTPUT)perf-archive -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)' |
883 | $(call QUIET_INSTALL, perf-with-kcore) \ | ||
884 | $(INSTALL) $(OUTPUT)perf-with-kcore -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)' | ||
878 | ifndef NO_LIBPERL | 885 | ifndef NO_LIBPERL |
879 | $(call QUIET_INSTALL, perl-scripts) \ | 886 | $(call QUIET_INSTALL, perl-scripts) \ |
880 | $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/Perf-Trace-Util/lib/Perf/Trace'; \ | 887 | $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/Perf-Trace-Util/lib/Perf/Trace'; \ |
@@ -920,7 +927,7 @@ config-clean: | |||
920 | @$(MAKE) -C config/feature-checks clean >/dev/null | 927 | @$(MAKE) -C config/feature-checks clean >/dev/null |
921 | 928 | ||
922 | clean: $(LIBTRACEEVENT)-clean $(LIBAPIKFS)-clean config-clean | 929 | clean: $(LIBTRACEEVENT)-clean $(LIBAPIKFS)-clean config-clean |
923 | $(call QUIET_CLEAN, core-objs) $(RM) $(LIB_OBJS) $(BUILTIN_OBJS) $(LIB_FILE) $(OUTPUT)perf-archive $(OUTPUT)perf.o $(LANG_BINDINGS) $(GTK_OBJS) | 930 | $(call QUIET_CLEAN, core-objs) $(RM) $(LIB_OBJS) $(BUILTIN_OBJS) $(LIB_FILE) $(OUTPUT)perf-archive $(OUTPUT)perf-with-kcore $(OUTPUT)perf.o $(LANG_BINDINGS) $(GTK_OBJS) |
924 | $(call QUIET_CLEAN, core-progs) $(RM) $(ALL_PROGRAMS) perf | 931 | $(call QUIET_CLEAN, core-progs) $(RM) $(ALL_PROGRAMS) perf |
925 | $(call QUIET_CLEAN, core-gen) $(RM) *.spec *.pyc *.pyo */*.pyc */*.pyo $(OUTPUT)common-cmds.h TAGS tags cscope* $(OUTPUT)PERF-VERSION-FILE $(OUTPUT)PERF-CFLAGS $(OUTPUT)PERF-FEATURES $(OUTPUT)util/*-bison* $(OUTPUT)util/*-flex* | 932 | $(call QUIET_CLEAN, core-gen) $(RM) *.spec *.pyc *.pyo */*.pyc */*.pyo $(OUTPUT)common-cmds.h TAGS tags cscope* $(OUTPUT)PERF-VERSION-FILE $(OUTPUT)PERF-CFLAGS $(OUTPUT)PERF-FEATURES $(OUTPUT)util/*-bison* $(OUTPUT)util/*-flex* |
926 | $(QUIET_SUBDIR0)Documentation $(QUIET_SUBDIR1) clean | 933 | $(QUIET_SUBDIR0)Documentation $(QUIET_SUBDIR1) clean |
diff --git a/tools/perf/arch/arm/tests/dwarf-unwind.c b/tools/perf/arch/arm/tests/dwarf-unwind.c index 9f870d27cb39..62eff847f91c 100644 --- a/tools/perf/arch/arm/tests/dwarf-unwind.c +++ b/tools/perf/arch/arm/tests/dwarf-unwind.c | |||
@@ -3,6 +3,7 @@ | |||
3 | #include "thread.h" | 3 | #include "thread.h" |
4 | #include "map.h" | 4 | #include "map.h" |
5 | #include "event.h" | 5 | #include "event.h" |
6 | #include "debug.h" | ||
6 | #include "tests/tests.h" | 7 | #include "tests/tests.h" |
7 | 8 | ||
8 | #define STACK_SIZE 8192 | 9 | #define STACK_SIZE 8192 |
diff --git a/tools/perf/arch/arm/util/unwind-libunwind.c b/tools/perf/arch/arm/util/unwind-libunwind.c index 729ed69a6664..62c397ed3d97 100644 --- a/tools/perf/arch/arm/util/unwind-libunwind.c +++ b/tools/perf/arch/arm/util/unwind-libunwind.c | |||
@@ -3,6 +3,7 @@ | |||
3 | #include <libunwind.h> | 3 | #include <libunwind.h> |
4 | #include "perf_regs.h" | 4 | #include "perf_regs.h" |
5 | #include "../../util/unwind.h" | 5 | #include "../../util/unwind.h" |
6 | #include "../../util/debug.h" | ||
6 | 7 | ||
7 | int libunwind__arch_reg_id(int regnum) | 8 | int libunwind__arch_reg_id(int regnum) |
8 | { | 9 | { |
diff --git a/tools/perf/arch/arm64/include/perf_regs.h b/tools/perf/arch/arm64/include/perf_regs.h index e9441b9e2a30..1d3f39c3aa56 100644 --- a/tools/perf/arch/arm64/include/perf_regs.h +++ b/tools/perf/arch/arm64/include/perf_regs.h | |||
@@ -6,6 +6,8 @@ | |||
6 | #include <asm/perf_regs.h> | 6 | #include <asm/perf_regs.h> |
7 | 7 | ||
8 | #define PERF_REGS_MASK ((1ULL << PERF_REG_ARM64_MAX) - 1) | 8 | #define PERF_REGS_MASK ((1ULL << PERF_REG_ARM64_MAX) - 1) |
9 | #define PERF_REGS_MAX PERF_REG_ARM64_MAX | ||
10 | |||
9 | #define PERF_REG_IP PERF_REG_ARM64_PC | 11 | #define PERF_REG_IP PERF_REG_ARM64_PC |
10 | #define PERF_REG_SP PERF_REG_ARM64_SP | 12 | #define PERF_REG_SP PERF_REG_ARM64_SP |
11 | 13 | ||
diff --git a/tools/perf/arch/arm64/util/unwind-libunwind.c b/tools/perf/arch/arm64/util/unwind-libunwind.c index 436ee43859dc..a87afa91a99e 100644 --- a/tools/perf/arch/arm64/util/unwind-libunwind.c +++ b/tools/perf/arch/arm64/util/unwind-libunwind.c | |||
@@ -3,6 +3,7 @@ | |||
3 | #include <libunwind.h> | 3 | #include <libunwind.h> |
4 | #include "perf_regs.h" | 4 | #include "perf_regs.h" |
5 | #include "../../util/unwind.h" | 5 | #include "../../util/unwind.h" |
6 | #include "../../util/debug.h" | ||
6 | 7 | ||
7 | int libunwind__arch_reg_id(int regnum) | 8 | int libunwind__arch_reg_id(int regnum) |
8 | { | 9 | { |
diff --git a/tools/perf/arch/common.c b/tools/perf/arch/common.c index 42faf369211c..49776f190abf 100644 --- a/tools/perf/arch/common.c +++ b/tools/perf/arch/common.c | |||
@@ -12,6 +12,11 @@ const char *const arm_triplets[] = { | |||
12 | NULL | 12 | NULL |
13 | }; | 13 | }; |
14 | 14 | ||
15 | const char *const arm64_triplets[] = { | ||
16 | "aarch64-linux-android-", | ||
17 | NULL | ||
18 | }; | ||
19 | |||
15 | const char *const powerpc_triplets[] = { | 20 | const char *const powerpc_triplets[] = { |
16 | "powerpc-unknown-linux-gnu-", | 21 | "powerpc-unknown-linux-gnu-", |
17 | "powerpc64-unknown-linux-gnu-", | 22 | "powerpc64-unknown-linux-gnu-", |
@@ -105,6 +110,8 @@ static const char *normalize_arch(char *arch) | |||
105 | return "x86"; | 110 | return "x86"; |
106 | if (!strcmp(arch, "sun4u") || !strncmp(arch, "sparc", 5)) | 111 | if (!strcmp(arch, "sun4u") || !strncmp(arch, "sparc", 5)) |
107 | return "sparc"; | 112 | return "sparc"; |
113 | if (!strcmp(arch, "aarch64") || !strcmp(arch, "arm64")) | ||
114 | return "arm64"; | ||
108 | if (!strncmp(arch, "arm", 3) || !strcmp(arch, "sa110")) | 115 | if (!strncmp(arch, "arm", 3) || !strcmp(arch, "sa110")) |
109 | return "arm"; | 116 | return "arm"; |
110 | if (!strncmp(arch, "s390", 4)) | 117 | if (!strncmp(arch, "s390", 4)) |
@@ -159,6 +166,8 @@ static int perf_session_env__lookup_binutils_path(struct perf_session_env *env, | |||
159 | 166 | ||
160 | if (!strcmp(arch, "arm")) | 167 | if (!strcmp(arch, "arm")) |
161 | path_list = arm_triplets; | 168 | path_list = arm_triplets; |
169 | else if (!strcmp(arch, "arm64")) | ||
170 | path_list = arm64_triplets; | ||
162 | else if (!strcmp(arch, "powerpc")) | 171 | else if (!strcmp(arch, "powerpc")) |
163 | path_list = powerpc_triplets; | 172 | path_list = powerpc_triplets; |
164 | else if (!strcmp(arch, "sh")) | 173 | else if (!strcmp(arch, "sh")) |
diff --git a/tools/perf/arch/powerpc/Makefile b/tools/perf/arch/powerpc/Makefile index b92219b1900d..6f7782bea5dd 100644 --- a/tools/perf/arch/powerpc/Makefile +++ b/tools/perf/arch/powerpc/Makefile | |||
@@ -1,6 +1,6 @@ | |||
1 | ifndef NO_DWARF | 1 | ifndef NO_DWARF |
2 | PERF_HAVE_DWARF_REGS := 1 | 2 | PERF_HAVE_DWARF_REGS := 1 |
3 | LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/dwarf-regs.o | 3 | LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/dwarf-regs.o |
4 | LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/skip-callchain-idx.o | ||
4 | endif | 5 | endif |
5 | LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/header.o | 6 | LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/header.o |
6 | LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/skip-callchain-idx.o | ||
diff --git a/tools/perf/arch/powerpc/util/skip-callchain-idx.c b/tools/perf/arch/powerpc/util/skip-callchain-idx.c index a7c23a4b3778..d73ef8bb08c7 100644 --- a/tools/perf/arch/powerpc/util/skip-callchain-idx.c +++ b/tools/perf/arch/powerpc/util/skip-callchain-idx.c | |||
@@ -15,6 +15,7 @@ | |||
15 | 15 | ||
16 | #include "util/thread.h" | 16 | #include "util/thread.h" |
17 | #include "util/callchain.h" | 17 | #include "util/callchain.h" |
18 | #include "util/debug.h" | ||
18 | 19 | ||
19 | /* | 20 | /* |
20 | * When saving the callchain on Power, the kernel conservatively saves | 21 | * When saving the callchain on Power, the kernel conservatively saves |
diff --git a/tools/perf/bench/futex-hash.c b/tools/perf/bench/futex-hash.c index a84206e9c4aa..fc9bebd2cca0 100644 --- a/tools/perf/bench/futex-hash.c +++ b/tools/perf/bench/futex-hash.c | |||
@@ -26,6 +26,7 @@ static unsigned int nsecs = 10; | |||
26 | /* amount of futexes per thread */ | 26 | /* amount of futexes per thread */ |
27 | static unsigned int nfutexes = 1024; | 27 | static unsigned int nfutexes = 1024; |
28 | static bool fshared = false, done = false, silent = false; | 28 | static bool fshared = false, done = false, silent = false; |
29 | static int futex_flag = 0; | ||
29 | 30 | ||
30 | struct timeval start, end, runtime; | 31 | struct timeval start, end, runtime; |
31 | static pthread_mutex_t thread_lock; | 32 | static pthread_mutex_t thread_lock; |
@@ -75,8 +76,7 @@ static void *workerfn(void *arg) | |||
75 | * such as internal waitqueue handling, thus enlarging | 76 | * such as internal waitqueue handling, thus enlarging |
76 | * the critical region protected by hb->lock. | 77 | * the critical region protected by hb->lock. |
77 | */ | 78 | */ |
78 | ret = futex_wait(&w->futex[i], 1234, NULL, | 79 | ret = futex_wait(&w->futex[i], 1234, NULL, futex_flag); |
79 | fshared ? 0 : FUTEX_PRIVATE_FLAG); | ||
80 | if (!silent && | 80 | if (!silent && |
81 | (!ret || errno != EAGAIN || errno != EWOULDBLOCK)) | 81 | (!ret || errno != EAGAIN || errno != EWOULDBLOCK)) |
82 | warn("Non-expected futex return call"); | 82 | warn("Non-expected futex return call"); |
@@ -135,6 +135,9 @@ int bench_futex_hash(int argc, const char **argv, | |||
135 | if (!worker) | 135 | if (!worker) |
136 | goto errmem; | 136 | goto errmem; |
137 | 137 | ||
138 | if (!fshared) | ||
139 | futex_flag = FUTEX_PRIVATE_FLAG; | ||
140 | |||
138 | printf("Run summary [PID %d]: %d threads, each operating on %d [%s] futexes for %d secs.\n\n", | 141 | printf("Run summary [PID %d]: %d threads, each operating on %d [%s] futexes for %d secs.\n\n", |
139 | getpid(), nthreads, nfutexes, fshared ? "shared":"private", nsecs); | 142 | getpid(), nthreads, nfutexes, fshared ? "shared":"private", nsecs); |
140 | 143 | ||
diff --git a/tools/perf/bench/futex-requeue.c b/tools/perf/bench/futex-requeue.c index 732403bfd31a..bedff6b5b3cf 100644 --- a/tools/perf/bench/futex-requeue.c +++ b/tools/perf/bench/futex-requeue.c | |||
@@ -30,16 +30,18 @@ static u_int32_t futex1 = 0, futex2 = 0; | |||
30 | static unsigned int nrequeue = 1; | 30 | static unsigned int nrequeue = 1; |
31 | 31 | ||
32 | static pthread_t *worker; | 32 | static pthread_t *worker; |
33 | static bool done = 0, silent = 0; | 33 | static bool done = false, silent = false, fshared = false; |
34 | static pthread_mutex_t thread_lock; | 34 | static pthread_mutex_t thread_lock; |
35 | static pthread_cond_t thread_parent, thread_worker; | 35 | static pthread_cond_t thread_parent, thread_worker; |
36 | static struct stats requeuetime_stats, requeued_stats; | 36 | static struct stats requeuetime_stats, requeued_stats; |
37 | static unsigned int ncpus, threads_starting, nthreads = 0; | 37 | static unsigned int ncpus, threads_starting, nthreads = 0; |
38 | static int futex_flag = 0; | ||
38 | 39 | ||
39 | static const struct option options[] = { | 40 | static const struct option options[] = { |
40 | OPT_UINTEGER('t', "threads", &nthreads, "Specify amount of threads"), | 41 | OPT_UINTEGER('t', "threads", &nthreads, "Specify amount of threads"), |
41 | OPT_UINTEGER('q', "nrequeue", &nrequeue, "Specify amount of threads to requeue at once"), | 42 | OPT_UINTEGER('q', "nrequeue", &nrequeue, "Specify amount of threads to requeue at once"), |
42 | OPT_BOOLEAN( 's', "silent", &silent, "Silent mode: do not display data/details"), | 43 | OPT_BOOLEAN( 's', "silent", &silent, "Silent mode: do not display data/details"), |
44 | OPT_BOOLEAN( 'S', "shared", &fshared, "Use shared futexes instead of private ones"), | ||
43 | OPT_END() | 45 | OPT_END() |
44 | }; | 46 | }; |
45 | 47 | ||
@@ -70,7 +72,7 @@ static void *workerfn(void *arg __maybe_unused) | |||
70 | pthread_cond_wait(&thread_worker, &thread_lock); | 72 | pthread_cond_wait(&thread_worker, &thread_lock); |
71 | pthread_mutex_unlock(&thread_lock); | 73 | pthread_mutex_unlock(&thread_lock); |
72 | 74 | ||
73 | futex_wait(&futex1, 0, NULL, FUTEX_PRIVATE_FLAG); | 75 | futex_wait(&futex1, 0, NULL, futex_flag); |
74 | return NULL; | 76 | return NULL; |
75 | } | 77 | } |
76 | 78 | ||
@@ -127,9 +129,12 @@ int bench_futex_requeue(int argc, const char **argv, | |||
127 | if (!worker) | 129 | if (!worker) |
128 | err(EXIT_FAILURE, "calloc"); | 130 | err(EXIT_FAILURE, "calloc"); |
129 | 131 | ||
130 | printf("Run summary [PID %d]: Requeuing %d threads (from %p to %p), " | 132 | if (!fshared) |
131 | "%d at a time.\n\n", | 133 | futex_flag = FUTEX_PRIVATE_FLAG; |
132 | getpid(), nthreads, &futex1, &futex2, nrequeue); | 134 | |
135 | printf("Run summary [PID %d]: Requeuing %d threads (from [%s] %p to %p), " | ||
136 | "%d at a time.\n\n", getpid(), nthreads, | ||
137 | fshared ? "shared":"private", &futex1, &futex2, nrequeue); | ||
133 | 138 | ||
134 | init_stats(&requeued_stats); | 139 | init_stats(&requeued_stats); |
135 | init_stats(&requeuetime_stats); | 140 | init_stats(&requeuetime_stats); |
@@ -156,16 +161,20 @@ int bench_futex_requeue(int argc, const char **argv, | |||
156 | 161 | ||
157 | /* Ok, all threads are patiently blocked, start requeueing */ | 162 | /* Ok, all threads are patiently blocked, start requeueing */ |
158 | gettimeofday(&start, NULL); | 163 | gettimeofday(&start, NULL); |
159 | for (nrequeued = 0; nrequeued < nthreads; nrequeued += nrequeue) | 164 | for (nrequeued = 0; nrequeued < nthreads; nrequeued += nrequeue) { |
160 | /* | 165 | /* |
161 | * Do not wakeup any tasks blocked on futex1, allowing | 166 | * Do not wakeup any tasks blocked on futex1, allowing |
162 | * us to really measure futex_wait functionality. | 167 | * us to really measure futex_wait functionality. |
163 | */ | 168 | */ |
164 | futex_cmp_requeue(&futex1, 0, &futex2, 0, nrequeue, | 169 | futex_cmp_requeue(&futex1, 0, &futex2, 0, |
165 | FUTEX_PRIVATE_FLAG); | 170 | nrequeue, futex_flag); |
171 | } | ||
166 | gettimeofday(&end, NULL); | 172 | gettimeofday(&end, NULL); |
167 | timersub(&end, &start, &runtime); | 173 | timersub(&end, &start, &runtime); |
168 | 174 | ||
175 | if (nrequeued > nthreads) | ||
176 | nrequeued = nthreads; | ||
177 | |||
169 | update_stats(&requeued_stats, nrequeued); | 178 | update_stats(&requeued_stats, nrequeued); |
170 | update_stats(&requeuetime_stats, runtime.tv_usec); | 179 | update_stats(&requeuetime_stats, runtime.tv_usec); |
171 | 180 | ||
@@ -175,7 +184,7 @@ int bench_futex_requeue(int argc, const char **argv, | |||
175 | } | 184 | } |
176 | 185 | ||
177 | /* everybody should be blocked on futex2, wake'em up */ | 186 | /* everybody should be blocked on futex2, wake'em up */ |
178 | nrequeued = futex_wake(&futex2, nthreads, FUTEX_PRIVATE_FLAG); | 187 | nrequeued = futex_wake(&futex2, nthreads, futex_flag); |
179 | if (nthreads != nrequeued) | 188 | if (nthreads != nrequeued) |
180 | warnx("couldn't wakeup all tasks (%d/%d)", nrequeued, nthreads); | 189 | warnx("couldn't wakeup all tasks (%d/%d)", nrequeued, nthreads); |
181 | 190 | ||
@@ -184,7 +193,6 @@ int bench_futex_requeue(int argc, const char **argv, | |||
184 | if (ret) | 193 | if (ret) |
185 | err(EXIT_FAILURE, "pthread_join"); | 194 | err(EXIT_FAILURE, "pthread_join"); |
186 | } | 195 | } |
187 | |||
188 | } | 196 | } |
189 | 197 | ||
190 | /* cleanup & report results */ | 198 | /* cleanup & report results */ |
diff --git a/tools/perf/bench/futex-wake.c b/tools/perf/bench/futex-wake.c index 50022cbce87e..929f762be47e 100644 --- a/tools/perf/bench/futex-wake.c +++ b/tools/perf/bench/futex-wake.c | |||
@@ -31,16 +31,18 @@ static u_int32_t futex1 = 0; | |||
31 | static unsigned int nwakes = 1; | 31 | static unsigned int nwakes = 1; |
32 | 32 | ||
33 | pthread_t *worker; | 33 | pthread_t *worker; |
34 | static bool done = false, silent = false; | 34 | static bool done = false, silent = false, fshared = false; |
35 | static pthread_mutex_t thread_lock; | 35 | static pthread_mutex_t thread_lock; |
36 | static pthread_cond_t thread_parent, thread_worker; | 36 | static pthread_cond_t thread_parent, thread_worker; |
37 | static struct stats waketime_stats, wakeup_stats; | 37 | static struct stats waketime_stats, wakeup_stats; |
38 | static unsigned int ncpus, threads_starting, nthreads = 0; | 38 | static unsigned int ncpus, threads_starting, nthreads = 0; |
39 | static int futex_flag = 0; | ||
39 | 40 | ||
40 | static const struct option options[] = { | 41 | static const struct option options[] = { |
41 | OPT_UINTEGER('t', "threads", &nthreads, "Specify amount of threads"), | 42 | OPT_UINTEGER('t', "threads", &nthreads, "Specify amount of threads"), |
42 | OPT_UINTEGER('w', "nwakes", &nwakes, "Specify amount of threads to wake at once"), | 43 | OPT_UINTEGER('w', "nwakes", &nwakes, "Specify amount of threads to wake at once"), |
43 | OPT_BOOLEAN( 's', "silent", &silent, "Silent mode: do not display data/details"), | 44 | OPT_BOOLEAN( 's', "silent", &silent, "Silent mode: do not display data/details"), |
45 | OPT_BOOLEAN( 'S', "shared", &fshared, "Use shared futexes instead of private ones"), | ||
44 | OPT_END() | 46 | OPT_END() |
45 | }; | 47 | }; |
46 | 48 | ||
@@ -58,7 +60,7 @@ static void *workerfn(void *arg __maybe_unused) | |||
58 | pthread_cond_wait(&thread_worker, &thread_lock); | 60 | pthread_cond_wait(&thread_worker, &thread_lock); |
59 | pthread_mutex_unlock(&thread_lock); | 61 | pthread_mutex_unlock(&thread_lock); |
60 | 62 | ||
61 | futex_wait(&futex1, 0, NULL, FUTEX_PRIVATE_FLAG); | 63 | futex_wait(&futex1, 0, NULL, futex_flag); |
62 | return NULL; | 64 | return NULL; |
63 | } | 65 | } |
64 | 66 | ||
@@ -130,9 +132,12 @@ int bench_futex_wake(int argc, const char **argv, | |||
130 | if (!worker) | 132 | if (!worker) |
131 | err(EXIT_FAILURE, "calloc"); | 133 | err(EXIT_FAILURE, "calloc"); |
132 | 134 | ||
133 | printf("Run summary [PID %d]: blocking on %d threads (at futex %p), " | 135 | if (!fshared) |
136 | futex_flag = FUTEX_PRIVATE_FLAG; | ||
137 | |||
138 | printf("Run summary [PID %d]: blocking on %d threads (at [%s] futex %p), " | ||
134 | "waking up %d at a time.\n\n", | 139 | "waking up %d at a time.\n\n", |
135 | getpid(), nthreads, &futex1, nwakes); | 140 | getpid(), nthreads, fshared ? "shared":"private", &futex1, nwakes); |
136 | 141 | ||
137 | init_stats(&wakeup_stats); | 142 | init_stats(&wakeup_stats); |
138 | init_stats(&waketime_stats); | 143 | init_stats(&waketime_stats); |
@@ -160,7 +165,7 @@ int bench_futex_wake(int argc, const char **argv, | |||
160 | /* Ok, all threads are patiently blocked, start waking folks up */ | 165 | /* Ok, all threads are patiently blocked, start waking folks up */ |
161 | gettimeofday(&start, NULL); | 166 | gettimeofday(&start, NULL); |
162 | while (nwoken != nthreads) | 167 | while (nwoken != nthreads) |
163 | nwoken += futex_wake(&futex1, nwakes, FUTEX_PRIVATE_FLAG); | 168 | nwoken += futex_wake(&futex1, nwakes, futex_flag); |
164 | gettimeofday(&end, NULL); | 169 | gettimeofday(&end, NULL); |
165 | timersub(&end, &start, &runtime); | 170 | timersub(&end, &start, &runtime); |
166 | 171 | ||
diff --git a/tools/perf/bench/sched-messaging.c b/tools/perf/bench/sched-messaging.c index 52a56599a543..d7f281c2828d 100644 --- a/tools/perf/bench/sched-messaging.c +++ b/tools/perf/bench/sched-messaging.c | |||
@@ -26,7 +26,7 @@ | |||
26 | #include <sys/socket.h> | 26 | #include <sys/socket.h> |
27 | #include <sys/wait.h> | 27 | #include <sys/wait.h> |
28 | #include <sys/time.h> | 28 | #include <sys/time.h> |
29 | #include <sys/poll.h> | 29 | #include <poll.h> |
30 | #include <limits.h> | 30 | #include <limits.h> |
31 | #include <err.h> | 31 | #include <err.h> |
32 | 32 | ||
diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c index 1ec429fef2be..be5939418425 100644 --- a/tools/perf/builtin-annotate.c +++ b/tools/perf/builtin-annotate.c | |||
@@ -36,7 +36,8 @@ | |||
36 | 36 | ||
37 | struct perf_annotate { | 37 | struct perf_annotate { |
38 | struct perf_tool tool; | 38 | struct perf_tool tool; |
39 | bool force, use_tui, use_stdio, use_gtk; | 39 | struct perf_session *session; |
40 | bool use_tui, use_stdio, use_gtk; | ||
40 | bool full_paths; | 41 | bool full_paths; |
41 | bool print_line; | 42 | bool print_line; |
42 | bool skip_missing; | 43 | bool skip_missing; |
@@ -188,18 +189,9 @@ find_next: | |||
188 | static int __cmd_annotate(struct perf_annotate *ann) | 189 | static int __cmd_annotate(struct perf_annotate *ann) |
189 | { | 190 | { |
190 | int ret; | 191 | int ret; |
191 | struct perf_session *session; | 192 | struct perf_session *session = ann->session; |
192 | struct perf_evsel *pos; | 193 | struct perf_evsel *pos; |
193 | u64 total_nr_samples; | 194 | u64 total_nr_samples; |
194 | struct perf_data_file file = { | ||
195 | .path = input_name, | ||
196 | .mode = PERF_DATA_MODE_READ, | ||
197 | .force = ann->force, | ||
198 | }; | ||
199 | |||
200 | session = perf_session__new(&file, false, &ann->tool); | ||
201 | if (session == NULL) | ||
202 | return -ENOMEM; | ||
203 | 195 | ||
204 | machines__set_symbol_filter(&session->machines, symbol__annotate_init); | 196 | machines__set_symbol_filter(&session->machines, symbol__annotate_init); |
205 | 197 | ||
@@ -207,22 +199,22 @@ static int __cmd_annotate(struct perf_annotate *ann) | |||
207 | ret = perf_session__cpu_bitmap(session, ann->cpu_list, | 199 | ret = perf_session__cpu_bitmap(session, ann->cpu_list, |
208 | ann->cpu_bitmap); | 200 | ann->cpu_bitmap); |
209 | if (ret) | 201 | if (ret) |
210 | goto out_delete; | 202 | goto out; |
211 | } | 203 | } |
212 | 204 | ||
213 | if (!objdump_path) { | 205 | if (!objdump_path) { |
214 | ret = perf_session_env__lookup_objdump(&session->header.env); | 206 | ret = perf_session_env__lookup_objdump(&session->header.env); |
215 | if (ret) | 207 | if (ret) |
216 | goto out_delete; | 208 | goto out; |
217 | } | 209 | } |
218 | 210 | ||
219 | ret = perf_session__process_events(session, &ann->tool); | 211 | ret = perf_session__process_events(session, &ann->tool); |
220 | if (ret) | 212 | if (ret) |
221 | goto out_delete; | 213 | goto out; |
222 | 214 | ||
223 | if (dump_trace) { | 215 | if (dump_trace) { |
224 | perf_session__fprintf_nr_events(session, stdout); | 216 | perf_session__fprintf_nr_events(session, stdout); |
225 | goto out_delete; | 217 | goto out; |
226 | } | 218 | } |
227 | 219 | ||
228 | if (verbose > 3) | 220 | if (verbose > 3) |
@@ -250,8 +242,8 @@ static int __cmd_annotate(struct perf_annotate *ann) | |||
250 | } | 242 | } |
251 | 243 | ||
252 | if (total_nr_samples == 0) { | 244 | if (total_nr_samples == 0) { |
253 | ui__error("The %s file has no samples!\n", file.path); | 245 | ui__error("The %s file has no samples!\n", session->file->path); |
254 | goto out_delete; | 246 | goto out; |
255 | } | 247 | } |
256 | 248 | ||
257 | if (use_browser == 2) { | 249 | if (use_browser == 2) { |
@@ -261,24 +253,12 @@ static int __cmd_annotate(struct perf_annotate *ann) | |||
261 | "perf_gtk__show_annotations"); | 253 | "perf_gtk__show_annotations"); |
262 | if (show_annotations == NULL) { | 254 | if (show_annotations == NULL) { |
263 | ui__error("GTK browser not found!\n"); | 255 | ui__error("GTK browser not found!\n"); |
264 | goto out_delete; | 256 | goto out; |
265 | } | 257 | } |
266 | show_annotations(); | 258 | show_annotations(); |
267 | } | 259 | } |
268 | 260 | ||
269 | out_delete: | 261 | out: |
270 | /* | ||
271 | * Speed up the exit process, for large files this can | ||
272 | * take quite a while. | ||
273 | * | ||
274 | * XXX Enable this when using valgrind or if we ever | ||
275 | * librarize this command. | ||
276 | * | ||
277 | * Also experiment with obstacks to see how much speed | ||
278 | * up we'll get here. | ||
279 | * | ||
280 | * perf_session__delete(session); | ||
281 | */ | ||
282 | return ret; | 262 | return ret; |
283 | } | 263 | } |
284 | 264 | ||
@@ -297,10 +277,14 @@ int cmd_annotate(int argc, const char **argv, const char *prefix __maybe_unused) | |||
297 | .comm = perf_event__process_comm, | 277 | .comm = perf_event__process_comm, |
298 | .exit = perf_event__process_exit, | 278 | .exit = perf_event__process_exit, |
299 | .fork = perf_event__process_fork, | 279 | .fork = perf_event__process_fork, |
300 | .ordered_samples = true, | 280 | .ordered_events = true, |
301 | .ordering_requires_timestamps = true, | 281 | .ordering_requires_timestamps = true, |
302 | }, | 282 | }, |
303 | }; | 283 | }; |
284 | struct perf_data_file file = { | ||
285 | .path = input_name, | ||
286 | .mode = PERF_DATA_MODE_READ, | ||
287 | }; | ||
304 | const struct option options[] = { | 288 | const struct option options[] = { |
305 | OPT_STRING('i', "input", &input_name, "file", | 289 | OPT_STRING('i', "input", &input_name, "file", |
306 | "input file name"), | 290 | "input file name"), |
@@ -308,7 +292,7 @@ int cmd_annotate(int argc, const char **argv, const char *prefix __maybe_unused) | |||
308 | "only consider symbols in these dsos"), | 292 | "only consider symbols in these dsos"), |
309 | OPT_STRING('s', "symbol", &annotate.sym_hist_filter, "symbol", | 293 | OPT_STRING('s', "symbol", &annotate.sym_hist_filter, "symbol", |
310 | "symbol to annotate"), | 294 | "symbol to annotate"), |
311 | OPT_BOOLEAN('f', "force", &annotate.force, "don't complain, do it"), | 295 | OPT_BOOLEAN('f', "force", &file.force, "don't complain, do it"), |
312 | OPT_INCR('v', "verbose", &verbose, | 296 | OPT_INCR('v', "verbose", &verbose, |
313 | "be more verbose (show symbol address, etc)"), | 297 | "be more verbose (show symbol address, etc)"), |
314 | OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace, | 298 | OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace, |
@@ -341,6 +325,7 @@ int cmd_annotate(int argc, const char **argv, const char *prefix __maybe_unused) | |||
341 | "Show event group information together"), | 325 | "Show event group information together"), |
342 | OPT_END() | 326 | OPT_END() |
343 | }; | 327 | }; |
328 | int ret; | ||
344 | 329 | ||
345 | argc = parse_options(argc, argv, options, annotate_usage, 0); | 330 | argc = parse_options(argc, argv, options, annotate_usage, 0); |
346 | 331 | ||
@@ -353,11 +338,16 @@ int cmd_annotate(int argc, const char **argv, const char *prefix __maybe_unused) | |||
353 | 338 | ||
354 | setup_browser(true); | 339 | setup_browser(true); |
355 | 340 | ||
341 | annotate.session = perf_session__new(&file, false, &annotate.tool); | ||
342 | if (annotate.session == NULL) | ||
343 | return -1; | ||
344 | |||
356 | symbol_conf.priv_size = sizeof(struct annotation); | 345 | symbol_conf.priv_size = sizeof(struct annotation); |
357 | symbol_conf.try_vmlinux_path = true; | 346 | symbol_conf.try_vmlinux_path = true; |
358 | 347 | ||
359 | if (symbol__init() < 0) | 348 | ret = symbol__init(&annotate.session->header.env); |
360 | return -1; | 349 | if (ret < 0) |
350 | goto out_delete; | ||
361 | 351 | ||
362 | if (setup_sorting() < 0) | 352 | if (setup_sorting() < 0) |
363 | usage_with_options(annotate_usage, options); | 353 | usage_with_options(annotate_usage, options); |
@@ -373,5 +363,20 @@ int cmd_annotate(int argc, const char **argv, const char *prefix __maybe_unused) | |||
373 | annotate.sym_hist_filter = argv[0]; | 363 | annotate.sym_hist_filter = argv[0]; |
374 | } | 364 | } |
375 | 365 | ||
376 | return __cmd_annotate(&annotate); | 366 | ret = __cmd_annotate(&annotate); |
367 | |||
368 | out_delete: | ||
369 | /* | ||
370 | * Speed up the exit process, for large files this can | ||
371 | * take quite a while. | ||
372 | * | ||
373 | * XXX Enable this when using valgrind or if we ever | ||
374 | * librarize this command. | ||
375 | * | ||
376 | * Also experiment with obstacks to see how much speed | ||
377 | * up we'll get here. | ||
378 | * | ||
379 | * perf_session__delete(session); | ||
380 | */ | ||
381 | return ret; | ||
377 | } | 382 | } |
diff --git a/tools/perf/builtin-buildid-cache.c b/tools/perf/builtin-buildid-cache.c index 2a2c78f80876..70385756da63 100644 --- a/tools/perf/builtin-buildid-cache.c +++ b/tools/perf/builtin-buildid-cache.c | |||
@@ -246,20 +246,9 @@ static bool dso__missing_buildid_cache(struct dso *dso, int parm __maybe_unused) | |||
246 | return true; | 246 | return true; |
247 | } | 247 | } |
248 | 248 | ||
249 | static int build_id_cache__fprintf_missing(const char *filename, bool force, FILE *fp) | 249 | static int build_id_cache__fprintf_missing(struct perf_session *session, FILE *fp) |
250 | { | 250 | { |
251 | struct perf_data_file file = { | ||
252 | .path = filename, | ||
253 | .mode = PERF_DATA_MODE_READ, | ||
254 | .force = force, | ||
255 | }; | ||
256 | struct perf_session *session = perf_session__new(&file, false, NULL); | ||
257 | if (session == NULL) | ||
258 | return -1; | ||
259 | |||
260 | perf_session__fprintf_dsos_buildid(session, fp, dso__missing_buildid_cache, 0); | 251 | perf_session__fprintf_dsos_buildid(session, fp, dso__missing_buildid_cache, 0); |
261 | perf_session__delete(session); | ||
262 | |||
263 | return 0; | 252 | return 0; |
264 | } | 253 | } |
265 | 254 | ||
@@ -302,6 +291,12 @@ int cmd_buildid_cache(int argc, const char **argv, | |||
302 | *missing_filename = NULL, | 291 | *missing_filename = NULL, |
303 | *update_name_list_str = NULL, | 292 | *update_name_list_str = NULL, |
304 | *kcore_filename; | 293 | *kcore_filename; |
294 | char sbuf[STRERR_BUFSIZE]; | ||
295 | |||
296 | struct perf_data_file file = { | ||
297 | .mode = PERF_DATA_MODE_READ, | ||
298 | }; | ||
299 | struct perf_session *session = NULL; | ||
305 | 300 | ||
306 | const struct option buildid_cache_options[] = { | 301 | const struct option buildid_cache_options[] = { |
307 | OPT_STRING('a', "add", &add_name_list_str, | 302 | OPT_STRING('a', "add", &add_name_list_str, |
@@ -326,8 +321,17 @@ int cmd_buildid_cache(int argc, const char **argv, | |||
326 | argc = parse_options(argc, argv, buildid_cache_options, | 321 | argc = parse_options(argc, argv, buildid_cache_options, |
327 | buildid_cache_usage, 0); | 322 | buildid_cache_usage, 0); |
328 | 323 | ||
329 | if (symbol__init() < 0) | 324 | if (missing_filename) { |
330 | return -1; | 325 | file.path = missing_filename; |
326 | file.force = force; | ||
327 | |||
328 | session = perf_session__new(&file, false, NULL); | ||
329 | if (session == NULL) | ||
330 | return -1; | ||
331 | } | ||
332 | |||
333 | if (symbol__init(session ? &session->header.env : NULL) < 0) | ||
334 | goto out; | ||
331 | 335 | ||
332 | setup_pager(); | 336 | setup_pager(); |
333 | 337 | ||
@@ -344,7 +348,7 @@ int cmd_buildid_cache(int argc, const char **argv, | |||
344 | continue; | 348 | continue; |
345 | } | 349 | } |
346 | pr_warning("Couldn't add %s: %s\n", | 350 | pr_warning("Couldn't add %s: %s\n", |
347 | pos->s, strerror(errno)); | 351 | pos->s, strerror_r(errno, sbuf, sizeof(sbuf))); |
348 | } | 352 | } |
349 | 353 | ||
350 | strlist__delete(list); | 354 | strlist__delete(list); |
@@ -362,7 +366,7 @@ int cmd_buildid_cache(int argc, const char **argv, | |||
362 | continue; | 366 | continue; |
363 | } | 367 | } |
364 | pr_warning("Couldn't remove %s: %s\n", | 368 | pr_warning("Couldn't remove %s: %s\n", |
365 | pos->s, strerror(errno)); | 369 | pos->s, strerror_r(errno, sbuf, sizeof(sbuf))); |
366 | } | 370 | } |
367 | 371 | ||
368 | strlist__delete(list); | 372 | strlist__delete(list); |
@@ -370,7 +374,7 @@ int cmd_buildid_cache(int argc, const char **argv, | |||
370 | } | 374 | } |
371 | 375 | ||
372 | if (missing_filename) | 376 | if (missing_filename) |
373 | ret = build_id_cache__fprintf_missing(missing_filename, force, stdout); | 377 | ret = build_id_cache__fprintf_missing(session, stdout); |
374 | 378 | ||
375 | if (update_name_list_str) { | 379 | if (update_name_list_str) { |
376 | list = strlist__new(true, update_name_list_str); | 380 | list = strlist__new(true, update_name_list_str); |
@@ -383,7 +387,7 @@ int cmd_buildid_cache(int argc, const char **argv, | |||
383 | continue; | 387 | continue; |
384 | } | 388 | } |
385 | pr_warning("Couldn't update %s: %s\n", | 389 | pr_warning("Couldn't update %s: %s\n", |
386 | pos->s, strerror(errno)); | 390 | pos->s, strerror_r(errno, sbuf, sizeof(sbuf))); |
387 | } | 391 | } |
388 | 392 | ||
389 | strlist__delete(list); | 393 | strlist__delete(list); |
@@ -394,5 +398,9 @@ int cmd_buildid_cache(int argc, const char **argv, | |||
394 | build_id_cache__add_kcore(kcore_filename, debugdir, force)) | 398 | build_id_cache__add_kcore(kcore_filename, debugdir, force)) |
395 | pr_warning("Couldn't add %s\n", kcore_filename); | 399 | pr_warning("Couldn't add %s\n", kcore_filename); |
396 | 400 | ||
401 | out: | ||
402 | if (session) | ||
403 | perf_session__delete(session); | ||
404 | |||
397 | return ret; | 405 | return ret; |
398 | } | 406 | } |
diff --git a/tools/perf/builtin-diff.c b/tools/perf/builtin-diff.c index 9a5a035cb426..a3ce19f7aebd 100644 --- a/tools/perf/builtin-diff.c +++ b/tools/perf/builtin-diff.c | |||
@@ -360,7 +360,7 @@ static struct perf_tool tool = { | |||
360 | .exit = perf_event__process_exit, | 360 | .exit = perf_event__process_exit, |
361 | .fork = perf_event__process_fork, | 361 | .fork = perf_event__process_fork, |
362 | .lost = perf_event__process_lost, | 362 | .lost = perf_event__process_lost, |
363 | .ordered_samples = true, | 363 | .ordered_events = true, |
364 | .ordering_requires_timestamps = true, | 364 | .ordering_requires_timestamps = true, |
365 | }; | 365 | }; |
366 | 366 | ||
@@ -683,7 +683,7 @@ static int __cmd_diff(void) | |||
683 | d->session = perf_session__new(&d->file, false, &tool); | 683 | d->session = perf_session__new(&d->file, false, &tool); |
684 | if (!d->session) { | 684 | if (!d->session) { |
685 | pr_err("Failed to open %s\n", d->file.path); | 685 | pr_err("Failed to open %s\n", d->file.path); |
686 | ret = -ENOMEM; | 686 | ret = -1; |
687 | goto out_delete; | 687 | goto out_delete; |
688 | } | 688 | } |
689 | 689 | ||
@@ -1143,7 +1143,7 @@ int cmd_diff(int argc, const char **argv, const char *prefix __maybe_unused) | |||
1143 | 1143 | ||
1144 | argc = parse_options(argc, argv, options, diff_usage, 0); | 1144 | argc = parse_options(argc, argv, options, diff_usage, 0); |
1145 | 1145 | ||
1146 | if (symbol__init() < 0) | 1146 | if (symbol__init(NULL) < 0) |
1147 | return -1; | 1147 | return -1; |
1148 | 1148 | ||
1149 | if (data_init(argc, argv) < 0) | 1149 | if (data_init(argc, argv) < 0) |
diff --git a/tools/perf/builtin-evlist.c b/tools/perf/builtin-evlist.c index 66e12f55c052..0f93f859b782 100644 --- a/tools/perf/builtin-evlist.c +++ b/tools/perf/builtin-evlist.c | |||
@@ -28,7 +28,7 @@ static int __cmd_evlist(const char *file_name, struct perf_attr_details *details | |||
28 | 28 | ||
29 | session = perf_session__new(&file, 0, NULL); | 29 | session = perf_session__new(&file, 0, NULL); |
30 | if (session == NULL) | 30 | if (session == NULL) |
31 | return -ENOMEM; | 31 | return -1; |
32 | 32 | ||
33 | evlist__for_each(session->evlist, pos) | 33 | evlist__for_each(session->evlist, pos) |
34 | perf_evsel__fprintf(pos, details, stdout); | 34 | perf_evsel__fprintf(pos, details, stdout); |
diff --git a/tools/perf/builtin-help.c b/tools/perf/builtin-help.c index 0384d930480b..25d20628212e 100644 --- a/tools/perf/builtin-help.c +++ b/tools/perf/builtin-help.c | |||
@@ -103,6 +103,8 @@ static int check_emacsclient_version(void) | |||
103 | 103 | ||
104 | static void exec_woman_emacs(const char *path, const char *page) | 104 | static void exec_woman_emacs(const char *path, const char *page) |
105 | { | 105 | { |
106 | char sbuf[STRERR_BUFSIZE]; | ||
107 | |||
106 | if (!check_emacsclient_version()) { | 108 | if (!check_emacsclient_version()) { |
107 | /* This works only with emacsclient version >= 22. */ | 109 | /* This works only with emacsclient version >= 22. */ |
108 | struct strbuf man_page = STRBUF_INIT; | 110 | struct strbuf man_page = STRBUF_INIT; |
@@ -111,16 +113,19 @@ static void exec_woman_emacs(const char *path, const char *page) | |||
111 | path = "emacsclient"; | 113 | path = "emacsclient"; |
112 | strbuf_addf(&man_page, "(woman \"%s\")", page); | 114 | strbuf_addf(&man_page, "(woman \"%s\")", page); |
113 | execlp(path, "emacsclient", "-e", man_page.buf, NULL); | 115 | execlp(path, "emacsclient", "-e", man_page.buf, NULL); |
114 | warning("failed to exec '%s': %s", path, strerror(errno)); | 116 | warning("failed to exec '%s': %s", path, |
117 | strerror_r(errno, sbuf, sizeof(sbuf))); | ||
115 | } | 118 | } |
116 | } | 119 | } |
117 | 120 | ||
118 | static void exec_man_konqueror(const char *path, const char *page) | 121 | static void exec_man_konqueror(const char *path, const char *page) |
119 | { | 122 | { |
120 | const char *display = getenv("DISPLAY"); | 123 | const char *display = getenv("DISPLAY"); |
124 | |||
121 | if (display && *display) { | 125 | if (display && *display) { |
122 | struct strbuf man_page = STRBUF_INIT; | 126 | struct strbuf man_page = STRBUF_INIT; |
123 | const char *filename = "kfmclient"; | 127 | const char *filename = "kfmclient"; |
128 | char sbuf[STRERR_BUFSIZE]; | ||
124 | 129 | ||
125 | /* It's simpler to launch konqueror using kfmclient. */ | 130 | /* It's simpler to launch konqueror using kfmclient. */ |
126 | if (path) { | 131 | if (path) { |
@@ -139,24 +144,31 @@ static void exec_man_konqueror(const char *path, const char *page) | |||
139 | path = "kfmclient"; | 144 | path = "kfmclient"; |
140 | strbuf_addf(&man_page, "man:%s(1)", page); | 145 | strbuf_addf(&man_page, "man:%s(1)", page); |
141 | execlp(path, filename, "newTab", man_page.buf, NULL); | 146 | execlp(path, filename, "newTab", man_page.buf, NULL); |
142 | warning("failed to exec '%s': %s", path, strerror(errno)); | 147 | warning("failed to exec '%s': %s", path, |
148 | strerror_r(errno, sbuf, sizeof(sbuf))); | ||
143 | } | 149 | } |
144 | } | 150 | } |
145 | 151 | ||
146 | static void exec_man_man(const char *path, const char *page) | 152 | static void exec_man_man(const char *path, const char *page) |
147 | { | 153 | { |
154 | char sbuf[STRERR_BUFSIZE]; | ||
155 | |||
148 | if (!path) | 156 | if (!path) |
149 | path = "man"; | 157 | path = "man"; |
150 | execlp(path, "man", page, NULL); | 158 | execlp(path, "man", page, NULL); |
151 | warning("failed to exec '%s': %s", path, strerror(errno)); | 159 | warning("failed to exec '%s': %s", path, |
160 | strerror_r(errno, sbuf, sizeof(sbuf))); | ||
152 | } | 161 | } |
153 | 162 | ||
154 | static void exec_man_cmd(const char *cmd, const char *page) | 163 | static void exec_man_cmd(const char *cmd, const char *page) |
155 | { | 164 | { |
156 | struct strbuf shell_cmd = STRBUF_INIT; | 165 | struct strbuf shell_cmd = STRBUF_INIT; |
166 | char sbuf[STRERR_BUFSIZE]; | ||
167 | |||
157 | strbuf_addf(&shell_cmd, "%s %s", cmd, page); | 168 | strbuf_addf(&shell_cmd, "%s %s", cmd, page); |
158 | execl("/bin/sh", "sh", "-c", shell_cmd.buf, NULL); | 169 | execl("/bin/sh", "sh", "-c", shell_cmd.buf, NULL); |
159 | warning("failed to exec '%s': %s", cmd, strerror(errno)); | 170 | warning("failed to exec '%s': %s", cmd, |
171 | strerror_r(errno, sbuf, sizeof(sbuf))); | ||
160 | } | 172 | } |
161 | 173 | ||
162 | static void add_man_viewer(const char *name) | 174 | static void add_man_viewer(const char *name) |
diff --git a/tools/perf/builtin-inject.c b/tools/perf/builtin-inject.c index 9a02807387d6..de99ca1bb942 100644 --- a/tools/perf/builtin-inject.c +++ b/tools/perf/builtin-inject.c | |||
@@ -23,6 +23,7 @@ | |||
23 | 23 | ||
24 | struct perf_inject { | 24 | struct perf_inject { |
25 | struct perf_tool tool; | 25 | struct perf_tool tool; |
26 | struct perf_session *session; | ||
26 | bool build_ids; | 27 | bool build_ids; |
27 | bool sched_stat; | 28 | bool sched_stat; |
28 | const char *input_name; | 29 | const char *input_name; |
@@ -340,12 +341,8 @@ static int perf_evsel__check_stype(struct perf_evsel *evsel, | |||
340 | 341 | ||
341 | static int __cmd_inject(struct perf_inject *inject) | 342 | static int __cmd_inject(struct perf_inject *inject) |
342 | { | 343 | { |
343 | struct perf_session *session; | ||
344 | int ret = -EINVAL; | 344 | int ret = -EINVAL; |
345 | struct perf_data_file file = { | 345 | struct perf_session *session = inject->session; |
346 | .path = inject->input_name, | ||
347 | .mode = PERF_DATA_MODE_READ, | ||
348 | }; | ||
349 | struct perf_data_file *file_out = &inject->output; | 346 | struct perf_data_file *file_out = &inject->output; |
350 | 347 | ||
351 | signal(SIGINT, sig_handler); | 348 | signal(SIGINT, sig_handler); |
@@ -357,16 +354,12 @@ static int __cmd_inject(struct perf_inject *inject) | |||
357 | inject->tool.tracing_data = perf_event__repipe_tracing_data; | 354 | inject->tool.tracing_data = perf_event__repipe_tracing_data; |
358 | } | 355 | } |
359 | 356 | ||
360 | session = perf_session__new(&file, true, &inject->tool); | ||
361 | if (session == NULL) | ||
362 | return -ENOMEM; | ||
363 | |||
364 | if (inject->build_ids) { | 357 | if (inject->build_ids) { |
365 | inject->tool.sample = perf_event__inject_buildid; | 358 | inject->tool.sample = perf_event__inject_buildid; |
366 | } else if (inject->sched_stat) { | 359 | } else if (inject->sched_stat) { |
367 | struct perf_evsel *evsel; | 360 | struct perf_evsel *evsel; |
368 | 361 | ||
369 | inject->tool.ordered_samples = true; | 362 | inject->tool.ordered_events = true; |
370 | 363 | ||
371 | evlist__for_each(session->evlist, evsel) { | 364 | evlist__for_each(session->evlist, evsel) { |
372 | const char *name = perf_evsel__name(evsel); | 365 | const char *name = perf_evsel__name(evsel); |
@@ -396,8 +389,6 @@ static int __cmd_inject(struct perf_inject *inject) | |||
396 | perf_session__write_header(session, session->evlist, file_out->fd, true); | 389 | perf_session__write_header(session, session->evlist, file_out->fd, true); |
397 | } | 390 | } |
398 | 391 | ||
399 | perf_session__delete(session); | ||
400 | |||
401 | return ret; | 392 | return ret; |
402 | } | 393 | } |
403 | 394 | ||
@@ -427,6 +418,11 @@ int cmd_inject(int argc, const char **argv, const char *prefix __maybe_unused) | |||
427 | .mode = PERF_DATA_MODE_WRITE, | 418 | .mode = PERF_DATA_MODE_WRITE, |
428 | }, | 419 | }, |
429 | }; | 420 | }; |
421 | struct perf_data_file file = { | ||
422 | .mode = PERF_DATA_MODE_READ, | ||
423 | }; | ||
424 | int ret; | ||
425 | |||
430 | const struct option options[] = { | 426 | const struct option options[] = { |
431 | OPT_BOOLEAN('b', "build-ids", &inject.build_ids, | 427 | OPT_BOOLEAN('b', "build-ids", &inject.build_ids, |
432 | "Inject build-ids into the output stream"), | 428 | "Inject build-ids into the output stream"), |
@@ -461,8 +457,17 @@ int cmd_inject(int argc, const char **argv, const char *prefix __maybe_unused) | |||
461 | return -1; | 457 | return -1; |
462 | } | 458 | } |
463 | 459 | ||
464 | if (symbol__init() < 0) | 460 | file.path = inject.input_name; |
461 | inject.session = perf_session__new(&file, true, &inject.tool); | ||
462 | if (inject.session == NULL) | ||
463 | return -1; | ||
464 | |||
465 | if (symbol__init(&inject.session->header.env) < 0) | ||
465 | return -1; | 466 | return -1; |
466 | 467 | ||
467 | return __cmd_inject(&inject); | 468 | ret = __cmd_inject(&inject); |
469 | |||
470 | perf_session__delete(inject.session); | ||
471 | |||
472 | return ret; | ||
468 | } | 473 | } |
diff --git a/tools/perf/builtin-kmem.c b/tools/perf/builtin-kmem.c index bef3376bfaf3..f295141025bc 100644 --- a/tools/perf/builtin-kmem.c +++ b/tools/perf/builtin-kmem.c | |||
@@ -256,7 +256,9 @@ static int process_sample_event(struct perf_tool *tool __maybe_unused, | |||
256 | static struct perf_tool perf_kmem = { | 256 | static struct perf_tool perf_kmem = { |
257 | .sample = process_sample_event, | 257 | .sample = process_sample_event, |
258 | .comm = perf_event__process_comm, | 258 | .comm = perf_event__process_comm, |
259 | .ordered_samples = true, | 259 | .mmap = perf_event__process_mmap, |
260 | .mmap2 = perf_event__process_mmap2, | ||
261 | .ordered_events = true, | ||
260 | }; | 262 | }; |
261 | 263 | ||
262 | static double fragmentation(unsigned long n_req, unsigned long n_alloc) | 264 | static double fragmentation(unsigned long n_req, unsigned long n_alloc) |
@@ -403,10 +405,9 @@ static void sort_result(void) | |||
403 | __sort_result(&root_caller_stat, &root_caller_sorted, &caller_sort); | 405 | __sort_result(&root_caller_stat, &root_caller_sorted, &caller_sort); |
404 | } | 406 | } |
405 | 407 | ||
406 | static int __cmd_kmem(void) | 408 | static int __cmd_kmem(struct perf_session *session) |
407 | { | 409 | { |
408 | int err = -EINVAL; | 410 | int err = -EINVAL; |
409 | struct perf_session *session; | ||
410 | const struct perf_evsel_str_handler kmem_tracepoints[] = { | 411 | const struct perf_evsel_str_handler kmem_tracepoints[] = { |
411 | { "kmem:kmalloc", perf_evsel__process_alloc_event, }, | 412 | { "kmem:kmalloc", perf_evsel__process_alloc_event, }, |
412 | { "kmem:kmem_cache_alloc", perf_evsel__process_alloc_event, }, | 413 | { "kmem:kmem_cache_alloc", perf_evsel__process_alloc_event, }, |
@@ -415,34 +416,22 @@ static int __cmd_kmem(void) | |||
415 | { "kmem:kfree", perf_evsel__process_free_event, }, | 416 | { "kmem:kfree", perf_evsel__process_free_event, }, |
416 | { "kmem:kmem_cache_free", perf_evsel__process_free_event, }, | 417 | { "kmem:kmem_cache_free", perf_evsel__process_free_event, }, |
417 | }; | 418 | }; |
418 | struct perf_data_file file = { | ||
419 | .path = input_name, | ||
420 | .mode = PERF_DATA_MODE_READ, | ||
421 | }; | ||
422 | |||
423 | session = perf_session__new(&file, false, &perf_kmem); | ||
424 | if (session == NULL) | ||
425 | return -ENOMEM; | ||
426 | |||
427 | if (perf_session__create_kernel_maps(session) < 0) | ||
428 | goto out_delete; | ||
429 | 419 | ||
430 | if (!perf_session__has_traces(session, "kmem record")) | 420 | if (!perf_session__has_traces(session, "kmem record")) |
431 | goto out_delete; | 421 | goto out; |
432 | 422 | ||
433 | if (perf_session__set_tracepoints_handlers(session, kmem_tracepoints)) { | 423 | if (perf_session__set_tracepoints_handlers(session, kmem_tracepoints)) { |
434 | pr_err("Initializing perf session tracepoint handlers failed\n"); | 424 | pr_err("Initializing perf session tracepoint handlers failed\n"); |
435 | return -1; | 425 | goto out; |
436 | } | 426 | } |
437 | 427 | ||
438 | setup_pager(); | 428 | setup_pager(); |
439 | err = perf_session__process_events(session, &perf_kmem); | 429 | err = perf_session__process_events(session, &perf_kmem); |
440 | if (err != 0) | 430 | if (err != 0) |
441 | goto out_delete; | 431 | goto out; |
442 | sort_result(); | 432 | sort_result(); |
443 | print_result(session); | 433 | print_result(session); |
444 | out_delete: | 434 | out: |
445 | perf_session__delete(session); | ||
446 | return err; | 435 | return err; |
447 | } | 436 | } |
448 | 437 | ||
@@ -689,29 +678,46 @@ int cmd_kmem(int argc, const char **argv, const char *prefix __maybe_unused) | |||
689 | NULL, | 678 | NULL, |
690 | NULL | 679 | NULL |
691 | }; | 680 | }; |
681 | struct perf_session *session; | ||
682 | struct perf_data_file file = { | ||
683 | .path = input_name, | ||
684 | .mode = PERF_DATA_MODE_READ, | ||
685 | }; | ||
686 | int ret = -1; | ||
687 | |||
692 | argc = parse_options_subcommand(argc, argv, kmem_options, | 688 | argc = parse_options_subcommand(argc, argv, kmem_options, |
693 | kmem_subcommands, kmem_usage, 0); | 689 | kmem_subcommands, kmem_usage, 0); |
694 | 690 | ||
695 | if (!argc) | 691 | if (!argc) |
696 | usage_with_options(kmem_usage, kmem_options); | 692 | usage_with_options(kmem_usage, kmem_options); |
697 | 693 | ||
698 | symbol__init(); | ||
699 | |||
700 | if (!strncmp(argv[0], "rec", 3)) { | 694 | if (!strncmp(argv[0], "rec", 3)) { |
695 | symbol__init(NULL); | ||
701 | return __cmd_record(argc, argv); | 696 | return __cmd_record(argc, argv); |
702 | } else if (!strcmp(argv[0], "stat")) { | 697 | } |
698 | |||
699 | session = perf_session__new(&file, false, &perf_kmem); | ||
700 | if (session == NULL) | ||
701 | return -1; | ||
702 | |||
703 | symbol__init(&session->header.env); | ||
704 | |||
705 | if (!strcmp(argv[0], "stat")) { | ||
703 | if (cpu__setup_cpunode_map()) | 706 | if (cpu__setup_cpunode_map()) |
704 | return -1; | 707 | goto out_delete; |
705 | 708 | ||
706 | if (list_empty(&caller_sort)) | 709 | if (list_empty(&caller_sort)) |
707 | setup_sorting(&caller_sort, default_sort_order); | 710 | setup_sorting(&caller_sort, default_sort_order); |
708 | if (list_empty(&alloc_sort)) | 711 | if (list_empty(&alloc_sort)) |
709 | setup_sorting(&alloc_sort, default_sort_order); | 712 | setup_sorting(&alloc_sort, default_sort_order); |
710 | 713 | ||
711 | return __cmd_kmem(); | 714 | ret = __cmd_kmem(session); |
712 | } else | 715 | } else |
713 | usage_with_options(kmem_usage, kmem_options); | 716 | usage_with_options(kmem_usage, kmem_options); |
714 | 717 | ||
715 | return 0; | 718 | out_delete: |
719 | perf_session__delete(session); | ||
720 | |||
721 | return ret; | ||
716 | } | 722 | } |
717 | 723 | ||
diff --git a/tools/perf/builtin-kvm.c b/tools/perf/builtin-kvm.c index 43367eb00510..d8bf2271f4ea 100644 --- a/tools/perf/builtin-kvm.c +++ b/tools/perf/builtin-kvm.c | |||
@@ -543,14 +543,12 @@ static void print_vcpu_info(struct perf_kvm_stat *kvm) | |||
543 | 543 | ||
544 | pr_info("Analyze events for "); | 544 | pr_info("Analyze events for "); |
545 | 545 | ||
546 | if (kvm->live) { | 546 | if (kvm->opts.target.system_wide) |
547 | if (kvm->opts.target.system_wide) | 547 | pr_info("all VMs, "); |
548 | pr_info("all VMs, "); | 548 | else if (kvm->opts.target.pid) |
549 | else if (kvm->opts.target.pid) | 549 | pr_info("pid(s) %s, ", kvm->opts.target.pid); |
550 | pr_info("pid(s) %s, ", kvm->opts.target.pid); | 550 | else |
551 | else | 551 | pr_info("dazed and confused on what is monitored, "); |
552 | pr_info("dazed and confused on what is monitored, "); | ||
553 | } | ||
554 | 552 | ||
555 | if (vcpu == -1) | 553 | if (vcpu == -1) |
556 | pr_info("all VCPUs:\n\n"); | 554 | pr_info("all VCPUs:\n\n"); |
@@ -592,8 +590,8 @@ static void print_result(struct perf_kvm_stat *kvm) | |||
592 | pr_info("%9s ", "Samples%"); | 590 | pr_info("%9s ", "Samples%"); |
593 | 591 | ||
594 | pr_info("%9s ", "Time%"); | 592 | pr_info("%9s ", "Time%"); |
595 | pr_info("%10s ", "Min Time"); | 593 | pr_info("%11s ", "Min Time"); |
596 | pr_info("%10s ", "Max Time"); | 594 | pr_info("%11s ", "Max Time"); |
597 | pr_info("%16s ", "Avg time"); | 595 | pr_info("%16s ", "Avg time"); |
598 | pr_info("\n\n"); | 596 | pr_info("\n\n"); |
599 | 597 | ||
@@ -610,8 +608,8 @@ static void print_result(struct perf_kvm_stat *kvm) | |||
610 | pr_info("%10llu ", (unsigned long long)ecount); | 608 | pr_info("%10llu ", (unsigned long long)ecount); |
611 | pr_info("%8.2f%% ", (double)ecount / kvm->total_count * 100); | 609 | pr_info("%8.2f%% ", (double)ecount / kvm->total_count * 100); |
612 | pr_info("%8.2f%% ", (double)etime / kvm->total_time * 100); | 610 | pr_info("%8.2f%% ", (double)etime / kvm->total_time * 100); |
613 | pr_info("%8" PRIu64 "us ", min / 1000); | 611 | pr_info("%9.2fus ", (double)min / 1e3); |
614 | pr_info("%8" PRIu64 "us ", max / 1000); | 612 | pr_info("%9.2fus ", (double)max / 1e3); |
615 | pr_info("%9.2fus ( +-%7.2f%% )", (double)etime / ecount/1e3, | 613 | pr_info("%9.2fus ( +-%7.2f%% )", (double)etime / ecount/1e3, |
616 | kvm_event_rel_stddev(vcpu, event)); | 614 | kvm_event_rel_stddev(vcpu, event)); |
617 | pr_info("\n"); | 615 | pr_info("\n"); |
@@ -732,7 +730,7 @@ static s64 perf_kvm__mmap_read_idx(struct perf_kvm_stat *kvm, int idx, | |||
732 | return -1; | 730 | return -1; |
733 | } | 731 | } |
734 | 732 | ||
735 | err = perf_session_queue_event(kvm->session, event, &sample, 0); | 733 | err = perf_session_queue_event(kvm->session, event, &kvm->tool, &sample, 0); |
736 | /* | 734 | /* |
737 | * FIXME: Here we can't consume the event, as perf_session_queue_event will | 735 | * FIXME: Here we can't consume the event, as perf_session_queue_event will |
738 | * point to it, and it'll get possibly overwritten by the kernel. | 736 | * point to it, and it'll get possibly overwritten by the kernel. |
@@ -785,7 +783,7 @@ static int perf_kvm__mmap_read(struct perf_kvm_stat *kvm) | |||
785 | 783 | ||
786 | /* flush queue after each round in which we processed events */ | 784 | /* flush queue after each round in which we processed events */ |
787 | if (ntotal) { | 785 | if (ntotal) { |
788 | kvm->session->ordered_samples.next_flush = flush_time; | 786 | kvm->session->ordered_events.next_flush = flush_time; |
789 | err = kvm->tool.finished_round(&kvm->tool, NULL, kvm->session); | 787 | err = kvm->tool.finished_round(&kvm->tool, NULL, kvm->session); |
790 | if (err) { | 788 | if (err) { |
791 | if (kvm->lost_events) | 789 | if (kvm->lost_events) |
@@ -885,15 +883,11 @@ static int fd_set_nonblock(int fd) | |||
885 | return 0; | 883 | return 0; |
886 | } | 884 | } |
887 | 885 | ||
888 | static | 886 | static int perf_kvm__handle_stdin(void) |
889 | int perf_kvm__handle_stdin(struct termios *tc_now, struct termios *tc_save) | ||
890 | { | 887 | { |
891 | int c; | 888 | int c; |
892 | 889 | ||
893 | tcsetattr(0, TCSANOW, tc_now); | ||
894 | c = getc(stdin); | 890 | c = getc(stdin); |
895 | tcsetattr(0, TCSAFLUSH, tc_save); | ||
896 | |||
897 | if (c == 'q') | 891 | if (c == 'q') |
898 | return 1; | 892 | return 1; |
899 | 893 | ||
@@ -904,7 +898,7 @@ static int kvm_events_live_report(struct perf_kvm_stat *kvm) | |||
904 | { | 898 | { |
905 | struct pollfd *pollfds = NULL; | 899 | struct pollfd *pollfds = NULL; |
906 | int nr_fds, nr_stdin, ret, err = -EINVAL; | 900 | int nr_fds, nr_stdin, ret, err = -EINVAL; |
907 | struct termios tc, save; | 901 | struct termios save; |
908 | 902 | ||
909 | /* live flag must be set first */ | 903 | /* live flag must be set first */ |
910 | kvm->live = true; | 904 | kvm->live = true; |
@@ -919,26 +913,14 @@ static int kvm_events_live_report(struct perf_kvm_stat *kvm) | |||
919 | goto out; | 913 | goto out; |
920 | } | 914 | } |
921 | 915 | ||
916 | set_term_quiet_input(&save); | ||
922 | init_kvm_event_record(kvm); | 917 | init_kvm_event_record(kvm); |
923 | 918 | ||
924 | tcgetattr(0, &save); | ||
925 | tc = save; | ||
926 | tc.c_lflag &= ~(ICANON | ECHO); | ||
927 | tc.c_cc[VMIN] = 0; | ||
928 | tc.c_cc[VTIME] = 0; | ||
929 | |||
930 | signal(SIGINT, sig_handler); | 919 | signal(SIGINT, sig_handler); |
931 | signal(SIGTERM, sig_handler); | 920 | signal(SIGTERM, sig_handler); |
932 | 921 | ||
933 | /* copy pollfds -- need to add timerfd and stdin */ | 922 | /* use pollfds -- need to add timerfd and stdin */ |
934 | nr_fds = kvm->evlist->nr_fds; | 923 | nr_fds = kvm->evlist->pollfd.nr; |
935 | pollfds = zalloc(sizeof(struct pollfd) * (nr_fds + 2)); | ||
936 | if (!pollfds) { | ||
937 | err = -ENOMEM; | ||
938 | goto out; | ||
939 | } | ||
940 | memcpy(pollfds, kvm->evlist->pollfd, | ||
941 | sizeof(struct pollfd) * kvm->evlist->nr_fds); | ||
942 | 924 | ||
943 | /* add timer fd */ | 925 | /* add timer fd */ |
944 | if (perf_kvm__timerfd_create(kvm) < 0) { | 926 | if (perf_kvm__timerfd_create(kvm) < 0) { |
@@ -946,17 +928,21 @@ static int kvm_events_live_report(struct perf_kvm_stat *kvm) | |||
946 | goto out; | 928 | goto out; |
947 | } | 929 | } |
948 | 930 | ||
949 | pollfds[nr_fds].fd = kvm->timerfd; | 931 | if (perf_evlist__add_pollfd(kvm->evlist, kvm->timerfd)) |
950 | pollfds[nr_fds].events = POLLIN; | 932 | goto out; |
933 | |||
951 | nr_fds++; | 934 | nr_fds++; |
952 | 935 | ||
953 | pollfds[nr_fds].fd = fileno(stdin); | 936 | if (perf_evlist__add_pollfd(kvm->evlist, fileno(stdin))) |
954 | pollfds[nr_fds].events = POLLIN; | 937 | goto out; |
938 | |||
955 | nr_stdin = nr_fds; | 939 | nr_stdin = nr_fds; |
956 | nr_fds++; | 940 | nr_fds++; |
957 | if (fd_set_nonblock(fileno(stdin)) != 0) | 941 | if (fd_set_nonblock(fileno(stdin)) != 0) |
958 | goto out; | 942 | goto out; |
959 | 943 | ||
944 | pollfds = kvm->evlist->pollfd.entries; | ||
945 | |||
960 | /* everything is good - enable the events and process */ | 946 | /* everything is good - enable the events and process */ |
961 | perf_evlist__enable(kvm->evlist); | 947 | perf_evlist__enable(kvm->evlist); |
962 | 948 | ||
@@ -972,7 +958,7 @@ static int kvm_events_live_report(struct perf_kvm_stat *kvm) | |||
972 | goto out; | 958 | goto out; |
973 | 959 | ||
974 | if (pollfds[nr_stdin].revents & POLLIN) | 960 | if (pollfds[nr_stdin].revents & POLLIN) |
975 | done = perf_kvm__handle_stdin(&tc, &save); | 961 | done = perf_kvm__handle_stdin(); |
976 | 962 | ||
977 | if (!rc && !done) | 963 | if (!rc && !done) |
978 | err = poll(pollfds, nr_fds, 100); | 964 | err = poll(pollfds, nr_fds, 100); |
@@ -989,7 +975,7 @@ out: | |||
989 | if (kvm->timerfd >= 0) | 975 | if (kvm->timerfd >= 0) |
990 | close(kvm->timerfd); | 976 | close(kvm->timerfd); |
991 | 977 | ||
992 | free(pollfds); | 978 | tcsetattr(0, TCSAFLUSH, &save); |
993 | return err; | 979 | return err; |
994 | } | 980 | } |
995 | 981 | ||
@@ -998,6 +984,7 @@ static int kvm_live_open_events(struct perf_kvm_stat *kvm) | |||
998 | int err, rc = -1; | 984 | int err, rc = -1; |
999 | struct perf_evsel *pos; | 985 | struct perf_evsel *pos; |
1000 | struct perf_evlist *evlist = kvm->evlist; | 986 | struct perf_evlist *evlist = kvm->evlist; |
987 | char sbuf[STRERR_BUFSIZE]; | ||
1001 | 988 | ||
1002 | perf_evlist__config(evlist, &kvm->opts); | 989 | perf_evlist__config(evlist, &kvm->opts); |
1003 | 990 | ||
@@ -1034,12 +1021,14 @@ static int kvm_live_open_events(struct perf_kvm_stat *kvm) | |||
1034 | 1021 | ||
1035 | err = perf_evlist__open(evlist); | 1022 | err = perf_evlist__open(evlist); |
1036 | if (err < 0) { | 1023 | if (err < 0) { |
1037 | printf("Couldn't create the events: %s\n", strerror(errno)); | 1024 | printf("Couldn't create the events: %s\n", |
1025 | strerror_r(errno, sbuf, sizeof(sbuf))); | ||
1038 | goto out; | 1026 | goto out; |
1039 | } | 1027 | } |
1040 | 1028 | ||
1041 | if (perf_evlist__mmap(evlist, kvm->opts.mmap_pages, false) < 0) { | 1029 | if (perf_evlist__mmap(evlist, kvm->opts.mmap_pages, false) < 0) { |
1042 | ui__error("Failed to mmap the events: %s\n", strerror(errno)); | 1030 | ui__error("Failed to mmap the events: %s\n", |
1031 | strerror_r(errno, sbuf, sizeof(sbuf))); | ||
1043 | perf_evlist__close(evlist); | 1032 | perf_evlist__close(evlist); |
1044 | goto out; | 1033 | goto out; |
1045 | } | 1034 | } |
@@ -1058,7 +1047,7 @@ static int read_events(struct perf_kvm_stat *kvm) | |||
1058 | struct perf_tool eops = { | 1047 | struct perf_tool eops = { |
1059 | .sample = process_sample_event, | 1048 | .sample = process_sample_event, |
1060 | .comm = perf_event__process_comm, | 1049 | .comm = perf_event__process_comm, |
1061 | .ordered_samples = true, | 1050 | .ordered_events = true, |
1062 | }; | 1051 | }; |
1063 | struct perf_data_file file = { | 1052 | struct perf_data_file file = { |
1064 | .path = kvm->file_name, | 1053 | .path = kvm->file_name, |
@@ -1069,9 +1058,11 @@ static int read_events(struct perf_kvm_stat *kvm) | |||
1069 | kvm->session = perf_session__new(&file, false, &kvm->tool); | 1058 | kvm->session = perf_session__new(&file, false, &kvm->tool); |
1070 | if (!kvm->session) { | 1059 | if (!kvm->session) { |
1071 | pr_err("Initializing perf session failed\n"); | 1060 | pr_err("Initializing perf session failed\n"); |
1072 | return -EINVAL; | 1061 | return -1; |
1073 | } | 1062 | } |
1074 | 1063 | ||
1064 | symbol__init(&kvm->session->header.env); | ||
1065 | |||
1075 | if (!perf_session__has_traces(kvm->session, "kvm record")) | 1066 | if (!perf_session__has_traces(kvm->session, "kvm record")) |
1076 | return -EINVAL; | 1067 | return -EINVAL; |
1077 | 1068 | ||
@@ -1088,8 +1079,8 @@ static int read_events(struct perf_kvm_stat *kvm) | |||
1088 | 1079 | ||
1089 | static int parse_target_str(struct perf_kvm_stat *kvm) | 1080 | static int parse_target_str(struct perf_kvm_stat *kvm) |
1090 | { | 1081 | { |
1091 | if (kvm->pid_str) { | 1082 | if (kvm->opts.target.pid) { |
1092 | kvm->pid_list = intlist__new(kvm->pid_str); | 1083 | kvm->pid_list = intlist__new(kvm->opts.target.pid); |
1093 | if (kvm->pid_list == NULL) { | 1084 | if (kvm->pid_list == NULL) { |
1094 | pr_err("Error parsing process id string\n"); | 1085 | pr_err("Error parsing process id string\n"); |
1095 | return -EINVAL; | 1086 | return -EINVAL; |
@@ -1191,7 +1182,7 @@ kvm_events_report(struct perf_kvm_stat *kvm, int argc, const char **argv) | |||
1191 | OPT_STRING('k', "key", &kvm->sort_key, "sort-key", | 1182 | OPT_STRING('k', "key", &kvm->sort_key, "sort-key", |
1192 | "key for sorting: sample(sort by samples number)" | 1183 | "key for sorting: sample(sort by samples number)" |
1193 | " time (sort by avg time)"), | 1184 | " time (sort by avg time)"), |
1194 | OPT_STRING('p', "pid", &kvm->pid_str, "pid", | 1185 | OPT_STRING('p', "pid", &kvm->opts.target.pid, "pid", |
1195 | "analyze events only for given process id(s)"), | 1186 | "analyze events only for given process id(s)"), |
1196 | OPT_END() | 1187 | OPT_END() |
1197 | }; | 1188 | }; |
@@ -1201,8 +1192,6 @@ kvm_events_report(struct perf_kvm_stat *kvm, int argc, const char **argv) | |||
1201 | NULL | 1192 | NULL |
1202 | }; | 1193 | }; |
1203 | 1194 | ||
1204 | symbol__init(); | ||
1205 | |||
1206 | if (argc) { | 1195 | if (argc) { |
1207 | argc = parse_options(argc, argv, | 1196 | argc = parse_options(argc, argv, |
1208 | kvm_events_report_options, | 1197 | kvm_events_report_options, |
@@ -1212,6 +1201,9 @@ kvm_events_report(struct perf_kvm_stat *kvm, int argc, const char **argv) | |||
1212 | kvm_events_report_options); | 1201 | kvm_events_report_options); |
1213 | } | 1202 | } |
1214 | 1203 | ||
1204 | if (!kvm->opts.target.pid) | ||
1205 | kvm->opts.target.system_wide = true; | ||
1206 | |||
1215 | return kvm_events_report_vcpu(kvm); | 1207 | return kvm_events_report_vcpu(kvm); |
1216 | } | 1208 | } |
1217 | 1209 | ||
@@ -1311,7 +1303,7 @@ static int kvm_events_live(struct perf_kvm_stat *kvm, | |||
1311 | kvm->tool.exit = perf_event__process_exit; | 1303 | kvm->tool.exit = perf_event__process_exit; |
1312 | kvm->tool.fork = perf_event__process_fork; | 1304 | kvm->tool.fork = perf_event__process_fork; |
1313 | kvm->tool.lost = process_lost_event; | 1305 | kvm->tool.lost = process_lost_event; |
1314 | kvm->tool.ordered_samples = true; | 1306 | kvm->tool.ordered_events = true; |
1315 | perf_tool__fill_defaults(&kvm->tool); | 1307 | perf_tool__fill_defaults(&kvm->tool); |
1316 | 1308 | ||
1317 | /* set defaults */ | 1309 | /* set defaults */ |
@@ -1322,7 +1314,7 @@ static int kvm_events_live(struct perf_kvm_stat *kvm, | |||
1322 | kvm->opts.target.uid_str = NULL; | 1314 | kvm->opts.target.uid_str = NULL; |
1323 | kvm->opts.target.uid = UINT_MAX; | 1315 | kvm->opts.target.uid = UINT_MAX; |
1324 | 1316 | ||
1325 | symbol__init(); | 1317 | symbol__init(NULL); |
1326 | disable_buildid_cache(); | 1318 | disable_buildid_cache(); |
1327 | 1319 | ||
1328 | use_browser = 0; | 1320 | use_browser = 0; |
@@ -1369,7 +1361,7 @@ static int kvm_events_live(struct perf_kvm_stat *kvm, | |||
1369 | */ | 1361 | */ |
1370 | kvm->session = perf_session__new(&file, false, &kvm->tool); | 1362 | kvm->session = perf_session__new(&file, false, &kvm->tool); |
1371 | if (kvm->session == NULL) { | 1363 | if (kvm->session == NULL) { |
1372 | err = -ENOMEM; | 1364 | err = -1; |
1373 | goto out; | 1365 | goto out; |
1374 | } | 1366 | } |
1375 | kvm->session->evlist = kvm->evlist; | 1367 | kvm->session->evlist = kvm->evlist; |
diff --git a/tools/perf/builtin-lock.c b/tools/perf/builtin-lock.c index 6148afc995c6..e7ec71589da6 100644 --- a/tools/perf/builtin-lock.c +++ b/tools/perf/builtin-lock.c | |||
@@ -852,7 +852,7 @@ static int __cmd_report(bool display_info) | |||
852 | struct perf_tool eops = { | 852 | struct perf_tool eops = { |
853 | .sample = process_sample_event, | 853 | .sample = process_sample_event, |
854 | .comm = perf_event__process_comm, | 854 | .comm = perf_event__process_comm, |
855 | .ordered_samples = true, | 855 | .ordered_events = true, |
856 | }; | 856 | }; |
857 | struct perf_data_file file = { | 857 | struct perf_data_file file = { |
858 | .path = input_name, | 858 | .path = input_name, |
@@ -862,9 +862,11 @@ static int __cmd_report(bool display_info) | |||
862 | session = perf_session__new(&file, false, &eops); | 862 | session = perf_session__new(&file, false, &eops); |
863 | if (!session) { | 863 | if (!session) { |
864 | pr_err("Initializing perf session failed\n"); | 864 | pr_err("Initializing perf session failed\n"); |
865 | return -ENOMEM; | 865 | return -1; |
866 | } | 866 | } |
867 | 867 | ||
868 | symbol__init(&session->header.env); | ||
869 | |||
868 | if (!perf_session__has_traces(session, "lock record")) | 870 | if (!perf_session__has_traces(session, "lock record")) |
869 | goto out_delete; | 871 | goto out_delete; |
870 | 872 | ||
@@ -974,7 +976,6 @@ int cmd_lock(int argc, const char **argv, const char *prefix __maybe_unused) | |||
974 | unsigned int i; | 976 | unsigned int i; |
975 | int rc = 0; | 977 | int rc = 0; |
976 | 978 | ||
977 | symbol__init(); | ||
978 | for (i = 0; i < LOCKHASH_SIZE; i++) | 979 | for (i = 0; i < LOCKHASH_SIZE; i++) |
979 | INIT_LIST_HEAD(lockhash_table + i); | 980 | INIT_LIST_HEAD(lockhash_table + i); |
980 | 981 | ||
diff --git a/tools/perf/builtin-mem.c b/tools/perf/builtin-mem.c index 4a1a6c94a5eb..24db6ffe2957 100644 --- a/tools/perf/builtin-mem.c +++ b/tools/perf/builtin-mem.c | |||
@@ -124,7 +124,7 @@ static int report_raw_events(struct perf_mem *mem) | |||
124 | &mem->tool); | 124 | &mem->tool); |
125 | 125 | ||
126 | if (session == NULL) | 126 | if (session == NULL) |
127 | return -ENOMEM; | 127 | return -1; |
128 | 128 | ||
129 | if (mem->cpu_list) { | 129 | if (mem->cpu_list) { |
130 | ret = perf_session__cpu_bitmap(session, mem->cpu_list, | 130 | ret = perf_session__cpu_bitmap(session, mem->cpu_list, |
@@ -133,7 +133,7 @@ static int report_raw_events(struct perf_mem *mem) | |||
133 | goto out_delete; | 133 | goto out_delete; |
134 | } | 134 | } |
135 | 135 | ||
136 | if (symbol__init() < 0) | 136 | if (symbol__init(&session->header.env) < 0) |
137 | return -1; | 137 | return -1; |
138 | 138 | ||
139 | printf("# PID, TID, IP, ADDR, LOCAL WEIGHT, DSRC, SYMBOL\n"); | 139 | printf("# PID, TID, IP, ADDR, LOCAL WEIGHT, DSRC, SYMBOL\n"); |
@@ -194,7 +194,7 @@ int cmd_mem(int argc, const char **argv, const char *prefix __maybe_unused) | |||
194 | .lost = perf_event__process_lost, | 194 | .lost = perf_event__process_lost, |
195 | .fork = perf_event__process_fork, | 195 | .fork = perf_event__process_fork, |
196 | .build_id = perf_event__process_build_id, | 196 | .build_id = perf_event__process_build_id, |
197 | .ordered_samples = true, | 197 | .ordered_events = true, |
198 | }, | 198 | }, |
199 | .input_name = "perf.data", | 199 | .input_name = "perf.data", |
200 | }; | 200 | }; |
diff --git a/tools/perf/builtin-probe.c b/tools/perf/builtin-probe.c index c63fa2925075..04412b4770a2 100644 --- a/tools/perf/builtin-probe.c +++ b/tools/perf/builtin-probe.c | |||
@@ -290,8 +290,11 @@ static void cleanup_params(void) | |||
290 | 290 | ||
291 | static void pr_err_with_code(const char *msg, int err) | 291 | static void pr_err_with_code(const char *msg, int err) |
292 | { | 292 | { |
293 | char sbuf[STRERR_BUFSIZE]; | ||
294 | |||
293 | pr_err("%s", msg); | 295 | pr_err("%s", msg); |
294 | pr_debug(" Reason: %s (Code: %d)", strerror(-err), err); | 296 | pr_debug(" Reason: %s (Code: %d)", |
297 | strerror_r(-err, sbuf, sizeof(sbuf)), err); | ||
295 | pr_err("\n"); | 298 | pr_err("\n"); |
296 | } | 299 | } |
297 | 300 | ||
@@ -373,6 +376,8 @@ __cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused) | |||
373 | "target executable name or path", opt_set_target), | 376 | "target executable name or path", opt_set_target), |
374 | OPT_BOOLEAN(0, "demangle", &symbol_conf.demangle, | 377 | OPT_BOOLEAN(0, "demangle", &symbol_conf.demangle, |
375 | "Disable symbol demangling"), | 378 | "Disable symbol demangling"), |
379 | OPT_BOOLEAN(0, "demangle-kernel", &symbol_conf.demangle_kernel, | ||
380 | "Enable kernel symbol demangling"), | ||
376 | OPT_END() | 381 | OPT_END() |
377 | }; | 382 | }; |
378 | int ret; | 383 | int ret; |
@@ -467,7 +472,8 @@ __cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused) | |||
467 | usage_with_options(probe_usage, options); | 472 | usage_with_options(probe_usage, options); |
468 | } | 473 | } |
469 | 474 | ||
470 | ret = show_line_range(¶ms.line_range, params.target); | 475 | ret = show_line_range(¶ms.line_range, params.target, |
476 | params.uprobes); | ||
471 | if (ret < 0) | 477 | if (ret < 0) |
472 | pr_err_with_code(" Error: Failed to show lines.", ret); | 478 | pr_err_with_code(" Error: Failed to show lines.", ret); |
473 | return ret; | 479 | return ret; |
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index 4869050e7194..44c6f3d55ce7 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c | |||
@@ -65,8 +65,9 @@ static int process_synthesized_event(struct perf_tool *tool, | |||
65 | return record__write(rec, event, event->header.size); | 65 | return record__write(rec, event, event->header.size); |
66 | } | 66 | } |
67 | 67 | ||
68 | static int record__mmap_read(struct record *rec, struct perf_mmap *md) | 68 | static int record__mmap_read(struct record *rec, int idx) |
69 | { | 69 | { |
70 | struct perf_mmap *md = &rec->evlist->mmap[idx]; | ||
70 | unsigned int head = perf_mmap__read_head(md); | 71 | unsigned int head = perf_mmap__read_head(md); |
71 | unsigned int old = md->prev; | 72 | unsigned int old = md->prev; |
72 | unsigned char *data = md->base + page_size; | 73 | unsigned char *data = md->base + page_size; |
@@ -102,8 +103,7 @@ static int record__mmap_read(struct record *rec, struct perf_mmap *md) | |||
102 | } | 103 | } |
103 | 104 | ||
104 | md->prev = old; | 105 | md->prev = old; |
105 | perf_mmap__write_tail(md, old); | 106 | perf_evlist__mmap_consume(rec->evlist, idx); |
106 | |||
107 | out: | 107 | out: |
108 | return rc; | 108 | return rc; |
109 | } | 109 | } |
@@ -161,7 +161,7 @@ try_again: | |||
161 | 161 | ||
162 | if (perf_evlist__apply_filters(evlist)) { | 162 | if (perf_evlist__apply_filters(evlist)) { |
163 | error("failed to set filter with %d (%s)\n", errno, | 163 | error("failed to set filter with %d (%s)\n", errno, |
164 | strerror(errno)); | 164 | strerror_r(errno, msg, sizeof(msg))); |
165 | rc = -1; | 165 | rc = -1; |
166 | goto out; | 166 | goto out; |
167 | } | 167 | } |
@@ -175,7 +175,8 @@ try_again: | |||
175 | "(current value: %u)\n", opts->mmap_pages); | 175 | "(current value: %u)\n", opts->mmap_pages); |
176 | rc = -errno; | 176 | rc = -errno; |
177 | } else { | 177 | } else { |
178 | pr_err("failed to mmap with %d (%s)\n", errno, strerror(errno)); | 178 | pr_err("failed to mmap with %d (%s)\n", errno, |
179 | strerror_r(errno, msg, sizeof(msg))); | ||
179 | rc = -errno; | 180 | rc = -errno; |
180 | } | 181 | } |
181 | goto out; | 182 | goto out; |
@@ -244,7 +245,7 @@ static int record__mmap_read_all(struct record *rec) | |||
244 | 245 | ||
245 | for (i = 0; i < rec->evlist->nr_mmaps; i++) { | 246 | for (i = 0; i < rec->evlist->nr_mmaps; i++) { |
246 | if (rec->evlist->mmap[i].base) { | 247 | if (rec->evlist->mmap[i].base) { |
247 | if (record__mmap_read(rec, &rec->evlist->mmap[i]) != 0) { | 248 | if (record__mmap_read(rec, i) != 0) { |
248 | rc = -1; | 249 | rc = -1; |
249 | goto out; | 250 | goto out; |
250 | } | 251 | } |
@@ -307,7 +308,7 @@ static int __cmd_record(struct record *rec, int argc, const char **argv) | |||
307 | struct record_opts *opts = &rec->opts; | 308 | struct record_opts *opts = &rec->opts; |
308 | struct perf_data_file *file = &rec->file; | 309 | struct perf_data_file *file = &rec->file; |
309 | struct perf_session *session; | 310 | struct perf_session *session; |
310 | bool disabled = false; | 311 | bool disabled = false, draining = false; |
311 | 312 | ||
312 | rec->progname = argv[0]; | 313 | rec->progname = argv[0]; |
313 | 314 | ||
@@ -456,9 +457,9 @@ static int __cmd_record(struct record *rec, int argc, const char **argv) | |||
456 | } | 457 | } |
457 | 458 | ||
458 | if (hits == rec->samples) { | 459 | if (hits == rec->samples) { |
459 | if (done) | 460 | if (done || draining) |
460 | break; | 461 | break; |
461 | err = poll(rec->evlist->pollfd, rec->evlist->nr_fds, -1); | 462 | err = perf_evlist__poll(rec->evlist, -1); |
462 | /* | 463 | /* |
463 | * Propagate error, only if there's any. Ignore positive | 464 | * Propagate error, only if there's any. Ignore positive |
464 | * number of returned events and interrupt error. | 465 | * number of returned events and interrupt error. |
@@ -466,6 +467,9 @@ static int __cmd_record(struct record *rec, int argc, const char **argv) | |||
466 | if (err > 0 || (err < 0 && errno == EINTR)) | 467 | if (err > 0 || (err < 0 && errno == EINTR)) |
467 | err = 0; | 468 | err = 0; |
468 | waking++; | 469 | waking++; |
470 | |||
471 | if (perf_evlist__filter_pollfd(rec->evlist, POLLERR | POLLHUP) == 0) | ||
472 | draining = true; | ||
469 | } | 473 | } |
470 | 474 | ||
471 | /* | 475 | /* |
@@ -480,7 +484,7 @@ static int __cmd_record(struct record *rec, int argc, const char **argv) | |||
480 | } | 484 | } |
481 | 485 | ||
482 | if (forks && workload_exec_errno) { | 486 | if (forks && workload_exec_errno) { |
483 | char msg[512]; | 487 | char msg[STRERR_BUFSIZE]; |
484 | const char *emsg = strerror_r(workload_exec_errno, msg, sizeof(msg)); | 488 | const char *emsg = strerror_r(workload_exec_errno, msg, sizeof(msg)); |
485 | pr_err("Workload failed: %s\n", emsg); | 489 | pr_err("Workload failed: %s\n", emsg); |
486 | err = -1; | 490 | err = -1; |
@@ -620,145 +624,56 @@ error: | |||
620 | return ret; | 624 | return ret; |
621 | } | 625 | } |
622 | 626 | ||
623 | #ifdef HAVE_DWARF_UNWIND_SUPPORT | 627 | static void callchain_debug(void) |
624 | static int get_stack_size(char *str, unsigned long *_size) | ||
625 | { | ||
626 | char *endptr; | ||
627 | unsigned long size; | ||
628 | unsigned long max_size = round_down(USHRT_MAX, sizeof(u64)); | ||
629 | |||
630 | size = strtoul(str, &endptr, 0); | ||
631 | |||
632 | do { | ||
633 | if (*endptr) | ||
634 | break; | ||
635 | |||
636 | size = round_up(size, sizeof(u64)); | ||
637 | if (!size || size > max_size) | ||
638 | break; | ||
639 | |||
640 | *_size = size; | ||
641 | return 0; | ||
642 | |||
643 | } while (0); | ||
644 | |||
645 | pr_err("callchain: Incorrect stack dump size (max %ld): %s\n", | ||
646 | max_size, str); | ||
647 | return -1; | ||
648 | } | ||
649 | #endif /* HAVE_DWARF_UNWIND_SUPPORT */ | ||
650 | |||
651 | int record_parse_callchain(const char *arg, struct record_opts *opts) | ||
652 | { | ||
653 | char *tok, *name, *saveptr = NULL; | ||
654 | char *buf; | ||
655 | int ret = -1; | ||
656 | |||
657 | /* We need buffer that we know we can write to. */ | ||
658 | buf = malloc(strlen(arg) + 1); | ||
659 | if (!buf) | ||
660 | return -ENOMEM; | ||
661 | |||
662 | strcpy(buf, arg); | ||
663 | |||
664 | tok = strtok_r((char *)buf, ",", &saveptr); | ||
665 | name = tok ? : (char *)buf; | ||
666 | |||
667 | do { | ||
668 | /* Framepointer style */ | ||
669 | if (!strncmp(name, "fp", sizeof("fp"))) { | ||
670 | if (!strtok_r(NULL, ",", &saveptr)) { | ||
671 | opts->call_graph = CALLCHAIN_FP; | ||
672 | ret = 0; | ||
673 | } else | ||
674 | pr_err("callchain: No more arguments " | ||
675 | "needed for -g fp\n"); | ||
676 | break; | ||
677 | |||
678 | #ifdef HAVE_DWARF_UNWIND_SUPPORT | ||
679 | /* Dwarf style */ | ||
680 | } else if (!strncmp(name, "dwarf", sizeof("dwarf"))) { | ||
681 | const unsigned long default_stack_dump_size = 8192; | ||
682 | |||
683 | ret = 0; | ||
684 | opts->call_graph = CALLCHAIN_DWARF; | ||
685 | opts->stack_dump_size = default_stack_dump_size; | ||
686 | |||
687 | tok = strtok_r(NULL, ",", &saveptr); | ||
688 | if (tok) { | ||
689 | unsigned long size = 0; | ||
690 | |||
691 | ret = get_stack_size(tok, &size); | ||
692 | opts->stack_dump_size = size; | ||
693 | } | ||
694 | #endif /* HAVE_DWARF_UNWIND_SUPPORT */ | ||
695 | } else { | ||
696 | pr_err("callchain: Unknown --call-graph option " | ||
697 | "value: %s\n", arg); | ||
698 | break; | ||
699 | } | ||
700 | |||
701 | } while (0); | ||
702 | |||
703 | free(buf); | ||
704 | return ret; | ||
705 | } | ||
706 | |||
707 | static void callchain_debug(struct record_opts *opts) | ||
708 | { | 628 | { |
709 | static const char *str[CALLCHAIN_MAX] = { "NONE", "FP", "DWARF" }; | 629 | static const char *str[CALLCHAIN_MAX] = { "NONE", "FP", "DWARF" }; |
710 | 630 | ||
711 | pr_debug("callchain: type %s\n", str[opts->call_graph]); | 631 | pr_debug("callchain: type %s\n", str[callchain_param.record_mode]); |
712 | 632 | ||
713 | if (opts->call_graph == CALLCHAIN_DWARF) | 633 | if (callchain_param.record_mode == CALLCHAIN_DWARF) |
714 | pr_debug("callchain: stack dump size %d\n", | 634 | pr_debug("callchain: stack dump size %d\n", |
715 | opts->stack_dump_size); | 635 | callchain_param.dump_size); |
716 | } | 636 | } |
717 | 637 | ||
718 | int record_parse_callchain_opt(const struct option *opt, | 638 | int record_parse_callchain_opt(const struct option *opt __maybe_unused, |
719 | const char *arg, | 639 | const char *arg, |
720 | int unset) | 640 | int unset) |
721 | { | 641 | { |
722 | struct record_opts *opts = opt->value; | ||
723 | int ret; | 642 | int ret; |
724 | 643 | ||
725 | opts->call_graph_enabled = !unset; | 644 | callchain_param.enabled = !unset; |
726 | 645 | ||
727 | /* --no-call-graph */ | 646 | /* --no-call-graph */ |
728 | if (unset) { | 647 | if (unset) { |
729 | opts->call_graph = CALLCHAIN_NONE; | 648 | callchain_param.record_mode = CALLCHAIN_NONE; |
730 | pr_debug("callchain: disabled\n"); | 649 | pr_debug("callchain: disabled\n"); |
731 | return 0; | 650 | return 0; |
732 | } | 651 | } |
733 | 652 | ||
734 | ret = record_parse_callchain(arg, opts); | 653 | ret = parse_callchain_record_opt(arg); |
735 | if (!ret) | 654 | if (!ret) |
736 | callchain_debug(opts); | 655 | callchain_debug(); |
737 | 656 | ||
738 | return ret; | 657 | return ret; |
739 | } | 658 | } |
740 | 659 | ||
741 | int record_callchain_opt(const struct option *opt, | 660 | int record_callchain_opt(const struct option *opt __maybe_unused, |
742 | const char *arg __maybe_unused, | 661 | const char *arg __maybe_unused, |
743 | int unset __maybe_unused) | 662 | int unset __maybe_unused) |
744 | { | 663 | { |
745 | struct record_opts *opts = opt->value; | 664 | callchain_param.enabled = true; |
746 | 665 | ||
747 | opts->call_graph_enabled = !unset; | 666 | if (callchain_param.record_mode == CALLCHAIN_NONE) |
667 | callchain_param.record_mode = CALLCHAIN_FP; | ||
748 | 668 | ||
749 | if (opts->call_graph == CALLCHAIN_NONE) | 669 | callchain_debug(); |
750 | opts->call_graph = CALLCHAIN_FP; | ||
751 | |||
752 | callchain_debug(opts); | ||
753 | return 0; | 670 | return 0; |
754 | } | 671 | } |
755 | 672 | ||
756 | static int perf_record_config(const char *var, const char *value, void *cb) | 673 | static int perf_record_config(const char *var, const char *value, void *cb) |
757 | { | 674 | { |
758 | struct record *rec = cb; | ||
759 | |||
760 | if (!strcmp(var, "record.call-graph")) | 675 | if (!strcmp(var, "record.call-graph")) |
761 | return record_parse_callchain(value, &rec->opts); | 676 | var = "call-graph.record-mode"; /* fall-through */ |
762 | 677 | ||
763 | return perf_default_config(var, value, cb); | 678 | return perf_default_config(var, value, cb); |
764 | } | 679 | } |
@@ -781,6 +696,7 @@ static const char * const record_usage[] = { | |||
781 | */ | 696 | */ |
782 | static struct record record = { | 697 | static struct record record = { |
783 | .opts = { | 698 | .opts = { |
699 | .sample_time = true, | ||
784 | .mmap_pages = UINT_MAX, | 700 | .mmap_pages = UINT_MAX, |
785 | .user_freq = UINT_MAX, | 701 | .user_freq = UINT_MAX, |
786 | .user_interval = ULLONG_MAX, | 702 | .user_interval = ULLONG_MAX, |
@@ -907,7 +823,7 @@ int cmd_record(int argc, const char **argv, const char *prefix __maybe_unused) | |||
907 | usage_with_options(record_usage, record_options); | 823 | usage_with_options(record_usage, record_options); |
908 | } | 824 | } |
909 | 825 | ||
910 | symbol__init(); | 826 | symbol__init(NULL); |
911 | 827 | ||
912 | if (symbol_conf.kptr_restrict) | 828 | if (symbol_conf.kptr_restrict) |
913 | pr_warning( | 829 | pr_warning( |
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index 21d830bafff3..ac145fae0521 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c | |||
@@ -58,17 +58,19 @@ struct report { | |||
58 | const char *symbol_filter_str; | 58 | const char *symbol_filter_str; |
59 | float min_percent; | 59 | float min_percent; |
60 | u64 nr_entries; | 60 | u64 nr_entries; |
61 | u64 queue_size; | ||
61 | DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS); | 62 | DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS); |
62 | }; | 63 | }; |
63 | 64 | ||
64 | static int report__config(const char *var, const char *value, void *cb) | 65 | static int report__config(const char *var, const char *value, void *cb) |
65 | { | 66 | { |
67 | struct report *rep = cb; | ||
68 | |||
66 | if (!strcmp(var, "report.group")) { | 69 | if (!strcmp(var, "report.group")) { |
67 | symbol_conf.event_group = perf_config_bool(var, value); | 70 | symbol_conf.event_group = perf_config_bool(var, value); |
68 | return 0; | 71 | return 0; |
69 | } | 72 | } |
70 | if (!strcmp(var, "report.percent-limit")) { | 73 | if (!strcmp(var, "report.percent-limit")) { |
71 | struct report *rep = cb; | ||
72 | rep->min_percent = strtof(value, NULL); | 74 | rep->min_percent = strtof(value, NULL); |
73 | return 0; | 75 | return 0; |
74 | } | 76 | } |
@@ -76,6 +78,10 @@ static int report__config(const char *var, const char *value, void *cb) | |||
76 | symbol_conf.cumulate_callchain = perf_config_bool(var, value); | 78 | symbol_conf.cumulate_callchain = perf_config_bool(var, value); |
77 | return 0; | 79 | return 0; |
78 | } | 80 | } |
81 | if (!strcmp(var, "report.queue-size")) { | ||
82 | rep->queue_size = perf_config_u64(var, value); | ||
83 | return 0; | ||
84 | } | ||
79 | 85 | ||
80 | return perf_default_config(var, value, cb); | 86 | return perf_default_config(var, value, cb); |
81 | } | 87 | } |
@@ -578,7 +584,7 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused) | |||
578 | .attr = perf_event__process_attr, | 584 | .attr = perf_event__process_attr, |
579 | .tracing_data = perf_event__process_tracing_data, | 585 | .tracing_data = perf_event__process_tracing_data, |
580 | .build_id = perf_event__process_build_id, | 586 | .build_id = perf_event__process_build_id, |
581 | .ordered_samples = true, | 587 | .ordered_events = true, |
582 | .ordering_requires_timestamps = true, | 588 | .ordering_requires_timestamps = true, |
583 | }, | 589 | }, |
584 | .max_stack = PERF_MAX_STACK_DEPTH, | 590 | .max_stack = PERF_MAX_STACK_DEPTH, |
@@ -674,6 +680,8 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused) | |||
674 | "objdump binary to use for disassembly and annotations"), | 680 | "objdump binary to use for disassembly and annotations"), |
675 | OPT_BOOLEAN(0, "demangle", &symbol_conf.demangle, | 681 | OPT_BOOLEAN(0, "demangle", &symbol_conf.demangle, |
676 | "Disable symbol demangling"), | 682 | "Disable symbol demangling"), |
683 | OPT_BOOLEAN(0, "demangle-kernel", &symbol_conf.demangle_kernel, | ||
684 | "Enable kernel symbol demangling"), | ||
677 | OPT_BOOLEAN(0, "mem-mode", &report.mem_mode, "mem access profile"), | 685 | OPT_BOOLEAN(0, "mem-mode", &report.mem_mode, "mem access profile"), |
678 | OPT_CALLBACK(0, "percent-limit", &report, "percent", | 686 | OPT_CALLBACK(0, "percent-limit", &report, "percent", |
679 | "Don't show entries under that percent", parse_percent_limit), | 687 | "Don't show entries under that percent", parse_percent_limit), |
@@ -712,14 +720,19 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused) | |||
712 | repeat: | 720 | repeat: |
713 | session = perf_session__new(&file, false, &report.tool); | 721 | session = perf_session__new(&file, false, &report.tool); |
714 | if (session == NULL) | 722 | if (session == NULL) |
715 | return -ENOMEM; | 723 | return -1; |
724 | |||
725 | if (report.queue_size) { | ||
726 | ordered_events__set_alloc_size(&session->ordered_events, | ||
727 | report.queue_size); | ||
728 | } | ||
716 | 729 | ||
717 | report.session = session; | 730 | report.session = session; |
718 | 731 | ||
719 | has_br_stack = perf_header__has_feat(&session->header, | 732 | has_br_stack = perf_header__has_feat(&session->header, |
720 | HEADER_BRANCH_STACK); | 733 | HEADER_BRANCH_STACK); |
721 | 734 | ||
722 | if (branch_mode == -1 && has_br_stack) { | 735 | if ((branch_mode == -1 && has_br_stack) || branch_mode == 1) { |
723 | sort__mode = SORT_MODE__BRANCH; | 736 | sort__mode = SORT_MODE__BRANCH; |
724 | symbol_conf.cumulate_callchain = false; | 737 | symbol_conf.cumulate_callchain = false; |
725 | } | 738 | } |
@@ -787,7 +800,7 @@ repeat: | |||
787 | } | 800 | } |
788 | } | 801 | } |
789 | 802 | ||
790 | if (symbol__init() < 0) | 803 | if (symbol__init(&session->header.env) < 0) |
791 | goto error; | 804 | goto error; |
792 | 805 | ||
793 | if (argc) { | 806 | if (argc) { |
diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c index f83c08c0dd87..9c9287fbf8e9 100644 --- a/tools/perf/builtin-sched.c +++ b/tools/perf/builtin-sched.c | |||
@@ -428,6 +428,7 @@ static u64 get_cpu_usage_nsec_parent(void) | |||
428 | static int self_open_counters(void) | 428 | static int self_open_counters(void) |
429 | { | 429 | { |
430 | struct perf_event_attr attr; | 430 | struct perf_event_attr attr; |
431 | char sbuf[STRERR_BUFSIZE]; | ||
431 | int fd; | 432 | int fd; |
432 | 433 | ||
433 | memset(&attr, 0, sizeof(attr)); | 434 | memset(&attr, 0, sizeof(attr)); |
@@ -440,7 +441,8 @@ static int self_open_counters(void) | |||
440 | 441 | ||
441 | if (fd < 0) | 442 | if (fd < 0) |
442 | pr_err("Error: sys_perf_event_open() syscall returned " | 443 | pr_err("Error: sys_perf_event_open() syscall returned " |
443 | "with %d (%s)\n", fd, strerror(errno)); | 444 | "with %d (%s)\n", fd, |
445 | strerror_r(errno, sbuf, sizeof(sbuf))); | ||
444 | return fd; | 446 | return fd; |
445 | } | 447 | } |
446 | 448 | ||
@@ -1462,6 +1464,8 @@ static int perf_sched__read_events(struct perf_sched *sched, | |||
1462 | return -1; | 1464 | return -1; |
1463 | } | 1465 | } |
1464 | 1466 | ||
1467 | symbol__init(&session->header.env); | ||
1468 | |||
1465 | if (perf_session__set_tracepoints_handlers(session, handlers)) | 1469 | if (perf_session__set_tracepoints_handlers(session, handlers)) |
1466 | goto out_delete; | 1470 | goto out_delete; |
1467 | 1471 | ||
@@ -1662,7 +1666,7 @@ int cmd_sched(int argc, const char **argv, const char *prefix __maybe_unused) | |||
1662 | .comm = perf_event__process_comm, | 1666 | .comm = perf_event__process_comm, |
1663 | .lost = perf_event__process_lost, | 1667 | .lost = perf_event__process_lost, |
1664 | .fork = perf_sched__process_fork_event, | 1668 | .fork = perf_sched__process_fork_event, |
1665 | .ordered_samples = true, | 1669 | .ordered_events = true, |
1666 | }, | 1670 | }, |
1667 | .cmp_pid = LIST_HEAD_INIT(sched.cmp_pid), | 1671 | .cmp_pid = LIST_HEAD_INIT(sched.cmp_pid), |
1668 | .sort_list = LIST_HEAD_INIT(sched.sort_list), | 1672 | .sort_list = LIST_HEAD_INIT(sched.sort_list), |
@@ -1747,7 +1751,6 @@ int cmd_sched(int argc, const char **argv, const char *prefix __maybe_unused) | |||
1747 | if (!strcmp(argv[0], "script")) | 1751 | if (!strcmp(argv[0], "script")) |
1748 | return cmd_script(argc, argv, prefix); | 1752 | return cmd_script(argc, argv, prefix); |
1749 | 1753 | ||
1750 | symbol__init(); | ||
1751 | if (!strncmp(argv[0], "rec", 3)) { | 1754 | if (!strncmp(argv[0], "rec", 3)) { |
1752 | return __cmd_record(argc, argv); | 1755 | return __cmd_record(argc, argv); |
1753 | } else if (!strncmp(argv[0], "lat", 3)) { | 1756 | } else if (!strncmp(argv[0], "lat", 3)) { |
diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c index f57035b89c15..b9b9e58a6c39 100644 --- a/tools/perf/builtin-script.c +++ b/tools/perf/builtin-script.c | |||
@@ -184,10 +184,6 @@ static int perf_evsel__check_attr(struct perf_evsel *evsel, | |||
184 | if (perf_evsel__check_stype(evsel, PERF_SAMPLE_IP, "IP", | 184 | if (perf_evsel__check_stype(evsel, PERF_SAMPLE_IP, "IP", |
185 | PERF_OUTPUT_IP)) | 185 | PERF_OUTPUT_IP)) |
186 | return -EINVAL; | 186 | return -EINVAL; |
187 | |||
188 | if (!no_callchain && | ||
189 | !(attr->sample_type & PERF_SAMPLE_CALLCHAIN)) | ||
190 | symbol_conf.use_callchain = false; | ||
191 | } | 187 | } |
192 | 188 | ||
193 | if (PRINT_FIELD(ADDR) && | 189 | if (PRINT_FIELD(ADDR) && |
@@ -290,6 +286,19 @@ static int perf_session__check_output_opt(struct perf_session *session) | |||
290 | set_print_ip_opts(&evsel->attr); | 286 | set_print_ip_opts(&evsel->attr); |
291 | } | 287 | } |
292 | 288 | ||
289 | if (!no_callchain) { | ||
290 | bool use_callchain = false; | ||
291 | |||
292 | evlist__for_each(session->evlist, evsel) { | ||
293 | if (evsel->attr.sample_type & PERF_SAMPLE_CALLCHAIN) { | ||
294 | use_callchain = true; | ||
295 | break; | ||
296 | } | ||
297 | } | ||
298 | if (!use_callchain) | ||
299 | symbol_conf.use_callchain = false; | ||
300 | } | ||
301 | |||
293 | /* | 302 | /* |
294 | * set default for tracepoints to print symbols only | 303 | * set default for tracepoints to print symbols only |
295 | * if callchains are present | 304 | * if callchains are present |
@@ -476,6 +485,11 @@ static int default_start_script(const char *script __maybe_unused, | |||
476 | return 0; | 485 | return 0; |
477 | } | 486 | } |
478 | 487 | ||
488 | static int default_flush_script(void) | ||
489 | { | ||
490 | return 0; | ||
491 | } | ||
492 | |||
479 | static int default_stop_script(void) | 493 | static int default_stop_script(void) |
480 | { | 494 | { |
481 | return 0; | 495 | return 0; |
@@ -489,6 +503,7 @@ static int default_generate_script(struct pevent *pevent __maybe_unused, | |||
489 | 503 | ||
490 | static struct scripting_ops default_scripting_ops = { | 504 | static struct scripting_ops default_scripting_ops = { |
491 | .start_script = default_start_script, | 505 | .start_script = default_start_script, |
506 | .flush_script = default_flush_script, | ||
492 | .stop_script = default_stop_script, | 507 | .stop_script = default_stop_script, |
493 | .process_event = process_event, | 508 | .process_event = process_event, |
494 | .generate_script = default_generate_script, | 509 | .generate_script = default_generate_script, |
@@ -504,6 +519,11 @@ static void setup_scripting(void) | |||
504 | scripting_ops = &default_scripting_ops; | 519 | scripting_ops = &default_scripting_ops; |
505 | } | 520 | } |
506 | 521 | ||
522 | static int flush_scripting(void) | ||
523 | { | ||
524 | return scripting_ops->flush_script(); | ||
525 | } | ||
526 | |||
507 | static int cleanup_scripting(void) | 527 | static int cleanup_scripting(void) |
508 | { | 528 | { |
509 | pr_debug("\nperf script stopped\n"); | 529 | pr_debug("\nperf script stopped\n"); |
@@ -1471,12 +1491,13 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused) | |||
1471 | bool show_full_info = false; | 1491 | bool show_full_info = false; |
1472 | bool header = false; | 1492 | bool header = false; |
1473 | bool header_only = false; | 1493 | bool header_only = false; |
1494 | bool script_started = false; | ||
1474 | char *rec_script_path = NULL; | 1495 | char *rec_script_path = NULL; |
1475 | char *rep_script_path = NULL; | 1496 | char *rep_script_path = NULL; |
1476 | struct perf_session *session; | 1497 | struct perf_session *session; |
1477 | char *script_path = NULL; | 1498 | char *script_path = NULL; |
1478 | const char **__argv; | 1499 | const char **__argv; |
1479 | int i, j, err; | 1500 | int i, j, err = 0; |
1480 | struct perf_script script = { | 1501 | struct perf_script script = { |
1481 | .tool = { | 1502 | .tool = { |
1482 | .sample = process_sample_event, | 1503 | .sample = process_sample_event, |
@@ -1488,7 +1509,7 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused) | |||
1488 | .attr = process_attr, | 1509 | .attr = process_attr, |
1489 | .tracing_data = perf_event__process_tracing_data, | 1510 | .tracing_data = perf_event__process_tracing_data, |
1490 | .build_id = perf_event__process_build_id, | 1511 | .build_id = perf_event__process_build_id, |
1491 | .ordered_samples = true, | 1512 | .ordered_events = true, |
1492 | .ordering_requires_timestamps = true, | 1513 | .ordering_requires_timestamps = true, |
1493 | }, | 1514 | }, |
1494 | }; | 1515 | }; |
@@ -1718,26 +1739,28 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused) | |||
1718 | exit(-1); | 1739 | exit(-1); |
1719 | } | 1740 | } |
1720 | 1741 | ||
1721 | if (symbol__init() < 0) | ||
1722 | return -1; | ||
1723 | if (!script_name) | 1742 | if (!script_name) |
1724 | setup_pager(); | 1743 | setup_pager(); |
1725 | 1744 | ||
1726 | session = perf_session__new(&file, false, &script.tool); | 1745 | session = perf_session__new(&file, false, &script.tool); |
1727 | if (session == NULL) | 1746 | if (session == NULL) |
1728 | return -ENOMEM; | 1747 | return -1; |
1729 | 1748 | ||
1730 | if (header || header_only) { | 1749 | if (header || header_only) { |
1731 | perf_session__fprintf_info(session, stdout, show_full_info); | 1750 | perf_session__fprintf_info(session, stdout, show_full_info); |
1732 | if (header_only) | 1751 | if (header_only) |
1733 | return 0; | 1752 | goto out_delete; |
1734 | } | 1753 | } |
1735 | 1754 | ||
1755 | if (symbol__init(&session->header.env) < 0) | ||
1756 | goto out_delete; | ||
1757 | |||
1736 | script.session = session; | 1758 | script.session = session; |
1737 | 1759 | ||
1738 | if (cpu_list) { | 1760 | if (cpu_list) { |
1739 | if (perf_session__cpu_bitmap(session, cpu_list, cpu_bitmap)) | 1761 | err = perf_session__cpu_bitmap(session, cpu_list, cpu_bitmap); |
1740 | return -1; | 1762 | if (err < 0) |
1763 | goto out_delete; | ||
1741 | } | 1764 | } |
1742 | 1765 | ||
1743 | if (!no_callchain) | 1766 | if (!no_callchain) |
@@ -1752,53 +1775,62 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused) | |||
1752 | if (output_set_by_user()) { | 1775 | if (output_set_by_user()) { |
1753 | fprintf(stderr, | 1776 | fprintf(stderr, |
1754 | "custom fields not supported for generated scripts"); | 1777 | "custom fields not supported for generated scripts"); |
1755 | return -1; | 1778 | err = -EINVAL; |
1779 | goto out_delete; | ||
1756 | } | 1780 | } |
1757 | 1781 | ||
1758 | input = open(file.path, O_RDONLY); /* input_name */ | 1782 | input = open(file.path, O_RDONLY); /* input_name */ |
1759 | if (input < 0) { | 1783 | if (input < 0) { |
1784 | err = -errno; | ||
1760 | perror("failed to open file"); | 1785 | perror("failed to open file"); |
1761 | return -1; | 1786 | goto out_delete; |
1762 | } | 1787 | } |
1763 | 1788 | ||
1764 | err = fstat(input, &perf_stat); | 1789 | err = fstat(input, &perf_stat); |
1765 | if (err < 0) { | 1790 | if (err < 0) { |
1766 | perror("failed to stat file"); | 1791 | perror("failed to stat file"); |
1767 | return -1; | 1792 | goto out_delete; |
1768 | } | 1793 | } |
1769 | 1794 | ||
1770 | if (!perf_stat.st_size) { | 1795 | if (!perf_stat.st_size) { |
1771 | fprintf(stderr, "zero-sized file, nothing to do!\n"); | 1796 | fprintf(stderr, "zero-sized file, nothing to do!\n"); |
1772 | return 0; | 1797 | goto out_delete; |
1773 | } | 1798 | } |
1774 | 1799 | ||
1775 | scripting_ops = script_spec__lookup(generate_script_lang); | 1800 | scripting_ops = script_spec__lookup(generate_script_lang); |
1776 | if (!scripting_ops) { | 1801 | if (!scripting_ops) { |
1777 | fprintf(stderr, "invalid language specifier"); | 1802 | fprintf(stderr, "invalid language specifier"); |
1778 | return -1; | 1803 | err = -ENOENT; |
1804 | goto out_delete; | ||
1779 | } | 1805 | } |
1780 | 1806 | ||
1781 | err = scripting_ops->generate_script(session->tevent.pevent, | 1807 | err = scripting_ops->generate_script(session->tevent.pevent, |
1782 | "perf-script"); | 1808 | "perf-script"); |
1783 | goto out; | 1809 | goto out_delete; |
1784 | } | 1810 | } |
1785 | 1811 | ||
1786 | if (script_name) { | 1812 | if (script_name) { |
1787 | err = scripting_ops->start_script(script_name, argc, argv); | 1813 | err = scripting_ops->start_script(script_name, argc, argv); |
1788 | if (err) | 1814 | if (err) |
1789 | goto out; | 1815 | goto out_delete; |
1790 | pr_debug("perf script started with script %s\n\n", script_name); | 1816 | pr_debug("perf script started with script %s\n\n", script_name); |
1817 | script_started = true; | ||
1791 | } | 1818 | } |
1792 | 1819 | ||
1793 | 1820 | ||
1794 | err = perf_session__check_output_opt(session); | 1821 | err = perf_session__check_output_opt(session); |
1795 | if (err < 0) | 1822 | if (err < 0) |
1796 | goto out; | 1823 | goto out_delete; |
1797 | 1824 | ||
1798 | err = __cmd_script(&script); | 1825 | err = __cmd_script(&script); |
1799 | 1826 | ||
1827 | flush_scripting(); | ||
1828 | |||
1829 | out_delete: | ||
1800 | perf_session__delete(session); | 1830 | perf_session__delete(session); |
1801 | cleanup_scripting(); | 1831 | |
1832 | if (script_started) | ||
1833 | cleanup_scripting(); | ||
1802 | out: | 1834 | out: |
1803 | return err; | 1835 | return err; |
1804 | } | 1836 | } |
diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index 3e80aa10cfd8..b22c62f80078 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c | |||
@@ -593,7 +593,7 @@ static int __run_perf_stat(int argc, const char **argv) | |||
593 | 593 | ||
594 | if (perf_evlist__apply_filters(evsel_list)) { | 594 | if (perf_evlist__apply_filters(evsel_list)) { |
595 | error("failed to set filter with %d (%s)\n", errno, | 595 | error("failed to set filter with %d (%s)\n", errno, |
596 | strerror(errno)); | 596 | strerror_r(errno, msg, sizeof(msg))); |
597 | return -1; | 597 | return -1; |
598 | } | 598 | } |
599 | 599 | ||
@@ -732,7 +732,7 @@ static void aggr_printout(struct perf_evsel *evsel, int id, int nr) | |||
732 | } | 732 | } |
733 | } | 733 | } |
734 | 734 | ||
735 | static void nsec_printout(int cpu, int nr, struct perf_evsel *evsel, double avg) | 735 | static void nsec_printout(int id, int nr, struct perf_evsel *evsel, double avg) |
736 | { | 736 | { |
737 | double msecs = avg / 1e6; | 737 | double msecs = avg / 1e6; |
738 | const char *fmt_v, *fmt_n; | 738 | const char *fmt_v, *fmt_n; |
@@ -741,7 +741,7 @@ static void nsec_printout(int cpu, int nr, struct perf_evsel *evsel, double avg) | |||
741 | fmt_v = csv_output ? "%.6f%s" : "%18.6f%s"; | 741 | fmt_v = csv_output ? "%.6f%s" : "%18.6f%s"; |
742 | fmt_n = csv_output ? "%s" : "%-25s"; | 742 | fmt_n = csv_output ? "%s" : "%-25s"; |
743 | 743 | ||
744 | aggr_printout(evsel, cpu, nr); | 744 | aggr_printout(evsel, id, nr); |
745 | 745 | ||
746 | scnprintf(name, sizeof(name), "%s%s", | 746 | scnprintf(name, sizeof(name), "%s%s", |
747 | perf_evsel__name(evsel), csv_output ? "" : " (msec)"); | 747 | perf_evsel__name(evsel), csv_output ? "" : " (msec)"); |
@@ -947,11 +947,12 @@ static void print_ll_cache_misses(int cpu, | |||
947 | fprintf(output, " of all LL-cache hits "); | 947 | fprintf(output, " of all LL-cache hits "); |
948 | } | 948 | } |
949 | 949 | ||
950 | static void abs_printout(int cpu, int nr, struct perf_evsel *evsel, double avg) | 950 | static void abs_printout(int id, int nr, struct perf_evsel *evsel, double avg) |
951 | { | 951 | { |
952 | double total, ratio = 0.0, total2; | 952 | double total, ratio = 0.0, total2; |
953 | double sc = evsel->scale; | 953 | double sc = evsel->scale; |
954 | const char *fmt; | 954 | const char *fmt; |
955 | int cpu = cpu_map__id_to_cpu(id); | ||
955 | 956 | ||
956 | if (csv_output) { | 957 | if (csv_output) { |
957 | fmt = sc != 1.0 ? "%.2f%s" : "%.0f%s"; | 958 | fmt = sc != 1.0 ? "%.2f%s" : "%.0f%s"; |
@@ -962,7 +963,7 @@ static void abs_printout(int cpu, int nr, struct perf_evsel *evsel, double avg) | |||
962 | fmt = sc != 1.0 ? "%18.2f%s" : "%18.0f%s"; | 963 | fmt = sc != 1.0 ? "%18.2f%s" : "%18.0f%s"; |
963 | } | 964 | } |
964 | 965 | ||
965 | aggr_printout(evsel, cpu, nr); | 966 | aggr_printout(evsel, id, nr); |
966 | 967 | ||
967 | if (aggr_mode == AGGR_GLOBAL) | 968 | if (aggr_mode == AGGR_GLOBAL) |
968 | cpu = 0; | 969 | cpu = 0; |
diff --git a/tools/perf/builtin-timechart.c b/tools/perf/builtin-timechart.c index 2f1a5220c090..35b425b6293f 100644 --- a/tools/perf/builtin-timechart.c +++ b/tools/perf/builtin-timechart.c | |||
@@ -1605,7 +1605,9 @@ static int __cmd_timechart(struct timechart *tchart, const char *output_name) | |||
1605 | int ret = -EINVAL; | 1605 | int ret = -EINVAL; |
1606 | 1606 | ||
1607 | if (session == NULL) | 1607 | if (session == NULL) |
1608 | return -ENOMEM; | 1608 | return -1; |
1609 | |||
1610 | symbol__init(&session->header.env); | ||
1609 | 1611 | ||
1610 | (void)perf_header__process_sections(&session->header, | 1612 | (void)perf_header__process_sections(&session->header, |
1611 | perf_data_file__fd(session->file), | 1613 | perf_data_file__fd(session->file), |
@@ -1920,7 +1922,7 @@ int cmd_timechart(int argc, const char **argv, | |||
1920 | .fork = process_fork_event, | 1922 | .fork = process_fork_event, |
1921 | .exit = process_exit_event, | 1923 | .exit = process_exit_event, |
1922 | .sample = process_sample_event, | 1924 | .sample = process_sample_event, |
1923 | .ordered_samples = true, | 1925 | .ordered_events = true, |
1924 | }, | 1926 | }, |
1925 | .proc_num = 15, | 1927 | .proc_num = 15, |
1926 | .min_time = 1000000, | 1928 | .min_time = 1000000, |
@@ -1982,8 +1984,6 @@ int cmd_timechart(int argc, const char **argv, | |||
1982 | return -1; | 1984 | return -1; |
1983 | } | 1985 | } |
1984 | 1986 | ||
1985 | symbol__init(); | ||
1986 | |||
1987 | if (argc && !strncmp(argv[0], "rec", 3)) { | 1987 | if (argc && !strncmp(argv[0], "rec", 3)) { |
1988 | argc = parse_options(argc, argv, record_options, record_usage, | 1988 | argc = parse_options(argc, argv, record_options, record_usage, |
1989 | PARSE_OPT_STOP_AT_NON_OPTION); | 1989 | PARSE_OPT_STOP_AT_NON_OPTION); |
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index 377971dc89a3..fc3d55f832ac 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c | |||
@@ -59,7 +59,7 @@ | |||
59 | 59 | ||
60 | #include <sys/syscall.h> | 60 | #include <sys/syscall.h> |
61 | #include <sys/ioctl.h> | 61 | #include <sys/ioctl.h> |
62 | #include <sys/poll.h> | 62 | #include <poll.h> |
63 | #include <sys/prctl.h> | 63 | #include <sys/prctl.h> |
64 | #include <sys/wait.h> | 64 | #include <sys/wait.h> |
65 | #include <sys/uio.h> | 65 | #include <sys/uio.h> |
@@ -276,11 +276,17 @@ static void perf_top__print_sym_table(struct perf_top *top) | |||
276 | return; | 276 | return; |
277 | } | 277 | } |
278 | 278 | ||
279 | if (top->zero) { | ||
280 | hists__delete_entries(&top->sym_evsel->hists); | ||
281 | } else { | ||
282 | hists__decay_entries(&top->sym_evsel->hists, | ||
283 | top->hide_user_symbols, | ||
284 | top->hide_kernel_symbols); | ||
285 | } | ||
286 | |||
279 | hists__collapse_resort(&top->sym_evsel->hists, NULL); | 287 | hists__collapse_resort(&top->sym_evsel->hists, NULL); |
280 | hists__output_resort(&top->sym_evsel->hists); | 288 | hists__output_resort(&top->sym_evsel->hists); |
281 | hists__decay_entries(&top->sym_evsel->hists, | 289 | |
282 | top->hide_user_symbols, | ||
283 | top->hide_kernel_symbols); | ||
284 | hists__output_recalc_col_len(&top->sym_evsel->hists, | 290 | hists__output_recalc_col_len(&top->sym_evsel->hists, |
285 | top->print_entries - printed); | 291 | top->print_entries - printed); |
286 | putchar('\n'); | 292 | putchar('\n'); |
@@ -427,18 +433,13 @@ static bool perf_top__handle_keypress(struct perf_top *top, int c) | |||
427 | 433 | ||
428 | if (!perf_top__key_mapped(top, c)) { | 434 | if (!perf_top__key_mapped(top, c)) { |
429 | struct pollfd stdin_poll = { .fd = 0, .events = POLLIN }; | 435 | struct pollfd stdin_poll = { .fd = 0, .events = POLLIN }; |
430 | struct termios tc, save; | 436 | struct termios save; |
431 | 437 | ||
432 | perf_top__print_mapped_keys(top); | 438 | perf_top__print_mapped_keys(top); |
433 | fprintf(stdout, "\nEnter selection, or unmapped key to continue: "); | 439 | fprintf(stdout, "\nEnter selection, or unmapped key to continue: "); |
434 | fflush(stdout); | 440 | fflush(stdout); |
435 | 441 | ||
436 | tcgetattr(0, &save); | 442 | set_term_quiet_input(&save); |
437 | tc = save; | ||
438 | tc.c_lflag &= ~(ICANON | ECHO); | ||
439 | tc.c_cc[VMIN] = 0; | ||
440 | tc.c_cc[VTIME] = 0; | ||
441 | tcsetattr(0, TCSANOW, &tc); | ||
442 | 443 | ||
443 | poll(&stdin_poll, 1, -1); | 444 | poll(&stdin_poll, 1, -1); |
444 | c = getc(stdin); | 445 | c = getc(stdin); |
@@ -542,11 +543,16 @@ static void perf_top__sort_new_samples(void *arg) | |||
542 | if (t->evlist->selected != NULL) | 543 | if (t->evlist->selected != NULL) |
543 | t->sym_evsel = t->evlist->selected; | 544 | t->sym_evsel = t->evlist->selected; |
544 | 545 | ||
546 | if (t->zero) { | ||
547 | hists__delete_entries(&t->sym_evsel->hists); | ||
548 | } else { | ||
549 | hists__decay_entries(&t->sym_evsel->hists, | ||
550 | t->hide_user_symbols, | ||
551 | t->hide_kernel_symbols); | ||
552 | } | ||
553 | |||
545 | hists__collapse_resort(&t->sym_evsel->hists, NULL); | 554 | hists__collapse_resort(&t->sym_evsel->hists, NULL); |
546 | hists__output_resort(&t->sym_evsel->hists); | 555 | hists__output_resort(&t->sym_evsel->hists); |
547 | hists__decay_entries(&t->sym_evsel->hists, | ||
548 | t->hide_user_symbols, | ||
549 | t->hide_kernel_symbols); | ||
550 | } | 556 | } |
551 | 557 | ||
552 | static void *display_thread_tui(void *arg) | 558 | static void *display_thread_tui(void *arg) |
@@ -577,23 +583,32 @@ static void *display_thread_tui(void *arg) | |||
577 | return NULL; | 583 | return NULL; |
578 | } | 584 | } |
579 | 585 | ||
586 | static void display_sig(int sig __maybe_unused) | ||
587 | { | ||
588 | done = 1; | ||
589 | } | ||
590 | |||
591 | static void display_setup_sig(void) | ||
592 | { | ||
593 | signal(SIGSEGV, display_sig); | ||
594 | signal(SIGFPE, display_sig); | ||
595 | signal(SIGINT, display_sig); | ||
596 | signal(SIGQUIT, display_sig); | ||
597 | signal(SIGTERM, display_sig); | ||
598 | } | ||
599 | |||
580 | static void *display_thread(void *arg) | 600 | static void *display_thread(void *arg) |
581 | { | 601 | { |
582 | struct pollfd stdin_poll = { .fd = 0, .events = POLLIN }; | 602 | struct pollfd stdin_poll = { .fd = 0, .events = POLLIN }; |
583 | struct termios tc, save; | 603 | struct termios save; |
584 | struct perf_top *top = arg; | 604 | struct perf_top *top = arg; |
585 | int delay_msecs, c; | 605 | int delay_msecs, c; |
586 | 606 | ||
587 | tcgetattr(0, &save); | 607 | display_setup_sig(); |
588 | tc = save; | ||
589 | tc.c_lflag &= ~(ICANON | ECHO); | ||
590 | tc.c_cc[VMIN] = 0; | ||
591 | tc.c_cc[VTIME] = 0; | ||
592 | |||
593 | pthread__unblock_sigwinch(); | 608 | pthread__unblock_sigwinch(); |
594 | repeat: | 609 | repeat: |
595 | delay_msecs = top->delay_secs * 1000; | 610 | delay_msecs = top->delay_secs * 1000; |
596 | tcsetattr(0, TCSANOW, &tc); | 611 | set_term_quiet_input(&save); |
597 | /* trash return*/ | 612 | /* trash return*/ |
598 | getc(stdin); | 613 | getc(stdin); |
599 | 614 | ||
@@ -620,13 +635,16 @@ repeat: | |||
620 | } | 635 | } |
621 | } | 636 | } |
622 | 637 | ||
638 | tcsetattr(0, TCSAFLUSH, &save); | ||
623 | return NULL; | 639 | return NULL; |
624 | } | 640 | } |
625 | 641 | ||
626 | static int symbol_filter(struct map *map __maybe_unused, struct symbol *sym) | 642 | static int symbol_filter(struct map *map, struct symbol *sym) |
627 | { | 643 | { |
628 | const char *name = sym->name; | 644 | const char *name = sym->name; |
629 | 645 | ||
646 | if (!map->dso->kernel) | ||
647 | return 0; | ||
630 | /* | 648 | /* |
631 | * ppc64 uses function descriptors and appends a '.' to the | 649 | * ppc64 uses function descriptors and appends a '.' to the |
632 | * start of every instruction address. Remove it. | 650 | * start of every instruction address. Remove it. |
@@ -876,7 +894,7 @@ try_again: | |||
876 | 894 | ||
877 | if (perf_evlist__mmap(evlist, opts->mmap_pages, false) < 0) { | 895 | if (perf_evlist__mmap(evlist, opts->mmap_pages, false) < 0) { |
878 | ui__error("Failed to mmap with %d (%s)\n", | 896 | ui__error("Failed to mmap with %d (%s)\n", |
879 | errno, strerror(errno)); | 897 | errno, strerror_r(errno, msg, sizeof(msg))); |
880 | goto out_err; | 898 | goto out_err; |
881 | } | 899 | } |
882 | 900 | ||
@@ -911,7 +929,7 @@ static int __cmd_top(struct perf_top *top) | |||
911 | 929 | ||
912 | top->session = perf_session__new(NULL, false, NULL); | 930 | top->session = perf_session__new(NULL, false, NULL); |
913 | if (top->session == NULL) | 931 | if (top->session == NULL) |
914 | return -ENOMEM; | 932 | return -1; |
915 | 933 | ||
916 | machines__set_symbol_filter(&top->session->machines, symbol_filter); | 934 | machines__set_symbol_filter(&top->session->machines, symbol_filter); |
917 | 935 | ||
@@ -946,7 +964,7 @@ static int __cmd_top(struct perf_top *top) | |||
946 | perf_evlist__enable(top->evlist); | 964 | perf_evlist__enable(top->evlist); |
947 | 965 | ||
948 | /* Wait for a minimal set of events before starting the snapshot */ | 966 | /* Wait for a minimal set of events before starting the snapshot */ |
949 | poll(top->evlist->pollfd, top->evlist->nr_fds, 100); | 967 | perf_evlist__poll(top->evlist, 100); |
950 | 968 | ||
951 | perf_top__mmap_read(top); | 969 | perf_top__mmap_read(top); |
952 | 970 | ||
@@ -963,7 +981,7 @@ static int __cmd_top(struct perf_top *top) | |||
963 | param.sched_priority = top->realtime_prio; | 981 | param.sched_priority = top->realtime_prio; |
964 | if (sched_setscheduler(0, SCHED_FIFO, ¶m)) { | 982 | if (sched_setscheduler(0, SCHED_FIFO, ¶m)) { |
965 | ui__error("Could not set realtime priority.\n"); | 983 | ui__error("Could not set realtime priority.\n"); |
966 | goto out_delete; | 984 | goto out_join; |
967 | } | 985 | } |
968 | } | 986 | } |
969 | 987 | ||
@@ -973,10 +991,12 @@ static int __cmd_top(struct perf_top *top) | |||
973 | perf_top__mmap_read(top); | 991 | perf_top__mmap_read(top); |
974 | 992 | ||
975 | if (hits == top->samples) | 993 | if (hits == top->samples) |
976 | ret = poll(top->evlist->pollfd, top->evlist->nr_fds, 100); | 994 | ret = perf_evlist__poll(top->evlist, 100); |
977 | } | 995 | } |
978 | 996 | ||
979 | ret = 0; | 997 | ret = 0; |
998 | out_join: | ||
999 | pthread_join(thread, NULL); | ||
980 | out_delete: | 1000 | out_delete: |
981 | perf_session__delete(top->session); | 1001 | perf_session__delete(top->session); |
982 | top->session = NULL; | 1002 | top->session = NULL; |
@@ -1000,10 +1020,8 @@ parse_callchain_opt(const struct option *opt, const char *arg, int unset) | |||
1000 | 1020 | ||
1001 | static int perf_top_config(const char *var, const char *value, void *cb) | 1021 | static int perf_top_config(const char *var, const char *value, void *cb) |
1002 | { | 1022 | { |
1003 | struct perf_top *top = cb; | ||
1004 | |||
1005 | if (!strcmp(var, "top.call-graph")) | 1023 | if (!strcmp(var, "top.call-graph")) |
1006 | return record_parse_callchain(value, &top->record_opts); | 1024 | var = "call-graph.record-mode"; /* fall-through */ |
1007 | if (!strcmp(var, "top.children")) { | 1025 | if (!strcmp(var, "top.children")) { |
1008 | symbol_conf.cumulate_callchain = perf_config_bool(var, value); | 1026 | symbol_conf.cumulate_callchain = perf_config_bool(var, value); |
1009 | return 0; | 1027 | return 0; |
@@ -1122,6 +1140,8 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused) | |||
1122 | "Interleave source code with assembly code (default)"), | 1140 | "Interleave source code with assembly code (default)"), |
1123 | OPT_BOOLEAN(0, "asm-raw", &symbol_conf.annotate_asm_raw, | 1141 | OPT_BOOLEAN(0, "asm-raw", &symbol_conf.annotate_asm_raw, |
1124 | "Display raw encoding of assembly instructions (default)"), | 1142 | "Display raw encoding of assembly instructions (default)"), |
1143 | OPT_BOOLEAN(0, "demangle-kernel", &symbol_conf.demangle_kernel, | ||
1144 | "Enable kernel symbol demangling"), | ||
1125 | OPT_STRING(0, "objdump", &objdump_path, "path", | 1145 | OPT_STRING(0, "objdump", &objdump_path, "path", |
1126 | "objdump binary to use for disassembly and annotations"), | 1146 | "objdump binary to use for disassembly and annotations"), |
1127 | OPT_STRING('M', "disassembler-style", &disassembler_style, "disassembler style", | 1147 | OPT_STRING('M', "disassembler-style", &disassembler_style, "disassembler style", |
@@ -1131,6 +1151,9 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused) | |||
1131 | "Don't show entries under that percent", parse_percent_limit), | 1151 | "Don't show entries under that percent", parse_percent_limit), |
1132 | OPT_CALLBACK(0, "percentage", NULL, "relative|absolute", | 1152 | OPT_CALLBACK(0, "percentage", NULL, "relative|absolute", |
1133 | "How to display percentage of filtered entries", parse_filter_percentage), | 1153 | "How to display percentage of filtered entries", parse_filter_percentage), |
1154 | OPT_STRING('w', "column-widths", &symbol_conf.col_width_list_str, | ||
1155 | "width[,width...]", | ||
1156 | "don't try to adjust column width, use these fixed values"), | ||
1134 | OPT_END() | 1157 | OPT_END() |
1135 | }; | 1158 | }; |
1136 | const char * const top_usage[] = { | 1159 | const char * const top_usage[] = { |
@@ -1217,7 +1240,7 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused) | |||
1217 | symbol_conf.priv_size = sizeof(struct annotation); | 1240 | symbol_conf.priv_size = sizeof(struct annotation); |
1218 | 1241 | ||
1219 | symbol_conf.try_vmlinux_path = (symbol_conf.vmlinux_name == NULL); | 1242 | symbol_conf.try_vmlinux_path = (symbol_conf.vmlinux_name == NULL); |
1220 | if (symbol__init() < 0) | 1243 | if (symbol__init(NULL) < 0) |
1221 | return -1; | 1244 | return -1; |
1222 | 1245 | ||
1223 | sort__setup_elide(stdout); | 1246 | sort__setup_elide(stdout); |
diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c index a6c375224f46..09bcf2393910 100644 --- a/tools/perf/builtin-trace.c +++ b/tools/perf/builtin-trace.c | |||
@@ -402,6 +402,31 @@ static size_t syscall_arg__scnprintf_mmap_flags(char *bf, size_t size, | |||
402 | 402 | ||
403 | #define SCA_MMAP_FLAGS syscall_arg__scnprintf_mmap_flags | 403 | #define SCA_MMAP_FLAGS syscall_arg__scnprintf_mmap_flags |
404 | 404 | ||
405 | static size_t syscall_arg__scnprintf_mremap_flags(char *bf, size_t size, | ||
406 | struct syscall_arg *arg) | ||
407 | { | ||
408 | int printed = 0, flags = arg->val; | ||
409 | |||
410 | #define P_MREMAP_FLAG(n) \ | ||
411 | if (flags & MREMAP_##n) { \ | ||
412 | printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \ | ||
413 | flags &= ~MREMAP_##n; \ | ||
414 | } | ||
415 | |||
416 | P_MREMAP_FLAG(MAYMOVE); | ||
417 | #ifdef MREMAP_FIXED | ||
418 | P_MREMAP_FLAG(FIXED); | ||
419 | #endif | ||
420 | #undef P_MREMAP_FLAG | ||
421 | |||
422 | if (flags) | ||
423 | printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags); | ||
424 | |||
425 | return printed; | ||
426 | } | ||
427 | |||
428 | #define SCA_MREMAP_FLAGS syscall_arg__scnprintf_mremap_flags | ||
429 | |||
405 | static size_t syscall_arg__scnprintf_madvise_behavior(char *bf, size_t size, | 430 | static size_t syscall_arg__scnprintf_madvise_behavior(char *bf, size_t size, |
406 | struct syscall_arg *arg) | 431 | struct syscall_arg *arg) |
407 | { | 432 | { |
@@ -1004,6 +1029,7 @@ static struct syscall_fmt { | |||
1004 | [2] = SCA_MMAP_PROT, /* prot */ }, }, | 1029 | [2] = SCA_MMAP_PROT, /* prot */ }, }, |
1005 | { .name = "mremap", .hexret = true, | 1030 | { .name = "mremap", .hexret = true, |
1006 | .arg_scnprintf = { [0] = SCA_HEX, /* addr */ | 1031 | .arg_scnprintf = { [0] = SCA_HEX, /* addr */ |
1032 | [3] = SCA_MREMAP_FLAGS, /* flags */ | ||
1007 | [4] = SCA_HEX, /* new_addr */ }, }, | 1033 | [4] = SCA_HEX, /* new_addr */ }, }, |
1008 | { .name = "munlock", .errmsg = true, | 1034 | { .name = "munlock", .errmsg = true, |
1009 | .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, }, | 1035 | .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, }, |
@@ -1385,7 +1411,7 @@ static int trace__tool_process(struct perf_tool *tool, | |||
1385 | 1411 | ||
1386 | static int trace__symbols_init(struct trace *trace, struct perf_evlist *evlist) | 1412 | static int trace__symbols_init(struct trace *trace, struct perf_evlist *evlist) |
1387 | { | 1413 | { |
1388 | int err = symbol__init(); | 1414 | int err = symbol__init(NULL); |
1389 | 1415 | ||
1390 | if (err) | 1416 | if (err) |
1391 | return err; | 1417 | return err; |
@@ -1669,7 +1695,7 @@ static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel, | |||
1669 | union perf_event *event __maybe_unused, | 1695 | union perf_event *event __maybe_unused, |
1670 | struct perf_sample *sample) | 1696 | struct perf_sample *sample) |
1671 | { | 1697 | { |
1672 | int ret; | 1698 | long ret; |
1673 | u64 duration = 0; | 1699 | u64 duration = 0; |
1674 | struct thread *thread; | 1700 | struct thread *thread; |
1675 | int id = perf_evsel__sc_tp_uint(evsel, id, sample); | 1701 | int id = perf_evsel__sc_tp_uint(evsel, id, sample); |
@@ -1722,9 +1748,9 @@ static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel, | |||
1722 | 1748 | ||
1723 | if (sc->fmt == NULL) { | 1749 | if (sc->fmt == NULL) { |
1724 | signed_print: | 1750 | signed_print: |
1725 | fprintf(trace->output, ") = %d", ret); | 1751 | fprintf(trace->output, ") = %ld", ret); |
1726 | } else if (ret < 0 && sc->fmt->errmsg) { | 1752 | } else if (ret < 0 && sc->fmt->errmsg) { |
1727 | char bf[256]; | 1753 | char bf[STRERR_BUFSIZE]; |
1728 | const char *emsg = strerror_r(-ret, bf, sizeof(bf)), | 1754 | const char *emsg = strerror_r(-ret, bf, sizeof(bf)), |
1729 | *e = audit_errno_to_name(-ret); | 1755 | *e = audit_errno_to_name(-ret); |
1730 | 1756 | ||
@@ -1732,7 +1758,7 @@ signed_print: | |||
1732 | } else if (ret == 0 && sc->fmt->timeout) | 1758 | } else if (ret == 0 && sc->fmt->timeout) |
1733 | fprintf(trace->output, ") = 0 Timeout"); | 1759 | fprintf(trace->output, ") = 0 Timeout"); |
1734 | else if (sc->fmt->hexret) | 1760 | else if (sc->fmt->hexret) |
1735 | fprintf(trace->output, ") = %#x", ret); | 1761 | fprintf(trace->output, ") = %#lx", ret); |
1736 | else | 1762 | else |
1737 | goto signed_print; | 1763 | goto signed_print; |
1738 | 1764 | ||
@@ -2018,6 +2044,8 @@ static int trace__run(struct trace *trace, int argc, const char **argv) | |||
2018 | int err = -1, i; | 2044 | int err = -1, i; |
2019 | unsigned long before; | 2045 | unsigned long before; |
2020 | const bool forks = argc > 0; | 2046 | const bool forks = argc > 0; |
2047 | bool draining = false; | ||
2048 | char sbuf[STRERR_BUFSIZE]; | ||
2021 | 2049 | ||
2022 | trace->live = true; | 2050 | trace->live = true; |
2023 | 2051 | ||
@@ -2079,7 +2107,8 @@ static int trace__run(struct trace *trace, int argc, const char **argv) | |||
2079 | 2107 | ||
2080 | err = perf_evlist__mmap(evlist, trace->opts.mmap_pages, false); | 2108 | err = perf_evlist__mmap(evlist, trace->opts.mmap_pages, false); |
2081 | if (err < 0) { | 2109 | if (err < 0) { |
2082 | fprintf(trace->output, "Couldn't mmap the events: %s\n", strerror(errno)); | 2110 | fprintf(trace->output, "Couldn't mmap the events: %s\n", |
2111 | strerror_r(errno, sbuf, sizeof(sbuf))); | ||
2083 | goto out_delete_evlist; | 2112 | goto out_delete_evlist; |
2084 | } | 2113 | } |
2085 | 2114 | ||
@@ -2143,8 +2172,12 @@ next_event: | |||
2143 | if (trace->nr_events == before) { | 2172 | if (trace->nr_events == before) { |
2144 | int timeout = done ? 100 : -1; | 2173 | int timeout = done ? 100 : -1; |
2145 | 2174 | ||
2146 | if (poll(evlist->pollfd, evlist->nr_fds, timeout) > 0) | 2175 | if (!draining && perf_evlist__poll(evlist, timeout) > 0) { |
2176 | if (perf_evlist__filter_pollfd(evlist, POLLERR | POLLHUP) == 0) | ||
2177 | draining = true; | ||
2178 | |||
2147 | goto again; | 2179 | goto again; |
2180 | } | ||
2148 | } else { | 2181 | } else { |
2149 | goto again; | 2182 | goto again; |
2150 | } | 2183 | } |
@@ -2209,18 +2242,18 @@ static int trace__replay(struct trace *trace) | |||
2209 | trace->tool.tracing_data = perf_event__process_tracing_data; | 2242 | trace->tool.tracing_data = perf_event__process_tracing_data; |
2210 | trace->tool.build_id = perf_event__process_build_id; | 2243 | trace->tool.build_id = perf_event__process_build_id; |
2211 | 2244 | ||
2212 | trace->tool.ordered_samples = true; | 2245 | trace->tool.ordered_events = true; |
2213 | trace->tool.ordering_requires_timestamps = true; | 2246 | trace->tool.ordering_requires_timestamps = true; |
2214 | 2247 | ||
2215 | /* add tid to output */ | 2248 | /* add tid to output */ |
2216 | trace->multiple_threads = true; | 2249 | trace->multiple_threads = true; |
2217 | 2250 | ||
2218 | if (symbol__init() < 0) | ||
2219 | return -1; | ||
2220 | |||
2221 | session = perf_session__new(&file, false, &trace->tool); | 2251 | session = perf_session__new(&file, false, &trace->tool); |
2222 | if (session == NULL) | 2252 | if (session == NULL) |
2223 | return -ENOMEM; | 2253 | return -1; |
2254 | |||
2255 | if (symbol__init(&session->header.env) < 0) | ||
2256 | goto out; | ||
2224 | 2257 | ||
2225 | trace->host = &session->machines.host; | 2258 | trace->host = &session->machines.host; |
2226 | 2259 | ||
diff --git a/tools/perf/config/Makefile b/tools/perf/config/Makefile index 1f67aa02d240..58f609198c6d 100644 --- a/tools/perf/config/Makefile +++ b/tools/perf/config/Makefile | |||
@@ -48,10 +48,6 @@ ifneq ($(ARCH),$(filter $(ARCH),x86 arm)) | |||
48 | NO_LIBDW_DWARF_UNWIND := 1 | 48 | NO_LIBDW_DWARF_UNWIND := 1 |
49 | endif | 49 | endif |
50 | 50 | ||
51 | ifeq ($(ARCH),powerpc) | ||
52 | CFLAGS += -DHAVE_SKIP_CALLCHAIN_IDX | ||
53 | endif | ||
54 | |||
55 | ifeq ($(LIBUNWIND_LIBS),) | 51 | ifeq ($(LIBUNWIND_LIBS),) |
56 | NO_LIBUNWIND := 1 | 52 | NO_LIBUNWIND := 1 |
57 | else | 53 | else |
@@ -120,6 +116,29 @@ ifdef PARSER_DEBUG | |||
120 | CFLAGS += -DPARSER_DEBUG | 116 | CFLAGS += -DPARSER_DEBUG |
121 | endif | 117 | endif |
122 | 118 | ||
119 | ifndef NO_LIBPYTHON | ||
120 | # Try different combinations to accommodate systems that only have | ||
121 | # python[2][-config] in weird combinations but always preferring | ||
122 | # python2 and python2-config as per pep-0394. If we catch a | ||
123 | # python[-config] in version 3, the version check will kill it. | ||
124 | PYTHON2 := $(if $(call get-executable,python2),python2,python) | ||
125 | override PYTHON := $(call get-executable-or-default,PYTHON,$(PYTHON2)) | ||
126 | PYTHON2_CONFIG := \ | ||
127 | $(if $(call get-executable,$(PYTHON)-config),$(PYTHON)-config,python-config) | ||
128 | override PYTHON_CONFIG := \ | ||
129 | $(call get-executable-or-default,PYTHON_CONFIG,$(PYTHON2_CONFIG)) | ||
130 | |||
131 | PYTHON_CONFIG_SQ := $(call shell-sq,$(PYTHON_CONFIG)) | ||
132 | |||
133 | PYTHON_EMBED_LDOPTS := $(shell $(PYTHON_CONFIG_SQ) --ldflags 2>/dev/null) | ||
134 | PYTHON_EMBED_CCOPTS := $(shell $(PYTHON_CONFIG_SQ) --cflags 2>/dev/null) | ||
135 | |||
136 | FEATURE_CHECK_CFLAGS-libpython := $(PYTHON_EMBED_CCOPTS) | ||
137 | FEATURE_CHECK_LDFLAGS-libpython := $(PYTHON_EMBED_LDOPTS) | ||
138 | FEATURE_CHECK_CFLAGS-libpython-version := $(PYTHON_EMBED_CCOPTS) | ||
139 | FEATURE_CHECK_LDFLAGS-libpython-version := $(PYTHON_EMBED_LDOPTS) | ||
140 | endif | ||
141 | |||
123 | CFLAGS += -fno-omit-frame-pointer | 142 | CFLAGS += -fno-omit-frame-pointer |
124 | CFLAGS += -ggdb3 | 143 | CFLAGS += -ggdb3 |
125 | CFLAGS += -funwind-tables | 144 | CFLAGS += -funwind-tables |
@@ -355,6 +374,12 @@ ifndef NO_LIBELF | |||
355 | endif # NO_DWARF | 374 | endif # NO_DWARF |
356 | endif # NO_LIBELF | 375 | endif # NO_LIBELF |
357 | 376 | ||
377 | ifeq ($(ARCH),powerpc) | ||
378 | ifndef NO_DWARF | ||
379 | CFLAGS += -DHAVE_SKIP_CALLCHAIN_IDX | ||
380 | endif | ||
381 | endif | ||
382 | |||
358 | ifndef NO_LIBUNWIND | 383 | ifndef NO_LIBUNWIND |
359 | ifneq ($(feature-libunwind), 1) | 384 | ifneq ($(feature-libunwind), 1) |
360 | msg := $(warning No libunwind found. Please install libunwind-dev[el] >= 1.1 and/or set LIBUNWIND_DIR); | 385 | msg := $(warning No libunwind found. Please install libunwind-dev[el] >= 1.1 and/or set LIBUNWIND_DIR); |
@@ -482,21 +507,14 @@ define disable-python_code | |||
482 | NO_LIBPYTHON := 1 | 507 | NO_LIBPYTHON := 1 |
483 | endef | 508 | endef |
484 | 509 | ||
485 | override PYTHON := \ | 510 | ifdef NO_LIBPYTHON |
486 | $(call get-executable-or-default,PYTHON,python) | 511 | $(call disable-python) |
487 | |||
488 | ifndef PYTHON | ||
489 | $(call disable-python,python interpreter) | ||
490 | else | 512 | else |
491 | 513 | ||
492 | PYTHON_WORD := $(call shell-wordify,$(PYTHON)) | 514 | ifndef PYTHON |
493 | 515 | $(call disable-python,python interpreter) | |
494 | ifdef NO_LIBPYTHON | ||
495 | $(call disable-python) | ||
496 | else | 516 | else |
497 | 517 | PYTHON_WORD := $(call shell-wordify,$(PYTHON)) | |
498 | override PYTHON_CONFIG := \ | ||
499 | $(call get-executable-or-default,PYTHON_CONFIG,$(PYTHON)-config) | ||
500 | 518 | ||
501 | ifndef PYTHON_CONFIG | 519 | ifndef PYTHON_CONFIG |
502 | $(call disable-python,python-config tool) | 520 | $(call disable-python,python-config tool) |
@@ -635,11 +653,13 @@ else | |||
635 | sysconfdir = $(prefix)/etc | 653 | sysconfdir = $(prefix)/etc |
636 | ETC_PERFCONFIG = etc/perfconfig | 654 | ETC_PERFCONFIG = etc/perfconfig |
637 | endif | 655 | endif |
656 | ifndef lib | ||
638 | ifeq ($(IS_X86_64),1) | 657 | ifeq ($(IS_X86_64),1) |
639 | lib = lib64 | 658 | lib = lib64 |
640 | else | 659 | else |
641 | lib = lib | 660 | lib = lib |
642 | endif | 661 | endif |
662 | endif # lib | ||
643 | libdir = $(prefix)/$(lib) | 663 | libdir = $(prefix)/$(lib) |
644 | 664 | ||
645 | # Shell quote (do not use $(call) to accommodate ancient setups); | 665 | # Shell quote (do not use $(call) to accommodate ancient setups); |
diff --git a/tools/perf/config/feature-checks/Makefile b/tools/perf/config/feature-checks/Makefile index 6088f8d8a434..72ab2984718e 100644 --- a/tools/perf/config/feature-checks/Makefile +++ b/tools/perf/config/feature-checks/Makefile | |||
@@ -101,25 +101,11 @@ FLAGS_PERL_EMBED=$(PERL_EMBED_CCOPTS) $(PERL_EMBED_LDOPTS) | |||
101 | test-libperl.bin: | 101 | test-libperl.bin: |
102 | $(BUILD) $(FLAGS_PERL_EMBED) | 102 | $(BUILD) $(FLAGS_PERL_EMBED) |
103 | 103 | ||
104 | override PYTHON := python | ||
105 | override PYTHON_CONFIG := python-config | ||
106 | |||
107 | escape-for-shell-sq = $(subst ','\'',$(1)) | ||
108 | shell-sq = '$(escape-for-shell-sq)' | ||
109 | |||
110 | PYTHON_CONFIG_SQ = $(call shell-sq,$(PYTHON_CONFIG)) | ||
111 | |||
112 | PYTHON_EMBED_LDOPTS = $(shell $(PYTHON_CONFIG_SQ) --ldflags 2>/dev/null) | ||
113 | PYTHON_EMBED_LDFLAGS = $(call strip-libs,$(PYTHON_EMBED_LDOPTS)) | ||
114 | PYTHON_EMBED_LIBADD = $(call grep-libs,$(PYTHON_EMBED_LDOPTS)) | ||
115 | PYTHON_EMBED_CCOPTS = $(shell $(PYTHON_CONFIG_SQ) --cflags 2>/dev/null) | ||
116 | FLAGS_PYTHON_EMBED = $(PYTHON_EMBED_CCOPTS) $(PYTHON_EMBED_LDOPTS) | ||
117 | |||
118 | test-libpython.bin: | 104 | test-libpython.bin: |
119 | $(BUILD) $(FLAGS_PYTHON_EMBED) | 105 | $(BUILD) |
120 | 106 | ||
121 | test-libpython-version.bin: | 107 | test-libpython-version.bin: |
122 | $(BUILD) $(FLAGS_PYTHON_EMBED) | 108 | $(BUILD) |
123 | 109 | ||
124 | test-libbfd.bin: | 110 | test-libbfd.bin: |
125 | $(BUILD) -DPACKAGE='"perf"' -lbfd -lz -liberty -ldl | 111 | $(BUILD) -DPACKAGE='"perf"' -lbfd -lz -liberty -ldl |
diff --git a/tools/perf/config/utilities.mak b/tools/perf/config/utilities.mak index 4d985e0f03f5..7076a62d0ff7 100644 --- a/tools/perf/config/utilities.mak +++ b/tools/perf/config/utilities.mak | |||
@@ -132,7 +132,7 @@ endef | |||
132 | # | 132 | # |
133 | # Usage: bool-value = $(call is-absolute,path) | 133 | # Usage: bool-value = $(call is-absolute,path) |
134 | # | 134 | # |
135 | is-absolute = $(shell echo $(shell-sq) | grep ^/ -q && echo y) | 135 | is-absolute = $(shell echo $(shell-sq) | grep -q ^/ && echo y) |
136 | 136 | ||
137 | # lookup | 137 | # lookup |
138 | # | 138 | # |
diff --git a/tools/perf/perf-with-kcore.sh b/tools/perf/perf-with-kcore.sh new file mode 100644 index 000000000000..c7ff90a90e4e --- /dev/null +++ b/tools/perf/perf-with-kcore.sh | |||
@@ -0,0 +1,259 @@ | |||
1 | #!/bin/bash | ||
2 | # perf-with-kcore: use perf with a copy of kcore | ||
3 | # Copyright (c) 2014, Intel Corporation. | ||
4 | # | ||
5 | # This program is free software; you can redistribute it and/or modify it | ||
6 | # under the terms and conditions of the GNU General Public License, | ||
7 | # version 2, as published by the Free Software Foundation. | ||
8 | # | ||
9 | # This program is distributed in the hope it will be useful, but WITHOUT | ||
10 | # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
11 | # FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
12 | # more details. | ||
13 | |||
14 | set -e | ||
15 | |||
16 | usage() | ||
17 | { | ||
18 | echo "Usage: perf-with-kcore <perf sub-command> <perf.data directory> [<sub-command options> [ -- <workload>]]" >&2 | ||
19 | echo " <perf sub-command> can be record, script, report or inject" >&2 | ||
20 | echo " or: perf-with-kcore fix_buildid_cache_permissions" >&2 | ||
21 | exit 1 | ||
22 | } | ||
23 | |||
24 | find_perf() | ||
25 | { | ||
26 | if [ -n "$PERF" ] ; then | ||
27 | return | ||
28 | fi | ||
29 | PERF=`which perf || true` | ||
30 | if [ -z "$PERF" ] ; then | ||
31 | echo "Failed to find perf" >&2 | ||
32 | exit 1 | ||
33 | fi | ||
34 | if [ ! -x "$PERF" ] ; then | ||
35 | echo "Failed to find perf" >&2 | ||
36 | exit 1 | ||
37 | fi | ||
38 | echo "Using $PERF" | ||
39 | "$PERF" version | ||
40 | } | ||
41 | |||
42 | copy_kcore() | ||
43 | { | ||
44 | echo "Copying kcore" | ||
45 | |||
46 | if [ $EUID -eq 0 ] ; then | ||
47 | SUDO="" | ||
48 | else | ||
49 | SUDO="sudo" | ||
50 | fi | ||
51 | |||
52 | rm -f perf.data.junk | ||
53 | ("$PERF" record -o perf.data.junk $PERF_OPTIONS -- sleep 60) >/dev/null 2>/dev/null & | ||
54 | PERF_PID=$! | ||
55 | |||
56 | # Need to make sure that perf has started | ||
57 | sleep 1 | ||
58 | |||
59 | KCORE=$(($SUDO "$PERF" buildid-cache -v -f -k /proc/kcore >/dev/null) 2>&1) | ||
60 | case "$KCORE" in | ||
61 | "kcore added to build-id cache directory "*) | ||
62 | KCORE_DIR=${KCORE#"kcore added to build-id cache directory "} | ||
63 | ;; | ||
64 | *) | ||
65 | kill $PERF_PID | ||
66 | wait >/dev/null 2>/dev/null || true | ||
67 | rm perf.data.junk | ||
68 | echo "$KCORE" | ||
69 | echo "Failed to find kcore" >&2 | ||
70 | exit 1 | ||
71 | ;; | ||
72 | esac | ||
73 | |||
74 | kill $PERF_PID | ||
75 | wait >/dev/null 2>/dev/null || true | ||
76 | rm perf.data.junk | ||
77 | |||
78 | $SUDO cp -a "$KCORE_DIR" "$(pwd)/$PERF_DATA_DIR" | ||
79 | $SUDO rm -f "$KCORE_DIR/kcore" | ||
80 | $SUDO rm -f "$KCORE_DIR/kallsyms" | ||
81 | $SUDO rm -f "$KCORE_DIR/modules" | ||
82 | $SUDO rmdir "$KCORE_DIR" | ||
83 | |||
84 | KCORE_DIR_BASENAME=$(basename "$KCORE_DIR") | ||
85 | KCORE_DIR="$(pwd)/$PERF_DATA_DIR/$KCORE_DIR_BASENAME" | ||
86 | |||
87 | $SUDO chown $UID "$KCORE_DIR" | ||
88 | $SUDO chown $UID "$KCORE_DIR/kcore" | ||
89 | $SUDO chown $UID "$KCORE_DIR/kallsyms" | ||
90 | $SUDO chown $UID "$KCORE_DIR/modules" | ||
91 | |||
92 | $SUDO chgrp $GROUPS "$KCORE_DIR" | ||
93 | $SUDO chgrp $GROUPS "$KCORE_DIR/kcore" | ||
94 | $SUDO chgrp $GROUPS "$KCORE_DIR/kallsyms" | ||
95 | $SUDO chgrp $GROUPS "$KCORE_DIR/modules" | ||
96 | |||
97 | ln -s "$KCORE_DIR_BASENAME" "$PERF_DATA_DIR/kcore_dir" | ||
98 | } | ||
99 | |||
100 | fix_buildid_cache_permissions() | ||
101 | { | ||
102 | if [ $EUID -ne 0 ] ; then | ||
103 | echo "This script must be run as root via sudo " >&2 | ||
104 | exit 1 | ||
105 | fi | ||
106 | |||
107 | if [ -z "$SUDO_USER" ] ; then | ||
108 | echo "This script must be run via sudo" >&2 | ||
109 | exit 1 | ||
110 | fi | ||
111 | |||
112 | USER_HOME=$(bash <<< "echo ~$SUDO_USER") | ||
113 | |||
114 | if [ "$HOME" != "$USER_HOME" ] ; then | ||
115 | echo "Fix unnecessary because root has a home: $HOME" >&2 | ||
116 | exit 1 | ||
117 | fi | ||
118 | |||
119 | echo "Fixing buildid cache permissions" | ||
120 | |||
121 | find "$USER_HOME/.debug" -xdev -type d ! -user "$SUDO_USER" -ls -exec chown "$SUDO_USER" \{\} \; | ||
122 | find "$USER_HOME/.debug" -xdev -type f -links 1 ! -user "$SUDO_USER" -ls -exec chown "$SUDO_USER" \{\} \; | ||
123 | find "$USER_HOME/.debug" -xdev -type l ! -user "$SUDO_USER" -ls -exec chown -h "$SUDO_USER" \{\} \; | ||
124 | |||
125 | if [ -n "$SUDO_GID" ] ; then | ||
126 | find "$USER_HOME/.debug" -xdev -type d ! -group "$SUDO_GID" -ls -exec chgrp "$SUDO_GID" \{\} \; | ||
127 | find "$USER_HOME/.debug" -xdev -type f -links 1 ! -group "$SUDO_GID" -ls -exec chgrp "$SUDO_GID" \{\} \; | ||
128 | find "$USER_HOME/.debug" -xdev -type l ! -group "$SUDO_GID" -ls -exec chgrp -h "$SUDO_GID" \{\} \; | ||
129 | fi | ||
130 | |||
131 | echo "Done" | ||
132 | } | ||
133 | |||
134 | check_buildid_cache_permissions() | ||
135 | { | ||
136 | if [ $EUID -eq 0 ] ; then | ||
137 | return | ||
138 | fi | ||
139 | |||
140 | PERMISSIONS_OK+=$(find "$HOME/.debug" -xdev -type d ! -user "$USER" -print -quit) | ||
141 | PERMISSIONS_OK+=$(find "$HOME/.debug" -xdev -type f -links 1 ! -user "$USER" -print -quit) | ||
142 | PERMISSIONS_OK+=$(find "$HOME/.debug" -xdev -type l ! -user "$USER" -print -quit) | ||
143 | |||
144 | PERMISSIONS_OK+=$(find "$HOME/.debug" -xdev -type d ! -group "$GROUPS" -print -quit) | ||
145 | PERMISSIONS_OK+=$(find "$HOME/.debug" -xdev -type f -links 1 ! -group "$GROUPS" -print -quit) | ||
146 | PERMISSIONS_OK+=$(find "$HOME/.debug" -xdev -type l ! -group "$GROUPS" -print -quit) | ||
147 | |||
148 | if [ -n "$PERMISSIONS_OK" ] ; then | ||
149 | echo "*** WARNING *** buildid cache permissions may need fixing" >&2 | ||
150 | fi | ||
151 | } | ||
152 | |||
153 | record() | ||
154 | { | ||
155 | echo "Recording" | ||
156 | |||
157 | if [ $EUID -ne 0 ] ; then | ||
158 | |||
159 | if [ "$(cat /proc/sys/kernel/kptr_restrict)" -ne 0 ] ; then | ||
160 | echo "*** WARNING *** /proc/sys/kernel/kptr_restrict prevents access to kernel addresses" >&2 | ||
161 | fi | ||
162 | |||
163 | if echo "$PERF_OPTIONS" | grep -q ' -a \|^-a \| -a$\|^-a$\| --all-cpus \|^--all-cpus \| --all-cpus$\|^--all-cpus$' ; then | ||
164 | echo "*** WARNING *** system-wide tracing without root access will not be able to read all necessary information from /proc" >&2 | ||
165 | fi | ||
166 | |||
167 | if echo "$PERF_OPTIONS" | grep -q 'intel_pt\|intel_bts\| -I\|^-I' ; then | ||
168 | if [ "$(cat /proc/sys/kernel/perf_event_paranoid)" -gt -1 ] ; then | ||
169 | echo "*** WARNING *** /proc/sys/kernel/perf_event_paranoid restricts buffer size and tracepoint (sched_switch) use" >&2 | ||
170 | fi | ||
171 | |||
172 | if echo "$PERF_OPTIONS" | grep -q ' --per-thread \|^--per-thread \| --per-thread$\|^--per-thread$' ; then | ||
173 | true | ||
174 | elif echo "$PERF_OPTIONS" | grep -q ' -t \|^-t \| -t$\|^-t$' ; then | ||
175 | true | ||
176 | elif [ ! -r /sys/kernel/debug -o ! -x /sys/kernel/debug ] ; then | ||
177 | echo "*** WARNING *** /sys/kernel/debug permissions prevent tracepoint (sched_switch) use" >&2 | ||
178 | fi | ||
179 | fi | ||
180 | fi | ||
181 | |||
182 | if [ -z "$1" ] ; then | ||
183 | echo "Workload is required for recording" >&2 | ||
184 | usage | ||
185 | fi | ||
186 | |||
187 | if [ -e "$PERF_DATA_DIR" ] ; then | ||
188 | echo "'$PERF_DATA_DIR' exists" >&2 | ||
189 | exit 1 | ||
190 | fi | ||
191 | |||
192 | find_perf | ||
193 | |||
194 | mkdir "$PERF_DATA_DIR" | ||
195 | |||
196 | echo "$PERF record -o $PERF_DATA_DIR/perf.data $PERF_OPTIONS -- $*" | ||
197 | "$PERF" record -o "$PERF_DATA_DIR/perf.data" $PERF_OPTIONS -- $* || true | ||
198 | |||
199 | if rmdir "$PERF_DATA_DIR" > /dev/null 2>/dev/null ; then | ||
200 | exit 1 | ||
201 | fi | ||
202 | |||
203 | copy_kcore | ||
204 | |||
205 | echo "Done" | ||
206 | } | ||
207 | |||
208 | subcommand() | ||
209 | { | ||
210 | find_perf | ||
211 | check_buildid_cache_permissions | ||
212 | echo "$PERF $PERF_SUB_COMMAND -i $PERF_DATA_DIR/perf.data --kallsyms=$PERF_DATA_DIR/kcore_dir/kallsyms $*" | ||
213 | "$PERF" $PERF_SUB_COMMAND -i "$PERF_DATA_DIR/perf.data" "--kallsyms=$PERF_DATA_DIR/kcore_dir/kallsyms" $* | ||
214 | } | ||
215 | |||
216 | if [ "$1" = "fix_buildid_cache_permissions" ] ; then | ||
217 | fix_buildid_cache_permissions | ||
218 | exit 0 | ||
219 | fi | ||
220 | |||
221 | PERF_SUB_COMMAND=$1 | ||
222 | PERF_DATA_DIR=$2 | ||
223 | shift || true | ||
224 | shift || true | ||
225 | |||
226 | if [ -z "$PERF_SUB_COMMAND" ] ; then | ||
227 | usage | ||
228 | fi | ||
229 | |||
230 | if [ -z "$PERF_DATA_DIR" ] ; then | ||
231 | usage | ||
232 | fi | ||
233 | |||
234 | case "$PERF_SUB_COMMAND" in | ||
235 | "record") | ||
236 | while [ "$1" != "--" ] ; do | ||
237 | PERF_OPTIONS+="$1 " | ||
238 | shift || break | ||
239 | done | ||
240 | if [ "$1" != "--" ] ; then | ||
241 | echo "Options and workload are required for recording" >&2 | ||
242 | usage | ||
243 | fi | ||
244 | shift | ||
245 | record $* | ||
246 | ;; | ||
247 | "script") | ||
248 | subcommand $* | ||
249 | ;; | ||
250 | "report") | ||
251 | subcommand $* | ||
252 | ;; | ||
253 | "inject") | ||
254 | subcommand $* | ||
255 | ;; | ||
256 | *) | ||
257 | usage | ||
258 | ;; | ||
259 | esac | ||
diff --git a/tools/perf/perf.c b/tools/perf/perf.c index 2282d41879a2..452a8474d29d 100644 --- a/tools/perf/perf.c +++ b/tools/perf/perf.c | |||
@@ -313,6 +313,7 @@ static int run_builtin(struct cmd_struct *p, int argc, const char **argv) | |||
313 | int status; | 313 | int status; |
314 | struct stat st; | 314 | struct stat st; |
315 | const char *prefix; | 315 | const char *prefix; |
316 | char sbuf[STRERR_BUFSIZE]; | ||
316 | 317 | ||
317 | prefix = NULL; | 318 | prefix = NULL; |
318 | if (p->option & RUN_SETUP) | 319 | if (p->option & RUN_SETUP) |
@@ -343,7 +344,8 @@ static int run_builtin(struct cmd_struct *p, int argc, const char **argv) | |||
343 | status = 1; | 344 | status = 1; |
344 | /* Check for ENOSPC and EIO errors.. */ | 345 | /* Check for ENOSPC and EIO errors.. */ |
345 | if (fflush(stdout)) { | 346 | if (fflush(stdout)) { |
346 | fprintf(stderr, "write failure on standard output: %s", strerror(errno)); | 347 | fprintf(stderr, "write failure on standard output: %s", |
348 | strerror_r(errno, sbuf, sizeof(sbuf))); | ||
347 | goto out; | 349 | goto out; |
348 | } | 350 | } |
349 | if (ferror(stdout)) { | 351 | if (ferror(stdout)) { |
@@ -351,7 +353,8 @@ static int run_builtin(struct cmd_struct *p, int argc, const char **argv) | |||
351 | goto out; | 353 | goto out; |
352 | } | 354 | } |
353 | if (fclose(stdout)) { | 355 | if (fclose(stdout)) { |
354 | fprintf(stderr, "close failed on standard output: %s", strerror(errno)); | 356 | fprintf(stderr, "close failed on standard output: %s", |
357 | strerror_r(errno, sbuf, sizeof(sbuf))); | ||
355 | goto out; | 358 | goto out; |
356 | } | 359 | } |
357 | status = 0; | 360 | status = 0; |
@@ -466,6 +469,7 @@ void pthread__unblock_sigwinch(void) | |||
466 | int main(int argc, const char **argv) | 469 | int main(int argc, const char **argv) |
467 | { | 470 | { |
468 | const char *cmd; | 471 | const char *cmd; |
472 | char sbuf[STRERR_BUFSIZE]; | ||
469 | 473 | ||
470 | /* The page_size is placed in util object. */ | 474 | /* The page_size is placed in util object. */ |
471 | page_size = sysconf(_SC_PAGE_SIZE); | 475 | page_size = sysconf(_SC_PAGE_SIZE); |
@@ -561,7 +565,7 @@ int main(int argc, const char **argv) | |||
561 | } | 565 | } |
562 | 566 | ||
563 | fprintf(stderr, "Failed to run command '%s': %s\n", | 567 | fprintf(stderr, "Failed to run command '%s': %s\n", |
564 | cmd, strerror(errno)); | 568 | cmd, strerror_r(errno, sbuf, sizeof(sbuf))); |
565 | out: | 569 | out: |
566 | return 1; | 570 | return 1; |
567 | } | 571 | } |
diff --git a/tools/perf/perf.h b/tools/perf/perf.h index 510c65f72858..220d44e44c1b 100644 --- a/tools/perf/perf.h +++ b/tools/perf/perf.h | |||
@@ -41,8 +41,6 @@ void pthread__unblock_sigwinch(void); | |||
41 | 41 | ||
42 | struct record_opts { | 42 | struct record_opts { |
43 | struct target target; | 43 | struct target target; |
44 | int call_graph; | ||
45 | bool call_graph_enabled; | ||
46 | bool group; | 44 | bool group; |
47 | bool inherit_stat; | 45 | bool inherit_stat; |
48 | bool no_buffering; | 46 | bool no_buffering; |
@@ -60,7 +58,6 @@ struct record_opts { | |||
60 | u64 branch_stack; | 58 | u64 branch_stack; |
61 | u64 default_interval; | 59 | u64 default_interval; |
62 | u64 user_interval; | 60 | u64 user_interval; |
63 | u16 stack_dump_size; | ||
64 | bool sample_transaction; | 61 | bool sample_transaction; |
65 | unsigned initial_delay; | 62 | unsigned initial_delay; |
66 | }; | 63 | }; |
diff --git a/tools/perf/tests/builtin-test.c b/tools/perf/tests/builtin-test.c index 6f8b01bc6033..ac655b0700e7 100644 --- a/tools/perf/tests/builtin-test.c +++ b/tools/perf/tests/builtin-test.c | |||
@@ -154,6 +154,18 @@ static struct test { | |||
154 | .func = test__hists_cumulate, | 154 | .func = test__hists_cumulate, |
155 | }, | 155 | }, |
156 | { | 156 | { |
157 | .desc = "Test tracking with sched_switch", | ||
158 | .func = test__switch_tracking, | ||
159 | }, | ||
160 | { | ||
161 | .desc = "Filter fds with revents mask in a fdarray", | ||
162 | .func = test__fdarray__filter, | ||
163 | }, | ||
164 | { | ||
165 | .desc = "Add fd to a fdarray, making it autogrow", | ||
166 | .func = test__fdarray__add, | ||
167 | }, | ||
168 | { | ||
157 | .func = NULL, | 169 | .func = NULL, |
158 | }, | 170 | }, |
159 | }; | 171 | }; |
@@ -185,9 +197,11 @@ static bool perf_test__matches(int curr, int argc, const char *argv[]) | |||
185 | static int run_test(struct test *test) | 197 | static int run_test(struct test *test) |
186 | { | 198 | { |
187 | int status, err = -1, child = fork(); | 199 | int status, err = -1, child = fork(); |
200 | char sbuf[STRERR_BUFSIZE]; | ||
188 | 201 | ||
189 | if (child < 0) { | 202 | if (child < 0) { |
190 | pr_err("failed to fork test: %s\n", strerror(errno)); | 203 | pr_err("failed to fork test: %s\n", |
204 | strerror_r(errno, sbuf, sizeof(sbuf))); | ||
191 | return -1; | 205 | return -1; |
192 | } | 206 | } |
193 | 207 | ||
@@ -297,7 +311,7 @@ int cmd_test(int argc, const char **argv, const char *prefix __maybe_unused) | |||
297 | symbol_conf.sort_by_name = true; | 311 | symbol_conf.sort_by_name = true; |
298 | symbol_conf.try_vmlinux_path = true; | 312 | symbol_conf.try_vmlinux_path = true; |
299 | 313 | ||
300 | if (symbol__init() < 0) | 314 | if (symbol__init(NULL) < 0) |
301 | return -1; | 315 | return -1; |
302 | 316 | ||
303 | if (skip != NULL) | 317 | if (skip != NULL) |
diff --git a/tools/perf/tests/fdarray.c b/tools/perf/tests/fdarray.c new file mode 100644 index 000000000000..d24b837951d4 --- /dev/null +++ b/tools/perf/tests/fdarray.c | |||
@@ -0,0 +1,174 @@ | |||
1 | #include <api/fd/array.h> | ||
2 | #include "util/debug.h" | ||
3 | #include "tests/tests.h" | ||
4 | |||
5 | static void fdarray__init_revents(struct fdarray *fda, short revents) | ||
6 | { | ||
7 | int fd; | ||
8 | |||
9 | fda->nr = fda->nr_alloc; | ||
10 | |||
11 | for (fd = 0; fd < fda->nr; ++fd) { | ||
12 | fda->entries[fd].fd = fda->nr - fd; | ||
13 | fda->entries[fd].revents = revents; | ||
14 | } | ||
15 | } | ||
16 | |||
17 | static int fdarray__fprintf_prefix(struct fdarray *fda, const char *prefix, FILE *fp) | ||
18 | { | ||
19 | int printed = 0; | ||
20 | |||
21 | if (!verbose) | ||
22 | return 0; | ||
23 | |||
24 | printed += fprintf(fp, "\n%s: ", prefix); | ||
25 | return printed + fdarray__fprintf(fda, fp); | ||
26 | } | ||
27 | |||
28 | int test__fdarray__filter(void) | ||
29 | { | ||
30 | int nr_fds, expected_fd[2], fd, err = TEST_FAIL; | ||
31 | struct fdarray *fda = fdarray__new(5, 5); | ||
32 | |||
33 | if (fda == NULL) { | ||
34 | pr_debug("\nfdarray__new() failed!"); | ||
35 | goto out; | ||
36 | } | ||
37 | |||
38 | fdarray__init_revents(fda, POLLIN); | ||
39 | nr_fds = fdarray__filter(fda, POLLHUP, NULL); | ||
40 | if (nr_fds != fda->nr_alloc) { | ||
41 | pr_debug("\nfdarray__filter()=%d != %d shouldn't have filtered anything", | ||
42 | nr_fds, fda->nr_alloc); | ||
43 | goto out_delete; | ||
44 | } | ||
45 | |||
46 | fdarray__init_revents(fda, POLLHUP); | ||
47 | nr_fds = fdarray__filter(fda, POLLHUP, NULL); | ||
48 | if (nr_fds != 0) { | ||
49 | pr_debug("\nfdarray__filter()=%d != %d, should have filtered all fds", | ||
50 | nr_fds, fda->nr_alloc); | ||
51 | goto out_delete; | ||
52 | } | ||
53 | |||
54 | fdarray__init_revents(fda, POLLHUP); | ||
55 | fda->entries[2].revents = POLLIN; | ||
56 | expected_fd[0] = fda->entries[2].fd; | ||
57 | |||
58 | pr_debug("\nfiltering all but fda->entries[2]:"); | ||
59 | fdarray__fprintf_prefix(fda, "before", stderr); | ||
60 | nr_fds = fdarray__filter(fda, POLLHUP, NULL); | ||
61 | fdarray__fprintf_prefix(fda, " after", stderr); | ||
62 | if (nr_fds != 1) { | ||
63 | pr_debug("\nfdarray__filter()=%d != 1, should have left just one event", nr_fds); | ||
64 | goto out_delete; | ||
65 | } | ||
66 | |||
67 | if (fda->entries[0].fd != expected_fd[0]) { | ||
68 | pr_debug("\nfda->entries[0].fd=%d != %d\n", | ||
69 | fda->entries[0].fd, expected_fd[0]); | ||
70 | goto out_delete; | ||
71 | } | ||
72 | |||
73 | fdarray__init_revents(fda, POLLHUP); | ||
74 | fda->entries[0].revents = POLLIN; | ||
75 | expected_fd[0] = fda->entries[0].fd; | ||
76 | fda->entries[3].revents = POLLIN; | ||
77 | expected_fd[1] = fda->entries[3].fd; | ||
78 | |||
79 | pr_debug("\nfiltering all but (fda->entries[0], fda->entries[3]):"); | ||
80 | fdarray__fprintf_prefix(fda, "before", stderr); | ||
81 | nr_fds = fdarray__filter(fda, POLLHUP, NULL); | ||
82 | fdarray__fprintf_prefix(fda, " after", stderr); | ||
83 | if (nr_fds != 2) { | ||
84 | pr_debug("\nfdarray__filter()=%d != 2, should have left just two events", | ||
85 | nr_fds); | ||
86 | goto out_delete; | ||
87 | } | ||
88 | |||
89 | for (fd = 0; fd < 2; ++fd) { | ||
90 | if (fda->entries[fd].fd != expected_fd[fd]) { | ||
91 | pr_debug("\nfda->entries[%d].fd=%d != %d\n", fd, | ||
92 | fda->entries[fd].fd, expected_fd[fd]); | ||
93 | goto out_delete; | ||
94 | } | ||
95 | } | ||
96 | |||
97 | pr_debug("\n"); | ||
98 | |||
99 | err = 0; | ||
100 | out_delete: | ||
101 | fdarray__delete(fda); | ||
102 | out: | ||
103 | return err; | ||
104 | } | ||
105 | |||
106 | int test__fdarray__add(void) | ||
107 | { | ||
108 | int err = TEST_FAIL; | ||
109 | struct fdarray *fda = fdarray__new(2, 2); | ||
110 | |||
111 | if (fda == NULL) { | ||
112 | pr_debug("\nfdarray__new() failed!"); | ||
113 | goto out; | ||
114 | } | ||
115 | |||
116 | #define FDA_CHECK(_idx, _fd, _revents) \ | ||
117 | if (fda->entries[_idx].fd != _fd) { \ | ||
118 | pr_debug("\n%d: fda->entries[%d](%d) != %d!", \ | ||
119 | __LINE__, _idx, fda->entries[1].fd, _fd); \ | ||
120 | goto out_delete; \ | ||
121 | } \ | ||
122 | if (fda->entries[_idx].events != (_revents)) { \ | ||
123 | pr_debug("\n%d: fda->entries[%d].revents(%d) != %d!", \ | ||
124 | __LINE__, _idx, fda->entries[_idx].fd, _revents); \ | ||
125 | goto out_delete; \ | ||
126 | } | ||
127 | |||
128 | #define FDA_ADD(_idx, _fd, _revents, _nr) \ | ||
129 | if (fdarray__add(fda, _fd, _revents) < 0) { \ | ||
130 | pr_debug("\n%d: fdarray__add(fda, %d, %d) failed!", \ | ||
131 | __LINE__,_fd, _revents); \ | ||
132 | goto out_delete; \ | ||
133 | } \ | ||
134 | if (fda->nr != _nr) { \ | ||
135 | pr_debug("\n%d: fdarray__add(fda, %d, %d)=%d != %d", \ | ||
136 | __LINE__,_fd, _revents, fda->nr, _nr); \ | ||
137 | goto out_delete; \ | ||
138 | } \ | ||
139 | FDA_CHECK(_idx, _fd, _revents) | ||
140 | |||
141 | FDA_ADD(0, 1, POLLIN, 1); | ||
142 | FDA_ADD(1, 2, POLLERR, 2); | ||
143 | |||
144 | fdarray__fprintf_prefix(fda, "before growing array", stderr); | ||
145 | |||
146 | FDA_ADD(2, 35, POLLHUP, 3); | ||
147 | |||
148 | if (fda->entries == NULL) { | ||
149 | pr_debug("\nfdarray__add(fda, 35, POLLHUP) should have allocated fda->pollfd!"); | ||
150 | goto out_delete; | ||
151 | } | ||
152 | |||
153 | fdarray__fprintf_prefix(fda, "after 3rd add", stderr); | ||
154 | |||
155 | FDA_ADD(3, 88, POLLIN | POLLOUT, 4); | ||
156 | |||
157 | fdarray__fprintf_prefix(fda, "after 4th add", stderr); | ||
158 | |||
159 | FDA_CHECK(0, 1, POLLIN); | ||
160 | FDA_CHECK(1, 2, POLLERR); | ||
161 | FDA_CHECK(2, 35, POLLHUP); | ||
162 | FDA_CHECK(3, 88, POLLIN | POLLOUT); | ||
163 | |||
164 | #undef FDA_ADD | ||
165 | #undef FDA_CHECK | ||
166 | |||
167 | pr_debug("\n"); | ||
168 | |||
169 | err = 0; | ||
170 | out_delete: | ||
171 | fdarray__delete(fda); | ||
172 | out: | ||
173 | return err; | ||
174 | } | ||
diff --git a/tools/perf/tests/mmap-basic.c b/tools/perf/tests/mmap-basic.c index 142263492f6f..9b9622a33932 100644 --- a/tools/perf/tests/mmap-basic.c +++ b/tools/perf/tests/mmap-basic.c | |||
@@ -31,6 +31,7 @@ int test__basic_mmap(void) | |||
31 | unsigned int nr_events[nsyscalls], | 31 | unsigned int nr_events[nsyscalls], |
32 | expected_nr_events[nsyscalls], i, j; | 32 | expected_nr_events[nsyscalls], i, j; |
33 | struct perf_evsel *evsels[nsyscalls], *evsel; | 33 | struct perf_evsel *evsels[nsyscalls], *evsel; |
34 | char sbuf[STRERR_BUFSIZE]; | ||
34 | 35 | ||
35 | threads = thread_map__new(-1, getpid(), UINT_MAX); | 36 | threads = thread_map__new(-1, getpid(), UINT_MAX); |
36 | if (threads == NULL) { | 37 | if (threads == NULL) { |
@@ -49,7 +50,7 @@ int test__basic_mmap(void) | |||
49 | sched_setaffinity(0, sizeof(cpu_set), &cpu_set); | 50 | sched_setaffinity(0, sizeof(cpu_set), &cpu_set); |
50 | if (sched_setaffinity(0, sizeof(cpu_set), &cpu_set) < 0) { | 51 | if (sched_setaffinity(0, sizeof(cpu_set), &cpu_set) < 0) { |
51 | pr_debug("sched_setaffinity() failed on CPU %d: %s ", | 52 | pr_debug("sched_setaffinity() failed on CPU %d: %s ", |
52 | cpus->map[0], strerror(errno)); | 53 | cpus->map[0], strerror_r(errno, sbuf, sizeof(sbuf))); |
53 | goto out_free_cpus; | 54 | goto out_free_cpus; |
54 | } | 55 | } |
55 | 56 | ||
@@ -79,7 +80,7 @@ int test__basic_mmap(void) | |||
79 | if (perf_evsel__open(evsels[i], cpus, threads) < 0) { | 80 | if (perf_evsel__open(evsels[i], cpus, threads) < 0) { |
80 | pr_debug("failed to open counter: %s, " | 81 | pr_debug("failed to open counter: %s, " |
81 | "tweak /proc/sys/kernel/perf_event_paranoid?\n", | 82 | "tweak /proc/sys/kernel/perf_event_paranoid?\n", |
82 | strerror(errno)); | 83 | strerror_r(errno, sbuf, sizeof(sbuf))); |
83 | goto out_delete_evlist; | 84 | goto out_delete_evlist; |
84 | } | 85 | } |
85 | 86 | ||
@@ -89,7 +90,7 @@ int test__basic_mmap(void) | |||
89 | 90 | ||
90 | if (perf_evlist__mmap(evlist, 128, true) < 0) { | 91 | if (perf_evlist__mmap(evlist, 128, true) < 0) { |
91 | pr_debug("failed to mmap events: %d (%s)\n", errno, | 92 | pr_debug("failed to mmap events: %d (%s)\n", errno, |
92 | strerror(errno)); | 93 | strerror_r(errno, sbuf, sizeof(sbuf))); |
93 | goto out_delete_evlist; | 94 | goto out_delete_evlist; |
94 | } | 95 | } |
95 | 96 | ||
diff --git a/tools/perf/tests/open-syscall-all-cpus.c b/tools/perf/tests/open-syscall-all-cpus.c index 5fecdbd2f5f7..8fa82d1700c7 100644 --- a/tools/perf/tests/open-syscall-all-cpus.c +++ b/tools/perf/tests/open-syscall-all-cpus.c | |||
@@ -12,6 +12,7 @@ int test__open_syscall_event_on_all_cpus(void) | |||
12 | unsigned int nr_open_calls = 111, i; | 12 | unsigned int nr_open_calls = 111, i; |
13 | cpu_set_t cpu_set; | 13 | cpu_set_t cpu_set; |
14 | struct thread_map *threads = thread_map__new(-1, getpid(), UINT_MAX); | 14 | struct thread_map *threads = thread_map__new(-1, getpid(), UINT_MAX); |
15 | char sbuf[STRERR_BUFSIZE]; | ||
15 | 16 | ||
16 | if (threads == NULL) { | 17 | if (threads == NULL) { |
17 | pr_debug("thread_map__new\n"); | 18 | pr_debug("thread_map__new\n"); |
@@ -35,7 +36,7 @@ int test__open_syscall_event_on_all_cpus(void) | |||
35 | if (perf_evsel__open(evsel, cpus, threads) < 0) { | 36 | if (perf_evsel__open(evsel, cpus, threads) < 0) { |
36 | pr_debug("failed to open counter: %s, " | 37 | pr_debug("failed to open counter: %s, " |
37 | "tweak /proc/sys/kernel/perf_event_paranoid?\n", | 38 | "tweak /proc/sys/kernel/perf_event_paranoid?\n", |
38 | strerror(errno)); | 39 | strerror_r(errno, sbuf, sizeof(sbuf))); |
39 | goto out_evsel_delete; | 40 | goto out_evsel_delete; |
40 | } | 41 | } |
41 | 42 | ||
@@ -56,7 +57,7 @@ int test__open_syscall_event_on_all_cpus(void) | |||
56 | if (sched_setaffinity(0, sizeof(cpu_set), &cpu_set) < 0) { | 57 | if (sched_setaffinity(0, sizeof(cpu_set), &cpu_set) < 0) { |
57 | pr_debug("sched_setaffinity() failed on CPU %d: %s ", | 58 | pr_debug("sched_setaffinity() failed on CPU %d: %s ", |
58 | cpus->map[cpu], | 59 | cpus->map[cpu], |
59 | strerror(errno)); | 60 | strerror_r(errno, sbuf, sizeof(sbuf))); |
60 | goto out_close_fd; | 61 | goto out_close_fd; |
61 | } | 62 | } |
62 | for (i = 0; i < ncalls; ++i) { | 63 | for (i = 0; i < ncalls; ++i) { |
diff --git a/tools/perf/tests/open-syscall-tp-fields.c b/tools/perf/tests/open-syscall-tp-fields.c index 0785b64ffd6c..127dcae0b760 100644 --- a/tools/perf/tests/open-syscall-tp-fields.c +++ b/tools/perf/tests/open-syscall-tp-fields.c | |||
@@ -22,6 +22,7 @@ int test__syscall_open_tp_fields(void) | |||
22 | struct perf_evlist *evlist = perf_evlist__new(); | 22 | struct perf_evlist *evlist = perf_evlist__new(); |
23 | struct perf_evsel *evsel; | 23 | struct perf_evsel *evsel; |
24 | int err = -1, i, nr_events = 0, nr_polls = 0; | 24 | int err = -1, i, nr_events = 0, nr_polls = 0; |
25 | char sbuf[STRERR_BUFSIZE]; | ||
25 | 26 | ||
26 | if (evlist == NULL) { | 27 | if (evlist == NULL) { |
27 | pr_debug("%s: perf_evlist__new\n", __func__); | 28 | pr_debug("%s: perf_evlist__new\n", __func__); |
@@ -48,13 +49,15 @@ int test__syscall_open_tp_fields(void) | |||
48 | 49 | ||
49 | err = perf_evlist__open(evlist); | 50 | err = perf_evlist__open(evlist); |
50 | if (err < 0) { | 51 | if (err < 0) { |
51 | pr_debug("perf_evlist__open: %s\n", strerror(errno)); | 52 | pr_debug("perf_evlist__open: %s\n", |
53 | strerror_r(errno, sbuf, sizeof(sbuf))); | ||
52 | goto out_delete_evlist; | 54 | goto out_delete_evlist; |
53 | } | 55 | } |
54 | 56 | ||
55 | err = perf_evlist__mmap(evlist, UINT_MAX, false); | 57 | err = perf_evlist__mmap(evlist, UINT_MAX, false); |
56 | if (err < 0) { | 58 | if (err < 0) { |
57 | pr_debug("perf_evlist__mmap: %s\n", strerror(errno)); | 59 | pr_debug("perf_evlist__mmap: %s\n", |
60 | strerror_r(errno, sbuf, sizeof(sbuf))); | ||
58 | goto out_delete_evlist; | 61 | goto out_delete_evlist; |
59 | } | 62 | } |
60 | 63 | ||
@@ -102,7 +105,7 @@ int test__syscall_open_tp_fields(void) | |||
102 | } | 105 | } |
103 | 106 | ||
104 | if (nr_events == before) | 107 | if (nr_events == before) |
105 | poll(evlist->pollfd, evlist->nr_fds, 10); | 108 | perf_evlist__poll(evlist, 10); |
106 | 109 | ||
107 | if (++nr_polls > 5) { | 110 | if (++nr_polls > 5) { |
108 | pr_debug("%s: no events!\n", __func__); | 111 | pr_debug("%s: no events!\n", __func__); |
diff --git a/tools/perf/tests/open-syscall.c b/tools/perf/tests/open-syscall.c index c1dc7d25f38c..a33b2daae40f 100644 --- a/tools/perf/tests/open-syscall.c +++ b/tools/perf/tests/open-syscall.c | |||
@@ -9,6 +9,7 @@ int test__open_syscall_event(void) | |||
9 | struct perf_evsel *evsel; | 9 | struct perf_evsel *evsel; |
10 | unsigned int nr_open_calls = 111, i; | 10 | unsigned int nr_open_calls = 111, i; |
11 | struct thread_map *threads = thread_map__new(-1, getpid(), UINT_MAX); | 11 | struct thread_map *threads = thread_map__new(-1, getpid(), UINT_MAX); |
12 | char sbuf[STRERR_BUFSIZE]; | ||
12 | 13 | ||
13 | if (threads == NULL) { | 14 | if (threads == NULL) { |
14 | pr_debug("thread_map__new\n"); | 15 | pr_debug("thread_map__new\n"); |
@@ -24,7 +25,7 @@ int test__open_syscall_event(void) | |||
24 | if (perf_evsel__open_per_thread(evsel, threads) < 0) { | 25 | if (perf_evsel__open_per_thread(evsel, threads) < 0) { |
25 | pr_debug("failed to open counter: %s, " | 26 | pr_debug("failed to open counter: %s, " |
26 | "tweak /proc/sys/kernel/perf_event_paranoid?\n", | 27 | "tweak /proc/sys/kernel/perf_event_paranoid?\n", |
27 | strerror(errno)); | 28 | strerror_r(errno, sbuf, sizeof(sbuf))); |
28 | goto out_evsel_delete; | 29 | goto out_evsel_delete; |
29 | } | 30 | } |
30 | 31 | ||
diff --git a/tools/perf/tests/perf-record.c b/tools/perf/tests/perf-record.c index aca1a83dd13a..7a228a2a070b 100644 --- a/tools/perf/tests/perf-record.c +++ b/tools/perf/tests/perf-record.c | |||
@@ -59,6 +59,7 @@ int test__PERF_RECORD(void) | |||
59 | int err = -1, errs = 0, i, wakeups = 0; | 59 | int err = -1, errs = 0, i, wakeups = 0; |
60 | u32 cpu; | 60 | u32 cpu; |
61 | int total_events = 0, nr_events[PERF_RECORD_MAX] = { 0, }; | 61 | int total_events = 0, nr_events[PERF_RECORD_MAX] = { 0, }; |
62 | char sbuf[STRERR_BUFSIZE]; | ||
62 | 63 | ||
63 | if (evlist == NULL || argv == NULL) { | 64 | if (evlist == NULL || argv == NULL) { |
64 | pr_debug("Not enough memory to create evlist\n"); | 65 | pr_debug("Not enough memory to create evlist\n"); |
@@ -100,7 +101,8 @@ int test__PERF_RECORD(void) | |||
100 | 101 | ||
101 | err = sched__get_first_possible_cpu(evlist->workload.pid, &cpu_mask); | 102 | err = sched__get_first_possible_cpu(evlist->workload.pid, &cpu_mask); |
102 | if (err < 0) { | 103 | if (err < 0) { |
103 | pr_debug("sched__get_first_possible_cpu: %s\n", strerror(errno)); | 104 | pr_debug("sched__get_first_possible_cpu: %s\n", |
105 | strerror_r(errno, sbuf, sizeof(sbuf))); | ||
104 | goto out_delete_evlist; | 106 | goto out_delete_evlist; |
105 | } | 107 | } |
106 | 108 | ||
@@ -110,7 +112,8 @@ int test__PERF_RECORD(void) | |||
110 | * So that we can check perf_sample.cpu on all the samples. | 112 | * So that we can check perf_sample.cpu on all the samples. |
111 | */ | 113 | */ |
112 | if (sched_setaffinity(evlist->workload.pid, cpu_mask_size, &cpu_mask) < 0) { | 114 | if (sched_setaffinity(evlist->workload.pid, cpu_mask_size, &cpu_mask) < 0) { |
113 | pr_debug("sched_setaffinity: %s\n", strerror(errno)); | 115 | pr_debug("sched_setaffinity: %s\n", |
116 | strerror_r(errno, sbuf, sizeof(sbuf))); | ||
114 | goto out_delete_evlist; | 117 | goto out_delete_evlist; |
115 | } | 118 | } |
116 | 119 | ||
@@ -120,7 +123,8 @@ int test__PERF_RECORD(void) | |||
120 | */ | 123 | */ |
121 | err = perf_evlist__open(evlist); | 124 | err = perf_evlist__open(evlist); |
122 | if (err < 0) { | 125 | if (err < 0) { |
123 | pr_debug("perf_evlist__open: %s\n", strerror(errno)); | 126 | pr_debug("perf_evlist__open: %s\n", |
127 | strerror_r(errno, sbuf, sizeof(sbuf))); | ||
124 | goto out_delete_evlist; | 128 | goto out_delete_evlist; |
125 | } | 129 | } |
126 | 130 | ||
@@ -131,7 +135,8 @@ int test__PERF_RECORD(void) | |||
131 | */ | 135 | */ |
132 | err = perf_evlist__mmap(evlist, opts.mmap_pages, false); | 136 | err = perf_evlist__mmap(evlist, opts.mmap_pages, false); |
133 | if (err < 0) { | 137 | if (err < 0) { |
134 | pr_debug("perf_evlist__mmap: %s\n", strerror(errno)); | 138 | pr_debug("perf_evlist__mmap: %s\n", |
139 | strerror_r(errno, sbuf, sizeof(sbuf))); | ||
135 | goto out_delete_evlist; | 140 | goto out_delete_evlist; |
136 | } | 141 | } |
137 | 142 | ||
@@ -263,7 +268,7 @@ int test__PERF_RECORD(void) | |||
263 | * perf_event_attr.wakeup_events, just PERF_EVENT_SAMPLE does. | 268 | * perf_event_attr.wakeup_events, just PERF_EVENT_SAMPLE does. |
264 | */ | 269 | */ |
265 | if (total_events == before && false) | 270 | if (total_events == before && false) |
266 | poll(evlist->pollfd, evlist->nr_fds, -1); | 271 | perf_evlist__poll(evlist, -1); |
267 | 272 | ||
268 | sleep(1); | 273 | sleep(1); |
269 | if (++wakeups > 5) { | 274 | if (++wakeups > 5) { |
diff --git a/tools/perf/tests/pmu.c b/tools/perf/tests/pmu.c index 12b322fa3475..eeb68bb1972d 100644 --- a/tools/perf/tests/pmu.c +++ b/tools/perf/tests/pmu.c | |||
@@ -152,7 +152,7 @@ int test__pmu(void) | |||
152 | if (ret) | 152 | if (ret) |
153 | break; | 153 | break; |
154 | 154 | ||
155 | ret = perf_pmu__config_terms(&formats, &attr, terms); | 155 | ret = perf_pmu__config_terms(&formats, &attr, terms, false); |
156 | if (ret) | 156 | if (ret) |
157 | break; | 157 | break; |
158 | 158 | ||
diff --git a/tools/perf/tests/rdpmc.c b/tools/perf/tests/rdpmc.c index c04d1f268576..d31f2c4d9f64 100644 --- a/tools/perf/tests/rdpmc.c +++ b/tools/perf/tests/rdpmc.c | |||
@@ -100,6 +100,7 @@ static int __test__rdpmc(void) | |||
100 | }; | 100 | }; |
101 | u64 delta_sum = 0; | 101 | u64 delta_sum = 0; |
102 | struct sigaction sa; | 102 | struct sigaction sa; |
103 | char sbuf[STRERR_BUFSIZE]; | ||
103 | 104 | ||
104 | sigfillset(&sa.sa_mask); | 105 | sigfillset(&sa.sa_mask); |
105 | sa.sa_sigaction = segfault_handler; | 106 | sa.sa_sigaction = segfault_handler; |
@@ -109,14 +110,15 @@ static int __test__rdpmc(void) | |||
109 | perf_event_open_cloexec_flag()); | 110 | perf_event_open_cloexec_flag()); |
110 | if (fd < 0) { | 111 | if (fd < 0) { |
111 | pr_err("Error: sys_perf_event_open() syscall returned " | 112 | pr_err("Error: sys_perf_event_open() syscall returned " |
112 | "with %d (%s)\n", fd, strerror(errno)); | 113 | "with %d (%s)\n", fd, |
114 | strerror_r(errno, sbuf, sizeof(sbuf))); | ||
113 | return -1; | 115 | return -1; |
114 | } | 116 | } |
115 | 117 | ||
116 | addr = mmap(NULL, page_size, PROT_READ, MAP_SHARED, fd, 0); | 118 | addr = mmap(NULL, page_size, PROT_READ, MAP_SHARED, fd, 0); |
117 | if (addr == (void *)(-1)) { | 119 | if (addr == (void *)(-1)) { |
118 | pr_err("Error: mmap() syscall returned with (%s)\n", | 120 | pr_err("Error: mmap() syscall returned with (%s)\n", |
119 | strerror(errno)); | 121 | strerror_r(errno, sbuf, sizeof(sbuf))); |
120 | goto out_close; | 122 | goto out_close; |
121 | } | 123 | } |
122 | 124 | ||
diff --git a/tools/perf/tests/sw-clock.c b/tools/perf/tests/sw-clock.c index 983d6b8562a8..1aa21c90731b 100644 --- a/tools/perf/tests/sw-clock.c +++ b/tools/perf/tests/sw-clock.c | |||
@@ -22,6 +22,7 @@ static int __test__sw_clock_freq(enum perf_sw_ids clock_id) | |||
22 | volatile int tmp = 0; | 22 | volatile int tmp = 0; |
23 | u64 total_periods = 0; | 23 | u64 total_periods = 0; |
24 | int nr_samples = 0; | 24 | int nr_samples = 0; |
25 | char sbuf[STRERR_BUFSIZE]; | ||
25 | union perf_event *event; | 26 | union perf_event *event; |
26 | struct perf_evsel *evsel; | 27 | struct perf_evsel *evsel; |
27 | struct perf_evlist *evlist; | 28 | struct perf_evlist *evlist; |
@@ -62,14 +63,15 @@ static int __test__sw_clock_freq(enum perf_sw_ids clock_id) | |||
62 | 63 | ||
63 | err = -errno; | 64 | err = -errno; |
64 | pr_debug("Couldn't open evlist: %s\nHint: check %s, using %" PRIu64 " in this test.\n", | 65 | pr_debug("Couldn't open evlist: %s\nHint: check %s, using %" PRIu64 " in this test.\n", |
65 | strerror(errno), knob, (u64)attr.sample_freq); | 66 | strerror_r(errno, sbuf, sizeof(sbuf)), |
67 | knob, (u64)attr.sample_freq); | ||
66 | goto out_delete_evlist; | 68 | goto out_delete_evlist; |
67 | } | 69 | } |
68 | 70 | ||
69 | err = perf_evlist__mmap(evlist, 128, true); | 71 | err = perf_evlist__mmap(evlist, 128, true); |
70 | if (err < 0) { | 72 | if (err < 0) { |
71 | pr_debug("failed to mmap event: %d (%s)\n", errno, | 73 | pr_debug("failed to mmap event: %d (%s)\n", errno, |
72 | strerror(errno)); | 74 | strerror_r(errno, sbuf, sizeof(sbuf))); |
73 | goto out_delete_evlist; | 75 | goto out_delete_evlist; |
74 | } | 76 | } |
75 | 77 | ||
diff --git a/tools/perf/tests/switch-tracking.c b/tools/perf/tests/switch-tracking.c new file mode 100644 index 000000000000..cc68648c7c55 --- /dev/null +++ b/tools/perf/tests/switch-tracking.c | |||
@@ -0,0 +1,572 @@ | |||
1 | #include <sys/time.h> | ||
2 | #include <sys/prctl.h> | ||
3 | #include <time.h> | ||
4 | #include <stdlib.h> | ||
5 | |||
6 | #include "parse-events.h" | ||
7 | #include "evlist.h" | ||
8 | #include "evsel.h" | ||
9 | #include "thread_map.h" | ||
10 | #include "cpumap.h" | ||
11 | #include "tests.h" | ||
12 | |||
13 | static int spin_sleep(void) | ||
14 | { | ||
15 | struct timeval start, now, diff, maxtime; | ||
16 | struct timespec ts; | ||
17 | int err, i; | ||
18 | |||
19 | maxtime.tv_sec = 0; | ||
20 | maxtime.tv_usec = 50000; | ||
21 | |||
22 | err = gettimeofday(&start, NULL); | ||
23 | if (err) | ||
24 | return err; | ||
25 | |||
26 | /* Spin for 50ms */ | ||
27 | while (1) { | ||
28 | for (i = 0; i < 1000; i++) | ||
29 | barrier(); | ||
30 | |||
31 | err = gettimeofday(&now, NULL); | ||
32 | if (err) | ||
33 | return err; | ||
34 | |||
35 | timersub(&now, &start, &diff); | ||
36 | if (timercmp(&diff, &maxtime, > /* For checkpatch */)) | ||
37 | break; | ||
38 | } | ||
39 | |||
40 | ts.tv_nsec = 50 * 1000 * 1000; | ||
41 | ts.tv_sec = 0; | ||
42 | |||
43 | /* Sleep for 50ms */ | ||
44 | err = nanosleep(&ts, NULL); | ||
45 | if (err == EINTR) | ||
46 | err = 0; | ||
47 | |||
48 | return err; | ||
49 | } | ||
50 | |||
51 | struct switch_tracking { | ||
52 | struct perf_evsel *switch_evsel; | ||
53 | struct perf_evsel *cycles_evsel; | ||
54 | pid_t *tids; | ||
55 | int nr_tids; | ||
56 | int comm_seen[4]; | ||
57 | int cycles_before_comm_1; | ||
58 | int cycles_between_comm_2_and_comm_3; | ||
59 | int cycles_after_comm_4; | ||
60 | }; | ||
61 | |||
62 | static int check_comm(struct switch_tracking *switch_tracking, | ||
63 | union perf_event *event, const char *comm, int nr) | ||
64 | { | ||
65 | if (event->header.type == PERF_RECORD_COMM && | ||
66 | (pid_t)event->comm.pid == getpid() && | ||
67 | (pid_t)event->comm.tid == getpid() && | ||
68 | strcmp(event->comm.comm, comm) == 0) { | ||
69 | if (switch_tracking->comm_seen[nr]) { | ||
70 | pr_debug("Duplicate comm event\n"); | ||
71 | return -1; | ||
72 | } | ||
73 | switch_tracking->comm_seen[nr] = 1; | ||
74 | pr_debug3("comm event: %s nr: %d\n", event->comm.comm, nr); | ||
75 | return 1; | ||
76 | } | ||
77 | return 0; | ||
78 | } | ||
79 | |||
80 | static int check_cpu(struct switch_tracking *switch_tracking, int cpu) | ||
81 | { | ||
82 | int i, nr = cpu + 1; | ||
83 | |||
84 | if (cpu < 0) | ||
85 | return -1; | ||
86 | |||
87 | if (!switch_tracking->tids) { | ||
88 | switch_tracking->tids = calloc(nr, sizeof(pid_t)); | ||
89 | if (!switch_tracking->tids) | ||
90 | return -1; | ||
91 | for (i = 0; i < nr; i++) | ||
92 | switch_tracking->tids[i] = -1; | ||
93 | switch_tracking->nr_tids = nr; | ||
94 | return 0; | ||
95 | } | ||
96 | |||
97 | if (cpu >= switch_tracking->nr_tids) { | ||
98 | void *addr; | ||
99 | |||
100 | addr = realloc(switch_tracking->tids, nr * sizeof(pid_t)); | ||
101 | if (!addr) | ||
102 | return -1; | ||
103 | switch_tracking->tids = addr; | ||
104 | for (i = switch_tracking->nr_tids; i < nr; i++) | ||
105 | switch_tracking->tids[i] = -1; | ||
106 | switch_tracking->nr_tids = nr; | ||
107 | return 0; | ||
108 | } | ||
109 | |||
110 | return 0; | ||
111 | } | ||
112 | |||
113 | static int process_sample_event(struct perf_evlist *evlist, | ||
114 | union perf_event *event, | ||
115 | struct switch_tracking *switch_tracking) | ||
116 | { | ||
117 | struct perf_sample sample; | ||
118 | struct perf_evsel *evsel; | ||
119 | pid_t next_tid, prev_tid; | ||
120 | int cpu, err; | ||
121 | |||
122 | if (perf_evlist__parse_sample(evlist, event, &sample)) { | ||
123 | pr_debug("perf_evlist__parse_sample failed\n"); | ||
124 | return -1; | ||
125 | } | ||
126 | |||
127 | evsel = perf_evlist__id2evsel(evlist, sample.id); | ||
128 | if (evsel == switch_tracking->switch_evsel) { | ||
129 | next_tid = perf_evsel__intval(evsel, &sample, "next_pid"); | ||
130 | prev_tid = perf_evsel__intval(evsel, &sample, "prev_pid"); | ||
131 | cpu = sample.cpu; | ||
132 | pr_debug3("sched_switch: cpu: %d prev_tid %d next_tid %d\n", | ||
133 | cpu, prev_tid, next_tid); | ||
134 | err = check_cpu(switch_tracking, cpu); | ||
135 | if (err) | ||
136 | return err; | ||
137 | /* | ||
138 | * Check for no missing sched_switch events i.e. that the | ||
139 | * evsel->system_wide flag has worked. | ||
140 | */ | ||
141 | if (switch_tracking->tids[cpu] != -1 && | ||
142 | switch_tracking->tids[cpu] != prev_tid) { | ||
143 | pr_debug("Missing sched_switch events\n"); | ||
144 | return -1; | ||
145 | } | ||
146 | switch_tracking->tids[cpu] = next_tid; | ||
147 | } | ||
148 | |||
149 | if (evsel == switch_tracking->cycles_evsel) { | ||
150 | pr_debug3("cycles event\n"); | ||
151 | if (!switch_tracking->comm_seen[0]) | ||
152 | switch_tracking->cycles_before_comm_1 = 1; | ||
153 | if (switch_tracking->comm_seen[1] && | ||
154 | !switch_tracking->comm_seen[2]) | ||
155 | switch_tracking->cycles_between_comm_2_and_comm_3 = 1; | ||
156 | if (switch_tracking->comm_seen[3]) | ||
157 | switch_tracking->cycles_after_comm_4 = 1; | ||
158 | } | ||
159 | |||
160 | return 0; | ||
161 | } | ||
162 | |||
163 | static int process_event(struct perf_evlist *evlist, union perf_event *event, | ||
164 | struct switch_tracking *switch_tracking) | ||
165 | { | ||
166 | if (event->header.type == PERF_RECORD_SAMPLE) | ||
167 | return process_sample_event(evlist, event, switch_tracking); | ||
168 | |||
169 | if (event->header.type == PERF_RECORD_COMM) { | ||
170 | int err, done = 0; | ||
171 | |||
172 | err = check_comm(switch_tracking, event, "Test COMM 1", 0); | ||
173 | if (err < 0) | ||
174 | return -1; | ||
175 | done += err; | ||
176 | err = check_comm(switch_tracking, event, "Test COMM 2", 1); | ||
177 | if (err < 0) | ||
178 | return -1; | ||
179 | done += err; | ||
180 | err = check_comm(switch_tracking, event, "Test COMM 3", 2); | ||
181 | if (err < 0) | ||
182 | return -1; | ||
183 | done += err; | ||
184 | err = check_comm(switch_tracking, event, "Test COMM 4", 3); | ||
185 | if (err < 0) | ||
186 | return -1; | ||
187 | done += err; | ||
188 | if (done != 1) { | ||
189 | pr_debug("Unexpected comm event\n"); | ||
190 | return -1; | ||
191 | } | ||
192 | } | ||
193 | |||
194 | return 0; | ||
195 | } | ||
196 | |||
197 | struct event_node { | ||
198 | struct list_head list; | ||
199 | union perf_event *event; | ||
200 | u64 event_time; | ||
201 | }; | ||
202 | |||
203 | static int add_event(struct perf_evlist *evlist, struct list_head *events, | ||
204 | union perf_event *event) | ||
205 | { | ||
206 | struct perf_sample sample; | ||
207 | struct event_node *node; | ||
208 | |||
209 | node = malloc(sizeof(struct event_node)); | ||
210 | if (!node) { | ||
211 | pr_debug("malloc failed\n"); | ||
212 | return -1; | ||
213 | } | ||
214 | node->event = event; | ||
215 | list_add(&node->list, events); | ||
216 | |||
217 | if (perf_evlist__parse_sample(evlist, event, &sample)) { | ||
218 | pr_debug("perf_evlist__parse_sample failed\n"); | ||
219 | return -1; | ||
220 | } | ||
221 | |||
222 | if (!sample.time) { | ||
223 | pr_debug("event with no time\n"); | ||
224 | return -1; | ||
225 | } | ||
226 | |||
227 | node->event_time = sample.time; | ||
228 | |||
229 | return 0; | ||
230 | } | ||
231 | |||
232 | static void free_event_nodes(struct list_head *events) | ||
233 | { | ||
234 | struct event_node *node; | ||
235 | |||
236 | while (!list_empty(events)) { | ||
237 | node = list_entry(events->next, struct event_node, list); | ||
238 | list_del(&node->list); | ||
239 | free(node); | ||
240 | } | ||
241 | } | ||
242 | |||
243 | static int compar(const void *a, const void *b) | ||
244 | { | ||
245 | const struct event_node *nodea = a; | ||
246 | const struct event_node *nodeb = b; | ||
247 | s64 cmp = nodea->event_time - nodeb->event_time; | ||
248 | |||
249 | return cmp; | ||
250 | } | ||
251 | |||
252 | static int process_events(struct perf_evlist *evlist, | ||
253 | struct switch_tracking *switch_tracking) | ||
254 | { | ||
255 | union perf_event *event; | ||
256 | unsigned pos, cnt = 0; | ||
257 | LIST_HEAD(events); | ||
258 | struct event_node *events_array, *node; | ||
259 | int i, ret; | ||
260 | |||
261 | for (i = 0; i < evlist->nr_mmaps; i++) { | ||
262 | while ((event = perf_evlist__mmap_read(evlist, i)) != NULL) { | ||
263 | cnt += 1; | ||
264 | ret = add_event(evlist, &events, event); | ||
265 | perf_evlist__mmap_consume(evlist, i); | ||
266 | if (ret < 0) | ||
267 | goto out_free_nodes; | ||
268 | } | ||
269 | } | ||
270 | |||
271 | events_array = calloc(cnt, sizeof(struct event_node)); | ||
272 | if (!events_array) { | ||
273 | pr_debug("calloc failed\n"); | ||
274 | ret = -1; | ||
275 | goto out_free_nodes; | ||
276 | } | ||
277 | |||
278 | pos = 0; | ||
279 | list_for_each_entry(node, &events, list) | ||
280 | events_array[pos++] = *node; | ||
281 | |||
282 | qsort(events_array, cnt, sizeof(struct event_node), compar); | ||
283 | |||
284 | for (pos = 0; pos < cnt; pos++) { | ||
285 | ret = process_event(evlist, events_array[pos].event, | ||
286 | switch_tracking); | ||
287 | if (ret < 0) | ||
288 | goto out_free; | ||
289 | } | ||
290 | |||
291 | ret = 0; | ||
292 | out_free: | ||
293 | pr_debug("%u events recorded\n", cnt); | ||
294 | free(events_array); | ||
295 | out_free_nodes: | ||
296 | free_event_nodes(&events); | ||
297 | return ret; | ||
298 | } | ||
299 | |||
300 | /** | ||
301 | * test__switch_tracking - test using sched_switch and tracking events. | ||
302 | * | ||
303 | * This function implements a test that checks that sched_switch events and | ||
304 | * tracking events can be recorded for a workload (current process) using the | ||
305 | * evsel->system_wide and evsel->tracking flags (respectively) with other events | ||
306 | * sometimes enabled or disabled. | ||
307 | */ | ||
308 | int test__switch_tracking(void) | ||
309 | { | ||
310 | const char *sched_switch = "sched:sched_switch"; | ||
311 | struct switch_tracking switch_tracking = { .tids = NULL, }; | ||
312 | struct record_opts opts = { | ||
313 | .mmap_pages = UINT_MAX, | ||
314 | .user_freq = UINT_MAX, | ||
315 | .user_interval = ULLONG_MAX, | ||
316 | .freq = 4000, | ||
317 | .target = { | ||
318 | .uses_mmap = true, | ||
319 | }, | ||
320 | }; | ||
321 | struct thread_map *threads = NULL; | ||
322 | struct cpu_map *cpus = NULL; | ||
323 | struct perf_evlist *evlist = NULL; | ||
324 | struct perf_evsel *evsel, *cpu_clocks_evsel, *cycles_evsel; | ||
325 | struct perf_evsel *switch_evsel, *tracking_evsel; | ||
326 | const char *comm; | ||
327 | int err = -1; | ||
328 | |||
329 | threads = thread_map__new(-1, getpid(), UINT_MAX); | ||
330 | if (!threads) { | ||
331 | pr_debug("thread_map__new failed!\n"); | ||
332 | goto out_err; | ||
333 | } | ||
334 | |||
335 | cpus = cpu_map__new(NULL); | ||
336 | if (!cpus) { | ||
337 | pr_debug("cpu_map__new failed!\n"); | ||
338 | goto out_err; | ||
339 | } | ||
340 | |||
341 | evlist = perf_evlist__new(); | ||
342 | if (!evlist) { | ||
343 | pr_debug("perf_evlist__new failed!\n"); | ||
344 | goto out_err; | ||
345 | } | ||
346 | |||
347 | perf_evlist__set_maps(evlist, cpus, threads); | ||
348 | |||
349 | /* First event */ | ||
350 | err = parse_events(evlist, "cpu-clock:u"); | ||
351 | if (err) { | ||
352 | pr_debug("Failed to parse event dummy:u\n"); | ||
353 | goto out_err; | ||
354 | } | ||
355 | |||
356 | cpu_clocks_evsel = perf_evlist__last(evlist); | ||
357 | |||
358 | /* Second event */ | ||
359 | err = parse_events(evlist, "cycles:u"); | ||
360 | if (err) { | ||
361 | pr_debug("Failed to parse event cycles:u\n"); | ||
362 | goto out_err; | ||
363 | } | ||
364 | |||
365 | cycles_evsel = perf_evlist__last(evlist); | ||
366 | |||
367 | /* Third event */ | ||
368 | if (!perf_evlist__can_select_event(evlist, sched_switch)) { | ||
369 | fprintf(stderr, " (no sched_switch)"); | ||
370 | err = 0; | ||
371 | goto out; | ||
372 | } | ||
373 | |||
374 | err = parse_events(evlist, sched_switch); | ||
375 | if (err) { | ||
376 | pr_debug("Failed to parse event %s\n", sched_switch); | ||
377 | goto out_err; | ||
378 | } | ||
379 | |||
380 | switch_evsel = perf_evlist__last(evlist); | ||
381 | |||
382 | perf_evsel__set_sample_bit(switch_evsel, CPU); | ||
383 | perf_evsel__set_sample_bit(switch_evsel, TIME); | ||
384 | |||
385 | switch_evsel->system_wide = true; | ||
386 | switch_evsel->no_aux_samples = true; | ||
387 | switch_evsel->immediate = true; | ||
388 | |||
389 | /* Test moving an event to the front */ | ||
390 | if (cycles_evsel == perf_evlist__first(evlist)) { | ||
391 | pr_debug("cycles event already at front"); | ||
392 | goto out_err; | ||
393 | } | ||
394 | perf_evlist__to_front(evlist, cycles_evsel); | ||
395 | if (cycles_evsel != perf_evlist__first(evlist)) { | ||
396 | pr_debug("Failed to move cycles event to front"); | ||
397 | goto out_err; | ||
398 | } | ||
399 | |||
400 | perf_evsel__set_sample_bit(cycles_evsel, CPU); | ||
401 | perf_evsel__set_sample_bit(cycles_evsel, TIME); | ||
402 | |||
403 | /* Fourth event */ | ||
404 | err = parse_events(evlist, "dummy:u"); | ||
405 | if (err) { | ||
406 | pr_debug("Failed to parse event dummy:u\n"); | ||
407 | goto out_err; | ||
408 | } | ||
409 | |||
410 | tracking_evsel = perf_evlist__last(evlist); | ||
411 | |||
412 | perf_evlist__set_tracking_event(evlist, tracking_evsel); | ||
413 | |||
414 | tracking_evsel->attr.freq = 0; | ||
415 | tracking_evsel->attr.sample_period = 1; | ||
416 | |||
417 | perf_evsel__set_sample_bit(tracking_evsel, TIME); | ||
418 | |||
419 | /* Config events */ | ||
420 | perf_evlist__config(evlist, &opts); | ||
421 | |||
422 | /* Check moved event is still at the front */ | ||
423 | if (cycles_evsel != perf_evlist__first(evlist)) { | ||
424 | pr_debug("Front event no longer at front"); | ||
425 | goto out_err; | ||
426 | } | ||
427 | |||
428 | /* Check tracking event is tracking */ | ||
429 | if (!tracking_evsel->attr.mmap || !tracking_evsel->attr.comm) { | ||
430 | pr_debug("Tracking event not tracking\n"); | ||
431 | goto out_err; | ||
432 | } | ||
433 | |||
434 | /* Check non-tracking events are not tracking */ | ||
435 | evlist__for_each(evlist, evsel) { | ||
436 | if (evsel != tracking_evsel) { | ||
437 | if (evsel->attr.mmap || evsel->attr.comm) { | ||
438 | pr_debug("Non-tracking event is tracking\n"); | ||
439 | goto out_err; | ||
440 | } | ||
441 | } | ||
442 | } | ||
443 | |||
444 | if (perf_evlist__open(evlist) < 0) { | ||
445 | fprintf(stderr, " (not supported)"); | ||
446 | err = 0; | ||
447 | goto out; | ||
448 | } | ||
449 | |||
450 | err = perf_evlist__mmap(evlist, UINT_MAX, false); | ||
451 | if (err) { | ||
452 | pr_debug("perf_evlist__mmap failed!\n"); | ||
453 | goto out_err; | ||
454 | } | ||
455 | |||
456 | perf_evlist__enable(evlist); | ||
457 | |||
458 | err = perf_evlist__disable_event(evlist, cpu_clocks_evsel); | ||
459 | if (err) { | ||
460 | pr_debug("perf_evlist__disable_event failed!\n"); | ||
461 | goto out_err; | ||
462 | } | ||
463 | |||
464 | err = spin_sleep(); | ||
465 | if (err) { | ||
466 | pr_debug("spin_sleep failed!\n"); | ||
467 | goto out_err; | ||
468 | } | ||
469 | |||
470 | comm = "Test COMM 1"; | ||
471 | err = prctl(PR_SET_NAME, (unsigned long)comm, 0, 0, 0); | ||
472 | if (err) { | ||
473 | pr_debug("PR_SET_NAME failed!\n"); | ||
474 | goto out_err; | ||
475 | } | ||
476 | |||
477 | err = perf_evlist__disable_event(evlist, cycles_evsel); | ||
478 | if (err) { | ||
479 | pr_debug("perf_evlist__disable_event failed!\n"); | ||
480 | goto out_err; | ||
481 | } | ||
482 | |||
483 | comm = "Test COMM 2"; | ||
484 | err = prctl(PR_SET_NAME, (unsigned long)comm, 0, 0, 0); | ||
485 | if (err) { | ||
486 | pr_debug("PR_SET_NAME failed!\n"); | ||
487 | goto out_err; | ||
488 | } | ||
489 | |||
490 | err = spin_sleep(); | ||
491 | if (err) { | ||
492 | pr_debug("spin_sleep failed!\n"); | ||
493 | goto out_err; | ||
494 | } | ||
495 | |||
496 | comm = "Test COMM 3"; | ||
497 | err = prctl(PR_SET_NAME, (unsigned long)comm, 0, 0, 0); | ||
498 | if (err) { | ||
499 | pr_debug("PR_SET_NAME failed!\n"); | ||
500 | goto out_err; | ||
501 | } | ||
502 | |||
503 | err = perf_evlist__enable_event(evlist, cycles_evsel); | ||
504 | if (err) { | ||
505 | pr_debug("perf_evlist__disable_event failed!\n"); | ||
506 | goto out_err; | ||
507 | } | ||
508 | |||
509 | comm = "Test COMM 4"; | ||
510 | err = prctl(PR_SET_NAME, (unsigned long)comm, 0, 0, 0); | ||
511 | if (err) { | ||
512 | pr_debug("PR_SET_NAME failed!\n"); | ||
513 | goto out_err; | ||
514 | } | ||
515 | |||
516 | err = spin_sleep(); | ||
517 | if (err) { | ||
518 | pr_debug("spin_sleep failed!\n"); | ||
519 | goto out_err; | ||
520 | } | ||
521 | |||
522 | perf_evlist__disable(evlist); | ||
523 | |||
524 | switch_tracking.switch_evsel = switch_evsel; | ||
525 | switch_tracking.cycles_evsel = cycles_evsel; | ||
526 | |||
527 | err = process_events(evlist, &switch_tracking); | ||
528 | |||
529 | zfree(&switch_tracking.tids); | ||
530 | |||
531 | if (err) | ||
532 | goto out_err; | ||
533 | |||
534 | /* Check all 4 comm events were seen i.e. that evsel->tracking works */ | ||
535 | if (!switch_tracking.comm_seen[0] || !switch_tracking.comm_seen[1] || | ||
536 | !switch_tracking.comm_seen[2] || !switch_tracking.comm_seen[3]) { | ||
537 | pr_debug("Missing comm events\n"); | ||
538 | goto out_err; | ||
539 | } | ||
540 | |||
541 | /* Check cycles event got enabled */ | ||
542 | if (!switch_tracking.cycles_before_comm_1) { | ||
543 | pr_debug("Missing cycles events\n"); | ||
544 | goto out_err; | ||
545 | } | ||
546 | |||
547 | /* Check cycles event got disabled */ | ||
548 | if (switch_tracking.cycles_between_comm_2_and_comm_3) { | ||
549 | pr_debug("cycles events even though event was disabled\n"); | ||
550 | goto out_err; | ||
551 | } | ||
552 | |||
553 | /* Check cycles event got enabled again */ | ||
554 | if (!switch_tracking.cycles_after_comm_4) { | ||
555 | pr_debug("Missing cycles events\n"); | ||
556 | goto out_err; | ||
557 | } | ||
558 | out: | ||
559 | if (evlist) { | ||
560 | perf_evlist__disable(evlist); | ||
561 | perf_evlist__delete(evlist); | ||
562 | } else { | ||
563 | cpu_map__delete(cpus); | ||
564 | thread_map__delete(threads); | ||
565 | } | ||
566 | |||
567 | return err; | ||
568 | |||
569 | out_err: | ||
570 | err = -1; | ||
571 | goto out; | ||
572 | } | ||
diff --git a/tools/perf/tests/task-exit.c b/tools/perf/tests/task-exit.c index 5ff3db318f12..3a8fedef83bc 100644 --- a/tools/perf/tests/task-exit.c +++ b/tools/perf/tests/task-exit.c | |||
@@ -42,6 +42,7 @@ int test__task_exit(void) | |||
42 | .uses_mmap = true, | 42 | .uses_mmap = true, |
43 | }; | 43 | }; |
44 | const char *argv[] = { "true", NULL }; | 44 | const char *argv[] = { "true", NULL }; |
45 | char sbuf[STRERR_BUFSIZE]; | ||
45 | 46 | ||
46 | signal(SIGCHLD, sig_handler); | 47 | signal(SIGCHLD, sig_handler); |
47 | 48 | ||
@@ -82,13 +83,14 @@ int test__task_exit(void) | |||
82 | 83 | ||
83 | err = perf_evlist__open(evlist); | 84 | err = perf_evlist__open(evlist); |
84 | if (err < 0) { | 85 | if (err < 0) { |
85 | pr_debug("Couldn't open the evlist: %s\n", strerror(-err)); | 86 | pr_debug("Couldn't open the evlist: %s\n", |
87 | strerror_r(-err, sbuf, sizeof(sbuf))); | ||
86 | goto out_delete_evlist; | 88 | goto out_delete_evlist; |
87 | } | 89 | } |
88 | 90 | ||
89 | if (perf_evlist__mmap(evlist, 128, true) < 0) { | 91 | if (perf_evlist__mmap(evlist, 128, true) < 0) { |
90 | pr_debug("failed to mmap events: %d (%s)\n", errno, | 92 | pr_debug("failed to mmap events: %d (%s)\n", errno, |
91 | strerror(errno)); | 93 | strerror_r(errno, sbuf, sizeof(sbuf))); |
92 | goto out_delete_evlist; | 94 | goto out_delete_evlist; |
93 | } | 95 | } |
94 | 96 | ||
@@ -103,7 +105,7 @@ retry: | |||
103 | } | 105 | } |
104 | 106 | ||
105 | if (!exited || !nr_exit) { | 107 | if (!exited || !nr_exit) { |
106 | poll(evlist->pollfd, evlist->nr_fds, -1); | 108 | perf_evlist__poll(evlist, -1); |
107 | goto retry; | 109 | goto retry; |
108 | } | 110 | } |
109 | 111 | ||
diff --git a/tools/perf/tests/tests.h b/tools/perf/tests/tests.h index ed64790a395f..00e776a87a9c 100644 --- a/tools/perf/tests/tests.h +++ b/tools/perf/tests/tests.h | |||
@@ -48,6 +48,9 @@ int test__mmap_thread_lookup(void); | |||
48 | int test__thread_mg_share(void); | 48 | int test__thread_mg_share(void); |
49 | int test__hists_output(void); | 49 | int test__hists_output(void); |
50 | int test__hists_cumulate(void); | 50 | int test__hists_cumulate(void); |
51 | int test__switch_tracking(void); | ||
52 | int test__fdarray__filter(void); | ||
53 | int test__fdarray__add(void); | ||
51 | 54 | ||
52 | #if defined(__x86_64__) || defined(__i386__) || defined(__arm__) | 55 | #if defined(__x86_64__) || defined(__i386__) || defined(__arm__) |
53 | #ifdef HAVE_DWARF_UNWIND_SUPPORT | 56 | #ifdef HAVE_DWARF_UNWIND_SUPPORT |
diff --git a/tools/perf/ui/browsers/hists.c b/tools/perf/ui/browsers/hists.c index a94b11fc5e00..8f60a970404f 100644 --- a/tools/perf/ui/browsers/hists.c +++ b/tools/perf/ui/browsers/hists.c | |||
@@ -10,6 +10,7 @@ | |||
10 | #include "../../util/pstack.h" | 10 | #include "../../util/pstack.h" |
11 | #include "../../util/sort.h" | 11 | #include "../../util/sort.h" |
12 | #include "../../util/util.h" | 12 | #include "../../util/util.h" |
13 | #include "../../util/top.h" | ||
13 | #include "../../arch/common.h" | 14 | #include "../../arch/common.h" |
14 | 15 | ||
15 | #include "../browser.h" | 16 | #include "../browser.h" |
@@ -228,8 +229,10 @@ static void callchain_node__init_have_children(struct callchain_node *node) | |||
228 | { | 229 | { |
229 | struct callchain_list *chain; | 230 | struct callchain_list *chain; |
230 | 231 | ||
231 | list_for_each_entry(chain, &node->val, list) | 232 | if (!list_empty(&node->val)) { |
233 | chain = list_entry(node->val.prev, struct callchain_list, list); | ||
232 | chain->ms.has_children = !RB_EMPTY_ROOT(&node->rb_root); | 234 | chain->ms.has_children = !RB_EMPTY_ROOT(&node->rb_root); |
235 | } | ||
233 | 236 | ||
234 | callchain_node__init_have_children_rb_tree(node); | 237 | callchain_node__init_have_children_rb_tree(node); |
235 | } | 238 | } |
@@ -474,26 +477,87 @@ static char *callchain_list__sym_name(struct callchain_list *cl, | |||
474 | return bf; | 477 | return bf; |
475 | } | 478 | } |
476 | 479 | ||
480 | struct callchain_print_arg { | ||
481 | /* for hists browser */ | ||
482 | off_t row_offset; | ||
483 | bool is_current_entry; | ||
484 | |||
485 | /* for file dump */ | ||
486 | FILE *fp; | ||
487 | int printed; | ||
488 | }; | ||
489 | |||
490 | typedef void (*print_callchain_entry_fn)(struct hist_browser *browser, | ||
491 | struct callchain_list *chain, | ||
492 | const char *str, int offset, | ||
493 | unsigned short row, | ||
494 | struct callchain_print_arg *arg); | ||
495 | |||
496 | static void hist_browser__show_callchain_entry(struct hist_browser *browser, | ||
497 | struct callchain_list *chain, | ||
498 | const char *str, int offset, | ||
499 | unsigned short row, | ||
500 | struct callchain_print_arg *arg) | ||
501 | { | ||
502 | int color, width; | ||
503 | char folded_sign = callchain_list__folded(chain); | ||
504 | |||
505 | color = HE_COLORSET_NORMAL; | ||
506 | width = browser->b.width - (offset + 2); | ||
507 | if (ui_browser__is_current_entry(&browser->b, row)) { | ||
508 | browser->selection = &chain->ms; | ||
509 | color = HE_COLORSET_SELECTED; | ||
510 | arg->is_current_entry = true; | ||
511 | } | ||
512 | |||
513 | ui_browser__set_color(&browser->b, color); | ||
514 | hist_browser__gotorc(browser, row, 0); | ||
515 | slsmg_write_nstring(" ", offset); | ||
516 | slsmg_printf("%c ", folded_sign); | ||
517 | slsmg_write_nstring(str, width); | ||
518 | } | ||
519 | |||
520 | static void hist_browser__fprintf_callchain_entry(struct hist_browser *b __maybe_unused, | ||
521 | struct callchain_list *chain, | ||
522 | const char *str, int offset, | ||
523 | unsigned short row __maybe_unused, | ||
524 | struct callchain_print_arg *arg) | ||
525 | { | ||
526 | char folded_sign = callchain_list__folded(chain); | ||
527 | |||
528 | arg->printed += fprintf(arg->fp, "%*s%c %s\n", offset, " ", | ||
529 | folded_sign, str); | ||
530 | } | ||
531 | |||
532 | typedef bool (*check_output_full_fn)(struct hist_browser *browser, | ||
533 | unsigned short row); | ||
534 | |||
535 | static bool hist_browser__check_output_full(struct hist_browser *browser, | ||
536 | unsigned short row) | ||
537 | { | ||
538 | return browser->b.rows == row; | ||
539 | } | ||
540 | |||
541 | static bool hist_browser__check_dump_full(struct hist_browser *browser __maybe_unused, | ||
542 | unsigned short row __maybe_unused) | ||
543 | { | ||
544 | return false; | ||
545 | } | ||
546 | |||
477 | #define LEVEL_OFFSET_STEP 3 | 547 | #define LEVEL_OFFSET_STEP 3 |
478 | 548 | ||
479 | static int hist_browser__show_callchain_node_rb_tree(struct hist_browser *browser, | 549 | static int hist_browser__show_callchain(struct hist_browser *browser, |
480 | struct callchain_node *chain_node, | 550 | struct rb_root *root, int level, |
481 | u64 total, int level, | 551 | unsigned short row, u64 total, |
482 | unsigned short row, | 552 | print_callchain_entry_fn print, |
483 | off_t *row_offset, | 553 | struct callchain_print_arg *arg, |
484 | bool *is_current_entry) | 554 | check_output_full_fn is_output_full) |
485 | { | 555 | { |
486 | struct rb_node *node; | 556 | struct rb_node *node; |
487 | int first_row = row, width, offset = level * LEVEL_OFFSET_STEP; | 557 | int first_row = row, offset = level * LEVEL_OFFSET_STEP; |
488 | u64 new_total, remaining; | 558 | u64 new_total; |
489 | 559 | ||
490 | if (callchain_param.mode == CHAIN_GRAPH_REL) | 560 | node = rb_first(root); |
491 | new_total = chain_node->children_hit; | ||
492 | else | ||
493 | new_total = total; | ||
494 | |||
495 | remaining = new_total; | ||
496 | node = rb_first(&chain_node->rb_root); | ||
497 | while (node) { | 561 | while (node) { |
498 | struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node); | 562 | struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node); |
499 | struct rb_node *next = rb_next(node); | 563 | struct rb_node *next = rb_next(node); |
@@ -503,30 +567,28 @@ static int hist_browser__show_callchain_node_rb_tree(struct hist_browser *browse | |||
503 | int first = true; | 567 | int first = true; |
504 | int extra_offset = 0; | 568 | int extra_offset = 0; |
505 | 569 | ||
506 | remaining -= cumul; | ||
507 | |||
508 | list_for_each_entry(chain, &child->val, list) { | 570 | list_for_each_entry(chain, &child->val, list) { |
509 | char bf[1024], *alloc_str; | 571 | char bf[1024], *alloc_str; |
510 | const char *str; | 572 | const char *str; |
511 | int color; | ||
512 | bool was_first = first; | 573 | bool was_first = first; |
513 | 574 | ||
514 | if (first) | 575 | if (first) |
515 | first = false; | 576 | first = false; |
516 | else | 577 | else if (level > 1) |
517 | extra_offset = LEVEL_OFFSET_STEP; | 578 | extra_offset = LEVEL_OFFSET_STEP; |
518 | 579 | ||
519 | folded_sign = callchain_list__folded(chain); | 580 | folded_sign = callchain_list__folded(chain); |
520 | if (*row_offset != 0) { | 581 | if (arg->row_offset != 0) { |
521 | --*row_offset; | 582 | arg->row_offset--; |
522 | goto do_next; | 583 | goto do_next; |
523 | } | 584 | } |
524 | 585 | ||
525 | alloc_str = NULL; | 586 | alloc_str = NULL; |
526 | str = callchain_list__sym_name(chain, bf, sizeof(bf), | 587 | str = callchain_list__sym_name(chain, bf, sizeof(bf), |
527 | browser->show_dso); | 588 | browser->show_dso); |
528 | if (was_first) { | 589 | |
529 | double percent = cumul * 100.0 / new_total; | 590 | if (was_first && level > 1) { |
591 | double percent = cumul * 100.0 / total; | ||
530 | 592 | ||
531 | if (asprintf(&alloc_str, "%2.2f%% %s", percent, str) < 0) | 593 | if (asprintf(&alloc_str, "%2.2f%% %s", percent, str) < 0) |
532 | str = "Not enough memory!"; | 594 | str = "Not enough memory!"; |
@@ -534,22 +596,11 @@ static int hist_browser__show_callchain_node_rb_tree(struct hist_browser *browse | |||
534 | str = alloc_str; | 596 | str = alloc_str; |
535 | } | 597 | } |
536 | 598 | ||
537 | color = HE_COLORSET_NORMAL; | 599 | print(browser, chain, str, offset + extra_offset, row, arg); |
538 | width = browser->b.width - (offset + extra_offset + 2); | ||
539 | if (ui_browser__is_current_entry(&browser->b, row)) { | ||
540 | browser->selection = &chain->ms; | ||
541 | color = HE_COLORSET_SELECTED; | ||
542 | *is_current_entry = true; | ||
543 | } | ||
544 | 600 | ||
545 | ui_browser__set_color(&browser->b, color); | ||
546 | hist_browser__gotorc(browser, row, 0); | ||
547 | slsmg_write_nstring(" ", offset + extra_offset); | ||
548 | slsmg_printf("%c ", folded_sign); | ||
549 | slsmg_write_nstring(str, width); | ||
550 | free(alloc_str); | 601 | free(alloc_str); |
551 | 602 | ||
552 | if (++row == browser->b.rows) | 603 | if (is_output_full(browser, ++row)) |
553 | goto out; | 604 | goto out; |
554 | do_next: | 605 | do_next: |
555 | if (folded_sign == '+') | 606 | if (folded_sign == '+') |
@@ -558,89 +609,21 @@ do_next: | |||
558 | 609 | ||
559 | if (folded_sign == '-') { | 610 | if (folded_sign == '-') { |
560 | const int new_level = level + (extra_offset ? 2 : 1); | 611 | const int new_level = level + (extra_offset ? 2 : 1); |
561 | row += hist_browser__show_callchain_node_rb_tree(browser, child, new_total, | ||
562 | new_level, row, row_offset, | ||
563 | is_current_entry); | ||
564 | } | ||
565 | if (row == browser->b.rows) | ||
566 | goto out; | ||
567 | node = next; | ||
568 | } | ||
569 | out: | ||
570 | return row - first_row; | ||
571 | } | ||
572 | |||
573 | static int hist_browser__show_callchain_node(struct hist_browser *browser, | ||
574 | struct callchain_node *node, | ||
575 | int level, unsigned short row, | ||
576 | off_t *row_offset, | ||
577 | bool *is_current_entry) | ||
578 | { | ||
579 | struct callchain_list *chain; | ||
580 | int first_row = row, | ||
581 | offset = level * LEVEL_OFFSET_STEP, | ||
582 | width = browser->b.width - offset; | ||
583 | char folded_sign = ' '; | ||
584 | 612 | ||
585 | list_for_each_entry(chain, &node->val, list) { | 613 | if (callchain_param.mode == CHAIN_GRAPH_REL) |
586 | char bf[1024], *s; | 614 | new_total = child->children_hit; |
587 | int color; | 615 | else |
588 | 616 | new_total = total; | |
589 | folded_sign = callchain_list__folded(chain); | ||
590 | |||
591 | if (*row_offset != 0) { | ||
592 | --*row_offset; | ||
593 | continue; | ||
594 | } | ||
595 | 617 | ||
596 | color = HE_COLORSET_NORMAL; | 618 | row += hist_browser__show_callchain(browser, &child->rb_root, |
597 | if (ui_browser__is_current_entry(&browser->b, row)) { | 619 | new_level, row, new_total, |
598 | browser->selection = &chain->ms; | 620 | print, arg, is_output_full); |
599 | color = HE_COLORSET_SELECTED; | ||
600 | *is_current_entry = true; | ||
601 | } | 621 | } |
602 | 622 | if (is_output_full(browser, row)) | |
603 | s = callchain_list__sym_name(chain, bf, sizeof(bf), | ||
604 | browser->show_dso); | ||
605 | hist_browser__gotorc(browser, row, 0); | ||
606 | ui_browser__set_color(&browser->b, color); | ||
607 | slsmg_write_nstring(" ", offset); | ||
608 | slsmg_printf("%c ", folded_sign); | ||
609 | slsmg_write_nstring(s, width - 2); | ||
610 | |||
611 | if (++row == browser->b.rows) | ||
612 | goto out; | ||
613 | } | ||
614 | |||
615 | if (folded_sign == '-') | ||
616 | row += hist_browser__show_callchain_node_rb_tree(browser, node, | ||
617 | browser->hists->stats.total_period, | ||
618 | level + 1, row, | ||
619 | row_offset, | ||
620 | is_current_entry); | ||
621 | out: | ||
622 | return row - first_row; | ||
623 | } | ||
624 | |||
625 | static int hist_browser__show_callchain(struct hist_browser *browser, | ||
626 | struct rb_root *chain, | ||
627 | int level, unsigned short row, | ||
628 | off_t *row_offset, | ||
629 | bool *is_current_entry) | ||
630 | { | ||
631 | struct rb_node *nd; | ||
632 | int first_row = row; | ||
633 | |||
634 | for (nd = rb_first(chain); nd; nd = rb_next(nd)) { | ||
635 | struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node); | ||
636 | |||
637 | row += hist_browser__show_callchain_node(browser, node, level, | ||
638 | row, row_offset, | ||
639 | is_current_entry); | ||
640 | if (row == browser->b.rows) | ||
641 | break; | 623 | break; |
624 | node = next; | ||
642 | } | 625 | } |
643 | 626 | out: | |
644 | return row - first_row; | 627 | return row - first_row; |
645 | } | 628 | } |
646 | 629 | ||
@@ -653,17 +636,18 @@ struct hpp_arg { | |||
653 | static int __hpp__slsmg_color_printf(struct perf_hpp *hpp, const char *fmt, ...) | 636 | static int __hpp__slsmg_color_printf(struct perf_hpp *hpp, const char *fmt, ...) |
654 | { | 637 | { |
655 | struct hpp_arg *arg = hpp->ptr; | 638 | struct hpp_arg *arg = hpp->ptr; |
656 | int ret; | 639 | int ret, len; |
657 | va_list args; | 640 | va_list args; |
658 | double percent; | 641 | double percent; |
659 | 642 | ||
660 | va_start(args, fmt); | 643 | va_start(args, fmt); |
644 | len = va_arg(args, int); | ||
661 | percent = va_arg(args, double); | 645 | percent = va_arg(args, double); |
662 | va_end(args); | 646 | va_end(args); |
663 | 647 | ||
664 | ui_browser__set_percent_color(arg->b, percent, arg->current_entry); | 648 | ui_browser__set_percent_color(arg->b, percent, arg->current_entry); |
665 | 649 | ||
666 | ret = scnprintf(hpp->buf, hpp->size, fmt, percent); | 650 | ret = scnprintf(hpp->buf, hpp->size, fmt, len, percent); |
667 | slsmg_printf("%s", hpp->buf); | 651 | slsmg_printf("%s", hpp->buf); |
668 | 652 | ||
669 | advance_hpp(hpp, ret); | 653 | advance_hpp(hpp, ret); |
@@ -677,12 +661,12 @@ static u64 __hpp_get_##_field(struct hist_entry *he) \ | |||
677 | } \ | 661 | } \ |
678 | \ | 662 | \ |
679 | static int \ | 663 | static int \ |
680 | hist_browser__hpp_color_##_type(struct perf_hpp_fmt *fmt __maybe_unused,\ | 664 | hist_browser__hpp_color_##_type(struct perf_hpp_fmt *fmt, \ |
681 | struct perf_hpp *hpp, \ | 665 | struct perf_hpp *hpp, \ |
682 | struct hist_entry *he) \ | 666 | struct hist_entry *he) \ |
683 | { \ | 667 | { \ |
684 | return __hpp__fmt(hpp, he, __hpp_get_##_field, " %6.2f%%", \ | 668 | return hpp__fmt(fmt, hpp, he, __hpp_get_##_field, " %*.2f%%", \ |
685 | __hpp__slsmg_color_printf, true); \ | 669 | __hpp__slsmg_color_printf, true); \ |
686 | } | 670 | } |
687 | 671 | ||
688 | #define __HPP_COLOR_ACC_PERCENT_FN(_type, _field) \ | 672 | #define __HPP_COLOR_ACC_PERCENT_FN(_type, _field) \ |
@@ -692,18 +676,20 @@ static u64 __hpp_get_acc_##_field(struct hist_entry *he) \ | |||
692 | } \ | 676 | } \ |
693 | \ | 677 | \ |
694 | static int \ | 678 | static int \ |
695 | hist_browser__hpp_color_##_type(struct perf_hpp_fmt *fmt __maybe_unused,\ | 679 | hist_browser__hpp_color_##_type(struct perf_hpp_fmt *fmt, \ |
696 | struct perf_hpp *hpp, \ | 680 | struct perf_hpp *hpp, \ |
697 | struct hist_entry *he) \ | 681 | struct hist_entry *he) \ |
698 | { \ | 682 | { \ |
699 | if (!symbol_conf.cumulate_callchain) { \ | 683 | if (!symbol_conf.cumulate_callchain) { \ |
700 | int ret = scnprintf(hpp->buf, hpp->size, "%8s", "N/A"); \ | 684 | int len = fmt->user_len ?: fmt->len; \ |
685 | int ret = scnprintf(hpp->buf, hpp->size, \ | ||
686 | "%*s", len, "N/A"); \ | ||
701 | slsmg_printf("%s", hpp->buf); \ | 687 | slsmg_printf("%s", hpp->buf); \ |
702 | \ | 688 | \ |
703 | return ret; \ | 689 | return ret; \ |
704 | } \ | 690 | } \ |
705 | return __hpp__fmt(hpp, he, __hpp_get_acc_##_field, " %6.2f%%", \ | 691 | return hpp__fmt(fmt, hpp, he, __hpp_get_acc_##_field, \ |
706 | __hpp__slsmg_color_printf, true); \ | 692 | " %*.2f%%", __hpp__slsmg_color_printf, true); \ |
707 | } | 693 | } |
708 | 694 | ||
709 | __HPP_COLOR_PERCENT_FN(overhead, period) | 695 | __HPP_COLOR_PERCENT_FN(overhead, period) |
@@ -812,10 +798,18 @@ static int hist_browser__show_entry(struct hist_browser *browser, | |||
812 | --row_offset; | 798 | --row_offset; |
813 | 799 | ||
814 | if (folded_sign == '-' && row != browser->b.rows) { | 800 | if (folded_sign == '-' && row != browser->b.rows) { |
815 | printed += hist_browser__show_callchain(browser, &entry->sorted_chain, | 801 | u64 total = hists__total_period(entry->hists); |
816 | 1, row, &row_offset, | 802 | struct callchain_print_arg arg = { |
817 | ¤t_entry); | 803 | .row_offset = row_offset, |
818 | if (current_entry) | 804 | .is_current_entry = current_entry, |
805 | }; | ||
806 | |||
807 | printed += hist_browser__show_callchain(browser, | ||
808 | &entry->sorted_chain, 1, row, total, | ||
809 | hist_browser__show_callchain_entry, &arg, | ||
810 | hist_browser__check_output_full); | ||
811 | |||
812 | if (arg.is_current_entry) | ||
819 | browser->he_selection = entry; | 813 | browser->he_selection = entry; |
820 | } | 814 | } |
821 | 815 | ||
@@ -847,9 +841,6 @@ static int hists__scnprintf_headers(char *buf, size_t size, struct hists *hists) | |||
847 | if (perf_hpp__should_skip(fmt)) | 841 | if (perf_hpp__should_skip(fmt)) |
848 | continue; | 842 | continue; |
849 | 843 | ||
850 | /* We need to add the length of the columns header. */ | ||
851 | perf_hpp__reset_width(fmt, hists); | ||
852 | |||
853 | ret = fmt->header(fmt, &dummy_hpp, hists_to_evsel(hists)); | 844 | ret = fmt->header(fmt, &dummy_hpp, hists_to_evsel(hists)); |
854 | if (advance_hpp_check(&dummy_hpp, ret)) | 845 | if (advance_hpp_check(&dummy_hpp, ret)) |
855 | break; | 846 | break; |
@@ -1074,113 +1065,21 @@ do_offset: | |||
1074 | } | 1065 | } |
1075 | } | 1066 | } |
1076 | 1067 | ||
1077 | static int hist_browser__fprintf_callchain_node_rb_tree(struct hist_browser *browser, | ||
1078 | struct callchain_node *chain_node, | ||
1079 | u64 total, int level, | ||
1080 | FILE *fp) | ||
1081 | { | ||
1082 | struct rb_node *node; | ||
1083 | int offset = level * LEVEL_OFFSET_STEP; | ||
1084 | u64 new_total, remaining; | ||
1085 | int printed = 0; | ||
1086 | |||
1087 | if (callchain_param.mode == CHAIN_GRAPH_REL) | ||
1088 | new_total = chain_node->children_hit; | ||
1089 | else | ||
1090 | new_total = total; | ||
1091 | |||
1092 | remaining = new_total; | ||
1093 | node = rb_first(&chain_node->rb_root); | ||
1094 | while (node) { | ||
1095 | struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node); | ||
1096 | struct rb_node *next = rb_next(node); | ||
1097 | u64 cumul = callchain_cumul_hits(child); | ||
1098 | struct callchain_list *chain; | ||
1099 | char folded_sign = ' '; | ||
1100 | int first = true; | ||
1101 | int extra_offset = 0; | ||
1102 | |||
1103 | remaining -= cumul; | ||
1104 | |||
1105 | list_for_each_entry(chain, &child->val, list) { | ||
1106 | char bf[1024], *alloc_str; | ||
1107 | const char *str; | ||
1108 | bool was_first = first; | ||
1109 | |||
1110 | if (first) | ||
1111 | first = false; | ||
1112 | else | ||
1113 | extra_offset = LEVEL_OFFSET_STEP; | ||
1114 | |||
1115 | folded_sign = callchain_list__folded(chain); | ||
1116 | |||
1117 | alloc_str = NULL; | ||
1118 | str = callchain_list__sym_name(chain, bf, sizeof(bf), | ||
1119 | browser->show_dso); | ||
1120 | if (was_first) { | ||
1121 | double percent = cumul * 100.0 / new_total; | ||
1122 | |||
1123 | if (asprintf(&alloc_str, "%2.2f%% %s", percent, str) < 0) | ||
1124 | str = "Not enough memory!"; | ||
1125 | else | ||
1126 | str = alloc_str; | ||
1127 | } | ||
1128 | |||
1129 | printed += fprintf(fp, "%*s%c %s\n", offset + extra_offset, " ", folded_sign, str); | ||
1130 | free(alloc_str); | ||
1131 | if (folded_sign == '+') | ||
1132 | break; | ||
1133 | } | ||
1134 | |||
1135 | if (folded_sign == '-') { | ||
1136 | const int new_level = level + (extra_offset ? 2 : 1); | ||
1137 | printed += hist_browser__fprintf_callchain_node_rb_tree(browser, child, new_total, | ||
1138 | new_level, fp); | ||
1139 | } | ||
1140 | |||
1141 | node = next; | ||
1142 | } | ||
1143 | |||
1144 | return printed; | ||
1145 | } | ||
1146 | |||
1147 | static int hist_browser__fprintf_callchain_node(struct hist_browser *browser, | ||
1148 | struct callchain_node *node, | ||
1149 | int level, FILE *fp) | ||
1150 | { | ||
1151 | struct callchain_list *chain; | ||
1152 | int offset = level * LEVEL_OFFSET_STEP; | ||
1153 | char folded_sign = ' '; | ||
1154 | int printed = 0; | ||
1155 | |||
1156 | list_for_each_entry(chain, &node->val, list) { | ||
1157 | char bf[1024], *s; | ||
1158 | |||
1159 | folded_sign = callchain_list__folded(chain); | ||
1160 | s = callchain_list__sym_name(chain, bf, sizeof(bf), browser->show_dso); | ||
1161 | printed += fprintf(fp, "%*s%c %s\n", offset, " ", folded_sign, s); | ||
1162 | } | ||
1163 | |||
1164 | if (folded_sign == '-') | ||
1165 | printed += hist_browser__fprintf_callchain_node_rb_tree(browser, node, | ||
1166 | browser->hists->stats.total_period, | ||
1167 | level + 1, fp); | ||
1168 | return printed; | ||
1169 | } | ||
1170 | |||
1171 | static int hist_browser__fprintf_callchain(struct hist_browser *browser, | 1068 | static int hist_browser__fprintf_callchain(struct hist_browser *browser, |
1172 | struct rb_root *chain, int level, FILE *fp) | 1069 | struct hist_entry *he, FILE *fp) |
1173 | { | 1070 | { |
1174 | struct rb_node *nd; | 1071 | u64 total = hists__total_period(he->hists); |
1175 | int printed = 0; | 1072 | struct callchain_print_arg arg = { |
1073 | .fp = fp, | ||
1074 | }; | ||
1176 | 1075 | ||
1177 | for (nd = rb_first(chain); nd; nd = rb_next(nd)) { | 1076 | if (symbol_conf.cumulate_callchain) |
1178 | struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node); | 1077 | total = he->stat_acc->period; |
1179 | 1078 | ||
1180 | printed += hist_browser__fprintf_callchain_node(browser, node, level, fp); | 1079 | hist_browser__show_callchain(browser, &he->sorted_chain, 1, 0, total, |
1181 | } | 1080 | hist_browser__fprintf_callchain_entry, &arg, |
1182 | 1081 | hist_browser__check_dump_full); | |
1183 | return printed; | 1082 | return arg.printed; |
1184 | } | 1083 | } |
1185 | 1084 | ||
1186 | static int hist_browser__fprintf_entry(struct hist_browser *browser, | 1085 | static int hist_browser__fprintf_entry(struct hist_browser *browser, |
@@ -1219,7 +1118,7 @@ static int hist_browser__fprintf_entry(struct hist_browser *browser, | |||
1219 | printed += fprintf(fp, "%s\n", rtrim(s)); | 1118 | printed += fprintf(fp, "%s\n", rtrim(s)); |
1220 | 1119 | ||
1221 | if (folded_sign == '-') | 1120 | if (folded_sign == '-') |
1222 | printed += hist_browser__fprintf_callchain(browser, &he->sorted_chain, 1, fp); | 1121 | printed += hist_browser__fprintf_callchain(browser, he, fp); |
1223 | 1122 | ||
1224 | return printed; | 1123 | return printed; |
1225 | } | 1124 | } |
@@ -1498,6 +1397,7 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events, | |||
1498 | char buf[64]; | 1397 | char buf[64]; |
1499 | char script_opt[64]; | 1398 | char script_opt[64]; |
1500 | int delay_secs = hbt ? hbt->refresh : 0; | 1399 | int delay_secs = hbt ? hbt->refresh : 0; |
1400 | struct perf_hpp_fmt *fmt; | ||
1501 | 1401 | ||
1502 | #define HIST_BROWSER_HELP_COMMON \ | 1402 | #define HIST_BROWSER_HELP_COMMON \ |
1503 | "h/?/F1 Show this window\n" \ | 1403 | "h/?/F1 Show this window\n" \ |
@@ -1529,6 +1429,7 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events, | |||
1529 | "P Print histograms to perf.hist.N\n" | 1429 | "P Print histograms to perf.hist.N\n" |
1530 | "t Zoom into current Thread\n" | 1430 | "t Zoom into current Thread\n" |
1531 | "V Verbose (DSO names in callchains, etc)\n" | 1431 | "V Verbose (DSO names in callchains, etc)\n" |
1432 | "z Toggle zeroing of samples\n" | ||
1532 | "/ Filter symbol by name"; | 1433 | "/ Filter symbol by name"; |
1533 | 1434 | ||
1534 | if (browser == NULL) | 1435 | if (browser == NULL) |
@@ -1547,6 +1448,12 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events, | |||
1547 | 1448 | ||
1548 | memset(options, 0, sizeof(options)); | 1449 | memset(options, 0, sizeof(options)); |
1549 | 1450 | ||
1451 | perf_hpp__for_each_format(fmt) | ||
1452 | perf_hpp__reset_width(fmt, hists); | ||
1453 | |||
1454 | if (symbol_conf.col_width_list_str) | ||
1455 | perf_hpp__set_user_width(symbol_conf.col_width_list_str); | ||
1456 | |||
1550 | while (1) { | 1457 | while (1) { |
1551 | const struct thread *thread = NULL; | 1458 | const struct thread *thread = NULL; |
1552 | const struct dso *dso = NULL; | 1459 | const struct dso *dso = NULL; |
@@ -1623,6 +1530,13 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events, | |||
1623 | case 'F': | 1530 | case 'F': |
1624 | symbol_conf.filter_relative ^= 1; | 1531 | symbol_conf.filter_relative ^= 1; |
1625 | continue; | 1532 | continue; |
1533 | case 'z': | ||
1534 | if (!is_report_browser(hbt)) { | ||
1535 | struct perf_top *top = hbt->arg; | ||
1536 | |||
1537 | top->zero = !top->zero; | ||
1538 | } | ||
1539 | continue; | ||
1626 | case K_F1: | 1540 | case K_F1: |
1627 | case 'h': | 1541 | case 'h': |
1628 | case '?': | 1542 | case '?': |
diff --git a/tools/perf/ui/gtk/hists.c b/tools/perf/ui/gtk/hists.c index 6ca60e482cdc..f3fa4258b256 100644 --- a/tools/perf/ui/gtk/hists.c +++ b/tools/perf/ui/gtk/hists.c | |||
@@ -11,6 +11,7 @@ | |||
11 | static int __percent_color_snprintf(struct perf_hpp *hpp, const char *fmt, ...) | 11 | static int __percent_color_snprintf(struct perf_hpp *hpp, const char *fmt, ...) |
12 | { | 12 | { |
13 | int ret = 0; | 13 | int ret = 0; |
14 | int len; | ||
14 | va_list args; | 15 | va_list args; |
15 | double percent; | 16 | double percent; |
16 | const char *markup; | 17 | const char *markup; |
@@ -18,6 +19,7 @@ static int __percent_color_snprintf(struct perf_hpp *hpp, const char *fmt, ...) | |||
18 | size_t size = hpp->size; | 19 | size_t size = hpp->size; |
19 | 20 | ||
20 | va_start(args, fmt); | 21 | va_start(args, fmt); |
22 | len = va_arg(args, int); | ||
21 | percent = va_arg(args, double); | 23 | percent = va_arg(args, double); |
22 | va_end(args); | 24 | va_end(args); |
23 | 25 | ||
@@ -25,7 +27,7 @@ static int __percent_color_snprintf(struct perf_hpp *hpp, const char *fmt, ...) | |||
25 | if (markup) | 27 | if (markup) |
26 | ret += scnprintf(buf, size, markup); | 28 | ret += scnprintf(buf, size, markup); |
27 | 29 | ||
28 | ret += scnprintf(buf + ret, size - ret, fmt, percent); | 30 | ret += scnprintf(buf + ret, size - ret, fmt, len, percent); |
29 | 31 | ||
30 | if (markup) | 32 | if (markup) |
31 | ret += scnprintf(buf + ret, size - ret, "</span>"); | 33 | ret += scnprintf(buf + ret, size - ret, "</span>"); |
@@ -39,12 +41,12 @@ static u64 he_get_##_field(struct hist_entry *he) \ | |||
39 | return he->stat._field; \ | 41 | return he->stat._field; \ |
40 | } \ | 42 | } \ |
41 | \ | 43 | \ |
42 | static int perf_gtk__hpp_color_##_type(struct perf_hpp_fmt *fmt __maybe_unused, \ | 44 | static int perf_gtk__hpp_color_##_type(struct perf_hpp_fmt *fmt, \ |
43 | struct perf_hpp *hpp, \ | 45 | struct perf_hpp *hpp, \ |
44 | struct hist_entry *he) \ | 46 | struct hist_entry *he) \ |
45 | { \ | 47 | { \ |
46 | return __hpp__fmt(hpp, he, he_get_##_field, " %6.2f%%", \ | 48 | return hpp__fmt(fmt, hpp, he, he_get_##_field, " %*.2f%%", \ |
47 | __percent_color_snprintf, true); \ | 49 | __percent_color_snprintf, true); \ |
48 | } | 50 | } |
49 | 51 | ||
50 | #define __HPP_COLOR_ACC_PERCENT_FN(_type, _field) \ | 52 | #define __HPP_COLOR_ACC_PERCENT_FN(_type, _field) \ |
@@ -57,8 +59,8 @@ static int perf_gtk__hpp_color_##_type(struct perf_hpp_fmt *fmt __maybe_unused, | |||
57 | struct perf_hpp *hpp, \ | 59 | struct perf_hpp *hpp, \ |
58 | struct hist_entry *he) \ | 60 | struct hist_entry *he) \ |
59 | { \ | 61 | { \ |
60 | return __hpp__fmt_acc(hpp, he, he_get_acc_##_field, " %6.2f%%", \ | 62 | return hpp__fmt_acc(fmt, hpp, he, he_get_acc_##_field, " %*.2f%%", \ |
61 | __percent_color_snprintf, true); \ | 63 | __percent_color_snprintf, true); \ |
62 | } | 64 | } |
63 | 65 | ||
64 | __HPP_COLOR_PERCENT_FN(overhead, period) | 66 | __HPP_COLOR_PERCENT_FN(overhead, period) |
@@ -205,10 +207,8 @@ static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists, | |||
205 | if (perf_hpp__is_sort_entry(fmt)) | 207 | if (perf_hpp__is_sort_entry(fmt)) |
206 | sym_col = col_idx; | 208 | sym_col = col_idx; |
207 | 209 | ||
208 | fmt->header(fmt, &hpp, hists_to_evsel(hists)); | ||
209 | |||
210 | gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view), | 210 | gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view), |
211 | -1, ltrim(s), | 211 | -1, fmt->name, |
212 | renderer, "markup", | 212 | renderer, "markup", |
213 | col_idx++, NULL); | 213 | col_idx++, NULL); |
214 | } | 214 | } |
diff --git a/tools/perf/ui/hist.c b/tools/perf/ui/hist.c index 498adb23c02e..2af18376b077 100644 --- a/tools/perf/ui/hist.c +++ b/tools/perf/ui/hist.c | |||
@@ -15,9 +15,9 @@ | |||
15 | __ret; \ | 15 | __ret; \ |
16 | }) | 16 | }) |
17 | 17 | ||
18 | int __hpp__fmt(struct perf_hpp *hpp, struct hist_entry *he, | 18 | static int __hpp__fmt(struct perf_hpp *hpp, struct hist_entry *he, |
19 | hpp_field_fn get_field, const char *fmt, | 19 | hpp_field_fn get_field, const char *fmt, int len, |
20 | hpp_snprint_fn print_fn, bool fmt_percent) | 20 | hpp_snprint_fn print_fn, bool fmt_percent) |
21 | { | 21 | { |
22 | int ret; | 22 | int ret; |
23 | struct hists *hists = he->hists; | 23 | struct hists *hists = he->hists; |
@@ -32,9 +32,9 @@ int __hpp__fmt(struct perf_hpp *hpp, struct hist_entry *he, | |||
32 | if (total) | 32 | if (total) |
33 | percent = 100.0 * get_field(he) / total; | 33 | percent = 100.0 * get_field(he) / total; |
34 | 34 | ||
35 | ret = hpp__call_print_fn(hpp, print_fn, fmt, percent); | 35 | ret = hpp__call_print_fn(hpp, print_fn, fmt, len, percent); |
36 | } else | 36 | } else |
37 | ret = hpp__call_print_fn(hpp, print_fn, fmt, get_field(he)); | 37 | ret = hpp__call_print_fn(hpp, print_fn, fmt, len, get_field(he)); |
38 | 38 | ||
39 | if (perf_evsel__is_group_event(evsel)) { | 39 | if (perf_evsel__is_group_event(evsel)) { |
40 | int prev_idx, idx_delta; | 40 | int prev_idx, idx_delta; |
@@ -60,19 +60,19 @@ int __hpp__fmt(struct perf_hpp *hpp, struct hist_entry *he, | |||
60 | */ | 60 | */ |
61 | if (fmt_percent) { | 61 | if (fmt_percent) { |
62 | ret += hpp__call_print_fn(hpp, print_fn, | 62 | ret += hpp__call_print_fn(hpp, print_fn, |
63 | fmt, 0.0); | 63 | fmt, len, 0.0); |
64 | } else { | 64 | } else { |
65 | ret += hpp__call_print_fn(hpp, print_fn, | 65 | ret += hpp__call_print_fn(hpp, print_fn, |
66 | fmt, 0ULL); | 66 | fmt, len, 0ULL); |
67 | } | 67 | } |
68 | } | 68 | } |
69 | 69 | ||
70 | if (fmt_percent) { | 70 | if (fmt_percent) { |
71 | ret += hpp__call_print_fn(hpp, print_fn, fmt, | 71 | ret += hpp__call_print_fn(hpp, print_fn, fmt, len, |
72 | 100.0 * period / total); | 72 | 100.0 * period / total); |
73 | } else { | 73 | } else { |
74 | ret += hpp__call_print_fn(hpp, print_fn, fmt, | 74 | ret += hpp__call_print_fn(hpp, print_fn, fmt, |
75 | period); | 75 | len, period); |
76 | } | 76 | } |
77 | 77 | ||
78 | prev_idx = perf_evsel__group_idx(evsel); | 78 | prev_idx = perf_evsel__group_idx(evsel); |
@@ -86,10 +86,10 @@ int __hpp__fmt(struct perf_hpp *hpp, struct hist_entry *he, | |||
86 | */ | 86 | */ |
87 | if (fmt_percent) { | 87 | if (fmt_percent) { |
88 | ret += hpp__call_print_fn(hpp, print_fn, | 88 | ret += hpp__call_print_fn(hpp, print_fn, |
89 | fmt, 0.0); | 89 | fmt, len, 0.0); |
90 | } else { | 90 | } else { |
91 | ret += hpp__call_print_fn(hpp, print_fn, | 91 | ret += hpp__call_print_fn(hpp, print_fn, |
92 | fmt, 0ULL); | 92 | fmt, len, 0ULL); |
93 | } | 93 | } |
94 | } | 94 | } |
95 | } | 95 | } |
@@ -104,16 +104,35 @@ int __hpp__fmt(struct perf_hpp *hpp, struct hist_entry *he, | |||
104 | return ret; | 104 | return ret; |
105 | } | 105 | } |
106 | 106 | ||
107 | int __hpp__fmt_acc(struct perf_hpp *hpp, struct hist_entry *he, | 107 | int hpp__fmt(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp, |
108 | hpp_field_fn get_field, const char *fmt, | 108 | struct hist_entry *he, hpp_field_fn get_field, |
109 | hpp_snprint_fn print_fn, bool fmt_percent) | 109 | const char *fmtstr, hpp_snprint_fn print_fn, bool fmt_percent) |
110 | { | ||
111 | int len = fmt->user_len ?: fmt->len; | ||
112 | |||
113 | if (symbol_conf.field_sep) { | ||
114 | return __hpp__fmt(hpp, he, get_field, fmtstr, 1, | ||
115 | print_fn, fmt_percent); | ||
116 | } | ||
117 | |||
118 | if (fmt_percent) | ||
119 | len -= 2; /* 2 for a space and a % sign */ | ||
120 | else | ||
121 | len -= 1; | ||
122 | |||
123 | return __hpp__fmt(hpp, he, get_field, fmtstr, len, print_fn, fmt_percent); | ||
124 | } | ||
125 | |||
126 | int hpp__fmt_acc(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp, | ||
127 | struct hist_entry *he, hpp_field_fn get_field, | ||
128 | const char *fmtstr, hpp_snprint_fn print_fn, bool fmt_percent) | ||
110 | { | 129 | { |
111 | if (!symbol_conf.cumulate_callchain) { | 130 | if (!symbol_conf.cumulate_callchain) { |
112 | return snprintf(hpp->buf, hpp->size, "%*s", | 131 | int len = fmt->user_len ?: fmt->len; |
113 | fmt_percent ? 8 : 12, "N/A"); | 132 | return snprintf(hpp->buf, hpp->size, " %*s", len - 1, "N/A"); |
114 | } | 133 | } |
115 | 134 | ||
116 | return __hpp__fmt(hpp, he, get_field, fmt, print_fn, fmt_percent); | 135 | return hpp__fmt(fmt, hpp, he, get_field, fmtstr, print_fn, fmt_percent); |
117 | } | 136 | } |
118 | 137 | ||
119 | static int field_cmp(u64 field_a, u64 field_b) | 138 | static int field_cmp(u64 field_a, u64 field_b) |
@@ -190,30 +209,26 @@ static int __hpp__sort_acc(struct hist_entry *a, struct hist_entry *b, | |||
190 | return ret; | 209 | return ret; |
191 | } | 210 | } |
192 | 211 | ||
193 | #define __HPP_HEADER_FN(_type, _str, _min_width, _unit_width) \ | 212 | static int hpp__width_fn(struct perf_hpp_fmt *fmt, |
194 | static int hpp__header_##_type(struct perf_hpp_fmt *fmt __maybe_unused, \ | 213 | struct perf_hpp *hpp __maybe_unused, |
195 | struct perf_hpp *hpp, \ | 214 | struct perf_evsel *evsel) |
196 | struct perf_evsel *evsel) \ | 215 | { |
197 | { \ | 216 | int len = fmt->user_len ?: fmt->len; |
198 | int len = _min_width; \ | 217 | |
199 | \ | 218 | if (symbol_conf.event_group) |
200 | if (symbol_conf.event_group) \ | 219 | len = max(len, evsel->nr_members * fmt->len); |
201 | len = max(len, evsel->nr_members * _unit_width); \ | 220 | |
202 | \ | 221 | if (len < (int)strlen(fmt->name)) |
203 | return scnprintf(hpp->buf, hpp->size, "%*s", len, _str); \ | 222 | len = strlen(fmt->name); |
204 | } | 223 | |
205 | 224 | return len; | |
206 | #define __HPP_WIDTH_FN(_type, _min_width, _unit_width) \ | 225 | } |
207 | static int hpp__width_##_type(struct perf_hpp_fmt *fmt __maybe_unused, \ | 226 | |
208 | struct perf_hpp *hpp __maybe_unused, \ | 227 | static int hpp__header_fn(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp, |
209 | struct perf_evsel *evsel) \ | 228 | struct perf_evsel *evsel) |
210 | { \ | 229 | { |
211 | int len = _min_width; \ | 230 | int len = hpp__width_fn(fmt, hpp, evsel); |
212 | \ | 231 | return scnprintf(hpp->buf, hpp->size, "%*s", len, fmt->name); |
213 | if (symbol_conf.event_group) \ | ||
214 | len = max(len, evsel->nr_members * _unit_width); \ | ||
215 | \ | ||
216 | return len; \ | ||
217 | } | 232 | } |
218 | 233 | ||
219 | static int hpp_color_scnprintf(struct perf_hpp *hpp, const char *fmt, ...) | 234 | static int hpp_color_scnprintf(struct perf_hpp *hpp, const char *fmt, ...) |
@@ -221,11 +236,12 @@ static int hpp_color_scnprintf(struct perf_hpp *hpp, const char *fmt, ...) | |||
221 | va_list args; | 236 | va_list args; |
222 | ssize_t ssize = hpp->size; | 237 | ssize_t ssize = hpp->size; |
223 | double percent; | 238 | double percent; |
224 | int ret; | 239 | int ret, len; |
225 | 240 | ||
226 | va_start(args, fmt); | 241 | va_start(args, fmt); |
242 | len = va_arg(args, int); | ||
227 | percent = va_arg(args, double); | 243 | percent = va_arg(args, double); |
228 | ret = value_color_snprintf(hpp->buf, hpp->size, fmt, percent); | 244 | ret = percent_color_len_snprintf(hpp->buf, hpp->size, fmt, len, percent); |
229 | va_end(args); | 245 | va_end(args); |
230 | 246 | ||
231 | return (ret >= ssize) ? (ssize - 1) : ret; | 247 | return (ret >= ssize) ? (ssize - 1) : ret; |
@@ -250,20 +266,19 @@ static u64 he_get_##_field(struct hist_entry *he) \ | |||
250 | return he->stat._field; \ | 266 | return he->stat._field; \ |
251 | } \ | 267 | } \ |
252 | \ | 268 | \ |
253 | static int hpp__color_##_type(struct perf_hpp_fmt *fmt __maybe_unused, \ | 269 | static int hpp__color_##_type(struct perf_hpp_fmt *fmt, \ |
254 | struct perf_hpp *hpp, struct hist_entry *he) \ | 270 | struct perf_hpp *hpp, struct hist_entry *he) \ |
255 | { \ | 271 | { \ |
256 | return __hpp__fmt(hpp, he, he_get_##_field, " %6.2f%%", \ | 272 | return hpp__fmt(fmt, hpp, he, he_get_##_field, " %*.2f%%", \ |
257 | hpp_color_scnprintf, true); \ | 273 | hpp_color_scnprintf, true); \ |
258 | } | 274 | } |
259 | 275 | ||
260 | #define __HPP_ENTRY_PERCENT_FN(_type, _field) \ | 276 | #define __HPP_ENTRY_PERCENT_FN(_type, _field) \ |
261 | static int hpp__entry_##_type(struct perf_hpp_fmt *_fmt __maybe_unused, \ | 277 | static int hpp__entry_##_type(struct perf_hpp_fmt *fmt, \ |
262 | struct perf_hpp *hpp, struct hist_entry *he) \ | 278 | struct perf_hpp *hpp, struct hist_entry *he) \ |
263 | { \ | 279 | { \ |
264 | const char *fmt = symbol_conf.field_sep ? " %.2f" : " %6.2f%%"; \ | 280 | return hpp__fmt(fmt, hpp, he, he_get_##_field, " %*.2f%%", \ |
265 | return __hpp__fmt(hpp, he, he_get_##_field, fmt, \ | 281 | hpp_entry_scnprintf, true); \ |
266 | hpp_entry_scnprintf, true); \ | ||
267 | } | 282 | } |
268 | 283 | ||
269 | #define __HPP_SORT_FN(_type, _field) \ | 284 | #define __HPP_SORT_FN(_type, _field) \ |
@@ -278,20 +293,19 @@ static u64 he_get_acc_##_field(struct hist_entry *he) \ | |||
278 | return he->stat_acc->_field; \ | 293 | return he->stat_acc->_field; \ |
279 | } \ | 294 | } \ |
280 | \ | 295 | \ |
281 | static int hpp__color_##_type(struct perf_hpp_fmt *fmt __maybe_unused, \ | 296 | static int hpp__color_##_type(struct perf_hpp_fmt *fmt, \ |
282 | struct perf_hpp *hpp, struct hist_entry *he) \ | 297 | struct perf_hpp *hpp, struct hist_entry *he) \ |
283 | { \ | 298 | { \ |
284 | return __hpp__fmt_acc(hpp, he, he_get_acc_##_field, " %6.2f%%", \ | 299 | return hpp__fmt_acc(fmt, hpp, he, he_get_acc_##_field, " %*.2f%%", \ |
285 | hpp_color_scnprintf, true); \ | 300 | hpp_color_scnprintf, true); \ |
286 | } | 301 | } |
287 | 302 | ||
288 | #define __HPP_ENTRY_ACC_PERCENT_FN(_type, _field) \ | 303 | #define __HPP_ENTRY_ACC_PERCENT_FN(_type, _field) \ |
289 | static int hpp__entry_##_type(struct perf_hpp_fmt *_fmt __maybe_unused, \ | 304 | static int hpp__entry_##_type(struct perf_hpp_fmt *fmt, \ |
290 | struct perf_hpp *hpp, struct hist_entry *he) \ | 305 | struct perf_hpp *hpp, struct hist_entry *he) \ |
291 | { \ | 306 | { \ |
292 | const char *fmt = symbol_conf.field_sep ? " %.2f" : " %6.2f%%"; \ | 307 | return hpp__fmt_acc(fmt, hpp, he, he_get_acc_##_field, " %*.2f%%", \ |
293 | return __hpp__fmt_acc(hpp, he, he_get_acc_##_field, fmt, \ | 308 | hpp_entry_scnprintf, true); \ |
294 | hpp_entry_scnprintf, true); \ | ||
295 | } | 309 | } |
296 | 310 | ||
297 | #define __HPP_SORT_ACC_FN(_type, _field) \ | 311 | #define __HPP_SORT_ACC_FN(_type, _field) \ |
@@ -306,12 +320,11 @@ static u64 he_get_raw_##_field(struct hist_entry *he) \ | |||
306 | return he->stat._field; \ | 320 | return he->stat._field; \ |
307 | } \ | 321 | } \ |
308 | \ | 322 | \ |
309 | static int hpp__entry_##_type(struct perf_hpp_fmt *_fmt __maybe_unused, \ | 323 | static int hpp__entry_##_type(struct perf_hpp_fmt *fmt, \ |
310 | struct perf_hpp *hpp, struct hist_entry *he) \ | 324 | struct perf_hpp *hpp, struct hist_entry *he) \ |
311 | { \ | 325 | { \ |
312 | const char *fmt = symbol_conf.field_sep ? " %"PRIu64 : " %11"PRIu64; \ | 326 | return hpp__fmt(fmt, hpp, he, he_get_raw_##_field, " %*"PRIu64, \ |
313 | return __hpp__fmt(hpp, he, he_get_raw_##_field, fmt, \ | 327 | hpp_entry_scnprintf, false); \ |
314 | hpp_entry_scnprintf, false); \ | ||
315 | } | 328 | } |
316 | 329 | ||
317 | #define __HPP_SORT_RAW_FN(_type, _field) \ | 330 | #define __HPP_SORT_RAW_FN(_type, _field) \ |
@@ -321,37 +334,29 @@ static int64_t hpp__sort_##_type(struct hist_entry *a, struct hist_entry *b) \ | |||
321 | } | 334 | } |
322 | 335 | ||
323 | 336 | ||
324 | #define HPP_PERCENT_FNS(_type, _str, _field, _min_width, _unit_width) \ | 337 | #define HPP_PERCENT_FNS(_type, _field) \ |
325 | __HPP_HEADER_FN(_type, _str, _min_width, _unit_width) \ | ||
326 | __HPP_WIDTH_FN(_type, _min_width, _unit_width) \ | ||
327 | __HPP_COLOR_PERCENT_FN(_type, _field) \ | 338 | __HPP_COLOR_PERCENT_FN(_type, _field) \ |
328 | __HPP_ENTRY_PERCENT_FN(_type, _field) \ | 339 | __HPP_ENTRY_PERCENT_FN(_type, _field) \ |
329 | __HPP_SORT_FN(_type, _field) | 340 | __HPP_SORT_FN(_type, _field) |
330 | 341 | ||
331 | #define HPP_PERCENT_ACC_FNS(_type, _str, _field, _min_width, _unit_width)\ | 342 | #define HPP_PERCENT_ACC_FNS(_type, _field) \ |
332 | __HPP_HEADER_FN(_type, _str, _min_width, _unit_width) \ | ||
333 | __HPP_WIDTH_FN(_type, _min_width, _unit_width) \ | ||
334 | __HPP_COLOR_ACC_PERCENT_FN(_type, _field) \ | 343 | __HPP_COLOR_ACC_PERCENT_FN(_type, _field) \ |
335 | __HPP_ENTRY_ACC_PERCENT_FN(_type, _field) \ | 344 | __HPP_ENTRY_ACC_PERCENT_FN(_type, _field) \ |
336 | __HPP_SORT_ACC_FN(_type, _field) | 345 | __HPP_SORT_ACC_FN(_type, _field) |
337 | 346 | ||
338 | #define HPP_RAW_FNS(_type, _str, _field, _min_width, _unit_width) \ | 347 | #define HPP_RAW_FNS(_type, _field) \ |
339 | __HPP_HEADER_FN(_type, _str, _min_width, _unit_width) \ | ||
340 | __HPP_WIDTH_FN(_type, _min_width, _unit_width) \ | ||
341 | __HPP_ENTRY_RAW_FN(_type, _field) \ | 348 | __HPP_ENTRY_RAW_FN(_type, _field) \ |
342 | __HPP_SORT_RAW_FN(_type, _field) | 349 | __HPP_SORT_RAW_FN(_type, _field) |
343 | 350 | ||
344 | __HPP_HEADER_FN(overhead_self, "Self", 8, 8) | 351 | HPP_PERCENT_FNS(overhead, period) |
345 | 352 | HPP_PERCENT_FNS(overhead_sys, period_sys) | |
346 | HPP_PERCENT_FNS(overhead, "Overhead", period, 8, 8) | 353 | HPP_PERCENT_FNS(overhead_us, period_us) |
347 | HPP_PERCENT_FNS(overhead_sys, "sys", period_sys, 8, 8) | 354 | HPP_PERCENT_FNS(overhead_guest_sys, period_guest_sys) |
348 | HPP_PERCENT_FNS(overhead_us, "usr", period_us, 8, 8) | 355 | HPP_PERCENT_FNS(overhead_guest_us, period_guest_us) |
349 | HPP_PERCENT_FNS(overhead_guest_sys, "guest sys", period_guest_sys, 9, 8) | 356 | HPP_PERCENT_ACC_FNS(overhead_acc, period) |
350 | HPP_PERCENT_FNS(overhead_guest_us, "guest usr", period_guest_us, 9, 8) | ||
351 | HPP_PERCENT_ACC_FNS(overhead_acc, "Children", period, 8, 8) | ||
352 | 357 | ||
353 | HPP_RAW_FNS(samples, "Samples", nr_events, 12, 12) | 358 | HPP_RAW_FNS(samples, nr_events) |
354 | HPP_RAW_FNS(period, "Period", period, 12, 12) | 359 | HPP_RAW_FNS(period, period) |
355 | 360 | ||
356 | static int64_t hpp__nop_cmp(struct hist_entry *a __maybe_unused, | 361 | static int64_t hpp__nop_cmp(struct hist_entry *a __maybe_unused, |
357 | struct hist_entry *b __maybe_unused) | 362 | struct hist_entry *b __maybe_unused) |
@@ -359,47 +364,50 @@ static int64_t hpp__nop_cmp(struct hist_entry *a __maybe_unused, | |||
359 | return 0; | 364 | return 0; |
360 | } | 365 | } |
361 | 366 | ||
362 | #define HPP__COLOR_PRINT_FNS(_name) \ | 367 | #define HPP__COLOR_PRINT_FNS(_name, _fn) \ |
363 | { \ | 368 | { \ |
364 | .header = hpp__header_ ## _name, \ | 369 | .name = _name, \ |
365 | .width = hpp__width_ ## _name, \ | 370 | .header = hpp__header_fn, \ |
366 | .color = hpp__color_ ## _name, \ | 371 | .width = hpp__width_fn, \ |
367 | .entry = hpp__entry_ ## _name, \ | 372 | .color = hpp__color_ ## _fn, \ |
373 | .entry = hpp__entry_ ## _fn, \ | ||
368 | .cmp = hpp__nop_cmp, \ | 374 | .cmp = hpp__nop_cmp, \ |
369 | .collapse = hpp__nop_cmp, \ | 375 | .collapse = hpp__nop_cmp, \ |
370 | .sort = hpp__sort_ ## _name, \ | 376 | .sort = hpp__sort_ ## _fn, \ |
371 | } | 377 | } |
372 | 378 | ||
373 | #define HPP__COLOR_ACC_PRINT_FNS(_name) \ | 379 | #define HPP__COLOR_ACC_PRINT_FNS(_name, _fn) \ |
374 | { \ | 380 | { \ |
375 | .header = hpp__header_ ## _name, \ | 381 | .name = _name, \ |
376 | .width = hpp__width_ ## _name, \ | 382 | .header = hpp__header_fn, \ |
377 | .color = hpp__color_ ## _name, \ | 383 | .width = hpp__width_fn, \ |
378 | .entry = hpp__entry_ ## _name, \ | 384 | .color = hpp__color_ ## _fn, \ |
385 | .entry = hpp__entry_ ## _fn, \ | ||
379 | .cmp = hpp__nop_cmp, \ | 386 | .cmp = hpp__nop_cmp, \ |
380 | .collapse = hpp__nop_cmp, \ | 387 | .collapse = hpp__nop_cmp, \ |
381 | .sort = hpp__sort_ ## _name, \ | 388 | .sort = hpp__sort_ ## _fn, \ |
382 | } | 389 | } |
383 | 390 | ||
384 | #define HPP__PRINT_FNS(_name) \ | 391 | #define HPP__PRINT_FNS(_name, _fn) \ |
385 | { \ | 392 | { \ |
386 | .header = hpp__header_ ## _name, \ | 393 | .name = _name, \ |
387 | .width = hpp__width_ ## _name, \ | 394 | .header = hpp__header_fn, \ |
388 | .entry = hpp__entry_ ## _name, \ | 395 | .width = hpp__width_fn, \ |
396 | .entry = hpp__entry_ ## _fn, \ | ||
389 | .cmp = hpp__nop_cmp, \ | 397 | .cmp = hpp__nop_cmp, \ |
390 | .collapse = hpp__nop_cmp, \ | 398 | .collapse = hpp__nop_cmp, \ |
391 | .sort = hpp__sort_ ## _name, \ | 399 | .sort = hpp__sort_ ## _fn, \ |
392 | } | 400 | } |
393 | 401 | ||
394 | struct perf_hpp_fmt perf_hpp__format[] = { | 402 | struct perf_hpp_fmt perf_hpp__format[] = { |
395 | HPP__COLOR_PRINT_FNS(overhead), | 403 | HPP__COLOR_PRINT_FNS("Overhead", overhead), |
396 | HPP__COLOR_PRINT_FNS(overhead_sys), | 404 | HPP__COLOR_PRINT_FNS("sys", overhead_sys), |
397 | HPP__COLOR_PRINT_FNS(overhead_us), | 405 | HPP__COLOR_PRINT_FNS("usr", overhead_us), |
398 | HPP__COLOR_PRINT_FNS(overhead_guest_sys), | 406 | HPP__COLOR_PRINT_FNS("guest sys", overhead_guest_sys), |
399 | HPP__COLOR_PRINT_FNS(overhead_guest_us), | 407 | HPP__COLOR_PRINT_FNS("guest usr", overhead_guest_us), |
400 | HPP__COLOR_ACC_PRINT_FNS(overhead_acc), | 408 | HPP__COLOR_ACC_PRINT_FNS("Children", overhead_acc), |
401 | HPP__PRINT_FNS(samples), | 409 | HPP__PRINT_FNS("Samples", samples), |
402 | HPP__PRINT_FNS(period) | 410 | HPP__PRINT_FNS("Period", period) |
403 | }; | 411 | }; |
404 | 412 | ||
405 | LIST_HEAD(perf_hpp__list); | 413 | LIST_HEAD(perf_hpp__list); |
@@ -444,14 +452,12 @@ void perf_hpp__init(void) | |||
444 | /* | 452 | /* |
445 | * If user specified field order, no need to setup default fields. | 453 | * If user specified field order, no need to setup default fields. |
446 | */ | 454 | */ |
447 | if (field_order) | 455 | if (is_strict_order(field_order)) |
448 | return; | 456 | return; |
449 | 457 | ||
450 | if (symbol_conf.cumulate_callchain) { | 458 | if (symbol_conf.cumulate_callchain) { |
451 | perf_hpp__column_enable(PERF_HPP__OVERHEAD_ACC); | 459 | perf_hpp__column_enable(PERF_HPP__OVERHEAD_ACC); |
452 | 460 | perf_hpp__format[PERF_HPP__OVERHEAD].name = "Self"; | |
453 | perf_hpp__format[PERF_HPP__OVERHEAD].header = | ||
454 | hpp__header_overhead_self; | ||
455 | } | 461 | } |
456 | 462 | ||
457 | perf_hpp__column_enable(PERF_HPP__OVERHEAD); | 463 | perf_hpp__column_enable(PERF_HPP__OVERHEAD); |
@@ -513,11 +519,11 @@ void perf_hpp__column_disable(unsigned col) | |||
513 | 519 | ||
514 | void perf_hpp__cancel_cumulate(void) | 520 | void perf_hpp__cancel_cumulate(void) |
515 | { | 521 | { |
516 | if (field_order) | 522 | if (is_strict_order(field_order)) |
517 | return; | 523 | return; |
518 | 524 | ||
519 | perf_hpp__column_disable(PERF_HPP__OVERHEAD_ACC); | 525 | perf_hpp__column_disable(PERF_HPP__OVERHEAD_ACC); |
520 | perf_hpp__format[PERF_HPP__OVERHEAD].header = hpp__header_overhead; | 526 | perf_hpp__format[PERF_HPP__OVERHEAD].name = "Overhead"; |
521 | } | 527 | } |
522 | 528 | ||
523 | void perf_hpp__setup_output_field(void) | 529 | void perf_hpp__setup_output_field(void) |
@@ -622,3 +628,59 @@ unsigned int hists__sort_list_width(struct hists *hists) | |||
622 | 628 | ||
623 | return ret; | 629 | return ret; |
624 | } | 630 | } |
631 | |||
632 | void perf_hpp__reset_width(struct perf_hpp_fmt *fmt, struct hists *hists) | ||
633 | { | ||
634 | int idx; | ||
635 | |||
636 | if (perf_hpp__is_sort_entry(fmt)) | ||
637 | return perf_hpp__reset_sort_width(fmt, hists); | ||
638 | |||
639 | for (idx = 0; idx < PERF_HPP__MAX_INDEX; idx++) { | ||
640 | if (fmt == &perf_hpp__format[idx]) | ||
641 | break; | ||
642 | } | ||
643 | |||
644 | if (idx == PERF_HPP__MAX_INDEX) | ||
645 | return; | ||
646 | |||
647 | switch (idx) { | ||
648 | case PERF_HPP__OVERHEAD: | ||
649 | case PERF_HPP__OVERHEAD_SYS: | ||
650 | case PERF_HPP__OVERHEAD_US: | ||
651 | case PERF_HPP__OVERHEAD_ACC: | ||
652 | fmt->len = 8; | ||
653 | break; | ||
654 | |||
655 | case PERF_HPP__OVERHEAD_GUEST_SYS: | ||
656 | case PERF_HPP__OVERHEAD_GUEST_US: | ||
657 | fmt->len = 9; | ||
658 | break; | ||
659 | |||
660 | case PERF_HPP__SAMPLES: | ||
661 | case PERF_HPP__PERIOD: | ||
662 | fmt->len = 12; | ||
663 | break; | ||
664 | |||
665 | default: | ||
666 | break; | ||
667 | } | ||
668 | } | ||
669 | |||
670 | void perf_hpp__set_user_width(const char *width_list_str) | ||
671 | { | ||
672 | struct perf_hpp_fmt *fmt; | ||
673 | const char *ptr = width_list_str; | ||
674 | |||
675 | perf_hpp__for_each_format(fmt) { | ||
676 | char *p; | ||
677 | |||
678 | int len = strtol(ptr, &p, 10); | ||
679 | fmt->user_len = len; | ||
680 | |||
681 | if (*p == ',') | ||
682 | ptr = p + 1; | ||
683 | else | ||
684 | break; | ||
685 | } | ||
686 | } | ||
diff --git a/tools/perf/ui/stdio/hist.c b/tools/perf/ui/stdio/hist.c index 40af0acb4fe9..15b451acbde6 100644 --- a/tools/perf/ui/stdio/hist.c +++ b/tools/perf/ui/stdio/hist.c | |||
@@ -395,10 +395,12 @@ size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows, | |||
395 | 395 | ||
396 | init_rem_hits(); | 396 | init_rem_hits(); |
397 | 397 | ||
398 | |||
399 | perf_hpp__for_each_format(fmt) | 398 | perf_hpp__for_each_format(fmt) |
400 | perf_hpp__reset_width(fmt, hists); | 399 | perf_hpp__reset_width(fmt, hists); |
401 | 400 | ||
401 | if (symbol_conf.col_width_list_str) | ||
402 | perf_hpp__set_user_width(symbol_conf.col_width_list_str); | ||
403 | |||
402 | if (!show_header) | 404 | if (!show_header) |
403 | goto print_entries; | 405 | goto print_entries; |
404 | 406 | ||
diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index 809b4c50beae..36437527dbb3 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c | |||
@@ -232,9 +232,16 @@ static int mov__parse(struct ins_operands *ops) | |||
232 | return -1; | 232 | return -1; |
233 | 233 | ||
234 | target = ++s; | 234 | target = ++s; |
235 | comment = strchr(s, '#'); | ||
235 | 236 | ||
236 | while (s[0] != '\0' && !isspace(s[0])) | 237 | if (comment != NULL) |
237 | ++s; | 238 | s = comment - 1; |
239 | else | ||
240 | s = strchr(s, '\0') - 1; | ||
241 | |||
242 | while (s > target && isspace(s[0])) | ||
243 | --s; | ||
244 | s++; | ||
238 | prev = *s; | 245 | prev = *s; |
239 | *s = '\0'; | 246 | *s = '\0'; |
240 | 247 | ||
@@ -244,7 +251,6 @@ static int mov__parse(struct ins_operands *ops) | |||
244 | if (ops->target.raw == NULL) | 251 | if (ops->target.raw == NULL) |
245 | goto out_free_source; | 252 | goto out_free_source; |
246 | 253 | ||
247 | comment = strchr(s, '#'); | ||
248 | if (comment == NULL) | 254 | if (comment == NULL) |
249 | return 0; | 255 | return 0; |
250 | 256 | ||
@@ -899,10 +905,8 @@ int symbol__annotate(struct symbol *sym, struct map *map, size_t privsize) | |||
899 | struct kcore_extract kce; | 905 | struct kcore_extract kce; |
900 | bool delete_extract = false; | 906 | bool delete_extract = false; |
901 | 907 | ||
902 | if (filename) { | 908 | if (filename) |
903 | snprintf(symfs_filename, sizeof(symfs_filename), "%s%s", | 909 | symbol__join_symfs(symfs_filename, filename); |
904 | symbol_conf.symfs, filename); | ||
905 | } | ||
906 | 910 | ||
907 | if (filename == NULL) { | 911 | if (filename == NULL) { |
908 | if (dso->has_build_id) { | 912 | if (dso->has_build_id) { |
@@ -922,8 +926,7 @@ fallback: | |||
922 | * DSO is the same as when 'perf record' ran. | 926 | * DSO is the same as when 'perf record' ran. |
923 | */ | 927 | */ |
924 | filename = (char *)dso->long_name; | 928 | filename = (char *)dso->long_name; |
925 | snprintf(symfs_filename, sizeof(symfs_filename), "%s%s", | 929 | symbol__join_symfs(symfs_filename, filename); |
926 | symbol_conf.symfs, filename); | ||
927 | free_filename = false; | 930 | free_filename = false; |
928 | } | 931 | } |
929 | 932 | ||
diff --git a/tools/perf/util/cache.h b/tools/perf/util/cache.h index 7b176dd02e1a..5cf9e1b5989d 100644 --- a/tools/perf/util/cache.h +++ b/tools/perf/util/cache.h | |||
@@ -22,6 +22,7 @@ typedef int (*config_fn_t)(const char *, const char *, void *); | |||
22 | extern int perf_default_config(const char *, const char *, void *); | 22 | extern int perf_default_config(const char *, const char *, void *); |
23 | extern int perf_config(config_fn_t fn, void *); | 23 | extern int perf_config(config_fn_t fn, void *); |
24 | extern int perf_config_int(const char *, const char *); | 24 | extern int perf_config_int(const char *, const char *); |
25 | extern u64 perf_config_u64(const char *, const char *); | ||
25 | extern int perf_config_bool(const char *, const char *); | 26 | extern int perf_config_bool(const char *, const char *); |
26 | extern int config_error_nonbool(const char *); | 27 | extern int config_error_nonbool(const char *); |
27 | extern const char *perf_config_dirname(const char *, const char *); | 28 | extern const char *perf_config_dirname(const char *, const char *); |
diff --git a/tools/perf/util/callchain.c b/tools/perf/util/callchain.c index 437ee09727e6..c84d3f8dcb75 100644 --- a/tools/perf/util/callchain.c +++ b/tools/perf/util/callchain.c | |||
@@ -25,77 +25,172 @@ | |||
25 | 25 | ||
26 | __thread struct callchain_cursor callchain_cursor; | 26 | __thread struct callchain_cursor callchain_cursor; |
27 | 27 | ||
28 | int | 28 | #ifdef HAVE_DWARF_UNWIND_SUPPORT |
29 | parse_callchain_report_opt(const char *arg) | 29 | static int get_stack_size(const char *str, unsigned long *_size) |
30 | { | 30 | { |
31 | char *tok, *tok2; | ||
32 | char *endptr; | 31 | char *endptr; |
32 | unsigned long size; | ||
33 | unsigned long max_size = round_down(USHRT_MAX, sizeof(u64)); | ||
33 | 34 | ||
34 | symbol_conf.use_callchain = true; | 35 | size = strtoul(str, &endptr, 0); |
35 | 36 | ||
36 | if (!arg) | 37 | do { |
38 | if (*endptr) | ||
39 | break; | ||
40 | |||
41 | size = round_up(size, sizeof(u64)); | ||
42 | if (!size || size > max_size) | ||
43 | break; | ||
44 | |||
45 | *_size = size; | ||
37 | return 0; | 46 | return 0; |
38 | 47 | ||
39 | tok = strtok((char *)arg, ","); | 48 | } while (0); |
40 | if (!tok) | ||
41 | return -1; | ||
42 | 49 | ||
43 | /* get the output mode */ | 50 | pr_err("callchain: Incorrect stack dump size (max %ld): %s\n", |
44 | if (!strncmp(tok, "graph", strlen(arg))) { | 51 | max_size, str); |
45 | callchain_param.mode = CHAIN_GRAPH_ABS; | 52 | return -1; |
53 | } | ||
54 | #endif /* HAVE_DWARF_UNWIND_SUPPORT */ | ||
46 | 55 | ||
47 | } else if (!strncmp(tok, "flat", strlen(arg))) { | 56 | int parse_callchain_record_opt(const char *arg) |
48 | callchain_param.mode = CHAIN_FLAT; | 57 | { |
49 | } else if (!strncmp(tok, "fractal", strlen(arg))) { | 58 | char *tok, *name, *saveptr = NULL; |
50 | callchain_param.mode = CHAIN_GRAPH_REL; | 59 | char *buf; |
51 | } else if (!strncmp(tok, "none", strlen(arg))) { | 60 | int ret = -1; |
52 | callchain_param.mode = CHAIN_NONE; | 61 | |
53 | symbol_conf.use_callchain = false; | 62 | /* We need buffer that we know we can write to. */ |
54 | return 0; | 63 | buf = malloc(strlen(arg) + 1); |
55 | } else { | 64 | if (!buf) |
56 | return -1; | 65 | return -ENOMEM; |
57 | } | 66 | |
67 | strcpy(buf, arg); | ||
68 | |||
69 | tok = strtok_r((char *)buf, ",", &saveptr); | ||
70 | name = tok ? : (char *)buf; | ||
71 | |||
72 | do { | ||
73 | /* Framepointer style */ | ||
74 | if (!strncmp(name, "fp", sizeof("fp"))) { | ||
75 | if (!strtok_r(NULL, ",", &saveptr)) { | ||
76 | callchain_param.record_mode = CALLCHAIN_FP; | ||
77 | ret = 0; | ||
78 | } else | ||
79 | pr_err("callchain: No more arguments " | ||
80 | "needed for -g fp\n"); | ||
81 | break; | ||
58 | 82 | ||
59 | /* get the min percentage */ | 83 | #ifdef HAVE_DWARF_UNWIND_SUPPORT |
60 | tok = strtok(NULL, ","); | 84 | /* Dwarf style */ |
61 | if (!tok) | 85 | } else if (!strncmp(name, "dwarf", sizeof("dwarf"))) { |
62 | goto setup; | 86 | const unsigned long default_stack_dump_size = 8192; |
63 | 87 | ||
64 | callchain_param.min_percent = strtod(tok, &endptr); | 88 | ret = 0; |
65 | if (tok == endptr) | 89 | callchain_param.record_mode = CALLCHAIN_DWARF; |
66 | return -1; | 90 | callchain_param.dump_size = default_stack_dump_size; |
67 | 91 | ||
68 | /* get the print limit */ | 92 | tok = strtok_r(NULL, ",", &saveptr); |
69 | tok2 = strtok(NULL, ","); | 93 | if (tok) { |
70 | if (!tok2) | 94 | unsigned long size = 0; |
71 | goto setup; | ||
72 | 95 | ||
73 | if (tok2[0] != 'c') { | 96 | ret = get_stack_size(tok, &size); |
74 | callchain_param.print_limit = strtoul(tok2, &endptr, 0); | 97 | callchain_param.dump_size = size; |
75 | tok2 = strtok(NULL, ","); | 98 | } |
76 | if (!tok2) | 99 | #endif /* HAVE_DWARF_UNWIND_SUPPORT */ |
77 | goto setup; | 100 | } else { |
101 | pr_err("callchain: Unknown --call-graph option " | ||
102 | "value: %s\n", arg); | ||
103 | break; | ||
104 | } | ||
105 | |||
106 | } while (0); | ||
107 | |||
108 | free(buf); | ||
109 | return ret; | ||
110 | } | ||
111 | |||
112 | static int parse_callchain_mode(const char *value) | ||
113 | { | ||
114 | if (!strncmp(value, "graph", strlen(value))) { | ||
115 | callchain_param.mode = CHAIN_GRAPH_ABS; | ||
116 | return 0; | ||
117 | } | ||
118 | if (!strncmp(value, "flat", strlen(value))) { | ||
119 | callchain_param.mode = CHAIN_FLAT; | ||
120 | return 0; | ||
78 | } | 121 | } |
122 | if (!strncmp(value, "fractal", strlen(value))) { | ||
123 | callchain_param.mode = CHAIN_GRAPH_REL; | ||
124 | return 0; | ||
125 | } | ||
126 | return -1; | ||
127 | } | ||
79 | 128 | ||
80 | /* get the call chain order */ | 129 | static int parse_callchain_order(const char *value) |
81 | if (!strncmp(tok2, "caller", strlen("caller"))) | 130 | { |
131 | if (!strncmp(value, "caller", strlen(value))) { | ||
82 | callchain_param.order = ORDER_CALLER; | 132 | callchain_param.order = ORDER_CALLER; |
83 | else if (!strncmp(tok2, "callee", strlen("callee"))) | 133 | return 0; |
134 | } | ||
135 | if (!strncmp(value, "callee", strlen(value))) { | ||
84 | callchain_param.order = ORDER_CALLEE; | 136 | callchain_param.order = ORDER_CALLEE; |
85 | else | 137 | return 0; |
86 | return -1; | 138 | } |
139 | return -1; | ||
140 | } | ||
87 | 141 | ||
88 | /* Get the sort key */ | 142 | static int parse_callchain_sort_key(const char *value) |
89 | tok2 = strtok(NULL, ","); | 143 | { |
90 | if (!tok2) | 144 | if (!strncmp(value, "function", strlen(value))) { |
91 | goto setup; | ||
92 | if (!strncmp(tok2, "function", strlen("function"))) | ||
93 | callchain_param.key = CCKEY_FUNCTION; | 145 | callchain_param.key = CCKEY_FUNCTION; |
94 | else if (!strncmp(tok2, "address", strlen("address"))) | 146 | return 0; |
147 | } | ||
148 | if (!strncmp(value, "address", strlen(value))) { | ||
95 | callchain_param.key = CCKEY_ADDRESS; | 149 | callchain_param.key = CCKEY_ADDRESS; |
96 | else | 150 | return 0; |
97 | return -1; | 151 | } |
98 | setup: | 152 | return -1; |
153 | } | ||
154 | |||
155 | int | ||
156 | parse_callchain_report_opt(const char *arg) | ||
157 | { | ||
158 | char *tok; | ||
159 | char *endptr; | ||
160 | bool minpcnt_set = false; | ||
161 | |||
162 | symbol_conf.use_callchain = true; | ||
163 | |||
164 | if (!arg) | ||
165 | return 0; | ||
166 | |||
167 | while ((tok = strtok((char *)arg, ",")) != NULL) { | ||
168 | if (!strncmp(tok, "none", strlen(tok))) { | ||
169 | callchain_param.mode = CHAIN_NONE; | ||
170 | symbol_conf.use_callchain = false; | ||
171 | return 0; | ||
172 | } | ||
173 | |||
174 | if (!parse_callchain_mode(tok) || | ||
175 | !parse_callchain_order(tok) || | ||
176 | !parse_callchain_sort_key(tok)) { | ||
177 | /* parsing ok - move on to the next */ | ||
178 | } else if (!minpcnt_set) { | ||
179 | /* try to get the min percent */ | ||
180 | callchain_param.min_percent = strtod(tok, &endptr); | ||
181 | if (tok == endptr) | ||
182 | return -1; | ||
183 | minpcnt_set = true; | ||
184 | } else { | ||
185 | /* try print limit at last */ | ||
186 | callchain_param.print_limit = strtoul(tok, &endptr, 0); | ||
187 | if (tok == endptr) | ||
188 | return -1; | ||
189 | } | ||
190 | |||
191 | arg = NULL; | ||
192 | } | ||
193 | |||
99 | if (callchain_register_param(&callchain_param) < 0) { | 194 | if (callchain_register_param(&callchain_param) < 0) { |
100 | pr_err("Can't register callchain params\n"); | 195 | pr_err("Can't register callchain params\n"); |
101 | return -1; | 196 | return -1; |
@@ -103,6 +198,47 @@ setup: | |||
103 | return 0; | 198 | return 0; |
104 | } | 199 | } |
105 | 200 | ||
201 | int perf_callchain_config(const char *var, const char *value) | ||
202 | { | ||
203 | char *endptr; | ||
204 | |||
205 | if (prefixcmp(var, "call-graph.")) | ||
206 | return 0; | ||
207 | var += sizeof("call-graph.") - 1; | ||
208 | |||
209 | if (!strcmp(var, "record-mode")) | ||
210 | return parse_callchain_record_opt(value); | ||
211 | #ifdef HAVE_DWARF_UNWIND_SUPPORT | ||
212 | if (!strcmp(var, "dump-size")) { | ||
213 | unsigned long size = 0; | ||
214 | int ret; | ||
215 | |||
216 | ret = get_stack_size(value, &size); | ||
217 | callchain_param.dump_size = size; | ||
218 | |||
219 | return ret; | ||
220 | } | ||
221 | #endif | ||
222 | if (!strcmp(var, "print-type")) | ||
223 | return parse_callchain_mode(value); | ||
224 | if (!strcmp(var, "order")) | ||
225 | return parse_callchain_order(value); | ||
226 | if (!strcmp(var, "sort-key")) | ||
227 | return parse_callchain_sort_key(value); | ||
228 | if (!strcmp(var, "threshold")) { | ||
229 | callchain_param.min_percent = strtod(value, &endptr); | ||
230 | if (value == endptr) | ||
231 | return -1; | ||
232 | } | ||
233 | if (!strcmp(var, "print-limit")) { | ||
234 | callchain_param.print_limit = strtod(value, &endptr); | ||
235 | if (value == endptr) | ||
236 | return -1; | ||
237 | } | ||
238 | |||
239 | return 0; | ||
240 | } | ||
241 | |||
106 | static void | 242 | static void |
107 | rb_insert_callchain(struct rb_root *root, struct callchain_node *chain, | 243 | rb_insert_callchain(struct rb_root *root, struct callchain_node *chain, |
108 | enum chain_mode mode) | 244 | enum chain_mode mode) |
diff --git a/tools/perf/util/callchain.h b/tools/perf/util/callchain.h index da43619d6173..2a1f5a46543a 100644 --- a/tools/perf/util/callchain.h +++ b/tools/perf/util/callchain.h | |||
@@ -54,6 +54,9 @@ enum chain_key { | |||
54 | }; | 54 | }; |
55 | 55 | ||
56 | struct callchain_param { | 56 | struct callchain_param { |
57 | bool enabled; | ||
58 | enum perf_call_graph_mode record_mode; | ||
59 | u32 dump_size; | ||
57 | enum chain_mode mode; | 60 | enum chain_mode mode; |
58 | u32 print_limit; | 61 | u32 print_limit; |
59 | double min_percent; | 62 | double min_percent; |
@@ -154,7 +157,6 @@ static inline void callchain_cursor_advance(struct callchain_cursor *cursor) | |||
154 | struct option; | 157 | struct option; |
155 | struct hist_entry; | 158 | struct hist_entry; |
156 | 159 | ||
157 | int record_parse_callchain(const char *arg, struct record_opts *opts); | ||
158 | int record_parse_callchain_opt(const struct option *opt, const char *arg, int unset); | 160 | int record_parse_callchain_opt(const struct option *opt, const char *arg, int unset); |
159 | int record_callchain_opt(const struct option *opt, const char *arg, int unset); | 161 | int record_callchain_opt(const struct option *opt, const char *arg, int unset); |
160 | 162 | ||
@@ -166,7 +168,9 @@ int fill_callchain_info(struct addr_location *al, struct callchain_cursor_node * | |||
166 | bool hide_unresolved); | 168 | bool hide_unresolved); |
167 | 169 | ||
168 | extern const char record_callchain_help[]; | 170 | extern const char record_callchain_help[]; |
171 | int parse_callchain_record_opt(const char *arg); | ||
169 | int parse_callchain_report_opt(const char *arg); | 172 | int parse_callchain_report_opt(const char *arg); |
173 | int perf_callchain_config(const char *var, const char *value); | ||
170 | 174 | ||
171 | static inline void callchain_cursor_snapshot(struct callchain_cursor *dest, | 175 | static inline void callchain_cursor_snapshot(struct callchain_cursor *dest, |
172 | struct callchain_cursor *src) | 176 | struct callchain_cursor *src) |
diff --git a/tools/perf/util/cloexec.c b/tools/perf/util/cloexec.c index c5d05ec17220..47b78b3f0325 100644 --- a/tools/perf/util/cloexec.c +++ b/tools/perf/util/cloexec.c | |||
@@ -1,7 +1,9 @@ | |||
1 | #include <sched.h> | ||
1 | #include "util.h" | 2 | #include "util.h" |
2 | #include "../perf.h" | 3 | #include "../perf.h" |
3 | #include "cloexec.h" | 4 | #include "cloexec.h" |
4 | #include "asm/bug.h" | 5 | #include "asm/bug.h" |
6 | #include "debug.h" | ||
5 | 7 | ||
6 | static unsigned long flag = PERF_FLAG_FD_CLOEXEC; | 8 | static unsigned long flag = PERF_FLAG_FD_CLOEXEC; |
7 | 9 | ||
@@ -9,15 +11,30 @@ static int perf_flag_probe(void) | |||
9 | { | 11 | { |
10 | /* use 'safest' configuration as used in perf_evsel__fallback() */ | 12 | /* use 'safest' configuration as used in perf_evsel__fallback() */ |
11 | struct perf_event_attr attr = { | 13 | struct perf_event_attr attr = { |
12 | .type = PERF_COUNT_SW_CPU_CLOCK, | 14 | .type = PERF_TYPE_SOFTWARE, |
13 | .config = PERF_COUNT_SW_CPU_CLOCK, | 15 | .config = PERF_COUNT_SW_CPU_CLOCK, |
16 | .exclude_kernel = 1, | ||
14 | }; | 17 | }; |
15 | int fd; | 18 | int fd; |
16 | int err; | 19 | int err; |
20 | int cpu; | ||
21 | pid_t pid = -1; | ||
22 | char sbuf[STRERR_BUFSIZE]; | ||
17 | 23 | ||
18 | /* check cloexec flag */ | 24 | cpu = sched_getcpu(); |
19 | fd = sys_perf_event_open(&attr, 0, -1, -1, | 25 | if (cpu < 0) |
20 | PERF_FLAG_FD_CLOEXEC); | 26 | cpu = 0; |
27 | |||
28 | while (1) { | ||
29 | /* check cloexec flag */ | ||
30 | fd = sys_perf_event_open(&attr, pid, cpu, -1, | ||
31 | PERF_FLAG_FD_CLOEXEC); | ||
32 | if (fd < 0 && pid == -1 && errno == EACCES) { | ||
33 | pid = 0; | ||
34 | continue; | ||
35 | } | ||
36 | break; | ||
37 | } | ||
21 | err = errno; | 38 | err = errno; |
22 | 39 | ||
23 | if (fd >= 0) { | 40 | if (fd >= 0) { |
@@ -25,17 +42,17 @@ static int perf_flag_probe(void) | |||
25 | return 1; | 42 | return 1; |
26 | } | 43 | } |
27 | 44 | ||
28 | WARN_ONCE(err != EINVAL, | 45 | WARN_ONCE(err != EINVAL && err != EBUSY, |
29 | "perf_event_open(..., PERF_FLAG_FD_CLOEXEC) failed with unexpected error %d (%s)\n", | 46 | "perf_event_open(..., PERF_FLAG_FD_CLOEXEC) failed with unexpected error %d (%s)\n", |
30 | err, strerror(err)); | 47 | err, strerror_r(err, sbuf, sizeof(sbuf))); |
31 | 48 | ||
32 | /* not supported, confirm error related to PERF_FLAG_FD_CLOEXEC */ | 49 | /* not supported, confirm error related to PERF_FLAG_FD_CLOEXEC */ |
33 | fd = sys_perf_event_open(&attr, 0, -1, -1, 0); | 50 | fd = sys_perf_event_open(&attr, pid, cpu, -1, 0); |
34 | err = errno; | 51 | err = errno; |
35 | 52 | ||
36 | if (WARN_ONCE(fd < 0, | 53 | if (WARN_ONCE(fd < 0 && err != EBUSY, |
37 | "perf_event_open(..., 0) failed unexpectedly with error %d (%s)\n", | 54 | "perf_event_open(..., 0) failed unexpectedly with error %d (%s)\n", |
38 | err, strerror(err))) | 55 | err, strerror_r(err, sbuf, sizeof(sbuf)))) |
39 | return -1; | 56 | return -1; |
40 | 57 | ||
41 | close(fd); | 58 | close(fd); |
diff --git a/tools/perf/util/color.c b/tools/perf/util/color.c index 87b8672eb413..f4654183d391 100644 --- a/tools/perf/util/color.c +++ b/tools/perf/util/color.c | |||
@@ -335,3 +335,19 @@ int percent_color_snprintf(char *bf, size_t size, const char *fmt, ...) | |||
335 | va_end(args); | 335 | va_end(args); |
336 | return value_color_snprintf(bf, size, fmt, percent); | 336 | return value_color_snprintf(bf, size, fmt, percent); |
337 | } | 337 | } |
338 | |||
339 | int percent_color_len_snprintf(char *bf, size_t size, const char *fmt, ...) | ||
340 | { | ||
341 | va_list args; | ||
342 | int len; | ||
343 | double percent; | ||
344 | const char *color; | ||
345 | |||
346 | va_start(args, fmt); | ||
347 | len = va_arg(args, int); | ||
348 | percent = va_arg(args, double); | ||
349 | va_end(args); | ||
350 | |||
351 | color = get_percent_color(percent); | ||
352 | return color_snprintf(bf, size, color, fmt, len, percent); | ||
353 | } | ||
diff --git a/tools/perf/util/color.h b/tools/perf/util/color.h index 7ff30a62a132..0a594b8a0c26 100644 --- a/tools/perf/util/color.h +++ b/tools/perf/util/color.h | |||
@@ -41,6 +41,7 @@ int color_fprintf_ln(FILE *fp, const char *color, const char *fmt, ...); | |||
41 | int color_fwrite_lines(FILE *fp, const char *color, size_t count, const char *buf); | 41 | int color_fwrite_lines(FILE *fp, const char *color, size_t count, const char *buf); |
42 | int value_color_snprintf(char *bf, size_t size, const char *fmt, double value); | 42 | int value_color_snprintf(char *bf, size_t size, const char *fmt, double value); |
43 | int percent_color_snprintf(char *bf, size_t size, const char *fmt, ...); | 43 | int percent_color_snprintf(char *bf, size_t size, const char *fmt, ...); |
44 | int percent_color_len_snprintf(char *bf, size_t size, const char *fmt, ...); | ||
44 | int percent_color_fprintf(FILE *fp, const char *fmt, double percent); | 45 | int percent_color_fprintf(FILE *fp, const char *fmt, double percent); |
45 | const char *get_percent_color(double percent); | 46 | const char *get_percent_color(double percent); |
46 | 47 | ||
diff --git a/tools/perf/util/comm.c b/tools/perf/util/comm.c index f9e777629e21..b2bb59df65e1 100644 --- a/tools/perf/util/comm.c +++ b/tools/perf/util/comm.c | |||
@@ -74,7 +74,7 @@ static struct comm_str *comm_str__findnew(const char *str, struct rb_root *root) | |||
74 | return new; | 74 | return new; |
75 | } | 75 | } |
76 | 76 | ||
77 | struct comm *comm__new(const char *str, u64 timestamp) | 77 | struct comm *comm__new(const char *str, u64 timestamp, bool exec) |
78 | { | 78 | { |
79 | struct comm *comm = zalloc(sizeof(*comm)); | 79 | struct comm *comm = zalloc(sizeof(*comm)); |
80 | 80 | ||
@@ -82,6 +82,7 @@ struct comm *comm__new(const char *str, u64 timestamp) | |||
82 | return NULL; | 82 | return NULL; |
83 | 83 | ||
84 | comm->start = timestamp; | 84 | comm->start = timestamp; |
85 | comm->exec = exec; | ||
85 | 86 | ||
86 | comm->comm_str = comm_str__findnew(str, &comm_str_root); | 87 | comm->comm_str = comm_str__findnew(str, &comm_str_root); |
87 | if (!comm->comm_str) { | 88 | if (!comm->comm_str) { |
@@ -94,7 +95,7 @@ struct comm *comm__new(const char *str, u64 timestamp) | |||
94 | return comm; | 95 | return comm; |
95 | } | 96 | } |
96 | 97 | ||
97 | int comm__override(struct comm *comm, const char *str, u64 timestamp) | 98 | int comm__override(struct comm *comm, const char *str, u64 timestamp, bool exec) |
98 | { | 99 | { |
99 | struct comm_str *new, *old = comm->comm_str; | 100 | struct comm_str *new, *old = comm->comm_str; |
100 | 101 | ||
@@ -106,6 +107,8 @@ int comm__override(struct comm *comm, const char *str, u64 timestamp) | |||
106 | comm_str__put(old); | 107 | comm_str__put(old); |
107 | comm->comm_str = new; | 108 | comm->comm_str = new; |
108 | comm->start = timestamp; | 109 | comm->start = timestamp; |
110 | if (exec) | ||
111 | comm->exec = true; | ||
109 | 112 | ||
110 | return 0; | 113 | return 0; |
111 | } | 114 | } |
diff --git a/tools/perf/util/comm.h b/tools/perf/util/comm.h index fac5bd51befc..51c10ab257f8 100644 --- a/tools/perf/util/comm.h +++ b/tools/perf/util/comm.h | |||
@@ -11,11 +11,13 @@ struct comm { | |||
11 | struct comm_str *comm_str; | 11 | struct comm_str *comm_str; |
12 | u64 start; | 12 | u64 start; |
13 | struct list_head list; | 13 | struct list_head list; |
14 | bool exec; | ||
14 | }; | 15 | }; |
15 | 16 | ||
16 | void comm__free(struct comm *comm); | 17 | void comm__free(struct comm *comm); |
17 | struct comm *comm__new(const char *str, u64 timestamp); | 18 | struct comm *comm__new(const char *str, u64 timestamp, bool exec); |
18 | const char *comm__str(const struct comm *comm); | 19 | const char *comm__str(const struct comm *comm); |
19 | int comm__override(struct comm *comm, const char *str, u64 timestamp); | 20 | int comm__override(struct comm *comm, const char *str, u64 timestamp, |
21 | bool exec); | ||
20 | 22 | ||
21 | #endif /* __PERF_COMM_H */ | 23 | #endif /* __PERF_COMM_H */ |
diff --git a/tools/perf/util/config.c b/tools/perf/util/config.c index 1e5e2e5af6b1..57ff826f150b 100644 --- a/tools/perf/util/config.c +++ b/tools/perf/util/config.c | |||
@@ -222,7 +222,8 @@ static int perf_parse_file(config_fn_t fn, void *data) | |||
222 | const unsigned char *bomptr = utf8_bom; | 222 | const unsigned char *bomptr = utf8_bom; |
223 | 223 | ||
224 | for (;;) { | 224 | for (;;) { |
225 | int c = get_next_char(); | 225 | int line, c = get_next_char(); |
226 | |||
226 | if (bomptr && *bomptr) { | 227 | if (bomptr && *bomptr) { |
227 | /* We are at the file beginning; skip UTF8-encoded BOM | 228 | /* We are at the file beginning; skip UTF8-encoded BOM |
228 | * if present. Sane editors won't put this in on their | 229 | * if present. Sane editors won't put this in on their |
@@ -261,8 +262,16 @@ static int perf_parse_file(config_fn_t fn, void *data) | |||
261 | if (!isalpha(c)) | 262 | if (!isalpha(c)) |
262 | break; | 263 | break; |
263 | var[baselen] = tolower(c); | 264 | var[baselen] = tolower(c); |
264 | if (get_value(fn, data, var, baselen+1) < 0) | 265 | |
266 | /* | ||
267 | * The get_value function might or might not reach the '\n', | ||
268 | * so saving the current line number for error reporting. | ||
269 | */ | ||
270 | line = config_linenr; | ||
271 | if (get_value(fn, data, var, baselen+1) < 0) { | ||
272 | config_linenr = line; | ||
265 | break; | 273 | break; |
274 | } | ||
266 | } | 275 | } |
267 | die("bad config file line %d in %s", config_linenr, config_file_name); | 276 | die("bad config file line %d in %s", config_linenr, config_file_name); |
268 | } | 277 | } |
@@ -286,6 +295,21 @@ static int parse_unit_factor(const char *end, unsigned long *val) | |||
286 | return 0; | 295 | return 0; |
287 | } | 296 | } |
288 | 297 | ||
298 | static int perf_parse_llong(const char *value, long long *ret) | ||
299 | { | ||
300 | if (value && *value) { | ||
301 | char *end; | ||
302 | long long val = strtoll(value, &end, 0); | ||
303 | unsigned long factor = 1; | ||
304 | |||
305 | if (!parse_unit_factor(end, &factor)) | ||
306 | return 0; | ||
307 | *ret = val * factor; | ||
308 | return 1; | ||
309 | } | ||
310 | return 0; | ||
311 | } | ||
312 | |||
289 | static int perf_parse_long(const char *value, long *ret) | 313 | static int perf_parse_long(const char *value, long *ret) |
290 | { | 314 | { |
291 | if (value && *value) { | 315 | if (value && *value) { |
@@ -307,6 +331,15 @@ static void die_bad_config(const char *name) | |||
307 | die("bad config value for '%s'", name); | 331 | die("bad config value for '%s'", name); |
308 | } | 332 | } |
309 | 333 | ||
334 | u64 perf_config_u64(const char *name, const char *value) | ||
335 | { | ||
336 | long long ret = 0; | ||
337 | |||
338 | if (!perf_parse_llong(value, &ret)) | ||
339 | die_bad_config(name); | ||
340 | return (u64) ret; | ||
341 | } | ||
342 | |||
310 | int perf_config_int(const char *name, const char *value) | 343 | int perf_config_int(const char *name, const char *value) |
311 | { | 344 | { |
312 | long ret = 0; | 345 | long ret = 0; |
@@ -372,6 +405,9 @@ int perf_default_config(const char *var, const char *value, | |||
372 | if (!prefixcmp(var, "ui.")) | 405 | if (!prefixcmp(var, "ui.")) |
373 | return perf_ui_config(var, value); | 406 | return perf_ui_config(var, value); |
374 | 407 | ||
408 | if (!prefixcmp(var, "call-graph.")) | ||
409 | return perf_callchain_config(var, value); | ||
410 | |||
375 | /* Add other config variables here. */ | 411 | /* Add other config variables here. */ |
376 | return 0; | 412 | return 0; |
377 | } | 413 | } |
diff --git a/tools/perf/util/data.c b/tools/perf/util/data.c index 29d720cf5844..1921942fc2e0 100644 --- a/tools/perf/util/data.c +++ b/tools/perf/util/data.c | |||
@@ -50,12 +50,14 @@ static int open_file_read(struct perf_data_file *file) | |||
50 | { | 50 | { |
51 | struct stat st; | 51 | struct stat st; |
52 | int fd; | 52 | int fd; |
53 | char sbuf[STRERR_BUFSIZE]; | ||
53 | 54 | ||
54 | fd = open(file->path, O_RDONLY); | 55 | fd = open(file->path, O_RDONLY); |
55 | if (fd < 0) { | 56 | if (fd < 0) { |
56 | int err = errno; | 57 | int err = errno; |
57 | 58 | ||
58 | pr_err("failed to open %s: %s", file->path, strerror(err)); | 59 | pr_err("failed to open %s: %s", file->path, |
60 | strerror_r(err, sbuf, sizeof(sbuf))); | ||
59 | if (err == ENOENT && !strcmp(file->path, "perf.data")) | 61 | if (err == ENOENT && !strcmp(file->path, "perf.data")) |
60 | pr_err(" (try 'perf record' first)"); | 62 | pr_err(" (try 'perf record' first)"); |
61 | pr_err("\n"); | 63 | pr_err("\n"); |
@@ -88,6 +90,7 @@ static int open_file_read(struct perf_data_file *file) | |||
88 | static int open_file_write(struct perf_data_file *file) | 90 | static int open_file_write(struct perf_data_file *file) |
89 | { | 91 | { |
90 | int fd; | 92 | int fd; |
93 | char sbuf[STRERR_BUFSIZE]; | ||
91 | 94 | ||
92 | if (check_backup(file)) | 95 | if (check_backup(file)) |
93 | return -1; | 96 | return -1; |
@@ -95,7 +98,8 @@ static int open_file_write(struct perf_data_file *file) | |||
95 | fd = open(file->path, O_CREAT|O_RDWR|O_TRUNC, S_IRUSR|S_IWUSR); | 98 | fd = open(file->path, O_CREAT|O_RDWR|O_TRUNC, S_IRUSR|S_IWUSR); |
96 | 99 | ||
97 | if (fd < 0) | 100 | if (fd < 0) |
98 | pr_err("failed to open %s : %s\n", file->path, strerror(errno)); | 101 | pr_err("failed to open %s : %s\n", file->path, |
102 | strerror_r(errno, sbuf, sizeof(sbuf))); | ||
99 | 103 | ||
100 | return fd; | 104 | return fd; |
101 | } | 105 | } |
diff --git a/tools/perf/util/debug.c b/tools/perf/util/debug.c index 71d419362634..ba357f3226c6 100644 --- a/tools/perf/util/debug.c +++ b/tools/perf/util/debug.c | |||
@@ -13,8 +13,12 @@ | |||
13 | #include "util.h" | 13 | #include "util.h" |
14 | #include "target.h" | 14 | #include "target.h" |
15 | 15 | ||
16 | #define NSECS_PER_SEC 1000000000ULL | ||
17 | #define NSECS_PER_USEC 1000ULL | ||
18 | |||
16 | int verbose; | 19 | int verbose; |
17 | bool dump_trace = false, quiet = false; | 20 | bool dump_trace = false, quiet = false; |
21 | int debug_ordered_events; | ||
18 | 22 | ||
19 | static int _eprintf(int level, int var, const char *fmt, va_list args) | 23 | static int _eprintf(int level, int var, const char *fmt, va_list args) |
20 | { | 24 | { |
@@ -42,6 +46,35 @@ int eprintf(int level, int var, const char *fmt, ...) | |||
42 | return ret; | 46 | return ret; |
43 | } | 47 | } |
44 | 48 | ||
49 | static int __eprintf_time(u64 t, const char *fmt, va_list args) | ||
50 | { | ||
51 | int ret = 0; | ||
52 | u64 secs, usecs, nsecs = t; | ||
53 | |||
54 | secs = nsecs / NSECS_PER_SEC; | ||
55 | nsecs -= secs * NSECS_PER_SEC; | ||
56 | usecs = nsecs / NSECS_PER_USEC; | ||
57 | |||
58 | ret = fprintf(stderr, "[%13" PRIu64 ".%06" PRIu64 "] ", | ||
59 | secs, usecs); | ||
60 | ret += vfprintf(stderr, fmt, args); | ||
61 | return ret; | ||
62 | } | ||
63 | |||
64 | int eprintf_time(int level, int var, u64 t, const char *fmt, ...) | ||
65 | { | ||
66 | int ret = 0; | ||
67 | va_list args; | ||
68 | |||
69 | if (var >= level) { | ||
70 | va_start(args, fmt); | ||
71 | ret = __eprintf_time(t, fmt, args); | ||
72 | va_end(args); | ||
73 | } | ||
74 | |||
75 | return ret; | ||
76 | } | ||
77 | |||
45 | /* | 78 | /* |
46 | * Overloading libtraceevent standard info print | 79 | * Overloading libtraceevent standard info print |
47 | * function, display with -v in perf. | 80 | * function, display with -v in perf. |
@@ -110,7 +143,8 @@ static struct debug_variable { | |||
110 | const char *name; | 143 | const char *name; |
111 | int *ptr; | 144 | int *ptr; |
112 | } debug_variables[] = { | 145 | } debug_variables[] = { |
113 | { .name = "verbose", .ptr = &verbose }, | 146 | { .name = "verbose", .ptr = &verbose }, |
147 | { .name = "ordered-events", .ptr = &debug_ordered_events}, | ||
114 | { .name = NULL, } | 148 | { .name = NULL, } |
115 | }; | 149 | }; |
116 | 150 | ||
diff --git a/tools/perf/util/debug.h b/tools/perf/util/debug.h index 89fb6b0f7ab2..be264d6f3b30 100644 --- a/tools/perf/util/debug.h +++ b/tools/perf/util/debug.h | |||
@@ -3,6 +3,7 @@ | |||
3 | #define __PERF_DEBUG_H | 3 | #define __PERF_DEBUG_H |
4 | 4 | ||
5 | #include <stdbool.h> | 5 | #include <stdbool.h> |
6 | #include <string.h> | ||
6 | #include "event.h" | 7 | #include "event.h" |
7 | #include "../ui/helpline.h" | 8 | #include "../ui/helpline.h" |
8 | #include "../ui/progress.h" | 9 | #include "../ui/progress.h" |
@@ -10,6 +11,7 @@ | |||
10 | 11 | ||
11 | extern int verbose; | 12 | extern int verbose; |
12 | extern bool quiet, dump_trace; | 13 | extern bool quiet, dump_trace; |
14 | extern int debug_ordered_events; | ||
13 | 15 | ||
14 | #ifndef pr_fmt | 16 | #ifndef pr_fmt |
15 | #define pr_fmt(fmt) fmt | 17 | #define pr_fmt(fmt) fmt |
@@ -29,6 +31,14 @@ extern bool quiet, dump_trace; | |||
29 | #define pr_debug3(fmt, ...) pr_debugN(3, pr_fmt(fmt), ##__VA_ARGS__) | 31 | #define pr_debug3(fmt, ...) pr_debugN(3, pr_fmt(fmt), ##__VA_ARGS__) |
30 | #define pr_debug4(fmt, ...) pr_debugN(4, pr_fmt(fmt), ##__VA_ARGS__) | 32 | #define pr_debug4(fmt, ...) pr_debugN(4, pr_fmt(fmt), ##__VA_ARGS__) |
31 | 33 | ||
34 | #define pr_time_N(n, var, t, fmt, ...) \ | ||
35 | eprintf_time(n, var, t, fmt, ##__VA_ARGS__) | ||
36 | |||
37 | #define pr_oe_time(t, fmt, ...) pr_time_N(1, debug_ordered_events, t, pr_fmt(fmt), ##__VA_ARGS__) | ||
38 | #define pr_oe_time2(t, fmt, ...) pr_time_N(2, debug_ordered_events, t, pr_fmt(fmt), ##__VA_ARGS__) | ||
39 | |||
40 | #define STRERR_BUFSIZE 128 /* For the buffer size of strerror_r */ | ||
41 | |||
32 | int dump_printf(const char *fmt, ...) __attribute__((format(printf, 1, 2))); | 42 | int dump_printf(const char *fmt, ...) __attribute__((format(printf, 1, 2))); |
33 | void trace_event(union perf_event *event); | 43 | void trace_event(union perf_event *event); |
34 | 44 | ||
@@ -38,6 +48,7 @@ int ui__warning(const char *format, ...) __attribute__((format(printf, 1, 2))); | |||
38 | void pr_stat(const char *fmt, ...); | 48 | void pr_stat(const char *fmt, ...); |
39 | 49 | ||
40 | int eprintf(int level, int var, const char *fmt, ...) __attribute__((format(printf, 3, 4))); | 50 | int eprintf(int level, int var, const char *fmt, ...) __attribute__((format(printf, 3, 4))); |
51 | int eprintf_time(int level, int var, u64 t, const char *fmt, ...) __attribute__((format(printf, 4, 5))); | ||
41 | 52 | ||
42 | int perf_debug_option(const char *str); | 53 | int perf_debug_option(const char *str); |
43 | 54 | ||
diff --git a/tools/perf/util/dso.c b/tools/perf/util/dso.c index 90d02c661dd4..0247acfdfaca 100644 --- a/tools/perf/util/dso.c +++ b/tools/perf/util/dso.c | |||
@@ -37,6 +37,7 @@ int dso__read_binary_type_filename(const struct dso *dso, | |||
37 | { | 37 | { |
38 | char build_id_hex[BUILD_ID_SIZE * 2 + 1]; | 38 | char build_id_hex[BUILD_ID_SIZE * 2 + 1]; |
39 | int ret = 0; | 39 | int ret = 0; |
40 | size_t len; | ||
40 | 41 | ||
41 | switch (type) { | 42 | switch (type) { |
42 | case DSO_BINARY_TYPE__DEBUGLINK: { | 43 | case DSO_BINARY_TYPE__DEBUGLINK: { |
@@ -60,26 +61,25 @@ int dso__read_binary_type_filename(const struct dso *dso, | |||
60 | break; | 61 | break; |
61 | 62 | ||
62 | case DSO_BINARY_TYPE__FEDORA_DEBUGINFO: | 63 | case DSO_BINARY_TYPE__FEDORA_DEBUGINFO: |
63 | snprintf(filename, size, "%s/usr/lib/debug%s.debug", | 64 | len = __symbol__join_symfs(filename, size, "/usr/lib/debug"); |
64 | symbol_conf.symfs, dso->long_name); | 65 | snprintf(filename + len, size - len, "%s.debug", dso->long_name); |
65 | break; | 66 | break; |
66 | 67 | ||
67 | case DSO_BINARY_TYPE__UBUNTU_DEBUGINFO: | 68 | case DSO_BINARY_TYPE__UBUNTU_DEBUGINFO: |
68 | snprintf(filename, size, "%s/usr/lib/debug%s", | 69 | len = __symbol__join_symfs(filename, size, "/usr/lib/debug"); |
69 | symbol_conf.symfs, dso->long_name); | 70 | snprintf(filename + len, size - len, "%s", dso->long_name); |
70 | break; | 71 | break; |
71 | 72 | ||
72 | case DSO_BINARY_TYPE__OPENEMBEDDED_DEBUGINFO: | 73 | case DSO_BINARY_TYPE__OPENEMBEDDED_DEBUGINFO: |
73 | { | 74 | { |
74 | const char *last_slash; | 75 | const char *last_slash; |
75 | size_t len; | ||
76 | size_t dir_size; | 76 | size_t dir_size; |
77 | 77 | ||
78 | last_slash = dso->long_name + dso->long_name_len; | 78 | last_slash = dso->long_name + dso->long_name_len; |
79 | while (last_slash != dso->long_name && *last_slash != '/') | 79 | while (last_slash != dso->long_name && *last_slash != '/') |
80 | last_slash--; | 80 | last_slash--; |
81 | 81 | ||
82 | len = scnprintf(filename, size, "%s", symbol_conf.symfs); | 82 | len = __symbol__join_symfs(filename, size, ""); |
83 | dir_size = last_slash - dso->long_name + 2; | 83 | dir_size = last_slash - dso->long_name + 2; |
84 | if (dir_size > (size - len)) { | 84 | if (dir_size > (size - len)) { |
85 | ret = -1; | 85 | ret = -1; |
@@ -100,26 +100,24 @@ int dso__read_binary_type_filename(const struct dso *dso, | |||
100 | build_id__sprintf(dso->build_id, | 100 | build_id__sprintf(dso->build_id, |
101 | sizeof(dso->build_id), | 101 | sizeof(dso->build_id), |
102 | build_id_hex); | 102 | build_id_hex); |
103 | snprintf(filename, size, | 103 | len = __symbol__join_symfs(filename, size, "/usr/lib/debug/.build-id/"); |
104 | "%s/usr/lib/debug/.build-id/%.2s/%s.debug", | 104 | snprintf(filename + len, size - len, "%.2s/%s.debug", |
105 | symbol_conf.symfs, build_id_hex, build_id_hex + 2); | 105 | build_id_hex, build_id_hex + 2); |
106 | break; | 106 | break; |
107 | 107 | ||
108 | case DSO_BINARY_TYPE__VMLINUX: | 108 | case DSO_BINARY_TYPE__VMLINUX: |
109 | case DSO_BINARY_TYPE__GUEST_VMLINUX: | 109 | case DSO_BINARY_TYPE__GUEST_VMLINUX: |
110 | case DSO_BINARY_TYPE__SYSTEM_PATH_DSO: | 110 | case DSO_BINARY_TYPE__SYSTEM_PATH_DSO: |
111 | snprintf(filename, size, "%s%s", | 111 | __symbol__join_symfs(filename, size, dso->long_name); |
112 | symbol_conf.symfs, dso->long_name); | ||
113 | break; | 112 | break; |
114 | 113 | ||
115 | case DSO_BINARY_TYPE__GUEST_KMODULE: | 114 | case DSO_BINARY_TYPE__GUEST_KMODULE: |
116 | snprintf(filename, size, "%s%s%s", symbol_conf.symfs, | 115 | path__join3(filename, size, symbol_conf.symfs, |
117 | root_dir, dso->long_name); | 116 | root_dir, dso->long_name); |
118 | break; | 117 | break; |
119 | 118 | ||
120 | case DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE: | 119 | case DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE: |
121 | snprintf(filename, size, "%s%s", symbol_conf.symfs, | 120 | __symbol__join_symfs(filename, size, dso->long_name); |
122 | dso->long_name); | ||
123 | break; | 121 | break; |
124 | 122 | ||
125 | case DSO_BINARY_TYPE__KCORE: | 123 | case DSO_BINARY_TYPE__KCORE: |
@@ -164,13 +162,15 @@ static void close_first_dso(void); | |||
164 | static int do_open(char *name) | 162 | static int do_open(char *name) |
165 | { | 163 | { |
166 | int fd; | 164 | int fd; |
165 | char sbuf[STRERR_BUFSIZE]; | ||
167 | 166 | ||
168 | do { | 167 | do { |
169 | fd = open(name, O_RDONLY); | 168 | fd = open(name, O_RDONLY); |
170 | if (fd >= 0) | 169 | if (fd >= 0) |
171 | return fd; | 170 | return fd; |
172 | 171 | ||
173 | pr_debug("dso open failed, mmap: %s\n", strerror(errno)); | 172 | pr_debug("dso open failed, mmap: %s\n", |
173 | strerror_r(errno, sbuf, sizeof(sbuf))); | ||
174 | if (!dso__data_open_cnt || errno != EMFILE) | 174 | if (!dso__data_open_cnt || errno != EMFILE) |
175 | break; | 175 | break; |
176 | 176 | ||
@@ -532,10 +532,12 @@ static ssize_t cached_read(struct dso *dso, u64 offset, u8 *data, ssize_t size) | |||
532 | static int data_file_size(struct dso *dso) | 532 | static int data_file_size(struct dso *dso) |
533 | { | 533 | { |
534 | struct stat st; | 534 | struct stat st; |
535 | char sbuf[STRERR_BUFSIZE]; | ||
535 | 536 | ||
536 | if (!dso->data.file_size) { | 537 | if (!dso->data.file_size) { |
537 | if (fstat(dso->data.fd, &st)) { | 538 | if (fstat(dso->data.fd, &st)) { |
538 | pr_err("dso mmap failed, fstat: %s\n", strerror(errno)); | 539 | pr_err("dso mmap failed, fstat: %s\n", |
540 | strerror_r(errno, sbuf, sizeof(sbuf))); | ||
539 | return -1; | 541 | return -1; |
540 | } | 542 | } |
541 | dso->data.file_size = st.st_size; | 543 | dso->data.file_size = st.st_size; |
@@ -651,6 +653,65 @@ struct dso *dso__kernel_findnew(struct machine *machine, const char *name, | |||
651 | return dso; | 653 | return dso; |
652 | } | 654 | } |
653 | 655 | ||
656 | /* | ||
657 | * Find a matching entry and/or link current entry to RB tree. | ||
658 | * Either one of the dso or name parameter must be non-NULL or the | ||
659 | * function will not work. | ||
660 | */ | ||
661 | static struct dso *dso__findlink_by_longname(struct rb_root *root, | ||
662 | struct dso *dso, const char *name) | ||
663 | { | ||
664 | struct rb_node **p = &root->rb_node; | ||
665 | struct rb_node *parent = NULL; | ||
666 | |||
667 | if (!name) | ||
668 | name = dso->long_name; | ||
669 | /* | ||
670 | * Find node with the matching name | ||
671 | */ | ||
672 | while (*p) { | ||
673 | struct dso *this = rb_entry(*p, struct dso, rb_node); | ||
674 | int rc = strcmp(name, this->long_name); | ||
675 | |||
676 | parent = *p; | ||
677 | if (rc == 0) { | ||
678 | /* | ||
679 | * In case the new DSO is a duplicate of an existing | ||
680 | * one, print an one-time warning & put the new entry | ||
681 | * at the end of the list of duplicates. | ||
682 | */ | ||
683 | if (!dso || (dso == this)) | ||
684 | return this; /* Find matching dso */ | ||
685 | /* | ||
686 | * The core kernel DSOs may have duplicated long name. | ||
687 | * In this case, the short name should be different. | ||
688 | * Comparing the short names to differentiate the DSOs. | ||
689 | */ | ||
690 | rc = strcmp(dso->short_name, this->short_name); | ||
691 | if (rc == 0) { | ||
692 | pr_err("Duplicated dso name: %s\n", name); | ||
693 | return NULL; | ||
694 | } | ||
695 | } | ||
696 | if (rc < 0) | ||
697 | p = &parent->rb_left; | ||
698 | else | ||
699 | p = &parent->rb_right; | ||
700 | } | ||
701 | if (dso) { | ||
702 | /* Add new node and rebalance tree */ | ||
703 | rb_link_node(&dso->rb_node, parent, p); | ||
704 | rb_insert_color(&dso->rb_node, root); | ||
705 | } | ||
706 | return NULL; | ||
707 | } | ||
708 | |||
709 | static inline struct dso * | ||
710 | dso__find_by_longname(const struct rb_root *root, const char *name) | ||
711 | { | ||
712 | return dso__findlink_by_longname((struct rb_root *)root, NULL, name); | ||
713 | } | ||
714 | |||
654 | void dso__set_long_name(struct dso *dso, const char *name, bool name_allocated) | 715 | void dso__set_long_name(struct dso *dso, const char *name, bool name_allocated) |
655 | { | 716 | { |
656 | if (name == NULL) | 717 | if (name == NULL) |
@@ -753,6 +814,7 @@ struct dso *dso__new(const char *name) | |||
753 | dso->a2l_fails = 1; | 814 | dso->a2l_fails = 1; |
754 | dso->kernel = DSO_TYPE_USER; | 815 | dso->kernel = DSO_TYPE_USER; |
755 | dso->needs_swap = DSO_SWAP__UNSET; | 816 | dso->needs_swap = DSO_SWAP__UNSET; |
817 | RB_CLEAR_NODE(&dso->rb_node); | ||
756 | INIT_LIST_HEAD(&dso->node); | 818 | INIT_LIST_HEAD(&dso->node); |
757 | INIT_LIST_HEAD(&dso->data.open_entry); | 819 | INIT_LIST_HEAD(&dso->data.open_entry); |
758 | } | 820 | } |
@@ -763,6 +825,10 @@ struct dso *dso__new(const char *name) | |||
763 | void dso__delete(struct dso *dso) | 825 | void dso__delete(struct dso *dso) |
764 | { | 826 | { |
765 | int i; | 827 | int i; |
828 | |||
829 | if (!RB_EMPTY_NODE(&dso->rb_node)) | ||
830 | pr_err("DSO %s is still in rbtree when being deleted!\n", | ||
831 | dso->long_name); | ||
766 | for (i = 0; i < MAP__NR_TYPES; ++i) | 832 | for (i = 0; i < MAP__NR_TYPES; ++i) |
767 | symbols__delete(&dso->symbols[i]); | 833 | symbols__delete(&dso->symbols[i]); |
768 | 834 | ||
@@ -849,35 +915,34 @@ bool __dsos__read_build_ids(struct list_head *head, bool with_hits) | |||
849 | return have_build_id; | 915 | return have_build_id; |
850 | } | 916 | } |
851 | 917 | ||
852 | void dsos__add(struct list_head *head, struct dso *dso) | 918 | void dsos__add(struct dsos *dsos, struct dso *dso) |
853 | { | 919 | { |
854 | list_add_tail(&dso->node, head); | 920 | list_add_tail(&dso->node, &dsos->head); |
921 | dso__findlink_by_longname(&dsos->root, dso, NULL); | ||
855 | } | 922 | } |
856 | 923 | ||
857 | struct dso *dsos__find(const struct list_head *head, const char *name, bool cmp_short) | 924 | struct dso *dsos__find(const struct dsos *dsos, const char *name, |
925 | bool cmp_short) | ||
858 | { | 926 | { |
859 | struct dso *pos; | 927 | struct dso *pos; |
860 | 928 | ||
861 | if (cmp_short) { | 929 | if (cmp_short) { |
862 | list_for_each_entry(pos, head, node) | 930 | list_for_each_entry(pos, &dsos->head, node) |
863 | if (strcmp(pos->short_name, name) == 0) | 931 | if (strcmp(pos->short_name, name) == 0) |
864 | return pos; | 932 | return pos; |
865 | return NULL; | 933 | return NULL; |
866 | } | 934 | } |
867 | list_for_each_entry(pos, head, node) | 935 | return dso__find_by_longname(&dsos->root, name); |
868 | if (strcmp(pos->long_name, name) == 0) | ||
869 | return pos; | ||
870 | return NULL; | ||
871 | } | 936 | } |
872 | 937 | ||
873 | struct dso *__dsos__findnew(struct list_head *head, const char *name) | 938 | struct dso *__dsos__findnew(struct dsos *dsos, const char *name) |
874 | { | 939 | { |
875 | struct dso *dso = dsos__find(head, name, false); | 940 | struct dso *dso = dsos__find(dsos, name, false); |
876 | 941 | ||
877 | if (!dso) { | 942 | if (!dso) { |
878 | dso = dso__new(name); | 943 | dso = dso__new(name); |
879 | if (dso != NULL) { | 944 | if (dso != NULL) { |
880 | dsos__add(head, dso); | 945 | dsos__add(dsos, dso); |
881 | dso__set_basename(dso); | 946 | dso__set_basename(dso); |
882 | } | 947 | } |
883 | } | 948 | } |
diff --git a/tools/perf/util/dso.h b/tools/perf/util/dso.h index 5e463c0964d4..acb651acc7fd 100644 --- a/tools/perf/util/dso.h +++ b/tools/perf/util/dso.h | |||
@@ -90,8 +90,18 @@ struct dso_cache { | |||
90 | char data[0]; | 90 | char data[0]; |
91 | }; | 91 | }; |
92 | 92 | ||
93 | /* | ||
94 | * DSOs are put into both a list for fast iteration and rbtree for fast | ||
95 | * long name lookup. | ||
96 | */ | ||
97 | struct dsos { | ||
98 | struct list_head head; | ||
99 | struct rb_root root; /* rbtree root sorted by long name */ | ||
100 | }; | ||
101 | |||
93 | struct dso { | 102 | struct dso { |
94 | struct list_head node; | 103 | struct list_head node; |
104 | struct rb_node rb_node; /* rbtree node sorted by long name */ | ||
95 | struct rb_root symbols[MAP__NR_TYPES]; | 105 | struct rb_root symbols[MAP__NR_TYPES]; |
96 | struct rb_root symbol_names[MAP__NR_TYPES]; | 106 | struct rb_root symbol_names[MAP__NR_TYPES]; |
97 | void *a2l; | 107 | void *a2l; |
@@ -224,10 +234,10 @@ struct map *dso__new_map(const char *name); | |||
224 | struct dso *dso__kernel_findnew(struct machine *machine, const char *name, | 234 | struct dso *dso__kernel_findnew(struct machine *machine, const char *name, |
225 | const char *short_name, int dso_type); | 235 | const char *short_name, int dso_type); |
226 | 236 | ||
227 | void dsos__add(struct list_head *head, struct dso *dso); | 237 | void dsos__add(struct dsos *dsos, struct dso *dso); |
228 | struct dso *dsos__find(const struct list_head *head, const char *name, | 238 | struct dso *dsos__find(const struct dsos *dsos, const char *name, |
229 | bool cmp_short); | 239 | bool cmp_short); |
230 | struct dso *__dsos__findnew(struct list_head *head, const char *name); | 240 | struct dso *__dsos__findnew(struct dsos *dsos, const char *name); |
231 | bool __dsos__read_build_ids(struct list_head *head, bool with_hits); | 241 | bool __dsos__read_build_ids(struct list_head *head, bool with_hits); |
232 | 242 | ||
233 | size_t __dsos__fprintf_buildid(struct list_head *head, FILE *fp, | 243 | size_t __dsos__fprintf_buildid(struct list_head *head, FILE *fp, |
diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c index 1398c83d896d..4af6b279e34a 100644 --- a/tools/perf/util/event.c +++ b/tools/perf/util/event.c | |||
@@ -558,13 +558,17 @@ int perf_event__synthesize_kernel_mmap(struct perf_tool *tool, | |||
558 | struct map *map; | 558 | struct map *map; |
559 | struct kmap *kmap; | 559 | struct kmap *kmap; |
560 | int err; | 560 | int err; |
561 | union perf_event *event; | ||
562 | |||
563 | if (machine->vmlinux_maps[0] == NULL) | ||
564 | return -1; | ||
565 | |||
561 | /* | 566 | /* |
562 | * We should get this from /sys/kernel/sections/.text, but till that is | 567 | * We should get this from /sys/kernel/sections/.text, but till that is |
563 | * available use this, and after it is use this as a fallback for older | 568 | * available use this, and after it is use this as a fallback for older |
564 | * kernels. | 569 | * kernels. |
565 | */ | 570 | */ |
566 | union perf_event *event = zalloc((sizeof(event->mmap) + | 571 | event = zalloc((sizeof(event->mmap) + machine->id_hdr_size)); |
567 | machine->id_hdr_size)); | ||
568 | if (event == NULL) { | 572 | if (event == NULL) { |
569 | pr_debug("Not enough memory synthesizing mmap event " | 573 | pr_debug("Not enough memory synthesizing mmap event " |
570 | "for kernel modules\n"); | 574 | "for kernel modules\n"); |
@@ -784,9 +788,9 @@ try_again: | |||
784 | * "[vdso]" dso, but for now lets use the old trick of looking | 788 | * "[vdso]" dso, but for now lets use the old trick of looking |
785 | * in the whole kernel symbol list. | 789 | * in the whole kernel symbol list. |
786 | */ | 790 | */ |
787 | if ((long long)al->addr < 0 && | 791 | if (cpumode == PERF_RECORD_MISC_USER && machine && |
788 | cpumode == PERF_RECORD_MISC_USER && | 792 | mg != &machine->kmaps && |
789 | machine && mg != &machine->kmaps) { | 793 | machine__kernel_ip(machine, al->addr)) { |
790 | mg = &machine->kmaps; | 794 | mg = &machine->kmaps; |
791 | load_map = true; | 795 | load_map = true; |
792 | goto try_again; | 796 | goto try_again; |
diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h index 94d6976180da..7eb7107731ec 100644 --- a/tools/perf/util/event.h +++ b/tools/perf/util/event.h | |||
@@ -156,6 +156,8 @@ struct perf_sample { | |||
156 | u32 cpu; | 156 | u32 cpu; |
157 | u32 raw_size; | 157 | u32 raw_size; |
158 | u64 data_src; | 158 | u64 data_src; |
159 | u32 flags; | ||
160 | u16 insn_len; | ||
159 | void *raw_data; | 161 | void *raw_data; |
160 | struct ip_callchain *callchain; | 162 | struct ip_callchain *callchain; |
161 | struct branch_stack *branch_stack; | 163 | struct branch_stack *branch_stack; |
diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c index 814e954c1318..3cebc9a8d52e 100644 --- a/tools/perf/util/evlist.c +++ b/tools/perf/util/evlist.c | |||
@@ -25,6 +25,9 @@ | |||
25 | #include <linux/bitops.h> | 25 | #include <linux/bitops.h> |
26 | #include <linux/hash.h> | 26 | #include <linux/hash.h> |
27 | 27 | ||
28 | static void perf_evlist__mmap_put(struct perf_evlist *evlist, int idx); | ||
29 | static void __perf_evlist__munmap(struct perf_evlist *evlist, int idx); | ||
30 | |||
28 | #define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y)) | 31 | #define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y)) |
29 | #define SID(e, x, y) xyarray__entry(e->sample_id, x, y) | 32 | #define SID(e, x, y) xyarray__entry(e->sample_id, x, y) |
30 | 33 | ||
@@ -37,6 +40,7 @@ void perf_evlist__init(struct perf_evlist *evlist, struct cpu_map *cpus, | |||
37 | INIT_HLIST_HEAD(&evlist->heads[i]); | 40 | INIT_HLIST_HEAD(&evlist->heads[i]); |
38 | INIT_LIST_HEAD(&evlist->entries); | 41 | INIT_LIST_HEAD(&evlist->entries); |
39 | perf_evlist__set_maps(evlist, cpus, threads); | 42 | perf_evlist__set_maps(evlist, cpus, threads); |
43 | fdarray__init(&evlist->pollfd, 64); | ||
40 | evlist->workload.pid = -1; | 44 | evlist->workload.pid = -1; |
41 | } | 45 | } |
42 | 46 | ||
@@ -102,7 +106,7 @@ static void perf_evlist__purge(struct perf_evlist *evlist) | |||
102 | void perf_evlist__exit(struct perf_evlist *evlist) | 106 | void perf_evlist__exit(struct perf_evlist *evlist) |
103 | { | 107 | { |
104 | zfree(&evlist->mmap); | 108 | zfree(&evlist->mmap); |
105 | zfree(&evlist->pollfd); | 109 | fdarray__exit(&evlist->pollfd); |
106 | } | 110 | } |
107 | 111 | ||
108 | void perf_evlist__delete(struct perf_evlist *evlist) | 112 | void perf_evlist__delete(struct perf_evlist *evlist) |
@@ -122,6 +126,7 @@ void perf_evlist__add(struct perf_evlist *evlist, struct perf_evsel *entry) | |||
122 | { | 126 | { |
123 | list_add_tail(&entry->node, &evlist->entries); | 127 | list_add_tail(&entry->node, &evlist->entries); |
124 | entry->idx = evlist->nr_entries; | 128 | entry->idx = evlist->nr_entries; |
129 | entry->tracking = !entry->idx; | ||
125 | 130 | ||
126 | if (!evlist->nr_entries++) | 131 | if (!evlist->nr_entries++) |
127 | perf_evlist__set_id_pos(evlist); | 132 | perf_evlist__set_id_pos(evlist); |
@@ -265,17 +270,27 @@ int perf_evlist__add_newtp(struct perf_evlist *evlist, | |||
265 | return 0; | 270 | return 0; |
266 | } | 271 | } |
267 | 272 | ||
273 | static int perf_evlist__nr_threads(struct perf_evlist *evlist, | ||
274 | struct perf_evsel *evsel) | ||
275 | { | ||
276 | if (evsel->system_wide) | ||
277 | return 1; | ||
278 | else | ||
279 | return thread_map__nr(evlist->threads); | ||
280 | } | ||
281 | |||
268 | void perf_evlist__disable(struct perf_evlist *evlist) | 282 | void perf_evlist__disable(struct perf_evlist *evlist) |
269 | { | 283 | { |
270 | int cpu, thread; | 284 | int cpu, thread; |
271 | struct perf_evsel *pos; | 285 | struct perf_evsel *pos; |
272 | int nr_cpus = cpu_map__nr(evlist->cpus); | 286 | int nr_cpus = cpu_map__nr(evlist->cpus); |
273 | int nr_threads = thread_map__nr(evlist->threads); | 287 | int nr_threads; |
274 | 288 | ||
275 | for (cpu = 0; cpu < nr_cpus; cpu++) { | 289 | for (cpu = 0; cpu < nr_cpus; cpu++) { |
276 | evlist__for_each(evlist, pos) { | 290 | evlist__for_each(evlist, pos) { |
277 | if (!perf_evsel__is_group_leader(pos) || !pos->fd) | 291 | if (!perf_evsel__is_group_leader(pos) || !pos->fd) |
278 | continue; | 292 | continue; |
293 | nr_threads = perf_evlist__nr_threads(evlist, pos); | ||
279 | for (thread = 0; thread < nr_threads; thread++) | 294 | for (thread = 0; thread < nr_threads; thread++) |
280 | ioctl(FD(pos, cpu, thread), | 295 | ioctl(FD(pos, cpu, thread), |
281 | PERF_EVENT_IOC_DISABLE, 0); | 296 | PERF_EVENT_IOC_DISABLE, 0); |
@@ -288,12 +303,13 @@ void perf_evlist__enable(struct perf_evlist *evlist) | |||
288 | int cpu, thread; | 303 | int cpu, thread; |
289 | struct perf_evsel *pos; | 304 | struct perf_evsel *pos; |
290 | int nr_cpus = cpu_map__nr(evlist->cpus); | 305 | int nr_cpus = cpu_map__nr(evlist->cpus); |
291 | int nr_threads = thread_map__nr(evlist->threads); | 306 | int nr_threads; |
292 | 307 | ||
293 | for (cpu = 0; cpu < nr_cpus; cpu++) { | 308 | for (cpu = 0; cpu < nr_cpus; cpu++) { |
294 | evlist__for_each(evlist, pos) { | 309 | evlist__for_each(evlist, pos) { |
295 | if (!perf_evsel__is_group_leader(pos) || !pos->fd) | 310 | if (!perf_evsel__is_group_leader(pos) || !pos->fd) |
296 | continue; | 311 | continue; |
312 | nr_threads = perf_evlist__nr_threads(evlist, pos); | ||
297 | for (thread = 0; thread < nr_threads; thread++) | 313 | for (thread = 0; thread < nr_threads; thread++) |
298 | ioctl(FD(pos, cpu, thread), | 314 | ioctl(FD(pos, cpu, thread), |
299 | PERF_EVENT_IOC_ENABLE, 0); | 315 | PERF_EVENT_IOC_ENABLE, 0); |
@@ -305,12 +321,14 @@ int perf_evlist__disable_event(struct perf_evlist *evlist, | |||
305 | struct perf_evsel *evsel) | 321 | struct perf_evsel *evsel) |
306 | { | 322 | { |
307 | int cpu, thread, err; | 323 | int cpu, thread, err; |
324 | int nr_cpus = cpu_map__nr(evlist->cpus); | ||
325 | int nr_threads = perf_evlist__nr_threads(evlist, evsel); | ||
308 | 326 | ||
309 | if (!evsel->fd) | 327 | if (!evsel->fd) |
310 | return 0; | 328 | return 0; |
311 | 329 | ||
312 | for (cpu = 0; cpu < evlist->cpus->nr; cpu++) { | 330 | for (cpu = 0; cpu < nr_cpus; cpu++) { |
313 | for (thread = 0; thread < evlist->threads->nr; thread++) { | 331 | for (thread = 0; thread < nr_threads; thread++) { |
314 | err = ioctl(FD(evsel, cpu, thread), | 332 | err = ioctl(FD(evsel, cpu, thread), |
315 | PERF_EVENT_IOC_DISABLE, 0); | 333 | PERF_EVENT_IOC_DISABLE, 0); |
316 | if (err) | 334 | if (err) |
@@ -324,12 +342,14 @@ int perf_evlist__enable_event(struct perf_evlist *evlist, | |||
324 | struct perf_evsel *evsel) | 342 | struct perf_evsel *evsel) |
325 | { | 343 | { |
326 | int cpu, thread, err; | 344 | int cpu, thread, err; |
345 | int nr_cpus = cpu_map__nr(evlist->cpus); | ||
346 | int nr_threads = perf_evlist__nr_threads(evlist, evsel); | ||
327 | 347 | ||
328 | if (!evsel->fd) | 348 | if (!evsel->fd) |
329 | return -EINVAL; | 349 | return -EINVAL; |
330 | 350 | ||
331 | for (cpu = 0; cpu < evlist->cpus->nr; cpu++) { | 351 | for (cpu = 0; cpu < nr_cpus; cpu++) { |
332 | for (thread = 0; thread < evlist->threads->nr; thread++) { | 352 | for (thread = 0; thread < nr_threads; thread++) { |
333 | err = ioctl(FD(evsel, cpu, thread), | 353 | err = ioctl(FD(evsel, cpu, thread), |
334 | PERF_EVENT_IOC_ENABLE, 0); | 354 | PERF_EVENT_IOC_ENABLE, 0); |
335 | if (err) | 355 | if (err) |
@@ -339,21 +359,111 @@ int perf_evlist__enable_event(struct perf_evlist *evlist, | |||
339 | return 0; | 359 | return 0; |
340 | } | 360 | } |
341 | 361 | ||
342 | static int perf_evlist__alloc_pollfd(struct perf_evlist *evlist) | 362 | static int perf_evlist__enable_event_cpu(struct perf_evlist *evlist, |
363 | struct perf_evsel *evsel, int cpu) | ||
364 | { | ||
365 | int thread, err; | ||
366 | int nr_threads = perf_evlist__nr_threads(evlist, evsel); | ||
367 | |||
368 | if (!evsel->fd) | ||
369 | return -EINVAL; | ||
370 | |||
371 | for (thread = 0; thread < nr_threads; thread++) { | ||
372 | err = ioctl(FD(evsel, cpu, thread), | ||
373 | PERF_EVENT_IOC_ENABLE, 0); | ||
374 | if (err) | ||
375 | return err; | ||
376 | } | ||
377 | return 0; | ||
378 | } | ||
379 | |||
380 | static int perf_evlist__enable_event_thread(struct perf_evlist *evlist, | ||
381 | struct perf_evsel *evsel, | ||
382 | int thread) | ||
383 | { | ||
384 | int cpu, err; | ||
385 | int nr_cpus = cpu_map__nr(evlist->cpus); | ||
386 | |||
387 | if (!evsel->fd) | ||
388 | return -EINVAL; | ||
389 | |||
390 | for (cpu = 0; cpu < nr_cpus; cpu++) { | ||
391 | err = ioctl(FD(evsel, cpu, thread), PERF_EVENT_IOC_ENABLE, 0); | ||
392 | if (err) | ||
393 | return err; | ||
394 | } | ||
395 | return 0; | ||
396 | } | ||
397 | |||
398 | int perf_evlist__enable_event_idx(struct perf_evlist *evlist, | ||
399 | struct perf_evsel *evsel, int idx) | ||
400 | { | ||
401 | bool per_cpu_mmaps = !cpu_map__empty(evlist->cpus); | ||
402 | |||
403 | if (per_cpu_mmaps) | ||
404 | return perf_evlist__enable_event_cpu(evlist, evsel, idx); | ||
405 | else | ||
406 | return perf_evlist__enable_event_thread(evlist, evsel, idx); | ||
407 | } | ||
408 | |||
409 | int perf_evlist__alloc_pollfd(struct perf_evlist *evlist) | ||
343 | { | 410 | { |
344 | int nr_cpus = cpu_map__nr(evlist->cpus); | 411 | int nr_cpus = cpu_map__nr(evlist->cpus); |
345 | int nr_threads = thread_map__nr(evlist->threads); | 412 | int nr_threads = thread_map__nr(evlist->threads); |
346 | int nfds = nr_cpus * nr_threads * evlist->nr_entries; | 413 | int nfds = 0; |
347 | evlist->pollfd = malloc(sizeof(struct pollfd) * nfds); | 414 | struct perf_evsel *evsel; |
348 | return evlist->pollfd != NULL ? 0 : -ENOMEM; | 415 | |
416 | list_for_each_entry(evsel, &evlist->entries, node) { | ||
417 | if (evsel->system_wide) | ||
418 | nfds += nr_cpus; | ||
419 | else | ||
420 | nfds += nr_cpus * nr_threads; | ||
421 | } | ||
422 | |||
423 | if (fdarray__available_entries(&evlist->pollfd) < nfds && | ||
424 | fdarray__grow(&evlist->pollfd, nfds) < 0) | ||
425 | return -ENOMEM; | ||
426 | |||
427 | return 0; | ||
428 | } | ||
429 | |||
430 | static int __perf_evlist__add_pollfd(struct perf_evlist *evlist, int fd, int idx) | ||
431 | { | ||
432 | int pos = fdarray__add(&evlist->pollfd, fd, POLLIN | POLLERR | POLLHUP); | ||
433 | /* | ||
434 | * Save the idx so that when we filter out fds POLLHUP'ed we can | ||
435 | * close the associated evlist->mmap[] entry. | ||
436 | */ | ||
437 | if (pos >= 0) { | ||
438 | evlist->pollfd.priv[pos].idx = idx; | ||
439 | |||
440 | fcntl(fd, F_SETFL, O_NONBLOCK); | ||
441 | } | ||
442 | |||
443 | return pos; | ||
444 | } | ||
445 | |||
446 | int perf_evlist__add_pollfd(struct perf_evlist *evlist, int fd) | ||
447 | { | ||
448 | return __perf_evlist__add_pollfd(evlist, fd, -1); | ||
449 | } | ||
450 | |||
451 | static void perf_evlist__munmap_filtered(struct fdarray *fda, int fd) | ||
452 | { | ||
453 | struct perf_evlist *evlist = container_of(fda, struct perf_evlist, pollfd); | ||
454 | |||
455 | perf_evlist__mmap_put(evlist, fda->priv[fd].idx); | ||
456 | } | ||
457 | |||
458 | int perf_evlist__filter_pollfd(struct perf_evlist *evlist, short revents_and_mask) | ||
459 | { | ||
460 | return fdarray__filter(&evlist->pollfd, revents_and_mask, | ||
461 | perf_evlist__munmap_filtered); | ||
349 | } | 462 | } |
350 | 463 | ||
351 | void perf_evlist__add_pollfd(struct perf_evlist *evlist, int fd) | 464 | int perf_evlist__poll(struct perf_evlist *evlist, int timeout) |
352 | { | 465 | { |
353 | fcntl(fd, F_SETFL, O_NONBLOCK); | 466 | return fdarray__poll(&evlist->pollfd, timeout); |
354 | evlist->pollfd[evlist->nr_fds].fd = fd; | ||
355 | evlist->pollfd[evlist->nr_fds].events = POLLIN; | ||
356 | evlist->nr_fds++; | ||
357 | } | 467 | } |
358 | 468 | ||
359 | static void perf_evlist__id_hash(struct perf_evlist *evlist, | 469 | static void perf_evlist__id_hash(struct perf_evlist *evlist, |
@@ -566,14 +676,36 @@ union perf_event *perf_evlist__mmap_read(struct perf_evlist *evlist, int idx) | |||
566 | return event; | 676 | return event; |
567 | } | 677 | } |
568 | 678 | ||
679 | static bool perf_mmap__empty(struct perf_mmap *md) | ||
680 | { | ||
681 | return perf_mmap__read_head(md) != md->prev; | ||
682 | } | ||
683 | |||
684 | static void perf_evlist__mmap_get(struct perf_evlist *evlist, int idx) | ||
685 | { | ||
686 | ++evlist->mmap[idx].refcnt; | ||
687 | } | ||
688 | |||
689 | static void perf_evlist__mmap_put(struct perf_evlist *evlist, int idx) | ||
690 | { | ||
691 | BUG_ON(evlist->mmap[idx].refcnt == 0); | ||
692 | |||
693 | if (--evlist->mmap[idx].refcnt == 0) | ||
694 | __perf_evlist__munmap(evlist, idx); | ||
695 | } | ||
696 | |||
569 | void perf_evlist__mmap_consume(struct perf_evlist *evlist, int idx) | 697 | void perf_evlist__mmap_consume(struct perf_evlist *evlist, int idx) |
570 | { | 698 | { |
699 | struct perf_mmap *md = &evlist->mmap[idx]; | ||
700 | |||
571 | if (!evlist->overwrite) { | 701 | if (!evlist->overwrite) { |
572 | struct perf_mmap *md = &evlist->mmap[idx]; | ||
573 | unsigned int old = md->prev; | 702 | unsigned int old = md->prev; |
574 | 703 | ||
575 | perf_mmap__write_tail(md, old); | 704 | perf_mmap__write_tail(md, old); |
576 | } | 705 | } |
706 | |||
707 | if (md->refcnt == 1 && perf_mmap__empty(md)) | ||
708 | perf_evlist__mmap_put(evlist, idx); | ||
577 | } | 709 | } |
578 | 710 | ||
579 | static void __perf_evlist__munmap(struct perf_evlist *evlist, int idx) | 711 | static void __perf_evlist__munmap(struct perf_evlist *evlist, int idx) |
@@ -581,6 +713,7 @@ static void __perf_evlist__munmap(struct perf_evlist *evlist, int idx) | |||
581 | if (evlist->mmap[idx].base != NULL) { | 713 | if (evlist->mmap[idx].base != NULL) { |
582 | munmap(evlist->mmap[idx].base, evlist->mmap_len); | 714 | munmap(evlist->mmap[idx].base, evlist->mmap_len); |
583 | evlist->mmap[idx].base = NULL; | 715 | evlist->mmap[idx].base = NULL; |
716 | evlist->mmap[idx].refcnt = 0; | ||
584 | } | 717 | } |
585 | } | 718 | } |
586 | 719 | ||
@@ -614,6 +747,20 @@ struct mmap_params { | |||
614 | static int __perf_evlist__mmap(struct perf_evlist *evlist, int idx, | 747 | static int __perf_evlist__mmap(struct perf_evlist *evlist, int idx, |
615 | struct mmap_params *mp, int fd) | 748 | struct mmap_params *mp, int fd) |
616 | { | 749 | { |
750 | /* | ||
751 | * The last one will be done at perf_evlist__mmap_consume(), so that we | ||
752 | * make sure we don't prevent tools from consuming every last event in | ||
753 | * the ring buffer. | ||
754 | * | ||
755 | * I.e. we can get the POLLHUP meaning that the fd doesn't exist | ||
756 | * anymore, but the last events for it are still in the ring buffer, | ||
757 | * waiting to be consumed. | ||
758 | * | ||
759 | * Tools can chose to ignore this at their own discretion, but the | ||
760 | * evlist layer can't just drop it when filtering events in | ||
761 | * perf_evlist__filter_pollfd(). | ||
762 | */ | ||
763 | evlist->mmap[idx].refcnt = 2; | ||
617 | evlist->mmap[idx].prev = 0; | 764 | evlist->mmap[idx].prev = 0; |
618 | evlist->mmap[idx].mask = mp->mask; | 765 | evlist->mmap[idx].mask = mp->mask; |
619 | evlist->mmap[idx].base = mmap(NULL, evlist->mmap_len, mp->prot, | 766 | evlist->mmap[idx].base = mmap(NULL, evlist->mmap_len, mp->prot, |
@@ -625,7 +772,6 @@ static int __perf_evlist__mmap(struct perf_evlist *evlist, int idx, | |||
625 | return -1; | 772 | return -1; |
626 | } | 773 | } |
627 | 774 | ||
628 | perf_evlist__add_pollfd(evlist, fd); | ||
629 | return 0; | 775 | return 0; |
630 | } | 776 | } |
631 | 777 | ||
@@ -636,7 +782,12 @@ static int perf_evlist__mmap_per_evsel(struct perf_evlist *evlist, int idx, | |||
636 | struct perf_evsel *evsel; | 782 | struct perf_evsel *evsel; |
637 | 783 | ||
638 | evlist__for_each(evlist, evsel) { | 784 | evlist__for_each(evlist, evsel) { |
639 | int fd = FD(evsel, cpu, thread); | 785 | int fd; |
786 | |||
787 | if (evsel->system_wide && thread) | ||
788 | continue; | ||
789 | |||
790 | fd = FD(evsel, cpu, thread); | ||
640 | 791 | ||
641 | if (*output == -1) { | 792 | if (*output == -1) { |
642 | *output = fd; | 793 | *output = fd; |
@@ -645,6 +796,13 @@ static int perf_evlist__mmap_per_evsel(struct perf_evlist *evlist, int idx, | |||
645 | } else { | 796 | } else { |
646 | if (ioctl(fd, PERF_EVENT_IOC_SET_OUTPUT, *output) != 0) | 797 | if (ioctl(fd, PERF_EVENT_IOC_SET_OUTPUT, *output) != 0) |
647 | return -1; | 798 | return -1; |
799 | |||
800 | perf_evlist__mmap_get(evlist, idx); | ||
801 | } | ||
802 | |||
803 | if (__perf_evlist__add_pollfd(evlist, fd, idx) < 0) { | ||
804 | perf_evlist__mmap_put(evlist, idx); | ||
805 | return -1; | ||
648 | } | 806 | } |
649 | 807 | ||
650 | if ((evsel->attr.read_format & PERF_FORMAT_ID) && | 808 | if ((evsel->attr.read_format & PERF_FORMAT_ID) && |
@@ -804,7 +962,7 @@ int perf_evlist__mmap(struct perf_evlist *evlist, unsigned int pages, | |||
804 | if (evlist->mmap == NULL && perf_evlist__alloc_mmap(evlist) < 0) | 962 | if (evlist->mmap == NULL && perf_evlist__alloc_mmap(evlist) < 0) |
805 | return -ENOMEM; | 963 | return -ENOMEM; |
806 | 964 | ||
807 | if (evlist->pollfd == NULL && perf_evlist__alloc_pollfd(evlist) < 0) | 965 | if (evlist->pollfd.entries == NULL && perf_evlist__alloc_pollfd(evlist) < 0) |
808 | return -ENOMEM; | 966 | return -ENOMEM; |
809 | 967 | ||
810 | evlist->overwrite = overwrite; | 968 | evlist->overwrite = overwrite; |
@@ -1061,6 +1219,8 @@ int perf_evlist__prepare_workload(struct perf_evlist *evlist, struct target *tar | |||
1061 | } | 1219 | } |
1062 | 1220 | ||
1063 | if (!evlist->workload.pid) { | 1221 | if (!evlist->workload.pid) { |
1222 | int ret; | ||
1223 | |||
1064 | if (pipe_output) | 1224 | if (pipe_output) |
1065 | dup2(2, 1); | 1225 | dup2(2, 1); |
1066 | 1226 | ||
@@ -1078,8 +1238,22 @@ int perf_evlist__prepare_workload(struct perf_evlist *evlist, struct target *tar | |||
1078 | /* | 1238 | /* |
1079 | * Wait until the parent tells us to go. | 1239 | * Wait until the parent tells us to go. |
1080 | */ | 1240 | */ |
1081 | if (read(go_pipe[0], &bf, 1) == -1) | 1241 | ret = read(go_pipe[0], &bf, 1); |
1082 | perror("unable to read pipe"); | 1242 | /* |
1243 | * The parent will ask for the execvp() to be performed by | ||
1244 | * writing exactly one byte, in workload.cork_fd, usually via | ||
1245 | * perf_evlist__start_workload(). | ||
1246 | * | ||
1247 | * For cancelling the workload without actuallin running it, | ||
1248 | * the parent will just close workload.cork_fd, without writing | ||
1249 | * anything, i.e. read will return zero and we just exit() | ||
1250 | * here. | ||
1251 | */ | ||
1252 | if (ret != 1) { | ||
1253 | if (ret == -1) | ||
1254 | perror("unable to read pipe"); | ||
1255 | exit(ret); | ||
1256 | } | ||
1083 | 1257 | ||
1084 | execvp(argv[0], (char **)argv); | 1258 | execvp(argv[0], (char **)argv); |
1085 | 1259 | ||
@@ -1202,7 +1376,7 @@ int perf_evlist__strerror_open(struct perf_evlist *evlist __maybe_unused, | |||
1202 | int err, char *buf, size_t size) | 1376 | int err, char *buf, size_t size) |
1203 | { | 1377 | { |
1204 | int printed, value; | 1378 | int printed, value; |
1205 | char sbuf[128], *emsg = strerror_r(err, sbuf, sizeof(sbuf)); | 1379 | char sbuf[STRERR_BUFSIZE], *emsg = strerror_r(err, sbuf, sizeof(sbuf)); |
1206 | 1380 | ||
1207 | switch (err) { | 1381 | switch (err) { |
1208 | case EACCES: | 1382 | case EACCES: |
@@ -1250,3 +1424,19 @@ void perf_evlist__to_front(struct perf_evlist *evlist, | |||
1250 | 1424 | ||
1251 | list_splice(&move, &evlist->entries); | 1425 | list_splice(&move, &evlist->entries); |
1252 | } | 1426 | } |
1427 | |||
1428 | void perf_evlist__set_tracking_event(struct perf_evlist *evlist, | ||
1429 | struct perf_evsel *tracking_evsel) | ||
1430 | { | ||
1431 | struct perf_evsel *evsel; | ||
1432 | |||
1433 | if (tracking_evsel->tracking) | ||
1434 | return; | ||
1435 | |||
1436 | evlist__for_each(evlist, evsel) { | ||
1437 | if (evsel != tracking_evsel) | ||
1438 | evsel->tracking = false; | ||
1439 | } | ||
1440 | |||
1441 | tracking_evsel->tracking = true; | ||
1442 | } | ||
diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h index f5173cd63693..bd312b01e876 100644 --- a/tools/perf/util/evlist.h +++ b/tools/perf/util/evlist.h | |||
@@ -2,6 +2,7 @@ | |||
2 | #define __PERF_EVLIST_H 1 | 2 | #define __PERF_EVLIST_H 1 |
3 | 3 | ||
4 | #include <linux/list.h> | 4 | #include <linux/list.h> |
5 | #include <api/fd/array.h> | ||
5 | #include <stdio.h> | 6 | #include <stdio.h> |
6 | #include "../perf.h" | 7 | #include "../perf.h" |
7 | #include "event.h" | 8 | #include "event.h" |
@@ -17,9 +18,15 @@ struct record_opts; | |||
17 | #define PERF_EVLIST__HLIST_BITS 8 | 18 | #define PERF_EVLIST__HLIST_BITS 8 |
18 | #define PERF_EVLIST__HLIST_SIZE (1 << PERF_EVLIST__HLIST_BITS) | 19 | #define PERF_EVLIST__HLIST_SIZE (1 << PERF_EVLIST__HLIST_BITS) |
19 | 20 | ||
21 | /** | ||
22 | * struct perf_mmap - perf's ring buffer mmap details | ||
23 | * | ||
24 | * @refcnt - e.g. code using PERF_EVENT_IOC_SET_OUTPUT to share this | ||
25 | */ | ||
20 | struct perf_mmap { | 26 | struct perf_mmap { |
21 | void *base; | 27 | void *base; |
22 | int mask; | 28 | int mask; |
29 | int refcnt; | ||
23 | unsigned int prev; | 30 | unsigned int prev; |
24 | char event_copy[PERF_SAMPLE_MAX_SIZE]; | 31 | char event_copy[PERF_SAMPLE_MAX_SIZE]; |
25 | }; | 32 | }; |
@@ -29,7 +36,6 @@ struct perf_evlist { | |||
29 | struct hlist_head heads[PERF_EVLIST__HLIST_SIZE]; | 36 | struct hlist_head heads[PERF_EVLIST__HLIST_SIZE]; |
30 | int nr_entries; | 37 | int nr_entries; |
31 | int nr_groups; | 38 | int nr_groups; |
32 | int nr_fds; | ||
33 | int nr_mmaps; | 39 | int nr_mmaps; |
34 | size_t mmap_len; | 40 | size_t mmap_len; |
35 | int id_pos; | 41 | int id_pos; |
@@ -40,8 +46,8 @@ struct perf_evlist { | |||
40 | pid_t pid; | 46 | pid_t pid; |
41 | } workload; | 47 | } workload; |
42 | bool overwrite; | 48 | bool overwrite; |
49 | struct fdarray pollfd; | ||
43 | struct perf_mmap *mmap; | 50 | struct perf_mmap *mmap; |
44 | struct pollfd *pollfd; | ||
45 | struct thread_map *threads; | 51 | struct thread_map *threads; |
46 | struct cpu_map *cpus; | 52 | struct cpu_map *cpus; |
47 | struct perf_evsel *selected; | 53 | struct perf_evsel *selected; |
@@ -82,7 +88,11 @@ perf_evlist__find_tracepoint_by_name(struct perf_evlist *evlist, | |||
82 | void perf_evlist__id_add(struct perf_evlist *evlist, struct perf_evsel *evsel, | 88 | void perf_evlist__id_add(struct perf_evlist *evlist, struct perf_evsel *evsel, |
83 | int cpu, int thread, u64 id); | 89 | int cpu, int thread, u64 id); |
84 | 90 | ||
85 | void perf_evlist__add_pollfd(struct perf_evlist *evlist, int fd); | 91 | int perf_evlist__add_pollfd(struct perf_evlist *evlist, int fd); |
92 | int perf_evlist__alloc_pollfd(struct perf_evlist *evlist); | ||
93 | int perf_evlist__filter_pollfd(struct perf_evlist *evlist, short revents_and_mask); | ||
94 | |||
95 | int perf_evlist__poll(struct perf_evlist *evlist, int timeout); | ||
86 | 96 | ||
87 | struct perf_evsel *perf_evlist__id2evsel(struct perf_evlist *evlist, u64 id); | 97 | struct perf_evsel *perf_evlist__id2evsel(struct perf_evlist *evlist, u64 id); |
88 | 98 | ||
@@ -122,6 +132,8 @@ int perf_evlist__disable_event(struct perf_evlist *evlist, | |||
122 | struct perf_evsel *evsel); | 132 | struct perf_evsel *evsel); |
123 | int perf_evlist__enable_event(struct perf_evlist *evlist, | 133 | int perf_evlist__enable_event(struct perf_evlist *evlist, |
124 | struct perf_evsel *evsel); | 134 | struct perf_evsel *evsel); |
135 | int perf_evlist__enable_event_idx(struct perf_evlist *evlist, | ||
136 | struct perf_evsel *evsel, int idx); | ||
125 | 137 | ||
126 | void perf_evlist__set_selected(struct perf_evlist *evlist, | 138 | void perf_evlist__set_selected(struct perf_evlist *evlist, |
127 | struct perf_evsel *evsel); | 139 | struct perf_evsel *evsel); |
@@ -262,4 +274,7 @@ void perf_evlist__to_front(struct perf_evlist *evlist, | |||
262 | #define evlist__for_each_safe(evlist, tmp, evsel) \ | 274 | #define evlist__for_each_safe(evlist, tmp, evsel) \ |
263 | __evlist__for_each_safe(&(evlist)->entries, tmp, evsel) | 275 | __evlist__for_each_safe(&(evlist)->entries, tmp, evsel) |
264 | 276 | ||
277 | void perf_evlist__set_tracking_event(struct perf_evlist *evlist, | ||
278 | struct perf_evsel *tracking_evsel); | ||
279 | |||
265 | #endif /* __PERF_EVLIST_H */ | 280 | #endif /* __PERF_EVLIST_H */ |
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index 21a373ebea22..e0868a901c4a 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c | |||
@@ -162,6 +162,7 @@ void perf_evsel__init(struct perf_evsel *evsel, | |||
162 | struct perf_event_attr *attr, int idx) | 162 | struct perf_event_attr *attr, int idx) |
163 | { | 163 | { |
164 | evsel->idx = idx; | 164 | evsel->idx = idx; |
165 | evsel->tracking = !idx; | ||
165 | evsel->attr = *attr; | 166 | evsel->attr = *attr; |
166 | evsel->leader = evsel; | 167 | evsel->leader = evsel; |
167 | evsel->unit = ""; | 168 | evsel->unit = ""; |
@@ -502,20 +503,19 @@ int perf_evsel__group_desc(struct perf_evsel *evsel, char *buf, size_t size) | |||
502 | } | 503 | } |
503 | 504 | ||
504 | static void | 505 | static void |
505 | perf_evsel__config_callgraph(struct perf_evsel *evsel, | 506 | perf_evsel__config_callgraph(struct perf_evsel *evsel) |
506 | struct record_opts *opts) | ||
507 | { | 507 | { |
508 | bool function = perf_evsel__is_function_event(evsel); | 508 | bool function = perf_evsel__is_function_event(evsel); |
509 | struct perf_event_attr *attr = &evsel->attr; | 509 | struct perf_event_attr *attr = &evsel->attr; |
510 | 510 | ||
511 | perf_evsel__set_sample_bit(evsel, CALLCHAIN); | 511 | perf_evsel__set_sample_bit(evsel, CALLCHAIN); |
512 | 512 | ||
513 | if (opts->call_graph == CALLCHAIN_DWARF) { | 513 | if (callchain_param.record_mode == CALLCHAIN_DWARF) { |
514 | if (!function) { | 514 | if (!function) { |
515 | perf_evsel__set_sample_bit(evsel, REGS_USER); | 515 | perf_evsel__set_sample_bit(evsel, REGS_USER); |
516 | perf_evsel__set_sample_bit(evsel, STACK_USER); | 516 | perf_evsel__set_sample_bit(evsel, STACK_USER); |
517 | attr->sample_regs_user = PERF_REGS_MASK; | 517 | attr->sample_regs_user = PERF_REGS_MASK; |
518 | attr->sample_stack_user = opts->stack_dump_size; | 518 | attr->sample_stack_user = callchain_param.dump_size; |
519 | attr->exclude_callchain_user = 1; | 519 | attr->exclude_callchain_user = 1; |
520 | } else { | 520 | } else { |
521 | pr_info("Cannot use DWARF unwind for function trace event," | 521 | pr_info("Cannot use DWARF unwind for function trace event," |
@@ -561,7 +561,7 @@ void perf_evsel__config(struct perf_evsel *evsel, struct record_opts *opts) | |||
561 | { | 561 | { |
562 | struct perf_evsel *leader = evsel->leader; | 562 | struct perf_evsel *leader = evsel->leader; |
563 | struct perf_event_attr *attr = &evsel->attr; | 563 | struct perf_event_attr *attr = &evsel->attr; |
564 | int track = !evsel->idx; /* only the first counter needs these */ | 564 | int track = evsel->tracking; |
565 | bool per_cpu = opts->target.default_per_cpu && !opts->target.per_thread; | 565 | bool per_cpu = opts->target.default_per_cpu && !opts->target.per_thread; |
566 | 566 | ||
567 | attr->sample_id_all = perf_missing_features.sample_id_all ? 0 : 1; | 567 | attr->sample_id_all = perf_missing_features.sample_id_all ? 0 : 1; |
@@ -624,8 +624,8 @@ void perf_evsel__config(struct perf_evsel *evsel, struct record_opts *opts) | |||
624 | attr->mmap_data = track; | 624 | attr->mmap_data = track; |
625 | } | 625 | } |
626 | 626 | ||
627 | if (opts->call_graph_enabled && !evsel->no_aux_samples) | 627 | if (callchain_param.enabled && !evsel->no_aux_samples) |
628 | perf_evsel__config_callgraph(evsel, opts); | 628 | perf_evsel__config_callgraph(evsel); |
629 | 629 | ||
630 | if (target__has_cpu(&opts->target)) | 630 | if (target__has_cpu(&opts->target)) |
631 | perf_evsel__set_sample_bit(evsel, CPU); | 631 | perf_evsel__set_sample_bit(evsel, CPU); |
@@ -633,9 +633,12 @@ void perf_evsel__config(struct perf_evsel *evsel, struct record_opts *opts) | |||
633 | if (opts->period) | 633 | if (opts->period) |
634 | perf_evsel__set_sample_bit(evsel, PERIOD); | 634 | perf_evsel__set_sample_bit(evsel, PERIOD); |
635 | 635 | ||
636 | if (!perf_missing_features.sample_id_all && | 636 | /* |
637 | (opts->sample_time || !opts->no_inherit || | 637 | * When the user explicitely disabled time don't force it here. |
638 | target__has_cpu(&opts->target) || per_cpu)) | 638 | */ |
639 | if (opts->sample_time && | ||
640 | (!perf_missing_features.sample_id_all && | ||
641 | (!opts->no_inherit || target__has_cpu(&opts->target) || per_cpu))) | ||
639 | perf_evsel__set_sample_bit(evsel, TIME); | 642 | perf_evsel__set_sample_bit(evsel, TIME); |
640 | 643 | ||
641 | if (opts->raw_samples && !evsel->no_aux_samples) { | 644 | if (opts->raw_samples && !evsel->no_aux_samples) { |
@@ -692,6 +695,10 @@ void perf_evsel__config(struct perf_evsel *evsel, struct record_opts *opts) | |||
692 | int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads) | 695 | int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads) |
693 | { | 696 | { |
694 | int cpu, thread; | 697 | int cpu, thread; |
698 | |||
699 | if (evsel->system_wide) | ||
700 | nthreads = 1; | ||
701 | |||
695 | evsel->fd = xyarray__new(ncpus, nthreads, sizeof(int)); | 702 | evsel->fd = xyarray__new(ncpus, nthreads, sizeof(int)); |
696 | 703 | ||
697 | if (evsel->fd) { | 704 | if (evsel->fd) { |
@@ -710,6 +717,9 @@ static int perf_evsel__run_ioctl(struct perf_evsel *evsel, int ncpus, int nthrea | |||
710 | { | 717 | { |
711 | int cpu, thread; | 718 | int cpu, thread; |
712 | 719 | ||
720 | if (evsel->system_wide) | ||
721 | nthreads = 1; | ||
722 | |||
713 | for (cpu = 0; cpu < ncpus; cpu++) { | 723 | for (cpu = 0; cpu < ncpus; cpu++) { |
714 | for (thread = 0; thread < nthreads; thread++) { | 724 | for (thread = 0; thread < nthreads; thread++) { |
715 | int fd = FD(evsel, cpu, thread), | 725 | int fd = FD(evsel, cpu, thread), |
@@ -740,6 +750,9 @@ int perf_evsel__enable(struct perf_evsel *evsel, int ncpus, int nthreads) | |||
740 | 750 | ||
741 | int perf_evsel__alloc_id(struct perf_evsel *evsel, int ncpus, int nthreads) | 751 | int perf_evsel__alloc_id(struct perf_evsel *evsel, int ncpus, int nthreads) |
742 | { | 752 | { |
753 | if (evsel->system_wide) | ||
754 | nthreads = 1; | ||
755 | |||
743 | evsel->sample_id = xyarray__new(ncpus, nthreads, sizeof(struct perf_sample_id)); | 756 | evsel->sample_id = xyarray__new(ncpus, nthreads, sizeof(struct perf_sample_id)); |
744 | if (evsel->sample_id == NULL) | 757 | if (evsel->sample_id == NULL) |
745 | return -ENOMEM; | 758 | return -ENOMEM; |
@@ -784,6 +797,9 @@ void perf_evsel__close_fd(struct perf_evsel *evsel, int ncpus, int nthreads) | |||
784 | { | 797 | { |
785 | int cpu, thread; | 798 | int cpu, thread; |
786 | 799 | ||
800 | if (evsel->system_wide) | ||
801 | nthreads = 1; | ||
802 | |||
787 | for (cpu = 0; cpu < ncpus; cpu++) | 803 | for (cpu = 0; cpu < ncpus; cpu++) |
788 | for (thread = 0; thread < nthreads; ++thread) { | 804 | for (thread = 0; thread < nthreads; ++thread) { |
789 | close(FD(evsel, cpu, thread)); | 805 | close(FD(evsel, cpu, thread)); |
@@ -872,6 +888,9 @@ int __perf_evsel__read(struct perf_evsel *evsel, | |||
872 | int cpu, thread; | 888 | int cpu, thread; |
873 | struct perf_counts_values *aggr = &evsel->counts->aggr, count; | 889 | struct perf_counts_values *aggr = &evsel->counts->aggr, count; |
874 | 890 | ||
891 | if (evsel->system_wide) | ||
892 | nthreads = 1; | ||
893 | |||
875 | aggr->val = aggr->ena = aggr->run = 0; | 894 | aggr->val = aggr->ena = aggr->run = 0; |
876 | 895 | ||
877 | for (cpu = 0; cpu < ncpus; cpu++) { | 896 | for (cpu = 0; cpu < ncpus; cpu++) { |
@@ -994,13 +1013,18 @@ static size_t perf_event_attr__fprintf(struct perf_event_attr *attr, FILE *fp) | |||
994 | static int __perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus, | 1013 | static int __perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus, |
995 | struct thread_map *threads) | 1014 | struct thread_map *threads) |
996 | { | 1015 | { |
997 | int cpu, thread; | 1016 | int cpu, thread, nthreads; |
998 | unsigned long flags = PERF_FLAG_FD_CLOEXEC; | 1017 | unsigned long flags = PERF_FLAG_FD_CLOEXEC; |
999 | int pid = -1, err; | 1018 | int pid = -1, err; |
1000 | enum { NO_CHANGE, SET_TO_MAX, INCREASED_MAX } set_rlimit = NO_CHANGE; | 1019 | enum { NO_CHANGE, SET_TO_MAX, INCREASED_MAX } set_rlimit = NO_CHANGE; |
1001 | 1020 | ||
1021 | if (evsel->system_wide) | ||
1022 | nthreads = 1; | ||
1023 | else | ||
1024 | nthreads = threads->nr; | ||
1025 | |||
1002 | if (evsel->fd == NULL && | 1026 | if (evsel->fd == NULL && |
1003 | perf_evsel__alloc_fd(evsel, cpus->nr, threads->nr) < 0) | 1027 | perf_evsel__alloc_fd(evsel, cpus->nr, nthreads) < 0) |
1004 | return -ENOMEM; | 1028 | return -ENOMEM; |
1005 | 1029 | ||
1006 | if (evsel->cgrp) { | 1030 | if (evsel->cgrp) { |
@@ -1024,10 +1048,10 @@ retry_sample_id: | |||
1024 | 1048 | ||
1025 | for (cpu = 0; cpu < cpus->nr; cpu++) { | 1049 | for (cpu = 0; cpu < cpus->nr; cpu++) { |
1026 | 1050 | ||
1027 | for (thread = 0; thread < threads->nr; thread++) { | 1051 | for (thread = 0; thread < nthreads; thread++) { |
1028 | int group_fd; | 1052 | int group_fd; |
1029 | 1053 | ||
1030 | if (!evsel->cgrp) | 1054 | if (!evsel->cgrp && !evsel->system_wide) |
1031 | pid = threads->map[thread]; | 1055 | pid = threads->map[thread]; |
1032 | 1056 | ||
1033 | group_fd = get_group_fd(evsel, cpu, thread); | 1057 | group_fd = get_group_fd(evsel, cpu, thread); |
@@ -1100,7 +1124,7 @@ out_close: | |||
1100 | close(FD(evsel, cpu, thread)); | 1124 | close(FD(evsel, cpu, thread)); |
1101 | FD(evsel, cpu, thread) = -1; | 1125 | FD(evsel, cpu, thread) = -1; |
1102 | } | 1126 | } |
1103 | thread = threads->nr; | 1127 | thread = nthreads; |
1104 | } while (--cpu >= 0); | 1128 | } while (--cpu >= 0); |
1105 | return err; | 1129 | return err; |
1106 | } | 1130 | } |
@@ -2002,6 +2026,8 @@ bool perf_evsel__fallback(struct perf_evsel *evsel, int err, | |||
2002 | int perf_evsel__open_strerror(struct perf_evsel *evsel, struct target *target, | 2026 | int perf_evsel__open_strerror(struct perf_evsel *evsel, struct target *target, |
2003 | int err, char *msg, size_t size) | 2027 | int err, char *msg, size_t size) |
2004 | { | 2028 | { |
2029 | char sbuf[STRERR_BUFSIZE]; | ||
2030 | |||
2005 | switch (err) { | 2031 | switch (err) { |
2006 | case EPERM: | 2032 | case EPERM: |
2007 | case EACCES: | 2033 | case EACCES: |
@@ -2036,13 +2062,20 @@ int perf_evsel__open_strerror(struct perf_evsel *evsel, struct target *target, | |||
2036 | "No APIC? If so then you can boot the kernel with the \"lapic\" boot parameter to force-enable it."); | 2062 | "No APIC? If so then you can boot the kernel with the \"lapic\" boot parameter to force-enable it."); |
2037 | #endif | 2063 | #endif |
2038 | break; | 2064 | break; |
2065 | case EBUSY: | ||
2066 | if (find_process("oprofiled")) | ||
2067 | return scnprintf(msg, size, | ||
2068 | "The PMU counters are busy/taken by another profiler.\n" | ||
2069 | "We found oprofile daemon running, please stop it and try again."); | ||
2070 | break; | ||
2039 | default: | 2071 | default: |
2040 | break; | 2072 | break; |
2041 | } | 2073 | } |
2042 | 2074 | ||
2043 | return scnprintf(msg, size, | 2075 | return scnprintf(msg, size, |
2044 | "The sys_perf_event_open() syscall returned with %d (%s) for event (%s). \n" | 2076 | "The sys_perf_event_open() syscall returned with %d (%s) for event (%s).\n" |
2045 | "/bin/dmesg may provide additional information.\n" | 2077 | "/bin/dmesg may provide additional information.\n" |
2046 | "No CONFIG_PERF_EVENTS=y kernel support configured?\n", | 2078 | "No CONFIG_PERF_EVENTS=y kernel support configured?\n", |
2047 | err, strerror(err), perf_evsel__name(evsel)); | 2079 | err, strerror_r(err, sbuf, sizeof(sbuf)), |
2080 | perf_evsel__name(evsel)); | ||
2048 | } | 2081 | } |
diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h index d7f93ce0ebc1..7bc314be6a7b 100644 --- a/tools/perf/util/evsel.h +++ b/tools/perf/util/evsel.h | |||
@@ -85,6 +85,8 @@ struct perf_evsel { | |||
85 | bool needs_swap; | 85 | bool needs_swap; |
86 | bool no_aux_samples; | 86 | bool no_aux_samples; |
87 | bool immediate; | 87 | bool immediate; |
88 | bool system_wide; | ||
89 | bool tracking; | ||
88 | /* parse modifier helper */ | 90 | /* parse modifier helper */ |
89 | int exclude_GH; | 91 | int exclude_GH; |
90 | int nr_members; | 92 | int nr_members; |
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index 158c787ce0c4..ce0de00399da 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c | |||
@@ -214,11 +214,11 @@ static int machine__hit_all_dsos(struct machine *machine) | |||
214 | { | 214 | { |
215 | int err; | 215 | int err; |
216 | 216 | ||
217 | err = __dsos__hit_all(&machine->kernel_dsos); | 217 | err = __dsos__hit_all(&machine->kernel_dsos.head); |
218 | if (err) | 218 | if (err) |
219 | return err; | 219 | return err; |
220 | 220 | ||
221 | return __dsos__hit_all(&machine->user_dsos); | 221 | return __dsos__hit_all(&machine->user_dsos.head); |
222 | } | 222 | } |
223 | 223 | ||
224 | int dsos__hit_all(struct perf_session *session) | 224 | int dsos__hit_all(struct perf_session *session) |
@@ -288,11 +288,12 @@ static int machine__write_buildid_table(struct machine *machine, int fd) | |||
288 | umisc = PERF_RECORD_MISC_GUEST_USER; | 288 | umisc = PERF_RECORD_MISC_GUEST_USER; |
289 | } | 289 | } |
290 | 290 | ||
291 | err = __dsos__write_buildid_table(&machine->kernel_dsos, machine, | 291 | err = __dsos__write_buildid_table(&machine->kernel_dsos.head, machine, |
292 | machine->pid, kmisc, fd); | 292 | machine->pid, kmisc, fd); |
293 | if (err == 0) | 293 | if (err == 0) |
294 | err = __dsos__write_buildid_table(&machine->user_dsos, machine, | 294 | err = __dsos__write_buildid_table(&machine->user_dsos.head, |
295 | machine->pid, umisc, fd); | 295 | machine, machine->pid, umisc, |
296 | fd); | ||
296 | return err; | 297 | return err; |
297 | } | 298 | } |
298 | 299 | ||
@@ -455,9 +456,10 @@ static int __dsos__cache_build_ids(struct list_head *head, | |||
455 | 456 | ||
456 | static int machine__cache_build_ids(struct machine *machine, const char *debugdir) | 457 | static int machine__cache_build_ids(struct machine *machine, const char *debugdir) |
457 | { | 458 | { |
458 | int ret = __dsos__cache_build_ids(&machine->kernel_dsos, machine, | 459 | int ret = __dsos__cache_build_ids(&machine->kernel_dsos.head, machine, |
459 | debugdir); | 460 | debugdir); |
460 | ret |= __dsos__cache_build_ids(&machine->user_dsos, machine, debugdir); | 461 | ret |= __dsos__cache_build_ids(&machine->user_dsos.head, machine, |
462 | debugdir); | ||
461 | return ret; | 463 | return ret; |
462 | } | 464 | } |
463 | 465 | ||
@@ -483,8 +485,10 @@ static int perf_session__cache_build_ids(struct perf_session *session) | |||
483 | 485 | ||
484 | static bool machine__read_build_ids(struct machine *machine, bool with_hits) | 486 | static bool machine__read_build_ids(struct machine *machine, bool with_hits) |
485 | { | 487 | { |
486 | bool ret = __dsos__read_build_ids(&machine->kernel_dsos, with_hits); | 488 | bool ret; |
487 | ret |= __dsos__read_build_ids(&machine->user_dsos, with_hits); | 489 | |
490 | ret = __dsos__read_build_ids(&machine->kernel_dsos.head, with_hits); | ||
491 | ret |= __dsos__read_build_ids(&machine->user_dsos.head, with_hits); | ||
488 | return ret; | 492 | return ret; |
489 | } | 493 | } |
490 | 494 | ||
@@ -1548,7 +1552,7 @@ static int __event_process_build_id(struct build_id_event *bev, | |||
1548 | struct perf_session *session) | 1552 | struct perf_session *session) |
1549 | { | 1553 | { |
1550 | int err = -1; | 1554 | int err = -1; |
1551 | struct list_head *head; | 1555 | struct dsos *dsos; |
1552 | struct machine *machine; | 1556 | struct machine *machine; |
1553 | u16 misc; | 1557 | u16 misc; |
1554 | struct dso *dso; | 1558 | struct dso *dso; |
@@ -1563,22 +1567,22 @@ static int __event_process_build_id(struct build_id_event *bev, | |||
1563 | switch (misc) { | 1567 | switch (misc) { |
1564 | case PERF_RECORD_MISC_KERNEL: | 1568 | case PERF_RECORD_MISC_KERNEL: |
1565 | dso_type = DSO_TYPE_KERNEL; | 1569 | dso_type = DSO_TYPE_KERNEL; |
1566 | head = &machine->kernel_dsos; | 1570 | dsos = &machine->kernel_dsos; |
1567 | break; | 1571 | break; |
1568 | case PERF_RECORD_MISC_GUEST_KERNEL: | 1572 | case PERF_RECORD_MISC_GUEST_KERNEL: |
1569 | dso_type = DSO_TYPE_GUEST_KERNEL; | 1573 | dso_type = DSO_TYPE_GUEST_KERNEL; |
1570 | head = &machine->kernel_dsos; | 1574 | dsos = &machine->kernel_dsos; |
1571 | break; | 1575 | break; |
1572 | case PERF_RECORD_MISC_USER: | 1576 | case PERF_RECORD_MISC_USER: |
1573 | case PERF_RECORD_MISC_GUEST_USER: | 1577 | case PERF_RECORD_MISC_GUEST_USER: |
1574 | dso_type = DSO_TYPE_USER; | 1578 | dso_type = DSO_TYPE_USER; |
1575 | head = &machine->user_dsos; | 1579 | dsos = &machine->user_dsos; |
1576 | break; | 1580 | break; |
1577 | default: | 1581 | default: |
1578 | goto out; | 1582 | goto out; |
1579 | } | 1583 | } |
1580 | 1584 | ||
1581 | dso = __dsos__findnew(head, filename); | 1585 | dso = __dsos__findnew(dsos, filename); |
1582 | if (dso != NULL) { | 1586 | if (dso != NULL) { |
1583 | char sbuild_id[BUILD_ID_SIZE * 2 + 1]; | 1587 | char sbuild_id[BUILD_ID_SIZE * 2 + 1]; |
1584 | 1588 | ||
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c index 30df6187ee02..86569fa3651d 100644 --- a/tools/perf/util/hist.c +++ b/tools/perf/util/hist.c | |||
@@ -277,6 +277,28 @@ void hists__decay_entries(struct hists *hists, bool zap_user, bool zap_kernel) | |||
277 | } | 277 | } |
278 | } | 278 | } |
279 | 279 | ||
280 | void hists__delete_entries(struct hists *hists) | ||
281 | { | ||
282 | struct rb_node *next = rb_first(&hists->entries); | ||
283 | struct hist_entry *n; | ||
284 | |||
285 | while (next) { | ||
286 | n = rb_entry(next, struct hist_entry, rb_node); | ||
287 | next = rb_next(&n->rb_node); | ||
288 | |||
289 | rb_erase(&n->rb_node, &hists->entries); | ||
290 | |||
291 | if (sort__need_collapse) | ||
292 | rb_erase(&n->rb_node_in, &hists->entries_collapsed); | ||
293 | |||
294 | --hists->nr_entries; | ||
295 | if (!n->filtered) | ||
296 | --hists->nr_non_filtered_entries; | ||
297 | |||
298 | hist_entry__free(n); | ||
299 | } | ||
300 | } | ||
301 | |||
280 | /* | 302 | /* |
281 | * histogram, sorted on item, collects periods | 303 | * histogram, sorted on item, collects periods |
282 | */ | 304 | */ |
diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h index 742f49a85725..8c9c70e18cbb 100644 --- a/tools/perf/util/hist.h +++ b/tools/perf/util/hist.h | |||
@@ -152,6 +152,7 @@ void hists__output_resort(struct hists *hists); | |||
152 | void hists__collapse_resort(struct hists *hists, struct ui_progress *prog); | 152 | void hists__collapse_resort(struct hists *hists, struct ui_progress *prog); |
153 | 153 | ||
154 | void hists__decay_entries(struct hists *hists, bool zap_user, bool zap_kernel); | 154 | void hists__decay_entries(struct hists *hists, bool zap_user, bool zap_kernel); |
155 | void hists__delete_entries(struct hists *hists); | ||
155 | void hists__output_recalc_col_len(struct hists *hists, int max_rows); | 156 | void hists__output_recalc_col_len(struct hists *hists, int max_rows); |
156 | 157 | ||
157 | u64 hists__total_period(struct hists *hists); | 158 | u64 hists__total_period(struct hists *hists); |
@@ -192,6 +193,7 @@ struct perf_hpp { | |||
192 | }; | 193 | }; |
193 | 194 | ||
194 | struct perf_hpp_fmt { | 195 | struct perf_hpp_fmt { |
196 | const char *name; | ||
195 | int (*header)(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp, | 197 | int (*header)(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp, |
196 | struct perf_evsel *evsel); | 198 | struct perf_evsel *evsel); |
197 | int (*width)(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp, | 199 | int (*width)(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp, |
@@ -207,6 +209,8 @@ struct perf_hpp_fmt { | |||
207 | struct list_head list; | 209 | struct list_head list; |
208 | struct list_head sort_list; | 210 | struct list_head sort_list; |
209 | bool elide; | 211 | bool elide; |
212 | int len; | ||
213 | int user_len; | ||
210 | }; | 214 | }; |
211 | 215 | ||
212 | extern struct list_head perf_hpp__list; | 216 | extern struct list_head perf_hpp__list; |
@@ -261,17 +265,19 @@ static inline bool perf_hpp__should_skip(struct perf_hpp_fmt *format) | |||
261 | } | 265 | } |
262 | 266 | ||
263 | void perf_hpp__reset_width(struct perf_hpp_fmt *fmt, struct hists *hists); | 267 | void perf_hpp__reset_width(struct perf_hpp_fmt *fmt, struct hists *hists); |
268 | void perf_hpp__reset_sort_width(struct perf_hpp_fmt *fmt, struct hists *hists); | ||
269 | void perf_hpp__set_user_width(const char *width_list_str); | ||
264 | 270 | ||
265 | typedef u64 (*hpp_field_fn)(struct hist_entry *he); | 271 | typedef u64 (*hpp_field_fn)(struct hist_entry *he); |
266 | typedef int (*hpp_callback_fn)(struct perf_hpp *hpp, bool front); | 272 | typedef int (*hpp_callback_fn)(struct perf_hpp *hpp, bool front); |
267 | typedef int (*hpp_snprint_fn)(struct perf_hpp *hpp, const char *fmt, ...); | 273 | typedef int (*hpp_snprint_fn)(struct perf_hpp *hpp, const char *fmt, ...); |
268 | 274 | ||
269 | int __hpp__fmt(struct perf_hpp *hpp, struct hist_entry *he, | 275 | int hpp__fmt(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp, |
270 | hpp_field_fn get_field, const char *fmt, | 276 | struct hist_entry *he, hpp_field_fn get_field, |
271 | hpp_snprint_fn print_fn, bool fmt_percent); | 277 | const char *fmtstr, hpp_snprint_fn print_fn, bool fmt_percent); |
272 | int __hpp__fmt_acc(struct perf_hpp *hpp, struct hist_entry *he, | 278 | int hpp__fmt_acc(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp, |
273 | hpp_field_fn get_field, const char *fmt, | 279 | struct hist_entry *he, hpp_field_fn get_field, |
274 | hpp_snprint_fn print_fn, bool fmt_percent); | 280 | const char *fmtstr, hpp_snprint_fn print_fn, bool fmt_percent); |
275 | 281 | ||
276 | static inline void advance_hpp(struct perf_hpp *hpp, int inc) | 282 | static inline void advance_hpp(struct perf_hpp *hpp, int inc) |
277 | { | 283 | { |
diff --git a/tools/perf/util/kvm-stat.h b/tools/perf/util/kvm-stat.h index 0b5a8cd2ee79..cf1d7913783b 100644 --- a/tools/perf/util/kvm-stat.h +++ b/tools/perf/util/kvm-stat.h | |||
@@ -92,7 +92,6 @@ struct perf_kvm_stat { | |||
92 | u64 lost_events; | 92 | u64 lost_events; |
93 | u64 duration; | 93 | u64 duration; |
94 | 94 | ||
95 | const char *pid_str; | ||
96 | struct intlist *pid_list; | 95 | struct intlist *pid_list; |
97 | 96 | ||
98 | struct rb_root result; | 97 | struct rb_root result; |
diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c index 16bba9fff2c8..b7d477fbda02 100644 --- a/tools/perf/util/machine.c +++ b/tools/perf/util/machine.c | |||
@@ -17,8 +17,8 @@ int machine__init(struct machine *machine, const char *root_dir, pid_t pid) | |||
17 | { | 17 | { |
18 | map_groups__init(&machine->kmaps); | 18 | map_groups__init(&machine->kmaps); |
19 | RB_CLEAR_NODE(&machine->rb_node); | 19 | RB_CLEAR_NODE(&machine->rb_node); |
20 | INIT_LIST_HEAD(&machine->user_dsos); | 20 | INIT_LIST_HEAD(&machine->user_dsos.head); |
21 | INIT_LIST_HEAD(&machine->kernel_dsos); | 21 | INIT_LIST_HEAD(&machine->kernel_dsos.head); |
22 | 22 | ||
23 | machine->threads = RB_ROOT; | 23 | machine->threads = RB_ROOT; |
24 | INIT_LIST_HEAD(&machine->dead_threads); | 24 | INIT_LIST_HEAD(&machine->dead_threads); |
@@ -31,6 +31,8 @@ int machine__init(struct machine *machine, const char *root_dir, pid_t pid) | |||
31 | 31 | ||
32 | machine->symbol_filter = NULL; | 32 | machine->symbol_filter = NULL; |
33 | machine->id_hdr_size = 0; | 33 | machine->id_hdr_size = 0; |
34 | machine->comm_exec = false; | ||
35 | machine->kernel_start = 0; | ||
34 | 36 | ||
35 | machine->root_dir = strdup(root_dir); | 37 | machine->root_dir = strdup(root_dir); |
36 | if (machine->root_dir == NULL) | 38 | if (machine->root_dir == NULL) |
@@ -70,11 +72,12 @@ out_delete: | |||
70 | return NULL; | 72 | return NULL; |
71 | } | 73 | } |
72 | 74 | ||
73 | static void dsos__delete(struct list_head *dsos) | 75 | static void dsos__delete(struct dsos *dsos) |
74 | { | 76 | { |
75 | struct dso *pos, *n; | 77 | struct dso *pos, *n; |
76 | 78 | ||
77 | list_for_each_entry_safe(pos, n, dsos, node) { | 79 | list_for_each_entry_safe(pos, n, &dsos->head, node) { |
80 | RB_CLEAR_NODE(&pos->rb_node); | ||
78 | list_del(&pos->node); | 81 | list_del(&pos->node); |
79 | dso__delete(pos); | 82 | dso__delete(pos); |
80 | } | 83 | } |
@@ -179,6 +182,19 @@ void machines__set_symbol_filter(struct machines *machines, | |||
179 | } | 182 | } |
180 | } | 183 | } |
181 | 184 | ||
185 | void machines__set_comm_exec(struct machines *machines, bool comm_exec) | ||
186 | { | ||
187 | struct rb_node *nd; | ||
188 | |||
189 | machines->host.comm_exec = comm_exec; | ||
190 | |||
191 | for (nd = rb_first(&machines->guests); nd; nd = rb_next(nd)) { | ||
192 | struct machine *machine = rb_entry(nd, struct machine, rb_node); | ||
193 | |||
194 | machine->comm_exec = comm_exec; | ||
195 | } | ||
196 | } | ||
197 | |||
182 | struct machine *machines__find(struct machines *machines, pid_t pid) | 198 | struct machine *machines__find(struct machines *machines, pid_t pid) |
183 | { | 199 | { |
184 | struct rb_node **p = &machines->guests.rb_node; | 200 | struct rb_node **p = &machines->guests.rb_node; |
@@ -398,17 +414,31 @@ struct thread *machine__find_thread(struct machine *machine, pid_t pid, | |||
398 | return __machine__findnew_thread(machine, pid, tid, false); | 414 | return __machine__findnew_thread(machine, pid, tid, false); |
399 | } | 415 | } |
400 | 416 | ||
417 | struct comm *machine__thread_exec_comm(struct machine *machine, | ||
418 | struct thread *thread) | ||
419 | { | ||
420 | if (machine->comm_exec) | ||
421 | return thread__exec_comm(thread); | ||
422 | else | ||
423 | return thread__comm(thread); | ||
424 | } | ||
425 | |||
401 | int machine__process_comm_event(struct machine *machine, union perf_event *event, | 426 | int machine__process_comm_event(struct machine *machine, union perf_event *event, |
402 | struct perf_sample *sample) | 427 | struct perf_sample *sample) |
403 | { | 428 | { |
404 | struct thread *thread = machine__findnew_thread(machine, | 429 | struct thread *thread = machine__findnew_thread(machine, |
405 | event->comm.pid, | 430 | event->comm.pid, |
406 | event->comm.tid); | 431 | event->comm.tid); |
432 | bool exec = event->header.misc & PERF_RECORD_MISC_COMM_EXEC; | ||
433 | |||
434 | if (exec) | ||
435 | machine->comm_exec = true; | ||
407 | 436 | ||
408 | if (dump_trace) | 437 | if (dump_trace) |
409 | perf_event__fprintf_comm(event, stdout); | 438 | perf_event__fprintf_comm(event, stdout); |
410 | 439 | ||
411 | if (thread == NULL || thread__set_comm(thread, event->comm.comm, sample->time)) { | 440 | if (thread == NULL || |
441 | __thread__set_comm(thread, event->comm.comm, sample->time, exec)) { | ||
412 | dump_printf("problem processing PERF_RECORD_COMM, skipping event.\n"); | 442 | dump_printf("problem processing PERF_RECORD_COMM, skipping event.\n"); |
413 | return -1; | 443 | return -1; |
414 | } | 444 | } |
@@ -448,23 +478,23 @@ struct map *machine__new_module(struct machine *machine, u64 start, | |||
448 | size_t machines__fprintf_dsos(struct machines *machines, FILE *fp) | 478 | size_t machines__fprintf_dsos(struct machines *machines, FILE *fp) |
449 | { | 479 | { |
450 | struct rb_node *nd; | 480 | struct rb_node *nd; |
451 | size_t ret = __dsos__fprintf(&machines->host.kernel_dsos, fp) + | 481 | size_t ret = __dsos__fprintf(&machines->host.kernel_dsos.head, fp) + |
452 | __dsos__fprintf(&machines->host.user_dsos, fp); | 482 | __dsos__fprintf(&machines->host.user_dsos.head, fp); |
453 | 483 | ||
454 | for (nd = rb_first(&machines->guests); nd; nd = rb_next(nd)) { | 484 | for (nd = rb_first(&machines->guests); nd; nd = rb_next(nd)) { |
455 | struct machine *pos = rb_entry(nd, struct machine, rb_node); | 485 | struct machine *pos = rb_entry(nd, struct machine, rb_node); |
456 | ret += __dsos__fprintf(&pos->kernel_dsos, fp); | 486 | ret += __dsos__fprintf(&pos->kernel_dsos.head, fp); |
457 | ret += __dsos__fprintf(&pos->user_dsos, fp); | 487 | ret += __dsos__fprintf(&pos->user_dsos.head, fp); |
458 | } | 488 | } |
459 | 489 | ||
460 | return ret; | 490 | return ret; |
461 | } | 491 | } |
462 | 492 | ||
463 | size_t machine__fprintf_dsos_buildid(struct machine *machine, FILE *fp, | 493 | size_t machine__fprintf_dsos_buildid(struct machine *m, FILE *fp, |
464 | bool (skip)(struct dso *dso, int parm), int parm) | 494 | bool (skip)(struct dso *dso, int parm), int parm) |
465 | { | 495 | { |
466 | return __dsos__fprintf_buildid(&machine->kernel_dsos, fp, skip, parm) + | 496 | return __dsos__fprintf_buildid(&m->kernel_dsos.head, fp, skip, parm) + |
467 | __dsos__fprintf_buildid(&machine->user_dsos, fp, skip, parm); | 497 | __dsos__fprintf_buildid(&m->user_dsos.head, fp, skip, parm); |
468 | } | 498 | } |
469 | 499 | ||
470 | size_t machines__fprintf_dsos_buildid(struct machines *machines, FILE *fp, | 500 | size_t machines__fprintf_dsos_buildid(struct machines *machines, FILE *fp, |
@@ -565,8 +595,8 @@ const char *ref_reloc_sym_names[] = {"_text", "_stext", NULL}; | |||
565 | * Returns the name of the start symbol in *symbol_name. Pass in NULL as | 595 | * Returns the name of the start symbol in *symbol_name. Pass in NULL as |
566 | * symbol_name if it's not that important. | 596 | * symbol_name if it's not that important. |
567 | */ | 597 | */ |
568 | static u64 machine__get_kernel_start_addr(struct machine *machine, | 598 | static u64 machine__get_running_kernel_start(struct machine *machine, |
569 | const char **symbol_name) | 599 | const char **symbol_name) |
570 | { | 600 | { |
571 | char filename[PATH_MAX]; | 601 | char filename[PATH_MAX]; |
572 | int i; | 602 | int i; |
@@ -593,7 +623,7 @@ static u64 machine__get_kernel_start_addr(struct machine *machine, | |||
593 | int __machine__create_kernel_maps(struct machine *machine, struct dso *kernel) | 623 | int __machine__create_kernel_maps(struct machine *machine, struct dso *kernel) |
594 | { | 624 | { |
595 | enum map_type type; | 625 | enum map_type type; |
596 | u64 start = machine__get_kernel_start_addr(machine, NULL); | 626 | u64 start = machine__get_running_kernel_start(machine, NULL); |
597 | 627 | ||
598 | for (type = 0; type < MAP__NR_TYPES; ++type) { | 628 | for (type = 0; type < MAP__NR_TYPES; ++type) { |
599 | struct kmap *kmap; | 629 | struct kmap *kmap; |
@@ -912,7 +942,7 @@ int machine__create_kernel_maps(struct machine *machine) | |||
912 | { | 942 | { |
913 | struct dso *kernel = machine__get_kernel(machine); | 943 | struct dso *kernel = machine__get_kernel(machine); |
914 | const char *name; | 944 | const char *name; |
915 | u64 addr = machine__get_kernel_start_addr(machine, &name); | 945 | u64 addr = machine__get_running_kernel_start(machine, &name); |
916 | if (!addr) | 946 | if (!addr) |
917 | return -1; | 947 | return -1; |
918 | 948 | ||
@@ -965,7 +995,7 @@ static bool machine__uses_kcore(struct machine *machine) | |||
965 | { | 995 | { |
966 | struct dso *dso; | 996 | struct dso *dso; |
967 | 997 | ||
968 | list_for_each_entry(dso, &machine->kernel_dsos, node) { | 998 | list_for_each_entry(dso, &machine->kernel_dsos.head, node) { |
969 | if (dso__is_kcore(dso)) | 999 | if (dso__is_kcore(dso)) |
970 | return true; | 1000 | return true; |
971 | } | 1001 | } |
@@ -1285,6 +1315,16 @@ static void ip__resolve_data(struct machine *machine, struct thread *thread, | |||
1285 | 1315 | ||
1286 | thread__find_addr_location(thread, machine, m, MAP__VARIABLE, addr, | 1316 | thread__find_addr_location(thread, machine, m, MAP__VARIABLE, addr, |
1287 | &al); | 1317 | &al); |
1318 | if (al.map == NULL) { | ||
1319 | /* | ||
1320 | * some shared data regions have execute bit set which puts | ||
1321 | * their mapping in the MAP__FUNCTION type array. | ||
1322 | * Check there as a fallback option before dropping the sample. | ||
1323 | */ | ||
1324 | thread__find_addr_location(thread, machine, m, MAP__FUNCTION, addr, | ||
1325 | &al); | ||
1326 | } | ||
1327 | |||
1288 | ams->addr = addr; | 1328 | ams->addr = addr; |
1289 | ams->al_addr = al.addr; | 1329 | ams->al_addr = al.addr; |
1290 | ams->sym = al.sym; | 1330 | ams->sym = al.sym; |
@@ -1531,3 +1571,25 @@ int machine__set_current_tid(struct machine *machine, int cpu, pid_t pid, | |||
1531 | 1571 | ||
1532 | return 0; | 1572 | return 0; |
1533 | } | 1573 | } |
1574 | |||
1575 | int machine__get_kernel_start(struct machine *machine) | ||
1576 | { | ||
1577 | struct map *map = machine__kernel_map(machine, MAP__FUNCTION); | ||
1578 | int err = 0; | ||
1579 | |||
1580 | /* | ||
1581 | * The only addresses above 2^63 are kernel addresses of a 64-bit | ||
1582 | * kernel. Note that addresses are unsigned so that on a 32-bit system | ||
1583 | * all addresses including kernel addresses are less than 2^32. In | ||
1584 | * that case (32-bit system), if the kernel mapping is unknown, all | ||
1585 | * addresses will be assumed to be in user space - see | ||
1586 | * machine__kernel_ip(). | ||
1587 | */ | ||
1588 | machine->kernel_start = 1ULL << 63; | ||
1589 | if (map) { | ||
1590 | err = map__load(map, machine->symbol_filter); | ||
1591 | if (map->start) | ||
1592 | machine->kernel_start = map->start; | ||
1593 | } | ||
1594 | return err; | ||
1595 | } | ||
diff --git a/tools/perf/util/machine.h b/tools/perf/util/machine.h index b972824e6294..2b651a7f5d0d 100644 --- a/tools/perf/util/machine.h +++ b/tools/perf/util/machine.h | |||
@@ -4,6 +4,7 @@ | |||
4 | #include <sys/types.h> | 4 | #include <sys/types.h> |
5 | #include <linux/rbtree.h> | 5 | #include <linux/rbtree.h> |
6 | #include "map.h" | 6 | #include "map.h" |
7 | #include "dso.h" | ||
7 | #include "event.h" | 8 | #include "event.h" |
8 | 9 | ||
9 | struct addr_location; | 10 | struct addr_location; |
@@ -26,15 +27,17 @@ struct machine { | |||
26 | struct rb_node rb_node; | 27 | struct rb_node rb_node; |
27 | pid_t pid; | 28 | pid_t pid; |
28 | u16 id_hdr_size; | 29 | u16 id_hdr_size; |
30 | bool comm_exec; | ||
29 | char *root_dir; | 31 | char *root_dir; |
30 | struct rb_root threads; | 32 | struct rb_root threads; |
31 | struct list_head dead_threads; | 33 | struct list_head dead_threads; |
32 | struct thread *last_match; | 34 | struct thread *last_match; |
33 | struct vdso_info *vdso_info; | 35 | struct vdso_info *vdso_info; |
34 | struct list_head user_dsos; | 36 | struct dsos user_dsos; |
35 | struct list_head kernel_dsos; | 37 | struct dsos kernel_dsos; |
36 | struct map_groups kmaps; | 38 | struct map_groups kmaps; |
37 | struct map *vmlinux_maps[MAP__NR_TYPES]; | 39 | struct map *vmlinux_maps[MAP__NR_TYPES]; |
40 | u64 kernel_start; | ||
38 | symbol_filter_t symbol_filter; | 41 | symbol_filter_t symbol_filter; |
39 | pid_t *current_tid; | 42 | pid_t *current_tid; |
40 | }; | 43 | }; |
@@ -45,8 +48,26 @@ struct map *machine__kernel_map(struct machine *machine, enum map_type type) | |||
45 | return machine->vmlinux_maps[type]; | 48 | return machine->vmlinux_maps[type]; |
46 | } | 49 | } |
47 | 50 | ||
51 | int machine__get_kernel_start(struct machine *machine); | ||
52 | |||
53 | static inline u64 machine__kernel_start(struct machine *machine) | ||
54 | { | ||
55 | if (!machine->kernel_start) | ||
56 | machine__get_kernel_start(machine); | ||
57 | return machine->kernel_start; | ||
58 | } | ||
59 | |||
60 | static inline bool machine__kernel_ip(struct machine *machine, u64 ip) | ||
61 | { | ||
62 | u64 kernel_start = machine__kernel_start(machine); | ||
63 | |||
64 | return ip >= kernel_start; | ||
65 | } | ||
66 | |||
48 | struct thread *machine__find_thread(struct machine *machine, pid_t pid, | 67 | struct thread *machine__find_thread(struct machine *machine, pid_t pid, |
49 | pid_t tid); | 68 | pid_t tid); |
69 | struct comm *machine__thread_exec_comm(struct machine *machine, | ||
70 | struct thread *thread); | ||
50 | 71 | ||
51 | int machine__process_comm_event(struct machine *machine, union perf_event *event, | 72 | int machine__process_comm_event(struct machine *machine, union perf_event *event, |
52 | struct perf_sample *sample); | 73 | struct perf_sample *sample); |
@@ -88,6 +109,7 @@ char *machine__mmap_name(struct machine *machine, char *bf, size_t size); | |||
88 | 109 | ||
89 | void machines__set_symbol_filter(struct machines *machines, | 110 | void machines__set_symbol_filter(struct machines *machines, |
90 | symbol_filter_t symbol_filter); | 111 | symbol_filter_t symbol_filter); |
112 | void machines__set_comm_exec(struct machines *machines, bool comm_exec); | ||
91 | 113 | ||
92 | struct machine *machine__new_host(void); | 114 | struct machine *machine__new_host(void); |
93 | int machine__init(struct machine *machine, const char *root_dir, pid_t pid); | 115 | int machine__init(struct machine *machine, const char *root_dir, pid_t pid); |
diff --git a/tools/perf/util/map.c b/tools/perf/util/map.c index 31b8905dd863..b7090596ac50 100644 --- a/tools/perf/util/map.c +++ b/tools/perf/util/map.c | |||
@@ -31,6 +31,7 @@ static inline int is_anon_memory(const char *filename) | |||
31 | static inline int is_no_dso_memory(const char *filename) | 31 | static inline int is_no_dso_memory(const char *filename) |
32 | { | 32 | { |
33 | return !strncmp(filename, "[stack", 6) || | 33 | return !strncmp(filename, "[stack", 6) || |
34 | !strncmp(filename, "/SYSV",5) || | ||
34 | !strcmp(filename, "[heap]"); | 35 | !strcmp(filename, "[heap]"); |
35 | } | 36 | } |
36 | 37 | ||
diff --git a/tools/perf/util/ordered-events.c b/tools/perf/util/ordered-events.c new file mode 100644 index 000000000000..706ce1a66169 --- /dev/null +++ b/tools/perf/util/ordered-events.c | |||
@@ -0,0 +1,245 @@ | |||
1 | #include <linux/list.h> | ||
2 | #include <linux/compiler.h> | ||
3 | #include "ordered-events.h" | ||
4 | #include "evlist.h" | ||
5 | #include "session.h" | ||
6 | #include "asm/bug.h" | ||
7 | #include "debug.h" | ||
8 | |||
9 | #define pr_N(n, fmt, ...) \ | ||
10 | eprintf(n, debug_ordered_events, fmt, ##__VA_ARGS__) | ||
11 | |||
12 | #define pr(fmt, ...) pr_N(1, pr_fmt(fmt), ##__VA_ARGS__) | ||
13 | |||
14 | static void queue_event(struct ordered_events *oe, struct ordered_event *new) | ||
15 | { | ||
16 | struct ordered_event *last = oe->last; | ||
17 | u64 timestamp = new->timestamp; | ||
18 | struct list_head *p; | ||
19 | |||
20 | ++oe->nr_events; | ||
21 | oe->last = new; | ||
22 | |||
23 | pr_oe_time2(timestamp, "queue_event nr_events %u\n", oe->nr_events); | ||
24 | |||
25 | if (!last) { | ||
26 | list_add(&new->list, &oe->events); | ||
27 | oe->max_timestamp = timestamp; | ||
28 | return; | ||
29 | } | ||
30 | |||
31 | /* | ||
32 | * last event might point to some random place in the list as it's | ||
33 | * the last queued event. We expect that the new event is close to | ||
34 | * this. | ||
35 | */ | ||
36 | if (last->timestamp <= timestamp) { | ||
37 | while (last->timestamp <= timestamp) { | ||
38 | p = last->list.next; | ||
39 | if (p == &oe->events) { | ||
40 | list_add_tail(&new->list, &oe->events); | ||
41 | oe->max_timestamp = timestamp; | ||
42 | return; | ||
43 | } | ||
44 | last = list_entry(p, struct ordered_event, list); | ||
45 | } | ||
46 | list_add_tail(&new->list, &last->list); | ||
47 | } else { | ||
48 | while (last->timestamp > timestamp) { | ||
49 | p = last->list.prev; | ||
50 | if (p == &oe->events) { | ||
51 | list_add(&new->list, &oe->events); | ||
52 | return; | ||
53 | } | ||
54 | last = list_entry(p, struct ordered_event, list); | ||
55 | } | ||
56 | list_add(&new->list, &last->list); | ||
57 | } | ||
58 | } | ||
59 | |||
60 | #define MAX_SAMPLE_BUFFER (64 * 1024 / sizeof(struct ordered_event)) | ||
61 | static struct ordered_event *alloc_event(struct ordered_events *oe) | ||
62 | { | ||
63 | struct list_head *cache = &oe->cache; | ||
64 | struct ordered_event *new = NULL; | ||
65 | |||
66 | if (!list_empty(cache)) { | ||
67 | new = list_entry(cache->next, struct ordered_event, list); | ||
68 | list_del(&new->list); | ||
69 | } else if (oe->buffer) { | ||
70 | new = oe->buffer + oe->buffer_idx; | ||
71 | if (++oe->buffer_idx == MAX_SAMPLE_BUFFER) | ||
72 | oe->buffer = NULL; | ||
73 | } else if (oe->cur_alloc_size < oe->max_alloc_size) { | ||
74 | size_t size = MAX_SAMPLE_BUFFER * sizeof(*new); | ||
75 | |||
76 | oe->buffer = malloc(size); | ||
77 | if (!oe->buffer) | ||
78 | return NULL; | ||
79 | |||
80 | pr("alloc size %" PRIu64 "B (+%zu), max %" PRIu64 "B\n", | ||
81 | oe->cur_alloc_size, size, oe->max_alloc_size); | ||
82 | |||
83 | oe->cur_alloc_size += size; | ||
84 | list_add(&oe->buffer->list, &oe->to_free); | ||
85 | |||
86 | /* First entry is abused to maintain the to_free list. */ | ||
87 | oe->buffer_idx = 2; | ||
88 | new = oe->buffer + 1; | ||
89 | } else { | ||
90 | pr("allocation limit reached %" PRIu64 "B\n", oe->max_alloc_size); | ||
91 | } | ||
92 | |||
93 | return new; | ||
94 | } | ||
95 | |||
96 | struct ordered_event * | ||
97 | ordered_events__new(struct ordered_events *oe, u64 timestamp) | ||
98 | { | ||
99 | struct ordered_event *new; | ||
100 | |||
101 | new = alloc_event(oe); | ||
102 | if (new) { | ||
103 | new->timestamp = timestamp; | ||
104 | queue_event(oe, new); | ||
105 | } | ||
106 | |||
107 | return new; | ||
108 | } | ||
109 | |||
110 | void ordered_events__delete(struct ordered_events *oe, struct ordered_event *event) | ||
111 | { | ||
112 | list_move(&event->list, &oe->cache); | ||
113 | oe->nr_events--; | ||
114 | } | ||
115 | |||
116 | static int __ordered_events__flush(struct perf_session *s, | ||
117 | struct perf_tool *tool) | ||
118 | { | ||
119 | struct ordered_events *oe = &s->ordered_events; | ||
120 | struct list_head *head = &oe->events; | ||
121 | struct ordered_event *tmp, *iter; | ||
122 | struct perf_sample sample; | ||
123 | u64 limit = oe->next_flush; | ||
124 | u64 last_ts = oe->last ? oe->last->timestamp : 0ULL; | ||
125 | bool show_progress = limit == ULLONG_MAX; | ||
126 | struct ui_progress prog; | ||
127 | int ret; | ||
128 | |||
129 | if (!tool->ordered_events || !limit) | ||
130 | return 0; | ||
131 | |||
132 | if (show_progress) | ||
133 | ui_progress__init(&prog, oe->nr_events, "Processing time ordered events..."); | ||
134 | |||
135 | list_for_each_entry_safe(iter, tmp, head, list) { | ||
136 | if (session_done()) | ||
137 | return 0; | ||
138 | |||
139 | if (iter->timestamp > limit) | ||
140 | break; | ||
141 | |||
142 | ret = perf_evlist__parse_sample(s->evlist, iter->event, &sample); | ||
143 | if (ret) | ||
144 | pr_err("Can't parse sample, err = %d\n", ret); | ||
145 | else { | ||
146 | ret = perf_session__deliver_event(s, iter->event, &sample, tool, | ||
147 | iter->file_offset); | ||
148 | if (ret) | ||
149 | return ret; | ||
150 | } | ||
151 | |||
152 | ordered_events__delete(oe, iter); | ||
153 | oe->last_flush = iter->timestamp; | ||
154 | |||
155 | if (show_progress) | ||
156 | ui_progress__update(&prog, 1); | ||
157 | } | ||
158 | |||
159 | if (list_empty(head)) | ||
160 | oe->last = NULL; | ||
161 | else if (last_ts <= limit) | ||
162 | oe->last = list_entry(head->prev, struct ordered_event, list); | ||
163 | |||
164 | return 0; | ||
165 | } | ||
166 | |||
167 | int ordered_events__flush(struct perf_session *s, struct perf_tool *tool, | ||
168 | enum oe_flush how) | ||
169 | { | ||
170 | struct ordered_events *oe = &s->ordered_events; | ||
171 | static const char * const str[] = { | ||
172 | "NONE", | ||
173 | "FINAL", | ||
174 | "ROUND", | ||
175 | "HALF ", | ||
176 | }; | ||
177 | int err; | ||
178 | |||
179 | switch (how) { | ||
180 | case OE_FLUSH__FINAL: | ||
181 | oe->next_flush = ULLONG_MAX; | ||
182 | break; | ||
183 | |||
184 | case OE_FLUSH__HALF: | ||
185 | { | ||
186 | struct ordered_event *first, *last; | ||
187 | struct list_head *head = &oe->events; | ||
188 | |||
189 | first = list_entry(head->next, struct ordered_event, list); | ||
190 | last = oe->last; | ||
191 | |||
192 | /* Warn if we are called before any event got allocated. */ | ||
193 | if (WARN_ONCE(!last || list_empty(head), "empty queue")) | ||
194 | return 0; | ||
195 | |||
196 | oe->next_flush = first->timestamp; | ||
197 | oe->next_flush += (last->timestamp - first->timestamp) / 2; | ||
198 | break; | ||
199 | } | ||
200 | |||
201 | case OE_FLUSH__ROUND: | ||
202 | case OE_FLUSH__NONE: | ||
203 | default: | ||
204 | break; | ||
205 | }; | ||
206 | |||
207 | pr_oe_time(oe->next_flush, "next_flush - ordered_events__flush PRE %s, nr_events %u\n", | ||
208 | str[how], oe->nr_events); | ||
209 | pr_oe_time(oe->max_timestamp, "max_timestamp\n"); | ||
210 | |||
211 | err = __ordered_events__flush(s, tool); | ||
212 | |||
213 | if (!err) { | ||
214 | if (how == OE_FLUSH__ROUND) | ||
215 | oe->next_flush = oe->max_timestamp; | ||
216 | |||
217 | oe->last_flush_type = how; | ||
218 | } | ||
219 | |||
220 | pr_oe_time(oe->next_flush, "next_flush - ordered_events__flush POST %s, nr_events %u\n", | ||
221 | str[how], oe->nr_events); | ||
222 | pr_oe_time(oe->last_flush, "last_flush\n"); | ||
223 | |||
224 | return err; | ||
225 | } | ||
226 | |||
227 | void ordered_events__init(struct ordered_events *oe) | ||
228 | { | ||
229 | INIT_LIST_HEAD(&oe->events); | ||
230 | INIT_LIST_HEAD(&oe->cache); | ||
231 | INIT_LIST_HEAD(&oe->to_free); | ||
232 | oe->max_alloc_size = (u64) -1; | ||
233 | oe->cur_alloc_size = 0; | ||
234 | } | ||
235 | |||
236 | void ordered_events__free(struct ordered_events *oe) | ||
237 | { | ||
238 | while (!list_empty(&oe->to_free)) { | ||
239 | struct ordered_event *event; | ||
240 | |||
241 | event = list_entry(oe->to_free.next, struct ordered_event, list); | ||
242 | list_del(&event->list); | ||
243 | free(event); | ||
244 | } | ||
245 | } | ||
diff --git a/tools/perf/util/ordered-events.h b/tools/perf/util/ordered-events.h new file mode 100644 index 000000000000..3b2f20542a01 --- /dev/null +++ b/tools/perf/util/ordered-events.h | |||
@@ -0,0 +1,51 @@ | |||
1 | #ifndef __ORDERED_EVENTS_H | ||
2 | #define __ORDERED_EVENTS_H | ||
3 | |||
4 | #include <linux/types.h> | ||
5 | #include "tool.h" | ||
6 | |||
7 | struct perf_session; | ||
8 | |||
9 | struct ordered_event { | ||
10 | u64 timestamp; | ||
11 | u64 file_offset; | ||
12 | union perf_event *event; | ||
13 | struct list_head list; | ||
14 | }; | ||
15 | |||
16 | enum oe_flush { | ||
17 | OE_FLUSH__NONE, | ||
18 | OE_FLUSH__FINAL, | ||
19 | OE_FLUSH__ROUND, | ||
20 | OE_FLUSH__HALF, | ||
21 | }; | ||
22 | |||
23 | struct ordered_events { | ||
24 | u64 last_flush; | ||
25 | u64 next_flush; | ||
26 | u64 max_timestamp; | ||
27 | u64 max_alloc_size; | ||
28 | u64 cur_alloc_size; | ||
29 | struct list_head events; | ||
30 | struct list_head cache; | ||
31 | struct list_head to_free; | ||
32 | struct ordered_event *buffer; | ||
33 | struct ordered_event *last; | ||
34 | int buffer_idx; | ||
35 | unsigned int nr_events; | ||
36 | enum oe_flush last_flush_type; | ||
37 | }; | ||
38 | |||
39 | struct ordered_event *ordered_events__new(struct ordered_events *oe, u64 timestamp); | ||
40 | void ordered_events__delete(struct ordered_events *oe, struct ordered_event *event); | ||
41 | int ordered_events__flush(struct perf_session *s, struct perf_tool *tool, | ||
42 | enum oe_flush how); | ||
43 | void ordered_events__init(struct ordered_events *oe); | ||
44 | void ordered_events__free(struct ordered_events *oe); | ||
45 | |||
46 | static inline | ||
47 | void ordered_events__set_alloc_size(struct ordered_events *oe, u64 size) | ||
48 | { | ||
49 | oe->max_alloc_size = size; | ||
50 | } | ||
51 | #endif /* __ORDERED_EVENTS_H */ | ||
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index 1e15df10a88c..d76aa30cb1fb 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c | |||
@@ -10,6 +10,7 @@ | |||
10 | #include "symbol.h" | 10 | #include "symbol.h" |
11 | #include "cache.h" | 11 | #include "cache.h" |
12 | #include "header.h" | 12 | #include "header.h" |
13 | #include "debug.h" | ||
13 | #include <api/fs/debugfs.h> | 14 | #include <api/fs/debugfs.h> |
14 | #include "parse-events-bison.h" | 15 | #include "parse-events-bison.h" |
15 | #define YY_EXTRA_TYPE int | 16 | #define YY_EXTRA_TYPE int |
@@ -633,18 +634,28 @@ int parse_events_add_pmu(struct list_head *list, int *idx, | |||
633 | char *name, struct list_head *head_config) | 634 | char *name, struct list_head *head_config) |
634 | { | 635 | { |
635 | struct perf_event_attr attr; | 636 | struct perf_event_attr attr; |
637 | struct perf_pmu_info info; | ||
636 | struct perf_pmu *pmu; | 638 | struct perf_pmu *pmu; |
637 | struct perf_evsel *evsel; | 639 | struct perf_evsel *evsel; |
638 | const char *unit; | ||
639 | double scale; | ||
640 | 640 | ||
641 | pmu = perf_pmu__find(name); | 641 | pmu = perf_pmu__find(name); |
642 | if (!pmu) | 642 | if (!pmu) |
643 | return -EINVAL; | 643 | return -EINVAL; |
644 | 644 | ||
645 | memset(&attr, 0, sizeof(attr)); | 645 | if (pmu->default_config) { |
646 | memcpy(&attr, pmu->default_config, | ||
647 | sizeof(struct perf_event_attr)); | ||
648 | } else { | ||
649 | memset(&attr, 0, sizeof(attr)); | ||
650 | } | ||
651 | |||
652 | if (!head_config) { | ||
653 | attr.type = pmu->type; | ||
654 | evsel = __add_event(list, idx, &attr, NULL, pmu->cpus); | ||
655 | return evsel ? 0 : -ENOMEM; | ||
656 | } | ||
646 | 657 | ||
647 | if (perf_pmu__check_alias(pmu, head_config, &unit, &scale)) | 658 | if (perf_pmu__check_alias(pmu, head_config, &info)) |
648 | return -EINVAL; | 659 | return -EINVAL; |
649 | 660 | ||
650 | /* | 661 | /* |
@@ -659,8 +670,8 @@ int parse_events_add_pmu(struct list_head *list, int *idx, | |||
659 | evsel = __add_event(list, idx, &attr, pmu_event_name(head_config), | 670 | evsel = __add_event(list, idx, &attr, pmu_event_name(head_config), |
660 | pmu->cpus); | 671 | pmu->cpus); |
661 | if (evsel) { | 672 | if (evsel) { |
662 | evsel->unit = unit; | 673 | evsel->unit = info.unit; |
663 | evsel->scale = scale; | 674 | evsel->scale = info.scale; |
664 | } | 675 | } |
665 | 676 | ||
666 | return evsel ? 0 : -ENOMEM; | 677 | return evsel ? 0 : -ENOMEM; |
@@ -973,7 +984,7 @@ int parse_filter(const struct option *opt, const char *str, | |||
973 | 984 | ||
974 | if (last == NULL || last->attr.type != PERF_TYPE_TRACEPOINT) { | 985 | if (last == NULL || last->attr.type != PERF_TYPE_TRACEPOINT) { |
975 | fprintf(stderr, | 986 | fprintf(stderr, |
976 | "-F option should follow a -e tracepoint option\n"); | 987 | "--filter option should follow a -e tracepoint option\n"); |
977 | return -1; | 988 | return -1; |
978 | } | 989 | } |
979 | 990 | ||
@@ -1006,9 +1017,11 @@ void print_tracepoint_events(const char *subsys_glob, const char *event_glob, | |||
1006 | struct dirent *sys_next, *evt_next, sys_dirent, evt_dirent; | 1017 | struct dirent *sys_next, *evt_next, sys_dirent, evt_dirent; |
1007 | char evt_path[MAXPATHLEN]; | 1018 | char evt_path[MAXPATHLEN]; |
1008 | char dir_path[MAXPATHLEN]; | 1019 | char dir_path[MAXPATHLEN]; |
1020 | char sbuf[STRERR_BUFSIZE]; | ||
1009 | 1021 | ||
1010 | if (debugfs_valid_mountpoint(tracing_events_path)) { | 1022 | if (debugfs_valid_mountpoint(tracing_events_path)) { |
1011 | printf(" [ Tracepoints not available: %s ]\n", strerror(errno)); | 1023 | printf(" [ Tracepoints not available: %s ]\n", |
1024 | strerror_r(errno, sbuf, sizeof(sbuf))); | ||
1012 | return; | 1025 | return; |
1013 | } | 1026 | } |
1014 | 1027 | ||
diff --git a/tools/perf/util/parse-events.y b/tools/perf/util/parse-events.y index 0bc87ba46bf3..55fab6ad609a 100644 --- a/tools/perf/util/parse-events.y +++ b/tools/perf/util/parse-events.y | |||
@@ -210,6 +210,16 @@ PE_NAME '/' event_config '/' | |||
210 | parse_events__free_terms($3); | 210 | parse_events__free_terms($3); |
211 | $$ = list; | 211 | $$ = list; |
212 | } | 212 | } |
213 | | | ||
214 | PE_NAME '/' '/' | ||
215 | { | ||
216 | struct parse_events_evlist *data = _data; | ||
217 | struct list_head *list; | ||
218 | |||
219 | ALLOC_LIST(list); | ||
220 | ABORT_ON(parse_events_add_pmu(list, &data->idx, $1, NULL)); | ||
221 | $$ = list; | ||
222 | } | ||
213 | 223 | ||
214 | value_sym: | 224 | value_sym: |
215 | PE_VALUE_SYM_HW | 225 | PE_VALUE_SYM_HW |
diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c index 7a811eb61f75..93a41ca96b8e 100644 --- a/tools/perf/util/pmu.c +++ b/tools/perf/util/pmu.c | |||
@@ -2,6 +2,8 @@ | |||
2 | #include <sys/types.h> | 2 | #include <sys/types.h> |
3 | #include <unistd.h> | 3 | #include <unistd.h> |
4 | #include <stdio.h> | 4 | #include <stdio.h> |
5 | #include <stdbool.h> | ||
6 | #include <stdarg.h> | ||
5 | #include <dirent.h> | 7 | #include <dirent.h> |
6 | #include <api/fs/fs.h> | 8 | #include <api/fs/fs.h> |
7 | #include <locale.h> | 9 | #include <locale.h> |
@@ -14,8 +16,8 @@ | |||
14 | 16 | ||
15 | struct perf_pmu_alias { | 17 | struct perf_pmu_alias { |
16 | char *name; | 18 | char *name; |
17 | struct list_head terms; | 19 | struct list_head terms; /* HEAD struct parse_events_term -> list */ |
18 | struct list_head list; | 20 | struct list_head list; /* ELEM */ |
19 | char unit[UNIT_MAX_LEN+1]; | 21 | char unit[UNIT_MAX_LEN+1]; |
20 | double scale; | 22 | double scale; |
21 | }; | 23 | }; |
@@ -208,6 +210,19 @@ static int perf_pmu__new_alias(struct list_head *list, char *dir, char *name, FI | |||
208 | return 0; | 210 | return 0; |
209 | } | 211 | } |
210 | 212 | ||
213 | static inline bool pmu_alias_info_file(char *name) | ||
214 | { | ||
215 | size_t len; | ||
216 | |||
217 | len = strlen(name); | ||
218 | if (len > 5 && !strcmp(name + len - 5, ".unit")) | ||
219 | return true; | ||
220 | if (len > 6 && !strcmp(name + len - 6, ".scale")) | ||
221 | return true; | ||
222 | |||
223 | return false; | ||
224 | } | ||
225 | |||
211 | /* | 226 | /* |
212 | * Process all the sysfs attributes located under the directory | 227 | * Process all the sysfs attributes located under the directory |
213 | * specified in 'dir' parameter. | 228 | * specified in 'dir' parameter. |
@@ -216,7 +231,6 @@ static int pmu_aliases_parse(char *dir, struct list_head *head) | |||
216 | { | 231 | { |
217 | struct dirent *evt_ent; | 232 | struct dirent *evt_ent; |
218 | DIR *event_dir; | 233 | DIR *event_dir; |
219 | size_t len; | ||
220 | int ret = 0; | 234 | int ret = 0; |
221 | 235 | ||
222 | event_dir = opendir(dir); | 236 | event_dir = opendir(dir); |
@@ -232,13 +246,9 @@ static int pmu_aliases_parse(char *dir, struct list_head *head) | |||
232 | continue; | 246 | continue; |
233 | 247 | ||
234 | /* | 248 | /* |
235 | * skip .unit and .scale info files | 249 | * skip info files parsed in perf_pmu__new_alias() |
236 | * parsed in perf_pmu__new_alias() | ||
237 | */ | 250 | */ |
238 | len = strlen(name); | 251 | if (pmu_alias_info_file(name)) |
239 | if (len > 5 && !strcmp(name + len - 5, ".unit")) | ||
240 | continue; | ||
241 | if (len > 6 && !strcmp(name + len - 6, ".scale")) | ||
242 | continue; | 252 | continue; |
243 | 253 | ||
244 | snprintf(path, PATH_MAX, "%s/%s", dir, name); | 254 | snprintf(path, PATH_MAX, "%s/%s", dir, name); |
@@ -387,6 +397,12 @@ static struct cpu_map *pmu_cpumask(const char *name) | |||
387 | return cpus; | 397 | return cpus; |
388 | } | 398 | } |
389 | 399 | ||
400 | struct perf_event_attr *__attribute__((weak)) | ||
401 | perf_pmu__get_default_config(struct perf_pmu *pmu __maybe_unused) | ||
402 | { | ||
403 | return NULL; | ||
404 | } | ||
405 | |||
390 | static struct perf_pmu *pmu_lookup(const char *name) | 406 | static struct perf_pmu *pmu_lookup(const char *name) |
391 | { | 407 | { |
392 | struct perf_pmu *pmu; | 408 | struct perf_pmu *pmu; |
@@ -421,6 +437,9 @@ static struct perf_pmu *pmu_lookup(const char *name) | |||
421 | pmu->name = strdup(name); | 437 | pmu->name = strdup(name); |
422 | pmu->type = type; | 438 | pmu->type = type; |
423 | list_add_tail(&pmu->list, &pmus); | 439 | list_add_tail(&pmu->list, &pmus); |
440 | |||
441 | pmu->default_config = perf_pmu__get_default_config(pmu); | ||
442 | |||
424 | return pmu; | 443 | return pmu; |
425 | } | 444 | } |
426 | 445 | ||
@@ -479,28 +498,24 @@ pmu_find_format(struct list_head *formats, char *name) | |||
479 | } | 498 | } |
480 | 499 | ||
481 | /* | 500 | /* |
482 | * Returns value based on the format definition (format parameter) | 501 | * Sets value based on the format definition (format parameter) |
483 | * and unformated value (value parameter). | 502 | * and unformated value (value parameter). |
484 | * | ||
485 | * TODO maybe optimize a little ;) | ||
486 | */ | 503 | */ |
487 | static __u64 pmu_format_value(unsigned long *format, __u64 value) | 504 | static void pmu_format_value(unsigned long *format, __u64 value, __u64 *v, |
505 | bool zero) | ||
488 | { | 506 | { |
489 | unsigned long fbit, vbit; | 507 | unsigned long fbit, vbit; |
490 | __u64 v = 0; | ||
491 | 508 | ||
492 | for (fbit = 0, vbit = 0; fbit < PERF_PMU_FORMAT_BITS; fbit++) { | 509 | for (fbit = 0, vbit = 0; fbit < PERF_PMU_FORMAT_BITS; fbit++) { |
493 | 510 | ||
494 | if (!test_bit(fbit, format)) | 511 | if (!test_bit(fbit, format)) |
495 | continue; | 512 | continue; |
496 | 513 | ||
497 | if (!(value & (1llu << vbit++))) | 514 | if (value & (1llu << vbit++)) |
498 | continue; | 515 | *v |= (1llu << fbit); |
499 | 516 | else if (zero) | |
500 | v |= (1llu << fbit); | 517 | *v &= ~(1llu << fbit); |
501 | } | 518 | } |
502 | |||
503 | return v; | ||
504 | } | 519 | } |
505 | 520 | ||
506 | /* | 521 | /* |
@@ -509,7 +524,8 @@ static __u64 pmu_format_value(unsigned long *format, __u64 value) | |||
509 | */ | 524 | */ |
510 | static int pmu_config_term(struct list_head *formats, | 525 | static int pmu_config_term(struct list_head *formats, |
511 | struct perf_event_attr *attr, | 526 | struct perf_event_attr *attr, |
512 | struct parse_events_term *term) | 527 | struct parse_events_term *term, |
528 | bool zero) | ||
513 | { | 529 | { |
514 | struct perf_pmu_format *format; | 530 | struct perf_pmu_format *format; |
515 | __u64 *vp; | 531 | __u64 *vp; |
@@ -548,18 +564,19 @@ static int pmu_config_term(struct list_head *formats, | |||
548 | * non-hardcoded terms, here's the place to translate | 564 | * non-hardcoded terms, here's the place to translate |
549 | * them into value. | 565 | * them into value. |
550 | */ | 566 | */ |
551 | *vp |= pmu_format_value(format->bits, term->val.num); | 567 | pmu_format_value(format->bits, term->val.num, vp, zero); |
552 | return 0; | 568 | return 0; |
553 | } | 569 | } |
554 | 570 | ||
555 | int perf_pmu__config_terms(struct list_head *formats, | 571 | int perf_pmu__config_terms(struct list_head *formats, |
556 | struct perf_event_attr *attr, | 572 | struct perf_event_attr *attr, |
557 | struct list_head *head_terms) | 573 | struct list_head *head_terms, |
574 | bool zero) | ||
558 | { | 575 | { |
559 | struct parse_events_term *term; | 576 | struct parse_events_term *term; |
560 | 577 | ||
561 | list_for_each_entry(term, head_terms, list) | 578 | list_for_each_entry(term, head_terms, list) |
562 | if (pmu_config_term(formats, attr, term)) | 579 | if (pmu_config_term(formats, attr, term, zero)) |
563 | return -EINVAL; | 580 | return -EINVAL; |
564 | 581 | ||
565 | return 0; | 582 | return 0; |
@@ -573,8 +590,10 @@ int perf_pmu__config_terms(struct list_head *formats, | |||
573 | int perf_pmu__config(struct perf_pmu *pmu, struct perf_event_attr *attr, | 590 | int perf_pmu__config(struct perf_pmu *pmu, struct perf_event_attr *attr, |
574 | struct list_head *head_terms) | 591 | struct list_head *head_terms) |
575 | { | 592 | { |
593 | bool zero = !!pmu->default_config; | ||
594 | |||
576 | attr->type = pmu->type; | 595 | attr->type = pmu->type; |
577 | return perf_pmu__config_terms(&pmu->format, attr, head_terms); | 596 | return perf_pmu__config_terms(&pmu->format, attr, head_terms, zero); |
578 | } | 597 | } |
579 | 598 | ||
580 | static struct perf_pmu_alias *pmu_find_alias(struct perf_pmu *pmu, | 599 | static struct perf_pmu_alias *pmu_find_alias(struct perf_pmu *pmu, |
@@ -634,7 +653,7 @@ static int check_unit_scale(struct perf_pmu_alias *alias, | |||
634 | * defined for the alias | 653 | * defined for the alias |
635 | */ | 654 | */ |
636 | int perf_pmu__check_alias(struct perf_pmu *pmu, struct list_head *head_terms, | 655 | int perf_pmu__check_alias(struct perf_pmu *pmu, struct list_head *head_terms, |
637 | const char **unit, double *scale) | 656 | struct perf_pmu_info *info) |
638 | { | 657 | { |
639 | struct parse_events_term *term, *h; | 658 | struct parse_events_term *term, *h; |
640 | struct perf_pmu_alias *alias; | 659 | struct perf_pmu_alias *alias; |
@@ -644,8 +663,8 @@ int perf_pmu__check_alias(struct perf_pmu *pmu, struct list_head *head_terms, | |||
644 | * Mark unit and scale as not set | 663 | * Mark unit and scale as not set |
645 | * (different from default values, see below) | 664 | * (different from default values, see below) |
646 | */ | 665 | */ |
647 | *unit = NULL; | 666 | info->unit = NULL; |
648 | *scale = 0.0; | 667 | info->scale = 0.0; |
649 | 668 | ||
650 | list_for_each_entry_safe(term, h, head_terms, list) { | 669 | list_for_each_entry_safe(term, h, head_terms, list) { |
651 | alias = pmu_find_alias(pmu, term); | 670 | alias = pmu_find_alias(pmu, term); |
@@ -655,7 +674,7 @@ int perf_pmu__check_alias(struct perf_pmu *pmu, struct list_head *head_terms, | |||
655 | if (ret) | 674 | if (ret) |
656 | return ret; | 675 | return ret; |
657 | 676 | ||
658 | ret = check_unit_scale(alias, unit, scale); | 677 | ret = check_unit_scale(alias, &info->unit, &info->scale); |
659 | if (ret) | 678 | if (ret) |
660 | return ret; | 679 | return ret; |
661 | 680 | ||
@@ -668,11 +687,11 @@ int perf_pmu__check_alias(struct perf_pmu *pmu, struct list_head *head_terms, | |||
668 | * set defaults as for evsel | 687 | * set defaults as for evsel |
669 | * unit cannot left to NULL | 688 | * unit cannot left to NULL |
670 | */ | 689 | */ |
671 | if (*unit == NULL) | 690 | if (info->unit == NULL) |
672 | *unit = ""; | 691 | info->unit = ""; |
673 | 692 | ||
674 | if (*scale == 0.0) | 693 | if (info->scale == 0.0) |
675 | *scale = 1.0; | 694 | info->scale = 1.0; |
676 | 695 | ||
677 | return 0; | 696 | return 0; |
678 | } | 697 | } |
@@ -794,3 +813,39 @@ bool pmu_have_event(const char *pname, const char *name) | |||
794 | } | 813 | } |
795 | return false; | 814 | return false; |
796 | } | 815 | } |
816 | |||
817 | static FILE *perf_pmu__open_file(struct perf_pmu *pmu, const char *name) | ||
818 | { | ||
819 | struct stat st; | ||
820 | char path[PATH_MAX]; | ||
821 | const char *sysfs; | ||
822 | |||
823 | sysfs = sysfs__mountpoint(); | ||
824 | if (!sysfs) | ||
825 | return NULL; | ||
826 | |||
827 | snprintf(path, PATH_MAX, | ||
828 | "%s" EVENT_SOURCE_DEVICE_PATH "%s/%s", sysfs, pmu->name, name); | ||
829 | |||
830 | if (stat(path, &st) < 0) | ||
831 | return NULL; | ||
832 | |||
833 | return fopen(path, "r"); | ||
834 | } | ||
835 | |||
836 | int perf_pmu__scan_file(struct perf_pmu *pmu, const char *name, const char *fmt, | ||
837 | ...) | ||
838 | { | ||
839 | va_list args; | ||
840 | FILE *file; | ||
841 | int ret = EOF; | ||
842 | |||
843 | va_start(args, fmt); | ||
844 | file = perf_pmu__open_file(pmu, name); | ||
845 | if (file) { | ||
846 | ret = vfscanf(file, fmt, args); | ||
847 | fclose(file); | ||
848 | } | ||
849 | va_end(args); | ||
850 | return ret; | ||
851 | } | ||
diff --git a/tools/perf/util/pmu.h b/tools/perf/util/pmu.h index c14a543ce1f3..fe90a012c003 100644 --- a/tools/perf/util/pmu.h +++ b/tools/perf/util/pmu.h | |||
@@ -13,13 +13,21 @@ enum { | |||
13 | 13 | ||
14 | #define PERF_PMU_FORMAT_BITS 64 | 14 | #define PERF_PMU_FORMAT_BITS 64 |
15 | 15 | ||
16 | struct perf_event_attr; | ||
17 | |||
16 | struct perf_pmu { | 18 | struct perf_pmu { |
17 | char *name; | 19 | char *name; |
18 | __u32 type; | 20 | __u32 type; |
21 | struct perf_event_attr *default_config; | ||
19 | struct cpu_map *cpus; | 22 | struct cpu_map *cpus; |
20 | struct list_head format; | 23 | struct list_head format; /* HEAD struct perf_pmu_format -> list */ |
21 | struct list_head aliases; | 24 | struct list_head aliases; /* HEAD struct perf_pmu_alias -> list */ |
22 | struct list_head list; | 25 | struct list_head list; /* ELEM */ |
26 | }; | ||
27 | |||
28 | struct perf_pmu_info { | ||
29 | const char *unit; | ||
30 | double scale; | ||
23 | }; | 31 | }; |
24 | 32 | ||
25 | struct perf_pmu *perf_pmu__find(const char *name); | 33 | struct perf_pmu *perf_pmu__find(const char *name); |
@@ -27,9 +35,10 @@ int perf_pmu__config(struct perf_pmu *pmu, struct perf_event_attr *attr, | |||
27 | struct list_head *head_terms); | 35 | struct list_head *head_terms); |
28 | int perf_pmu__config_terms(struct list_head *formats, | 36 | int perf_pmu__config_terms(struct list_head *formats, |
29 | struct perf_event_attr *attr, | 37 | struct perf_event_attr *attr, |
30 | struct list_head *head_terms); | 38 | struct list_head *head_terms, |
39 | bool zero); | ||
31 | int perf_pmu__check_alias(struct perf_pmu *pmu, struct list_head *head_terms, | 40 | int perf_pmu__check_alias(struct perf_pmu *pmu, struct list_head *head_terms, |
32 | const char **unit, double *scale); | 41 | struct perf_pmu_info *info); |
33 | struct list_head *perf_pmu__alias(struct perf_pmu *pmu, | 42 | struct list_head *perf_pmu__alias(struct perf_pmu *pmu, |
34 | struct list_head *head_terms); | 43 | struct list_head *head_terms); |
35 | int perf_pmu_wrap(void); | 44 | int perf_pmu_wrap(void); |
@@ -45,5 +54,11 @@ struct perf_pmu *perf_pmu__scan(struct perf_pmu *pmu); | |||
45 | void print_pmu_events(const char *event_glob, bool name_only); | 54 | void print_pmu_events(const char *event_glob, bool name_only); |
46 | bool pmu_have_event(const char *pname, const char *name); | 55 | bool pmu_have_event(const char *pname, const char *name); |
47 | 56 | ||
57 | int perf_pmu__scan_file(struct perf_pmu *pmu, const char *name, const char *fmt, | ||
58 | ...) __attribute__((format(scanf, 3, 4))); | ||
59 | |||
48 | int perf_pmu__test(void); | 60 | int perf_pmu__test(void); |
61 | |||
62 | struct perf_event_attr *perf_pmu__get_default_config(struct perf_pmu *pmu); | ||
63 | |||
49 | #endif /* __PMU_H */ | 64 | #endif /* __PMU_H */ |
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c index 9a0a1839a377..c150ca4343eb 100644 --- a/tools/perf/util/probe-event.c +++ b/tools/perf/util/probe-event.c | |||
@@ -79,7 +79,7 @@ static int init_symbol_maps(bool user_only) | |||
79 | int ret; | 79 | int ret; |
80 | 80 | ||
81 | symbol_conf.sort_by_name = true; | 81 | symbol_conf.sort_by_name = true; |
82 | ret = symbol__init(); | 82 | ret = symbol__init(NULL); |
83 | if (ret < 0) { | 83 | if (ret < 0) { |
84 | pr_debug("Failed to init symbol map.\n"); | 84 | pr_debug("Failed to init symbol map.\n"); |
85 | goto out; | 85 | goto out; |
@@ -184,7 +184,8 @@ static struct dso *kernel_get_module_dso(const char *module) | |||
184 | const char *vmlinux_name; | 184 | const char *vmlinux_name; |
185 | 185 | ||
186 | if (module) { | 186 | if (module) { |
187 | list_for_each_entry(dso, &host_machine->kernel_dsos, node) { | 187 | list_for_each_entry(dso, &host_machine->kernel_dsos.head, |
188 | node) { | ||
188 | if (strncmp(dso->short_name + 1, module, | 189 | if (strncmp(dso->short_name + 1, module, |
189 | dso->short_name_len - 2) == 0) | 190 | dso->short_name_len - 2) == 0) |
190 | goto found; | 191 | goto found; |
@@ -258,21 +259,33 @@ static void clear_probe_trace_events(struct probe_trace_event *tevs, int ntevs) | |||
258 | #ifdef HAVE_DWARF_SUPPORT | 259 | #ifdef HAVE_DWARF_SUPPORT |
259 | 260 | ||
260 | /* Open new debuginfo of given module */ | 261 | /* Open new debuginfo of given module */ |
261 | static struct debuginfo *open_debuginfo(const char *module) | 262 | static struct debuginfo *open_debuginfo(const char *module, bool silent) |
262 | { | 263 | { |
263 | const char *path = module; | 264 | const char *path = module; |
265 | struct debuginfo *ret; | ||
264 | 266 | ||
265 | if (!module || !strchr(module, '/')) { | 267 | if (!module || !strchr(module, '/')) { |
266 | path = kernel_get_module_path(module); | 268 | path = kernel_get_module_path(module); |
267 | if (!path) { | 269 | if (!path) { |
268 | pr_err("Failed to find path of %s module.\n", | 270 | if (!silent) |
269 | module ?: "kernel"); | 271 | pr_err("Failed to find path of %s module.\n", |
272 | module ?: "kernel"); | ||
270 | return NULL; | 273 | return NULL; |
271 | } | 274 | } |
272 | } | 275 | } |
273 | return debuginfo__new(path); | 276 | ret = debuginfo__new(path); |
277 | if (!ret && !silent) { | ||
278 | pr_warning("The %s file has no debug information.\n", path); | ||
279 | if (!module || !strtailcmp(path, ".ko")) | ||
280 | pr_warning("Rebuild with CONFIG_DEBUG_INFO=y, "); | ||
281 | else | ||
282 | pr_warning("Rebuild with -g, "); | ||
283 | pr_warning("or install an appropriate debuginfo package.\n"); | ||
284 | } | ||
285 | return ret; | ||
274 | } | 286 | } |
275 | 287 | ||
288 | |||
276 | static int get_text_start_address(const char *exec, unsigned long *address) | 289 | static int get_text_start_address(const char *exec, unsigned long *address) |
277 | { | 290 | { |
278 | Elf *elf; | 291 | Elf *elf; |
@@ -333,15 +346,13 @@ static int find_perf_probe_point_from_dwarf(struct probe_trace_point *tp, | |||
333 | pr_debug("try to find information at %" PRIx64 " in %s\n", addr, | 346 | pr_debug("try to find information at %" PRIx64 " in %s\n", addr, |
334 | tp->module ? : "kernel"); | 347 | tp->module ? : "kernel"); |
335 | 348 | ||
336 | dinfo = open_debuginfo(tp->module); | 349 | dinfo = open_debuginfo(tp->module, verbose == 0); |
337 | if (dinfo) { | 350 | if (dinfo) { |
338 | ret = debuginfo__find_probe_point(dinfo, | 351 | ret = debuginfo__find_probe_point(dinfo, |
339 | (unsigned long)addr, pp); | 352 | (unsigned long)addr, pp); |
340 | debuginfo__delete(dinfo); | 353 | debuginfo__delete(dinfo); |
341 | } else { | 354 | } else |
342 | pr_debug("Failed to open debuginfo at 0x%" PRIx64 "\n", addr); | ||
343 | ret = -ENOENT; | 355 | ret = -ENOENT; |
344 | } | ||
345 | 356 | ||
346 | if (ret > 0) { | 357 | if (ret > 0) { |
347 | pp->retprobe = tp->retprobe; | 358 | pp->retprobe = tp->retprobe; |
@@ -457,13 +468,11 @@ static int try_to_find_probe_trace_events(struct perf_probe_event *pev, | |||
457 | struct debuginfo *dinfo; | 468 | struct debuginfo *dinfo; |
458 | int ntevs, ret = 0; | 469 | int ntevs, ret = 0; |
459 | 470 | ||
460 | dinfo = open_debuginfo(target); | 471 | dinfo = open_debuginfo(target, !need_dwarf); |
461 | 472 | ||
462 | if (!dinfo) { | 473 | if (!dinfo) { |
463 | if (need_dwarf) { | 474 | if (need_dwarf) |
464 | pr_warning("Failed to open debuginfo file.\n"); | ||
465 | return -ENOENT; | 475 | return -ENOENT; |
466 | } | ||
467 | pr_debug("Could not open debuginfo. Try to use symbols.\n"); | 476 | pr_debug("Could not open debuginfo. Try to use symbols.\n"); |
468 | return 0; | 477 | return 0; |
469 | } | 478 | } |
@@ -565,7 +574,7 @@ static int get_real_path(const char *raw_path, const char *comp_dir, | |||
565 | 574 | ||
566 | static int __show_one_line(FILE *fp, int l, bool skip, bool show_num) | 575 | static int __show_one_line(FILE *fp, int l, bool skip, bool show_num) |
567 | { | 576 | { |
568 | char buf[LINEBUF_SIZE]; | 577 | char buf[LINEBUF_SIZE], sbuf[STRERR_BUFSIZE]; |
569 | const char *color = show_num ? "" : PERF_COLOR_BLUE; | 578 | const char *color = show_num ? "" : PERF_COLOR_BLUE; |
570 | const char *prefix = NULL; | 579 | const char *prefix = NULL; |
571 | 580 | ||
@@ -585,7 +594,8 @@ static int __show_one_line(FILE *fp, int l, bool skip, bool show_num) | |||
585 | return 1; | 594 | return 1; |
586 | error: | 595 | error: |
587 | if (ferror(fp)) { | 596 | if (ferror(fp)) { |
588 | pr_warning("File read error: %s\n", strerror(errno)); | 597 | pr_warning("File read error: %s\n", |
598 | strerror_r(errno, sbuf, sizeof(sbuf))); | ||
589 | return -1; | 599 | return -1; |
590 | } | 600 | } |
591 | return 0; | 601 | return 0; |
@@ -618,13 +628,12 @@ static int __show_line_range(struct line_range *lr, const char *module) | |||
618 | FILE *fp; | 628 | FILE *fp; |
619 | int ret; | 629 | int ret; |
620 | char *tmp; | 630 | char *tmp; |
631 | char sbuf[STRERR_BUFSIZE]; | ||
621 | 632 | ||
622 | /* Search a line range */ | 633 | /* Search a line range */ |
623 | dinfo = open_debuginfo(module); | 634 | dinfo = open_debuginfo(module, false); |
624 | if (!dinfo) { | 635 | if (!dinfo) |
625 | pr_warning("Failed to open debuginfo file.\n"); | ||
626 | return -ENOENT; | 636 | return -ENOENT; |
627 | } | ||
628 | 637 | ||
629 | ret = debuginfo__find_line_range(dinfo, lr); | 638 | ret = debuginfo__find_line_range(dinfo, lr); |
630 | debuginfo__delete(dinfo); | 639 | debuginfo__delete(dinfo); |
@@ -656,7 +665,7 @@ static int __show_line_range(struct line_range *lr, const char *module) | |||
656 | fp = fopen(lr->path, "r"); | 665 | fp = fopen(lr->path, "r"); |
657 | if (fp == NULL) { | 666 | if (fp == NULL) { |
658 | pr_warning("Failed to open %s: %s\n", lr->path, | 667 | pr_warning("Failed to open %s: %s\n", lr->path, |
659 | strerror(errno)); | 668 | strerror_r(errno, sbuf, sizeof(sbuf))); |
660 | return -errno; | 669 | return -errno; |
661 | } | 670 | } |
662 | /* Skip to starting line number */ | 671 | /* Skip to starting line number */ |
@@ -689,11 +698,11 @@ end: | |||
689 | return ret; | 698 | return ret; |
690 | } | 699 | } |
691 | 700 | ||
692 | int show_line_range(struct line_range *lr, const char *module) | 701 | int show_line_range(struct line_range *lr, const char *module, bool user) |
693 | { | 702 | { |
694 | int ret; | 703 | int ret; |
695 | 704 | ||
696 | ret = init_symbol_maps(false); | 705 | ret = init_symbol_maps(user); |
697 | if (ret < 0) | 706 | if (ret < 0) |
698 | return ret; | 707 | return ret; |
699 | ret = __show_line_range(lr, module); | 708 | ret = __show_line_range(lr, module); |
@@ -768,13 +777,12 @@ int show_available_vars(struct perf_probe_event *pevs, int npevs, | |||
768 | int i, ret = 0; | 777 | int i, ret = 0; |
769 | struct debuginfo *dinfo; | 778 | struct debuginfo *dinfo; |
770 | 779 | ||
771 | ret = init_symbol_maps(false); | 780 | ret = init_symbol_maps(pevs->uprobes); |
772 | if (ret < 0) | 781 | if (ret < 0) |
773 | return ret; | 782 | return ret; |
774 | 783 | ||
775 | dinfo = open_debuginfo(module); | 784 | dinfo = open_debuginfo(module, false); |
776 | if (!dinfo) { | 785 | if (!dinfo) { |
777 | pr_warning("Failed to open debuginfo file.\n"); | ||
778 | ret = -ENOENT; | 786 | ret = -ENOENT; |
779 | goto out; | 787 | goto out; |
780 | } | 788 | } |
@@ -815,7 +823,8 @@ static int try_to_find_probe_trace_events(struct perf_probe_event *pev, | |||
815 | } | 823 | } |
816 | 824 | ||
817 | int show_line_range(struct line_range *lr __maybe_unused, | 825 | int show_line_range(struct line_range *lr __maybe_unused, |
818 | const char *module __maybe_unused) | 826 | const char *module __maybe_unused, |
827 | bool user __maybe_unused) | ||
819 | { | 828 | { |
820 | pr_warning("Debuginfo-analysis is not supported.\n"); | 829 | pr_warning("Debuginfo-analysis is not supported.\n"); |
821 | return -ENOSYS; | 830 | return -ENOSYS; |
@@ -1405,8 +1414,7 @@ int synthesize_perf_probe_arg(struct perf_probe_arg *pa, char *buf, size_t len) | |||
1405 | 1414 | ||
1406 | return tmp - buf; | 1415 | return tmp - buf; |
1407 | error: | 1416 | error: |
1408 | pr_debug("Failed to synthesize perf probe argument: %s\n", | 1417 | pr_debug("Failed to synthesize perf probe argument: %d\n", ret); |
1409 | strerror(-ret)); | ||
1410 | return ret; | 1418 | return ret; |
1411 | } | 1419 | } |
1412 | 1420 | ||
@@ -1455,8 +1463,7 @@ static char *synthesize_perf_probe_point(struct perf_probe_point *pp) | |||
1455 | 1463 | ||
1456 | return buf; | 1464 | return buf; |
1457 | error: | 1465 | error: |
1458 | pr_debug("Failed to synthesize perf probe point: %s\n", | 1466 | pr_debug("Failed to synthesize perf probe point: %d\n", ret); |
1459 | strerror(-ret)); | ||
1460 | free(buf); | 1467 | free(buf); |
1461 | return NULL; | 1468 | return NULL; |
1462 | } | 1469 | } |
@@ -1780,10 +1787,11 @@ static void clear_probe_trace_event(struct probe_trace_event *tev) | |||
1780 | memset(tev, 0, sizeof(*tev)); | 1787 | memset(tev, 0, sizeof(*tev)); |
1781 | } | 1788 | } |
1782 | 1789 | ||
1783 | static void print_warn_msg(const char *file, bool is_kprobe) | 1790 | static void print_open_warning(int err, bool is_kprobe) |
1784 | { | 1791 | { |
1792 | char sbuf[STRERR_BUFSIZE]; | ||
1785 | 1793 | ||
1786 | if (errno == ENOENT) { | 1794 | if (err == -ENOENT) { |
1787 | const char *config; | 1795 | const char *config; |
1788 | 1796 | ||
1789 | if (!is_kprobe) | 1797 | if (!is_kprobe) |
@@ -1791,25 +1799,43 @@ static void print_warn_msg(const char *file, bool is_kprobe) | |||
1791 | else | 1799 | else |
1792 | config = "CONFIG_KPROBE_EVENTS"; | 1800 | config = "CONFIG_KPROBE_EVENTS"; |
1793 | 1801 | ||
1794 | pr_warning("%s file does not exist - please rebuild kernel" | 1802 | pr_warning("%cprobe_events file does not exist" |
1795 | " with %s.\n", file, config); | 1803 | " - please rebuild kernel with %s.\n", |
1796 | } else | 1804 | is_kprobe ? 'k' : 'u', config); |
1797 | pr_warning("Failed to open %s file: %s\n", file, | 1805 | } else if (err == -ENOTSUP) |
1798 | strerror(errno)); | 1806 | pr_warning("Debugfs is not mounted.\n"); |
1807 | else | ||
1808 | pr_warning("Failed to open %cprobe_events: %s\n", | ||
1809 | is_kprobe ? 'k' : 'u', | ||
1810 | strerror_r(-err, sbuf, sizeof(sbuf))); | ||
1811 | } | ||
1812 | |||
1813 | static void print_both_open_warning(int kerr, int uerr) | ||
1814 | { | ||
1815 | /* Both kprobes and uprobes are disabled, warn it. */ | ||
1816 | if (kerr == -ENOTSUP && uerr == -ENOTSUP) | ||
1817 | pr_warning("Debugfs is not mounted.\n"); | ||
1818 | else if (kerr == -ENOENT && uerr == -ENOENT) | ||
1819 | pr_warning("Please rebuild kernel with CONFIG_KPROBE_EVENTS " | ||
1820 | "or/and CONFIG_UPROBE_EVENTS.\n"); | ||
1821 | else { | ||
1822 | char sbuf[STRERR_BUFSIZE]; | ||
1823 | pr_warning("Failed to open kprobe events: %s.\n", | ||
1824 | strerror_r(-kerr, sbuf, sizeof(sbuf))); | ||
1825 | pr_warning("Failed to open uprobe events: %s.\n", | ||
1826 | strerror_r(-uerr, sbuf, sizeof(sbuf))); | ||
1827 | } | ||
1799 | } | 1828 | } |
1800 | 1829 | ||
1801 | static int open_probe_events(const char *trace_file, bool readwrite, | 1830 | static int open_probe_events(const char *trace_file, bool readwrite) |
1802 | bool is_kprobe) | ||
1803 | { | 1831 | { |
1804 | char buf[PATH_MAX]; | 1832 | char buf[PATH_MAX]; |
1805 | const char *__debugfs; | 1833 | const char *__debugfs; |
1806 | int ret; | 1834 | int ret; |
1807 | 1835 | ||
1808 | __debugfs = debugfs_find_mountpoint(); | 1836 | __debugfs = debugfs_find_mountpoint(); |
1809 | if (__debugfs == NULL) { | 1837 | if (__debugfs == NULL) |
1810 | pr_warning("Debugfs is not mounted.\n"); | 1838 | return -ENOTSUP; |
1811 | return -ENOENT; | ||
1812 | } | ||
1813 | 1839 | ||
1814 | ret = e_snprintf(buf, PATH_MAX, "%s/%s", __debugfs, trace_file); | 1840 | ret = e_snprintf(buf, PATH_MAX, "%s/%s", __debugfs, trace_file); |
1815 | if (ret >= 0) { | 1841 | if (ret >= 0) { |
@@ -1820,19 +1846,19 @@ static int open_probe_events(const char *trace_file, bool readwrite, | |||
1820 | ret = open(buf, O_RDONLY, 0); | 1846 | ret = open(buf, O_RDONLY, 0); |
1821 | 1847 | ||
1822 | if (ret < 0) | 1848 | if (ret < 0) |
1823 | print_warn_msg(buf, is_kprobe); | 1849 | ret = -errno; |
1824 | } | 1850 | } |
1825 | return ret; | 1851 | return ret; |
1826 | } | 1852 | } |
1827 | 1853 | ||
1828 | static int open_kprobe_events(bool readwrite) | 1854 | static int open_kprobe_events(bool readwrite) |
1829 | { | 1855 | { |
1830 | return open_probe_events("tracing/kprobe_events", readwrite, true); | 1856 | return open_probe_events("tracing/kprobe_events", readwrite); |
1831 | } | 1857 | } |
1832 | 1858 | ||
1833 | static int open_uprobe_events(bool readwrite) | 1859 | static int open_uprobe_events(bool readwrite) |
1834 | { | 1860 | { |
1835 | return open_probe_events("tracing/uprobe_events", readwrite, false); | 1861 | return open_probe_events("tracing/uprobe_events", readwrite); |
1836 | } | 1862 | } |
1837 | 1863 | ||
1838 | /* Get raw string list of current kprobe_events or uprobe_events */ | 1864 | /* Get raw string list of current kprobe_events or uprobe_events */ |
@@ -1857,7 +1883,7 @@ static struct strlist *get_probe_trace_command_rawlist(int fd) | |||
1857 | p[idx] = '\0'; | 1883 | p[idx] = '\0'; |
1858 | ret = strlist__add(sl, buf); | 1884 | ret = strlist__add(sl, buf); |
1859 | if (ret < 0) { | 1885 | if (ret < 0) { |
1860 | pr_debug("strlist__add failed: %s\n", strerror(-ret)); | 1886 | pr_debug("strlist__add failed (%d)\n", ret); |
1861 | strlist__delete(sl); | 1887 | strlist__delete(sl); |
1862 | return NULL; | 1888 | return NULL; |
1863 | } | 1889 | } |
@@ -1916,7 +1942,7 @@ static int __show_perf_probe_events(int fd, bool is_kprobe) | |||
1916 | 1942 | ||
1917 | rawlist = get_probe_trace_command_rawlist(fd); | 1943 | rawlist = get_probe_trace_command_rawlist(fd); |
1918 | if (!rawlist) | 1944 | if (!rawlist) |
1919 | return -ENOENT; | 1945 | return -ENOMEM; |
1920 | 1946 | ||
1921 | strlist__for_each(ent, rawlist) { | 1947 | strlist__for_each(ent, rawlist) { |
1922 | ret = parse_probe_trace_command(ent->s, &tev); | 1948 | ret = parse_probe_trace_command(ent->s, &tev); |
@@ -1940,27 +1966,34 @@ static int __show_perf_probe_events(int fd, bool is_kprobe) | |||
1940 | /* List up current perf-probe events */ | 1966 | /* List up current perf-probe events */ |
1941 | int show_perf_probe_events(void) | 1967 | int show_perf_probe_events(void) |
1942 | { | 1968 | { |
1943 | int fd, ret; | 1969 | int kp_fd, up_fd, ret; |
1944 | 1970 | ||
1945 | setup_pager(); | 1971 | setup_pager(); |
1946 | fd = open_kprobe_events(false); | ||
1947 | |||
1948 | if (fd < 0) | ||
1949 | return fd; | ||
1950 | 1972 | ||
1951 | ret = init_symbol_maps(false); | 1973 | ret = init_symbol_maps(false); |
1952 | if (ret < 0) | 1974 | if (ret < 0) |
1953 | return ret; | 1975 | return ret; |
1954 | 1976 | ||
1955 | ret = __show_perf_probe_events(fd, true); | 1977 | kp_fd = open_kprobe_events(false); |
1956 | close(fd); | 1978 | if (kp_fd >= 0) { |
1979 | ret = __show_perf_probe_events(kp_fd, true); | ||
1980 | close(kp_fd); | ||
1981 | if (ret < 0) | ||
1982 | goto out; | ||
1983 | } | ||
1957 | 1984 | ||
1958 | fd = open_uprobe_events(false); | 1985 | up_fd = open_uprobe_events(false); |
1959 | if (fd >= 0) { | 1986 | if (kp_fd < 0 && up_fd < 0) { |
1960 | ret = __show_perf_probe_events(fd, false); | 1987 | print_both_open_warning(kp_fd, up_fd); |
1961 | close(fd); | 1988 | ret = kp_fd; |
1989 | goto out; | ||
1962 | } | 1990 | } |
1963 | 1991 | ||
1992 | if (up_fd >= 0) { | ||
1993 | ret = __show_perf_probe_events(up_fd, false); | ||
1994 | close(up_fd); | ||
1995 | } | ||
1996 | out: | ||
1964 | exit_symbol_maps(); | 1997 | exit_symbol_maps(); |
1965 | return ret; | 1998 | return ret; |
1966 | } | 1999 | } |
@@ -1976,6 +2009,8 @@ static struct strlist *get_probe_trace_event_names(int fd, bool include_group) | |||
1976 | 2009 | ||
1977 | memset(&tev, 0, sizeof(tev)); | 2010 | memset(&tev, 0, sizeof(tev)); |
1978 | rawlist = get_probe_trace_command_rawlist(fd); | 2011 | rawlist = get_probe_trace_command_rawlist(fd); |
2012 | if (!rawlist) | ||
2013 | return NULL; | ||
1979 | sl = strlist__new(true, NULL); | 2014 | sl = strlist__new(true, NULL); |
1980 | strlist__for_each(ent, rawlist) { | 2015 | strlist__for_each(ent, rawlist) { |
1981 | ret = parse_probe_trace_command(ent->s, &tev); | 2016 | ret = parse_probe_trace_command(ent->s, &tev); |
@@ -2005,6 +2040,7 @@ static int write_probe_trace_event(int fd, struct probe_trace_event *tev) | |||
2005 | { | 2040 | { |
2006 | int ret = 0; | 2041 | int ret = 0; |
2007 | char *buf = synthesize_probe_trace_command(tev); | 2042 | char *buf = synthesize_probe_trace_command(tev); |
2043 | char sbuf[STRERR_BUFSIZE]; | ||
2008 | 2044 | ||
2009 | if (!buf) { | 2045 | if (!buf) { |
2010 | pr_debug("Failed to synthesize probe trace event.\n"); | 2046 | pr_debug("Failed to synthesize probe trace event.\n"); |
@@ -2016,7 +2052,7 @@ static int write_probe_trace_event(int fd, struct probe_trace_event *tev) | |||
2016 | ret = write(fd, buf, strlen(buf)); | 2052 | ret = write(fd, buf, strlen(buf)); |
2017 | if (ret <= 0) | 2053 | if (ret <= 0) |
2018 | pr_warning("Failed to write event: %s\n", | 2054 | pr_warning("Failed to write event: %s\n", |
2019 | strerror(errno)); | 2055 | strerror_r(errno, sbuf, sizeof(sbuf))); |
2020 | } | 2056 | } |
2021 | free(buf); | 2057 | free(buf); |
2022 | return ret; | 2058 | return ret; |
@@ -2030,7 +2066,7 @@ static int get_new_event_name(char *buf, size_t len, const char *base, | |||
2030 | /* Try no suffix */ | 2066 | /* Try no suffix */ |
2031 | ret = e_snprintf(buf, len, "%s", base); | 2067 | ret = e_snprintf(buf, len, "%s", base); |
2032 | if (ret < 0) { | 2068 | if (ret < 0) { |
2033 | pr_debug("snprintf() failed: %s\n", strerror(-ret)); | 2069 | pr_debug("snprintf() failed: %d\n", ret); |
2034 | return ret; | 2070 | return ret; |
2035 | } | 2071 | } |
2036 | if (!strlist__has_entry(namelist, buf)) | 2072 | if (!strlist__has_entry(namelist, buf)) |
@@ -2046,7 +2082,7 @@ static int get_new_event_name(char *buf, size_t len, const char *base, | |||
2046 | for (i = 1; i < MAX_EVENT_INDEX; i++) { | 2082 | for (i = 1; i < MAX_EVENT_INDEX; i++) { |
2047 | ret = e_snprintf(buf, len, "%s_%d", base, i); | 2083 | ret = e_snprintf(buf, len, "%s_%d", base, i); |
2048 | if (ret < 0) { | 2084 | if (ret < 0) { |
2049 | pr_debug("snprintf() failed: %s\n", strerror(-ret)); | 2085 | pr_debug("snprintf() failed: %d\n", ret); |
2050 | return ret; | 2086 | return ret; |
2051 | } | 2087 | } |
2052 | if (!strlist__has_entry(namelist, buf)) | 2088 | if (!strlist__has_entry(namelist, buf)) |
@@ -2075,8 +2111,11 @@ static int __add_probe_trace_events(struct perf_probe_event *pev, | |||
2075 | else | 2111 | else |
2076 | fd = open_kprobe_events(true); | 2112 | fd = open_kprobe_events(true); |
2077 | 2113 | ||
2078 | if (fd < 0) | 2114 | if (fd < 0) { |
2115 | print_open_warning(fd, !pev->uprobes); | ||
2079 | return fd; | 2116 | return fd; |
2117 | } | ||
2118 | |||
2080 | /* Get current event names */ | 2119 | /* Get current event names */ |
2081 | namelist = get_probe_trace_event_names(fd, false); | 2120 | namelist = get_probe_trace_event_names(fd, false); |
2082 | if (!namelist) { | 2121 | if (!namelist) { |
@@ -2408,7 +2447,8 @@ static int __del_trace_probe_event(int fd, struct str_node *ent) | |||
2408 | printf("Removed event: %s\n", ent->s); | 2447 | printf("Removed event: %s\n", ent->s); |
2409 | return 0; | 2448 | return 0; |
2410 | error: | 2449 | error: |
2411 | pr_warning("Failed to delete event: %s\n", strerror(-ret)); | 2450 | pr_warning("Failed to delete event: %s\n", |
2451 | strerror_r(-ret, buf, sizeof(buf))); | ||
2412 | return ret; | 2452 | return ret; |
2413 | } | 2453 | } |
2414 | 2454 | ||
@@ -2449,15 +2489,18 @@ int del_perf_probe_events(struct strlist *dellist) | |||
2449 | 2489 | ||
2450 | /* Get current event names */ | 2490 | /* Get current event names */ |
2451 | kfd = open_kprobe_events(true); | 2491 | kfd = open_kprobe_events(true); |
2452 | if (kfd < 0) | 2492 | if (kfd >= 0) |
2453 | return kfd; | 2493 | namelist = get_probe_trace_event_names(kfd, true); |
2454 | 2494 | ||
2455 | namelist = get_probe_trace_event_names(kfd, true); | ||
2456 | ufd = open_uprobe_events(true); | 2495 | ufd = open_uprobe_events(true); |
2457 | |||
2458 | if (ufd >= 0) | 2496 | if (ufd >= 0) |
2459 | unamelist = get_probe_trace_event_names(ufd, true); | 2497 | unamelist = get_probe_trace_event_names(ufd, true); |
2460 | 2498 | ||
2499 | if (kfd < 0 && ufd < 0) { | ||
2500 | print_both_open_warning(kfd, ufd); | ||
2501 | goto error; | ||
2502 | } | ||
2503 | |||
2461 | if (namelist == NULL && unamelist == NULL) | 2504 | if (namelist == NULL && unamelist == NULL) |
2462 | goto error; | 2505 | goto error; |
2463 | 2506 | ||
diff --git a/tools/perf/util/probe-event.h b/tools/perf/util/probe-event.h index 776c9347a3b6..e01e9943139f 100644 --- a/tools/perf/util/probe-event.h +++ b/tools/perf/util/probe-event.h | |||
@@ -128,7 +128,8 @@ extern int add_perf_probe_events(struct perf_probe_event *pevs, int npevs, | |||
128 | bool force_add); | 128 | bool force_add); |
129 | extern int del_perf_probe_events(struct strlist *dellist); | 129 | extern int del_perf_probe_events(struct strlist *dellist); |
130 | extern int show_perf_probe_events(void); | 130 | extern int show_perf_probe_events(void); |
131 | extern int show_line_range(struct line_range *lr, const char *module); | 131 | extern int show_line_range(struct line_range *lr, const char *module, |
132 | bool user); | ||
132 | extern int show_available_vars(struct perf_probe_event *pevs, int npevs, | 133 | extern int show_available_vars(struct perf_probe_event *pevs, int npevs, |
133 | int max_probe_points, const char *module, | 134 | int max_probe_points, const char *module, |
134 | struct strfilter *filter, bool externs); | 135 | struct strfilter *filter, bool externs); |
diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c index dca9145d704c..c7918f83b300 100644 --- a/tools/perf/util/probe-finder.c +++ b/tools/perf/util/probe-finder.c | |||
@@ -281,6 +281,7 @@ static int convert_variable_type(Dwarf_Die *vr_die, | |||
281 | struct probe_trace_arg_ref **ref_ptr = &tvar->ref; | 281 | struct probe_trace_arg_ref **ref_ptr = &tvar->ref; |
282 | Dwarf_Die type; | 282 | Dwarf_Die type; |
283 | char buf[16]; | 283 | char buf[16]; |
284 | char sbuf[STRERR_BUFSIZE]; | ||
284 | int bsize, boffs, total; | 285 | int bsize, boffs, total; |
285 | int ret; | 286 | int ret; |
286 | 287 | ||
@@ -367,7 +368,7 @@ formatted: | |||
367 | if (ret >= 16) | 368 | if (ret >= 16) |
368 | ret = -E2BIG; | 369 | ret = -E2BIG; |
369 | pr_warning("Failed to convert variable type: %s\n", | 370 | pr_warning("Failed to convert variable type: %s\n", |
370 | strerror(-ret)); | 371 | strerror_r(-ret, sbuf, sizeof(sbuf))); |
371 | return ret; | 372 | return ret; |
372 | } | 373 | } |
373 | tvar->type = strdup(buf); | 374 | tvar->type = strdup(buf); |
@@ -608,14 +609,18 @@ static int convert_to_trace_point(Dwarf_Die *sp_die, Dwfl_Module *mod, | |||
608 | return -EINVAL; | 609 | return -EINVAL; |
609 | } | 610 | } |
610 | 611 | ||
611 | /* Get an appropriate symbol from symtab */ | 612 | symbol = dwarf_diename(sp_die); |
612 | symbol = dwfl_module_addrsym(mod, paddr, &sym, NULL); | ||
613 | if (!symbol) { | 613 | if (!symbol) { |
614 | pr_warning("Failed to find symbol at 0x%lx\n", | 614 | /* Try to get the symbol name from symtab */ |
615 | (unsigned long)paddr); | 615 | symbol = dwfl_module_addrsym(mod, paddr, &sym, NULL); |
616 | return -ENOENT; | 616 | if (!symbol) { |
617 | pr_warning("Failed to find symbol at 0x%lx\n", | ||
618 | (unsigned long)paddr); | ||
619 | return -ENOENT; | ||
620 | } | ||
621 | eaddr = sym.st_value; | ||
617 | } | 622 | } |
618 | tp->offset = (unsigned long)(paddr - sym.st_value); | 623 | tp->offset = (unsigned long)(paddr - eaddr); |
619 | tp->address = (unsigned long)paddr; | 624 | tp->address = (unsigned long)paddr; |
620 | tp->symbol = strdup(symbol); | 625 | tp->symbol = strdup(symbol); |
621 | if (!tp->symbol) | 626 | if (!tp->symbol) |
@@ -779,10 +784,12 @@ static int find_lazy_match_lines(struct intlist *list, | |||
779 | size_t line_len; | 784 | size_t line_len; |
780 | ssize_t len; | 785 | ssize_t len; |
781 | int count = 0, linenum = 1; | 786 | int count = 0, linenum = 1; |
787 | char sbuf[STRERR_BUFSIZE]; | ||
782 | 788 | ||
783 | fp = fopen(fname, "r"); | 789 | fp = fopen(fname, "r"); |
784 | if (!fp) { | 790 | if (!fp) { |
785 | pr_warning("Failed to open %s: %s\n", fname, strerror(errno)); | 791 | pr_warning("Failed to open %s: %s\n", fname, |
792 | strerror_r(errno, sbuf, sizeof(sbuf))); | ||
786 | return -errno; | 793 | return -errno; |
787 | } | 794 | } |
788 | 795 | ||
diff --git a/tools/perf/util/python.c b/tools/perf/util/python.c index 12aa9b0d0ba1..3dda85ca50c1 100644 --- a/tools/perf/util/python.c +++ b/tools/perf/util/python.c | |||
@@ -736,7 +736,7 @@ static PyObject *pyrf_evlist__poll(struct pyrf_evlist *pevlist, | |||
736 | if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|i", kwlist, &timeout)) | 736 | if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|i", kwlist, &timeout)) |
737 | return NULL; | 737 | return NULL; |
738 | 738 | ||
739 | n = poll(evlist->pollfd, evlist->nr_fds, timeout); | 739 | n = perf_evlist__poll(evlist, timeout); |
740 | if (n < 0) { | 740 | if (n < 0) { |
741 | PyErr_SetFromErrno(PyExc_OSError); | 741 | PyErr_SetFromErrno(PyExc_OSError); |
742 | return NULL; | 742 | return NULL; |
@@ -753,9 +753,9 @@ static PyObject *pyrf_evlist__get_pollfd(struct pyrf_evlist *pevlist, | |||
753 | PyObject *list = PyList_New(0); | 753 | PyObject *list = PyList_New(0); |
754 | int i; | 754 | int i; |
755 | 755 | ||
756 | for (i = 0; i < evlist->nr_fds; ++i) { | 756 | for (i = 0; i < evlist->pollfd.nr; ++i) { |
757 | PyObject *file; | 757 | PyObject *file; |
758 | FILE *fp = fdopen(evlist->pollfd[i].fd, "r"); | 758 | FILE *fp = fdopen(evlist->pollfd.entries[i].fd, "r"); |
759 | 759 | ||
760 | if (fp == NULL) | 760 | if (fp == NULL) |
761 | goto free_list; | 761 | goto free_list; |
diff --git a/tools/perf/util/record.c b/tools/perf/util/record.c index fe8079edbdc1..cf69325b985f 100644 --- a/tools/perf/util/record.c +++ b/tools/perf/util/record.c | |||
@@ -14,6 +14,7 @@ static int perf_do_probe_api(setup_probe_fn_t fn, int cpu, const char *str) | |||
14 | struct perf_evsel *evsel; | 14 | struct perf_evsel *evsel; |
15 | unsigned long flags = perf_event_open_cloexec_flag(); | 15 | unsigned long flags = perf_event_open_cloexec_flag(); |
16 | int err = -EAGAIN, fd; | 16 | int err = -EAGAIN, fd; |
17 | static pid_t pid = -1; | ||
17 | 18 | ||
18 | evlist = perf_evlist__new(); | 19 | evlist = perf_evlist__new(); |
19 | if (!evlist) | 20 | if (!evlist) |
@@ -24,14 +25,22 @@ static int perf_do_probe_api(setup_probe_fn_t fn, int cpu, const char *str) | |||
24 | 25 | ||
25 | evsel = perf_evlist__first(evlist); | 26 | evsel = perf_evlist__first(evlist); |
26 | 27 | ||
27 | fd = sys_perf_event_open(&evsel->attr, -1, cpu, -1, flags); | 28 | while (1) { |
28 | if (fd < 0) | 29 | fd = sys_perf_event_open(&evsel->attr, pid, cpu, -1, flags); |
29 | goto out_delete; | 30 | if (fd < 0) { |
31 | if (pid == -1 && errno == EACCES) { | ||
32 | pid = 0; | ||
33 | continue; | ||
34 | } | ||
35 | goto out_delete; | ||
36 | } | ||
37 | break; | ||
38 | } | ||
30 | close(fd); | 39 | close(fd); |
31 | 40 | ||
32 | fn(evsel); | 41 | fn(evsel); |
33 | 42 | ||
34 | fd = sys_perf_event_open(&evsel->attr, -1, cpu, -1, flags); | 43 | fd = sys_perf_event_open(&evsel->attr, pid, cpu, -1, flags); |
35 | if (fd < 0) { | 44 | if (fd < 0) { |
36 | if (errno == EINVAL) | 45 | if (errno == EINVAL) |
37 | err = -EINVAL; | 46 | err = -EINVAL; |
@@ -47,7 +56,7 @@ out_delete: | |||
47 | 56 | ||
48 | static bool perf_probe_api(setup_probe_fn_t fn) | 57 | static bool perf_probe_api(setup_probe_fn_t fn) |
49 | { | 58 | { |
50 | const char *try[] = {"cycles:u", "instructions:u", "cpu-clock", NULL}; | 59 | const char *try[] = {"cycles:u", "instructions:u", "cpu-clock:u", NULL}; |
51 | struct cpu_map *cpus; | 60 | struct cpu_map *cpus; |
52 | int cpu, ret, i = 0; | 61 | int cpu, ret, i = 0; |
53 | 62 | ||
@@ -106,7 +115,7 @@ void perf_evlist__config(struct perf_evlist *evlist, struct record_opts *opts) | |||
106 | 115 | ||
107 | evlist__for_each(evlist, evsel) { | 116 | evlist__for_each(evlist, evsel) { |
108 | perf_evsel__config(evsel, opts); | 117 | perf_evsel__config(evsel, opts); |
109 | if (!evsel->idx && use_comm_exec) | 118 | if (evsel->tracking && use_comm_exec) |
110 | evsel->attr.comm_exec = 1; | 119 | evsel->attr.comm_exec = 1; |
111 | } | 120 | } |
112 | 121 | ||
@@ -201,6 +210,7 @@ bool perf_evlist__can_select_event(struct perf_evlist *evlist, const char *str) | |||
201 | struct perf_evsel *evsel; | 210 | struct perf_evsel *evsel; |
202 | int err, fd, cpu; | 211 | int err, fd, cpu; |
203 | bool ret = false; | 212 | bool ret = false; |
213 | pid_t pid = -1; | ||
204 | 214 | ||
205 | temp_evlist = perf_evlist__new(); | 215 | temp_evlist = perf_evlist__new(); |
206 | if (!temp_evlist) | 216 | if (!temp_evlist) |
@@ -221,12 +231,20 @@ bool perf_evlist__can_select_event(struct perf_evlist *evlist, const char *str) | |||
221 | cpu = evlist->cpus->map[0]; | 231 | cpu = evlist->cpus->map[0]; |
222 | } | 232 | } |
223 | 233 | ||
224 | fd = sys_perf_event_open(&evsel->attr, -1, cpu, -1, | 234 | while (1) { |
225 | perf_event_open_cloexec_flag()); | 235 | fd = sys_perf_event_open(&evsel->attr, pid, cpu, -1, |
226 | if (fd >= 0) { | 236 | perf_event_open_cloexec_flag()); |
227 | close(fd); | 237 | if (fd < 0) { |
228 | ret = true; | 238 | if (pid == -1 && errno == EACCES) { |
239 | pid = 0; | ||
240 | continue; | ||
241 | } | ||
242 | goto out_delete; | ||
243 | } | ||
244 | break; | ||
229 | } | 245 | } |
246 | close(fd); | ||
247 | ret = true; | ||
230 | 248 | ||
231 | out_delete: | 249 | out_delete: |
232 | perf_evlist__delete(temp_evlist); | 250 | perf_evlist__delete(temp_evlist); |
diff --git a/tools/perf/util/run-command.c b/tools/perf/util/run-command.c index da8e9b285f51..34622b53e733 100644 --- a/tools/perf/util/run-command.c +++ b/tools/perf/util/run-command.c | |||
@@ -1,6 +1,7 @@ | |||
1 | #include "cache.h" | 1 | #include "cache.h" |
2 | #include "run-command.h" | 2 | #include "run-command.h" |
3 | #include "exec_cmd.h" | 3 | #include "exec_cmd.h" |
4 | #include "debug.h" | ||
4 | 5 | ||
5 | static inline void close_pair(int fd[2]) | 6 | static inline void close_pair(int fd[2]) |
6 | { | 7 | { |
@@ -19,6 +20,7 @@ int start_command(struct child_process *cmd) | |||
19 | { | 20 | { |
20 | int need_in, need_out, need_err; | 21 | int need_in, need_out, need_err; |
21 | int fdin[2], fdout[2], fderr[2]; | 22 | int fdin[2], fdout[2], fderr[2]; |
23 | char sbuf[STRERR_BUFSIZE]; | ||
22 | 24 | ||
23 | /* | 25 | /* |
24 | * In case of errors we must keep the promise to close FDs | 26 | * In case of errors we must keep the promise to close FDs |
@@ -99,7 +101,7 @@ int start_command(struct child_process *cmd) | |||
99 | 101 | ||
100 | if (cmd->dir && chdir(cmd->dir)) | 102 | if (cmd->dir && chdir(cmd->dir)) |
101 | die("exec %s: cd to %s failed (%s)", cmd->argv[0], | 103 | die("exec %s: cd to %s failed (%s)", cmd->argv[0], |
102 | cmd->dir, strerror(errno)); | 104 | cmd->dir, strerror_r(errno, sbuf, sizeof(sbuf))); |
103 | if (cmd->env) { | 105 | if (cmd->env) { |
104 | for (; *cmd->env; cmd->env++) { | 106 | for (; *cmd->env; cmd->env++) { |
105 | if (strchr(*cmd->env, '=')) | 107 | if (strchr(*cmd->env, '=')) |
@@ -153,6 +155,8 @@ int start_command(struct child_process *cmd) | |||
153 | 155 | ||
154 | static int wait_or_whine(pid_t pid) | 156 | static int wait_or_whine(pid_t pid) |
155 | { | 157 | { |
158 | char sbuf[STRERR_BUFSIZE]; | ||
159 | |||
156 | for (;;) { | 160 | for (;;) { |
157 | int status, code; | 161 | int status, code; |
158 | pid_t waiting = waitpid(pid, &status, 0); | 162 | pid_t waiting = waitpid(pid, &status, 0); |
@@ -160,7 +164,8 @@ static int wait_or_whine(pid_t pid) | |||
160 | if (waiting < 0) { | 164 | if (waiting < 0) { |
161 | if (errno == EINTR) | 165 | if (errno == EINTR) |
162 | continue; | 166 | continue; |
163 | error("waitpid failed (%s)", strerror(errno)); | 167 | error("waitpid failed (%s)", |
168 | strerror_r(errno, sbuf, sizeof(sbuf))); | ||
164 | return -ERR_RUN_COMMAND_WAITPID; | 169 | return -ERR_RUN_COMMAND_WAITPID; |
165 | } | 170 | } |
166 | if (waiting != pid) | 171 | if (waiting != pid) |
diff --git a/tools/perf/util/scripting-engines/trace-event-perl.c b/tools/perf/util/scripting-engines/trace-event-perl.c index b2dba9c0a3a1..0a01bac4ce02 100644 --- a/tools/perf/util/scripting-engines/trace-event-perl.c +++ b/tools/perf/util/scripting-engines/trace-event-perl.c | |||
@@ -432,6 +432,11 @@ error: | |||
432 | return err; | 432 | return err; |
433 | } | 433 | } |
434 | 434 | ||
435 | static int perl_flush_script(void) | ||
436 | { | ||
437 | return 0; | ||
438 | } | ||
439 | |||
435 | /* | 440 | /* |
436 | * Stop trace script | 441 | * Stop trace script |
437 | */ | 442 | */ |
@@ -633,6 +638,7 @@ static int perl_generate_script(struct pevent *pevent, const char *outfile) | |||
633 | struct scripting_ops perl_scripting_ops = { | 638 | struct scripting_ops perl_scripting_ops = { |
634 | .name = "Perl", | 639 | .name = "Perl", |
635 | .start_script = perl_start_script, | 640 | .start_script = perl_start_script, |
641 | .flush_script = perl_flush_script, | ||
636 | .stop_script = perl_stop_script, | 642 | .stop_script = perl_stop_script, |
637 | .process_event = perl_process_event, | 643 | .process_event = perl_process_event, |
638 | .generate_script = perl_generate_script, | 644 | .generate_script = perl_generate_script, |
diff --git a/tools/perf/util/scripting-engines/trace-event-python.c b/tools/perf/util/scripting-engines/trace-event-python.c index cbce2545da45..56ba07cce549 100644 --- a/tools/perf/util/scripting-engines/trace-event-python.c +++ b/tools/perf/util/scripting-engines/trace-event-python.c | |||
@@ -73,6 +73,35 @@ static void pydict_set_item_string_decref(PyObject *dict, const char *key, PyObj | |||
73 | Py_DECREF(val); | 73 | Py_DECREF(val); |
74 | } | 74 | } |
75 | 75 | ||
76 | static PyObject *get_handler(const char *handler_name) | ||
77 | { | ||
78 | PyObject *handler; | ||
79 | |||
80 | handler = PyDict_GetItemString(main_dict, handler_name); | ||
81 | if (handler && !PyCallable_Check(handler)) | ||
82 | return NULL; | ||
83 | return handler; | ||
84 | } | ||
85 | |||
86 | static void call_object(PyObject *handler, PyObject *args, const char *die_msg) | ||
87 | { | ||
88 | PyObject *retval; | ||
89 | |||
90 | retval = PyObject_CallObject(handler, args); | ||
91 | if (retval == NULL) | ||
92 | handler_call_die(die_msg); | ||
93 | Py_DECREF(retval); | ||
94 | } | ||
95 | |||
96 | static void try_call_object(const char *handler_name, PyObject *args) | ||
97 | { | ||
98 | PyObject *handler; | ||
99 | |||
100 | handler = get_handler(handler_name); | ||
101 | if (handler) | ||
102 | call_object(handler, args, handler_name); | ||
103 | } | ||
104 | |||
76 | static void define_value(enum print_arg_type field_type, | 105 | static void define_value(enum print_arg_type field_type, |
77 | const char *ev_name, | 106 | const char *ev_name, |
78 | const char *field_name, | 107 | const char *field_name, |
@@ -80,7 +109,7 @@ static void define_value(enum print_arg_type field_type, | |||
80 | const char *field_str) | 109 | const char *field_str) |
81 | { | 110 | { |
82 | const char *handler_name = "define_flag_value"; | 111 | const char *handler_name = "define_flag_value"; |
83 | PyObject *handler, *t, *retval; | 112 | PyObject *t; |
84 | unsigned long long value; | 113 | unsigned long long value; |
85 | unsigned n = 0; | 114 | unsigned n = 0; |
86 | 115 | ||
@@ -98,13 +127,7 @@ static void define_value(enum print_arg_type field_type, | |||
98 | PyTuple_SetItem(t, n++, PyInt_FromLong(value)); | 127 | PyTuple_SetItem(t, n++, PyInt_FromLong(value)); |
99 | PyTuple_SetItem(t, n++, PyString_FromString(field_str)); | 128 | PyTuple_SetItem(t, n++, PyString_FromString(field_str)); |
100 | 129 | ||
101 | handler = PyDict_GetItemString(main_dict, handler_name); | 130 | try_call_object(handler_name, t); |
102 | if (handler && PyCallable_Check(handler)) { | ||
103 | retval = PyObject_CallObject(handler, t); | ||
104 | if (retval == NULL) | ||
105 | handler_call_die(handler_name); | ||
106 | Py_DECREF(retval); | ||
107 | } | ||
108 | 131 | ||
109 | Py_DECREF(t); | 132 | Py_DECREF(t); |
110 | } | 133 | } |
@@ -127,7 +150,7 @@ static void define_field(enum print_arg_type field_type, | |||
127 | const char *delim) | 150 | const char *delim) |
128 | { | 151 | { |
129 | const char *handler_name = "define_flag_field"; | 152 | const char *handler_name = "define_flag_field"; |
130 | PyObject *handler, *t, *retval; | 153 | PyObject *t; |
131 | unsigned n = 0; | 154 | unsigned n = 0; |
132 | 155 | ||
133 | if (field_type == PRINT_SYMBOL) | 156 | if (field_type == PRINT_SYMBOL) |
@@ -145,13 +168,7 @@ static void define_field(enum print_arg_type field_type, | |||
145 | if (field_type == PRINT_FLAGS) | 168 | if (field_type == PRINT_FLAGS) |
146 | PyTuple_SetItem(t, n++, PyString_FromString(delim)); | 169 | PyTuple_SetItem(t, n++, PyString_FromString(delim)); |
147 | 170 | ||
148 | handler = PyDict_GetItemString(main_dict, handler_name); | 171 | try_call_object(handler_name, t); |
149 | if (handler && PyCallable_Check(handler)) { | ||
150 | retval = PyObject_CallObject(handler, t); | ||
151 | if (retval == NULL) | ||
152 | handler_call_die(handler_name); | ||
153 | Py_DECREF(retval); | ||
154 | } | ||
155 | 172 | ||
156 | Py_DECREF(t); | 173 | Py_DECREF(t); |
157 | } | 174 | } |
@@ -362,7 +379,7 @@ static void python_process_tracepoint(struct perf_sample *sample, | |||
362 | struct thread *thread, | 379 | struct thread *thread, |
363 | struct addr_location *al) | 380 | struct addr_location *al) |
364 | { | 381 | { |
365 | PyObject *handler, *retval, *context, *t, *obj, *callchain; | 382 | PyObject *handler, *context, *t, *obj, *callchain; |
366 | PyObject *dict = NULL; | 383 | PyObject *dict = NULL; |
367 | static char handler_name[256]; | 384 | static char handler_name[256]; |
368 | struct format_field *field; | 385 | struct format_field *field; |
@@ -387,9 +404,7 @@ static void python_process_tracepoint(struct perf_sample *sample, | |||
387 | 404 | ||
388 | sprintf(handler_name, "%s__%s", event->system, event->name); | 405 | sprintf(handler_name, "%s__%s", event->system, event->name); |
389 | 406 | ||
390 | handler = PyDict_GetItemString(main_dict, handler_name); | 407 | handler = get_handler(handler_name); |
391 | if (handler && !PyCallable_Check(handler)) | ||
392 | handler = NULL; | ||
393 | if (!handler) { | 408 | if (!handler) { |
394 | dict = PyDict_New(); | 409 | dict = PyDict_New(); |
395 | if (!dict) | 410 | if (!dict) |
@@ -450,19 +465,9 @@ static void python_process_tracepoint(struct perf_sample *sample, | |||
450 | Py_FatalError("error resizing Python tuple"); | 465 | Py_FatalError("error resizing Python tuple"); |
451 | 466 | ||
452 | if (handler) { | 467 | if (handler) { |
453 | retval = PyObject_CallObject(handler, t); | 468 | call_object(handler, t, handler_name); |
454 | if (retval == NULL) | ||
455 | handler_call_die(handler_name); | ||
456 | Py_DECREF(retval); | ||
457 | } else { | 469 | } else { |
458 | handler = PyDict_GetItemString(main_dict, "trace_unhandled"); | 470 | try_call_object("trace_unhandled", t); |
459 | if (handler && PyCallable_Check(handler)) { | ||
460 | |||
461 | retval = PyObject_CallObject(handler, t); | ||
462 | if (retval == NULL) | ||
463 | handler_call_die("trace_unhandled"); | ||
464 | Py_DECREF(retval); | ||
465 | } | ||
466 | Py_DECREF(dict); | 471 | Py_DECREF(dict); |
467 | } | 472 | } |
468 | 473 | ||
@@ -474,7 +479,7 @@ static void python_process_general_event(struct perf_sample *sample, | |||
474 | struct thread *thread, | 479 | struct thread *thread, |
475 | struct addr_location *al) | 480 | struct addr_location *al) |
476 | { | 481 | { |
477 | PyObject *handler, *retval, *t, *dict, *callchain, *dict_sample; | 482 | PyObject *handler, *t, *dict, *callchain, *dict_sample; |
478 | static char handler_name[64]; | 483 | static char handler_name[64]; |
479 | unsigned n = 0; | 484 | unsigned n = 0; |
480 | 485 | ||
@@ -496,8 +501,8 @@ static void python_process_general_event(struct perf_sample *sample, | |||
496 | 501 | ||
497 | snprintf(handler_name, sizeof(handler_name), "%s", "process_event"); | 502 | snprintf(handler_name, sizeof(handler_name), "%s", "process_event"); |
498 | 503 | ||
499 | handler = PyDict_GetItemString(main_dict, handler_name); | 504 | handler = get_handler(handler_name); |
500 | if (!handler || !PyCallable_Check(handler)) | 505 | if (!handler) |
501 | goto exit; | 506 | goto exit; |
502 | 507 | ||
503 | pydict_set_item_string_decref(dict, "ev_name", PyString_FromString(perf_evsel__name(evsel))); | 508 | pydict_set_item_string_decref(dict, "ev_name", PyString_FromString(perf_evsel__name(evsel))); |
@@ -539,10 +544,7 @@ static void python_process_general_event(struct perf_sample *sample, | |||
539 | if (_PyTuple_Resize(&t, n) == -1) | 544 | if (_PyTuple_Resize(&t, n) == -1) |
540 | Py_FatalError("error resizing Python tuple"); | 545 | Py_FatalError("error resizing Python tuple"); |
541 | 546 | ||
542 | retval = PyObject_CallObject(handler, t); | 547 | call_object(handler, t, handler_name); |
543 | if (retval == NULL) | ||
544 | handler_call_die(handler_name); | ||
545 | Py_DECREF(retval); | ||
546 | exit: | 548 | exit: |
547 | Py_DECREF(dict); | 549 | Py_DECREF(dict); |
548 | Py_DECREF(t); | 550 | Py_DECREF(t); |
@@ -566,36 +568,24 @@ static void python_process_event(union perf_event *event __maybe_unused, | |||
566 | 568 | ||
567 | static int run_start_sub(void) | 569 | static int run_start_sub(void) |
568 | { | 570 | { |
569 | PyObject *handler, *retval; | ||
570 | int err = 0; | ||
571 | |||
572 | main_module = PyImport_AddModule("__main__"); | 571 | main_module = PyImport_AddModule("__main__"); |
573 | if (main_module == NULL) | 572 | if (main_module == NULL) |
574 | return -1; | 573 | return -1; |
575 | Py_INCREF(main_module); | 574 | Py_INCREF(main_module); |
576 | 575 | ||
577 | main_dict = PyModule_GetDict(main_module); | 576 | main_dict = PyModule_GetDict(main_module); |
578 | if (main_dict == NULL) { | 577 | if (main_dict == NULL) |
579 | err = -1; | ||
580 | goto error; | 578 | goto error; |
581 | } | ||
582 | Py_INCREF(main_dict); | 579 | Py_INCREF(main_dict); |
583 | 580 | ||
584 | handler = PyDict_GetItemString(main_dict, "trace_begin"); | 581 | try_call_object("trace_begin", NULL); |
585 | if (handler == NULL || !PyCallable_Check(handler)) | ||
586 | goto out; | ||
587 | 582 | ||
588 | retval = PyObject_CallObject(handler, NULL); | 583 | return 0; |
589 | if (retval == NULL) | ||
590 | handler_call_die("trace_begin"); | ||
591 | 584 | ||
592 | Py_DECREF(retval); | ||
593 | return err; | ||
594 | error: | 585 | error: |
595 | Py_XDECREF(main_dict); | 586 | Py_XDECREF(main_dict); |
596 | Py_XDECREF(main_module); | 587 | Py_XDECREF(main_module); |
597 | out: | 588 | return -1; |
598 | return err; | ||
599 | } | 589 | } |
600 | 590 | ||
601 | /* | 591 | /* |
@@ -649,28 +639,23 @@ error: | |||
649 | return err; | 639 | return err; |
650 | } | 640 | } |
651 | 641 | ||
642 | static int python_flush_script(void) | ||
643 | { | ||
644 | return 0; | ||
645 | } | ||
646 | |||
652 | /* | 647 | /* |
653 | * Stop trace script | 648 | * Stop trace script |
654 | */ | 649 | */ |
655 | static int python_stop_script(void) | 650 | static int python_stop_script(void) |
656 | { | 651 | { |
657 | PyObject *handler, *retval; | 652 | try_call_object("trace_end", NULL); |
658 | int err = 0; | ||
659 | 653 | ||
660 | handler = PyDict_GetItemString(main_dict, "trace_end"); | ||
661 | if (handler == NULL || !PyCallable_Check(handler)) | ||
662 | goto out; | ||
663 | |||
664 | retval = PyObject_CallObject(handler, NULL); | ||
665 | if (retval == NULL) | ||
666 | handler_call_die("trace_end"); | ||
667 | Py_DECREF(retval); | ||
668 | out: | ||
669 | Py_XDECREF(main_dict); | 654 | Py_XDECREF(main_dict); |
670 | Py_XDECREF(main_module); | 655 | Py_XDECREF(main_module); |
671 | Py_Finalize(); | 656 | Py_Finalize(); |
672 | 657 | ||
673 | return err; | 658 | return 0; |
674 | } | 659 | } |
675 | 660 | ||
676 | static int python_generate_script(struct pevent *pevent, const char *outfile) | 661 | static int python_generate_script(struct pevent *pevent, const char *outfile) |
@@ -843,6 +828,7 @@ static int python_generate_script(struct pevent *pevent, const char *outfile) | |||
843 | struct scripting_ops python_scripting_ops = { | 828 | struct scripting_ops python_scripting_ops = { |
844 | .name = "Python", | 829 | .name = "Python", |
845 | .start_script = python_start_script, | 830 | .start_script = python_start_script, |
831 | .flush_script = python_flush_script, | ||
846 | .stop_script = python_stop_script, | 832 | .stop_script = python_stop_script, |
847 | .process_event = python_process_event, | 833 | .process_event = python_process_event, |
848 | .generate_script = python_generate_script, | 834 | .generate_script = python_generate_script, |
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index 88dfef70c13d..883406f4b381 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c | |||
@@ -14,6 +14,7 @@ | |||
14 | #include "util.h" | 14 | #include "util.h" |
15 | #include "cpumap.h" | 15 | #include "cpumap.h" |
16 | #include "perf_regs.h" | 16 | #include "perf_regs.h" |
17 | #include "asm/bug.h" | ||
17 | 18 | ||
18 | static int perf_session__open(struct perf_session *session) | 19 | static int perf_session__open(struct perf_session *session) |
19 | { | 20 | { |
@@ -66,6 +67,25 @@ static void perf_session__destroy_kernel_maps(struct perf_session *session) | |||
66 | machines__destroy_kernel_maps(&session->machines); | 67 | machines__destroy_kernel_maps(&session->machines); |
67 | } | 68 | } |
68 | 69 | ||
70 | static bool perf_session__has_comm_exec(struct perf_session *session) | ||
71 | { | ||
72 | struct perf_evsel *evsel; | ||
73 | |||
74 | evlist__for_each(session->evlist, evsel) { | ||
75 | if (evsel->attr.comm_exec) | ||
76 | return true; | ||
77 | } | ||
78 | |||
79 | return false; | ||
80 | } | ||
81 | |||
82 | static void perf_session__set_comm_exec(struct perf_session *session) | ||
83 | { | ||
84 | bool comm_exec = perf_session__has_comm_exec(session); | ||
85 | |||
86 | machines__set_comm_exec(&session->machines, comm_exec); | ||
87 | } | ||
88 | |||
69 | struct perf_session *perf_session__new(struct perf_data_file *file, | 89 | struct perf_session *perf_session__new(struct perf_data_file *file, |
70 | bool repipe, struct perf_tool *tool) | 90 | bool repipe, struct perf_tool *tool) |
71 | { | 91 | { |
@@ -75,9 +95,7 @@ struct perf_session *perf_session__new(struct perf_data_file *file, | |||
75 | goto out; | 95 | goto out; |
76 | 96 | ||
77 | session->repipe = repipe; | 97 | session->repipe = repipe; |
78 | INIT_LIST_HEAD(&session->ordered_samples.samples); | 98 | ordered_events__init(&session->ordered_events); |
79 | INIT_LIST_HEAD(&session->ordered_samples.sample_cache); | ||
80 | INIT_LIST_HEAD(&session->ordered_samples.to_free); | ||
81 | machines__init(&session->machines); | 99 | machines__init(&session->machines); |
82 | 100 | ||
83 | if (file) { | 101 | if (file) { |
@@ -91,6 +109,7 @@ struct perf_session *perf_session__new(struct perf_data_file *file, | |||
91 | goto out_close; | 109 | goto out_close; |
92 | 110 | ||
93 | perf_session__set_id_hdr_size(session); | 111 | perf_session__set_id_hdr_size(session); |
112 | perf_session__set_comm_exec(session); | ||
94 | } | 113 | } |
95 | } | 114 | } |
96 | 115 | ||
@@ -100,13 +119,13 @@ struct perf_session *perf_session__new(struct perf_data_file *file, | |||
100 | * kernel MMAP event, in perf_event__process_mmap(). | 119 | * kernel MMAP event, in perf_event__process_mmap(). |
101 | */ | 120 | */ |
102 | if (perf_session__create_kernel_maps(session) < 0) | 121 | if (perf_session__create_kernel_maps(session) < 0) |
103 | goto out_delete; | 122 | pr_warning("Cannot read kernel map\n"); |
104 | } | 123 | } |
105 | 124 | ||
106 | if (tool && tool->ordering_requires_timestamps && | 125 | if (tool && tool->ordering_requires_timestamps && |
107 | tool->ordered_samples && !perf_evlist__sample_id_all(session->evlist)) { | 126 | tool->ordered_events && !perf_evlist__sample_id_all(session->evlist)) { |
108 | dump_printf("WARNING: No sample_id_all support, falling back to unordered processing\n"); | 127 | dump_printf("WARNING: No sample_id_all support, falling back to unordered processing\n"); |
109 | tool->ordered_samples = false; | 128 | tool->ordered_events = false; |
110 | } | 129 | } |
111 | 130 | ||
112 | return session; | 131 | return session; |
@@ -238,7 +257,7 @@ void perf_tool__fill_defaults(struct perf_tool *tool) | |||
238 | if (tool->build_id == NULL) | 257 | if (tool->build_id == NULL) |
239 | tool->build_id = process_finished_round_stub; | 258 | tool->build_id = process_finished_round_stub; |
240 | if (tool->finished_round == NULL) { | 259 | if (tool->finished_round == NULL) { |
241 | if (tool->ordered_samples) | 260 | if (tool->ordered_events) |
242 | tool->finished_round = process_finished_round; | 261 | tool->finished_round = process_finished_round; |
243 | else | 262 | else |
244 | tool->finished_round = process_finished_round_stub; | 263 | tool->finished_round = process_finished_round_stub; |
@@ -444,87 +463,6 @@ static perf_event__swap_op perf_event__swap_ops[] = { | |||
444 | [PERF_RECORD_HEADER_MAX] = NULL, | 463 | [PERF_RECORD_HEADER_MAX] = NULL, |
445 | }; | 464 | }; |
446 | 465 | ||
447 | struct sample_queue { | ||
448 | u64 timestamp; | ||
449 | u64 file_offset; | ||
450 | union perf_event *event; | ||
451 | struct list_head list; | ||
452 | }; | ||
453 | |||
454 | static void perf_session_free_sample_buffers(struct perf_session *session) | ||
455 | { | ||
456 | struct ordered_samples *os = &session->ordered_samples; | ||
457 | |||
458 | while (!list_empty(&os->to_free)) { | ||
459 | struct sample_queue *sq; | ||
460 | |||
461 | sq = list_entry(os->to_free.next, struct sample_queue, list); | ||
462 | list_del(&sq->list); | ||
463 | free(sq); | ||
464 | } | ||
465 | } | ||
466 | |||
467 | static int perf_session_deliver_event(struct perf_session *session, | ||
468 | union perf_event *event, | ||
469 | struct perf_sample *sample, | ||
470 | struct perf_tool *tool, | ||
471 | u64 file_offset); | ||
472 | |||
473 | static int flush_sample_queue(struct perf_session *s, | ||
474 | struct perf_tool *tool) | ||
475 | { | ||
476 | struct ordered_samples *os = &s->ordered_samples; | ||
477 | struct list_head *head = &os->samples; | ||
478 | struct sample_queue *tmp, *iter; | ||
479 | struct perf_sample sample; | ||
480 | u64 limit = os->next_flush; | ||
481 | u64 last_ts = os->last_sample ? os->last_sample->timestamp : 0ULL; | ||
482 | bool show_progress = limit == ULLONG_MAX; | ||
483 | struct ui_progress prog; | ||
484 | int ret; | ||
485 | |||
486 | if (!tool->ordered_samples || !limit) | ||
487 | return 0; | ||
488 | |||
489 | if (show_progress) | ||
490 | ui_progress__init(&prog, os->nr_samples, "Processing time ordered events..."); | ||
491 | |||
492 | list_for_each_entry_safe(iter, tmp, head, list) { | ||
493 | if (session_done()) | ||
494 | return 0; | ||
495 | |||
496 | if (iter->timestamp > limit) | ||
497 | break; | ||
498 | |||
499 | ret = perf_evlist__parse_sample(s->evlist, iter->event, &sample); | ||
500 | if (ret) | ||
501 | pr_err("Can't parse sample, err = %d\n", ret); | ||
502 | else { | ||
503 | ret = perf_session_deliver_event(s, iter->event, &sample, tool, | ||
504 | iter->file_offset); | ||
505 | if (ret) | ||
506 | return ret; | ||
507 | } | ||
508 | |||
509 | os->last_flush = iter->timestamp; | ||
510 | list_del(&iter->list); | ||
511 | list_add(&iter->list, &os->sample_cache); | ||
512 | os->nr_samples--; | ||
513 | |||
514 | if (show_progress) | ||
515 | ui_progress__update(&prog, 1); | ||
516 | } | ||
517 | |||
518 | if (list_empty(head)) { | ||
519 | os->last_sample = NULL; | ||
520 | } else if (last_ts <= limit) { | ||
521 | os->last_sample = | ||
522 | list_entry(head->prev, struct sample_queue, list); | ||
523 | } | ||
524 | |||
525 | return 0; | ||
526 | } | ||
527 | |||
528 | /* | 466 | /* |
529 | * When perf record finishes a pass on every buffers, it records this pseudo | 467 | * When perf record finishes a pass on every buffers, it records this pseudo |
530 | * event. | 468 | * event. |
@@ -568,99 +506,43 @@ static int process_finished_round(struct perf_tool *tool, | |||
568 | union perf_event *event __maybe_unused, | 506 | union perf_event *event __maybe_unused, |
569 | struct perf_session *session) | 507 | struct perf_session *session) |
570 | { | 508 | { |
571 | int ret = flush_sample_queue(session, tool); | 509 | return ordered_events__flush(session, tool, OE_FLUSH__ROUND); |
572 | if (!ret) | ||
573 | session->ordered_samples.next_flush = session->ordered_samples.max_timestamp; | ||
574 | |||
575 | return ret; | ||
576 | } | ||
577 | |||
578 | /* The queue is ordered by time */ | ||
579 | static void __queue_event(struct sample_queue *new, struct perf_session *s) | ||
580 | { | ||
581 | struct ordered_samples *os = &s->ordered_samples; | ||
582 | struct sample_queue *sample = os->last_sample; | ||
583 | u64 timestamp = new->timestamp; | ||
584 | struct list_head *p; | ||
585 | |||
586 | ++os->nr_samples; | ||
587 | os->last_sample = new; | ||
588 | |||
589 | if (!sample) { | ||
590 | list_add(&new->list, &os->samples); | ||
591 | os->max_timestamp = timestamp; | ||
592 | return; | ||
593 | } | ||
594 | |||
595 | /* | ||
596 | * last_sample might point to some random place in the list as it's | ||
597 | * the last queued event. We expect that the new event is close to | ||
598 | * this. | ||
599 | */ | ||
600 | if (sample->timestamp <= timestamp) { | ||
601 | while (sample->timestamp <= timestamp) { | ||
602 | p = sample->list.next; | ||
603 | if (p == &os->samples) { | ||
604 | list_add_tail(&new->list, &os->samples); | ||
605 | os->max_timestamp = timestamp; | ||
606 | return; | ||
607 | } | ||
608 | sample = list_entry(p, struct sample_queue, list); | ||
609 | } | ||
610 | list_add_tail(&new->list, &sample->list); | ||
611 | } else { | ||
612 | while (sample->timestamp > timestamp) { | ||
613 | p = sample->list.prev; | ||
614 | if (p == &os->samples) { | ||
615 | list_add(&new->list, &os->samples); | ||
616 | return; | ||
617 | } | ||
618 | sample = list_entry(p, struct sample_queue, list); | ||
619 | } | ||
620 | list_add(&new->list, &sample->list); | ||
621 | } | ||
622 | } | 510 | } |
623 | 511 | ||
624 | #define MAX_SAMPLE_BUFFER (64 * 1024 / sizeof(struct sample_queue)) | ||
625 | |||
626 | int perf_session_queue_event(struct perf_session *s, union perf_event *event, | 512 | int perf_session_queue_event(struct perf_session *s, union perf_event *event, |
627 | struct perf_sample *sample, u64 file_offset) | 513 | struct perf_tool *tool, struct perf_sample *sample, |
514 | u64 file_offset) | ||
628 | { | 515 | { |
629 | struct ordered_samples *os = &s->ordered_samples; | 516 | struct ordered_events *oe = &s->ordered_events; |
630 | struct list_head *sc = &os->sample_cache; | ||
631 | u64 timestamp = sample->time; | 517 | u64 timestamp = sample->time; |
632 | struct sample_queue *new; | 518 | struct ordered_event *new; |
633 | 519 | ||
634 | if (!timestamp || timestamp == ~0ULL) | 520 | if (!timestamp || timestamp == ~0ULL) |
635 | return -ETIME; | 521 | return -ETIME; |
636 | 522 | ||
637 | if (timestamp < s->ordered_samples.last_flush) { | 523 | if (timestamp < oe->last_flush) { |
638 | printf("Warning: Timestamp below last timeslice flush\n"); | 524 | WARN_ONCE(1, "Timestamp below last timeslice flush\n"); |
639 | return -EINVAL; | 525 | |
526 | pr_oe_time(timestamp, "out of order event"); | ||
527 | pr_oe_time(oe->last_flush, "last flush, last_flush_type %d\n", | ||
528 | oe->last_flush_type); | ||
529 | |||
530 | /* We could get out of order messages after forced flush. */ | ||
531 | if (oe->last_flush_type != OE_FLUSH__HALF) | ||
532 | return -EINVAL; | ||
640 | } | 533 | } |
641 | 534 | ||
642 | if (!list_empty(sc)) { | 535 | new = ordered_events__new(oe, timestamp); |
643 | new = list_entry(sc->next, struct sample_queue, list); | 536 | if (!new) { |
644 | list_del(&new->list); | 537 | ordered_events__flush(s, tool, OE_FLUSH__HALF); |
645 | } else if (os->sample_buffer) { | 538 | new = ordered_events__new(oe, timestamp); |
646 | new = os->sample_buffer + os->sample_buffer_idx; | ||
647 | if (++os->sample_buffer_idx == MAX_SAMPLE_BUFFER) | ||
648 | os->sample_buffer = NULL; | ||
649 | } else { | ||
650 | os->sample_buffer = malloc(MAX_SAMPLE_BUFFER * sizeof(*new)); | ||
651 | if (!os->sample_buffer) | ||
652 | return -ENOMEM; | ||
653 | list_add(&os->sample_buffer->list, &os->to_free); | ||
654 | os->sample_buffer_idx = 2; | ||
655 | new = os->sample_buffer + 1; | ||
656 | } | 539 | } |
657 | 540 | ||
658 | new->timestamp = timestamp; | 541 | if (!new) |
542 | return -ENOMEM; | ||
543 | |||
659 | new->file_offset = file_offset; | 544 | new->file_offset = file_offset; |
660 | new->event = event; | 545 | new->event = event; |
661 | |||
662 | __queue_event(new, s); | ||
663 | |||
664 | return 0; | 546 | return 0; |
665 | } | 547 | } |
666 | 548 | ||
@@ -920,11 +802,10 @@ perf_session__deliver_sample(struct perf_session *session, | |||
920 | &sample->read.one, machine); | 802 | &sample->read.one, machine); |
921 | } | 803 | } |
922 | 804 | ||
923 | static int perf_session_deliver_event(struct perf_session *session, | 805 | int perf_session__deliver_event(struct perf_session *session, |
924 | union perf_event *event, | 806 | union perf_event *event, |
925 | struct perf_sample *sample, | 807 | struct perf_sample *sample, |
926 | struct perf_tool *tool, | 808 | struct perf_tool *tool, u64 file_offset) |
927 | u64 file_offset) | ||
928 | { | 809 | { |
929 | struct perf_evsel *evsel; | 810 | struct perf_evsel *evsel; |
930 | struct machine *machine; | 811 | struct machine *machine; |
@@ -1005,8 +886,10 @@ static s64 perf_session__process_user_event(struct perf_session *session, | |||
1005 | switch (event->header.type) { | 886 | switch (event->header.type) { |
1006 | case PERF_RECORD_HEADER_ATTR: | 887 | case PERF_RECORD_HEADER_ATTR: |
1007 | err = tool->attr(tool, event, &session->evlist); | 888 | err = tool->attr(tool, event, &session->evlist); |
1008 | if (err == 0) | 889 | if (err == 0) { |
1009 | perf_session__set_id_hdr_size(session); | 890 | perf_session__set_id_hdr_size(session); |
891 | perf_session__set_comm_exec(session); | ||
892 | } | ||
1010 | return err; | 893 | return err; |
1011 | case PERF_RECORD_HEADER_EVENT_TYPE: | 894 | case PERF_RECORD_HEADER_EVENT_TYPE: |
1012 | /* | 895 | /* |
@@ -1036,6 +919,61 @@ static void event_swap(union perf_event *event, bool sample_id_all) | |||
1036 | swap(event, sample_id_all); | 919 | swap(event, sample_id_all); |
1037 | } | 920 | } |
1038 | 921 | ||
922 | int perf_session__peek_event(struct perf_session *session, off_t file_offset, | ||
923 | void *buf, size_t buf_sz, | ||
924 | union perf_event **event_ptr, | ||
925 | struct perf_sample *sample) | ||
926 | { | ||
927 | union perf_event *event; | ||
928 | size_t hdr_sz, rest; | ||
929 | int fd; | ||
930 | |||
931 | if (session->one_mmap && !session->header.needs_swap) { | ||
932 | event = file_offset - session->one_mmap_offset + | ||
933 | session->one_mmap_addr; | ||
934 | goto out_parse_sample; | ||
935 | } | ||
936 | |||
937 | if (perf_data_file__is_pipe(session->file)) | ||
938 | return -1; | ||
939 | |||
940 | fd = perf_data_file__fd(session->file); | ||
941 | hdr_sz = sizeof(struct perf_event_header); | ||
942 | |||
943 | if (buf_sz < hdr_sz) | ||
944 | return -1; | ||
945 | |||
946 | if (lseek(fd, file_offset, SEEK_SET) == (off_t)-1 || | ||
947 | readn(fd, &buf, hdr_sz) != (ssize_t)hdr_sz) | ||
948 | return -1; | ||
949 | |||
950 | event = (union perf_event *)buf; | ||
951 | |||
952 | if (session->header.needs_swap) | ||
953 | perf_event_header__bswap(&event->header); | ||
954 | |||
955 | if (event->header.size < hdr_sz) | ||
956 | return -1; | ||
957 | |||
958 | rest = event->header.size - hdr_sz; | ||
959 | |||
960 | if (readn(fd, &buf, rest) != (ssize_t)rest) | ||
961 | return -1; | ||
962 | |||
963 | if (session->header.needs_swap) | ||
964 | event_swap(event, perf_evlist__sample_id_all(session->evlist)); | ||
965 | |||
966 | out_parse_sample: | ||
967 | |||
968 | if (sample && event->header.type < PERF_RECORD_USER_TYPE_START && | ||
969 | perf_evlist__parse_sample(session->evlist, event, sample)) | ||
970 | return -1; | ||
971 | |||
972 | *event_ptr = event; | ||
973 | |||
974 | return 0; | ||
975 | } | ||
976 | |||
1039 | static s64 perf_session__process_event(struct perf_session *session, | 977 | static s64 perf_session__process_event(struct perf_session *session, |
1040 | union perf_event *event, | 978 | union perf_event *event, |
1041 | struct perf_tool *tool, | 979 | struct perf_tool *tool, |
@@ -1062,15 +1000,15 @@ static s64 perf_session__process_event(struct perf_session *session, | |||
1062 | if (ret) | 1000 | if (ret) |
1063 | return ret; | 1001 | return ret; |
1064 | 1002 | ||
1065 | if (tool->ordered_samples) { | 1003 | if (tool->ordered_events) { |
1066 | ret = perf_session_queue_event(session, event, &sample, | 1004 | ret = perf_session_queue_event(session, event, tool, &sample, |
1067 | file_offset); | 1005 | file_offset); |
1068 | if (ret != -ETIME) | 1006 | if (ret != -ETIME) |
1069 | return ret; | 1007 | return ret; |
1070 | } | 1008 | } |
1071 | 1009 | ||
1072 | return perf_session_deliver_event(session, event, &sample, tool, | 1010 | return perf_session__deliver_event(session, event, &sample, tool, |
1073 | file_offset); | 1011 | file_offset); |
1074 | } | 1012 | } |
1075 | 1013 | ||
1076 | void perf_event_header__bswap(struct perf_event_header *hdr) | 1014 | void perf_event_header__bswap(struct perf_event_header *hdr) |
@@ -1222,12 +1160,11 @@ more: | |||
1222 | goto more; | 1160 | goto more; |
1223 | done: | 1161 | done: |
1224 | /* do the final flush for ordered samples */ | 1162 | /* do the final flush for ordered samples */ |
1225 | session->ordered_samples.next_flush = ULLONG_MAX; | 1163 | err = ordered_events__flush(session, tool, OE_FLUSH__FINAL); |
1226 | err = flush_sample_queue(session, tool); | ||
1227 | out_err: | 1164 | out_err: |
1228 | free(buf); | 1165 | free(buf); |
1229 | perf_session__warn_about_errors(session, tool); | 1166 | perf_session__warn_about_errors(session, tool); |
1230 | perf_session_free_sample_buffers(session); | 1167 | ordered_events__free(&session->ordered_events); |
1231 | return err; | 1168 | return err; |
1232 | } | 1169 | } |
1233 | 1170 | ||
@@ -1368,12 +1305,11 @@ more: | |||
1368 | 1305 | ||
1369 | out: | 1306 | out: |
1370 | /* do the final flush for ordered samples */ | 1307 | /* do the final flush for ordered samples */ |
1371 | session->ordered_samples.next_flush = ULLONG_MAX; | 1308 | err = ordered_events__flush(session, tool, OE_FLUSH__FINAL); |
1372 | err = flush_sample_queue(session, tool); | ||
1373 | out_err: | 1309 | out_err: |
1374 | ui_progress__finish(); | 1310 | ui_progress__finish(); |
1375 | perf_session__warn_about_errors(session, tool); | 1311 | perf_session__warn_about_errors(session, tool); |
1376 | perf_session_free_sample_buffers(session); | 1312 | ordered_events__free(&session->ordered_events); |
1377 | session->one_mmap = false; | 1313 | session->one_mmap = false; |
1378 | return err; | 1314 | return err; |
1379 | } | 1315 | } |
diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h index 0321013bd9fd..ffb440462008 100644 --- a/tools/perf/util/session.h +++ b/tools/perf/util/session.h | |||
@@ -9,26 +9,13 @@ | |||
9 | #include "symbol.h" | 9 | #include "symbol.h" |
10 | #include "thread.h" | 10 | #include "thread.h" |
11 | #include "data.h" | 11 | #include "data.h" |
12 | #include "ordered-events.h" | ||
12 | #include <linux/rbtree.h> | 13 | #include <linux/rbtree.h> |
13 | #include <linux/perf_event.h> | 14 | #include <linux/perf_event.h> |
14 | 15 | ||
15 | struct sample_queue; | ||
16 | struct ip_callchain; | 16 | struct ip_callchain; |
17 | struct thread; | 17 | struct thread; |
18 | 18 | ||
19 | struct ordered_samples { | ||
20 | u64 last_flush; | ||
21 | u64 next_flush; | ||
22 | u64 max_timestamp; | ||
23 | struct list_head samples; | ||
24 | struct list_head sample_cache; | ||
25 | struct list_head to_free; | ||
26 | struct sample_queue *sample_buffer; | ||
27 | struct sample_queue *last_sample; | ||
28 | int sample_buffer_idx; | ||
29 | unsigned int nr_samples; | ||
30 | }; | ||
31 | |||
32 | struct perf_session { | 19 | struct perf_session { |
33 | struct perf_header header; | 20 | struct perf_header header; |
34 | struct machines machines; | 21 | struct machines machines; |
@@ -39,7 +26,7 @@ struct perf_session { | |||
39 | bool one_mmap; | 26 | bool one_mmap; |
40 | void *one_mmap_addr; | 27 | void *one_mmap_addr; |
41 | u64 one_mmap_offset; | 28 | u64 one_mmap_offset; |
42 | struct ordered_samples ordered_samples; | 29 | struct ordered_events ordered_events; |
43 | struct perf_data_file *file; | 30 | struct perf_data_file *file; |
44 | }; | 31 | }; |
45 | 32 | ||
@@ -58,6 +45,11 @@ void perf_session__delete(struct perf_session *session); | |||
58 | 45 | ||
59 | void perf_event_header__bswap(struct perf_event_header *hdr); | 46 | void perf_event_header__bswap(struct perf_event_header *hdr); |
60 | 47 | ||
48 | int perf_session__peek_event(struct perf_session *session, off_t file_offset, | ||
49 | void *buf, size_t buf_sz, | ||
50 | union perf_event **event_ptr, | ||
51 | struct perf_sample *sample); | ||
52 | |||
61 | int __perf_session__process_events(struct perf_session *session, | 53 | int __perf_session__process_events(struct perf_session *session, |
62 | u64 data_offset, u64 data_size, u64 size, | 54 | u64 data_offset, u64 data_size, u64 size, |
63 | struct perf_tool *tool); | 55 | struct perf_tool *tool); |
@@ -65,10 +57,16 @@ int perf_session__process_events(struct perf_session *session, | |||
65 | struct perf_tool *tool); | 57 | struct perf_tool *tool); |
66 | 58 | ||
67 | int perf_session_queue_event(struct perf_session *s, union perf_event *event, | 59 | int perf_session_queue_event(struct perf_session *s, union perf_event *event, |
68 | struct perf_sample *sample, u64 file_offset); | 60 | struct perf_tool *tool, struct perf_sample *sample, |
61 | u64 file_offset); | ||
69 | 62 | ||
70 | void perf_tool__fill_defaults(struct perf_tool *tool); | 63 | void perf_tool__fill_defaults(struct perf_tool *tool); |
71 | 64 | ||
65 | int perf_session__deliver_event(struct perf_session *session, | ||
66 | union perf_event *event, | ||
67 | struct perf_sample *sample, | ||
68 | struct perf_tool *tool, u64 file_offset); | ||
69 | |||
72 | int perf_session__resolve_callchain(struct perf_session *session, | 70 | int perf_session__resolve_callchain(struct perf_session *session, |
73 | struct perf_evsel *evsel, | 71 | struct perf_evsel *evsel, |
74 | struct thread *thread, | 72 | struct thread *thread, |
@@ -128,5 +126,5 @@ int __perf_session__set_tracepoints_handlers(struct perf_session *session, | |||
128 | 126 | ||
129 | extern volatile int session_done; | 127 | extern volatile int session_done; |
130 | 128 | ||
131 | #define session_done() (*(volatile int *)(&session_done)) | 129 | #define session_done() ACCESS_ONCE(session_done) |
132 | #endif /* __PERF_SESSION_H */ | 130 | #endif /* __PERF_SESSION_H */ |
diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c index 14e5a039bc45..289df9d1e65a 100644 --- a/tools/perf/util/sort.c +++ b/tools/perf/util/sort.c | |||
@@ -70,12 +70,14 @@ static int hist_entry__thread_snprintf(struct hist_entry *he, char *bf, | |||
70 | size_t size, unsigned int width) | 70 | size_t size, unsigned int width) |
71 | { | 71 | { |
72 | const char *comm = thread__comm_str(he->thread); | 72 | const char *comm = thread__comm_str(he->thread); |
73 | return repsep_snprintf(bf, size, "%*s:%5d", width - 6, | 73 | |
74 | comm ?: "", he->thread->tid); | 74 | width = max(7U, width) - 6; |
75 | return repsep_snprintf(bf, size, "%5d:%-*.*s", he->thread->tid, | ||
76 | width, width, comm ?: ""); | ||
75 | } | 77 | } |
76 | 78 | ||
77 | struct sort_entry sort_thread = { | 79 | struct sort_entry sort_thread = { |
78 | .se_header = "Command: Pid", | 80 | .se_header = " Pid:Command", |
79 | .se_cmp = sort__thread_cmp, | 81 | .se_cmp = sort__thread_cmp, |
80 | .se_snprintf = hist_entry__thread_snprintf, | 82 | .se_snprintf = hist_entry__thread_snprintf, |
81 | .se_width_idx = HISTC_THREAD, | 83 | .se_width_idx = HISTC_THREAD, |
@@ -106,7 +108,7 @@ sort__comm_sort(struct hist_entry *left, struct hist_entry *right) | |||
106 | static int hist_entry__comm_snprintf(struct hist_entry *he, char *bf, | 108 | static int hist_entry__comm_snprintf(struct hist_entry *he, char *bf, |
107 | size_t size, unsigned int width) | 109 | size_t size, unsigned int width) |
108 | { | 110 | { |
109 | return repsep_snprintf(bf, size, "%*s", width, comm__str(he->comm)); | 111 | return repsep_snprintf(bf, size, "%-*.*s", width, width, comm__str(he->comm)); |
110 | } | 112 | } |
111 | 113 | ||
112 | struct sort_entry sort_comm = { | 114 | struct sort_entry sort_comm = { |
@@ -152,10 +154,10 @@ static int _hist_entry__dso_snprintf(struct map *map, char *bf, | |||
152 | if (map && map->dso) { | 154 | if (map && map->dso) { |
153 | const char *dso_name = !verbose ? map->dso->short_name : | 155 | const char *dso_name = !verbose ? map->dso->short_name : |
154 | map->dso->long_name; | 156 | map->dso->long_name; |
155 | return repsep_snprintf(bf, size, "%-*s", width, dso_name); | 157 | return repsep_snprintf(bf, size, "%-*.*s", width, width, dso_name); |
156 | } | 158 | } |
157 | 159 | ||
158 | return repsep_snprintf(bf, size, "%-*s", width, "[unknown]"); | 160 | return repsep_snprintf(bf, size, "%-*.*s", width, width, "[unknown]"); |
159 | } | 161 | } |
160 | 162 | ||
161 | static int hist_entry__dso_snprintf(struct hist_entry *he, char *bf, | 163 | static int hist_entry__dso_snprintf(struct hist_entry *he, char *bf, |
@@ -257,7 +259,10 @@ static int _hist_entry__sym_snprintf(struct map *map, struct symbol *sym, | |||
257 | width - ret, ""); | 259 | width - ret, ""); |
258 | } | 260 | } |
259 | 261 | ||
260 | return ret; | 262 | if (ret > width) |
263 | bf[width] = '\0'; | ||
264 | |||
265 | return width; | ||
261 | } | 266 | } |
262 | 267 | ||
263 | static int hist_entry__sym_snprintf(struct hist_entry *he, char *bf, | 268 | static int hist_entry__sym_snprintf(struct hist_entry *he, char *bf, |
@@ -302,10 +307,9 @@ sort__srcline_cmp(struct hist_entry *left, struct hist_entry *right) | |||
302 | } | 307 | } |
303 | 308 | ||
304 | static int hist_entry__srcline_snprintf(struct hist_entry *he, char *bf, | 309 | static int hist_entry__srcline_snprintf(struct hist_entry *he, char *bf, |
305 | size_t size, | 310 | size_t size, unsigned int width) |
306 | unsigned int width __maybe_unused) | ||
307 | { | 311 | { |
308 | return repsep_snprintf(bf, size, "%s", he->srcline); | 312 | return repsep_snprintf(bf, size, "%*.*-s", width, width, he->srcline); |
309 | } | 313 | } |
310 | 314 | ||
311 | struct sort_entry sort_srcline = { | 315 | struct sort_entry sort_srcline = { |
@@ -332,7 +336,7 @@ sort__parent_cmp(struct hist_entry *left, struct hist_entry *right) | |||
332 | static int hist_entry__parent_snprintf(struct hist_entry *he, char *bf, | 336 | static int hist_entry__parent_snprintf(struct hist_entry *he, char *bf, |
333 | size_t size, unsigned int width) | 337 | size_t size, unsigned int width) |
334 | { | 338 | { |
335 | return repsep_snprintf(bf, size, "%-*s", width, | 339 | return repsep_snprintf(bf, size, "%-*.*s", width, width, |
336 | he->parent ? he->parent->name : "[other]"); | 340 | he->parent ? he->parent->name : "[other]"); |
337 | } | 341 | } |
338 | 342 | ||
@@ -354,7 +358,7 @@ sort__cpu_cmp(struct hist_entry *left, struct hist_entry *right) | |||
354 | static int hist_entry__cpu_snprintf(struct hist_entry *he, char *bf, | 358 | static int hist_entry__cpu_snprintf(struct hist_entry *he, char *bf, |
355 | size_t size, unsigned int width) | 359 | size_t size, unsigned int width) |
356 | { | 360 | { |
357 | return repsep_snprintf(bf, size, "%*d", width, he->cpu); | 361 | return repsep_snprintf(bf, size, "%*.*d", width, width, he->cpu); |
358 | } | 362 | } |
359 | 363 | ||
360 | struct sort_entry sort_cpu = { | 364 | struct sort_entry sort_cpu = { |
@@ -484,7 +488,7 @@ static int hist_entry__mispredict_snprintf(struct hist_entry *he, char *bf, | |||
484 | else if (he->branch_info->flags.mispred) | 488 | else if (he->branch_info->flags.mispred) |
485 | out = "Y"; | 489 | out = "Y"; |
486 | 490 | ||
487 | return repsep_snprintf(bf, size, "%-*s", width, out); | 491 | return repsep_snprintf(bf, size, "%-*.*s", width, width, out); |
488 | } | 492 | } |
489 | 493 | ||
490 | /* --sort daddr_sym */ | 494 | /* --sort daddr_sym */ |
@@ -1194,7 +1198,7 @@ bool perf_hpp__same_sort_entry(struct perf_hpp_fmt *a, struct perf_hpp_fmt *b) | |||
1194 | return hse_a->se == hse_b->se; | 1198 | return hse_a->se == hse_b->se; |
1195 | } | 1199 | } |
1196 | 1200 | ||
1197 | void perf_hpp__reset_width(struct perf_hpp_fmt *fmt, struct hists *hists) | 1201 | void perf_hpp__reset_sort_width(struct perf_hpp_fmt *fmt, struct hists *hists) |
1198 | { | 1202 | { |
1199 | struct hpp_sort_entry *hse; | 1203 | struct hpp_sort_entry *hse; |
1200 | 1204 | ||
@@ -1202,20 +1206,21 @@ void perf_hpp__reset_width(struct perf_hpp_fmt *fmt, struct hists *hists) | |||
1202 | return; | 1206 | return; |
1203 | 1207 | ||
1204 | hse = container_of(fmt, struct hpp_sort_entry, hpp); | 1208 | hse = container_of(fmt, struct hpp_sort_entry, hpp); |
1205 | hists__new_col_len(hists, hse->se->se_width_idx, | 1209 | hists__new_col_len(hists, hse->se->se_width_idx, strlen(fmt->name)); |
1206 | strlen(hse->se->se_header)); | ||
1207 | } | 1210 | } |
1208 | 1211 | ||
1209 | static int __sort__hpp_header(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp, | 1212 | static int __sort__hpp_header(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp, |
1210 | struct perf_evsel *evsel) | 1213 | struct perf_evsel *evsel) |
1211 | { | 1214 | { |
1212 | struct hpp_sort_entry *hse; | 1215 | struct hpp_sort_entry *hse; |
1213 | size_t len; | 1216 | size_t len = fmt->user_len; |
1214 | 1217 | ||
1215 | hse = container_of(fmt, struct hpp_sort_entry, hpp); | 1218 | hse = container_of(fmt, struct hpp_sort_entry, hpp); |
1216 | len = hists__col_len(&evsel->hists, hse->se->se_width_idx); | ||
1217 | 1219 | ||
1218 | return scnprintf(hpp->buf, hpp->size, "%-*s", len, hse->se->se_header); | 1220 | if (!len) |
1221 | len = hists__col_len(&evsel->hists, hse->se->se_width_idx); | ||
1222 | |||
1223 | return scnprintf(hpp->buf, hpp->size, "%-*.*s", len, len, fmt->name); | ||
1219 | } | 1224 | } |
1220 | 1225 | ||
1221 | static int __sort__hpp_width(struct perf_hpp_fmt *fmt, | 1226 | static int __sort__hpp_width(struct perf_hpp_fmt *fmt, |
@@ -1223,20 +1228,26 @@ static int __sort__hpp_width(struct perf_hpp_fmt *fmt, | |||
1223 | struct perf_evsel *evsel) | 1228 | struct perf_evsel *evsel) |
1224 | { | 1229 | { |
1225 | struct hpp_sort_entry *hse; | 1230 | struct hpp_sort_entry *hse; |
1231 | size_t len = fmt->user_len; | ||
1226 | 1232 | ||
1227 | hse = container_of(fmt, struct hpp_sort_entry, hpp); | 1233 | hse = container_of(fmt, struct hpp_sort_entry, hpp); |
1228 | 1234 | ||
1229 | return hists__col_len(&evsel->hists, hse->se->se_width_idx); | 1235 | if (!len) |
1236 | len = hists__col_len(&evsel->hists, hse->se->se_width_idx); | ||
1237 | |||
1238 | return len; | ||
1230 | } | 1239 | } |
1231 | 1240 | ||
1232 | static int __sort__hpp_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp, | 1241 | static int __sort__hpp_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp, |
1233 | struct hist_entry *he) | 1242 | struct hist_entry *he) |
1234 | { | 1243 | { |
1235 | struct hpp_sort_entry *hse; | 1244 | struct hpp_sort_entry *hse; |
1236 | size_t len; | 1245 | size_t len = fmt->user_len; |
1237 | 1246 | ||
1238 | hse = container_of(fmt, struct hpp_sort_entry, hpp); | 1247 | hse = container_of(fmt, struct hpp_sort_entry, hpp); |
1239 | len = hists__col_len(he->hists, hse->se->se_width_idx); | 1248 | |
1249 | if (!len) | ||
1250 | len = hists__col_len(he->hists, hse->se->se_width_idx); | ||
1240 | 1251 | ||
1241 | return hse->se->se_snprintf(he, hpp->buf, hpp->size, len); | 1252 | return hse->se->se_snprintf(he, hpp->buf, hpp->size, len); |
1242 | } | 1253 | } |
@@ -1253,6 +1264,7 @@ __sort_dimension__alloc_hpp(struct sort_dimension *sd) | |||
1253 | } | 1264 | } |
1254 | 1265 | ||
1255 | hse->se = sd->entry; | 1266 | hse->se = sd->entry; |
1267 | hse->hpp.name = sd->entry->se_header; | ||
1256 | hse->hpp.header = __sort__hpp_header; | 1268 | hse->hpp.header = __sort__hpp_header; |
1257 | hse->hpp.width = __sort__hpp_width; | 1269 | hse->hpp.width = __sort__hpp_width; |
1258 | hse->hpp.entry = __sort__hpp_entry; | 1270 | hse->hpp.entry = __sort__hpp_entry; |
@@ -1265,6 +1277,8 @@ __sort_dimension__alloc_hpp(struct sort_dimension *sd) | |||
1265 | INIT_LIST_HEAD(&hse->hpp.list); | 1277 | INIT_LIST_HEAD(&hse->hpp.list); |
1266 | INIT_LIST_HEAD(&hse->hpp.sort_list); | 1278 | INIT_LIST_HEAD(&hse->hpp.sort_list); |
1267 | hse->hpp.elide = false; | 1279 | hse->hpp.elide = false; |
1280 | hse->hpp.len = 0; | ||
1281 | hse->hpp.user_len = 0; | ||
1268 | 1282 | ||
1269 | return hse; | 1283 | return hse; |
1270 | } | 1284 | } |
@@ -1432,14 +1446,49 @@ static const char *get_default_sort_order(void) | |||
1432 | return default_sort_orders[sort__mode]; | 1446 | return default_sort_orders[sort__mode]; |
1433 | } | 1447 | } |
1434 | 1448 | ||
1449 | static int setup_sort_order(void) | ||
1450 | { | ||
1451 | char *new_sort_order; | ||
1452 | |||
1453 | /* | ||
1454 | * Append '+'-prefixed sort order to the default sort | ||
1455 | * order string. | ||
1456 | */ | ||
1457 | if (!sort_order || is_strict_order(sort_order)) | ||
1458 | return 0; | ||
1459 | |||
1460 | if (sort_order[1] == '\0') { | ||
1461 | error("Invalid --sort key: `+'"); | ||
1462 | return -EINVAL; | ||
1463 | } | ||
1464 | |||
1465 | /* | ||
1466 | * We allocate new sort_order string, but we never free it, | ||
1467 | * because it's checked over the rest of the code. | ||
1468 | */ | ||
1469 | if (asprintf(&new_sort_order, "%s,%s", | ||
1470 | get_default_sort_order(), sort_order + 1) < 0) { | ||
1471 | error("Not enough memory to set up --sort"); | ||
1472 | return -ENOMEM; | ||
1473 | } | ||
1474 | |||
1475 | sort_order = new_sort_order; | ||
1476 | return 0; | ||
1477 | } | ||
1478 | |||
1435 | static int __setup_sorting(void) | 1479 | static int __setup_sorting(void) |
1436 | { | 1480 | { |
1437 | char *tmp, *tok, *str; | 1481 | char *tmp, *tok, *str; |
1438 | const char *sort_keys = sort_order; | 1482 | const char *sort_keys; |
1439 | int ret = 0; | 1483 | int ret = 0; |
1440 | 1484 | ||
1485 | ret = setup_sort_order(); | ||
1486 | if (ret) | ||
1487 | return ret; | ||
1488 | |||
1489 | sort_keys = sort_order; | ||
1441 | if (sort_keys == NULL) { | 1490 | if (sort_keys == NULL) { |
1442 | if (field_order) { | 1491 | if (is_strict_order(field_order)) { |
1443 | /* | 1492 | /* |
1444 | * If user specified field order but no sort order, | 1493 | * If user specified field order but no sort order, |
1445 | * we'll honor it and not add default sort orders. | 1494 | * we'll honor it and not add default sort orders. |
@@ -1625,23 +1674,36 @@ static void reset_dimensions(void) | |||
1625 | memory_sort_dimensions[i].taken = 0; | 1674 | memory_sort_dimensions[i].taken = 0; |
1626 | } | 1675 | } |
1627 | 1676 | ||
1677 | bool is_strict_order(const char *order) | ||
1678 | { | ||
1679 | return order && (*order != '+'); | ||
1680 | } | ||
1681 | |||
1628 | static int __setup_output_field(void) | 1682 | static int __setup_output_field(void) |
1629 | { | 1683 | { |
1630 | char *tmp, *tok, *str; | 1684 | char *tmp, *tok, *str, *strp; |
1631 | int ret = 0; | 1685 | int ret = -EINVAL; |
1632 | 1686 | ||
1633 | if (field_order == NULL) | 1687 | if (field_order == NULL) |
1634 | return 0; | 1688 | return 0; |
1635 | 1689 | ||
1636 | reset_dimensions(); | 1690 | reset_dimensions(); |
1637 | 1691 | ||
1638 | str = strdup(field_order); | 1692 | strp = str = strdup(field_order); |
1639 | if (str == NULL) { | 1693 | if (str == NULL) { |
1640 | error("Not enough memory to setup output fields"); | 1694 | error("Not enough memory to setup output fields"); |
1641 | return -ENOMEM; | 1695 | return -ENOMEM; |
1642 | } | 1696 | } |
1643 | 1697 | ||
1644 | for (tok = strtok_r(str, ", ", &tmp); | 1698 | if (!is_strict_order(field_order)) |
1699 | strp++; | ||
1700 | |||
1701 | if (!strlen(strp)) { | ||
1702 | error("Invalid --fields key: `+'"); | ||
1703 | goto out; | ||
1704 | } | ||
1705 | |||
1706 | for (tok = strtok_r(strp, ", ", &tmp); | ||
1645 | tok; tok = strtok_r(NULL, ", ", &tmp)) { | 1707 | tok; tok = strtok_r(NULL, ", ", &tmp)) { |
1646 | ret = output_field_add(tok); | 1708 | ret = output_field_add(tok); |
1647 | if (ret == -EINVAL) { | 1709 | if (ret == -EINVAL) { |
@@ -1653,6 +1715,7 @@ static int __setup_output_field(void) | |||
1653 | } | 1715 | } |
1654 | } | 1716 | } |
1655 | 1717 | ||
1718 | out: | ||
1656 | free(str); | 1719 | free(str); |
1657 | return ret; | 1720 | return ret; |
1658 | } | 1721 | } |
diff --git a/tools/perf/util/sort.h b/tools/perf/util/sort.h index 041f0c9cea2b..c03e4ff8beff 100644 --- a/tools/perf/util/sort.h +++ b/tools/perf/util/sort.h | |||
@@ -218,4 +218,5 @@ void perf_hpp__set_elide(int idx, bool elide); | |||
218 | 218 | ||
219 | int report_parse_ignore_callees_opt(const struct option *opt, const char *arg, int unset); | 219 | int report_parse_ignore_callees_opt(const struct option *opt, const char *arg, int unset); |
220 | 220 | ||
221 | bool is_strict_order(const char *order); | ||
221 | #endif /* __PERF_SORT_H */ | 222 | #endif /* __PERF_SORT_H */ |
diff --git a/tools/perf/util/symbol-elf.c b/tools/perf/util/symbol-elf.c index d75349979e65..1e23a5bfb044 100644 --- a/tools/perf/util/symbol-elf.c +++ b/tools/perf/util/symbol-elf.c | |||
@@ -6,6 +6,7 @@ | |||
6 | #include <inttypes.h> | 6 | #include <inttypes.h> |
7 | 7 | ||
8 | #include "symbol.h" | 8 | #include "symbol.h" |
9 | #include "machine.h" | ||
9 | #include "vdso.h" | 10 | #include "vdso.h" |
10 | #include <symbol/kallsyms.h> | 11 | #include <symbol/kallsyms.h> |
11 | #include "debug.h" | 12 | #include "debug.h" |
@@ -680,6 +681,11 @@ static u64 ref_reloc(struct kmap *kmap) | |||
680 | return 0; | 681 | return 0; |
681 | } | 682 | } |
682 | 683 | ||
684 | static bool want_demangle(bool is_kernel_sym) | ||
685 | { | ||
686 | return is_kernel_sym ? symbol_conf.demangle_kernel : symbol_conf.demangle; | ||
687 | } | ||
688 | |||
683 | int dso__load_sym(struct dso *dso, struct map *map, | 689 | int dso__load_sym(struct dso *dso, struct map *map, |
684 | struct symsrc *syms_ss, struct symsrc *runtime_ss, | 690 | struct symsrc *syms_ss, struct symsrc *runtime_ss, |
685 | symbol_filter_t filter, int kmodule) | 691 | symbol_filter_t filter, int kmodule) |
@@ -712,6 +718,14 @@ int dso__load_sym(struct dso *dso, struct map *map, | |||
712 | symbols__delete(&dso->symbols[map->type]); | 718 | symbols__delete(&dso->symbols[map->type]); |
713 | 719 | ||
714 | if (!syms_ss->symtab) { | 720 | if (!syms_ss->symtab) { |
721 | /* | ||
722 | * If the vmlinux is stripped, fail so we will fall back | ||
723 | * to using kallsyms. The vmlinux runtime symbols aren't | ||
724 | * of much use. | ||
725 | */ | ||
726 | if (dso->kernel) | ||
727 | goto out_elf_end; | ||
728 | |||
715 | syms_ss->symtab = syms_ss->dynsym; | 729 | syms_ss->symtab = syms_ss->dynsym; |
716 | syms_ss->symshdr = syms_ss->dynshdr; | 730 | syms_ss->symshdr = syms_ss->dynshdr; |
717 | } | 731 | } |
@@ -736,7 +750,7 @@ int dso__load_sym(struct dso *dso, struct map *map, | |||
736 | if (symstrs == NULL) | 750 | if (symstrs == NULL) |
737 | goto out_elf_end; | 751 | goto out_elf_end; |
738 | 752 | ||
739 | sec_strndx = elf_getscn(elf, ehdr.e_shstrndx); | 753 | sec_strndx = elf_getscn(runtime_ss->elf, runtime_ss->ehdr.e_shstrndx); |
740 | if (sec_strndx == NULL) | 754 | if (sec_strndx == NULL) |
741 | goto out_elf_end; | 755 | goto out_elf_end; |
742 | 756 | ||
@@ -916,7 +930,11 @@ int dso__load_sym(struct dso *dso, struct map *map, | |||
916 | } | 930 | } |
917 | curr_dso->symtab_type = dso->symtab_type; | 931 | curr_dso->symtab_type = dso->symtab_type; |
918 | map_groups__insert(kmap->kmaps, curr_map); | 932 | map_groups__insert(kmap->kmaps, curr_map); |
919 | dsos__add(&dso->node, curr_dso); | 933 | /* |
934 | * The new DSO should go to the kernel DSOS | ||
935 | */ | ||
936 | dsos__add(&map->groups->machine->kernel_dsos, | ||
937 | curr_dso); | ||
920 | dso__set_loaded(curr_dso, map->type); | 938 | dso__set_loaded(curr_dso, map->type); |
921 | } else | 939 | } else |
922 | curr_dso = curr_map->dso; | 940 | curr_dso = curr_map->dso; |
@@ -938,9 +956,12 @@ new_symbol: | |||
938 | * DWARF DW_compile_unit has this, but we don't always have access | 956 | * DWARF DW_compile_unit has this, but we don't always have access |
939 | * to it... | 957 | * to it... |
940 | */ | 958 | */ |
941 | if (symbol_conf.demangle) { | 959 | if (want_demangle(dso->kernel || kmodule)) { |
942 | demangled = bfd_demangle(NULL, elf_name, | 960 | int demangle_flags = DMGL_NO_OPTS; |
943 | DMGL_PARAMS | DMGL_ANSI); | 961 | if (verbose) |
962 | demangle_flags = DMGL_PARAMS | DMGL_ANSI; | ||
963 | |||
964 | demangled = bfd_demangle(NULL, elf_name, demangle_flags); | ||
944 | if (demangled != NULL) | 965 | if (demangled != NULL) |
945 | elf_name = demangled; | 966 | elf_name = demangled; |
946 | } | 967 | } |
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index eb06746b06b2..be84f7a9838b 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c | |||
@@ -15,6 +15,7 @@ | |||
15 | #include "machine.h" | 15 | #include "machine.h" |
16 | #include "symbol.h" | 16 | #include "symbol.h" |
17 | #include "strlist.h" | 17 | #include "strlist.h" |
18 | #include "header.h" | ||
18 | 19 | ||
19 | #include <elf.h> | 20 | #include <elf.h> |
20 | #include <limits.h> | 21 | #include <limits.h> |
@@ -33,6 +34,7 @@ struct symbol_conf symbol_conf = { | |||
33 | .try_vmlinux_path = true, | 34 | .try_vmlinux_path = true, |
34 | .annotate_src = true, | 35 | .annotate_src = true, |
35 | .demangle = true, | 36 | .demangle = true, |
37 | .demangle_kernel = false, | ||
36 | .cumulate_callchain = true, | 38 | .cumulate_callchain = true, |
37 | .show_hist_headers = true, | 39 | .show_hist_headers = true, |
38 | .symfs = "", | 40 | .symfs = "", |
@@ -523,10 +525,15 @@ struct process_kallsyms_args { | |||
523 | struct dso *dso; | 525 | struct dso *dso; |
524 | }; | 526 | }; |
525 | 527 | ||
528 | /* | ||
529 | * These are symbols in the kernel image, so make sure that | ||
530 | * sym is from a kernel DSO. | ||
531 | */ | ||
526 | bool symbol__is_idle(struct symbol *sym) | 532 | bool symbol__is_idle(struct symbol *sym) |
527 | { | 533 | { |
528 | const char * const idle_symbols[] = { | 534 | const char * const idle_symbols[] = { |
529 | "cpu_idle", | 535 | "cpu_idle", |
536 | "cpu_startup_entry", | ||
530 | "intel_idle", | 537 | "intel_idle", |
531 | "default_idle", | 538 | "default_idle", |
532 | "native_safe_halt", | 539 | "native_safe_halt", |
@@ -1468,8 +1475,7 @@ int dso__load_vmlinux(struct dso *dso, struct map *map, | |||
1468 | if (vmlinux[0] == '/') | 1475 | if (vmlinux[0] == '/') |
1469 | snprintf(symfs_vmlinux, sizeof(symfs_vmlinux), "%s", vmlinux); | 1476 | snprintf(symfs_vmlinux, sizeof(symfs_vmlinux), "%s", vmlinux); |
1470 | else | 1477 | else |
1471 | snprintf(symfs_vmlinux, sizeof(symfs_vmlinux), "%s%s", | 1478 | symbol__join_symfs(symfs_vmlinux, vmlinux); |
1472 | symbol_conf.symfs, vmlinux); | ||
1473 | 1479 | ||
1474 | if (dso->kernel == DSO_TYPE_GUEST_KERNEL) | 1480 | if (dso->kernel == DSO_TYPE_GUEST_KERNEL) |
1475 | symtab_type = DSO_BINARY_TYPE__GUEST_VMLINUX; | 1481 | symtab_type = DSO_BINARY_TYPE__GUEST_VMLINUX; |
@@ -1745,12 +1751,13 @@ static void vmlinux_path__exit(void) | |||
1745 | zfree(&vmlinux_path); | 1751 | zfree(&vmlinux_path); |
1746 | } | 1752 | } |
1747 | 1753 | ||
1748 | static int vmlinux_path__init(void) | 1754 | static int vmlinux_path__init(struct perf_session_env *env) |
1749 | { | 1755 | { |
1750 | struct utsname uts; | 1756 | struct utsname uts; |
1751 | char bf[PATH_MAX]; | 1757 | char bf[PATH_MAX]; |
1758 | char *kernel_version; | ||
1752 | 1759 | ||
1753 | vmlinux_path = malloc(sizeof(char *) * 5); | 1760 | vmlinux_path = malloc(sizeof(char *) * 6); |
1754 | if (vmlinux_path == NULL) | 1761 | if (vmlinux_path == NULL) |
1755 | return -1; | 1762 | return -1; |
1756 | 1763 | ||
@@ -1763,25 +1770,37 @@ static int vmlinux_path__init(void) | |||
1763 | goto out_fail; | 1770 | goto out_fail; |
1764 | ++vmlinux_path__nr_entries; | 1771 | ++vmlinux_path__nr_entries; |
1765 | 1772 | ||
1766 | /* only try running kernel version if no symfs was given */ | 1773 | /* only try kernel version if no symfs was given */ |
1767 | if (symbol_conf.symfs[0] != 0) | 1774 | if (symbol_conf.symfs[0] != 0) |
1768 | return 0; | 1775 | return 0; |
1769 | 1776 | ||
1770 | if (uname(&uts) < 0) | 1777 | if (env) { |
1771 | return -1; | 1778 | kernel_version = env->os_release; |
1779 | } else { | ||
1780 | if (uname(&uts) < 0) | ||
1781 | goto out_fail; | ||
1772 | 1782 | ||
1773 | snprintf(bf, sizeof(bf), "/boot/vmlinux-%s", uts.release); | 1783 | kernel_version = uts.release; |
1784 | } | ||
1785 | |||
1786 | snprintf(bf, sizeof(bf), "/boot/vmlinux-%s", kernel_version); | ||
1774 | vmlinux_path[vmlinux_path__nr_entries] = strdup(bf); | 1787 | vmlinux_path[vmlinux_path__nr_entries] = strdup(bf); |
1775 | if (vmlinux_path[vmlinux_path__nr_entries] == NULL) | 1788 | if (vmlinux_path[vmlinux_path__nr_entries] == NULL) |
1776 | goto out_fail; | 1789 | goto out_fail; |
1777 | ++vmlinux_path__nr_entries; | 1790 | ++vmlinux_path__nr_entries; |
1778 | snprintf(bf, sizeof(bf), "/lib/modules/%s/build/vmlinux", uts.release); | 1791 | snprintf(bf, sizeof(bf), "/usr/lib/debug/boot/vmlinux-%s", |
1792 | kernel_version); | ||
1793 | vmlinux_path[vmlinux_path__nr_entries] = strdup(bf); | ||
1794 | if (vmlinux_path[vmlinux_path__nr_entries] == NULL) | ||
1795 | goto out_fail; | ||
1796 | ++vmlinux_path__nr_entries; | ||
1797 | snprintf(bf, sizeof(bf), "/lib/modules/%s/build/vmlinux", kernel_version); | ||
1779 | vmlinux_path[vmlinux_path__nr_entries] = strdup(bf); | 1798 | vmlinux_path[vmlinux_path__nr_entries] = strdup(bf); |
1780 | if (vmlinux_path[vmlinux_path__nr_entries] == NULL) | 1799 | if (vmlinux_path[vmlinux_path__nr_entries] == NULL) |
1781 | goto out_fail; | 1800 | goto out_fail; |
1782 | ++vmlinux_path__nr_entries; | 1801 | ++vmlinux_path__nr_entries; |
1783 | snprintf(bf, sizeof(bf), "/usr/lib/debug/lib/modules/%s/vmlinux", | 1802 | snprintf(bf, sizeof(bf), "/usr/lib/debug/lib/modules/%s/vmlinux", |
1784 | uts.release); | 1803 | kernel_version); |
1785 | vmlinux_path[vmlinux_path__nr_entries] = strdup(bf); | 1804 | vmlinux_path[vmlinux_path__nr_entries] = strdup(bf); |
1786 | if (vmlinux_path[vmlinux_path__nr_entries] == NULL) | 1805 | if (vmlinux_path[vmlinux_path__nr_entries] == NULL) |
1787 | goto out_fail; | 1806 | goto out_fail; |
@@ -1827,7 +1846,7 @@ static bool symbol__read_kptr_restrict(void) | |||
1827 | return value; | 1846 | return value; |
1828 | } | 1847 | } |
1829 | 1848 | ||
1830 | int symbol__init(void) | 1849 | int symbol__init(struct perf_session_env *env) |
1831 | { | 1850 | { |
1832 | const char *symfs; | 1851 | const char *symfs; |
1833 | 1852 | ||
@@ -1842,7 +1861,7 @@ int symbol__init(void) | |||
1842 | symbol_conf.priv_size += (sizeof(struct symbol_name_rb_node) - | 1861 | symbol_conf.priv_size += (sizeof(struct symbol_name_rb_node) - |
1843 | sizeof(struct symbol)); | 1862 | sizeof(struct symbol)); |
1844 | 1863 | ||
1845 | if (symbol_conf.try_vmlinux_path && vmlinux_path__init() < 0) | 1864 | if (symbol_conf.try_vmlinux_path && vmlinux_path__init(env) < 0) |
1846 | return -1; | 1865 | return -1; |
1847 | 1866 | ||
1848 | if (symbol_conf.field_sep && *symbol_conf.field_sep == '.') { | 1867 | if (symbol_conf.field_sep && *symbol_conf.field_sep == '.') { |
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h index e7295e93cff9..bec4b7bd09de 100644 --- a/tools/perf/util/symbol.h +++ b/tools/perf/util/symbol.h | |||
@@ -13,6 +13,7 @@ | |||
13 | #include <libgen.h> | 13 | #include <libgen.h> |
14 | #include "build-id.h" | 14 | #include "build-id.h" |
15 | #include "event.h" | 15 | #include "event.h" |
16 | #include "util.h" | ||
16 | 17 | ||
17 | #ifdef HAVE_LIBELF_SUPPORT | 18 | #ifdef HAVE_LIBELF_SUPPORT |
18 | #include <libelf.h> | 19 | #include <libelf.h> |
@@ -59,6 +60,7 @@ extern Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep, | |||
59 | #endif | 60 | #endif |
60 | 61 | ||
61 | #ifndef DMGL_PARAMS | 62 | #ifndef DMGL_PARAMS |
63 | #define DMGL_NO_OPTS 0 /* For readability... */ | ||
62 | #define DMGL_PARAMS (1 << 0) /* Include function args */ | 64 | #define DMGL_PARAMS (1 << 0) /* Include function args */ |
63 | #define DMGL_ANSI (1 << 1) /* Include const, volatile, etc */ | 65 | #define DMGL_ANSI (1 << 1) /* Include const, volatile, etc */ |
64 | #endif | 66 | #endif |
@@ -118,6 +120,7 @@ struct symbol_conf { | |||
118 | annotate_src, | 120 | annotate_src, |
119 | event_group, | 121 | event_group, |
120 | demangle, | 122 | demangle, |
123 | demangle_kernel, | ||
121 | filter_relative, | 124 | filter_relative, |
122 | show_hist_headers; | 125 | show_hist_headers; |
123 | const char *vmlinux_name, | 126 | const char *vmlinux_name, |
@@ -143,6 +146,14 @@ struct symbol_conf { | |||
143 | }; | 146 | }; |
144 | 147 | ||
145 | extern struct symbol_conf symbol_conf; | 148 | extern struct symbol_conf symbol_conf; |
149 | |||
150 | static inline int __symbol__join_symfs(char *bf, size_t size, const char *path) | ||
151 | { | ||
152 | return path__join(bf, size, symbol_conf.symfs, path); | ||
153 | } | ||
154 | |||
155 | #define symbol__join_symfs(bf, path) __symbol__join_symfs(bf, sizeof(bf), path) | ||
156 | |||
146 | extern int vmlinux_path__nr_entries; | 157 | extern int vmlinux_path__nr_entries; |
147 | extern char **vmlinux_path; | 158 | extern char **vmlinux_path; |
148 | 159 | ||
@@ -253,7 +264,8 @@ int modules__parse(const char *filename, void *arg, | |||
253 | int filename__read_debuglink(const char *filename, char *debuglink, | 264 | int filename__read_debuglink(const char *filename, char *debuglink, |
254 | size_t size); | 265 | size_t size); |
255 | 266 | ||
256 | int symbol__init(void); | 267 | struct perf_session_env; |
268 | int symbol__init(struct perf_session_env *env); | ||
257 | void symbol__exit(void); | 269 | void symbol__exit(void); |
258 | void symbol__elf_init(void); | 270 | void symbol__elf_init(void); |
259 | struct symbol *symbol__new(u64 start, u64 len, u8 binding, const char *name); | 271 | struct symbol *symbol__new(u64 start, u64 len, u8 binding, const char *name); |
diff --git a/tools/perf/util/thread.c b/tools/perf/util/thread.c index 12c7a253a63c..a9df7f2c6dc9 100644 --- a/tools/perf/util/thread.c +++ b/tools/perf/util/thread.c | |||
@@ -42,7 +42,7 @@ struct thread *thread__new(pid_t pid, pid_t tid) | |||
42 | goto err_thread; | 42 | goto err_thread; |
43 | 43 | ||
44 | snprintf(comm_str, 32, ":%d", tid); | 44 | snprintf(comm_str, 32, ":%d", tid); |
45 | comm = comm__new(comm_str, 0); | 45 | comm = comm__new(comm_str, 0, false); |
46 | free(comm_str); | 46 | free(comm_str); |
47 | if (!comm) | 47 | if (!comm) |
48 | goto err_thread; | 48 | goto err_thread; |
@@ -81,19 +81,33 @@ struct comm *thread__comm(const struct thread *thread) | |||
81 | return list_first_entry(&thread->comm_list, struct comm, list); | 81 | return list_first_entry(&thread->comm_list, struct comm, list); |
82 | } | 82 | } |
83 | 83 | ||
84 | struct comm *thread__exec_comm(const struct thread *thread) | ||
85 | { | ||
86 | struct comm *comm, *last = NULL; | ||
87 | |||
88 | list_for_each_entry(comm, &thread->comm_list, list) { | ||
89 | if (comm->exec) | ||
90 | return comm; | ||
91 | last = comm; | ||
92 | } | ||
93 | |||
94 | return last; | ||
95 | } | ||
96 | |||
84 | /* CHECKME: time should always be 0 if event aren't ordered */ | 97 | /* CHECKME: time should always be 0 if event aren't ordered */ |
85 | int thread__set_comm(struct thread *thread, const char *str, u64 timestamp) | 98 | int __thread__set_comm(struct thread *thread, const char *str, u64 timestamp, |
99 | bool exec) | ||
86 | { | 100 | { |
87 | struct comm *new, *curr = thread__comm(thread); | 101 | struct comm *new, *curr = thread__comm(thread); |
88 | int err; | 102 | int err; |
89 | 103 | ||
90 | /* Override latest entry if it had no specific time coverage */ | 104 | /* Override latest entry if it had no specific time coverage */ |
91 | if (!curr->start) { | 105 | if (!curr->start && !curr->exec) { |
92 | err = comm__override(curr, str, timestamp); | 106 | err = comm__override(curr, str, timestamp, exec); |
93 | if (err) | 107 | if (err) |
94 | return err; | 108 | return err; |
95 | } else { | 109 | } else { |
96 | new = comm__new(str, timestamp); | 110 | new = comm__new(str, timestamp, exec); |
97 | if (!new) | 111 | if (!new) |
98 | return -ENOMEM; | 112 | return -ENOMEM; |
99 | list_add(&new->list, &thread->comm_list); | 113 | list_add(&new->list, &thread->comm_list); |
diff --git a/tools/perf/util/thread.h b/tools/perf/util/thread.h index 716b7723cce2..8c75fa774706 100644 --- a/tools/perf/util/thread.h +++ b/tools/perf/util/thread.h | |||
@@ -38,9 +38,17 @@ static inline void thread__exited(struct thread *thread) | |||
38 | thread->dead = true; | 38 | thread->dead = true; |
39 | } | 39 | } |
40 | 40 | ||
41 | int thread__set_comm(struct thread *thread, const char *comm, u64 timestamp); | 41 | int __thread__set_comm(struct thread *thread, const char *comm, u64 timestamp, |
42 | bool exec); | ||
43 | static inline int thread__set_comm(struct thread *thread, const char *comm, | ||
44 | u64 timestamp) | ||
45 | { | ||
46 | return __thread__set_comm(thread, comm, timestamp, false); | ||
47 | } | ||
48 | |||
42 | int thread__comm_len(struct thread *thread); | 49 | int thread__comm_len(struct thread *thread); |
43 | struct comm *thread__comm(const struct thread *thread); | 50 | struct comm *thread__comm(const struct thread *thread); |
51 | struct comm *thread__exec_comm(const struct thread *thread); | ||
44 | const char *thread__comm_str(const struct thread *thread); | 52 | const char *thread__comm_str(const struct thread *thread); |
45 | void thread__insert_map(struct thread *thread, struct map *map); | 53 | void thread__insert_map(struct thread *thread, struct map *map); |
46 | int thread__fork(struct thread *thread, struct thread *parent, u64 timestamp); | 54 | int thread__fork(struct thread *thread, struct thread *parent, u64 timestamp); |
diff --git a/tools/perf/util/tool.h b/tools/perf/util/tool.h index 4385816d3d49..f11636966a0f 100644 --- a/tools/perf/util/tool.h +++ b/tools/perf/util/tool.h | |||
@@ -40,7 +40,7 @@ struct perf_tool { | |||
40 | event_op2 tracing_data; | 40 | event_op2 tracing_data; |
41 | event_op2 finished_round, | 41 | event_op2 finished_round, |
42 | build_id; | 42 | build_id; |
43 | bool ordered_samples; | 43 | bool ordered_events; |
44 | bool ordering_requires_timestamps; | 44 | bool ordering_requires_timestamps; |
45 | }; | 45 | }; |
46 | 46 | ||
diff --git a/tools/perf/util/trace-event-scripting.c b/tools/perf/util/trace-event-scripting.c index 57aaccc1692e..5c9bdd1591a9 100644 --- a/tools/perf/util/trace-event-scripting.c +++ b/tools/perf/util/trace-event-scripting.c | |||
@@ -30,6 +30,11 @@ | |||
30 | 30 | ||
31 | struct scripting_context *scripting_context; | 31 | struct scripting_context *scripting_context; |
32 | 32 | ||
33 | static int flush_script_unsupported(void) | ||
34 | { | ||
35 | return 0; | ||
36 | } | ||
37 | |||
33 | static int stop_script_unsupported(void) | 38 | static int stop_script_unsupported(void) |
34 | { | 39 | { |
35 | return 0; | 40 | return 0; |
@@ -74,6 +79,7 @@ static int python_generate_script_unsupported(struct pevent *pevent | |||
74 | struct scripting_ops python_scripting_unsupported_ops = { | 79 | struct scripting_ops python_scripting_unsupported_ops = { |
75 | .name = "Python", | 80 | .name = "Python", |
76 | .start_script = python_start_script_unsupported, | 81 | .start_script = python_start_script_unsupported, |
82 | .flush_script = flush_script_unsupported, | ||
77 | .stop_script = stop_script_unsupported, | 83 | .stop_script = stop_script_unsupported, |
78 | .process_event = process_event_unsupported, | 84 | .process_event = process_event_unsupported, |
79 | .generate_script = python_generate_script_unsupported, | 85 | .generate_script = python_generate_script_unsupported, |
@@ -137,6 +143,7 @@ static int perl_generate_script_unsupported(struct pevent *pevent | |||
137 | struct scripting_ops perl_scripting_unsupported_ops = { | 143 | struct scripting_ops perl_scripting_unsupported_ops = { |
138 | .name = "Perl", | 144 | .name = "Perl", |
139 | .start_script = perl_start_script_unsupported, | 145 | .start_script = perl_start_script_unsupported, |
146 | .flush_script = flush_script_unsupported, | ||
140 | .stop_script = stop_script_unsupported, | 147 | .stop_script = stop_script_unsupported, |
141 | .process_event = process_event_unsupported, | 148 | .process_event = process_event_unsupported, |
142 | .generate_script = perl_generate_script_unsupported, | 149 | .generate_script = perl_generate_script_unsupported, |
diff --git a/tools/perf/util/trace-event.h b/tools/perf/util/trace-event.h index 7b6d68688327..52aaa19e1eb1 100644 --- a/tools/perf/util/trace-event.h +++ b/tools/perf/util/trace-event.h | |||
@@ -64,6 +64,7 @@ struct perf_session; | |||
64 | struct scripting_ops { | 64 | struct scripting_ops { |
65 | const char *name; | 65 | const char *name; |
66 | int (*start_script) (const char *script, int argc, const char **argv); | 66 | int (*start_script) (const char *script, int argc, const char **argv); |
67 | int (*flush_script) (void); | ||
67 | int (*stop_script) (void); | 68 | int (*stop_script) (void); |
68 | void (*process_event) (union perf_event *event, | 69 | void (*process_event) (union perf_event *event, |
69 | struct perf_sample *sample, | 70 | struct perf_sample *sample, |
diff --git a/tools/perf/util/util.c b/tools/perf/util/util.c index e52e7461911b..24e8d871b74e 100644 --- a/tools/perf/util/util.c +++ b/tools/perf/util/util.c | |||
@@ -13,6 +13,7 @@ | |||
13 | #include <limits.h> | 13 | #include <limits.h> |
14 | #include <byteswap.h> | 14 | #include <byteswap.h> |
15 | #include <linux/kernel.h> | 15 | #include <linux/kernel.h> |
16 | #include <unistd.h> | ||
16 | 17 | ||
17 | /* | 18 | /* |
18 | * XXX We need to find a better place for these things... | 19 | * XXX We need to find a better place for these things... |
@@ -282,6 +283,18 @@ void get_term_dimensions(struct winsize *ws) | |||
282 | ws->ws_col = 80; | 283 | ws->ws_col = 80; |
283 | } | 284 | } |
284 | 285 | ||
286 | void set_term_quiet_input(struct termios *old) | ||
287 | { | ||
288 | struct termios tc; | ||
289 | |||
290 | tcgetattr(0, old); | ||
291 | tc = *old; | ||
292 | tc.c_lflag &= ~(ICANON | ECHO); | ||
293 | tc.c_cc[VMIN] = 0; | ||
294 | tc.c_cc[VTIME] = 0; | ||
295 | tcsetattr(0, TCSANOW, &tc); | ||
296 | } | ||
297 | |||
285 | static void set_tracing_events_path(const char *mountpoint) | 298 | static void set_tracing_events_path(const char *mountpoint) |
286 | { | 299 | { |
287 | snprintf(tracing_events_path, sizeof(tracing_events_path), "%s/%s", | 300 | snprintf(tracing_events_path, sizeof(tracing_events_path), "%s/%s", |
@@ -443,6 +456,7 @@ int filename__read_str(const char *filename, char **buf, size_t *sizep) | |||
443 | size_t size = 0, alloc_size = 0; | 456 | size_t size = 0, alloc_size = 0; |
444 | void *bf = NULL, *nbf; | 457 | void *bf = NULL, *nbf; |
445 | int fd, n, err = 0; | 458 | int fd, n, err = 0; |
459 | char sbuf[STRERR_BUFSIZE]; | ||
446 | 460 | ||
447 | fd = open(filename, O_RDONLY); | 461 | fd = open(filename, O_RDONLY); |
448 | if (fd < 0) | 462 | if (fd < 0) |
@@ -463,8 +477,8 @@ int filename__read_str(const char *filename, char **buf, size_t *sizep) | |||
463 | n = read(fd, bf + size, alloc_size - size); | 477 | n = read(fd, bf + size, alloc_size - size); |
464 | if (n < 0) { | 478 | if (n < 0) { |
465 | if (size) { | 479 | if (size) { |
466 | pr_warning("read failed %d: %s\n", | 480 | pr_warning("read failed %d: %s\n", errno, |
467 | errno, strerror(errno)); | 481 | strerror_r(errno, sbuf, sizeof(sbuf))); |
468 | err = 0; | 482 | err = 0; |
469 | } else | 483 | } else |
470 | err = -errno; | 484 | err = -errno; |
@@ -536,3 +550,39 @@ void mem_bswap_64(void *src, int byte_size) | |||
536 | ++m; | 550 | ++m; |
537 | } | 551 | } |
538 | } | 552 | } |
553 | |||
554 | bool find_process(const char *name) | ||
555 | { | ||
556 | size_t len = strlen(name); | ||
557 | DIR *dir; | ||
558 | struct dirent *d; | ||
559 | int ret = -1; | ||
560 | |||
561 | dir = opendir(procfs__mountpoint()); | ||
562 | if (!dir) | ||
563 | return -1; | ||
564 | |||
565 | /* Walk through the directory. */ | ||
566 | while (ret && (d = readdir(dir)) != NULL) { | ||
567 | char path[PATH_MAX]; | ||
568 | char *data; | ||
569 | size_t size; | ||
570 | |||
571 | if ((d->d_type != DT_DIR) || | ||
572 | !strcmp(".", d->d_name) || | ||
573 | !strcmp("..", d->d_name)) | ||
574 | continue; | ||
575 | |||
576 | scnprintf(path, sizeof(path), "%s/%s/comm", | ||
577 | procfs__mountpoint(), d->d_name); | ||
578 | |||
579 | if (filename__read_str(path, &data, &size)) | ||
580 | continue; | ||
581 | |||
582 | ret = strncmp(name, data, len); | ||
583 | free(data); | ||
584 | } | ||
585 | |||
586 | closedir(dir); | ||
587 | return ret ? false : true; | ||
588 | } | ||
diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h index 66864364ccb4..80bfdaa0e2a4 100644 --- a/tools/perf/util/util.h +++ b/tools/perf/util/util.h | |||
@@ -39,6 +39,8 @@ | |||
39 | 39 | ||
40 | #define _ALL_SOURCE 1 | 40 | #define _ALL_SOURCE 1 |
41 | #define _BSD_SOURCE 1 | 41 | #define _BSD_SOURCE 1 |
42 | /* glibc 2.20 deprecates _BSD_SOURCE in favour of _DEFAULT_SOURCE */ | ||
43 | #define _DEFAULT_SOURCE 1 | ||
42 | #define HAS_BOOL | 44 | #define HAS_BOOL |
43 | 45 | ||
44 | #include <unistd.h> | 46 | #include <unistd.h> |
@@ -64,16 +66,18 @@ | |||
64 | #include <regex.h> | 66 | #include <regex.h> |
65 | #include <utime.h> | 67 | #include <utime.h> |
66 | #include <sys/wait.h> | 68 | #include <sys/wait.h> |
67 | #include <sys/poll.h> | 69 | #include <poll.h> |
68 | #include <sys/socket.h> | 70 | #include <sys/socket.h> |
69 | #include <sys/ioctl.h> | 71 | #include <sys/ioctl.h> |
70 | #include <inttypes.h> | 72 | #include <inttypes.h> |
73 | #include <linux/kernel.h> | ||
71 | #include <linux/magic.h> | 74 | #include <linux/magic.h> |
72 | #include <linux/types.h> | 75 | #include <linux/types.h> |
73 | #include <sys/ttydefaults.h> | 76 | #include <sys/ttydefaults.h> |
74 | #include <api/fs/debugfs.h> | 77 | #include <api/fs/debugfs.h> |
75 | #include <termios.h> | 78 | #include <termios.h> |
76 | #include <linux/bitops.h> | 79 | #include <linux/bitops.h> |
80 | #include <termios.h> | ||
77 | 81 | ||
78 | extern const char *graph_line; | 82 | extern const char *graph_line; |
79 | extern const char *graph_dotted_line; | 83 | extern const char *graph_dotted_line; |
@@ -307,6 +311,7 @@ extern unsigned int page_size; | |||
307 | extern int cacheline_size; | 311 | extern int cacheline_size; |
308 | 312 | ||
309 | void get_term_dimensions(struct winsize *ws); | 313 | void get_term_dimensions(struct winsize *ws); |
314 | void set_term_quiet_input(struct termios *old); | ||
310 | 315 | ||
311 | struct parse_tag { | 316 | struct parse_tag { |
312 | char tag; | 317 | char tag; |
@@ -317,6 +322,21 @@ unsigned long parse_tag_value(const char *str, struct parse_tag *tags); | |||
317 | 322 | ||
318 | #define SRCLINE_UNKNOWN ((char *) "??:0") | 323 | #define SRCLINE_UNKNOWN ((char *) "??:0") |
319 | 324 | ||
325 | static inline int path__join(char *bf, size_t size, | ||
326 | const char *path1, const char *path2) | ||
327 | { | ||
328 | return scnprintf(bf, size, "%s%s%s", path1, path1[0] ? "/" : "", path2); | ||
329 | } | ||
330 | |||
331 | static inline int path__join3(char *bf, size_t size, | ||
332 | const char *path1, const char *path2, | ||
333 | const char *path3) | ||
334 | { | ||
335 | return scnprintf(bf, size, "%s%s%s%s%s", | ||
336 | path1, path1[0] ? "/" : "", | ||
337 | path2, path2[0] ? "/" : "", path3); | ||
338 | } | ||
339 | |||
320 | struct dso; | 340 | struct dso; |
321 | 341 | ||
322 | char *get_srcline(struct dso *dso, unsigned long addr); | 342 | char *get_srcline(struct dso *dso, unsigned long addr); |
@@ -330,4 +350,5 @@ void mem_bswap_64(void *src, int byte_size); | |||
330 | void mem_bswap_32(void *src, int byte_size); | 350 | void mem_bswap_32(void *src, int byte_size); |
331 | 351 | ||
332 | const char *get_filename_for_perf_kvm(void); | 352 | const char *get_filename_for_perf_kvm(void); |
353 | bool find_process(const char *name); | ||
333 | #endif /* GIT_COMPAT_UTIL_H */ | 354 | #endif /* GIT_COMPAT_UTIL_H */ |