diff options
75 files changed, 1432 insertions, 788 deletions
@@ -1331,11 +1331,11 @@ kernelversion: | |||
1331 | # Clear a bunch of variables before executing the submake | 1331 | # Clear a bunch of variables before executing the submake |
1332 | tools/: FORCE | 1332 | tools/: FORCE |
1333 | $(Q)mkdir -p $(objtree)/tools | 1333 | $(Q)mkdir -p $(objtree)/tools |
1334 | $(Q)$(MAKE) LDFLAGS= MAKEFLAGS= O=$(objtree) subdir=tools -C $(src)/tools/ | 1334 | $(Q)$(MAKE) LDFLAGS= MAKEFLAGS="$(filter --j% -j,$(MAKEFLAGS))" O=$(objtree) subdir=tools -C $(src)/tools/ |
1335 | 1335 | ||
1336 | tools/%: FORCE | 1336 | tools/%: FORCE |
1337 | $(Q)mkdir -p $(objtree)/tools | 1337 | $(Q)mkdir -p $(objtree)/tools |
1338 | $(Q)$(MAKE) LDFLAGS= MAKEFLAGS= O=$(objtree) subdir=tools -C $(src)/tools/ $* | 1338 | $(Q)$(MAKE) LDFLAGS= MAKEFLAGS="$(filter --j% -j,$(MAKEFLAGS))" O=$(objtree) subdir=tools -C $(src)/tools/ $* |
1339 | 1339 | ||
1340 | # Single targets | 1340 | # Single targets |
1341 | # --------------------------------------------------------------------------- | 1341 | # --------------------------------------------------------------------------- |
diff --git a/tools/Makefile b/tools/Makefile index fa36565b209d..6aaeb6cd867d 100644 --- a/tools/Makefile +++ b/tools/Makefile | |||
@@ -34,7 +34,13 @@ help: | |||
34 | cpupower: FORCE | 34 | cpupower: FORCE |
35 | $(call descend,power/$@) | 35 | $(call descend,power/$@) |
36 | 36 | ||
37 | cgroup firewire lguest perf usb virtio vm: FORCE | 37 | cgroup firewire guest usb virtio vm: FORCE |
38 | $(call descend,$@) | ||
39 | |||
40 | liblk: FORCE | ||
41 | $(call descend,lib/lk) | ||
42 | |||
43 | perf: liblk FORCE | ||
38 | $(call descend,$@) | 44 | $(call descend,$@) |
39 | 45 | ||
40 | selftests: FORCE | 46 | selftests: FORCE |
@@ -62,7 +68,13 @@ install: cgroup_install cpupower_install firewire_install lguest_install \ | |||
62 | cpupower_clean: | 68 | cpupower_clean: |
63 | $(call descend,power/cpupower,clean) | 69 | $(call descend,power/cpupower,clean) |
64 | 70 | ||
65 | cgroup_clean firewire_clean lguest_clean perf_clean usb_clean virtio_clean vm_clean: | 71 | cgroup_clean firewire_clean lguest_clean usb_clean virtio_clean vm_clean: |
72 | $(call descend,$(@:_clean=),clean) | ||
73 | |||
74 | liblk_clean: | ||
75 | $(call descend,lib/lk,clean) | ||
76 | |||
77 | perf_clean: liblk_clean | ||
66 | $(call descend,$(@:_clean=),clean) | 78 | $(call descend,$(@:_clean=),clean) |
67 | 79 | ||
68 | selftests_clean: | 80 | selftests_clean: |
diff --git a/tools/lib/lk/Makefile b/tools/lib/lk/Makefile new file mode 100644 index 000000000000..926cbf3efc7f --- /dev/null +++ b/tools/lib/lk/Makefile | |||
@@ -0,0 +1,35 @@ | |||
1 | include ../../scripts/Makefile.include | ||
2 | |||
3 | # guard against environment variables | ||
4 | LIB_H= | ||
5 | LIB_OBJS= | ||
6 | |||
7 | LIB_H += debugfs.h | ||
8 | |||
9 | LIB_OBJS += $(OUTPUT)debugfs.o | ||
10 | |||
11 | LIBFILE = liblk.a | ||
12 | |||
13 | CFLAGS = -ggdb3 -Wall -Wextra -std=gnu99 -Werror -O6 -D_FORTIFY_SOURCE=2 $(EXTRA_WARNINGS) $(EXTRA_CFLAGS) -fPIC | ||
14 | EXTLIBS = -lpthread -lrt -lelf -lm | ||
15 | ALL_CFLAGS = $(CFLAGS) $(BASIC_CFLAGS) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 | ||
16 | ALL_LDFLAGS = $(LDFLAGS) | ||
17 | |||
18 | RM = rm -f | ||
19 | |||
20 | $(LIBFILE): $(LIB_OBJS) | ||
21 | $(QUIET_AR)$(RM) $@ && $(AR) rcs $(OUTPUT)$@ $(LIB_OBJS) | ||
22 | |||
23 | $(LIB_OBJS): $(LIB_H) | ||
24 | |||
25 | $(OUTPUT)%.o: %.c | ||
26 | $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) $< | ||
27 | $(OUTPUT)%.s: %.c | ||
28 | $(QUIET_CC)$(CC) -S $(ALL_CFLAGS) $< | ||
29 | $(OUTPUT)%.o: %.S | ||
30 | $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) $< | ||
31 | |||
32 | clean: | ||
33 | $(RM) $(LIB_OBJS) $(LIBFILE) | ||
34 | |||
35 | .PHONY: clean | ||
diff --git a/tools/perf/util/debugfs.c b/tools/lib/lk/debugfs.c index dd8b19319c03..099e7cd022e4 100644 --- a/tools/perf/util/debugfs.c +++ b/tools/lib/lk/debugfs.c | |||
@@ -1,36 +1,39 @@ | |||
1 | #include "util.h" | 1 | #include <errno.h> |
2 | #include "debugfs.h" | 2 | #include <stdio.h> |
3 | #include "cache.h" | 3 | #include <stdlib.h> |
4 | 4 | #include <string.h> | |
5 | #include <linux/kernel.h> | 5 | #include <stdbool.h> |
6 | #include <sys/vfs.h> | ||
6 | #include <sys/mount.h> | 7 | #include <sys/mount.h> |
8 | #include <linux/magic.h> | ||
9 | #include <linux/kernel.h> | ||
10 | |||
11 | #include "debugfs.h" | ||
7 | 12 | ||
8 | static int debugfs_premounted; | ||
9 | char debugfs_mountpoint[PATH_MAX + 1] = "/sys/kernel/debug"; | 13 | char debugfs_mountpoint[PATH_MAX + 1] = "/sys/kernel/debug"; |
10 | char tracing_events_path[PATH_MAX + 1] = "/sys/kernel/debug/tracing/events"; | ||
11 | 14 | ||
12 | static const char *debugfs_known_mountpoints[] = { | 15 | static const char * const debugfs_known_mountpoints[] = { |
13 | "/sys/kernel/debug/", | 16 | "/sys/kernel/debug/", |
14 | "/debug/", | 17 | "/debug/", |
15 | 0, | 18 | 0, |
16 | }; | 19 | }; |
17 | 20 | ||
18 | static int debugfs_found; | 21 | static bool debugfs_found; |
19 | 22 | ||
20 | /* find the path to the mounted debugfs */ | 23 | /* find the path to the mounted debugfs */ |
21 | const char *debugfs_find_mountpoint(void) | 24 | const char *debugfs_find_mountpoint(void) |
22 | { | 25 | { |
23 | const char **ptr; | 26 | const char * const *ptr; |
24 | char type[100]; | 27 | char type[100]; |
25 | FILE *fp; | 28 | FILE *fp; |
26 | 29 | ||
27 | if (debugfs_found) | 30 | if (debugfs_found) |
28 | return (const char *) debugfs_mountpoint; | 31 | return (const char *)debugfs_mountpoint; |
29 | 32 | ||
30 | ptr = debugfs_known_mountpoints; | 33 | ptr = debugfs_known_mountpoints; |
31 | while (*ptr) { | 34 | while (*ptr) { |
32 | if (debugfs_valid_mountpoint(*ptr) == 0) { | 35 | if (debugfs_valid_mountpoint(*ptr) == 0) { |
33 | debugfs_found = 1; | 36 | debugfs_found = true; |
34 | strcpy(debugfs_mountpoint, *ptr); | 37 | strcpy(debugfs_mountpoint, *ptr); |
35 | return debugfs_mountpoint; | 38 | return debugfs_mountpoint; |
36 | } | 39 | } |
@@ -52,7 +55,7 @@ const char *debugfs_find_mountpoint(void) | |||
52 | if (strcmp(type, "debugfs") != 0) | 55 | if (strcmp(type, "debugfs") != 0) |
53 | return NULL; | 56 | return NULL; |
54 | 57 | ||
55 | debugfs_found = 1; | 58 | debugfs_found = true; |
56 | 59 | ||
57 | return debugfs_mountpoint; | 60 | return debugfs_mountpoint; |
58 | } | 61 | } |
@@ -71,21 +74,12 @@ int debugfs_valid_mountpoint(const char *debugfs) | |||
71 | return 0; | 74 | return 0; |
72 | } | 75 | } |
73 | 76 | ||
74 | static void debugfs_set_tracing_events_path(const char *mountpoint) | ||
75 | { | ||
76 | snprintf(tracing_events_path, sizeof(tracing_events_path), "%s/%s", | ||
77 | mountpoint, "tracing/events"); | ||
78 | } | ||
79 | |||
80 | /* mount the debugfs somewhere if it's not mounted */ | 77 | /* mount the debugfs somewhere if it's not mounted */ |
81 | |||
82 | char *debugfs_mount(const char *mountpoint) | 78 | char *debugfs_mount(const char *mountpoint) |
83 | { | 79 | { |
84 | /* see if it's already mounted */ | 80 | /* see if it's already mounted */ |
85 | if (debugfs_find_mountpoint()) { | 81 | if (debugfs_find_mountpoint()) |
86 | debugfs_premounted = 1; | ||
87 | goto out; | 82 | goto out; |
88 | } | ||
89 | 83 | ||
90 | /* if not mounted and no argument */ | 84 | /* if not mounted and no argument */ |
91 | if (mountpoint == NULL) { | 85 | if (mountpoint == NULL) { |
@@ -100,15 +94,8 @@ char *debugfs_mount(const char *mountpoint) | |||
100 | return NULL; | 94 | return NULL; |
101 | 95 | ||
102 | /* save the mountpoint */ | 96 | /* save the mountpoint */ |
103 | debugfs_found = 1; | 97 | debugfs_found = true; |
104 | strncpy(debugfs_mountpoint, mountpoint, sizeof(debugfs_mountpoint)); | 98 | strncpy(debugfs_mountpoint, mountpoint, sizeof(debugfs_mountpoint)); |
105 | out: | 99 | out: |
106 | debugfs_set_tracing_events_path(debugfs_mountpoint); | ||
107 | return debugfs_mountpoint; | 100 | return debugfs_mountpoint; |
108 | } | 101 | } |
109 | |||
110 | void debugfs_set_path(const char *mountpoint) | ||
111 | { | ||
112 | snprintf(debugfs_mountpoint, sizeof(debugfs_mountpoint), "%s", mountpoint); | ||
113 | debugfs_set_tracing_events_path(mountpoint); | ||
114 | } | ||
diff --git a/tools/lib/lk/debugfs.h b/tools/lib/lk/debugfs.h new file mode 100644 index 000000000000..935c59bdb442 --- /dev/null +++ b/tools/lib/lk/debugfs.h | |||
@@ -0,0 +1,29 @@ | |||
1 | #ifndef __LK_DEBUGFS_H__ | ||
2 | #define __LK_DEBUGFS_H__ | ||
3 | |||
4 | #define _STR(x) #x | ||
5 | #define STR(x) _STR(x) | ||
6 | |||
7 | /* | ||
8 | * On most systems <limits.h> would have given us this, but not on some systems | ||
9 | * (e.g. GNU/Hurd). | ||
10 | */ | ||
11 | #ifndef PATH_MAX | ||
12 | #define PATH_MAX 4096 | ||
13 | #endif | ||
14 | |||
15 | #ifndef DEBUGFS_MAGIC | ||
16 | #define DEBUGFS_MAGIC 0x64626720 | ||
17 | #endif | ||
18 | |||
19 | #ifndef PERF_DEBUGFS_ENVIRONMENT | ||
20 | #define PERF_DEBUGFS_ENVIRONMENT "PERF_DEBUGFS_DIR" | ||
21 | #endif | ||
22 | |||
23 | const char *debugfs_find_mountpoint(void); | ||
24 | int debugfs_valid_mountpoint(const char *debugfs); | ||
25 | char *debugfs_mount(const char *mountpoint); | ||
26 | |||
27 | extern char debugfs_mountpoint[]; | ||
28 | |||
29 | #endif /* __LK_DEBUGFS_H__ */ | ||
diff --git a/tools/perf/Documentation/perf-annotate.txt b/tools/perf/Documentation/perf-annotate.txt index 5ad07ef417f0..e9cd39a92dc2 100644 --- a/tools/perf/Documentation/perf-annotate.txt +++ b/tools/perf/Documentation/perf-annotate.txt | |||
@@ -93,6 +93,9 @@ OPTIONS | |||
93 | --skip-missing:: | 93 | --skip-missing:: |
94 | Skip symbols that cannot be annotated. | 94 | Skip symbols that cannot be annotated. |
95 | 95 | ||
96 | --group:: | ||
97 | Show event group information together | ||
98 | |||
96 | SEE ALSO | 99 | SEE ALSO |
97 | -------- | 100 | -------- |
98 | linkperf:perf-record[1], linkperf:perf-report[1] | 101 | linkperf:perf-record[1], linkperf:perf-report[1] |
diff --git a/tools/perf/Documentation/perf-stat.txt b/tools/perf/Documentation/perf-stat.txt index faf4f4feebcc..23e587ad549e 100644 --- a/tools/perf/Documentation/perf-stat.txt +++ b/tools/perf/Documentation/perf-stat.txt | |||
@@ -52,7 +52,7 @@ OPTIONS | |||
52 | 52 | ||
53 | -r:: | 53 | -r:: |
54 | --repeat=<n>:: | 54 | --repeat=<n>:: |
55 | repeat command and print average + stddev (max: 100) | 55 | repeat command and print average + stddev (max: 100). 0 means forever. |
56 | 56 | ||
57 | -B:: | 57 | -B:: |
58 | --big-num:: | 58 | --big-num:: |
diff --git a/tools/perf/MANIFEST b/tools/perf/MANIFEST index 39d41068484f..025de796067c 100644 --- a/tools/perf/MANIFEST +++ b/tools/perf/MANIFEST | |||
@@ -1,6 +1,7 @@ | |||
1 | tools/perf | 1 | tools/perf |
2 | tools/scripts | 2 | tools/scripts |
3 | tools/lib/traceevent | 3 | tools/lib/traceevent |
4 | tools/lib/lk | ||
4 | include/linux/const.h | 5 | include/linux/const.h |
5 | include/linux/perf_event.h | 6 | include/linux/perf_event.h |
6 | include/linux/rbtree.h | 7 | include/linux/rbtree.h |
diff --git a/tools/perf/Makefile b/tools/perf/Makefile index bb74c79cd16e..0230b75ed7f9 100644 --- a/tools/perf/Makefile +++ b/tools/perf/Makefile | |||
@@ -215,6 +215,7 @@ BASIC_CFLAGS = \ | |||
215 | -Iutil \ | 215 | -Iutil \ |
216 | -I. \ | 216 | -I. \ |
217 | -I$(TRACE_EVENT_DIR) \ | 217 | -I$(TRACE_EVENT_DIR) \ |
218 | -I../lib/ \ | ||
218 | -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE | 219 | -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE |
219 | 220 | ||
220 | BASIC_LDFLAGS = | 221 | BASIC_LDFLAGS = |
@@ -240,19 +241,28 @@ SCRIPT_SH += perf-archive.sh | |||
240 | grep-libs = $(filter -l%,$(1)) | 241 | grep-libs = $(filter -l%,$(1)) |
241 | strip-libs = $(filter-out -l%,$(1)) | 242 | strip-libs = $(filter-out -l%,$(1)) |
242 | 243 | ||
244 | LK_DIR = ../lib/lk/ | ||
243 | TRACE_EVENT_DIR = ../lib/traceevent/ | 245 | TRACE_EVENT_DIR = ../lib/traceevent/ |
244 | 246 | ||
247 | LK_PATH=$(LK_DIR) | ||
248 | |||
245 | ifneq ($(OUTPUT),) | 249 | ifneq ($(OUTPUT),) |
246 | TE_PATH=$(OUTPUT) | 250 | TE_PATH=$(OUTPUT) |
251 | ifneq ($(subdir),) | ||
252 | LK_PATH=$(OUTPUT)$(LK_DIR) | ||
253 | else | ||
254 | LK_PATH=$(OUTPUT) | ||
255 | endif | ||
247 | else | 256 | else |
248 | TE_PATH=$(TRACE_EVENT_DIR) | 257 | TE_PATH=$(TRACE_EVENT_DIR) |
249 | endif | 258 | endif |
250 | 259 | ||
251 | LIBTRACEEVENT = $(TE_PATH)libtraceevent.a | 260 | LIBTRACEEVENT = $(TE_PATH)libtraceevent.a |
252 | TE_LIB := -L$(TE_PATH) -ltraceevent | ||
253 | |||
254 | export LIBTRACEEVENT | 261 | export LIBTRACEEVENT |
255 | 262 | ||
263 | LIBLK = $(LK_PATH)liblk.a | ||
264 | export LIBLK | ||
265 | |||
256 | # python extension build directories | 266 | # python extension build directories |
257 | PYTHON_EXTBUILD := $(OUTPUT)python_ext_build/ | 267 | PYTHON_EXTBUILD := $(OUTPUT)python_ext_build/ |
258 | PYTHON_EXTBUILD_LIB := $(PYTHON_EXTBUILD)lib/ | 268 | PYTHON_EXTBUILD_LIB := $(PYTHON_EXTBUILD)lib/ |
@@ -355,7 +365,6 @@ LIB_H += util/cache.h | |||
355 | LIB_H += util/callchain.h | 365 | LIB_H += util/callchain.h |
356 | LIB_H += util/build-id.h | 366 | LIB_H += util/build-id.h |
357 | LIB_H += util/debug.h | 367 | LIB_H += util/debug.h |
358 | LIB_H += util/debugfs.h | ||
359 | LIB_H += util/sysfs.h | 368 | LIB_H += util/sysfs.h |
360 | LIB_H += util/pmu.h | 369 | LIB_H += util/pmu.h |
361 | LIB_H += util/event.h | 370 | LIB_H += util/event.h |
@@ -416,7 +425,6 @@ LIB_OBJS += $(OUTPUT)util/annotate.o | |||
416 | LIB_OBJS += $(OUTPUT)util/build-id.o | 425 | LIB_OBJS += $(OUTPUT)util/build-id.o |
417 | LIB_OBJS += $(OUTPUT)util/config.o | 426 | LIB_OBJS += $(OUTPUT)util/config.o |
418 | LIB_OBJS += $(OUTPUT)util/ctype.o | 427 | LIB_OBJS += $(OUTPUT)util/ctype.o |
419 | LIB_OBJS += $(OUTPUT)util/debugfs.o | ||
420 | LIB_OBJS += $(OUTPUT)util/sysfs.o | 428 | LIB_OBJS += $(OUTPUT)util/sysfs.o |
421 | LIB_OBJS += $(OUTPUT)util/pmu.o | 429 | LIB_OBJS += $(OUTPUT)util/pmu.o |
422 | LIB_OBJS += $(OUTPUT)util/environment.o | 430 | LIB_OBJS += $(OUTPUT)util/environment.o |
@@ -503,6 +511,10 @@ LIB_OBJS += $(OUTPUT)tests/evsel-tp-sched.o | |||
503 | LIB_OBJS += $(OUTPUT)tests/pmu.o | 511 | LIB_OBJS += $(OUTPUT)tests/pmu.o |
504 | LIB_OBJS += $(OUTPUT)tests/hists_link.o | 512 | LIB_OBJS += $(OUTPUT)tests/hists_link.o |
505 | LIB_OBJS += $(OUTPUT)tests/python-use.o | 513 | LIB_OBJS += $(OUTPUT)tests/python-use.o |
514 | LIB_OBJS += $(OUTPUT)tests/bp_signal.o | ||
515 | LIB_OBJS += $(OUTPUT)tests/bp_signal_overflow.o | ||
516 | LIB_OBJS += $(OUTPUT)tests/task-exit.o | ||
517 | LIB_OBJS += $(OUTPUT)tests/sw-clock.o | ||
506 | 518 | ||
507 | BUILTIN_OBJS += $(OUTPUT)builtin-annotate.o | 519 | BUILTIN_OBJS += $(OUTPUT)builtin-annotate.o |
508 | BUILTIN_OBJS += $(OUTPUT)builtin-bench.o | 520 | BUILTIN_OBJS += $(OUTPUT)builtin-bench.o |
@@ -536,7 +548,7 @@ BUILTIN_OBJS += $(OUTPUT)builtin-kvm.o | |||
536 | BUILTIN_OBJS += $(OUTPUT)builtin-inject.o | 548 | BUILTIN_OBJS += $(OUTPUT)builtin-inject.o |
537 | BUILTIN_OBJS += $(OUTPUT)tests/builtin-test.o | 549 | BUILTIN_OBJS += $(OUTPUT)tests/builtin-test.o |
538 | 550 | ||
539 | PERFLIBS = $(LIB_FILE) $(LIBTRACEEVENT) | 551 | PERFLIBS = $(LIB_FILE) $(LIBLK) $(LIBTRACEEVENT) |
540 | 552 | ||
541 | # | 553 | # |
542 | # Platform specific tweaks | 554 | # Platform specific tweaks |
@@ -1051,6 +1063,18 @@ $(LIBTRACEEVENT): | |||
1051 | $(LIBTRACEEVENT)-clean: | 1063 | $(LIBTRACEEVENT)-clean: |
1052 | $(QUIET_SUBDIR0)$(TRACE_EVENT_DIR) $(QUIET_SUBDIR1) O=$(OUTPUT) clean | 1064 | $(QUIET_SUBDIR0)$(TRACE_EVENT_DIR) $(QUIET_SUBDIR1) O=$(OUTPUT) clean |
1053 | 1065 | ||
1066 | # if subdir is set, we've been called from above so target has been built | ||
1067 | # already | ||
1068 | $(LIBLK): | ||
1069 | ifeq ($(subdir),) | ||
1070 | $(QUIET_SUBDIR0)$(LK_DIR) $(QUIET_SUBDIR1) O=$(OUTPUT) liblk.a | ||
1071 | endif | ||
1072 | |||
1073 | $(LIBLK)-clean: | ||
1074 | ifeq ($(subdir),) | ||
1075 | $(QUIET_SUBDIR0)$(LK_DIR) $(QUIET_SUBDIR1) O=$(OUTPUT) clean | ||
1076 | endif | ||
1077 | |||
1054 | help: | 1078 | help: |
1055 | @echo 'Perf make targets:' | 1079 | @echo 'Perf make targets:' |
1056 | @echo ' doc - make *all* documentation (see below)' | 1080 | @echo ' doc - make *all* documentation (see below)' |
@@ -1171,7 +1195,7 @@ $(INSTALL_DOC_TARGETS): | |||
1171 | 1195 | ||
1172 | ### Cleaning rules | 1196 | ### Cleaning rules |
1173 | 1197 | ||
1174 | clean: $(LIBTRACEEVENT)-clean | 1198 | clean: $(LIBTRACEEVENT)-clean $(LIBLK)-clean |
1175 | $(RM) $(LIB_OBJS) $(BUILTIN_OBJS) $(LIB_FILE) $(OUTPUT)perf-archive $(OUTPUT)perf.o $(LANG_BINDINGS) | 1199 | $(RM) $(LIB_OBJS) $(BUILTIN_OBJS) $(LIB_FILE) $(OUTPUT)perf-archive $(OUTPUT)perf.o $(LANG_BINDINGS) |
1176 | $(RM) $(ALL_PROGRAMS) perf | 1200 | $(RM) $(ALL_PROGRAMS) perf |
1177 | $(RM) *.spec *.pyc *.pyo */*.pyc */*.pyo $(OUTPUT)common-cmds.h TAGS tags cscope* | 1201 | $(RM) *.spec *.pyc *.pyo */*.pyc */*.pyo $(OUTPUT)common-cmds.h TAGS tags cscope* |
@@ -1181,6 +1205,6 @@ clean: $(LIBTRACEEVENT)-clean | |||
1181 | $(RM) $(OUTPUT)util/*-flex* | 1205 | $(RM) $(OUTPUT)util/*-flex* |
1182 | $(python-clean) | 1206 | $(python-clean) |
1183 | 1207 | ||
1184 | .PHONY: all install clean strip $(LIBTRACEEVENT) | 1208 | .PHONY: all install clean strip $(LIBTRACEEVENT) $(LIBLK) |
1185 | .PHONY: shell_compatibility_test please_set_SHELL_PATH_to_a_more_modern_shell | 1209 | .PHONY: shell_compatibility_test please_set_SHELL_PATH_to_a_more_modern_shell |
1186 | .PHONY: .FORCE-PERF-VERSION-FILE TAGS tags cscope .FORCE-PERF-CFLAGS | 1210 | .PHONY: .FORCE-PERF-VERSION-FILE TAGS tags cscope .FORCE-PERF-CFLAGS |
diff --git a/tools/perf/arch/arm/util/dwarf-regs.c b/tools/perf/arch/arm/util/dwarf-regs.c index e8d5c551c69c..33ec5b339da8 100644 --- a/tools/perf/arch/arm/util/dwarf-regs.c +++ b/tools/perf/arch/arm/util/dwarf-regs.c | |||
@@ -8,10 +8,7 @@ | |||
8 | * published by the Free Software Foundation. | 8 | * published by the Free Software Foundation. |
9 | */ | 9 | */ |
10 | 10 | ||
11 | #include <stdlib.h> | 11 | #include <stddef.h> |
12 | #ifndef __UCLIBC__ | ||
13 | #include <libio.h> | ||
14 | #endif | ||
15 | #include <dwarf-regs.h> | 12 | #include <dwarf-regs.h> |
16 | 13 | ||
17 | struct pt_regs_dwarfnum { | 14 | struct pt_regs_dwarfnum { |
diff --git a/tools/perf/arch/powerpc/util/dwarf-regs.c b/tools/perf/arch/powerpc/util/dwarf-regs.c index 7cdd61d0e27c..733151cdf46e 100644 --- a/tools/perf/arch/powerpc/util/dwarf-regs.c +++ b/tools/perf/arch/powerpc/util/dwarf-regs.c | |||
@@ -9,10 +9,7 @@ | |||
9 | * 2 of the License, or (at your option) any later version. | 9 | * 2 of the License, or (at your option) any later version. |
10 | */ | 10 | */ |
11 | 11 | ||
12 | #include <stdlib.h> | 12 | #include <stddef.h> |
13 | #ifndef __UCLIBC__ | ||
14 | #include <libio.h> | ||
15 | #endif | ||
16 | #include <dwarf-regs.h> | 13 | #include <dwarf-regs.h> |
17 | 14 | ||
18 | 15 | ||
diff --git a/tools/perf/arch/s390/util/dwarf-regs.c b/tools/perf/arch/s390/util/dwarf-regs.c index e19653e025fa..0469df02ee62 100644 --- a/tools/perf/arch/s390/util/dwarf-regs.c +++ b/tools/perf/arch/s390/util/dwarf-regs.c | |||
@@ -6,7 +6,7 @@ | |||
6 | * | 6 | * |
7 | */ | 7 | */ |
8 | 8 | ||
9 | #include <libio.h> | 9 | #include <stddef.h> |
10 | #include <dwarf-regs.h> | 10 | #include <dwarf-regs.h> |
11 | 11 | ||
12 | #define NUM_GPRS 16 | 12 | #define NUM_GPRS 16 |
diff --git a/tools/perf/arch/sh/util/dwarf-regs.c b/tools/perf/arch/sh/util/dwarf-regs.c index a11edb007a6c..0d0897f57a10 100644 --- a/tools/perf/arch/sh/util/dwarf-regs.c +++ b/tools/perf/arch/sh/util/dwarf-regs.c | |||
@@ -19,7 +19,7 @@ | |||
19 | * | 19 | * |
20 | */ | 20 | */ |
21 | 21 | ||
22 | #include <libio.h> | 22 | #include <stddef.h> |
23 | #include <dwarf-regs.h> | 23 | #include <dwarf-regs.h> |
24 | 24 | ||
25 | /* | 25 | /* |
diff --git a/tools/perf/arch/sparc/util/dwarf-regs.c b/tools/perf/arch/sparc/util/dwarf-regs.c index 0ab88483720c..92eda412fed3 100644 --- a/tools/perf/arch/sparc/util/dwarf-regs.c +++ b/tools/perf/arch/sparc/util/dwarf-regs.c | |||
@@ -9,7 +9,7 @@ | |||
9 | * 2 of the License, or (at your option) any later version. | 9 | * 2 of the License, or (at your option) any later version. |
10 | */ | 10 | */ |
11 | 11 | ||
12 | #include <libio.h> | 12 | #include <stddef.h> |
13 | #include <dwarf-regs.h> | 13 | #include <dwarf-regs.h> |
14 | 14 | ||
15 | #define SPARC_MAX_REGS 96 | 15 | #define SPARC_MAX_REGS 96 |
diff --git a/tools/perf/arch/x86/util/dwarf-regs.c b/tools/perf/arch/x86/util/dwarf-regs.c index a794d3081928..be22dd463232 100644 --- a/tools/perf/arch/x86/util/dwarf-regs.c +++ b/tools/perf/arch/x86/util/dwarf-regs.c | |||
@@ -20,7 +20,7 @@ | |||
20 | * | 20 | * |
21 | */ | 21 | */ |
22 | 22 | ||
23 | #include <libio.h> | 23 | #include <stddef.h> |
24 | #include <dwarf-regs.h> | 24 | #include <dwarf-regs.h> |
25 | 25 | ||
26 | /* | 26 | /* |
diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c index 2e6961ea3184..ae36f3cb5410 100644 --- a/tools/perf/builtin-annotate.c +++ b/tools/perf/builtin-annotate.c | |||
@@ -109,14 +109,16 @@ static int process_sample_event(struct perf_tool *tool, | |||
109 | return 0; | 109 | return 0; |
110 | } | 110 | } |
111 | 111 | ||
112 | static int hist_entry__tty_annotate(struct hist_entry *he, int evidx, | 112 | static int hist_entry__tty_annotate(struct hist_entry *he, |
113 | struct perf_evsel *evsel, | ||
113 | struct perf_annotate *ann) | 114 | struct perf_annotate *ann) |
114 | { | 115 | { |
115 | return symbol__tty_annotate(he->ms.sym, he->ms.map, evidx, | 116 | return symbol__tty_annotate(he->ms.sym, he->ms.map, evsel, |
116 | ann->print_line, ann->full_paths, 0, 0); | 117 | ann->print_line, ann->full_paths, 0, 0); |
117 | } | 118 | } |
118 | 119 | ||
119 | static void hists__find_annotations(struct hists *self, int evidx, | 120 | static void hists__find_annotations(struct hists *self, |
121 | struct perf_evsel *evsel, | ||
120 | struct perf_annotate *ann) | 122 | struct perf_annotate *ann) |
121 | { | 123 | { |
122 | struct rb_node *nd = rb_first(&self->entries), *next; | 124 | struct rb_node *nd = rb_first(&self->entries), *next; |
@@ -142,14 +144,14 @@ find_next: | |||
142 | if (use_browser == 2) { | 144 | if (use_browser == 2) { |
143 | int ret; | 145 | int ret; |
144 | 146 | ||
145 | ret = hist_entry__gtk_annotate(he, evidx, NULL); | 147 | ret = hist_entry__gtk_annotate(he, evsel, NULL); |
146 | if (!ret || !ann->skip_missing) | 148 | if (!ret || !ann->skip_missing) |
147 | return; | 149 | return; |
148 | 150 | ||
149 | /* skip missing symbols */ | 151 | /* skip missing symbols */ |
150 | nd = rb_next(nd); | 152 | nd = rb_next(nd); |
151 | } else if (use_browser == 1) { | 153 | } else if (use_browser == 1) { |
152 | key = hist_entry__tui_annotate(he, evidx, NULL); | 154 | key = hist_entry__tui_annotate(he, evsel, NULL); |
153 | switch (key) { | 155 | switch (key) { |
154 | case -1: | 156 | case -1: |
155 | if (!ann->skip_missing) | 157 | if (!ann->skip_missing) |
@@ -168,7 +170,7 @@ find_next: | |||
168 | if (next != NULL) | 170 | if (next != NULL) |
169 | nd = next; | 171 | nd = next; |
170 | } else { | 172 | } else { |
171 | hist_entry__tty_annotate(he, evidx, ann); | 173 | hist_entry__tty_annotate(he, evsel, ann); |
172 | nd = rb_next(nd); | 174 | nd = rb_next(nd); |
173 | /* | 175 | /* |
174 | * Since we have a hist_entry per IP for the same | 176 | * Since we have a hist_entry per IP for the same |
@@ -230,7 +232,12 @@ static int __cmd_annotate(struct perf_annotate *ann) | |||
230 | total_nr_samples += nr_samples; | 232 | total_nr_samples += nr_samples; |
231 | hists__collapse_resort(hists); | 233 | hists__collapse_resort(hists); |
232 | hists__output_resort(hists); | 234 | hists__output_resort(hists); |
233 | hists__find_annotations(hists, pos->idx, ann); | 235 | |
236 | if (symbol_conf.event_group && | ||
237 | !perf_evsel__is_group_leader(pos)) | ||
238 | continue; | ||
239 | |||
240 | hists__find_annotations(hists, pos, ann); | ||
234 | } | 241 | } |
235 | } | 242 | } |
236 | 243 | ||
@@ -312,6 +319,8 @@ int cmd_annotate(int argc, const char **argv, const char *prefix __maybe_unused) | |||
312 | "Specify disassembler style (e.g. -M intel for intel syntax)"), | 319 | "Specify disassembler style (e.g. -M intel for intel syntax)"), |
313 | OPT_STRING(0, "objdump", &objdump_path, "path", | 320 | OPT_STRING(0, "objdump", &objdump_path, "path", |
314 | "objdump binary to use for disassembly and annotations"), | 321 | "objdump binary to use for disassembly and annotations"), |
322 | OPT_BOOLEAN(0, "group", &symbol_conf.event_group, | ||
323 | "Show event group information together"), | ||
315 | OPT_END() | 324 | OPT_END() |
316 | }; | 325 | }; |
317 | 326 | ||
diff --git a/tools/perf/builtin-kvm.c b/tools/perf/builtin-kvm.c index 37a769d7f9fe..533501e2b07c 100644 --- a/tools/perf/builtin-kvm.c +++ b/tools/perf/builtin-kvm.c | |||
@@ -12,7 +12,7 @@ | |||
12 | #include "util/parse-options.h" | 12 | #include "util/parse-options.h" |
13 | #include "util/trace-event.h" | 13 | #include "util/trace-event.h" |
14 | #include "util/debug.h" | 14 | #include "util/debug.h" |
15 | #include "util/debugfs.h" | 15 | #include <lk/debugfs.h> |
16 | #include "util/tool.h" | 16 | #include "util/tool.h" |
17 | #include "util/stat.h" | 17 | #include "util/stat.h" |
18 | 18 | ||
diff --git a/tools/perf/builtin-probe.c b/tools/perf/builtin-probe.c index de38a034b129..e8a66f9a6715 100644 --- a/tools/perf/builtin-probe.c +++ b/tools/perf/builtin-probe.c | |||
@@ -37,7 +37,7 @@ | |||
37 | #include "util/strfilter.h" | 37 | #include "util/strfilter.h" |
38 | #include "util/symbol.h" | 38 | #include "util/symbol.h" |
39 | #include "util/debug.h" | 39 | #include "util/debug.h" |
40 | #include "util/debugfs.h" | 40 | #include <lk/debugfs.h> |
41 | #include "util/parse-options.h" | 41 | #include "util/parse-options.h" |
42 | #include "util/probe-finder.h" | 42 | #include "util/probe-finder.h" |
43 | #include "util/probe-event.h" | 43 | #include "util/probe-event.h" |
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index f1a939ebc19c..9f2344a2c506 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c | |||
@@ -474,7 +474,9 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv) | |||
474 | } | 474 | } |
475 | 475 | ||
476 | if (forks) { | 476 | if (forks) { |
477 | err = perf_evlist__prepare_workload(evsel_list, opts, argv); | 477 | err = perf_evlist__prepare_workload(evsel_list, &opts->target, |
478 | argv, opts->pipe_output, | ||
479 | true); | ||
478 | if (err < 0) { | 480 | if (err < 0) { |
479 | pr_err("Couldn't run the workload!\n"); | 481 | pr_err("Couldn't run the workload!\n"); |
480 | goto out_delete_session; | 482 | goto out_delete_session; |
@@ -964,7 +966,7 @@ int cmd_record(int argc, const char **argv, const char *prefix __maybe_unused) | |||
964 | struct perf_record *rec = &record; | 966 | struct perf_record *rec = &record; |
965 | char errbuf[BUFSIZ]; | 967 | char errbuf[BUFSIZ]; |
966 | 968 | ||
967 | evsel_list = perf_evlist__new(NULL, NULL); | 969 | evsel_list = perf_evlist__new(); |
968 | if (evsel_list == NULL) | 970 | if (evsel_list == NULL) |
969 | return -ENOMEM; | 971 | return -ENOMEM; |
970 | 972 | ||
@@ -1026,7 +1028,7 @@ int cmd_record(int argc, const char **argv, const char *prefix __maybe_unused) | |||
1026 | ui__error("%s", errbuf); | 1028 | ui__error("%s", errbuf); |
1027 | 1029 | ||
1028 | err = -saved_errno; | 1030 | err = -saved_errno; |
1029 | goto out_free_fd; | 1031 | goto out_symbol_exit; |
1030 | } | 1032 | } |
1031 | 1033 | ||
1032 | err = -ENOMEM; | 1034 | err = -ENOMEM; |
@@ -1057,6 +1059,9 @@ int cmd_record(int argc, const char **argv, const char *prefix __maybe_unused) | |||
1057 | } | 1059 | } |
1058 | 1060 | ||
1059 | err = __cmd_record(&record, argc, argv); | 1061 | err = __cmd_record(&record, argc, argv); |
1062 | |||
1063 | perf_evlist__munmap(evsel_list); | ||
1064 | perf_evlist__close(evsel_list); | ||
1060 | out_free_fd: | 1065 | out_free_fd: |
1061 | perf_evlist__delete_maps(evsel_list); | 1066 | perf_evlist__delete_maps(evsel_list); |
1062 | out_symbol_exit: | 1067 | out_symbol_exit: |
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index 96b5a7fee4bb..296bd219977a 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c | |||
@@ -13,7 +13,6 @@ | |||
13 | #include "util/annotate.h" | 13 | #include "util/annotate.h" |
14 | #include "util/color.h" | 14 | #include "util/color.h" |
15 | #include <linux/list.h> | 15 | #include <linux/list.h> |
16 | #include "util/cache.h" | ||
17 | #include <linux/rbtree.h> | 16 | #include <linux/rbtree.h> |
18 | #include "util/symbol.h" | 17 | #include "util/symbol.h" |
19 | #include "util/callchain.h" | 18 | #include "util/callchain.h" |
@@ -314,7 +313,7 @@ static size_t hists__fprintf_nr_sample_events(struct hists *self, | |||
314 | char buf[512]; | 313 | char buf[512]; |
315 | size_t size = sizeof(buf); | 314 | size_t size = sizeof(buf); |
316 | 315 | ||
317 | if (symbol_conf.event_group && evsel->nr_members > 1) { | 316 | if (perf_evsel__is_group_event(evsel)) { |
318 | struct perf_evsel *pos; | 317 | struct perf_evsel *pos; |
319 | 318 | ||
320 | perf_evsel__group_desc(evsel, buf, size); | 319 | perf_evsel__group_desc(evsel, buf, size); |
diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index 99848761f573..ba0bdd87c279 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c | |||
@@ -94,6 +94,7 @@ static const char *pre_cmd = NULL; | |||
94 | static const char *post_cmd = NULL; | 94 | static const char *post_cmd = NULL; |
95 | static bool sync_run = false; | 95 | static bool sync_run = false; |
96 | static unsigned int interval = 0; | 96 | static unsigned int interval = 0; |
97 | static bool forever = false; | ||
97 | static struct timespec ref_time; | 98 | static struct timespec ref_time; |
98 | static struct cpu_map *sock_map; | 99 | static struct cpu_map *sock_map; |
99 | 100 | ||
@@ -125,6 +126,11 @@ static inline int perf_evsel__nr_cpus(struct perf_evsel *evsel) | |||
125 | return perf_evsel__cpus(evsel)->nr; | 126 | return perf_evsel__cpus(evsel)->nr; |
126 | } | 127 | } |
127 | 128 | ||
129 | static void perf_evsel__reset_stat_priv(struct perf_evsel *evsel) | ||
130 | { | ||
131 | memset(evsel->priv, 0, sizeof(struct perf_stat)); | ||
132 | } | ||
133 | |||
128 | static int perf_evsel__alloc_stat_priv(struct perf_evsel *evsel) | 134 | static int perf_evsel__alloc_stat_priv(struct perf_evsel *evsel) |
129 | { | 135 | { |
130 | evsel->priv = zalloc(sizeof(struct perf_stat)); | 136 | evsel->priv = zalloc(sizeof(struct perf_stat)); |
@@ -160,6 +166,35 @@ static void perf_evsel__free_prev_raw_counts(struct perf_evsel *evsel) | |||
160 | evsel->prev_raw_counts = NULL; | 166 | evsel->prev_raw_counts = NULL; |
161 | } | 167 | } |
162 | 168 | ||
169 | static void perf_evlist__free_stats(struct perf_evlist *evlist) | ||
170 | { | ||
171 | struct perf_evsel *evsel; | ||
172 | |||
173 | list_for_each_entry(evsel, &evlist->entries, node) { | ||
174 | perf_evsel__free_stat_priv(evsel); | ||
175 | perf_evsel__free_counts(evsel); | ||
176 | perf_evsel__free_prev_raw_counts(evsel); | ||
177 | } | ||
178 | } | ||
179 | |||
180 | static int perf_evlist__alloc_stats(struct perf_evlist *evlist, bool alloc_raw) | ||
181 | { | ||
182 | struct perf_evsel *evsel; | ||
183 | |||
184 | list_for_each_entry(evsel, &evlist->entries, node) { | ||
185 | if (perf_evsel__alloc_stat_priv(evsel) < 0 || | ||
186 | perf_evsel__alloc_counts(evsel, perf_evsel__nr_cpus(evsel)) < 0 || | ||
187 | (alloc_raw && perf_evsel__alloc_prev_raw_counts(evsel) < 0)) | ||
188 | goto out_free; | ||
189 | } | ||
190 | |||
191 | return 0; | ||
192 | |||
193 | out_free: | ||
194 | perf_evlist__free_stats(evlist); | ||
195 | return -1; | ||
196 | } | ||
197 | |||
163 | static struct stats runtime_nsecs_stats[MAX_NR_CPUS]; | 198 | static struct stats runtime_nsecs_stats[MAX_NR_CPUS]; |
164 | static struct stats runtime_cycles_stats[MAX_NR_CPUS]; | 199 | static struct stats runtime_cycles_stats[MAX_NR_CPUS]; |
165 | static struct stats runtime_stalled_cycles_front_stats[MAX_NR_CPUS]; | 200 | static struct stats runtime_stalled_cycles_front_stats[MAX_NR_CPUS]; |
@@ -173,6 +208,29 @@ static struct stats runtime_itlb_cache_stats[MAX_NR_CPUS]; | |||
173 | static struct stats runtime_dtlb_cache_stats[MAX_NR_CPUS]; | 208 | static struct stats runtime_dtlb_cache_stats[MAX_NR_CPUS]; |
174 | static struct stats walltime_nsecs_stats; | 209 | static struct stats walltime_nsecs_stats; |
175 | 210 | ||
211 | static void perf_stat__reset_stats(struct perf_evlist *evlist) | ||
212 | { | ||
213 | struct perf_evsel *evsel; | ||
214 | |||
215 | list_for_each_entry(evsel, &evlist->entries, node) { | ||
216 | perf_evsel__reset_stat_priv(evsel); | ||
217 | perf_evsel__reset_counts(evsel, perf_evsel__nr_cpus(evsel)); | ||
218 | } | ||
219 | |||
220 | memset(runtime_nsecs_stats, 0, sizeof(runtime_nsecs_stats)); | ||
221 | memset(runtime_cycles_stats, 0, sizeof(runtime_cycles_stats)); | ||
222 | memset(runtime_stalled_cycles_front_stats, 0, sizeof(runtime_stalled_cycles_front_stats)); | ||
223 | memset(runtime_stalled_cycles_back_stats, 0, sizeof(runtime_stalled_cycles_back_stats)); | ||
224 | memset(runtime_branches_stats, 0, sizeof(runtime_branches_stats)); | ||
225 | memset(runtime_cacherefs_stats, 0, sizeof(runtime_cacherefs_stats)); | ||
226 | memset(runtime_l1_dcache_stats, 0, sizeof(runtime_l1_dcache_stats)); | ||
227 | memset(runtime_l1_icache_stats, 0, sizeof(runtime_l1_icache_stats)); | ||
228 | memset(runtime_ll_cache_stats, 0, sizeof(runtime_ll_cache_stats)); | ||
229 | memset(runtime_itlb_cache_stats, 0, sizeof(runtime_itlb_cache_stats)); | ||
230 | memset(runtime_dtlb_cache_stats, 0, sizeof(runtime_dtlb_cache_stats)); | ||
231 | memset(&walltime_nsecs_stats, 0, sizeof(walltime_nsecs_stats)); | ||
232 | } | ||
233 | |||
176 | static int create_perf_stat_counter(struct perf_evsel *evsel) | 234 | static int create_perf_stat_counter(struct perf_evsel *evsel) |
177 | { | 235 | { |
178 | struct perf_event_attr *attr = &evsel->attr; | 236 | struct perf_event_attr *attr = &evsel->attr; |
@@ -249,7 +307,7 @@ static int read_counter_aggr(struct perf_evsel *counter) | |||
249 | int i; | 307 | int i; |
250 | 308 | ||
251 | if (__perf_evsel__read(counter, perf_evsel__nr_cpus(counter), | 309 | if (__perf_evsel__read(counter, perf_evsel__nr_cpus(counter), |
252 | evsel_list->threads->nr, scale) < 0) | 310 | thread_map__nr(evsel_list->threads), scale) < 0) |
253 | return -1; | 311 | return -1; |
254 | 312 | ||
255 | for (i = 0; i < 3; i++) | 313 | for (i = 0; i < 3; i++) |
@@ -337,16 +395,14 @@ static void print_interval(void) | |||
337 | } | 395 | } |
338 | } | 396 | } |
339 | 397 | ||
340 | static int __run_perf_stat(int argc __maybe_unused, const char **argv) | 398 | static int __run_perf_stat(int argc, const char **argv) |
341 | { | 399 | { |
342 | char msg[512]; | 400 | char msg[512]; |
343 | unsigned long long t0, t1; | 401 | unsigned long long t0, t1; |
344 | struct perf_evsel *counter; | 402 | struct perf_evsel *counter; |
345 | struct timespec ts; | 403 | struct timespec ts; |
346 | int status = 0; | 404 | int status = 0; |
347 | int child_ready_pipe[2], go_pipe[2]; | ||
348 | const bool forks = (argc > 0); | 405 | const bool forks = (argc > 0); |
349 | char buf; | ||
350 | 406 | ||
351 | if (interval) { | 407 | if (interval) { |
352 | ts.tv_sec = interval / 1000; | 408 | ts.tv_sec = interval / 1000; |
@@ -362,55 +418,12 @@ static int __run_perf_stat(int argc __maybe_unused, const char **argv) | |||
362 | return -1; | 418 | return -1; |
363 | } | 419 | } |
364 | 420 | ||
365 | if (forks && (pipe(child_ready_pipe) < 0 || pipe(go_pipe) < 0)) { | ||
366 | perror("failed to create pipes"); | ||
367 | return -1; | ||
368 | } | ||
369 | |||
370 | if (forks) { | 421 | if (forks) { |
371 | if ((child_pid = fork()) < 0) | 422 | if (perf_evlist__prepare_workload(evsel_list, &target, argv, |
372 | perror("failed to fork"); | 423 | false, false) < 0) { |
373 | 424 | perror("failed to prepare workload"); | |
374 | if (!child_pid) { | 425 | return -1; |
375 | close(child_ready_pipe[0]); | ||
376 | close(go_pipe[1]); | ||
377 | fcntl(go_pipe[0], F_SETFD, FD_CLOEXEC); | ||
378 | |||
379 | /* | ||
380 | * Do a dummy execvp to get the PLT entry resolved, | ||
381 | * so we avoid the resolver overhead on the real | ||
382 | * execvp call. | ||
383 | */ | ||
384 | execvp("", (char **)argv); | ||
385 | |||
386 | /* | ||
387 | * Tell the parent we're ready to go | ||
388 | */ | ||
389 | close(child_ready_pipe[1]); | ||
390 | |||
391 | /* | ||
392 | * Wait until the parent tells us to go. | ||
393 | */ | ||
394 | if (read(go_pipe[0], &buf, 1) == -1) | ||
395 | perror("unable to read pipe"); | ||
396 | |||
397 | execvp(argv[0], (char **)argv); | ||
398 | |||
399 | perror(argv[0]); | ||
400 | exit(-1); | ||
401 | } | 426 | } |
402 | |||
403 | if (perf_target__none(&target)) | ||
404 | evsel_list->threads->map[0] = child_pid; | ||
405 | |||
406 | /* | ||
407 | * Wait for the child to be ready to exec. | ||
408 | */ | ||
409 | close(child_ready_pipe[1]); | ||
410 | close(go_pipe[0]); | ||
411 | if (read(child_ready_pipe[0], &buf, 1) == -1) | ||
412 | perror("unable to read pipe"); | ||
413 | close(child_ready_pipe[0]); | ||
414 | } | 427 | } |
415 | 428 | ||
416 | if (group) | 429 | if (group) |
@@ -457,7 +470,8 @@ static int __run_perf_stat(int argc __maybe_unused, const char **argv) | |||
457 | clock_gettime(CLOCK_MONOTONIC, &ref_time); | 470 | clock_gettime(CLOCK_MONOTONIC, &ref_time); |
458 | 471 | ||
459 | if (forks) { | 472 | if (forks) { |
460 | close(go_pipe[1]); | 473 | perf_evlist__start_workload(evsel_list); |
474 | |||
461 | if (interval) { | 475 | if (interval) { |
462 | while (!waitpid(child_pid, &status, WNOHANG)) { | 476 | while (!waitpid(child_pid, &status, WNOHANG)) { |
463 | nanosleep(&ts, NULL); | 477 | nanosleep(&ts, NULL); |
@@ -488,7 +502,7 @@ static int __run_perf_stat(int argc __maybe_unused, const char **argv) | |||
488 | list_for_each_entry(counter, &evsel_list->entries, node) { | 502 | list_for_each_entry(counter, &evsel_list->entries, node) { |
489 | read_counter_aggr(counter); | 503 | read_counter_aggr(counter); |
490 | perf_evsel__close_fd(counter, perf_evsel__nr_cpus(counter), | 504 | perf_evsel__close_fd(counter, perf_evsel__nr_cpus(counter), |
491 | evsel_list->threads->nr); | 505 | thread_map__nr(evsel_list->threads)); |
492 | } | 506 | } |
493 | } | 507 | } |
494 | 508 | ||
@@ -1296,7 +1310,7 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused) | |||
1296 | OPT_INCR('v', "verbose", &verbose, | 1310 | OPT_INCR('v', "verbose", &verbose, |
1297 | "be more verbose (show counter open errors, etc)"), | 1311 | "be more verbose (show counter open errors, etc)"), |
1298 | OPT_INTEGER('r', "repeat", &run_count, | 1312 | OPT_INTEGER('r', "repeat", &run_count, |
1299 | "repeat command and print average + stddev (max: 100)"), | 1313 | "repeat command and print average + stddev (max: 100, forever: 0)"), |
1300 | OPT_BOOLEAN('n', "null", &null_run, | 1314 | OPT_BOOLEAN('n', "null", &null_run, |
1301 | "null run - dont start any counters"), | 1315 | "null run - dont start any counters"), |
1302 | OPT_INCR('d', "detailed", &detailed_run, | 1316 | OPT_INCR('d', "detailed", &detailed_run, |
@@ -1330,13 +1344,12 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused) | |||
1330 | "perf stat [<options>] [<command>]", | 1344 | "perf stat [<options>] [<command>]", |
1331 | NULL | 1345 | NULL |
1332 | }; | 1346 | }; |
1333 | struct perf_evsel *pos; | ||
1334 | int status = -ENOMEM, run_idx; | 1347 | int status = -ENOMEM, run_idx; |
1335 | const char *mode; | 1348 | const char *mode; |
1336 | 1349 | ||
1337 | setlocale(LC_ALL, ""); | 1350 | setlocale(LC_ALL, ""); |
1338 | 1351 | ||
1339 | evsel_list = perf_evlist__new(NULL, NULL); | 1352 | evsel_list = perf_evlist__new(); |
1340 | if (evsel_list == NULL) | 1353 | if (evsel_list == NULL) |
1341 | return -ENOMEM; | 1354 | return -ENOMEM; |
1342 | 1355 | ||
@@ -1399,8 +1412,12 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused) | |||
1399 | 1412 | ||
1400 | if (!argc && !perf_target__has_task(&target)) | 1413 | if (!argc && !perf_target__has_task(&target)) |
1401 | usage_with_options(stat_usage, options); | 1414 | usage_with_options(stat_usage, options); |
1402 | if (run_count <= 0) | 1415 | if (run_count < 0) { |
1403 | usage_with_options(stat_usage, options); | 1416 | usage_with_options(stat_usage, options); |
1417 | } else if (run_count == 0) { | ||
1418 | forever = true; | ||
1419 | run_count = 1; | ||
1420 | } | ||
1404 | 1421 | ||
1405 | /* no_aggr, cgroup are for system-wide only */ | 1422 | /* no_aggr, cgroup are for system-wide only */ |
1406 | if ((no_aggr || nr_cgroups) && !perf_target__has_cpu(&target)) { | 1423 | if ((no_aggr || nr_cgroups) && !perf_target__has_cpu(&target)) { |
@@ -1438,17 +1455,8 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused) | |||
1438 | return -1; | 1455 | return -1; |
1439 | } | 1456 | } |
1440 | 1457 | ||
1441 | list_for_each_entry(pos, &evsel_list->entries, node) { | 1458 | if (perf_evlist__alloc_stats(evsel_list, interval)) |
1442 | if (perf_evsel__alloc_stat_priv(pos) < 0 || | 1459 | goto out_free_maps; |
1443 | perf_evsel__alloc_counts(pos, perf_evsel__nr_cpus(pos)) < 0) | ||
1444 | goto out_free_fd; | ||
1445 | } | ||
1446 | if (interval) { | ||
1447 | list_for_each_entry(pos, &evsel_list->entries, node) { | ||
1448 | if (perf_evsel__alloc_prev_raw_counts(pos) < 0) | ||
1449 | goto out_free_fd; | ||
1450 | } | ||
1451 | } | ||
1452 | 1460 | ||
1453 | /* | 1461 | /* |
1454 | * We dont want to block the signals - that would cause | 1462 | * We dont want to block the signals - that would cause |
@@ -1457,28 +1465,30 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused) | |||
1457 | * task, but being ignored by perf stat itself: | 1465 | * task, but being ignored by perf stat itself: |
1458 | */ | 1466 | */ |
1459 | atexit(sig_atexit); | 1467 | atexit(sig_atexit); |
1460 | signal(SIGINT, skip_signal); | 1468 | if (!forever) |
1469 | signal(SIGINT, skip_signal); | ||
1461 | signal(SIGCHLD, skip_signal); | 1470 | signal(SIGCHLD, skip_signal); |
1462 | signal(SIGALRM, skip_signal); | 1471 | signal(SIGALRM, skip_signal); |
1463 | signal(SIGABRT, skip_signal); | 1472 | signal(SIGABRT, skip_signal); |
1464 | 1473 | ||
1465 | status = 0; | 1474 | status = 0; |
1466 | for (run_idx = 0; run_idx < run_count; run_idx++) { | 1475 | for (run_idx = 0; forever || run_idx < run_count; run_idx++) { |
1467 | if (run_count != 1 && verbose) | 1476 | if (run_count != 1 && verbose) |
1468 | fprintf(output, "[ perf stat: executing run #%d ... ]\n", | 1477 | fprintf(output, "[ perf stat: executing run #%d ... ]\n", |
1469 | run_idx + 1); | 1478 | run_idx + 1); |
1470 | 1479 | ||
1471 | status = run_perf_stat(argc, argv); | 1480 | status = run_perf_stat(argc, argv); |
1481 | if (forever && status != -1) { | ||
1482 | print_stat(argc, argv); | ||
1483 | perf_stat__reset_stats(evsel_list); | ||
1484 | } | ||
1472 | } | 1485 | } |
1473 | 1486 | ||
1474 | if (status != -1 && !interval) | 1487 | if (!forever && status != -1 && !interval) |
1475 | print_stat(argc, argv); | 1488 | print_stat(argc, argv); |
1476 | out_free_fd: | 1489 | |
1477 | list_for_each_entry(pos, &evsel_list->entries, node) { | 1490 | perf_evlist__free_stats(evsel_list); |
1478 | perf_evsel__free_stat_priv(pos); | 1491 | out_free_maps: |
1479 | perf_evsel__free_counts(pos); | ||
1480 | perf_evsel__free_prev_raw_counts(pos); | ||
1481 | } | ||
1482 | perf_evlist__delete_maps(evsel_list); | 1492 | perf_evlist__delete_maps(evsel_list); |
1483 | out: | 1493 | out: |
1484 | perf_evlist__delete(evsel_list); | 1494 | perf_evlist__delete(evsel_list); |
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index 72f6eb7b4173..b5520ad0dbb8 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c | |||
@@ -231,7 +231,7 @@ static void perf_top__show_details(struct perf_top *top) | |||
231 | printf("Showing %s for %s\n", perf_evsel__name(top->sym_evsel), symbol->name); | 231 | printf("Showing %s for %s\n", perf_evsel__name(top->sym_evsel), symbol->name); |
232 | printf(" Events Pcnt (>=%d%%)\n", top->sym_pcnt_filter); | 232 | printf(" Events Pcnt (>=%d%%)\n", top->sym_pcnt_filter); |
233 | 233 | ||
234 | more = symbol__annotate_printf(symbol, he->ms.map, top->sym_evsel->idx, | 234 | more = symbol__annotate_printf(symbol, he->ms.map, top->sym_evsel, |
235 | 0, top->sym_pcnt_filter, top->print_entries, 4); | 235 | 0, top->sym_pcnt_filter, top->print_entries, 4); |
236 | if (top->zero) | 236 | if (top->zero) |
237 | symbol__annotate_zero_histogram(symbol, top->sym_evsel->idx); | 237 | symbol__annotate_zero_histogram(symbol, top->sym_evsel->idx); |
@@ -1116,7 +1116,7 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused) | |||
1116 | NULL | 1116 | NULL |
1117 | }; | 1117 | }; |
1118 | 1118 | ||
1119 | top.evlist = perf_evlist__new(NULL, NULL); | 1119 | top.evlist = perf_evlist__new(); |
1120 | if (top.evlist == NULL) | 1120 | if (top.evlist == NULL) |
1121 | return -ENOMEM; | 1121 | return -ENOMEM; |
1122 | 1122 | ||
diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c index d222d7fc7e96..ab3ed4af1466 100644 --- a/tools/perf/builtin-trace.c +++ b/tools/perf/builtin-trace.c | |||
@@ -419,7 +419,7 @@ out_dump: | |||
419 | 419 | ||
420 | static int trace__run(struct trace *trace, int argc, const char **argv) | 420 | static int trace__run(struct trace *trace, int argc, const char **argv) |
421 | { | 421 | { |
422 | struct perf_evlist *evlist = perf_evlist__new(NULL, NULL); | 422 | struct perf_evlist *evlist = perf_evlist__new(); |
423 | struct perf_evsel *evsel; | 423 | struct perf_evsel *evsel; |
424 | int err = -1, i; | 424 | int err = -1, i; |
425 | unsigned long before; | 425 | unsigned long before; |
@@ -452,7 +452,7 @@ static int trace__run(struct trace *trace, int argc, const char **argv) | |||
452 | err = trace__symbols_init(trace, evlist); | 452 | err = trace__symbols_init(trace, evlist); |
453 | if (err < 0) { | 453 | if (err < 0) { |
454 | printf("Problems initializing symbol libraries!\n"); | 454 | printf("Problems initializing symbol libraries!\n"); |
455 | goto out_delete_evlist; | 455 | goto out_delete_maps; |
456 | } | 456 | } |
457 | 457 | ||
458 | perf_evlist__config(evlist, &trace->opts); | 458 | perf_evlist__config(evlist, &trace->opts); |
@@ -461,23 +461,24 @@ static int trace__run(struct trace *trace, int argc, const char **argv) | |||
461 | signal(SIGINT, sig_handler); | 461 | signal(SIGINT, sig_handler); |
462 | 462 | ||
463 | if (forks) { | 463 | if (forks) { |
464 | err = perf_evlist__prepare_workload(evlist, &trace->opts, argv); | 464 | err = perf_evlist__prepare_workload(evlist, &trace->opts.target, |
465 | argv, false, false); | ||
465 | if (err < 0) { | 466 | if (err < 0) { |
466 | printf("Couldn't run the workload!\n"); | 467 | printf("Couldn't run the workload!\n"); |
467 | goto out_delete_evlist; | 468 | goto out_delete_maps; |
468 | } | 469 | } |
469 | } | 470 | } |
470 | 471 | ||
471 | err = perf_evlist__open(evlist); | 472 | err = perf_evlist__open(evlist); |
472 | if (err < 0) { | 473 | if (err < 0) { |
473 | printf("Couldn't create the events: %s\n", strerror(errno)); | 474 | printf("Couldn't create the events: %s\n", strerror(errno)); |
474 | goto out_delete_evlist; | 475 | goto out_delete_maps; |
475 | } | 476 | } |
476 | 477 | ||
477 | err = perf_evlist__mmap(evlist, UINT_MAX, false); | 478 | err = perf_evlist__mmap(evlist, UINT_MAX, false); |
478 | if (err < 0) { | 479 | if (err < 0) { |
479 | printf("Couldn't mmap the events: %s\n", strerror(errno)); | 480 | printf("Couldn't mmap the events: %s\n", strerror(errno)); |
480 | goto out_delete_evlist; | 481 | goto out_close_evlist; |
481 | } | 482 | } |
482 | 483 | ||
483 | perf_evlist__enable(evlist); | 484 | perf_evlist__enable(evlist); |
@@ -526,13 +527,6 @@ again: | |||
526 | continue; | 527 | continue; |
527 | } | 528 | } |
528 | 529 | ||
529 | if (sample.raw_data == NULL) { | ||
530 | printf("%s sample with no payload for tid: %d, cpu %d, raw_size=%d, skipping...\n", | ||
531 | perf_evsel__name(evsel), sample.tid, | ||
532 | sample.cpu, sample.raw_size); | ||
533 | continue; | ||
534 | } | ||
535 | |||
536 | handler = evsel->handler.func; | 530 | handler = evsel->handler.func; |
537 | handler(trace, evsel, &sample); | 531 | handler(trace, evsel, &sample); |
538 | } | 532 | } |
@@ -540,7 +534,7 @@ again: | |||
540 | 534 | ||
541 | if (trace->nr_events == before) { | 535 | if (trace->nr_events == before) { |
542 | if (done) | 536 | if (done) |
543 | goto out_delete_evlist; | 537 | goto out_unmap_evlist; |
544 | 538 | ||
545 | poll(evlist->pollfd, evlist->nr_fds, -1); | 539 | poll(evlist->pollfd, evlist->nr_fds, -1); |
546 | } | 540 | } |
@@ -550,6 +544,12 @@ again: | |||
550 | 544 | ||
551 | goto again; | 545 | goto again; |
552 | 546 | ||
547 | out_unmap_evlist: | ||
548 | perf_evlist__munmap(evlist); | ||
549 | out_close_evlist: | ||
550 | perf_evlist__close(evlist); | ||
551 | out_delete_maps: | ||
552 | perf_evlist__delete_maps(evlist); | ||
553 | out_delete_evlist: | 553 | out_delete_evlist: |
554 | perf_evlist__delete(evlist); | 554 | perf_evlist__delete(evlist); |
555 | out: | 555 | out: |
diff --git a/tools/perf/command-list.txt b/tools/perf/command-list.txt index 3e86bbd8c2d5..a28e31be6cb4 100644 --- a/tools/perf/command-list.txt +++ b/tools/perf/command-list.txt | |||
@@ -10,17 +10,17 @@ perf-buildid-list mainporcelain common | |||
10 | perf-diff mainporcelain common | 10 | perf-diff mainporcelain common |
11 | perf-evlist mainporcelain common | 11 | perf-evlist mainporcelain common |
12 | perf-inject mainporcelain common | 12 | perf-inject mainporcelain common |
13 | perf-kmem mainporcelain common | ||
14 | perf-kvm mainporcelain common | ||
13 | perf-list mainporcelain common | 15 | perf-list mainporcelain common |
14 | perf-sched mainporcelain common | 16 | perf-lock mainporcelain common |
17 | perf-probe mainporcelain full | ||
15 | perf-record mainporcelain common | 18 | perf-record mainporcelain common |
16 | perf-report mainporcelain common | 19 | perf-report mainporcelain common |
20 | perf-sched mainporcelain common | ||
21 | perf-script mainporcelain common | ||
17 | perf-stat mainporcelain common | 22 | perf-stat mainporcelain common |
23 | perf-test mainporcelain common | ||
18 | perf-timechart mainporcelain common | 24 | perf-timechart mainporcelain common |
19 | perf-top mainporcelain common | 25 | perf-top mainporcelain common |
20 | perf-trace mainporcelain common | 26 | perf-trace mainporcelain common |
21 | perf-script mainporcelain common | ||
22 | perf-probe mainporcelain full | ||
23 | perf-kmem mainporcelain common | ||
24 | perf-lock mainporcelain common | ||
25 | perf-kvm mainporcelain common | ||
26 | perf-test mainporcelain common | ||
diff --git a/tools/perf/perf.c b/tools/perf/perf.c index 095b88207cd3..f6ba7b73f40e 100644 --- a/tools/perf/perf.c +++ b/tools/perf/perf.c | |||
@@ -13,7 +13,7 @@ | |||
13 | #include "util/quote.h" | 13 | #include "util/quote.h" |
14 | #include "util/run-command.h" | 14 | #include "util/run-command.h" |
15 | #include "util/parse-events.h" | 15 | #include "util/parse-events.h" |
16 | #include "util/debugfs.h" | 16 | #include <lk/debugfs.h> |
17 | #include <pthread.h> | 17 | #include <pthread.h> |
18 | 18 | ||
19 | const char perf_usage_string[] = | 19 | const char perf_usage_string[] = |
@@ -193,13 +193,13 @@ static int handle_options(const char ***argv, int *argc, int *envchanged) | |||
193 | fprintf(stderr, "No directory given for --debugfs-dir.\n"); | 193 | fprintf(stderr, "No directory given for --debugfs-dir.\n"); |
194 | usage(perf_usage_string); | 194 | usage(perf_usage_string); |
195 | } | 195 | } |
196 | debugfs_set_path((*argv)[1]); | 196 | perf_debugfs_set_path((*argv)[1]); |
197 | if (envchanged) | 197 | if (envchanged) |
198 | *envchanged = 1; | 198 | *envchanged = 1; |
199 | (*argv)++; | 199 | (*argv)++; |
200 | (*argc)--; | 200 | (*argc)--; |
201 | } else if (!prefixcmp(cmd, CMD_DEBUGFS_DIR)) { | 201 | } else if (!prefixcmp(cmd, CMD_DEBUGFS_DIR)) { |
202 | debugfs_set_path(cmd + strlen(CMD_DEBUGFS_DIR)); | 202 | perf_debugfs_set_path(cmd + strlen(CMD_DEBUGFS_DIR)); |
203 | fprintf(stderr, "dir: %s\n", debugfs_mountpoint); | 203 | fprintf(stderr, "dir: %s\n", debugfs_mountpoint); |
204 | if (envchanged) | 204 | if (envchanged) |
205 | *envchanged = 1; | 205 | *envchanged = 1; |
@@ -461,7 +461,7 @@ int main(int argc, const char **argv) | |||
461 | if (!cmd) | 461 | if (!cmd) |
462 | cmd = "perf-help"; | 462 | cmd = "perf-help"; |
463 | /* get debugfs mount point from /proc/mounts */ | 463 | /* get debugfs mount point from /proc/mounts */ |
464 | debugfs_mount(NULL); | 464 | perf_debugfs_mount(NULL); |
465 | /* | 465 | /* |
466 | * "perf-xxxx" is the same as "perf xxxx", but we obviously: | 466 | * "perf-xxxx" is the same as "perf xxxx", but we obviously: |
467 | * | 467 | * |
diff --git a/tools/perf/tests/attr.c b/tools/perf/tests/attr.c index bdcceb886f77..038de3ecb8cb 100644 --- a/tools/perf/tests/attr.c +++ b/tools/perf/tests/attr.c | |||
@@ -147,10 +147,15 @@ void test_attr__open(struct perf_event_attr *attr, pid_t pid, int cpu, | |||
147 | 147 | ||
148 | static int run_dir(const char *d, const char *perf) | 148 | static int run_dir(const char *d, const char *perf) |
149 | { | 149 | { |
150 | char v[] = "-vvvvv"; | ||
151 | int vcnt = min(verbose, (int) sizeof(v) - 1); | ||
150 | char cmd[3*PATH_MAX]; | 152 | char cmd[3*PATH_MAX]; |
151 | 153 | ||
152 | snprintf(cmd, 3*PATH_MAX, PYTHON " %s/attr.py -d %s/attr/ -p %s %s", | 154 | if (verbose) |
153 | d, d, perf, verbose ? "-v" : ""); | 155 | vcnt++; |
156 | |||
157 | snprintf(cmd, 3*PATH_MAX, PYTHON " %s/attr.py -d %s/attr/ -p %s %.*s", | ||
158 | d, d, perf, vcnt, v); | ||
154 | 159 | ||
155 | return system(cmd); | 160 | return system(cmd); |
156 | } | 161 | } |
diff --git a/tools/perf/tests/attr.py b/tools/perf/tests/attr.py index 2f629ca485bc..c9b4b6269b51 100644 --- a/tools/perf/tests/attr.py +++ b/tools/perf/tests/attr.py | |||
@@ -24,6 +24,7 @@ class Unsup(Exception): | |||
24 | 24 | ||
25 | class Event(dict): | 25 | class Event(dict): |
26 | terms = [ | 26 | terms = [ |
27 | 'cpu', | ||
27 | 'flags', | 28 | 'flags', |
28 | 'type', | 29 | 'type', |
29 | 'size', | 30 | 'size', |
@@ -121,7 +122,7 @@ class Test(object): | |||
121 | parser = ConfigParser.SafeConfigParser() | 122 | parser = ConfigParser.SafeConfigParser() |
122 | parser.read(path) | 123 | parser.read(path) |
123 | 124 | ||
124 | log.debug("running '%s'" % path) | 125 | log.warning("running '%s'" % path) |
125 | 126 | ||
126 | self.path = path | 127 | self.path = path |
127 | self.test_dir = options.test_dir | 128 | self.test_dir = options.test_dir |
@@ -172,7 +173,7 @@ class Test(object): | |||
172 | self.perf, self.command, tempdir, self.args) | 173 | self.perf, self.command, tempdir, self.args) |
173 | ret = os.WEXITSTATUS(os.system(cmd)) | 174 | ret = os.WEXITSTATUS(os.system(cmd)) |
174 | 175 | ||
175 | log.warning(" running '%s' ret %d " % (cmd, ret)) | 176 | log.info(" '%s' ret %d " % (cmd, ret)) |
176 | 177 | ||
177 | if ret != int(self.ret): | 178 | if ret != int(self.ret): |
178 | raise Unsup(self) | 179 | raise Unsup(self) |
diff --git a/tools/perf/tests/attr/base-record b/tools/perf/tests/attr/base-record index 5bc3880f7be5..b4fc835de607 100644 --- a/tools/perf/tests/attr/base-record +++ b/tools/perf/tests/attr/base-record | |||
@@ -2,6 +2,7 @@ | |||
2 | fd=1 | 2 | fd=1 |
3 | group_fd=-1 | 3 | group_fd=-1 |
4 | flags=0 | 4 | flags=0 |
5 | cpu=* | ||
5 | type=0|1 | 6 | type=0|1 |
6 | size=96 | 7 | size=96 |
7 | config=0 | 8 | config=0 |
diff --git a/tools/perf/tests/attr/base-stat b/tools/perf/tests/attr/base-stat index 4bd79a82784f..748ee949a204 100644 --- a/tools/perf/tests/attr/base-stat +++ b/tools/perf/tests/attr/base-stat | |||
@@ -2,6 +2,7 @@ | |||
2 | fd=1 | 2 | fd=1 |
3 | group_fd=-1 | 3 | group_fd=-1 |
4 | flags=0 | 4 | flags=0 |
5 | cpu=* | ||
5 | type=0 | 6 | type=0 |
6 | size=96 | 7 | size=96 |
7 | config=0 | 8 | config=0 |
diff --git a/tools/perf/tests/attr/test-record-C0 b/tools/perf/tests/attr/test-record-C0 new file mode 100644 index 000000000000..d6a7e43f61b3 --- /dev/null +++ b/tools/perf/tests/attr/test-record-C0 | |||
@@ -0,0 +1,13 @@ | |||
1 | [config] | ||
2 | command = record | ||
3 | args = -C 0 kill >/dev/null 2>&1 | ||
4 | |||
5 | [event:base-record] | ||
6 | cpu=0 | ||
7 | |||
8 | # no enable on exec for CPU attached | ||
9 | enable_on_exec=0 | ||
10 | |||
11 | # PERF_SAMPLE_IP | PERF_SAMPLE_TID PERF_SAMPLE_TIME | # PERF_SAMPLE_PERIOD | ||
12 | # + PERF_SAMPLE_CPU added by -C 0 | ||
13 | sample_type=391 | ||
diff --git a/tools/perf/tests/attr/test-stat-C0 b/tools/perf/tests/attr/test-stat-C0 new file mode 100644 index 000000000000..aa835950751f --- /dev/null +++ b/tools/perf/tests/attr/test-stat-C0 | |||
@@ -0,0 +1,9 @@ | |||
1 | [config] | ||
2 | command = stat | ||
3 | args = -e cycles -C 0 kill >/dev/null 2>&1 | ||
4 | ret = 1 | ||
5 | |||
6 | [event:base-stat] | ||
7 | # events are enabled by default when attached to cpu | ||
8 | disabled=0 | ||
9 | enable_on_exec=0 | ||
diff --git a/tools/perf/tests/bp_signal.c b/tools/perf/tests/bp_signal.c new file mode 100644 index 000000000000..68daa289e94c --- /dev/null +++ b/tools/perf/tests/bp_signal.c | |||
@@ -0,0 +1,186 @@ | |||
1 | /* | ||
2 | * Inspired by breakpoint overflow test done by | ||
3 | * Vince Weaver <vincent.weaver@maine.edu> for perf_event_tests | ||
4 | * (git://github.com/deater/perf_event_tests) | ||
5 | */ | ||
6 | |||
7 | #include <stdlib.h> | ||
8 | #include <stdio.h> | ||
9 | #include <unistd.h> | ||
10 | #include <string.h> | ||
11 | #include <sys/ioctl.h> | ||
12 | #include <time.h> | ||
13 | #include <fcntl.h> | ||
14 | #include <signal.h> | ||
15 | #include <sys/mman.h> | ||
16 | #include <linux/compiler.h> | ||
17 | #include <linux/hw_breakpoint.h> | ||
18 | |||
19 | #include "tests.h" | ||
20 | #include "debug.h" | ||
21 | #include "perf.h" | ||
22 | |||
23 | static int fd1; | ||
24 | static int fd2; | ||
25 | static int overflows; | ||
26 | |||
27 | __attribute__ ((noinline)) | ||
28 | static int test_function(void) | ||
29 | { | ||
30 | return time(NULL); | ||
31 | } | ||
32 | |||
33 | static void sig_handler(int signum __maybe_unused, | ||
34 | siginfo_t *oh __maybe_unused, | ||
35 | void *uc __maybe_unused) | ||
36 | { | ||
37 | overflows++; | ||
38 | |||
39 | if (overflows > 10) { | ||
40 | /* | ||
41 | * This should be executed only once during | ||
42 | * this test, if we are here for the 10th | ||
43 | * time, consider this the recursive issue. | ||
44 | * | ||
45 | * We can get out of here by disable events, | ||
46 | * so no new SIGIO is delivered. | ||
47 | */ | ||
48 | ioctl(fd1, PERF_EVENT_IOC_DISABLE, 0); | ||
49 | ioctl(fd2, PERF_EVENT_IOC_DISABLE, 0); | ||
50 | } | ||
51 | } | ||
52 | |||
53 | static int bp_event(void *fn, int setup_signal) | ||
54 | { | ||
55 | struct perf_event_attr pe; | ||
56 | int fd; | ||
57 | |||
58 | memset(&pe, 0, sizeof(struct perf_event_attr)); | ||
59 | pe.type = PERF_TYPE_BREAKPOINT; | ||
60 | pe.size = sizeof(struct perf_event_attr); | ||
61 | |||
62 | pe.config = 0; | ||
63 | pe.bp_type = HW_BREAKPOINT_X; | ||
64 | pe.bp_addr = (unsigned long) fn; | ||
65 | pe.bp_len = sizeof(long); | ||
66 | |||
67 | pe.sample_period = 1; | ||
68 | pe.sample_type = PERF_SAMPLE_IP; | ||
69 | pe.wakeup_events = 1; | ||
70 | |||
71 | pe.disabled = 1; | ||
72 | pe.exclude_kernel = 1; | ||
73 | pe.exclude_hv = 1; | ||
74 | |||
75 | fd = sys_perf_event_open(&pe, 0, -1, -1, 0); | ||
76 | if (fd < 0) { | ||
77 | pr_debug("failed opening event %llx\n", pe.config); | ||
78 | return TEST_FAIL; | ||
79 | } | ||
80 | |||
81 | if (setup_signal) { | ||
82 | fcntl(fd, F_SETFL, O_RDWR|O_NONBLOCK|O_ASYNC); | ||
83 | fcntl(fd, F_SETSIG, SIGIO); | ||
84 | fcntl(fd, F_SETOWN, getpid()); | ||
85 | } | ||
86 | |||
87 | ioctl(fd, PERF_EVENT_IOC_RESET, 0); | ||
88 | |||
89 | return fd; | ||
90 | } | ||
91 | |||
92 | static long long bp_count(int fd) | ||
93 | { | ||
94 | long long count; | ||
95 | int ret; | ||
96 | |||
97 | ret = read(fd, &count, sizeof(long long)); | ||
98 | if (ret != sizeof(long long)) { | ||
99 | pr_debug("failed to read: %d\n", ret); | ||
100 | return TEST_FAIL; | ||
101 | } | ||
102 | |||
103 | return count; | ||
104 | } | ||
105 | |||
106 | int test__bp_signal(void) | ||
107 | { | ||
108 | struct sigaction sa; | ||
109 | long long count1, count2; | ||
110 | |||
111 | /* setup SIGIO signal handler */ | ||
112 | memset(&sa, 0, sizeof(struct sigaction)); | ||
113 | sa.sa_sigaction = (void *) sig_handler; | ||
114 | sa.sa_flags = SA_SIGINFO; | ||
115 | |||
116 | if (sigaction(SIGIO, &sa, NULL) < 0) { | ||
117 | pr_debug("failed setting up signal handler\n"); | ||
118 | return TEST_FAIL; | ||
119 | } | ||
120 | |||
121 | /* | ||
122 | * We create following events: | ||
123 | * | ||
124 | * fd1 - breakpoint event on test_function with SIGIO | ||
125 | * signal configured. We should get signal | ||
126 | * notification each time the breakpoint is hit | ||
127 | * | ||
128 | * fd2 - breakpoint event on sig_handler without SIGIO | ||
129 | * configured. | ||
130 | * | ||
131 | * Following processing should happen: | ||
132 | * - execute test_function | ||
133 | * - fd1 event breakpoint hit -> count1 == 1 | ||
134 | * - SIGIO is delivered -> overflows == 1 | ||
135 | * - fd2 event breakpoint hit -> count2 == 1 | ||
136 | * | ||
137 | * The test case check following error conditions: | ||
138 | * - we get stuck in signal handler because of debug | ||
139 | * exception being triggered receursively due to | ||
140 | * the wrong RF EFLAG management | ||
141 | * | ||
142 | * - we never trigger the sig_handler breakpoint due | ||
143 | * to the rong RF EFLAG management | ||
144 | * | ||
145 | */ | ||
146 | |||
147 | fd1 = bp_event(test_function, 1); | ||
148 | fd2 = bp_event(sig_handler, 0); | ||
149 | |||
150 | ioctl(fd1, PERF_EVENT_IOC_ENABLE, 0); | ||
151 | ioctl(fd2, PERF_EVENT_IOC_ENABLE, 0); | ||
152 | |||
153 | /* | ||
154 | * Kick off the test by trigering 'fd1' | ||
155 | * breakpoint. | ||
156 | */ | ||
157 | test_function(); | ||
158 | |||
159 | ioctl(fd1, PERF_EVENT_IOC_DISABLE, 0); | ||
160 | ioctl(fd2, PERF_EVENT_IOC_DISABLE, 0); | ||
161 | |||
162 | count1 = bp_count(fd1); | ||
163 | count2 = bp_count(fd2); | ||
164 | |||
165 | close(fd1); | ||
166 | close(fd2); | ||
167 | |||
168 | pr_debug("count1 %lld, count2 %lld, overflow %d\n", | ||
169 | count1, count2, overflows); | ||
170 | |||
171 | if (count1 != 1) { | ||
172 | if (count1 == 11) | ||
173 | pr_debug("failed: RF EFLAG recursion issue detected\n"); | ||
174 | else | ||
175 | pr_debug("failed: wrong count for bp1%lld\n", count1); | ||
176 | } | ||
177 | |||
178 | if (overflows != 1) | ||
179 | pr_debug("failed: wrong overflow hit\n"); | ||
180 | |||
181 | if (count2 != 1) | ||
182 | pr_debug("failed: wrong count for bp2\n"); | ||
183 | |||
184 | return count1 == 1 && overflows == 1 && count2 == 1 ? | ||
185 | TEST_OK : TEST_FAIL; | ||
186 | } | ||
diff --git a/tools/perf/tests/bp_signal_overflow.c b/tools/perf/tests/bp_signal_overflow.c new file mode 100644 index 000000000000..fe7ed28815f8 --- /dev/null +++ b/tools/perf/tests/bp_signal_overflow.c | |||
@@ -0,0 +1,126 @@ | |||
1 | /* | ||
2 | * Originally done by Vince Weaver <vincent.weaver@maine.edu> for | ||
3 | * perf_event_tests (git://github.com/deater/perf_event_tests) | ||
4 | */ | ||
5 | |||
6 | #include <stdlib.h> | ||
7 | #include <stdio.h> | ||
8 | #include <unistd.h> | ||
9 | #include <string.h> | ||
10 | #include <sys/ioctl.h> | ||
11 | #include <time.h> | ||
12 | #include <fcntl.h> | ||
13 | #include <signal.h> | ||
14 | #include <sys/mman.h> | ||
15 | #include <linux/compiler.h> | ||
16 | #include <linux/hw_breakpoint.h> | ||
17 | |||
18 | #include "tests.h" | ||
19 | #include "debug.h" | ||
20 | #include "perf.h" | ||
21 | |||
22 | static int overflows; | ||
23 | |||
24 | __attribute__ ((noinline)) | ||
25 | static int test_function(void) | ||
26 | { | ||
27 | return time(NULL); | ||
28 | } | ||
29 | |||
30 | static void sig_handler(int signum __maybe_unused, | ||
31 | siginfo_t *oh __maybe_unused, | ||
32 | void *uc __maybe_unused) | ||
33 | { | ||
34 | overflows++; | ||
35 | } | ||
36 | |||
37 | static long long bp_count(int fd) | ||
38 | { | ||
39 | long long count; | ||
40 | int ret; | ||
41 | |||
42 | ret = read(fd, &count, sizeof(long long)); | ||
43 | if (ret != sizeof(long long)) { | ||
44 | pr_debug("failed to read: %d\n", ret); | ||
45 | return TEST_FAIL; | ||
46 | } | ||
47 | |||
48 | return count; | ||
49 | } | ||
50 | |||
51 | #define EXECUTIONS 10000 | ||
52 | #define THRESHOLD 100 | ||
53 | |||
54 | int test__bp_signal_overflow(void) | ||
55 | { | ||
56 | struct perf_event_attr pe; | ||
57 | struct sigaction sa; | ||
58 | long long count; | ||
59 | int fd, i, fails = 0; | ||
60 | |||
61 | /* setup SIGIO signal handler */ | ||
62 | memset(&sa, 0, sizeof(struct sigaction)); | ||
63 | sa.sa_sigaction = (void *) sig_handler; | ||
64 | sa.sa_flags = SA_SIGINFO; | ||
65 | |||
66 | if (sigaction(SIGIO, &sa, NULL) < 0) { | ||
67 | pr_debug("failed setting up signal handler\n"); | ||
68 | return TEST_FAIL; | ||
69 | } | ||
70 | |||
71 | memset(&pe, 0, sizeof(struct perf_event_attr)); | ||
72 | pe.type = PERF_TYPE_BREAKPOINT; | ||
73 | pe.size = sizeof(struct perf_event_attr); | ||
74 | |||
75 | pe.config = 0; | ||
76 | pe.bp_type = HW_BREAKPOINT_X; | ||
77 | pe.bp_addr = (unsigned long) test_function; | ||
78 | pe.bp_len = sizeof(long); | ||
79 | |||
80 | pe.sample_period = THRESHOLD; | ||
81 | pe.sample_type = PERF_SAMPLE_IP; | ||
82 | pe.wakeup_events = 1; | ||
83 | |||
84 | pe.disabled = 1; | ||
85 | pe.exclude_kernel = 1; | ||
86 | pe.exclude_hv = 1; | ||
87 | |||
88 | fd = sys_perf_event_open(&pe, 0, -1, -1, 0); | ||
89 | if (fd < 0) { | ||
90 | pr_debug("failed opening event %llx\n", pe.config); | ||
91 | return TEST_FAIL; | ||
92 | } | ||
93 | |||
94 | fcntl(fd, F_SETFL, O_RDWR|O_NONBLOCK|O_ASYNC); | ||
95 | fcntl(fd, F_SETSIG, SIGIO); | ||
96 | fcntl(fd, F_SETOWN, getpid()); | ||
97 | |||
98 | ioctl(fd, PERF_EVENT_IOC_RESET, 0); | ||
99 | ioctl(fd, PERF_EVENT_IOC_ENABLE, 0); | ||
100 | |||
101 | for (i = 0; i < EXECUTIONS; i++) | ||
102 | test_function(); | ||
103 | |||
104 | ioctl(fd, PERF_EVENT_IOC_DISABLE, 0); | ||
105 | |||
106 | count = bp_count(fd); | ||
107 | |||
108 | close(fd); | ||
109 | |||
110 | pr_debug("count %lld, overflow %d\n", | ||
111 | count, overflows); | ||
112 | |||
113 | if (count != EXECUTIONS) { | ||
114 | pr_debug("\tWrong number of executions %lld != %d\n", | ||
115 | count, EXECUTIONS); | ||
116 | fails++; | ||
117 | } | ||
118 | |||
119 | if (overflows != EXECUTIONS / THRESHOLD) { | ||
120 | pr_debug("\tWrong number of overflows %d != %d\n", | ||
121 | overflows, EXECUTIONS / THRESHOLD); | ||
122 | fails++; | ||
123 | } | ||
124 | |||
125 | return fails ? TEST_FAIL : TEST_OK; | ||
126 | } | ||
diff --git a/tools/perf/tests/builtin-test.c b/tools/perf/tests/builtin-test.c index acb98e0e39f2..0918ada4cc41 100644 --- a/tools/perf/tests/builtin-test.c +++ b/tools/perf/tests/builtin-test.c | |||
@@ -78,6 +78,22 @@ static struct test { | |||
78 | .func = test__python_use, | 78 | .func = test__python_use, |
79 | }, | 79 | }, |
80 | { | 80 | { |
81 | .desc = "Test breakpoint overflow signal handler", | ||
82 | .func = test__bp_signal, | ||
83 | }, | ||
84 | { | ||
85 | .desc = "Test breakpoint overflow sampling", | ||
86 | .func = test__bp_signal_overflow, | ||
87 | }, | ||
88 | { | ||
89 | .desc = "Test number of exit event of a simple workload", | ||
90 | .func = test__task_exit, | ||
91 | }, | ||
92 | { | ||
93 | .desc = "Test software clock events have valid period values", | ||
94 | .func = test__sw_clock_freq, | ||
95 | }, | ||
96 | { | ||
81 | .func = NULL, | 97 | .func = NULL, |
82 | }, | 98 | }, |
83 | }; | 99 | }; |
diff --git a/tools/perf/tests/evsel-roundtrip-name.c b/tools/perf/tests/evsel-roundtrip-name.c index 0fd99a9adb91..0197bda9c461 100644 --- a/tools/perf/tests/evsel-roundtrip-name.c +++ b/tools/perf/tests/evsel-roundtrip-name.c | |||
@@ -8,7 +8,7 @@ static int perf_evsel__roundtrip_cache_name_test(void) | |||
8 | char name[128]; | 8 | char name[128]; |
9 | int type, op, err = 0, ret = 0, i, idx; | 9 | int type, op, err = 0, ret = 0, i, idx; |
10 | struct perf_evsel *evsel; | 10 | struct perf_evsel *evsel; |
11 | struct perf_evlist *evlist = perf_evlist__new(NULL, NULL); | 11 | struct perf_evlist *evlist = perf_evlist__new(); |
12 | 12 | ||
13 | if (evlist == NULL) | 13 | if (evlist == NULL) |
14 | return -ENOMEM; | 14 | return -ENOMEM; |
@@ -64,7 +64,7 @@ static int __perf_evsel__name_array_test(const char *names[], int nr_names) | |||
64 | { | 64 | { |
65 | int i, err; | 65 | int i, err; |
66 | struct perf_evsel *evsel; | 66 | struct perf_evsel *evsel; |
67 | struct perf_evlist *evlist = perf_evlist__new(NULL, NULL); | 67 | struct perf_evlist *evlist = perf_evlist__new(); |
68 | 68 | ||
69 | if (evlist == NULL) | 69 | if (evlist == NULL) |
70 | return -ENOMEM; | 70 | return -ENOMEM; |
diff --git a/tools/perf/tests/hists_link.c b/tools/perf/tests/hists_link.c index 1be64a6c5daf..e0c0267858a1 100644 --- a/tools/perf/tests/hists_link.c +++ b/tools/perf/tests/hists_link.c | |||
@@ -436,7 +436,7 @@ int test__hists_link(void) | |||
436 | struct machines machines; | 436 | struct machines machines; |
437 | struct machine *machine = NULL; | 437 | struct machine *machine = NULL; |
438 | struct perf_evsel *evsel, *first; | 438 | struct perf_evsel *evsel, *first; |
439 | struct perf_evlist *evlist = perf_evlist__new(NULL, NULL); | 439 | struct perf_evlist *evlist = perf_evlist__new(); |
440 | 440 | ||
441 | if (evlist == NULL) | 441 | if (evlist == NULL) |
442 | return -ENOMEM; | 442 | return -ENOMEM; |
diff --git a/tools/perf/tests/mmap-basic.c b/tools/perf/tests/mmap-basic.c index cdd50755af51..5b1b5aba722b 100644 --- a/tools/perf/tests/mmap-basic.c +++ b/tools/perf/tests/mmap-basic.c | |||
@@ -53,12 +53,14 @@ int test__basic_mmap(void) | |||
53 | goto out_free_cpus; | 53 | goto out_free_cpus; |
54 | } | 54 | } |
55 | 55 | ||
56 | evlist = perf_evlist__new(cpus, threads); | 56 | evlist = perf_evlist__new(); |
57 | if (evlist == NULL) { | 57 | if (evlist == NULL) { |
58 | pr_debug("perf_evlist__new\n"); | 58 | pr_debug("perf_evlist__new\n"); |
59 | goto out_free_cpus; | 59 | goto out_free_cpus; |
60 | } | 60 | } |
61 | 61 | ||
62 | perf_evlist__set_maps(evlist, cpus, threads); | ||
63 | |||
62 | for (i = 0; i < nsyscalls; ++i) { | 64 | for (i = 0; i < nsyscalls; ++i) { |
63 | char name[64]; | 65 | char name[64]; |
64 | 66 | ||
diff --git a/tools/perf/tests/open-syscall-tp-fields.c b/tools/perf/tests/open-syscall-tp-fields.c index 1c52fdc1164e..fc5b9fca8b47 100644 --- a/tools/perf/tests/open-syscall-tp-fields.c +++ b/tools/perf/tests/open-syscall-tp-fields.c | |||
@@ -18,7 +18,7 @@ int test__syscall_open_tp_fields(void) | |||
18 | }; | 18 | }; |
19 | const char *filename = "/etc/passwd"; | 19 | const char *filename = "/etc/passwd"; |
20 | int flags = O_RDONLY | O_DIRECTORY; | 20 | int flags = O_RDONLY | O_DIRECTORY; |
21 | struct perf_evlist *evlist = perf_evlist__new(NULL, NULL); | 21 | struct perf_evlist *evlist = perf_evlist__new(); |
22 | struct perf_evsel *evsel; | 22 | struct perf_evsel *evsel; |
23 | int err = -1, i, nr_events = 0, nr_polls = 0; | 23 | int err = -1, i, nr_events = 0, nr_polls = 0; |
24 | 24 | ||
@@ -48,13 +48,13 @@ int test__syscall_open_tp_fields(void) | |||
48 | err = perf_evlist__open(evlist); | 48 | err = perf_evlist__open(evlist); |
49 | if (err < 0) { | 49 | if (err < 0) { |
50 | pr_debug("perf_evlist__open: %s\n", strerror(errno)); | 50 | pr_debug("perf_evlist__open: %s\n", strerror(errno)); |
51 | goto out_delete_evlist; | 51 | goto out_delete_maps; |
52 | } | 52 | } |
53 | 53 | ||
54 | err = perf_evlist__mmap(evlist, UINT_MAX, false); | 54 | err = perf_evlist__mmap(evlist, UINT_MAX, false); |
55 | if (err < 0) { | 55 | if (err < 0) { |
56 | pr_debug("perf_evlist__mmap: %s\n", strerror(errno)); | 56 | pr_debug("perf_evlist__mmap: %s\n", strerror(errno)); |
57 | goto out_delete_evlist; | 57 | goto out_close_evlist; |
58 | } | 58 | } |
59 | 59 | ||
60 | perf_evlist__enable(evlist); | 60 | perf_evlist__enable(evlist); |
@@ -110,6 +110,10 @@ out_ok: | |||
110 | err = 0; | 110 | err = 0; |
111 | out_munmap: | 111 | out_munmap: |
112 | perf_evlist__munmap(evlist); | 112 | perf_evlist__munmap(evlist); |
113 | out_close_evlist: | ||
114 | perf_evlist__close(evlist); | ||
115 | out_delete_maps: | ||
116 | perf_evlist__delete_maps(evlist); | ||
113 | out_delete_evlist: | 117 | out_delete_evlist: |
114 | perf_evlist__delete(evlist); | 118 | perf_evlist__delete(evlist); |
115 | out: | 119 | out: |
diff --git a/tools/perf/tests/parse-events.c b/tools/perf/tests/parse-events.c index c5636f36fe31..88e2f44cb157 100644 --- a/tools/perf/tests/parse-events.c +++ b/tools/perf/tests/parse-events.c | |||
@@ -3,7 +3,7 @@ | |||
3 | #include "evsel.h" | 3 | #include "evsel.h" |
4 | #include "evlist.h" | 4 | #include "evlist.h" |
5 | #include "sysfs.h" | 5 | #include "sysfs.h" |
6 | #include "debugfs.h" | 6 | #include <lk/debugfs.h> |
7 | #include "tests.h" | 7 | #include "tests.h" |
8 | #include <linux/hw_breakpoint.h> | 8 | #include <linux/hw_breakpoint.h> |
9 | 9 | ||
@@ -1218,7 +1218,7 @@ static int test_event(struct evlist_test *e) | |||
1218 | struct perf_evlist *evlist; | 1218 | struct perf_evlist *evlist; |
1219 | int ret; | 1219 | int ret; |
1220 | 1220 | ||
1221 | evlist = perf_evlist__new(NULL, NULL); | 1221 | evlist = perf_evlist__new(); |
1222 | if (evlist == NULL) | 1222 | if (evlist == NULL) |
1223 | return -ENOMEM; | 1223 | return -ENOMEM; |
1224 | 1224 | ||
diff --git a/tools/perf/tests/perf-record.c b/tools/perf/tests/perf-record.c index 1e8e5128d0da..72d8881873b0 100644 --- a/tools/perf/tests/perf-record.c +++ b/tools/perf/tests/perf-record.c | |||
@@ -45,7 +45,7 @@ int test__PERF_RECORD(void) | |||
45 | }; | 45 | }; |
46 | cpu_set_t cpu_mask; | 46 | cpu_set_t cpu_mask; |
47 | size_t cpu_mask_size = sizeof(cpu_mask); | 47 | size_t cpu_mask_size = sizeof(cpu_mask); |
48 | struct perf_evlist *evlist = perf_evlist__new(NULL, NULL); | 48 | struct perf_evlist *evlist = perf_evlist__new(); |
49 | struct perf_evsel *evsel; | 49 | struct perf_evsel *evsel; |
50 | struct perf_sample sample; | 50 | struct perf_sample sample; |
51 | const char *cmd = "sleep"; | 51 | const char *cmd = "sleep"; |
@@ -93,7 +93,8 @@ int test__PERF_RECORD(void) | |||
93 | * so that we have time to open the evlist (calling sys_perf_event_open | 93 | * so that we have time to open the evlist (calling sys_perf_event_open |
94 | * on all the fds) and then mmap them. | 94 | * on all the fds) and then mmap them. |
95 | */ | 95 | */ |
96 | err = perf_evlist__prepare_workload(evlist, &opts, argv); | 96 | err = perf_evlist__prepare_workload(evlist, &opts.target, argv, |
97 | false, false); | ||
97 | if (err < 0) { | 98 | if (err < 0) { |
98 | pr_debug("Couldn't run the workload!\n"); | 99 | pr_debug("Couldn't run the workload!\n"); |
99 | goto out_delete_maps; | 100 | goto out_delete_maps; |
@@ -142,7 +143,7 @@ int test__PERF_RECORD(void) | |||
142 | err = perf_evlist__mmap(evlist, opts.mmap_pages, false); | 143 | err = perf_evlist__mmap(evlist, opts.mmap_pages, false); |
143 | if (err < 0) { | 144 | if (err < 0) { |
144 | pr_debug("perf_evlist__mmap: %s\n", strerror(errno)); | 145 | pr_debug("perf_evlist__mmap: %s\n", strerror(errno)); |
145 | goto out_delete_maps; | 146 | goto out_close_evlist; |
146 | } | 147 | } |
147 | 148 | ||
148 | /* | 149 | /* |
@@ -305,6 +306,8 @@ found_exit: | |||
305 | } | 306 | } |
306 | out_err: | 307 | out_err: |
307 | perf_evlist__munmap(evlist); | 308 | perf_evlist__munmap(evlist); |
309 | out_close_evlist: | ||
310 | perf_evlist__close(evlist); | ||
308 | out_delete_maps: | 311 | out_delete_maps: |
309 | perf_evlist__delete_maps(evlist); | 312 | perf_evlist__delete_maps(evlist); |
310 | out_delete_evlist: | 313 | out_delete_evlist: |
diff --git a/tools/perf/tests/sw-clock.c b/tools/perf/tests/sw-clock.c new file mode 100644 index 000000000000..2e41e2d32ccc --- /dev/null +++ b/tools/perf/tests/sw-clock.c | |||
@@ -0,0 +1,119 @@ | |||
1 | #include <unistd.h> | ||
2 | #include <stdlib.h> | ||
3 | #include <signal.h> | ||
4 | #include <sys/mman.h> | ||
5 | |||
6 | #include "tests.h" | ||
7 | #include "util/evsel.h" | ||
8 | #include "util/evlist.h" | ||
9 | #include "util/cpumap.h" | ||
10 | #include "util/thread_map.h" | ||
11 | |||
12 | #define NR_LOOPS 1000000 | ||
13 | |||
14 | /* | ||
15 | * This test will open software clock events (cpu-clock, task-clock) | ||
16 | * then check their frequency -> period conversion has no artifact of | ||
17 | * setting period to 1 forcefully. | ||
18 | */ | ||
19 | static int __test__sw_clock_freq(enum perf_sw_ids clock_id) | ||
20 | { | ||
21 | int i, err = -1; | ||
22 | volatile int tmp = 0; | ||
23 | u64 total_periods = 0; | ||
24 | int nr_samples = 0; | ||
25 | union perf_event *event; | ||
26 | struct perf_evsel *evsel; | ||
27 | struct perf_evlist *evlist; | ||
28 | struct perf_event_attr attr = { | ||
29 | .type = PERF_TYPE_SOFTWARE, | ||
30 | .config = clock_id, | ||
31 | .sample_type = PERF_SAMPLE_PERIOD, | ||
32 | .exclude_kernel = 1, | ||
33 | .disabled = 1, | ||
34 | .freq = 1, | ||
35 | }; | ||
36 | |||
37 | attr.sample_freq = 10000; | ||
38 | |||
39 | evlist = perf_evlist__new(); | ||
40 | if (evlist == NULL) { | ||
41 | pr_debug("perf_evlist__new\n"); | ||
42 | return -1; | ||
43 | } | ||
44 | |||
45 | evsel = perf_evsel__new(&attr, 0); | ||
46 | if (evsel == NULL) { | ||
47 | pr_debug("perf_evsel__new\n"); | ||
48 | goto out_free_evlist; | ||
49 | } | ||
50 | perf_evlist__add(evlist, evsel); | ||
51 | |||
52 | evlist->cpus = cpu_map__dummy_new(); | ||
53 | evlist->threads = thread_map__new_by_tid(getpid()); | ||
54 | if (!evlist->cpus || !evlist->threads) { | ||
55 | err = -ENOMEM; | ||
56 | pr_debug("Not enough memory to create thread/cpu maps\n"); | ||
57 | goto out_delete_maps; | ||
58 | } | ||
59 | |||
60 | perf_evlist__open(evlist); | ||
61 | |||
62 | err = perf_evlist__mmap(evlist, 128, true); | ||
63 | if (err < 0) { | ||
64 | pr_debug("failed to mmap event: %d (%s)\n", errno, | ||
65 | strerror(errno)); | ||
66 | goto out_close_evlist; | ||
67 | } | ||
68 | |||
69 | perf_evlist__enable(evlist); | ||
70 | |||
71 | /* collect samples */ | ||
72 | for (i = 0; i < NR_LOOPS; i++) | ||
73 | tmp++; | ||
74 | |||
75 | perf_evlist__disable(evlist); | ||
76 | |||
77 | while ((event = perf_evlist__mmap_read(evlist, 0)) != NULL) { | ||
78 | struct perf_sample sample; | ||
79 | |||
80 | if (event->header.type != PERF_RECORD_SAMPLE) | ||
81 | continue; | ||
82 | |||
83 | err = perf_evlist__parse_sample(evlist, event, &sample); | ||
84 | if (err < 0) { | ||
85 | pr_debug("Error during parse sample\n"); | ||
86 | goto out_unmap_evlist; | ||
87 | } | ||
88 | |||
89 | total_periods += sample.period; | ||
90 | nr_samples++; | ||
91 | } | ||
92 | |||
93 | if ((u64) nr_samples == total_periods) { | ||
94 | pr_debug("All (%d) samples have period value of 1!\n", | ||
95 | nr_samples); | ||
96 | err = -1; | ||
97 | } | ||
98 | |||
99 | out_unmap_evlist: | ||
100 | perf_evlist__munmap(evlist); | ||
101 | out_close_evlist: | ||
102 | perf_evlist__close(evlist); | ||
103 | out_delete_maps: | ||
104 | perf_evlist__delete_maps(evlist); | ||
105 | out_free_evlist: | ||
106 | perf_evlist__delete(evlist); | ||
107 | return err; | ||
108 | } | ||
109 | |||
110 | int test__sw_clock_freq(void) | ||
111 | { | ||
112 | int ret; | ||
113 | |||
114 | ret = __test__sw_clock_freq(PERF_COUNT_SW_CPU_CLOCK); | ||
115 | if (!ret) | ||
116 | ret = __test__sw_clock_freq(PERF_COUNT_SW_TASK_CLOCK); | ||
117 | |||
118 | return ret; | ||
119 | } | ||
diff --git a/tools/perf/tests/task-exit.c b/tools/perf/tests/task-exit.c new file mode 100644 index 000000000000..28fe5894b061 --- /dev/null +++ b/tools/perf/tests/task-exit.c | |||
@@ -0,0 +1,123 @@ | |||
1 | #include "evlist.h" | ||
2 | #include "evsel.h" | ||
3 | #include "thread_map.h" | ||
4 | #include "cpumap.h" | ||
5 | #include "tests.h" | ||
6 | |||
7 | #include <signal.h> | ||
8 | |||
9 | static int exited; | ||
10 | static int nr_exit; | ||
11 | |||
12 | static void sig_handler(int sig) | ||
13 | { | ||
14 | exited = 1; | ||
15 | |||
16 | if (sig == SIGUSR1) | ||
17 | nr_exit = -1; | ||
18 | } | ||
19 | |||
20 | /* | ||
21 | * This test will start a workload that does nothing then it checks | ||
22 | * if the number of exit event reported by the kernel is 1 or not | ||
23 | * in order to check the kernel returns correct number of event. | ||
24 | */ | ||
25 | int test__task_exit(void) | ||
26 | { | ||
27 | int err = -1; | ||
28 | union perf_event *event; | ||
29 | struct perf_evsel *evsel; | ||
30 | struct perf_evlist *evlist; | ||
31 | struct perf_target target = { | ||
32 | .uid = UINT_MAX, | ||
33 | .uses_mmap = true, | ||
34 | }; | ||
35 | const char *argv[] = { "true", NULL }; | ||
36 | |||
37 | signal(SIGCHLD, sig_handler); | ||
38 | signal(SIGUSR1, sig_handler); | ||
39 | |||
40 | evlist = perf_evlist__new(); | ||
41 | if (evlist == NULL) { | ||
42 | pr_debug("perf_evlist__new\n"); | ||
43 | return -1; | ||
44 | } | ||
45 | /* | ||
46 | * We need at least one evsel in the evlist, use the default | ||
47 | * one: "cycles". | ||
48 | */ | ||
49 | err = perf_evlist__add_default(evlist); | ||
50 | if (err < 0) { | ||
51 | pr_debug("Not enough memory to create evsel\n"); | ||
52 | goto out_free_evlist; | ||
53 | } | ||
54 | |||
55 | /* | ||
56 | * Create maps of threads and cpus to monitor. In this case | ||
57 | * we start with all threads and cpus (-1, -1) but then in | ||
58 | * perf_evlist__prepare_workload we'll fill in the only thread | ||
59 | * we're monitoring, the one forked there. | ||
60 | */ | ||
61 | evlist->cpus = cpu_map__dummy_new(); | ||
62 | evlist->threads = thread_map__new_by_tid(-1); | ||
63 | if (!evlist->cpus || !evlist->threads) { | ||
64 | err = -ENOMEM; | ||
65 | pr_debug("Not enough memory to create thread/cpu maps\n"); | ||
66 | goto out_delete_maps; | ||
67 | } | ||
68 | |||
69 | err = perf_evlist__prepare_workload(evlist, &target, argv, false, true); | ||
70 | if (err < 0) { | ||
71 | pr_debug("Couldn't run the workload!\n"); | ||
72 | goto out_delete_maps; | ||
73 | } | ||
74 | |||
75 | evsel = perf_evlist__first(evlist); | ||
76 | evsel->attr.task = 1; | ||
77 | evsel->attr.sample_freq = 0; | ||
78 | evsel->attr.inherit = 0; | ||
79 | evsel->attr.watermark = 0; | ||
80 | evsel->attr.wakeup_events = 1; | ||
81 | evsel->attr.exclude_kernel = 1; | ||
82 | |||
83 | err = perf_evlist__open(evlist); | ||
84 | if (err < 0) { | ||
85 | pr_debug("Couldn't open the evlist: %s\n", strerror(-err)); | ||
86 | goto out_delete_maps; | ||
87 | } | ||
88 | |||
89 | if (perf_evlist__mmap(evlist, 128, true) < 0) { | ||
90 | pr_debug("failed to mmap events: %d (%s)\n", errno, | ||
91 | strerror(errno)); | ||
92 | goto out_close_evlist; | ||
93 | } | ||
94 | |||
95 | perf_evlist__start_workload(evlist); | ||
96 | |||
97 | retry: | ||
98 | while ((event = perf_evlist__mmap_read(evlist, 0)) != NULL) { | ||
99 | if (event->header.type != PERF_RECORD_EXIT) | ||
100 | continue; | ||
101 | |||
102 | nr_exit++; | ||
103 | } | ||
104 | |||
105 | if (!exited || !nr_exit) { | ||
106 | poll(evlist->pollfd, evlist->nr_fds, -1); | ||
107 | goto retry; | ||
108 | } | ||
109 | |||
110 | if (nr_exit != 1) { | ||
111 | pr_debug("received %d EXIT records\n", nr_exit); | ||
112 | err = -1; | ||
113 | } | ||
114 | |||
115 | perf_evlist__munmap(evlist); | ||
116 | out_close_evlist: | ||
117 | perf_evlist__close(evlist); | ||
118 | out_delete_maps: | ||
119 | perf_evlist__delete_maps(evlist); | ||
120 | out_free_evlist: | ||
121 | perf_evlist__delete(evlist); | ||
122 | return err; | ||
123 | } | ||
diff --git a/tools/perf/tests/tests.h b/tools/perf/tests/tests.h index 5de0be1ff4b6..dd7feae2d37b 100644 --- a/tools/perf/tests/tests.h +++ b/tools/perf/tests/tests.h | |||
@@ -23,5 +23,9 @@ int test__dso_data(void); | |||
23 | int test__parse_events(void); | 23 | int test__parse_events(void); |
24 | int test__hists_link(void); | 24 | int test__hists_link(void); |
25 | int test__python_use(void); | 25 | int test__python_use(void); |
26 | int test__bp_signal(void); | ||
27 | int test__bp_signal_overflow(void); | ||
28 | int test__task_exit(void); | ||
29 | int test__sw_clock_freq(void); | ||
26 | 30 | ||
27 | #endif /* TESTS_H */ | 31 | #endif /* TESTS_H */ |
diff --git a/tools/perf/ui/browsers/annotate.c b/tools/perf/ui/browsers/annotate.c index 7dca1555c610..f56247a03a22 100644 --- a/tools/perf/ui/browsers/annotate.c +++ b/tools/perf/ui/browsers/annotate.c | |||
@@ -8,15 +8,20 @@ | |||
8 | #include "../../util/hist.h" | 8 | #include "../../util/hist.h" |
9 | #include "../../util/sort.h" | 9 | #include "../../util/sort.h" |
10 | #include "../../util/symbol.h" | 10 | #include "../../util/symbol.h" |
11 | #include "../../util/evsel.h" | ||
11 | #include <pthread.h> | 12 | #include <pthread.h> |
12 | #include <newt.h> | 13 | #include <newt.h> |
13 | 14 | ||
14 | struct browser_disasm_line { | 15 | struct browser_disasm_line { |
15 | struct rb_node rb_node; | 16 | struct rb_node rb_node; |
16 | double percent; | ||
17 | u32 idx; | 17 | u32 idx; |
18 | int idx_asm; | 18 | int idx_asm; |
19 | int jump_sources; | 19 | int jump_sources; |
20 | /* | ||
21 | * actual length of this array is saved on the nr_events field | ||
22 | * of the struct annotate_browser | ||
23 | */ | ||
24 | double percent[1]; | ||
20 | }; | 25 | }; |
21 | 26 | ||
22 | static struct annotate_browser_opt { | 27 | static struct annotate_browser_opt { |
@@ -33,8 +38,9 @@ struct annotate_browser { | |||
33 | struct ui_browser b; | 38 | struct ui_browser b; |
34 | struct rb_root entries; | 39 | struct rb_root entries; |
35 | struct rb_node *curr_hot; | 40 | struct rb_node *curr_hot; |
36 | struct disasm_line *selection; | 41 | struct disasm_line *selection; |
37 | struct disasm_line **offsets; | 42 | struct disasm_line **offsets; |
43 | int nr_events; | ||
38 | u64 start; | 44 | u64 start; |
39 | int nr_asm_entries; | 45 | int nr_asm_entries; |
40 | int nr_entries; | 46 | int nr_entries; |
@@ -94,14 +100,24 @@ static void annotate_browser__write(struct ui_browser *browser, void *entry, int | |||
94 | (!current_entry || (browser->use_navkeypressed && | 100 | (!current_entry || (browser->use_navkeypressed && |
95 | !browser->navkeypressed))); | 101 | !browser->navkeypressed))); |
96 | int width = browser->width, printed; | 102 | int width = browser->width, printed; |
103 | int i, pcnt_width = 7 * ab->nr_events; | ||
104 | double percent_max = 0.0; | ||
97 | char bf[256]; | 105 | char bf[256]; |
98 | 106 | ||
99 | if (dl->offset != -1 && bdl->percent != 0.0) { | 107 | for (i = 0; i < ab->nr_events; i++) { |
100 | ui_browser__set_percent_color(browser, bdl->percent, current_entry); | 108 | if (bdl->percent[i] > percent_max) |
101 | slsmg_printf("%6.2f ", bdl->percent); | 109 | percent_max = bdl->percent[i]; |
110 | } | ||
111 | |||
112 | if (dl->offset != -1 && percent_max != 0.0) { | ||
113 | for (i = 0; i < ab->nr_events; i++) { | ||
114 | ui_browser__set_percent_color(browser, bdl->percent[i], | ||
115 | current_entry); | ||
116 | slsmg_printf("%6.2f ", bdl->percent[i]); | ||
117 | } | ||
102 | } else { | 118 | } else { |
103 | ui_browser__set_percent_color(browser, 0, current_entry); | 119 | ui_browser__set_percent_color(browser, 0, current_entry); |
104 | slsmg_write_nstring(" ", 7); | 120 | slsmg_write_nstring(" ", pcnt_width); |
105 | } | 121 | } |
106 | 122 | ||
107 | SLsmg_write_char(' '); | 123 | SLsmg_write_char(' '); |
@@ -111,12 +127,12 @@ static void annotate_browser__write(struct ui_browser *browser, void *entry, int | |||
111 | width += 1; | 127 | width += 1; |
112 | 128 | ||
113 | if (!*dl->line) | 129 | if (!*dl->line) |
114 | slsmg_write_nstring(" ", width - 7); | 130 | slsmg_write_nstring(" ", width - pcnt_width); |
115 | else if (dl->offset == -1) { | 131 | else if (dl->offset == -1) { |
116 | printed = scnprintf(bf, sizeof(bf), "%*s ", | 132 | printed = scnprintf(bf, sizeof(bf), "%*s ", |
117 | ab->addr_width, " "); | 133 | ab->addr_width, " "); |
118 | slsmg_write_nstring(bf, printed); | 134 | slsmg_write_nstring(bf, printed); |
119 | slsmg_write_nstring(dl->line, width - printed - 6); | 135 | slsmg_write_nstring(dl->line, width - printed - pcnt_width + 1); |
120 | } else { | 136 | } else { |
121 | u64 addr = dl->offset; | 137 | u64 addr = dl->offset; |
122 | int color = -1; | 138 | int color = -1; |
@@ -175,7 +191,7 @@ static void annotate_browser__write(struct ui_browser *browser, void *entry, int | |||
175 | } | 191 | } |
176 | 192 | ||
177 | disasm_line__scnprintf(dl, bf, sizeof(bf), !annotate_browser__opts.use_offset); | 193 | disasm_line__scnprintf(dl, bf, sizeof(bf), !annotate_browser__opts.use_offset); |
178 | slsmg_write_nstring(bf, width - 10 - printed); | 194 | slsmg_write_nstring(bf, width - pcnt_width - 3 - printed); |
179 | } | 195 | } |
180 | 196 | ||
181 | if (current_entry) | 197 | if (current_entry) |
@@ -200,6 +216,7 @@ static void annotate_browser__draw_current_jump(struct ui_browser *browser) | |||
200 | unsigned int from, to; | 216 | unsigned int from, to; |
201 | struct map_symbol *ms = ab->b.priv; | 217 | struct map_symbol *ms = ab->b.priv; |
202 | struct symbol *sym = ms->sym; | 218 | struct symbol *sym = ms->sym; |
219 | u8 pcnt_width = 7; | ||
203 | 220 | ||
204 | /* PLT symbols contain external offsets */ | 221 | /* PLT symbols contain external offsets */ |
205 | if (strstr(sym->name, "@plt")) | 222 | if (strstr(sym->name, "@plt")) |
@@ -223,57 +240,44 @@ static void annotate_browser__draw_current_jump(struct ui_browser *browser) | |||
223 | to = (u64)btarget->idx; | 240 | to = (u64)btarget->idx; |
224 | } | 241 | } |
225 | 242 | ||
243 | pcnt_width *= ab->nr_events; | ||
244 | |||
226 | ui_browser__set_color(browser, HE_COLORSET_CODE); | 245 | ui_browser__set_color(browser, HE_COLORSET_CODE); |
227 | __ui_browser__line_arrow(browser, 9 + ab->addr_width, from, to); | 246 | __ui_browser__line_arrow(browser, pcnt_width + 2 + ab->addr_width, |
247 | from, to); | ||
228 | } | 248 | } |
229 | 249 | ||
230 | static unsigned int annotate_browser__refresh(struct ui_browser *browser) | 250 | static unsigned int annotate_browser__refresh(struct ui_browser *browser) |
231 | { | 251 | { |
252 | struct annotate_browser *ab = container_of(browser, struct annotate_browser, b); | ||
232 | int ret = ui_browser__list_head_refresh(browser); | 253 | int ret = ui_browser__list_head_refresh(browser); |
254 | int pcnt_width; | ||
255 | |||
256 | pcnt_width = 7 * ab->nr_events; | ||
233 | 257 | ||
234 | if (annotate_browser__opts.jump_arrows) | 258 | if (annotate_browser__opts.jump_arrows) |
235 | annotate_browser__draw_current_jump(browser); | 259 | annotate_browser__draw_current_jump(browser); |
236 | 260 | ||
237 | ui_browser__set_color(browser, HE_COLORSET_NORMAL); | 261 | ui_browser__set_color(browser, HE_COLORSET_NORMAL); |
238 | __ui_browser__vline(browser, 7, 0, browser->height - 1); | 262 | __ui_browser__vline(browser, pcnt_width, 0, browser->height - 1); |
239 | return ret; | 263 | return ret; |
240 | } | 264 | } |
241 | 265 | ||
242 | static double disasm_line__calc_percent(struct disasm_line *dl, struct symbol *sym, int evidx) | 266 | static int disasm__cmp(struct browser_disasm_line *a, |
267 | struct browser_disasm_line *b, int nr_pcnt) | ||
243 | { | 268 | { |
244 | double percent = 0.0; | 269 | int i; |
245 | |||
246 | if (dl->offset != -1) { | ||
247 | int len = sym->end - sym->start; | ||
248 | unsigned int hits = 0; | ||
249 | struct annotation *notes = symbol__annotation(sym); | ||
250 | struct source_line *src_line = notes->src->lines; | ||
251 | struct sym_hist *h = annotation__histogram(notes, evidx); | ||
252 | s64 offset = dl->offset; | ||
253 | struct disasm_line *next; | ||
254 | 270 | ||
255 | next = disasm__get_next_ip_line(¬es->src->source, dl); | 271 | for (i = 0; i < nr_pcnt; i++) { |
256 | while (offset < (s64)len && | 272 | if (a->percent[i] == b->percent[i]) |
257 | (next == NULL || offset < next->offset)) { | 273 | continue; |
258 | if (src_line) { | 274 | return a->percent[i] < b->percent[i]; |
259 | percent += src_line[offset].percent; | ||
260 | } else | ||
261 | hits += h->addr[offset]; | ||
262 | |||
263 | ++offset; | ||
264 | } | ||
265 | /* | ||
266 | * If the percentage wasn't already calculated in | ||
267 | * symbol__get_source_line, do it now: | ||
268 | */ | ||
269 | if (src_line == NULL && h->sum) | ||
270 | percent = 100.0 * hits / h->sum; | ||
271 | } | 275 | } |
272 | 276 | return 0; | |
273 | return percent; | ||
274 | } | 277 | } |
275 | 278 | ||
276 | static void disasm_rb_tree__insert(struct rb_root *root, struct browser_disasm_line *bdl) | 279 | static void disasm_rb_tree__insert(struct rb_root *root, struct browser_disasm_line *bdl, |
280 | int nr_events) | ||
277 | { | 281 | { |
278 | struct rb_node **p = &root->rb_node; | 282 | struct rb_node **p = &root->rb_node; |
279 | struct rb_node *parent = NULL; | 283 | struct rb_node *parent = NULL; |
@@ -282,7 +286,8 @@ static void disasm_rb_tree__insert(struct rb_root *root, struct browser_disasm_l | |||
282 | while (*p != NULL) { | 286 | while (*p != NULL) { |
283 | parent = *p; | 287 | parent = *p; |
284 | l = rb_entry(parent, struct browser_disasm_line, rb_node); | 288 | l = rb_entry(parent, struct browser_disasm_line, rb_node); |
285 | if (bdl->percent < l->percent) | 289 | |
290 | if (disasm__cmp(bdl, l, nr_events)) | ||
286 | p = &(*p)->rb_left; | 291 | p = &(*p)->rb_left; |
287 | else | 292 | else |
288 | p = &(*p)->rb_right; | 293 | p = &(*p)->rb_right; |
@@ -331,12 +336,13 @@ static void annotate_browser__set_rb_top(struct annotate_browser *browser, | |||
331 | } | 336 | } |
332 | 337 | ||
333 | static void annotate_browser__calc_percent(struct annotate_browser *browser, | 338 | static void annotate_browser__calc_percent(struct annotate_browser *browser, |
334 | int evidx) | 339 | struct perf_evsel *evsel) |
335 | { | 340 | { |
336 | struct map_symbol *ms = browser->b.priv; | 341 | struct map_symbol *ms = browser->b.priv; |
337 | struct symbol *sym = ms->sym; | 342 | struct symbol *sym = ms->sym; |
338 | struct annotation *notes = symbol__annotation(sym); | 343 | struct annotation *notes = symbol__annotation(sym); |
339 | struct disasm_line *pos; | 344 | struct disasm_line *pos, *next; |
345 | s64 len = symbol__size(sym); | ||
340 | 346 | ||
341 | browser->entries = RB_ROOT; | 347 | browser->entries = RB_ROOT; |
342 | 348 | ||
@@ -344,12 +350,34 @@ static void annotate_browser__calc_percent(struct annotate_browser *browser, | |||
344 | 350 | ||
345 | list_for_each_entry(pos, ¬es->src->source, node) { | 351 | list_for_each_entry(pos, ¬es->src->source, node) { |
346 | struct browser_disasm_line *bpos = disasm_line__browser(pos); | 352 | struct browser_disasm_line *bpos = disasm_line__browser(pos); |
347 | bpos->percent = disasm_line__calc_percent(pos, sym, evidx); | 353 | const char *path = NULL; |
348 | if (bpos->percent < 0.01) { | 354 | double max_percent = 0.0; |
355 | int i; | ||
356 | |||
357 | if (pos->offset == -1) { | ||
358 | RB_CLEAR_NODE(&bpos->rb_node); | ||
359 | continue; | ||
360 | } | ||
361 | |||
362 | next = disasm__get_next_ip_line(¬es->src->source, pos); | ||
363 | |||
364 | for (i = 0; i < browser->nr_events; i++) { | ||
365 | bpos->percent[i] = disasm__calc_percent(notes, | ||
366 | evsel->idx + i, | ||
367 | pos->offset, | ||
368 | next ? next->offset : len, | ||
369 | &path); | ||
370 | |||
371 | if (max_percent < bpos->percent[i]) | ||
372 | max_percent = bpos->percent[i]; | ||
373 | } | ||
374 | |||
375 | if (max_percent < 0.01) { | ||
349 | RB_CLEAR_NODE(&bpos->rb_node); | 376 | RB_CLEAR_NODE(&bpos->rb_node); |
350 | continue; | 377 | continue; |
351 | } | 378 | } |
352 | disasm_rb_tree__insert(&browser->entries, bpos); | 379 | disasm_rb_tree__insert(&browser->entries, bpos, |
380 | browser->nr_events); | ||
353 | } | 381 | } |
354 | pthread_mutex_unlock(¬es->lock); | 382 | pthread_mutex_unlock(¬es->lock); |
355 | 383 | ||
@@ -401,7 +429,8 @@ static void annotate_browser__init_asm_mode(struct annotate_browser *browser) | |||
401 | browser->b.nr_entries = browser->nr_asm_entries; | 429 | browser->b.nr_entries = browser->nr_asm_entries; |
402 | } | 430 | } |
403 | 431 | ||
404 | static bool annotate_browser__callq(struct annotate_browser *browser, int evidx, | 432 | static bool annotate_browser__callq(struct annotate_browser *browser, |
433 | struct perf_evsel *evsel, | ||
405 | struct hist_browser_timer *hbt) | 434 | struct hist_browser_timer *hbt) |
406 | { | 435 | { |
407 | struct map_symbol *ms = browser->b.priv; | 436 | struct map_symbol *ms = browser->b.priv; |
@@ -432,7 +461,7 @@ static bool annotate_browser__callq(struct annotate_browser *browser, int evidx, | |||
432 | } | 461 | } |
433 | 462 | ||
434 | pthread_mutex_unlock(¬es->lock); | 463 | pthread_mutex_unlock(¬es->lock); |
435 | symbol__tui_annotate(target, ms->map, evidx, hbt); | 464 | symbol__tui_annotate(target, ms->map, evsel, hbt); |
436 | ui_browser__show_title(&browser->b, sym->name); | 465 | ui_browser__show_title(&browser->b, sym->name); |
437 | return true; | 466 | return true; |
438 | } | 467 | } |
@@ -615,7 +644,8 @@ static void annotate_browser__update_addr_width(struct annotate_browser *browser | |||
615 | browser->addr_width += browser->jumps_width + 1; | 644 | browser->addr_width += browser->jumps_width + 1; |
616 | } | 645 | } |
617 | 646 | ||
618 | static int annotate_browser__run(struct annotate_browser *browser, int evidx, | 647 | static int annotate_browser__run(struct annotate_browser *browser, |
648 | struct perf_evsel *evsel, | ||
619 | struct hist_browser_timer *hbt) | 649 | struct hist_browser_timer *hbt) |
620 | { | 650 | { |
621 | struct rb_node *nd = NULL; | 651 | struct rb_node *nd = NULL; |
@@ -628,7 +658,7 @@ static int annotate_browser__run(struct annotate_browser *browser, int evidx, | |||
628 | if (ui_browser__show(&browser->b, sym->name, help) < 0) | 658 | if (ui_browser__show(&browser->b, sym->name, help) < 0) |
629 | return -1; | 659 | return -1; |
630 | 660 | ||
631 | annotate_browser__calc_percent(browser, evidx); | 661 | annotate_browser__calc_percent(browser, evsel); |
632 | 662 | ||
633 | if (browser->curr_hot) { | 663 | if (browser->curr_hot) { |
634 | annotate_browser__set_rb_top(browser, browser->curr_hot); | 664 | annotate_browser__set_rb_top(browser, browser->curr_hot); |
@@ -641,7 +671,7 @@ static int annotate_browser__run(struct annotate_browser *browser, int evidx, | |||
641 | key = ui_browser__run(&browser->b, delay_secs); | 671 | key = ui_browser__run(&browser->b, delay_secs); |
642 | 672 | ||
643 | if (delay_secs != 0) { | 673 | if (delay_secs != 0) { |
644 | annotate_browser__calc_percent(browser, evidx); | 674 | annotate_browser__calc_percent(browser, evsel); |
645 | /* | 675 | /* |
646 | * Current line focus got out of the list of most active | 676 | * Current line focus got out of the list of most active |
647 | * lines, NULL it so that if TAB|UNTAB is pressed, we | 677 | * lines, NULL it so that if TAB|UNTAB is pressed, we |
@@ -657,7 +687,7 @@ static int annotate_browser__run(struct annotate_browser *browser, int evidx, | |||
657 | hbt->timer(hbt->arg); | 687 | hbt->timer(hbt->arg); |
658 | 688 | ||
659 | if (delay_secs != 0) | 689 | if (delay_secs != 0) |
660 | symbol__annotate_decay_histogram(sym, evidx); | 690 | symbol__annotate_decay_histogram(sym, evsel->idx); |
661 | continue; | 691 | continue; |
662 | case K_TAB: | 692 | case K_TAB: |
663 | if (nd != NULL) { | 693 | if (nd != NULL) { |
@@ -754,7 +784,7 @@ show_help: | |||
754 | goto show_sup_ins; | 784 | goto show_sup_ins; |
755 | goto out; | 785 | goto out; |
756 | } else if (!(annotate_browser__jump(browser) || | 786 | } else if (!(annotate_browser__jump(browser) || |
757 | annotate_browser__callq(browser, evidx, hbt))) { | 787 | annotate_browser__callq(browser, evsel, hbt))) { |
758 | show_sup_ins: | 788 | show_sup_ins: |
759 | ui_helpline__puts("Actions are only available for 'callq', 'retq' & jump instructions."); | 789 | ui_helpline__puts("Actions are only available for 'callq', 'retq' & jump instructions."); |
760 | } | 790 | } |
@@ -776,10 +806,10 @@ out: | |||
776 | return key; | 806 | return key; |
777 | } | 807 | } |
778 | 808 | ||
779 | int hist_entry__tui_annotate(struct hist_entry *he, int evidx, | 809 | int hist_entry__tui_annotate(struct hist_entry *he, struct perf_evsel *evsel, |
780 | struct hist_browser_timer *hbt) | 810 | struct hist_browser_timer *hbt) |
781 | { | 811 | { |
782 | return symbol__tui_annotate(he->ms.sym, he->ms.map, evidx, hbt); | 812 | return symbol__tui_annotate(he->ms.sym, he->ms.map, evsel, hbt); |
783 | } | 813 | } |
784 | 814 | ||
785 | static void annotate_browser__mark_jump_targets(struct annotate_browser *browser, | 815 | static void annotate_browser__mark_jump_targets(struct annotate_browser *browser, |
@@ -826,7 +856,8 @@ static inline int width_jumps(int n) | |||
826 | return 1; | 856 | return 1; |
827 | } | 857 | } |
828 | 858 | ||
829 | int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx, | 859 | int symbol__tui_annotate(struct symbol *sym, struct map *map, |
860 | struct perf_evsel *evsel, | ||
830 | struct hist_browser_timer *hbt) | 861 | struct hist_browser_timer *hbt) |
831 | { | 862 | { |
832 | struct disasm_line *pos, *n; | 863 | struct disasm_line *pos, *n; |
@@ -847,6 +878,8 @@ int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx, | |||
847 | }, | 878 | }, |
848 | }; | 879 | }; |
849 | int ret = -1; | 880 | int ret = -1; |
881 | int nr_pcnt = 1; | ||
882 | size_t sizeof_bdl = sizeof(struct browser_disasm_line); | ||
850 | 883 | ||
851 | if (sym == NULL) | 884 | if (sym == NULL) |
852 | return -1; | 885 | return -1; |
@@ -862,7 +895,12 @@ int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx, | |||
862 | return -1; | 895 | return -1; |
863 | } | 896 | } |
864 | 897 | ||
865 | if (symbol__annotate(sym, map, sizeof(struct browser_disasm_line)) < 0) { | 898 | if (perf_evsel__is_group_event(evsel)) { |
899 | nr_pcnt = evsel->nr_members; | ||
900 | sizeof_bdl += sizeof(double) * (nr_pcnt - 1); | ||
901 | } | ||
902 | |||
903 | if (symbol__annotate(sym, map, sizeof_bdl) < 0) { | ||
866 | ui__error("%s", ui_helpline__last_msg); | 904 | ui__error("%s", ui_helpline__last_msg); |
867 | goto out_free_offsets; | 905 | goto out_free_offsets; |
868 | } | 906 | } |
@@ -900,6 +938,7 @@ int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx, | |||
900 | browser.addr_width = browser.target_width = browser.min_addr_width = hex_width(size); | 938 | browser.addr_width = browser.target_width = browser.min_addr_width = hex_width(size); |
901 | browser.max_addr_width = hex_width(sym->end); | 939 | browser.max_addr_width = hex_width(sym->end); |
902 | browser.jumps_width = width_jumps(browser.max_jump_sources); | 940 | browser.jumps_width = width_jumps(browser.max_jump_sources); |
941 | browser.nr_events = nr_pcnt; | ||
903 | browser.b.nr_entries = browser.nr_entries; | 942 | browser.b.nr_entries = browser.nr_entries; |
904 | browser.b.entries = ¬es->src->source, | 943 | browser.b.entries = ¬es->src->source, |
905 | browser.b.width += 18; /* Percentage */ | 944 | browser.b.width += 18; /* Percentage */ |
@@ -909,7 +948,7 @@ int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx, | |||
909 | 948 | ||
910 | annotate_browser__update_addr_width(&browser); | 949 | annotate_browser__update_addr_width(&browser); |
911 | 950 | ||
912 | ret = annotate_browser__run(&browser, evidx, hbt); | 951 | ret = annotate_browser__run(&browser, evsel, hbt); |
913 | list_for_each_entry_safe(pos, n, ¬es->src->source, node) { | 952 | list_for_each_entry_safe(pos, n, ¬es->src->source, node) { |
914 | list_del(&pos->node); | 953 | list_del(&pos->node); |
915 | disasm_line__free(pos); | 954 | disasm_line__free(pos); |
diff --git a/tools/perf/ui/browsers/hists.c b/tools/perf/ui/browsers/hists.c index aa22704047d6..a5843fd6ab51 100644 --- a/tools/perf/ui/browsers/hists.c +++ b/tools/perf/ui/browsers/hists.c | |||
@@ -1193,7 +1193,7 @@ static int hists__browser_title(struct hists *hists, char *bf, size_t size, | |||
1193 | char buf[512]; | 1193 | char buf[512]; |
1194 | size_t buflen = sizeof(buf); | 1194 | size_t buflen = sizeof(buf); |
1195 | 1195 | ||
1196 | if (symbol_conf.event_group && evsel->nr_members > 1) { | 1196 | if (perf_evsel__is_group_event(evsel)) { |
1197 | struct perf_evsel *pos; | 1197 | struct perf_evsel *pos; |
1198 | 1198 | ||
1199 | perf_evsel__group_desc(evsel, buf, buflen); | 1199 | perf_evsel__group_desc(evsel, buf, buflen); |
@@ -1599,7 +1599,7 @@ do_annotate: | |||
1599 | * Don't let this be freed, say, by hists__decay_entry. | 1599 | * Don't let this be freed, say, by hists__decay_entry. |
1600 | */ | 1600 | */ |
1601 | he->used = true; | 1601 | he->used = true; |
1602 | err = hist_entry__tui_annotate(he, evsel->idx, hbt); | 1602 | err = hist_entry__tui_annotate(he, evsel, hbt); |
1603 | he->used = false; | 1603 | he->used = false; |
1604 | /* | 1604 | /* |
1605 | * offer option to annotate the other branch source or target | 1605 | * offer option to annotate the other branch source or target |
@@ -1709,7 +1709,7 @@ static void perf_evsel_menu__write(struct ui_browser *browser, | |||
1709 | ui_browser__set_color(browser, current_entry ? HE_COLORSET_SELECTED : | 1709 | ui_browser__set_color(browser, current_entry ? HE_COLORSET_SELECTED : |
1710 | HE_COLORSET_NORMAL); | 1710 | HE_COLORSET_NORMAL); |
1711 | 1711 | ||
1712 | if (symbol_conf.event_group && evsel->nr_members > 1) { | 1712 | if (perf_evsel__is_group_event(evsel)) { |
1713 | struct perf_evsel *pos; | 1713 | struct perf_evsel *pos; |
1714 | 1714 | ||
1715 | ev_name = perf_evsel__group_name(evsel); | 1715 | ev_name = perf_evsel__group_name(evsel); |
diff --git a/tools/perf/ui/gtk/annotate.c b/tools/perf/ui/gtk/annotate.c index 7d8dc581a545..f538794615db 100644 --- a/tools/perf/ui/gtk/annotate.c +++ b/tools/perf/ui/gtk/annotate.c | |||
@@ -1,6 +1,7 @@ | |||
1 | #include "gtk.h" | 1 | #include "gtk.h" |
2 | #include "util/debug.h" | 2 | #include "util/debug.h" |
3 | #include "util/annotate.h" | 3 | #include "util/annotate.h" |
4 | #include "util/evsel.h" | ||
4 | #include "ui/helpline.h" | 5 | #include "ui/helpline.h" |
5 | 6 | ||
6 | 7 | ||
@@ -32,7 +33,7 @@ static int perf_gtk__get_percent(char *buf, size_t size, struct symbol *sym, | |||
32 | return 0; | 33 | return 0; |
33 | 34 | ||
34 | symhist = annotation__histogram(symbol__annotation(sym), evidx); | 35 | symhist = annotation__histogram(symbol__annotation(sym), evidx); |
35 | if (!symhist->addr[dl->offset]) | 36 | if (!symbol_conf.event_group && !symhist->addr[dl->offset]) |
36 | return 0; | 37 | return 0; |
37 | 38 | ||
38 | percent = 100.0 * symhist->addr[dl->offset] / symhist->sum; | 39 | percent = 100.0 * symhist->addr[dl->offset] / symhist->sum; |
@@ -85,7 +86,7 @@ static int perf_gtk__get_line(char *buf, size_t size, struct disasm_line *dl) | |||
85 | } | 86 | } |
86 | 87 | ||
87 | static int perf_gtk__annotate_symbol(GtkWidget *window, struct symbol *sym, | 88 | static int perf_gtk__annotate_symbol(GtkWidget *window, struct symbol *sym, |
88 | struct map *map, int evidx, | 89 | struct map *map, struct perf_evsel *evsel, |
89 | struct hist_browser_timer *hbt __maybe_unused) | 90 | struct hist_browser_timer *hbt __maybe_unused) |
90 | { | 91 | { |
91 | struct disasm_line *pos, *n; | 92 | struct disasm_line *pos, *n; |
@@ -118,10 +119,24 @@ static int perf_gtk__annotate_symbol(GtkWidget *window, struct symbol *sym, | |||
118 | 119 | ||
119 | list_for_each_entry(pos, ¬es->src->source, node) { | 120 | list_for_each_entry(pos, ¬es->src->source, node) { |
120 | GtkTreeIter iter; | 121 | GtkTreeIter iter; |
122 | int ret = 0; | ||
121 | 123 | ||
122 | gtk_list_store_append(store, &iter); | 124 | gtk_list_store_append(store, &iter); |
123 | 125 | ||
124 | if (perf_gtk__get_percent(s, sizeof(s), sym, pos, evidx)) | 126 | if (perf_evsel__is_group_event(evsel)) { |
127 | for (i = 0; i < evsel->nr_members; i++) { | ||
128 | ret += perf_gtk__get_percent(s + ret, | ||
129 | sizeof(s) - ret, | ||
130 | sym, pos, | ||
131 | evsel->idx + i); | ||
132 | ret += scnprintf(s + ret, sizeof(s) - ret, " "); | ||
133 | } | ||
134 | } else { | ||
135 | ret = perf_gtk__get_percent(s, sizeof(s), sym, pos, | ||
136 | evsel->idx); | ||
137 | } | ||
138 | |||
139 | if (ret) | ||
125 | gtk_list_store_set(store, &iter, ANN_COL__PERCENT, s, -1); | 140 | gtk_list_store_set(store, &iter, ANN_COL__PERCENT, s, -1); |
126 | if (perf_gtk__get_offset(s, sizeof(s), sym, map, pos)) | 141 | if (perf_gtk__get_offset(s, sizeof(s), sym, map, pos)) |
127 | gtk_list_store_set(store, &iter, ANN_COL__OFFSET, s, -1); | 142 | gtk_list_store_set(store, &iter, ANN_COL__OFFSET, s, -1); |
@@ -139,7 +154,8 @@ static int perf_gtk__annotate_symbol(GtkWidget *window, struct symbol *sym, | |||
139 | return 0; | 154 | return 0; |
140 | } | 155 | } |
141 | 156 | ||
142 | int symbol__gtk_annotate(struct symbol *sym, struct map *map, int evidx, | 157 | int symbol__gtk_annotate(struct symbol *sym, struct map *map, |
158 | struct perf_evsel *evsel, | ||
143 | struct hist_browser_timer *hbt) | 159 | struct hist_browser_timer *hbt) |
144 | { | 160 | { |
145 | GtkWidget *window; | 161 | GtkWidget *window; |
@@ -206,7 +222,7 @@ int symbol__gtk_annotate(struct symbol *sym, struct map *map, int evidx, | |||
206 | gtk_notebook_append_page(GTK_NOTEBOOK(notebook), scrolled_window, | 222 | gtk_notebook_append_page(GTK_NOTEBOOK(notebook), scrolled_window, |
207 | tab_label); | 223 | tab_label); |
208 | 224 | ||
209 | perf_gtk__annotate_symbol(scrolled_window, sym, map, evidx, hbt); | 225 | perf_gtk__annotate_symbol(scrolled_window, sym, map, evsel, hbt); |
210 | return 0; | 226 | return 0; |
211 | } | 227 | } |
212 | 228 | ||
diff --git a/tools/perf/ui/gtk/hists.c b/tools/perf/ui/gtk/hists.c index 1e764a8ad259..6f259b3d14e2 100644 --- a/tools/perf/ui/gtk/hists.c +++ b/tools/perf/ui/gtk/hists.c | |||
@@ -32,21 +32,18 @@ static int __hpp__color_fmt(struct perf_hpp *hpp, struct hist_entry *he, | |||
32 | int ret; | 32 | int ret; |
33 | double percent = 0.0; | 33 | double percent = 0.0; |
34 | struct hists *hists = he->hists; | 34 | struct hists *hists = he->hists; |
35 | struct perf_evsel *evsel = hists_to_evsel(hists); | ||
35 | 36 | ||
36 | if (hists->stats.total_period) | 37 | if (hists->stats.total_period) |
37 | percent = 100.0 * get_field(he) / hists->stats.total_period; | 38 | percent = 100.0 * get_field(he) / hists->stats.total_period; |
38 | 39 | ||
39 | ret = __percent_color_snprintf(hpp->buf, hpp->size, percent); | 40 | ret = __percent_color_snprintf(hpp->buf, hpp->size, percent); |
40 | 41 | ||
41 | if (symbol_conf.event_group) { | 42 | if (perf_evsel__is_group_event(evsel)) { |
42 | int prev_idx, idx_delta; | 43 | int prev_idx, idx_delta; |
43 | struct perf_evsel *evsel = hists_to_evsel(hists); | ||
44 | struct hist_entry *pair; | 44 | struct hist_entry *pair; |
45 | int nr_members = evsel->nr_members; | 45 | int nr_members = evsel->nr_members; |
46 | 46 | ||
47 | if (nr_members <= 1) | ||
48 | return ret; | ||
49 | |||
50 | prev_idx = perf_evsel__group_idx(evsel); | 47 | prev_idx = perf_evsel__group_idx(evsel); |
51 | 48 | ||
52 | list_for_each_entry(pair, &he->pairs.head, pairs.node) { | 49 | list_for_each_entry(pair, &he->pairs.head, pairs.node) { |
diff --git a/tools/perf/ui/hist.c b/tools/perf/ui/hist.c index d671e63aa351..4bf91b09d62d 100644 --- a/tools/perf/ui/hist.c +++ b/tools/perf/ui/hist.c | |||
@@ -16,6 +16,7 @@ static int __hpp__fmt(struct perf_hpp *hpp, struct hist_entry *he, | |||
16 | { | 16 | { |
17 | int ret; | 17 | int ret; |
18 | struct hists *hists = he->hists; | 18 | struct hists *hists = he->hists; |
19 | struct perf_evsel *evsel = hists_to_evsel(hists); | ||
19 | 20 | ||
20 | if (fmt_percent) { | 21 | if (fmt_percent) { |
21 | double percent = 0.0; | 22 | double percent = 0.0; |
@@ -28,15 +29,11 @@ static int __hpp__fmt(struct perf_hpp *hpp, struct hist_entry *he, | |||
28 | } else | 29 | } else |
29 | ret = print_fn(hpp->buf, hpp->size, fmt, get_field(he)); | 30 | ret = print_fn(hpp->buf, hpp->size, fmt, get_field(he)); |
30 | 31 | ||
31 | if (symbol_conf.event_group) { | 32 | if (perf_evsel__is_group_event(evsel)) { |
32 | int prev_idx, idx_delta; | 33 | int prev_idx, idx_delta; |
33 | struct perf_evsel *evsel = hists_to_evsel(hists); | ||
34 | struct hist_entry *pair; | 34 | struct hist_entry *pair; |
35 | int nr_members = evsel->nr_members; | 35 | int nr_members = evsel->nr_members; |
36 | 36 | ||
37 | if (nr_members <= 1) | ||
38 | return ret; | ||
39 | |||
40 | prev_idx = perf_evsel__group_idx(evsel); | 37 | prev_idx = perf_evsel__group_idx(evsel); |
41 | 38 | ||
42 | list_for_each_entry(pair, &he->pairs.head, pairs.node) { | 39 | list_for_each_entry(pair, &he->pairs.head, pairs.node) { |
diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index d33fe937e6f1..d102716c43a1 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c | |||
@@ -14,6 +14,7 @@ | |||
14 | #include "symbol.h" | 14 | #include "symbol.h" |
15 | #include "debug.h" | 15 | #include "debug.h" |
16 | #include "annotate.h" | 16 | #include "annotate.h" |
17 | #include "evsel.h" | ||
17 | #include <pthread.h> | 18 | #include <pthread.h> |
18 | #include <linux/bitops.h> | 19 | #include <linux/bitops.h> |
19 | 20 | ||
@@ -602,8 +603,42 @@ struct disasm_line *disasm__get_next_ip_line(struct list_head *head, struct disa | |||
602 | return NULL; | 603 | return NULL; |
603 | } | 604 | } |
604 | 605 | ||
606 | double disasm__calc_percent(struct annotation *notes, int evidx, s64 offset, | ||
607 | s64 end, const char **path) | ||
608 | { | ||
609 | struct source_line *src_line = notes->src->lines; | ||
610 | double percent = 0.0; | ||
611 | |||
612 | if (src_line) { | ||
613 | size_t sizeof_src_line = sizeof(*src_line) + | ||
614 | sizeof(src_line->p) * (src_line->nr_pcnt - 1); | ||
615 | |||
616 | while (offset < end) { | ||
617 | src_line = (void *)notes->src->lines + | ||
618 | (sizeof_src_line * offset); | ||
619 | |||
620 | if (*path == NULL) | ||
621 | *path = src_line->path; | ||
622 | |||
623 | percent += src_line->p[evidx].percent; | ||
624 | offset++; | ||
625 | } | ||
626 | } else { | ||
627 | struct sym_hist *h = annotation__histogram(notes, evidx); | ||
628 | unsigned int hits = 0; | ||
629 | |||
630 | while (offset < end) | ||
631 | hits += h->addr[offset++]; | ||
632 | |||
633 | if (h->sum) | ||
634 | percent = 100.0 * hits / h->sum; | ||
635 | } | ||
636 | |||
637 | return percent; | ||
638 | } | ||
639 | |||
605 | static int disasm_line__print(struct disasm_line *dl, struct symbol *sym, u64 start, | 640 | static int disasm_line__print(struct disasm_line *dl, struct symbol *sym, u64 start, |
606 | int evidx, u64 len, int min_pcnt, int printed, | 641 | struct perf_evsel *evsel, u64 len, int min_pcnt, int printed, |
607 | int max_lines, struct disasm_line *queue) | 642 | int max_lines, struct disasm_line *queue) |
608 | { | 643 | { |
609 | static const char *prev_line; | 644 | static const char *prev_line; |
@@ -611,34 +646,37 @@ static int disasm_line__print(struct disasm_line *dl, struct symbol *sym, u64 st | |||
611 | 646 | ||
612 | if (dl->offset != -1) { | 647 | if (dl->offset != -1) { |
613 | const char *path = NULL; | 648 | const char *path = NULL; |
614 | unsigned int hits = 0; | 649 | double percent, max_percent = 0.0; |
615 | double percent = 0.0; | 650 | double *ppercents = &percent; |
651 | int i, nr_percent = 1; | ||
616 | const char *color; | 652 | const char *color; |
617 | struct annotation *notes = symbol__annotation(sym); | 653 | struct annotation *notes = symbol__annotation(sym); |
618 | struct source_line *src_line = notes->src->lines; | ||
619 | struct sym_hist *h = annotation__histogram(notes, evidx); | ||
620 | s64 offset = dl->offset; | 654 | s64 offset = dl->offset; |
621 | const u64 addr = start + offset; | 655 | const u64 addr = start + offset; |
622 | struct disasm_line *next; | 656 | struct disasm_line *next; |
623 | 657 | ||
624 | next = disasm__get_next_ip_line(¬es->src->source, dl); | 658 | next = disasm__get_next_ip_line(¬es->src->source, dl); |
625 | 659 | ||
626 | while (offset < (s64)len && | 660 | if (perf_evsel__is_group_event(evsel)) { |
627 | (next == NULL || offset < next->offset)) { | 661 | nr_percent = evsel->nr_members; |
628 | if (src_line) { | 662 | ppercents = calloc(nr_percent, sizeof(double)); |
629 | if (path == NULL) | 663 | if (ppercents == NULL) |
630 | path = src_line[offset].path; | 664 | return -1; |
631 | percent += src_line[offset].percent; | ||
632 | } else | ||
633 | hits += h->addr[offset]; | ||
634 | |||
635 | ++offset; | ||
636 | } | 665 | } |
637 | 666 | ||
638 | if (src_line == NULL && h->sum) | 667 | for (i = 0; i < nr_percent; i++) { |
639 | percent = 100.0 * hits / h->sum; | 668 | percent = disasm__calc_percent(notes, |
669 | notes->src->lines ? i : evsel->idx + i, | ||
670 | offset, | ||
671 | next ? next->offset : (s64) len, | ||
672 | &path); | ||
673 | |||
674 | ppercents[i] = percent; | ||
675 | if (percent > max_percent) | ||
676 | max_percent = percent; | ||
677 | } | ||
640 | 678 | ||
641 | if (percent < min_pcnt) | 679 | if (max_percent < min_pcnt) |
642 | return -1; | 680 | return -1; |
643 | 681 | ||
644 | if (max_lines && printed >= max_lines) | 682 | if (max_lines && printed >= max_lines) |
@@ -648,12 +686,12 @@ static int disasm_line__print(struct disasm_line *dl, struct symbol *sym, u64 st | |||
648 | list_for_each_entry_from(queue, ¬es->src->source, node) { | 686 | list_for_each_entry_from(queue, ¬es->src->source, node) { |
649 | if (queue == dl) | 687 | if (queue == dl) |
650 | break; | 688 | break; |
651 | disasm_line__print(queue, sym, start, evidx, len, | 689 | disasm_line__print(queue, sym, start, evsel, len, |
652 | 0, 0, 1, NULL); | 690 | 0, 0, 1, NULL); |
653 | } | 691 | } |
654 | } | 692 | } |
655 | 693 | ||
656 | color = get_percent_color(percent); | 694 | color = get_percent_color(max_percent); |
657 | 695 | ||
658 | /* | 696 | /* |
659 | * Also color the filename and line if needed, with | 697 | * Also color the filename and line if needed, with |
@@ -669,25 +707,59 @@ static int disasm_line__print(struct disasm_line *dl, struct symbol *sym, u64 st | |||
669 | } | 707 | } |
670 | } | 708 | } |
671 | 709 | ||
672 | color_fprintf(stdout, color, " %7.2f", percent); | 710 | for (i = 0; i < nr_percent; i++) { |
711 | percent = ppercents[i]; | ||
712 | color = get_percent_color(percent); | ||
713 | color_fprintf(stdout, color, " %7.2f", percent); | ||
714 | } | ||
715 | |||
673 | printf(" : "); | 716 | printf(" : "); |
674 | color_fprintf(stdout, PERF_COLOR_MAGENTA, " %" PRIx64 ":", addr); | 717 | color_fprintf(stdout, PERF_COLOR_MAGENTA, " %" PRIx64 ":", addr); |
675 | color_fprintf(stdout, PERF_COLOR_BLUE, "%s\n", dl->line); | 718 | color_fprintf(stdout, PERF_COLOR_BLUE, "%s\n", dl->line); |
719 | |||
720 | if (ppercents != &percent) | ||
721 | free(ppercents); | ||
722 | |||
676 | } else if (max_lines && printed >= max_lines) | 723 | } else if (max_lines && printed >= max_lines) |
677 | return 1; | 724 | return 1; |
678 | else { | 725 | else { |
726 | int width = 8; | ||
727 | |||
679 | if (queue) | 728 | if (queue) |
680 | return -1; | 729 | return -1; |
681 | 730 | ||
731 | if (perf_evsel__is_group_event(evsel)) | ||
732 | width *= evsel->nr_members; | ||
733 | |||
682 | if (!*dl->line) | 734 | if (!*dl->line) |
683 | printf(" :\n"); | 735 | printf(" %*s:\n", width, " "); |
684 | else | 736 | else |
685 | printf(" : %s\n", dl->line); | 737 | printf(" %*s: %s\n", width, " ", dl->line); |
686 | } | 738 | } |
687 | 739 | ||
688 | return 0; | 740 | return 0; |
689 | } | 741 | } |
690 | 742 | ||
743 | /* | ||
744 | * symbol__parse_objdump_line() parses objdump output (with -d --no-show-raw) | ||
745 | * which looks like following | ||
746 | * | ||
747 | * 0000000000415500 <_init>: | ||
748 | * 415500: sub $0x8,%rsp | ||
749 | * 415504: mov 0x2f5ad5(%rip),%rax # 70afe0 <_DYNAMIC+0x2f8> | ||
750 | * 41550b: test %rax,%rax | ||
751 | * 41550e: je 415515 <_init+0x15> | ||
752 | * 415510: callq 416e70 <__gmon_start__@plt> | ||
753 | * 415515: add $0x8,%rsp | ||
754 | * 415519: retq | ||
755 | * | ||
756 | * it will be parsed and saved into struct disasm_line as | ||
757 | * <offset> <name> <ops.raw> | ||
758 | * | ||
759 | * The offset will be a relative offset from the start of the symbol and -1 | ||
760 | * means that it's not a disassembly line so should be treated differently. | ||
761 | * The ops.raw part will be parsed further according to type of the instruction. | ||
762 | */ | ||
691 | static int symbol__parse_objdump_line(struct symbol *sym, struct map *map, | 763 | static int symbol__parse_objdump_line(struct symbol *sym, struct map *map, |
692 | FILE *file, size_t privsize) | 764 | FILE *file, size_t privsize) |
693 | { | 765 | { |
@@ -858,7 +930,7 @@ static void insert_source_line(struct rb_root *root, struct source_line *src_lin | |||
858 | struct source_line *iter; | 930 | struct source_line *iter; |
859 | struct rb_node **p = &root->rb_node; | 931 | struct rb_node **p = &root->rb_node; |
860 | struct rb_node *parent = NULL; | 932 | struct rb_node *parent = NULL; |
861 | int ret; | 933 | int i, ret; |
862 | 934 | ||
863 | while (*p != NULL) { | 935 | while (*p != NULL) { |
864 | parent = *p; | 936 | parent = *p; |
@@ -866,7 +938,8 @@ static void insert_source_line(struct rb_root *root, struct source_line *src_lin | |||
866 | 938 | ||
867 | ret = strcmp(iter->path, src_line->path); | 939 | ret = strcmp(iter->path, src_line->path); |
868 | if (ret == 0) { | 940 | if (ret == 0) { |
869 | iter->percent_sum += src_line->percent; | 941 | for (i = 0; i < src_line->nr_pcnt; i++) |
942 | iter->p[i].percent_sum += src_line->p[i].percent; | ||
870 | return; | 943 | return; |
871 | } | 944 | } |
872 | 945 | ||
@@ -876,12 +949,26 @@ static void insert_source_line(struct rb_root *root, struct source_line *src_lin | |||
876 | p = &(*p)->rb_right; | 949 | p = &(*p)->rb_right; |
877 | } | 950 | } |
878 | 951 | ||
879 | src_line->percent_sum = src_line->percent; | 952 | for (i = 0; i < src_line->nr_pcnt; i++) |
953 | src_line->p[i].percent_sum = src_line->p[i].percent; | ||
880 | 954 | ||
881 | rb_link_node(&src_line->node, parent, p); | 955 | rb_link_node(&src_line->node, parent, p); |
882 | rb_insert_color(&src_line->node, root); | 956 | rb_insert_color(&src_line->node, root); |
883 | } | 957 | } |
884 | 958 | ||
959 | static int cmp_source_line(struct source_line *a, struct source_line *b) | ||
960 | { | ||
961 | int i; | ||
962 | |||
963 | for (i = 0; i < a->nr_pcnt; i++) { | ||
964 | if (a->p[i].percent_sum == b->p[i].percent_sum) | ||
965 | continue; | ||
966 | return a->p[i].percent_sum > b->p[i].percent_sum; | ||
967 | } | ||
968 | |||
969 | return 0; | ||
970 | } | ||
971 | |||
885 | static void __resort_source_line(struct rb_root *root, struct source_line *src_line) | 972 | static void __resort_source_line(struct rb_root *root, struct source_line *src_line) |
886 | { | 973 | { |
887 | struct source_line *iter; | 974 | struct source_line *iter; |
@@ -892,7 +979,7 @@ static void __resort_source_line(struct rb_root *root, struct source_line *src_l | |||
892 | parent = *p; | 979 | parent = *p; |
893 | iter = rb_entry(parent, struct source_line, node); | 980 | iter = rb_entry(parent, struct source_line, node); |
894 | 981 | ||
895 | if (src_line->percent_sum > iter->percent_sum) | 982 | if (cmp_source_line(src_line, iter)) |
896 | p = &(*p)->rb_left; | 983 | p = &(*p)->rb_left; |
897 | else | 984 | else |
898 | p = &(*p)->rb_right; | 985 | p = &(*p)->rb_right; |
@@ -924,32 +1011,52 @@ static void symbol__free_source_line(struct symbol *sym, int len) | |||
924 | { | 1011 | { |
925 | struct annotation *notes = symbol__annotation(sym); | 1012 | struct annotation *notes = symbol__annotation(sym); |
926 | struct source_line *src_line = notes->src->lines; | 1013 | struct source_line *src_line = notes->src->lines; |
1014 | size_t sizeof_src_line; | ||
927 | int i; | 1015 | int i; |
928 | 1016 | ||
929 | for (i = 0; i < len; i++) | 1017 | sizeof_src_line = sizeof(*src_line) + |
930 | free(src_line[i].path); | 1018 | (sizeof(src_line->p) * (src_line->nr_pcnt - 1)); |
1019 | |||
1020 | for (i = 0; i < len; i++) { | ||
1021 | free(src_line->path); | ||
1022 | src_line = (void *)src_line + sizeof_src_line; | ||
1023 | } | ||
931 | 1024 | ||
932 | free(src_line); | 1025 | free(notes->src->lines); |
933 | notes->src->lines = NULL; | 1026 | notes->src->lines = NULL; |
934 | } | 1027 | } |
935 | 1028 | ||
936 | /* Get the filename:line for the colored entries */ | 1029 | /* Get the filename:line for the colored entries */ |
937 | static int symbol__get_source_line(struct symbol *sym, struct map *map, | 1030 | static int symbol__get_source_line(struct symbol *sym, struct map *map, |
938 | int evidx, struct rb_root *root, int len, | 1031 | struct perf_evsel *evsel, |
1032 | struct rb_root *root, int len, | ||
939 | const char *filename) | 1033 | const char *filename) |
940 | { | 1034 | { |
941 | u64 start; | 1035 | u64 start; |
942 | int i; | 1036 | int i, k; |
1037 | int evidx = evsel->idx; | ||
943 | char cmd[PATH_MAX * 2]; | 1038 | char cmd[PATH_MAX * 2]; |
944 | struct source_line *src_line; | 1039 | struct source_line *src_line; |
945 | struct annotation *notes = symbol__annotation(sym); | 1040 | struct annotation *notes = symbol__annotation(sym); |
946 | struct sym_hist *h = annotation__histogram(notes, evidx); | 1041 | struct sym_hist *h = annotation__histogram(notes, evidx); |
947 | struct rb_root tmp_root = RB_ROOT; | 1042 | struct rb_root tmp_root = RB_ROOT; |
1043 | int nr_pcnt = 1; | ||
1044 | u64 h_sum = h->sum; | ||
1045 | size_t sizeof_src_line = sizeof(struct source_line); | ||
1046 | |||
1047 | if (perf_evsel__is_group_event(evsel)) { | ||
1048 | for (i = 1; i < evsel->nr_members; i++) { | ||
1049 | h = annotation__histogram(notes, evidx + i); | ||
1050 | h_sum += h->sum; | ||
1051 | } | ||
1052 | nr_pcnt = evsel->nr_members; | ||
1053 | sizeof_src_line += (nr_pcnt - 1) * sizeof(src_line->p); | ||
1054 | } | ||
948 | 1055 | ||
949 | if (!h->sum) | 1056 | if (!h_sum) |
950 | return 0; | 1057 | return 0; |
951 | 1058 | ||
952 | src_line = notes->src->lines = calloc(len, sizeof(struct source_line)); | 1059 | src_line = notes->src->lines = calloc(len, sizeof_src_line); |
953 | if (!notes->src->lines) | 1060 | if (!notes->src->lines) |
954 | return -1; | 1061 | return -1; |
955 | 1062 | ||
@@ -960,29 +1067,41 @@ static int symbol__get_source_line(struct symbol *sym, struct map *map, | |||
960 | size_t line_len; | 1067 | size_t line_len; |
961 | u64 offset; | 1068 | u64 offset; |
962 | FILE *fp; | 1069 | FILE *fp; |
1070 | double percent_max = 0.0; | ||
963 | 1071 | ||
964 | src_line[i].percent = 100.0 * h->addr[i] / h->sum; | 1072 | src_line->nr_pcnt = nr_pcnt; |
965 | if (src_line[i].percent <= 0.5) | 1073 | |
966 | continue; | 1074 | for (k = 0; k < nr_pcnt; k++) { |
1075 | h = annotation__histogram(notes, evidx + k); | ||
1076 | src_line->p[k].percent = 100.0 * h->addr[i] / h->sum; | ||
1077 | |||
1078 | if (src_line->p[k].percent > percent_max) | ||
1079 | percent_max = src_line->p[k].percent; | ||
1080 | } | ||
1081 | |||
1082 | if (percent_max <= 0.5) | ||
1083 | goto next; | ||
967 | 1084 | ||
968 | offset = start + i; | 1085 | offset = start + i; |
969 | sprintf(cmd, "addr2line -e %s %016" PRIx64, filename, offset); | 1086 | sprintf(cmd, "addr2line -e %s %016" PRIx64, filename, offset); |
970 | fp = popen(cmd, "r"); | 1087 | fp = popen(cmd, "r"); |
971 | if (!fp) | 1088 | if (!fp) |
972 | continue; | 1089 | goto next; |
973 | 1090 | ||
974 | if (getline(&path, &line_len, fp) < 0 || !line_len) | 1091 | if (getline(&path, &line_len, fp) < 0 || !line_len) |
975 | goto next; | 1092 | goto next_close; |
976 | 1093 | ||
977 | src_line[i].path = malloc(sizeof(char) * line_len + 1); | 1094 | src_line->path = malloc(sizeof(char) * line_len + 1); |
978 | if (!src_line[i].path) | 1095 | if (!src_line->path) |
979 | goto next; | 1096 | goto next_close; |
980 | 1097 | ||
981 | strcpy(src_line[i].path, path); | 1098 | strcpy(src_line->path, path); |
982 | insert_source_line(&tmp_root, &src_line[i]); | 1099 | insert_source_line(&tmp_root, src_line); |
983 | 1100 | ||
984 | next: | 1101 | next_close: |
985 | pclose(fp); | 1102 | pclose(fp); |
1103 | next: | ||
1104 | src_line = (void *)src_line + sizeof_src_line; | ||
986 | } | 1105 | } |
987 | 1106 | ||
988 | resort_source_line(root, &tmp_root); | 1107 | resort_source_line(root, &tmp_root); |
@@ -1004,24 +1123,33 @@ static void print_summary(struct rb_root *root, const char *filename) | |||
1004 | 1123 | ||
1005 | node = rb_first(root); | 1124 | node = rb_first(root); |
1006 | while (node) { | 1125 | while (node) { |
1007 | double percent; | 1126 | double percent, percent_max = 0.0; |
1008 | const char *color; | 1127 | const char *color; |
1009 | char *path; | 1128 | char *path; |
1129 | int i; | ||
1010 | 1130 | ||
1011 | src_line = rb_entry(node, struct source_line, node); | 1131 | src_line = rb_entry(node, struct source_line, node); |
1012 | percent = src_line->percent_sum; | 1132 | for (i = 0; i < src_line->nr_pcnt; i++) { |
1013 | color = get_percent_color(percent); | 1133 | percent = src_line->p[i].percent_sum; |
1134 | color = get_percent_color(percent); | ||
1135 | color_fprintf(stdout, color, " %7.2f", percent); | ||
1136 | |||
1137 | if (percent > percent_max) | ||
1138 | percent_max = percent; | ||
1139 | } | ||
1140 | |||
1014 | path = src_line->path; | 1141 | path = src_line->path; |
1142 | color = get_percent_color(percent_max); | ||
1143 | color_fprintf(stdout, color, " %s", path); | ||
1015 | 1144 | ||
1016 | color_fprintf(stdout, color, " %7.2f %s", percent, path); | ||
1017 | node = rb_next(node); | 1145 | node = rb_next(node); |
1018 | } | 1146 | } |
1019 | } | 1147 | } |
1020 | 1148 | ||
1021 | static void symbol__annotate_hits(struct symbol *sym, int evidx) | 1149 | static void symbol__annotate_hits(struct symbol *sym, struct perf_evsel *evsel) |
1022 | { | 1150 | { |
1023 | struct annotation *notes = symbol__annotation(sym); | 1151 | struct annotation *notes = symbol__annotation(sym); |
1024 | struct sym_hist *h = annotation__histogram(notes, evidx); | 1152 | struct sym_hist *h = annotation__histogram(notes, evsel->idx); |
1025 | u64 len = symbol__size(sym), offset; | 1153 | u64 len = symbol__size(sym), offset; |
1026 | 1154 | ||
1027 | for (offset = 0; offset < len; ++offset) | 1155 | for (offset = 0; offset < len; ++offset) |
@@ -1031,9 +1159,9 @@ static void symbol__annotate_hits(struct symbol *sym, int evidx) | |||
1031 | printf("%*s: %" PRIu64 "\n", BITS_PER_LONG / 2, "h->sum", h->sum); | 1159 | printf("%*s: %" PRIu64 "\n", BITS_PER_LONG / 2, "h->sum", h->sum); |
1032 | } | 1160 | } |
1033 | 1161 | ||
1034 | int symbol__annotate_printf(struct symbol *sym, struct map *map, int evidx, | 1162 | int symbol__annotate_printf(struct symbol *sym, struct map *map, |
1035 | bool full_paths, int min_pcnt, int max_lines, | 1163 | struct perf_evsel *evsel, bool full_paths, |
1036 | int context) | 1164 | int min_pcnt, int max_lines, int context) |
1037 | { | 1165 | { |
1038 | struct dso *dso = map->dso; | 1166 | struct dso *dso = map->dso; |
1039 | char *filename; | 1167 | char *filename; |
@@ -1044,6 +1172,8 @@ int symbol__annotate_printf(struct symbol *sym, struct map *map, int evidx, | |||
1044 | int printed = 2, queue_len = 0; | 1172 | int printed = 2, queue_len = 0; |
1045 | int more = 0; | 1173 | int more = 0; |
1046 | u64 len; | 1174 | u64 len; |
1175 | int width = 8; | ||
1176 | int namelen; | ||
1047 | 1177 | ||
1048 | filename = strdup(dso->long_name); | 1178 | filename = strdup(dso->long_name); |
1049 | if (!filename) | 1179 | if (!filename) |
@@ -1055,12 +1185,18 @@ int symbol__annotate_printf(struct symbol *sym, struct map *map, int evidx, | |||
1055 | d_filename = basename(filename); | 1185 | d_filename = basename(filename); |
1056 | 1186 | ||
1057 | len = symbol__size(sym); | 1187 | len = symbol__size(sym); |
1188 | namelen = strlen(d_filename); | ||
1189 | |||
1190 | if (perf_evsel__is_group_event(evsel)) | ||
1191 | width *= evsel->nr_members; | ||
1058 | 1192 | ||
1059 | printf(" Percent | Source code & Disassembly of %s\n", d_filename); | 1193 | printf(" %-*.*s| Source code & Disassembly of %s\n", |
1060 | printf("------------------------------------------------\n"); | 1194 | width, width, "Percent", d_filename); |
1195 | printf("-%-*.*s-------------------------------------\n", | ||
1196 | width+namelen, width+namelen, graph_dotted_line); | ||
1061 | 1197 | ||
1062 | if (verbose) | 1198 | if (verbose) |
1063 | symbol__annotate_hits(sym, evidx); | 1199 | symbol__annotate_hits(sym, evsel); |
1064 | 1200 | ||
1065 | list_for_each_entry(pos, ¬es->src->source, node) { | 1201 | list_for_each_entry(pos, ¬es->src->source, node) { |
1066 | if (context && queue == NULL) { | 1202 | if (context && queue == NULL) { |
@@ -1068,7 +1204,7 @@ int symbol__annotate_printf(struct symbol *sym, struct map *map, int evidx, | |||
1068 | queue_len = 0; | 1204 | queue_len = 0; |
1069 | } | 1205 | } |
1070 | 1206 | ||
1071 | switch (disasm_line__print(pos, sym, start, evidx, len, | 1207 | switch (disasm_line__print(pos, sym, start, evsel, len, |
1072 | min_pcnt, printed, max_lines, | 1208 | min_pcnt, printed, max_lines, |
1073 | queue)) { | 1209 | queue)) { |
1074 | case 0: | 1210 | case 0: |
@@ -1163,9 +1299,9 @@ size_t disasm__fprintf(struct list_head *head, FILE *fp) | |||
1163 | return printed; | 1299 | return printed; |
1164 | } | 1300 | } |
1165 | 1301 | ||
1166 | int symbol__tty_annotate(struct symbol *sym, struct map *map, int evidx, | 1302 | int symbol__tty_annotate(struct symbol *sym, struct map *map, |
1167 | bool print_lines, bool full_paths, int min_pcnt, | 1303 | struct perf_evsel *evsel, bool print_lines, |
1168 | int max_lines) | 1304 | bool full_paths, int min_pcnt, int max_lines) |
1169 | { | 1305 | { |
1170 | struct dso *dso = map->dso; | 1306 | struct dso *dso = map->dso; |
1171 | const char *filename = dso->long_name; | 1307 | const char *filename = dso->long_name; |
@@ -1178,12 +1314,12 @@ int symbol__tty_annotate(struct symbol *sym, struct map *map, int evidx, | |||
1178 | len = symbol__size(sym); | 1314 | len = symbol__size(sym); |
1179 | 1315 | ||
1180 | if (print_lines) { | 1316 | if (print_lines) { |
1181 | symbol__get_source_line(sym, map, evidx, &source_line, | 1317 | symbol__get_source_line(sym, map, evsel, &source_line, |
1182 | len, filename); | 1318 | len, filename); |
1183 | print_summary(&source_line, filename); | 1319 | print_summary(&source_line, filename); |
1184 | } | 1320 | } |
1185 | 1321 | ||
1186 | symbol__annotate_printf(sym, map, evidx, full_paths, | 1322 | symbol__annotate_printf(sym, map, evsel, full_paths, |
1187 | min_pcnt, max_lines, 0); | 1323 | min_pcnt, max_lines, 0); |
1188 | if (print_lines) | 1324 | if (print_lines) |
1189 | symbol__free_source_line(sym, len); | 1325 | symbol__free_source_line(sym, len); |
diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h index c422440fe611..6f3c16f01ab4 100644 --- a/tools/perf/util/annotate.h +++ b/tools/perf/util/annotate.h | |||
@@ -50,6 +50,8 @@ bool ins__is_jump(const struct ins *ins); | |||
50 | bool ins__is_call(const struct ins *ins); | 50 | bool ins__is_call(const struct ins *ins); |
51 | int ins__scnprintf(struct ins *ins, char *bf, size_t size, struct ins_operands *ops); | 51 | int ins__scnprintf(struct ins *ins, char *bf, size_t size, struct ins_operands *ops); |
52 | 52 | ||
53 | struct annotation; | ||
54 | |||
53 | struct disasm_line { | 55 | struct disasm_line { |
54 | struct list_head node; | 56 | struct list_head node; |
55 | s64 offset; | 57 | s64 offset; |
@@ -68,17 +70,24 @@ void disasm_line__free(struct disasm_line *dl); | |||
68 | struct disasm_line *disasm__get_next_ip_line(struct list_head *head, struct disasm_line *pos); | 70 | struct disasm_line *disasm__get_next_ip_line(struct list_head *head, struct disasm_line *pos); |
69 | int disasm_line__scnprintf(struct disasm_line *dl, char *bf, size_t size, bool raw); | 71 | int disasm_line__scnprintf(struct disasm_line *dl, char *bf, size_t size, bool raw); |
70 | size_t disasm__fprintf(struct list_head *head, FILE *fp); | 72 | size_t disasm__fprintf(struct list_head *head, FILE *fp); |
73 | double disasm__calc_percent(struct annotation *notes, int evidx, s64 offset, | ||
74 | s64 end, const char **path); | ||
71 | 75 | ||
72 | struct sym_hist { | 76 | struct sym_hist { |
73 | u64 sum; | 77 | u64 sum; |
74 | u64 addr[0]; | 78 | u64 addr[0]; |
75 | }; | 79 | }; |
76 | 80 | ||
77 | struct source_line { | 81 | struct source_line_percent { |
78 | struct rb_node node; | ||
79 | double percent; | 82 | double percent; |
80 | double percent_sum; | 83 | double percent_sum; |
84 | }; | ||
85 | |||
86 | struct source_line { | ||
87 | struct rb_node node; | ||
81 | char *path; | 88 | char *path; |
89 | int nr_pcnt; | ||
90 | struct source_line_percent p[1]; | ||
82 | }; | 91 | }; |
83 | 92 | ||
84 | /** struct annotated_source - symbols with hits have this attached as in sannotation | 93 | /** struct annotated_source - symbols with hits have this attached as in sannotation |
@@ -130,47 +139,49 @@ void symbol__annotate_zero_histograms(struct symbol *sym); | |||
130 | 139 | ||
131 | int symbol__annotate(struct symbol *sym, struct map *map, size_t privsize); | 140 | int symbol__annotate(struct symbol *sym, struct map *map, size_t privsize); |
132 | int symbol__annotate_init(struct map *map __maybe_unused, struct symbol *sym); | 141 | int symbol__annotate_init(struct map *map __maybe_unused, struct symbol *sym); |
133 | int symbol__annotate_printf(struct symbol *sym, struct map *map, int evidx, | 142 | int symbol__annotate_printf(struct symbol *sym, struct map *map, |
134 | bool full_paths, int min_pcnt, int max_lines, | 143 | struct perf_evsel *evsel, bool full_paths, |
135 | int context); | 144 | int min_pcnt, int max_lines, int context); |
136 | void symbol__annotate_zero_histogram(struct symbol *sym, int evidx); | 145 | void symbol__annotate_zero_histogram(struct symbol *sym, int evidx); |
137 | void symbol__annotate_decay_histogram(struct symbol *sym, int evidx); | 146 | void symbol__annotate_decay_histogram(struct symbol *sym, int evidx); |
138 | void disasm__purge(struct list_head *head); | 147 | void disasm__purge(struct list_head *head); |
139 | 148 | ||
140 | int symbol__tty_annotate(struct symbol *sym, struct map *map, int evidx, | 149 | int symbol__tty_annotate(struct symbol *sym, struct map *map, |
141 | bool print_lines, bool full_paths, int min_pcnt, | 150 | struct perf_evsel *evsel, bool print_lines, |
142 | int max_lines); | 151 | bool full_paths, int min_pcnt, int max_lines); |
143 | 152 | ||
144 | #ifdef NEWT_SUPPORT | 153 | #ifdef NEWT_SUPPORT |
145 | int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx, | 154 | int symbol__tui_annotate(struct symbol *sym, struct map *map, |
155 | struct perf_evsel *evsel, | ||
146 | struct hist_browser_timer *hbt); | 156 | struct hist_browser_timer *hbt); |
147 | #else | 157 | #else |
148 | static inline int symbol__tui_annotate(struct symbol *sym __maybe_unused, | 158 | static inline int symbol__tui_annotate(struct symbol *sym __maybe_unused, |
149 | struct map *map __maybe_unused, | 159 | struct map *map __maybe_unused, |
150 | int evidx __maybe_unused, | 160 | struct perf_evsel *evsel __maybe_unused, |
151 | struct hist_browser_timer *hbt | 161 | struct hist_browser_timer *hbt |
152 | __maybe_unused) | 162 | __maybe_unused) |
153 | { | 163 | { |
154 | return 0; | 164 | return 0; |
155 | } | 165 | } |
156 | #endif | 166 | #endif |
157 | 167 | ||
158 | #ifdef GTK2_SUPPORT | 168 | #ifdef GTK2_SUPPORT |
159 | int symbol__gtk_annotate(struct symbol *sym, struct map *map, int evidx, | 169 | int symbol__gtk_annotate(struct symbol *sym, struct map *map, |
170 | struct perf_evsel *evsel, | ||
160 | struct hist_browser_timer *hbt); | 171 | struct hist_browser_timer *hbt); |
161 | 172 | ||
162 | static inline int hist_entry__gtk_annotate(struct hist_entry *he, int evidx, | 173 | static inline int hist_entry__gtk_annotate(struct hist_entry *he, |
174 | struct perf_evsel *evsel, | ||
163 | struct hist_browser_timer *hbt) | 175 | struct hist_browser_timer *hbt) |
164 | { | 176 | { |
165 | return symbol__gtk_annotate(he->ms.sym, he->ms.map, evidx, hbt); | 177 | return symbol__gtk_annotate(he->ms.sym, he->ms.map, evsel, hbt); |
166 | } | 178 | } |
167 | 179 | ||
168 | void perf_gtk__show_annotations(void); | 180 | void perf_gtk__show_annotations(void); |
169 | #else | 181 | #else |
170 | static inline int hist_entry__gtk_annotate(struct hist_entry *he __maybe_unused, | 182 | static inline int hist_entry__gtk_annotate(struct hist_entry *he __maybe_unused, |
171 | int evidx __maybe_unused, | 183 | struct perf_evsel *evsel __maybe_unused, |
172 | struct hist_browser_timer *hbt | 184 | struct hist_browser_timer *hbt __maybe_unused) |
173 | __maybe_unused) | ||
174 | { | 185 | { |
175 | return 0; | 186 | return 0; |
176 | } | 187 | } |
diff --git a/tools/perf/util/debugfs.h b/tools/perf/util/debugfs.h deleted file mode 100644 index 68f3e87ec57f..000000000000 --- a/tools/perf/util/debugfs.h +++ /dev/null | |||
@@ -1,12 +0,0 @@ | |||
1 | #ifndef __DEBUGFS_H__ | ||
2 | #define __DEBUGFS_H__ | ||
3 | |||
4 | const char *debugfs_find_mountpoint(void); | ||
5 | int debugfs_valid_mountpoint(const char *debugfs); | ||
6 | char *debugfs_mount(const char *mountpoint); | ||
7 | void debugfs_set_path(const char *mountpoint); | ||
8 | |||
9 | extern char debugfs_mountpoint[]; | ||
10 | extern char tracing_events_path[]; | ||
11 | |||
12 | #endif /* __DEBUGFS_H__ */ | ||
diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c index c8be0fbc5145..f7c727801aab 100644 --- a/tools/perf/util/evlist.c +++ b/tools/perf/util/evlist.c | |||
@@ -7,7 +7,7 @@ | |||
7 | * Released under the GPL v2. (and only v2, not any later version) | 7 | * Released under the GPL v2. (and only v2, not any later version) |
8 | */ | 8 | */ |
9 | #include "util.h" | 9 | #include "util.h" |
10 | #include "debugfs.h" | 10 | #include <lk/debugfs.h> |
11 | #include <poll.h> | 11 | #include <poll.h> |
12 | #include "cpumap.h" | 12 | #include "cpumap.h" |
13 | #include "thread_map.h" | 13 | #include "thread_map.h" |
@@ -38,13 +38,12 @@ void perf_evlist__init(struct perf_evlist *evlist, struct cpu_map *cpus, | |||
38 | evlist->workload.pid = -1; | 38 | evlist->workload.pid = -1; |
39 | } | 39 | } |
40 | 40 | ||
41 | struct perf_evlist *perf_evlist__new(struct cpu_map *cpus, | 41 | struct perf_evlist *perf_evlist__new(void) |
42 | struct thread_map *threads) | ||
43 | { | 42 | { |
44 | struct perf_evlist *evlist = zalloc(sizeof(*evlist)); | 43 | struct perf_evlist *evlist = zalloc(sizeof(*evlist)); |
45 | 44 | ||
46 | if (evlist != NULL) | 45 | if (evlist != NULL) |
47 | perf_evlist__init(evlist, cpus, threads); | 46 | perf_evlist__init(evlist, NULL, NULL); |
48 | 47 | ||
49 | return evlist; | 48 | return evlist; |
50 | } | 49 | } |
@@ -228,12 +227,14 @@ void perf_evlist__disable(struct perf_evlist *evlist) | |||
228 | { | 227 | { |
229 | int cpu, thread; | 228 | int cpu, thread; |
230 | struct perf_evsel *pos; | 229 | struct perf_evsel *pos; |
230 | int nr_cpus = cpu_map__nr(evlist->cpus); | ||
231 | int nr_threads = thread_map__nr(evlist->threads); | ||
231 | 232 | ||
232 | for (cpu = 0; cpu < evlist->cpus->nr; cpu++) { | 233 | for (cpu = 0; cpu < nr_cpus; cpu++) { |
233 | list_for_each_entry(pos, &evlist->entries, node) { | 234 | list_for_each_entry(pos, &evlist->entries, node) { |
234 | if (!perf_evsel__is_group_leader(pos)) | 235 | if (!perf_evsel__is_group_leader(pos)) |
235 | continue; | 236 | continue; |
236 | for (thread = 0; thread < evlist->threads->nr; thread++) | 237 | for (thread = 0; thread < nr_threads; thread++) |
237 | ioctl(FD(pos, cpu, thread), | 238 | ioctl(FD(pos, cpu, thread), |
238 | PERF_EVENT_IOC_DISABLE, 0); | 239 | PERF_EVENT_IOC_DISABLE, 0); |
239 | } | 240 | } |
@@ -244,12 +245,14 @@ void perf_evlist__enable(struct perf_evlist *evlist) | |||
244 | { | 245 | { |
245 | int cpu, thread; | 246 | int cpu, thread; |
246 | struct perf_evsel *pos; | 247 | struct perf_evsel *pos; |
248 | int nr_cpus = cpu_map__nr(evlist->cpus); | ||
249 | int nr_threads = thread_map__nr(evlist->threads); | ||
247 | 250 | ||
248 | for (cpu = 0; cpu < cpu_map__nr(evlist->cpus); cpu++) { | 251 | for (cpu = 0; cpu < nr_cpus; cpu++) { |
249 | list_for_each_entry(pos, &evlist->entries, node) { | 252 | list_for_each_entry(pos, &evlist->entries, node) { |
250 | if (!perf_evsel__is_group_leader(pos)) | 253 | if (!perf_evsel__is_group_leader(pos)) |
251 | continue; | 254 | continue; |
252 | for (thread = 0; thread < evlist->threads->nr; thread++) | 255 | for (thread = 0; thread < nr_threads; thread++) |
253 | ioctl(FD(pos, cpu, thread), | 256 | ioctl(FD(pos, cpu, thread), |
254 | PERF_EVENT_IOC_ENABLE, 0); | 257 | PERF_EVENT_IOC_ENABLE, 0); |
255 | } | 258 | } |
@@ -258,7 +261,9 @@ void perf_evlist__enable(struct perf_evlist *evlist) | |||
258 | 261 | ||
259 | static int perf_evlist__alloc_pollfd(struct perf_evlist *evlist) | 262 | static int perf_evlist__alloc_pollfd(struct perf_evlist *evlist) |
260 | { | 263 | { |
261 | int nfds = cpu_map__nr(evlist->cpus) * evlist->threads->nr * evlist->nr_entries; | 264 | int nr_cpus = cpu_map__nr(evlist->cpus); |
265 | int nr_threads = thread_map__nr(evlist->threads); | ||
266 | int nfds = nr_cpus * nr_threads * evlist->nr_entries; | ||
262 | evlist->pollfd = malloc(sizeof(struct pollfd) * nfds); | 267 | evlist->pollfd = malloc(sizeof(struct pollfd) * nfds); |
263 | return evlist->pollfd != NULL ? 0 : -ENOMEM; | 268 | return evlist->pollfd != NULL ? 0 : -ENOMEM; |
264 | } | 269 | } |
@@ -417,7 +422,7 @@ static int perf_evlist__alloc_mmap(struct perf_evlist *evlist) | |||
417 | { | 422 | { |
418 | evlist->nr_mmaps = cpu_map__nr(evlist->cpus); | 423 | evlist->nr_mmaps = cpu_map__nr(evlist->cpus); |
419 | if (cpu_map__all(evlist->cpus)) | 424 | if (cpu_map__all(evlist->cpus)) |
420 | evlist->nr_mmaps = evlist->threads->nr; | 425 | evlist->nr_mmaps = thread_map__nr(evlist->threads); |
421 | evlist->mmap = zalloc(evlist->nr_mmaps * sizeof(struct perf_mmap)); | 426 | evlist->mmap = zalloc(evlist->nr_mmaps * sizeof(struct perf_mmap)); |
422 | return evlist->mmap != NULL ? 0 : -ENOMEM; | 427 | return evlist->mmap != NULL ? 0 : -ENOMEM; |
423 | } | 428 | } |
@@ -442,11 +447,13 @@ static int perf_evlist__mmap_per_cpu(struct perf_evlist *evlist, int prot, int m | |||
442 | { | 447 | { |
443 | struct perf_evsel *evsel; | 448 | struct perf_evsel *evsel; |
444 | int cpu, thread; | 449 | int cpu, thread; |
450 | int nr_cpus = cpu_map__nr(evlist->cpus); | ||
451 | int nr_threads = thread_map__nr(evlist->threads); | ||
445 | 452 | ||
446 | for (cpu = 0; cpu < evlist->cpus->nr; cpu++) { | 453 | for (cpu = 0; cpu < nr_cpus; cpu++) { |
447 | int output = -1; | 454 | int output = -1; |
448 | 455 | ||
449 | for (thread = 0; thread < evlist->threads->nr; thread++) { | 456 | for (thread = 0; thread < nr_threads; thread++) { |
450 | list_for_each_entry(evsel, &evlist->entries, node) { | 457 | list_for_each_entry(evsel, &evlist->entries, node) { |
451 | int fd = FD(evsel, cpu, thread); | 458 | int fd = FD(evsel, cpu, thread); |
452 | 459 | ||
@@ -470,7 +477,7 @@ static int perf_evlist__mmap_per_cpu(struct perf_evlist *evlist, int prot, int m | |||
470 | return 0; | 477 | return 0; |
471 | 478 | ||
472 | out_unmap: | 479 | out_unmap: |
473 | for (cpu = 0; cpu < evlist->cpus->nr; cpu++) { | 480 | for (cpu = 0; cpu < nr_cpus; cpu++) { |
474 | if (evlist->mmap[cpu].base != NULL) { | 481 | if (evlist->mmap[cpu].base != NULL) { |
475 | munmap(evlist->mmap[cpu].base, evlist->mmap_len); | 482 | munmap(evlist->mmap[cpu].base, evlist->mmap_len); |
476 | evlist->mmap[cpu].base = NULL; | 483 | evlist->mmap[cpu].base = NULL; |
@@ -483,8 +490,9 @@ static int perf_evlist__mmap_per_thread(struct perf_evlist *evlist, int prot, in | |||
483 | { | 490 | { |
484 | struct perf_evsel *evsel; | 491 | struct perf_evsel *evsel; |
485 | int thread; | 492 | int thread; |
493 | int nr_threads = thread_map__nr(evlist->threads); | ||
486 | 494 | ||
487 | for (thread = 0; thread < evlist->threads->nr; thread++) { | 495 | for (thread = 0; thread < nr_threads; thread++) { |
488 | int output = -1; | 496 | int output = -1; |
489 | 497 | ||
490 | list_for_each_entry(evsel, &evlist->entries, node) { | 498 | list_for_each_entry(evsel, &evlist->entries, node) { |
@@ -509,7 +517,7 @@ static int perf_evlist__mmap_per_thread(struct perf_evlist *evlist, int prot, in | |||
509 | return 0; | 517 | return 0; |
510 | 518 | ||
511 | out_unmap: | 519 | out_unmap: |
512 | for (thread = 0; thread < evlist->threads->nr; thread++) { | 520 | for (thread = 0; thread < nr_threads; thread++) { |
513 | if (evlist->mmap[thread].base != NULL) { | 521 | if (evlist->mmap[thread].base != NULL) { |
514 | munmap(evlist->mmap[thread].base, evlist->mmap_len); | 522 | munmap(evlist->mmap[thread].base, evlist->mmap_len); |
515 | evlist->mmap[thread].base = NULL; | 523 | evlist->mmap[thread].base = NULL; |
@@ -610,7 +618,7 @@ int perf_evlist__apply_filters(struct perf_evlist *evlist) | |||
610 | struct perf_evsel *evsel; | 618 | struct perf_evsel *evsel; |
611 | int err = 0; | 619 | int err = 0; |
612 | const int ncpus = cpu_map__nr(evlist->cpus), | 620 | const int ncpus = cpu_map__nr(evlist->cpus), |
613 | nthreads = evlist->threads->nr; | 621 | nthreads = thread_map__nr(evlist->threads); |
614 | 622 | ||
615 | list_for_each_entry(evsel, &evlist->entries, node) { | 623 | list_for_each_entry(evsel, &evlist->entries, node) { |
616 | if (evsel->filter == NULL) | 624 | if (evsel->filter == NULL) |
@@ -629,7 +637,7 @@ int perf_evlist__set_filter(struct perf_evlist *evlist, const char *filter) | |||
629 | struct perf_evsel *evsel; | 637 | struct perf_evsel *evsel; |
630 | int err = 0; | 638 | int err = 0; |
631 | const int ncpus = cpu_map__nr(evlist->cpus), | 639 | const int ncpus = cpu_map__nr(evlist->cpus), |
632 | nthreads = evlist->threads->nr; | 640 | nthreads = thread_map__nr(evlist->threads); |
633 | 641 | ||
634 | list_for_each_entry(evsel, &evlist->entries, node) { | 642 | list_for_each_entry(evsel, &evlist->entries, node) { |
635 | err = perf_evsel__set_filter(evsel, ncpus, nthreads, filter); | 643 | err = perf_evsel__set_filter(evsel, ncpus, nthreads, filter); |
@@ -712,10 +720,20 @@ void perf_evlist__set_selected(struct perf_evlist *evlist, | |||
712 | evlist->selected = evsel; | 720 | evlist->selected = evsel; |
713 | } | 721 | } |
714 | 722 | ||
723 | void perf_evlist__close(struct perf_evlist *evlist) | ||
724 | { | ||
725 | struct perf_evsel *evsel; | ||
726 | int ncpus = cpu_map__nr(evlist->cpus); | ||
727 | int nthreads = thread_map__nr(evlist->threads); | ||
728 | |||
729 | list_for_each_entry_reverse(evsel, &evlist->entries, node) | ||
730 | perf_evsel__close(evsel, ncpus, nthreads); | ||
731 | } | ||
732 | |||
715 | int perf_evlist__open(struct perf_evlist *evlist) | 733 | int perf_evlist__open(struct perf_evlist *evlist) |
716 | { | 734 | { |
717 | struct perf_evsel *evsel; | 735 | struct perf_evsel *evsel; |
718 | int err, ncpus, nthreads; | 736 | int err; |
719 | 737 | ||
720 | list_for_each_entry(evsel, &evlist->entries, node) { | 738 | list_for_each_entry(evsel, &evlist->entries, node) { |
721 | err = perf_evsel__open(evsel, evlist->cpus, evlist->threads); | 739 | err = perf_evsel__open(evsel, evlist->cpus, evlist->threads); |
@@ -725,19 +743,15 @@ int perf_evlist__open(struct perf_evlist *evlist) | |||
725 | 743 | ||
726 | return 0; | 744 | return 0; |
727 | out_err: | 745 | out_err: |
728 | ncpus = evlist->cpus ? evlist->cpus->nr : 1; | 746 | perf_evlist__close(evlist); |
729 | nthreads = evlist->threads ? evlist->threads->nr : 1; | ||
730 | |||
731 | list_for_each_entry_reverse(evsel, &evlist->entries, node) | ||
732 | perf_evsel__close(evsel, ncpus, nthreads); | ||
733 | |||
734 | errno = -err; | 747 | errno = -err; |
735 | return err; | 748 | return err; |
736 | } | 749 | } |
737 | 750 | ||
738 | int perf_evlist__prepare_workload(struct perf_evlist *evlist, | 751 | int perf_evlist__prepare_workload(struct perf_evlist *evlist, |
739 | struct perf_record_opts *opts, | 752 | struct perf_target *target, |
740 | const char *argv[]) | 753 | const char *argv[], bool pipe_output, |
754 | bool want_signal) | ||
741 | { | 755 | { |
742 | int child_ready_pipe[2], go_pipe[2]; | 756 | int child_ready_pipe[2], go_pipe[2]; |
743 | char bf; | 757 | char bf; |
@@ -759,7 +773,7 @@ int perf_evlist__prepare_workload(struct perf_evlist *evlist, | |||
759 | } | 773 | } |
760 | 774 | ||
761 | if (!evlist->workload.pid) { | 775 | if (!evlist->workload.pid) { |
762 | if (opts->pipe_output) | 776 | if (pipe_output) |
763 | dup2(2, 1); | 777 | dup2(2, 1); |
764 | 778 | ||
765 | close(child_ready_pipe[0]); | 779 | close(child_ready_pipe[0]); |
@@ -787,11 +801,12 @@ int perf_evlist__prepare_workload(struct perf_evlist *evlist, | |||
787 | execvp(argv[0], (char **)argv); | 801 | execvp(argv[0], (char **)argv); |
788 | 802 | ||
789 | perror(argv[0]); | 803 | perror(argv[0]); |
790 | kill(getppid(), SIGUSR1); | 804 | if (want_signal) |
805 | kill(getppid(), SIGUSR1); | ||
791 | exit(-1); | 806 | exit(-1); |
792 | } | 807 | } |
793 | 808 | ||
794 | if (perf_target__none(&opts->target)) | 809 | if (perf_target__none(target)) |
795 | evlist->threads->map[0] = evlist->workload.pid; | 810 | evlist->threads->map[0] = evlist->workload.pid; |
796 | 811 | ||
797 | close(child_ready_pipe[1]); | 812 | close(child_ready_pipe[1]); |
diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h index 2dd07bd60b4f..0583d36252be 100644 --- a/tools/perf/util/evlist.h +++ b/tools/perf/util/evlist.h | |||
@@ -49,8 +49,7 @@ struct perf_evsel_str_handler { | |||
49 | void *handler; | 49 | void *handler; |
50 | }; | 50 | }; |
51 | 51 | ||
52 | struct perf_evlist *perf_evlist__new(struct cpu_map *cpus, | 52 | struct perf_evlist *perf_evlist__new(void); |
53 | struct thread_map *threads); | ||
54 | void perf_evlist__init(struct perf_evlist *evlist, struct cpu_map *cpus, | 53 | void perf_evlist__init(struct perf_evlist *evlist, struct cpu_map *cpus, |
55 | struct thread_map *threads); | 54 | struct thread_map *threads); |
56 | void perf_evlist__exit(struct perf_evlist *evlist); | 55 | void perf_evlist__exit(struct perf_evlist *evlist); |
@@ -82,13 +81,15 @@ struct perf_evsel *perf_evlist__id2evsel(struct perf_evlist *evlist, u64 id); | |||
82 | union perf_event *perf_evlist__mmap_read(struct perf_evlist *self, int idx); | 81 | union perf_event *perf_evlist__mmap_read(struct perf_evlist *self, int idx); |
83 | 82 | ||
84 | int perf_evlist__open(struct perf_evlist *evlist); | 83 | int perf_evlist__open(struct perf_evlist *evlist); |
84 | void perf_evlist__close(struct perf_evlist *evlist); | ||
85 | 85 | ||
86 | void perf_evlist__config(struct perf_evlist *evlist, | 86 | void perf_evlist__config(struct perf_evlist *evlist, |
87 | struct perf_record_opts *opts); | 87 | struct perf_record_opts *opts); |
88 | 88 | ||
89 | int perf_evlist__prepare_workload(struct perf_evlist *evlist, | 89 | int perf_evlist__prepare_workload(struct perf_evlist *evlist, |
90 | struct perf_record_opts *opts, | 90 | struct perf_target *target, |
91 | const char *argv[]); | 91 | const char *argv[], bool pipe_output, |
92 | bool want_signal); | ||
92 | int perf_evlist__start_workload(struct perf_evlist *evlist); | 93 | int perf_evlist__start_workload(struct perf_evlist *evlist); |
93 | 94 | ||
94 | int perf_evlist__mmap(struct perf_evlist *evlist, unsigned int pages, | 95 | int perf_evlist__mmap(struct perf_evlist *evlist, unsigned int pages, |
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index 9c82f98f26de..1adb824610f0 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c | |||
@@ -10,7 +10,7 @@ | |||
10 | #include <byteswap.h> | 10 | #include <byteswap.h> |
11 | #include <linux/bitops.h> | 11 | #include <linux/bitops.h> |
12 | #include "asm/bug.h" | 12 | #include "asm/bug.h" |
13 | #include "debugfs.h" | 13 | #include <lk/debugfs.h> |
14 | #include "event-parse.h" | 14 | #include "event-parse.h" |
15 | #include "evsel.h" | 15 | #include "evsel.h" |
16 | #include "evlist.h" | 16 | #include "evlist.h" |
@@ -633,6 +633,12 @@ int perf_evsel__alloc_id(struct perf_evsel *evsel, int ncpus, int nthreads) | |||
633 | return 0; | 633 | return 0; |
634 | } | 634 | } |
635 | 635 | ||
636 | void perf_evsel__reset_counts(struct perf_evsel *evsel, int ncpus) | ||
637 | { | ||
638 | memset(evsel->counts, 0, (sizeof(*evsel->counts) + | ||
639 | (ncpus * sizeof(struct perf_counts_values)))); | ||
640 | } | ||
641 | |||
636 | int perf_evsel__alloc_counts(struct perf_evsel *evsel, int ncpus) | 642 | int perf_evsel__alloc_counts(struct perf_evsel *evsel, int ncpus) |
637 | { | 643 | { |
638 | evsel->counts = zalloc((sizeof(*evsel->counts) + | 644 | evsel->counts = zalloc((sizeof(*evsel->counts) + |
@@ -673,9 +679,8 @@ void perf_evsel__free_counts(struct perf_evsel *evsel) | |||
673 | void perf_evsel__exit(struct perf_evsel *evsel) | 679 | void perf_evsel__exit(struct perf_evsel *evsel) |
674 | { | 680 | { |
675 | assert(list_empty(&evsel->node)); | 681 | assert(list_empty(&evsel->node)); |
676 | xyarray__delete(evsel->fd); | 682 | perf_evsel__free_fd(evsel); |
677 | xyarray__delete(evsel->sample_id); | 683 | perf_evsel__free_id(evsel); |
678 | free(evsel->id); | ||
679 | } | 684 | } |
680 | 685 | ||
681 | void perf_evsel__delete(struct perf_evsel *evsel) | 686 | void perf_evsel__delete(struct perf_evsel *evsel) |
diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h index 52021c3087df..3f156ccc1acb 100644 --- a/tools/perf/util/evsel.h +++ b/tools/perf/util/evsel.h | |||
@@ -9,6 +9,7 @@ | |||
9 | #include "xyarray.h" | 9 | #include "xyarray.h" |
10 | #include "cgroup.h" | 10 | #include "cgroup.h" |
11 | #include "hist.h" | 11 | #include "hist.h" |
12 | #include "symbol.h" | ||
12 | 13 | ||
13 | struct perf_counts_values { | 14 | struct perf_counts_values { |
14 | union { | 15 | union { |
@@ -120,6 +121,7 @@ int perf_evsel__group_desc(struct perf_evsel *evsel, char *buf, size_t size); | |||
120 | int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads); | 121 | int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads); |
121 | int perf_evsel__alloc_id(struct perf_evsel *evsel, int ncpus, int nthreads); | 122 | int perf_evsel__alloc_id(struct perf_evsel *evsel, int ncpus, int nthreads); |
122 | int perf_evsel__alloc_counts(struct perf_evsel *evsel, int ncpus); | 123 | int perf_evsel__alloc_counts(struct perf_evsel *evsel, int ncpus); |
124 | void perf_evsel__reset_counts(struct perf_evsel *evsel, int ncpus); | ||
123 | void perf_evsel__free_fd(struct perf_evsel *evsel); | 125 | void perf_evsel__free_fd(struct perf_evsel *evsel); |
124 | void perf_evsel__free_id(struct perf_evsel *evsel); | 126 | void perf_evsel__free_id(struct perf_evsel *evsel); |
125 | void perf_evsel__free_counts(struct perf_evsel *evsel); | 127 | void perf_evsel__free_counts(struct perf_evsel *evsel); |
@@ -246,11 +248,34 @@ static inline struct perf_evsel *perf_evsel__next(struct perf_evsel *evsel) | |||
246 | return list_entry(evsel->node.next, struct perf_evsel, node); | 248 | return list_entry(evsel->node.next, struct perf_evsel, node); |
247 | } | 249 | } |
248 | 250 | ||
251 | /** | ||
252 | * perf_evsel__is_group_leader - Return whether given evsel is a leader event | ||
253 | * | ||
254 | * @evsel - evsel selector to be tested | ||
255 | * | ||
256 | * Return %true if @evsel is a group leader or a stand-alone event | ||
257 | */ | ||
249 | static inline bool perf_evsel__is_group_leader(const struct perf_evsel *evsel) | 258 | static inline bool perf_evsel__is_group_leader(const struct perf_evsel *evsel) |
250 | { | 259 | { |
251 | return evsel->leader == evsel; | 260 | return evsel->leader == evsel; |
252 | } | 261 | } |
253 | 262 | ||
263 | /** | ||
264 | * perf_evsel__is_group_event - Return whether given evsel is a group event | ||
265 | * | ||
266 | * @evsel - evsel selector to be tested | ||
267 | * | ||
268 | * Return %true iff event group view is enabled and @evsel is a actual group | ||
269 | * leader which has other members in the group | ||
270 | */ | ||
271 | static inline bool perf_evsel__is_group_event(struct perf_evsel *evsel) | ||
272 | { | ||
273 | if (!symbol_conf.event_group) | ||
274 | return false; | ||
275 | |||
276 | return perf_evsel__is_group_leader(evsel) && evsel->nr_members > 1; | ||
277 | } | ||
278 | |||
254 | struct perf_attr_details { | 279 | struct perf_attr_details { |
255 | bool freq; | 280 | bool freq; |
256 | bool verbose; | 281 | bool verbose; |
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index f4bfd79ef6a7..a9b7349f7c5f 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c | |||
@@ -2789,7 +2789,7 @@ int perf_session__read_header(struct perf_session *session, int fd) | |||
2789 | u64 f_id; | 2789 | u64 f_id; |
2790 | int nr_attrs, nr_ids, i, j; | 2790 | int nr_attrs, nr_ids, i, j; |
2791 | 2791 | ||
2792 | session->evlist = perf_evlist__new(NULL, NULL); | 2792 | session->evlist = perf_evlist__new(); |
2793 | if (session->evlist == NULL) | 2793 | if (session->evlist == NULL) |
2794 | return -ENOMEM; | 2794 | return -ENOMEM; |
2795 | 2795 | ||
@@ -2940,7 +2940,7 @@ int perf_event__process_attr(union perf_event *event, | |||
2940 | struct perf_evlist *evlist = *pevlist; | 2940 | struct perf_evlist *evlist = *pevlist; |
2941 | 2941 | ||
2942 | if (evlist == NULL) { | 2942 | if (evlist == NULL) { |
2943 | *pevlist = evlist = perf_evlist__new(NULL, NULL); | 2943 | *pevlist = evlist = perf_evlist__new(); |
2944 | if (evlist == NULL) | 2944 | if (evlist == NULL) |
2945 | return -ENOMEM; | 2945 | return -ENOMEM; |
2946 | } | 2946 | } |
diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h index 226a4ae2f936..848331377bdb 100644 --- a/tools/perf/util/hist.h +++ b/tools/perf/util/hist.h | |||
@@ -177,7 +177,7 @@ struct hist_browser_timer { | |||
177 | 177 | ||
178 | #ifdef NEWT_SUPPORT | 178 | #ifdef NEWT_SUPPORT |
179 | #include "../ui/keysyms.h" | 179 | #include "../ui/keysyms.h" |
180 | int hist_entry__tui_annotate(struct hist_entry *he, int evidx, | 180 | int hist_entry__tui_annotate(struct hist_entry *he, struct perf_evsel *evsel, |
181 | struct hist_browser_timer *hbt); | 181 | struct hist_browser_timer *hbt); |
182 | 182 | ||
183 | int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help, | 183 | int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help, |
@@ -196,7 +196,8 @@ int perf_evlist__tui_browse_hists(struct perf_evlist *evlist __maybe_unused, | |||
196 | 196 | ||
197 | static inline int hist_entry__tui_annotate(struct hist_entry *self | 197 | static inline int hist_entry__tui_annotate(struct hist_entry *self |
198 | __maybe_unused, | 198 | __maybe_unused, |
199 | int evidx __maybe_unused, | 199 | struct perf_evsel *evsel |
200 | __maybe_unused, | ||
200 | struct hist_browser_timer *hbt | 201 | struct hist_browser_timer *hbt |
201 | __maybe_unused) | 202 | __maybe_unused) |
202 | { | 203 | { |
diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c index efdb38e65a92..c5e3b123782b 100644 --- a/tools/perf/util/machine.c +++ b/tools/perf/util/machine.c | |||
@@ -1003,6 +1003,17 @@ int machine__process_fork_event(struct machine *machine, union perf_event *event | |||
1003 | return 0; | 1003 | return 0; |
1004 | } | 1004 | } |
1005 | 1005 | ||
1006 | static void machine__remove_thread(struct machine *machine, struct thread *th) | ||
1007 | { | ||
1008 | machine->last_match = NULL; | ||
1009 | rb_erase(&th->rb_node, &machine->threads); | ||
1010 | /* | ||
1011 | * We may have references to this thread, for instance in some hist_entry | ||
1012 | * instances, so just move them to a separate list. | ||
1013 | */ | ||
1014 | list_add_tail(&th->node, &machine->dead_threads); | ||
1015 | } | ||
1016 | |||
1006 | int machine__process_exit_event(struct machine *machine, union perf_event *event) | 1017 | int machine__process_exit_event(struct machine *machine, union perf_event *event) |
1007 | { | 1018 | { |
1008 | struct thread *thread = machine__find_thread(machine, event->fork.tid); | 1019 | struct thread *thread = machine__find_thread(machine, event->fork.tid); |
@@ -1039,17 +1050,6 @@ int machine__process_event(struct machine *machine, union perf_event *event) | |||
1039 | return ret; | 1050 | return ret; |
1040 | } | 1051 | } |
1041 | 1052 | ||
1042 | void machine__remove_thread(struct machine *machine, struct thread *th) | ||
1043 | { | ||
1044 | machine->last_match = NULL; | ||
1045 | rb_erase(&th->rb_node, &machine->threads); | ||
1046 | /* | ||
1047 | * We may have references to this thread, for instance in some hist_entry | ||
1048 | * instances, so just move them to a separate list. | ||
1049 | */ | ||
1050 | list_add_tail(&th->node, &machine->dead_threads); | ||
1051 | } | ||
1052 | |||
1053 | static bool symbol__match_parent_regex(struct symbol *sym) | 1053 | static bool symbol__match_parent_regex(struct symbol *sym) |
1054 | { | 1054 | { |
1055 | if (sym->name && !regexec(&parent_regex, sym->name, 0, NULL, 0)) | 1055 | if (sym->name && !regexec(&parent_regex, sym->name, 0, NULL, 0)) |
diff --git a/tools/perf/util/machine.h b/tools/perf/util/machine.h index 5ac5892f2326..e0b2c00b2e75 100644 --- a/tools/perf/util/machine.h +++ b/tools/perf/util/machine.h | |||
@@ -97,7 +97,6 @@ static inline bool machine__is_host(struct machine *machine) | |||
97 | } | 97 | } |
98 | 98 | ||
99 | struct thread *machine__findnew_thread(struct machine *machine, pid_t pid); | 99 | struct thread *machine__findnew_thread(struct machine *machine, pid_t pid); |
100 | void machine__remove_thread(struct machine *machine, struct thread *th); | ||
101 | 100 | ||
102 | size_t machine__fprintf(struct machine *machine, FILE *fp); | 101 | size_t machine__fprintf(struct machine *machine, FILE *fp); |
103 | 102 | ||
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index c84f48cf9678..6c8bb0fb189b 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c | |||
@@ -10,7 +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 "debugfs.h" | 13 | #include <lk/debugfs.h> |
14 | #include "parse-events-bison.h" | 14 | #include "parse-events-bison.h" |
15 | #define YY_EXTRA_TYPE int | 15 | #define YY_EXTRA_TYPE int |
16 | #include "parse-events-flex.h" | 16 | #include "parse-events-flex.h" |
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c index 49a256e6e0a2..aa04bf9c9ad7 100644 --- a/tools/perf/util/probe-event.c +++ b/tools/perf/util/probe-event.c | |||
@@ -40,7 +40,7 @@ | |||
40 | #include "color.h" | 40 | #include "color.h" |
41 | #include "symbol.h" | 41 | #include "symbol.h" |
42 | #include "thread.h" | 42 | #include "thread.h" |
43 | #include "debugfs.h" | 43 | #include <lk/debugfs.h> |
44 | #include "trace-event.h" /* For __maybe_unused */ | 44 | #include "trace-event.h" /* For __maybe_unused */ |
45 | #include "probe-event.h" | 45 | #include "probe-event.h" |
46 | #include "probe-finder.h" | 46 | #include "probe-finder.h" |
diff --git a/tools/perf/util/python-ext-sources b/tools/perf/util/python-ext-sources index 64536a993f4a..f75ae1b9900c 100644 --- a/tools/perf/util/python-ext-sources +++ b/tools/perf/util/python-ext-sources | |||
@@ -15,7 +15,6 @@ util/thread_map.c | |||
15 | util/util.c | 15 | util/util.c |
16 | util/xyarray.c | 16 | util/xyarray.c |
17 | util/cgroup.c | 17 | util/cgroup.c |
18 | util/debugfs.c | ||
19 | util/rblist.c | 18 | util/rblist.c |
20 | util/strlist.c | 19 | util/strlist.c |
21 | util/sysfs.c | 20 | util/sysfs.c |
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index bd85280bb6e8..ab265c2cfab3 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c | |||
@@ -1365,18 +1365,6 @@ size_t perf_session__fprintf(struct perf_session *session, FILE *fp) | |||
1365 | return machine__fprintf(&session->machines.host, fp); | 1365 | return machine__fprintf(&session->machines.host, fp); |
1366 | } | 1366 | } |
1367 | 1367 | ||
1368 | void perf_session__remove_thread(struct perf_session *session, | ||
1369 | struct thread *th) | ||
1370 | { | ||
1371 | /* | ||
1372 | * FIXME: This one makes no sense, we need to remove the thread from | ||
1373 | * the machine it belongs to, perf_session can have many machines, so | ||
1374 | * doing it always on ->machines.host is wrong. Fix when auditing all | ||
1375 | * the 'perf kvm' code. | ||
1376 | */ | ||
1377 | machine__remove_thread(&session->machines.host, th); | ||
1378 | } | ||
1379 | |||
1380 | struct perf_evsel *perf_session__find_first_evtype(struct perf_session *session, | 1368 | struct perf_evsel *perf_session__find_first_evtype(struct perf_session *session, |
1381 | unsigned int type) | 1369 | unsigned int type) |
1382 | { | 1370 | { |
diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h index b5c0847edfa9..6b51d47acdba 100644 --- a/tools/perf/util/session.h +++ b/tools/perf/util/session.h | |||
@@ -72,7 +72,6 @@ void perf_event__attr_swap(struct perf_event_attr *attr); | |||
72 | int perf_session__create_kernel_maps(struct perf_session *self); | 72 | int perf_session__create_kernel_maps(struct perf_session *self); |
73 | 73 | ||
74 | void perf_session__set_id_hdr_size(struct perf_session *session); | 74 | void perf_session__set_id_hdr_size(struct perf_session *session); |
75 | void perf_session__remove_thread(struct perf_session *self, struct thread *th); | ||
76 | 75 | ||
77 | static inline | 76 | static inline |
78 | struct machine *perf_session__find_machine(struct perf_session *self, pid_t pid) | 77 | struct machine *perf_session__find_machine(struct perf_session *self, pid_t pid) |
diff --git a/tools/perf/util/setup.py b/tools/perf/util/setup.py index 73d510269784..6b0ed322907e 100644 --- a/tools/perf/util/setup.py +++ b/tools/perf/util/setup.py | |||
@@ -24,6 +24,7 @@ cflags += getenv('CFLAGS', '').split() | |||
24 | build_lib = getenv('PYTHON_EXTBUILD_LIB') | 24 | build_lib = getenv('PYTHON_EXTBUILD_LIB') |
25 | build_tmp = getenv('PYTHON_EXTBUILD_TMP') | 25 | build_tmp = getenv('PYTHON_EXTBUILD_TMP') |
26 | libtraceevent = getenv('LIBTRACEEVENT') | 26 | libtraceevent = getenv('LIBTRACEEVENT') |
27 | liblk = getenv('LIBLK') | ||
27 | 28 | ||
28 | ext_sources = [f.strip() for f in file('util/python-ext-sources') | 29 | ext_sources = [f.strip() for f in file('util/python-ext-sources') |
29 | if len(f.strip()) > 0 and f[0] != '#'] | 30 | if len(f.strip()) > 0 and f[0] != '#'] |
@@ -32,7 +33,7 @@ perf = Extension('perf', | |||
32 | sources = ext_sources, | 33 | sources = ext_sources, |
33 | include_dirs = ['util/include'], | 34 | include_dirs = ['util/include'], |
34 | extra_compile_args = cflags, | 35 | extra_compile_args = cflags, |
35 | extra_objects = [libtraceevent], | 36 | extra_objects = [libtraceevent, liblk], |
36 | ) | 37 | ) |
37 | 38 | ||
38 | setup(name='perf', | 39 | setup(name='perf', |
diff --git a/tools/perf/util/thread_map.h b/tools/perf/util/thread_map.h index f718df8a3c59..0cd8b3108084 100644 --- a/tools/perf/util/thread_map.h +++ b/tools/perf/util/thread_map.h | |||
@@ -21,4 +21,9 @@ void thread_map__delete(struct thread_map *threads); | |||
21 | 21 | ||
22 | size_t thread_map__fprintf(struct thread_map *threads, FILE *fp); | 22 | size_t thread_map__fprintf(struct thread_map *threads, FILE *fp); |
23 | 23 | ||
24 | static inline int thread_map__nr(struct thread_map *threads) | ||
25 | { | ||
26 | return threads ? threads->nr : 1; | ||
27 | } | ||
28 | |||
24 | #endif /* __PERF_THREAD_MAP_H */ | 29 | #endif /* __PERF_THREAD_MAP_H */ |
diff --git a/tools/perf/util/trace-event-info.c b/tools/perf/util/trace-event-info.c index a8d81c35ef66..5729f434c5b1 100644 --- a/tools/perf/util/trace-event-info.c +++ b/tools/perf/util/trace-event-info.c | |||
@@ -38,35 +38,14 @@ | |||
38 | 38 | ||
39 | #include "../perf.h" | 39 | #include "../perf.h" |
40 | #include "trace-event.h" | 40 | #include "trace-event.h" |
41 | #include "debugfs.h" | 41 | #include <lk/debugfs.h> |
42 | #include "evsel.h" | 42 | #include "evsel.h" |
43 | 43 | ||
44 | #define VERSION "0.5" | 44 | #define VERSION "0.5" |
45 | 45 | ||
46 | #define TRACE_CTRL "tracing_on" | ||
47 | #define TRACE "trace" | ||
48 | #define AVAILABLE "available_tracers" | ||
49 | #define CURRENT "current_tracer" | ||
50 | #define ITER_CTRL "trace_options" | ||
51 | #define MAX_LATENCY "tracing_max_latency" | ||
52 | |||
53 | unsigned int page_size; | ||
54 | |||
55 | static const char *output_file = "trace.info"; | 46 | static const char *output_file = "trace.info"; |
56 | static int output_fd; | 47 | static int output_fd; |
57 | 48 | ||
58 | struct event_list { | ||
59 | struct event_list *next; | ||
60 | const char *event; | ||
61 | }; | ||
62 | |||
63 | struct events { | ||
64 | struct events *sibling; | ||
65 | struct events *children; | ||
66 | struct events *next; | ||
67 | char *name; | ||
68 | }; | ||
69 | |||
70 | 49 | ||
71 | static void *malloc_or_die(unsigned int size) | 50 | static void *malloc_or_die(unsigned int size) |
72 | { | 51 | { |
@@ -80,7 +59,7 @@ static void *malloc_or_die(unsigned int size) | |||
80 | 59 | ||
81 | static const char *find_debugfs(void) | 60 | static const char *find_debugfs(void) |
82 | { | 61 | { |
83 | const char *path = debugfs_mount(NULL); | 62 | const char *path = perf_debugfs_mount(NULL); |
84 | 63 | ||
85 | if (!path) | 64 | if (!path) |
86 | die("Your kernel not support debugfs filesystem"); | 65 | die("Your kernel not support debugfs filesystem"); |
@@ -131,17 +110,10 @@ static void put_tracing_file(char *file) | |||
131 | free(file); | 110 | free(file); |
132 | } | 111 | } |
133 | 112 | ||
134 | static ssize_t calc_data_size; | ||
135 | |||
136 | static ssize_t write_or_die(const void *buf, size_t len) | 113 | static ssize_t write_or_die(const void *buf, size_t len) |
137 | { | 114 | { |
138 | int ret; | 115 | int ret; |
139 | 116 | ||
140 | if (calc_data_size) { | ||
141 | calc_data_size += len; | ||
142 | return len; | ||
143 | } | ||
144 | |||
145 | ret = write(output_fd, buf, len); | 117 | ret = write(output_fd, buf, len); |
146 | if (ret < 0) | 118 | if (ret < 0) |
147 | die("writing to '%s'", output_file); | 119 | die("writing to '%s'", output_file); |
@@ -457,7 +429,6 @@ static void tracing_data_header(void) | |||
457 | write_or_die(buf, 1); | 429 | write_or_die(buf, 1); |
458 | 430 | ||
459 | /* save page_size */ | 431 | /* save page_size */ |
460 | page_size = sysconf(_SC_PAGESIZE); | ||
461 | write_or_die(&page_size, 4); | 432 | write_or_die(&page_size, 4); |
462 | } | 433 | } |
463 | 434 | ||
diff --git a/tools/perf/util/trace-event-parse.c b/tools/perf/util/trace-event-parse.c index 3aabcd687cd5..4454835a9ebc 100644 --- a/tools/perf/util/trace-event-parse.c +++ b/tools/perf/util/trace-event-parse.c | |||
@@ -183,43 +183,6 @@ void event_format__print(struct event_format *event, | |||
183 | trace_seq_do_printf(&s); | 183 | trace_seq_do_printf(&s); |
184 | } | 184 | } |
185 | 185 | ||
186 | void print_trace_event(struct pevent *pevent, int cpu, void *data, int size) | ||
187 | { | ||
188 | int type = trace_parse_common_type(pevent, data); | ||
189 | struct event_format *event = pevent_find_event(pevent, type); | ||
190 | |||
191 | if (!event) { | ||
192 | warning("ug! no event found for type %d", type); | ||
193 | return; | ||
194 | } | ||
195 | |||
196 | event_format__print(event, cpu, data, size); | ||
197 | } | ||
198 | |||
199 | void print_event(struct pevent *pevent, int cpu, void *data, int size, | ||
200 | unsigned long long nsecs, char *comm) | ||
201 | { | ||
202 | struct pevent_record record; | ||
203 | struct trace_seq s; | ||
204 | int pid; | ||
205 | |||
206 | pevent->latency_format = latency_format; | ||
207 | |||
208 | record.ts = nsecs; | ||
209 | record.cpu = cpu; | ||
210 | record.size = size; | ||
211 | record.data = data; | ||
212 | pid = pevent_data_pid(pevent, &record); | ||
213 | |||
214 | if (!pevent_pid_is_registered(pevent, pid)) | ||
215 | pevent_register_comm(pevent, comm, pid); | ||
216 | |||
217 | trace_seq_init(&s); | ||
218 | pevent_print_event(pevent, &s, &record); | ||
219 | trace_seq_do_printf(&s); | ||
220 | printf("\n"); | ||
221 | } | ||
222 | |||
223 | void parse_proc_kallsyms(struct pevent *pevent, | 186 | void parse_proc_kallsyms(struct pevent *pevent, |
224 | char *file, unsigned int size __maybe_unused) | 187 | char *file, unsigned int size __maybe_unused) |
225 | { | 188 | { |
diff --git a/tools/perf/util/trace-event-read.c b/tools/perf/util/trace-event-read.c index 3741572696af..7cb24635adf2 100644 --- a/tools/perf/util/trace-event-read.c +++ b/tools/perf/util/trace-event-read.c | |||
@@ -41,8 +41,6 @@ | |||
41 | 41 | ||
42 | static int input_fd; | 42 | static int input_fd; |
43 | 43 | ||
44 | static int read_page; | ||
45 | |||
46 | int file_bigendian; | 44 | int file_bigendian; |
47 | int host_bigendian; | 45 | int host_bigendian; |
48 | static int long_size; | 46 | static int long_size; |
@@ -287,205 +285,6 @@ static void read_event_files(struct pevent *pevent) | |||
287 | } | 285 | } |
288 | } | 286 | } |
289 | 287 | ||
290 | struct cpu_data { | ||
291 | unsigned long long offset; | ||
292 | unsigned long long size; | ||
293 | unsigned long long timestamp; | ||
294 | struct pevent_record *next; | ||
295 | char *page; | ||
296 | int cpu; | ||
297 | int index; | ||
298 | int page_size; | ||
299 | }; | ||
300 | |||
301 | static struct cpu_data *cpu_data; | ||
302 | |||
303 | static void update_cpu_data_index(int cpu) | ||
304 | { | ||
305 | cpu_data[cpu].offset += page_size; | ||
306 | cpu_data[cpu].size -= page_size; | ||
307 | cpu_data[cpu].index = 0; | ||
308 | } | ||
309 | |||
310 | static void get_next_page(int cpu) | ||
311 | { | ||
312 | off_t save_seek; | ||
313 | off_t ret; | ||
314 | |||
315 | if (!cpu_data[cpu].page) | ||
316 | return; | ||
317 | |||
318 | if (read_page) { | ||
319 | if (cpu_data[cpu].size <= page_size) { | ||
320 | free(cpu_data[cpu].page); | ||
321 | cpu_data[cpu].page = NULL; | ||
322 | return; | ||
323 | } | ||
324 | |||
325 | update_cpu_data_index(cpu); | ||
326 | |||
327 | /* other parts of the code may expect the pointer to not move */ | ||
328 | save_seek = lseek(input_fd, 0, SEEK_CUR); | ||
329 | |||
330 | ret = lseek(input_fd, cpu_data[cpu].offset, SEEK_SET); | ||
331 | if (ret == (off_t)-1) | ||
332 | die("failed to lseek"); | ||
333 | ret = read(input_fd, cpu_data[cpu].page, page_size); | ||
334 | if (ret < 0) | ||
335 | die("failed to read page"); | ||
336 | |||
337 | /* reset the file pointer back */ | ||
338 | lseek(input_fd, save_seek, SEEK_SET); | ||
339 | |||
340 | return; | ||
341 | } | ||
342 | |||
343 | munmap(cpu_data[cpu].page, page_size); | ||
344 | cpu_data[cpu].page = NULL; | ||
345 | |||
346 | if (cpu_data[cpu].size <= page_size) | ||
347 | return; | ||
348 | |||
349 | update_cpu_data_index(cpu); | ||
350 | |||
351 | cpu_data[cpu].page = mmap(NULL, page_size, PROT_READ, MAP_PRIVATE, | ||
352 | input_fd, cpu_data[cpu].offset); | ||
353 | if (cpu_data[cpu].page == MAP_FAILED) | ||
354 | die("failed to mmap cpu %d at offset 0x%llx", | ||
355 | cpu, cpu_data[cpu].offset); | ||
356 | } | ||
357 | |||
358 | static unsigned int type_len4host(unsigned int type_len_ts) | ||
359 | { | ||
360 | if (file_bigendian) | ||
361 | return (type_len_ts >> 27) & ((1 << 5) - 1); | ||
362 | else | ||
363 | return type_len_ts & ((1 << 5) - 1); | ||
364 | } | ||
365 | |||
366 | static unsigned int ts4host(unsigned int type_len_ts) | ||
367 | { | ||
368 | if (file_bigendian) | ||
369 | return type_len_ts & ((1 << 27) - 1); | ||
370 | else | ||
371 | return type_len_ts >> 5; | ||
372 | } | ||
373 | |||
374 | static int calc_index(void *ptr, int cpu) | ||
375 | { | ||
376 | return (unsigned long)ptr - (unsigned long)cpu_data[cpu].page; | ||
377 | } | ||
378 | |||
379 | struct pevent_record *trace_peek_data(struct pevent *pevent, int cpu) | ||
380 | { | ||
381 | struct pevent_record *data; | ||
382 | void *page = cpu_data[cpu].page; | ||
383 | int idx = cpu_data[cpu].index; | ||
384 | void *ptr = page + idx; | ||
385 | unsigned long long extend; | ||
386 | unsigned int type_len_ts; | ||
387 | unsigned int type_len; | ||
388 | unsigned int delta; | ||
389 | unsigned int length = 0; | ||
390 | |||
391 | if (cpu_data[cpu].next) | ||
392 | return cpu_data[cpu].next; | ||
393 | |||
394 | if (!page) | ||
395 | return NULL; | ||
396 | |||
397 | if (!idx) { | ||
398 | /* FIXME: handle header page */ | ||
399 | if (header_page_ts_size != 8) | ||
400 | die("expected a long long type for timestamp"); | ||
401 | cpu_data[cpu].timestamp = data2host8(pevent, ptr); | ||
402 | ptr += 8; | ||
403 | switch (header_page_size_size) { | ||
404 | case 4: | ||
405 | cpu_data[cpu].page_size = data2host4(pevent, ptr); | ||
406 | ptr += 4; | ||
407 | break; | ||
408 | case 8: | ||
409 | cpu_data[cpu].page_size = data2host8(pevent, ptr); | ||
410 | ptr += 8; | ||
411 | break; | ||
412 | default: | ||
413 | die("bad long size"); | ||
414 | } | ||
415 | ptr = cpu_data[cpu].page + header_page_data_offset; | ||
416 | } | ||
417 | |||
418 | read_again: | ||
419 | idx = calc_index(ptr, cpu); | ||
420 | |||
421 | if (idx >= cpu_data[cpu].page_size) { | ||
422 | get_next_page(cpu); | ||
423 | return trace_peek_data(pevent, cpu); | ||
424 | } | ||
425 | |||
426 | type_len_ts = data2host4(pevent, ptr); | ||
427 | ptr += 4; | ||
428 | |||
429 | type_len = type_len4host(type_len_ts); | ||
430 | delta = ts4host(type_len_ts); | ||
431 | |||
432 | switch (type_len) { | ||
433 | case RINGBUF_TYPE_PADDING: | ||
434 | if (!delta) | ||
435 | die("error, hit unexpected end of page"); | ||
436 | length = data2host4(pevent, ptr); | ||
437 | ptr += 4; | ||
438 | length *= 4; | ||
439 | ptr += length; | ||
440 | goto read_again; | ||
441 | |||
442 | case RINGBUF_TYPE_TIME_EXTEND: | ||
443 | extend = data2host4(pevent, ptr); | ||
444 | ptr += 4; | ||
445 | extend <<= TS_SHIFT; | ||
446 | extend += delta; | ||
447 | cpu_data[cpu].timestamp += extend; | ||
448 | goto read_again; | ||
449 | |||
450 | case RINGBUF_TYPE_TIME_STAMP: | ||
451 | ptr += 12; | ||
452 | break; | ||
453 | case 0: | ||
454 | length = data2host4(pevent, ptr); | ||
455 | ptr += 4; | ||
456 | die("here! length=%d", length); | ||
457 | break; | ||
458 | default: | ||
459 | length = type_len * 4; | ||
460 | break; | ||
461 | } | ||
462 | |||
463 | cpu_data[cpu].timestamp += delta; | ||
464 | |||
465 | data = malloc_or_die(sizeof(*data)); | ||
466 | memset(data, 0, sizeof(*data)); | ||
467 | |||
468 | data->ts = cpu_data[cpu].timestamp; | ||
469 | data->size = length; | ||
470 | data->data = ptr; | ||
471 | ptr += length; | ||
472 | |||
473 | cpu_data[cpu].index = calc_index(ptr, cpu); | ||
474 | cpu_data[cpu].next = data; | ||
475 | |||
476 | return data; | ||
477 | } | ||
478 | |||
479 | struct pevent_record *trace_read_data(struct pevent *pevent, int cpu) | ||
480 | { | ||
481 | struct pevent_record *data; | ||
482 | |||
483 | data = trace_peek_data(pevent, cpu); | ||
484 | cpu_data[cpu].next = NULL; | ||
485 | |||
486 | return data; | ||
487 | } | ||
488 | |||
489 | ssize_t trace_report(int fd, struct pevent **ppevent, bool __repipe) | 288 | ssize_t trace_report(int fd, struct pevent **ppevent, bool __repipe) |
490 | { | 289 | { |
491 | char buf[BUFSIZ]; | 290 | char buf[BUFSIZ]; |
diff --git a/tools/perf/util/trace-event.h b/tools/perf/util/trace-event.h index a55fd37ffea1..28ccde8ba20f 100644 --- a/tools/perf/util/trace-event.h +++ b/tools/perf/util/trace-event.h | |||
@@ -30,13 +30,9 @@ enum { | |||
30 | int bigendian(void); | 30 | int bigendian(void); |
31 | 31 | ||
32 | struct pevent *read_trace_init(int file_bigendian, int host_bigendian); | 32 | struct pevent *read_trace_init(int file_bigendian, int host_bigendian); |
33 | void print_trace_event(struct pevent *pevent, int cpu, void *data, int size); | ||
34 | void event_format__print(struct event_format *event, | 33 | void event_format__print(struct event_format *event, |
35 | int cpu, void *data, int size); | 34 | int cpu, void *data, int size); |
36 | 35 | ||
37 | void print_event(struct pevent *pevent, int cpu, void *data, int size, | ||
38 | unsigned long long nsecs, char *comm); | ||
39 | |||
40 | int parse_ftrace_file(struct pevent *pevent, char *buf, unsigned long size); | 36 | int parse_ftrace_file(struct pevent *pevent, char *buf, unsigned long size); |
41 | int parse_event_file(struct pevent *pevent, | 37 | int parse_event_file(struct pevent *pevent, |
42 | char *buf, unsigned long size, char *sys); | 38 | char *buf, unsigned long size, char *sys); |
diff --git a/tools/perf/util/util.c b/tools/perf/util/util.c index 805d1f52c5b4..59d868add275 100644 --- a/tools/perf/util/util.c +++ b/tools/perf/util/util.c | |||
@@ -17,6 +17,8 @@ bool test_attr__enabled; | |||
17 | bool perf_host = true; | 17 | bool perf_host = true; |
18 | bool perf_guest = false; | 18 | bool perf_guest = false; |
19 | 19 | ||
20 | char tracing_events_path[PATH_MAX + 1] = "/sys/kernel/debug/tracing/events"; | ||
21 | |||
20 | void event_attr_init(struct perf_event_attr *attr) | 22 | void event_attr_init(struct perf_event_attr *attr) |
21 | { | 23 | { |
22 | if (!perf_host) | 24 | if (!perf_host) |
@@ -242,3 +244,28 @@ void get_term_dimensions(struct winsize *ws) | |||
242 | ws->ws_row = 25; | 244 | ws->ws_row = 25; |
243 | ws->ws_col = 80; | 245 | ws->ws_col = 80; |
244 | } | 246 | } |
247 | |||
248 | static void set_tracing_events_path(const char *mountpoint) | ||
249 | { | ||
250 | snprintf(tracing_events_path, sizeof(tracing_events_path), "%s/%s", | ||
251 | mountpoint, "tracing/events"); | ||
252 | } | ||
253 | |||
254 | const char *perf_debugfs_mount(const char *mountpoint) | ||
255 | { | ||
256 | const char *mnt; | ||
257 | |||
258 | mnt = debugfs_mount(mountpoint); | ||
259 | if (!mnt) | ||
260 | return NULL; | ||
261 | |||
262 | set_tracing_events_path(mnt); | ||
263 | |||
264 | return mnt; | ||
265 | } | ||
266 | |||
267 | void perf_debugfs_set_path(const char *mntpt) | ||
268 | { | ||
269 | snprintf(debugfs_mountpoint, strlen(debugfs_mountpoint), "%s", mntpt); | ||
270 | set_tracing_events_path(mntpt); | ||
271 | } | ||
diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h index 09b4c26b71aa..6a0781c3a573 100644 --- a/tools/perf/util/util.h +++ b/tools/perf/util/util.h | |||
@@ -73,10 +73,14 @@ | |||
73 | #include <linux/magic.h> | 73 | #include <linux/magic.h> |
74 | #include "types.h" | 74 | #include "types.h" |
75 | #include <sys/ttydefaults.h> | 75 | #include <sys/ttydefaults.h> |
76 | #include <lk/debugfs.h> | ||
76 | 77 | ||
77 | extern const char *graph_line; | 78 | extern const char *graph_line; |
78 | extern const char *graph_dotted_line; | 79 | extern const char *graph_dotted_line; |
79 | extern char buildid_dir[]; | 80 | extern char buildid_dir[]; |
81 | extern char tracing_events_path[]; | ||
82 | extern void perf_debugfs_set_path(const char *mountpoint); | ||
83 | const char *perf_debugfs_mount(const char *mountpoint); | ||
80 | 84 | ||
81 | /* On most systems <limits.h> would have given us this, but | 85 | /* On most systems <limits.h> would have given us this, but |
82 | * not on some systems (e.g. GNU/Hurd). | 86 | * not on some systems (e.g. GNU/Hurd). |
@@ -274,5 +278,4 @@ extern unsigned int page_size; | |||
274 | 278 | ||
275 | struct winsize; | 279 | struct winsize; |
276 | void get_term_dimensions(struct winsize *ws); | 280 | void get_term_dimensions(struct winsize *ws); |
277 | 281 | #endif /* GIT_COMPAT_UTIL_H */ | |
278 | #endif | ||
diff --git a/tools/scripts/Makefile.include b/tools/scripts/Makefile.include index 2964b96aa55f..f03e681f8891 100644 --- a/tools/scripts/Makefile.include +++ b/tools/scripts/Makefile.include | |||
@@ -1,3 +1,4 @@ | |||
1 | ifneq ($(O),) | ||
1 | ifeq ($(origin O), command line) | 2 | ifeq ($(origin O), command line) |
2 | dummy := $(if $(shell test -d $(O) || echo $(O)),$(error O=$(O) does not exist),) | 3 | dummy := $(if $(shell test -d $(O) || echo $(O)),$(error O=$(O) does not exist),) |
3 | ABSOLUTE_O := $(shell cd $(O) ; pwd) | 4 | ABSOLUTE_O := $(shell cd $(O) ; pwd) |
@@ -7,9 +8,10 @@ ifeq ($(objtree),) | |||
7 | objtree := $(O) | 8 | objtree := $(O) |
8 | endif | 9 | endif |
9 | endif | 10 | endif |
11 | endif | ||
10 | 12 | ||
11 | ifneq ($(OUTPUT),) | ||
12 | # check that the output directory actually exists | 13 | # check that the output directory actually exists |
14 | ifneq ($(OUTPUT),) | ||
13 | OUTDIR := $(shell cd $(OUTPUT) && /bin/pwd) | 15 | OUTDIR := $(shell cd $(OUTPUT) && /bin/pwd) |
14 | $(if $(OUTDIR),, $(error output directory "$(OUTPUT)" does not exist)) | 16 | $(if $(OUTDIR),, $(error output directory "$(OUTPUT)" does not exist)) |
15 | endif | 17 | endif |
@@ -70,7 +72,7 @@ ifndef V | |||
70 | QUIET_BISON = @echo ' ' BISON $@; | 72 | QUIET_BISON = @echo ' ' BISON $@; |
71 | 73 | ||
72 | descend = \ | 74 | descend = \ |
73 | @echo ' ' DESCEND $(1); \ | 75 | +@echo ' ' DESCEND $(1); \ |
74 | mkdir -p $(OUTPUT)$(1) && \ | 76 | mkdir -p $(OUTPUT)$(1) && \ |
75 | $(MAKE) $(COMMAND_O) subdir=$(if $(subdir),$(subdir)/$(1),$(1)) $(PRINT_DIR) -C $(1) $(2) | 77 | $(MAKE) $(COMMAND_O) subdir=$(if $(subdir),$(subdir)/$(1),$(1)) $(PRINT_DIR) -C $(1) $(2) |
76 | endif | 78 | endif |
diff --git a/tools/vm/Makefile b/tools/vm/Makefile index 8e30e5c40f8a..24e9ddd93fa4 100644 --- a/tools/vm/Makefile +++ b/tools/vm/Makefile | |||
@@ -1,11 +1,22 @@ | |||
1 | # Makefile for vm tools | 1 | # Makefile for vm tools |
2 | # | ||
3 | TARGETS=page-types slabinfo | ||
4 | |||
5 | LK_DIR = ../lib/lk | ||
6 | LIBLK = $(LK_DIR)/liblk.a | ||
2 | 7 | ||
3 | CC = $(CROSS_COMPILE)gcc | 8 | CC = $(CROSS_COMPILE)gcc |
4 | CFLAGS = -Wall -Wextra | 9 | CFLAGS = -Wall -Wextra -I../lib/ |
10 | LDFLAGS = $(LIBLK) | ||
11 | |||
12 | $(TARGETS): liblk | ||
13 | |||
14 | liblk: | ||
15 | make -C $(LK_DIR) | ||
5 | 16 | ||
6 | all: page-types slabinfo | ||
7 | %: %.c | 17 | %: %.c |
8 | $(CC) $(CFLAGS) -o $@ $^ | 18 | $(CC) $(CFLAGS) -o $@ $< $(LDFLAGS) |
9 | 19 | ||
10 | clean: | 20 | clean: |
11 | $(RM) page-types slabinfo | 21 | $(RM) page-types slabinfo |
22 | make -C ../lib/lk clean | ||
diff --git a/tools/vm/page-types.c b/tools/vm/page-types.c index b76edf2f8333..71c9c2511ee7 100644 --- a/tools/vm/page-types.c +++ b/tools/vm/page-types.c | |||
@@ -36,7 +36,7 @@ | |||
36 | #include <sys/statfs.h> | 36 | #include <sys/statfs.h> |
37 | #include "../../include/uapi/linux/magic.h" | 37 | #include "../../include/uapi/linux/magic.h" |
38 | #include "../../include/uapi/linux/kernel-page-flags.h" | 38 | #include "../../include/uapi/linux/kernel-page-flags.h" |
39 | 39 | #include <lk/debugfs.h> | |
40 | 40 | ||
41 | #ifndef MAX_PATH | 41 | #ifndef MAX_PATH |
42 | # define MAX_PATH 256 | 42 | # define MAX_PATH 256 |
@@ -178,7 +178,7 @@ static int kpageflags_fd; | |||
178 | static int opt_hwpoison; | 178 | static int opt_hwpoison; |
179 | static int opt_unpoison; | 179 | static int opt_unpoison; |
180 | 180 | ||
181 | static char hwpoison_debug_fs[MAX_PATH+1]; | 181 | static char *hwpoison_debug_fs; |
182 | static int hwpoison_inject_fd; | 182 | static int hwpoison_inject_fd; |
183 | static int hwpoison_forget_fd; | 183 | static int hwpoison_forget_fd; |
184 | 184 | ||
@@ -458,81 +458,6 @@ static uint64_t kpageflags_flags(uint64_t flags) | |||
458 | return flags; | 458 | return flags; |
459 | } | 459 | } |
460 | 460 | ||
461 | /* verify that a mountpoint is actually a debugfs instance */ | ||
462 | static int debugfs_valid_mountpoint(const char *debugfs) | ||
463 | { | ||
464 | struct statfs st_fs; | ||
465 | |||
466 | if (statfs(debugfs, &st_fs) < 0) | ||
467 | return -ENOENT; | ||
468 | else if (st_fs.f_type != (long) DEBUGFS_MAGIC) | ||
469 | return -ENOENT; | ||
470 | |||
471 | return 0; | ||
472 | } | ||
473 | |||
474 | /* find the path to the mounted debugfs */ | ||
475 | static const char *debugfs_find_mountpoint(void) | ||
476 | { | ||
477 | const char *const *ptr; | ||
478 | char type[100]; | ||
479 | FILE *fp; | ||
480 | |||
481 | ptr = debugfs_known_mountpoints; | ||
482 | while (*ptr) { | ||
483 | if (debugfs_valid_mountpoint(*ptr) == 0) { | ||
484 | strcpy(hwpoison_debug_fs, *ptr); | ||
485 | return hwpoison_debug_fs; | ||
486 | } | ||
487 | ptr++; | ||
488 | } | ||
489 | |||
490 | /* give up and parse /proc/mounts */ | ||
491 | fp = fopen("/proc/mounts", "r"); | ||
492 | if (fp == NULL) | ||
493 | perror("Can't open /proc/mounts for read"); | ||
494 | |||
495 | while (fscanf(fp, "%*s %" | ||
496 | STR(MAX_PATH) | ||
497 | "s %99s %*s %*d %*d\n", | ||
498 | hwpoison_debug_fs, type) == 2) { | ||
499 | if (strcmp(type, "debugfs") == 0) | ||
500 | break; | ||
501 | } | ||
502 | fclose(fp); | ||
503 | |||
504 | if (strcmp(type, "debugfs") != 0) | ||
505 | return NULL; | ||
506 | |||
507 | return hwpoison_debug_fs; | ||
508 | } | ||
509 | |||
510 | /* mount the debugfs somewhere if it's not mounted */ | ||
511 | |||
512 | static void debugfs_mount(void) | ||
513 | { | ||
514 | const char *const *ptr; | ||
515 | |||
516 | /* see if it's already mounted */ | ||
517 | if (debugfs_find_mountpoint()) | ||
518 | return; | ||
519 | |||
520 | ptr = debugfs_known_mountpoints; | ||
521 | while (*ptr) { | ||
522 | if (mount(NULL, *ptr, "debugfs", 0, NULL) == 0) { | ||
523 | /* save the mountpoint */ | ||
524 | strcpy(hwpoison_debug_fs, *ptr); | ||
525 | break; | ||
526 | } | ||
527 | ptr++; | ||
528 | } | ||
529 | |||
530 | if (*ptr == NULL) { | ||
531 | perror("mount debugfs"); | ||
532 | exit(EXIT_FAILURE); | ||
533 | } | ||
534 | } | ||
535 | |||
536 | /* | 461 | /* |
537 | * page actions | 462 | * page actions |
538 | */ | 463 | */ |
@@ -541,7 +466,11 @@ static void prepare_hwpoison_fd(void) | |||
541 | { | 466 | { |
542 | char buf[MAX_PATH + 1]; | 467 | char buf[MAX_PATH + 1]; |
543 | 468 | ||
544 | debugfs_mount(); | 469 | hwpoison_debug_fs = debugfs_mount(NULL); |
470 | if (!hwpoison_debug_fs) { | ||
471 | perror("mount debugfs"); | ||
472 | exit(EXIT_FAILURE); | ||
473 | } | ||
545 | 474 | ||
546 | if (opt_hwpoison && !hwpoison_inject_fd) { | 475 | if (opt_hwpoison && !hwpoison_inject_fd) { |
547 | snprintf(buf, MAX_PATH, "%s/hwpoison/corrupt-pfn", | 476 | snprintf(buf, MAX_PATH, "%s/hwpoison/corrupt-pfn", |