diff options
author | James Morris <james.l.morris@oracle.com> | 2014-04-13 21:23:14 -0400 |
---|---|---|
committer | James Morris <james.l.morris@oracle.com> | 2014-04-13 21:23:14 -0400 |
commit | ecd740c6f2f092b90b95fa35f757973589eaaca2 (patch) | |
tree | ce02b1e18c4fc5729699251460cd8be7604d8401 /tools | |
parent | f64410ec665479d7b4b77b7519e814253ed0f686 (diff) | |
parent | 455c6fdbd219161bd09b1165f11699d6d73de11c (diff) |
Merge commit 'v3.14' into next
Diffstat (limited to 'tools')
363 files changed, 15055 insertions, 2948 deletions
diff --git a/tools/Makefile b/tools/Makefile index a9b02008443c..feec3ad5fd09 100644 --- a/tools/Makefile +++ b/tools/Makefile | |||
@@ -3,6 +3,7 @@ include scripts/Makefile.include | |||
3 | help: | 3 | help: |
4 | @echo 'Possible targets:' | 4 | @echo 'Possible targets:' |
5 | @echo '' | 5 | @echo '' |
6 | @echo ' acpi - ACPI tools' | ||
6 | @echo ' cgroup - cgroup tools' | 7 | @echo ' cgroup - cgroup tools' |
7 | @echo ' cpupower - a tool for all things x86 CPU power' | 8 | @echo ' cpupower - a tool for all things x86 CPU power' |
8 | @echo ' firewire - the userspace part of nosy, an IEEE-1394 traffic sniffer' | 9 | @echo ' firewire - the userspace part of nosy, an IEEE-1394 traffic sniffer' |
@@ -33,16 +34,19 @@ help: | |||
33 | @echo ' the respective build directory.' | 34 | @echo ' the respective build directory.' |
34 | @echo ' clean: a summary clean target to clean _all_ folders' | 35 | @echo ' clean: a summary clean target to clean _all_ folders' |
35 | 36 | ||
37 | acpi: FORCE | ||
38 | $(call descend,power/$@) | ||
39 | |||
36 | cpupower: FORCE | 40 | cpupower: FORCE |
37 | $(call descend,power/$@) | 41 | $(call descend,power/$@) |
38 | 42 | ||
39 | cgroup firewire guest usb virtio vm net: FORCE | 43 | cgroup firewire guest usb virtio vm net: FORCE |
40 | $(call descend,$@) | 44 | $(call descend,$@) |
41 | 45 | ||
42 | liblk: FORCE | 46 | libapikfs: FORCE |
43 | $(call descend,lib/lk) | 47 | $(call descend,lib/api) |
44 | 48 | ||
45 | perf: liblk FORCE | 49 | perf: libapikfs FORCE |
46 | $(call descend,$@) | 50 | $(call descend,$@) |
47 | 51 | ||
48 | selftests: FORCE | 52 | selftests: FORCE |
@@ -54,6 +58,9 @@ turbostat x86_energy_perf_policy: FORCE | |||
54 | tmon: FORCE | 58 | tmon: FORCE |
55 | $(call descend,thermal/$@) | 59 | $(call descend,thermal/$@) |
56 | 60 | ||
61 | acpi_install: | ||
62 | $(call descend,power/$(@:_install=),install) | ||
63 | |||
57 | cpupower_install: | 64 | cpupower_install: |
58 | $(call descend,power/$(@:_install=),install) | 65 | $(call descend,power/$(@:_install=),install) |
59 | 66 | ||
@@ -69,21 +76,24 @@ turbostat_install x86_energy_perf_policy_install: | |||
69 | tmon_install: | 76 | tmon_install: |
70 | $(call descend,thermal/$(@:_install=),install) | 77 | $(call descend,thermal/$(@:_install=),install) |
71 | 78 | ||
72 | install: cgroup_install cpupower_install firewire_install lguest_install \ | 79 | install: acpi_install cgroup_install cpupower_install firewire_install lguest_install \ |
73 | perf_install selftests_install turbostat_install usb_install \ | 80 | perf_install selftests_install turbostat_install usb_install \ |
74 | virtio_install vm_install net_install x86_energy_perf_policy_install \ | 81 | virtio_install vm_install net_install x86_energy_perf_policy_install \ |
75 | tmon | 82 | tmon |
76 | 83 | ||
84 | acpi_clean: | ||
85 | $(call descend,power/acpi,clean) | ||
86 | |||
77 | cpupower_clean: | 87 | cpupower_clean: |
78 | $(call descend,power/cpupower,clean) | 88 | $(call descend,power/cpupower,clean) |
79 | 89 | ||
80 | cgroup_clean firewire_clean lguest_clean usb_clean virtio_clean vm_clean net_clean: | 90 | cgroup_clean firewire_clean lguest_clean usb_clean virtio_clean vm_clean net_clean: |
81 | $(call descend,$(@:_clean=),clean) | 91 | $(call descend,$(@:_clean=),clean) |
82 | 92 | ||
83 | liblk_clean: | 93 | libapikfs_clean: |
84 | $(call descend,lib/lk,clean) | 94 | $(call descend,lib/api,clean) |
85 | 95 | ||
86 | perf_clean: liblk_clean | 96 | perf_clean: libapikfs_clean |
87 | $(call descend,$(@:_clean=),clean) | 97 | $(call descend,$(@:_clean=),clean) |
88 | 98 | ||
89 | selftests_clean: | 99 | selftests_clean: |
@@ -95,8 +105,8 @@ turbostat_clean x86_energy_perf_policy_clean: | |||
95 | tmon_clean: | 105 | tmon_clean: |
96 | $(call descend,thermal/tmon,clean) | 106 | $(call descend,thermal/tmon,clean) |
97 | 107 | ||
98 | clean: cgroup_clean cpupower_clean firewire_clean lguest_clean perf_clean \ | 108 | clean: acpi_clean cgroup_clean cpupower_clean firewire_clean lguest_clean \ |
99 | selftests_clean turbostat_clean usb_clean virtio_clean \ | 109 | perf_clean selftests_clean turbostat_clean usb_clean virtio_clean \ |
100 | vm_clean net_clean x86_energy_perf_policy_clean tmon_clean | 110 | vm_clean net_clean x86_energy_perf_policy_clean tmon_clean |
101 | 111 | ||
102 | .PHONY: FORCE | 112 | .PHONY: FORCE |
diff --git a/tools/hv/hv_kvp_daemon.c b/tools/hv/hv_kvp_daemon.c index b8d6d541d854..4088b816a3ee 100644 --- a/tools/hv/hv_kvp_daemon.c +++ b/tools/hv/hv_kvp_daemon.c | |||
@@ -26,7 +26,6 @@ | |||
26 | #include <sys/socket.h> | 26 | #include <sys/socket.h> |
27 | #include <sys/poll.h> | 27 | #include <sys/poll.h> |
28 | #include <sys/utsname.h> | 28 | #include <sys/utsname.h> |
29 | #include <linux/types.h> | ||
30 | #include <stdio.h> | 29 | #include <stdio.h> |
31 | #include <stdlib.h> | 30 | #include <stdlib.h> |
32 | #include <unistd.h> | 31 | #include <unistd.h> |
diff --git a/tools/hv/hv_vss_daemon.c b/tools/hv/hv_vss_daemon.c index 8bcb04096eb2..520de3304571 100644 --- a/tools/hv/hv_vss_daemon.c +++ b/tools/hv/hv_vss_daemon.c | |||
@@ -22,7 +22,6 @@ | |||
22 | #include <sys/socket.h> | 22 | #include <sys/socket.h> |
23 | #include <sys/poll.h> | 23 | #include <sys/poll.h> |
24 | #include <sys/ioctl.h> | 24 | #include <sys/ioctl.h> |
25 | #include <linux/types.h> | ||
26 | #include <fcntl.h> | 25 | #include <fcntl.h> |
27 | #include <stdio.h> | 26 | #include <stdio.h> |
28 | #include <mntent.h> | 27 | #include <mntent.h> |
diff --git a/tools/perf/util/include/asm/bug.h b/tools/include/asm/bug.h index 7fcc6810adc2..9e5f4846967f 100644 --- a/tools/perf/util/include/asm/bug.h +++ b/tools/include/asm/bug.h | |||
@@ -1,5 +1,7 @@ | |||
1 | #ifndef _PERF_ASM_GENERIC_BUG_H | 1 | #ifndef _TOOLS_ASM_BUG_H |
2 | #define _PERF_ASM_GENERIC_BUG_H | 2 | #define _TOOLS_ASM_BUG_H |
3 | |||
4 | #include <linux/compiler.h> | ||
3 | 5 | ||
4 | #define __WARN_printf(arg...) do { fprintf(stderr, arg); } while (0) | 6 | #define __WARN_printf(arg...) do { fprintf(stderr, arg); } while (0) |
5 | 7 | ||
@@ -19,4 +21,5 @@ | |||
19 | __warned = 1; \ | 21 | __warned = 1; \ |
20 | unlikely(__ret_warn_once); \ | 22 | unlikely(__ret_warn_once); \ |
21 | }) | 23 | }) |
22 | #endif | 24 | |
25 | #endif /* _TOOLS_ASM_BUG_H */ | ||
diff --git a/tools/perf/util/include/linux/compiler.h b/tools/include/linux/compiler.h index b003ad7200b2..fbc6665c6d53 100644 --- a/tools/perf/util/include/linux/compiler.h +++ b/tools/include/linux/compiler.h | |||
@@ -1,5 +1,5 @@ | |||
1 | #ifndef _PERF_LINUX_COMPILER_H_ | 1 | #ifndef _TOOLS_LINUX_COMPILER_H_ |
2 | #define _PERF_LINUX_COMPILER_H_ | 2 | #define _TOOLS_LINUX_COMPILER_H_ |
3 | 3 | ||
4 | #ifndef __always_inline | 4 | #ifndef __always_inline |
5 | # define __always_inline inline __attribute__((always_inline)) | 5 | # define __always_inline inline __attribute__((always_inline)) |
@@ -27,4 +27,12 @@ | |||
27 | # define __weak __attribute__((weak)) | 27 | # define __weak __attribute__((weak)) |
28 | #endif | 28 | #endif |
29 | 29 | ||
30 | #ifndef likely | ||
31 | # define likely(x) __builtin_expect(!!(x), 1) | ||
30 | #endif | 32 | #endif |
33 | |||
34 | #ifndef unlikely | ||
35 | # define unlikely(x) __builtin_expect(!!(x), 0) | ||
36 | #endif | ||
37 | |||
38 | #endif /* _TOOLS_LINUX_COMPILER_H */ | ||
diff --git a/tools/lib/lk/Makefile b/tools/lib/api/Makefile index 3dba0a4aebbf..ed2f51e11b80 100644 --- a/tools/lib/lk/Makefile +++ b/tools/lib/api/Makefile | |||
@@ -1,4 +1,5 @@ | |||
1 | include ../../scripts/Makefile.include | 1 | include ../../scripts/Makefile.include |
2 | include ../../perf/config/utilities.mak # QUIET_CLEAN | ||
2 | 3 | ||
3 | CC = $(CROSS_COMPILE)gcc | 4 | CC = $(CROSS_COMPILE)gcc |
4 | AR = $(CROSS_COMPILE)ar | 5 | AR = $(CROSS_COMPILE)ar |
@@ -7,11 +8,11 @@ AR = $(CROSS_COMPILE)ar | |||
7 | LIB_H= | 8 | LIB_H= |
8 | LIB_OBJS= | 9 | LIB_OBJS= |
9 | 10 | ||
10 | LIB_H += debugfs.h | 11 | LIB_H += fs/debugfs.h |
11 | 12 | ||
12 | LIB_OBJS += $(OUTPUT)debugfs.o | 13 | LIB_OBJS += $(OUTPUT)fs/debugfs.o |
13 | 14 | ||
14 | LIBFILE = liblk.a | 15 | LIBFILE = libapikfs.a |
15 | 16 | ||
16 | CFLAGS = -ggdb3 -Wall -Wextra -std=gnu99 -Werror -O6 -D_FORTIFY_SOURCE=2 $(EXTRA_WARNINGS) $(EXTRA_CFLAGS) -fPIC | 17 | CFLAGS = -ggdb3 -Wall -Wextra -std=gnu99 -Werror -O6 -D_FORTIFY_SOURCE=2 $(EXTRA_WARNINGS) $(EXTRA_CFLAGS) -fPIC |
17 | EXTLIBS = -lelf -lpthread -lrt -lm | 18 | EXTLIBS = -lelf -lpthread -lrt -lm |
@@ -25,14 +26,17 @@ $(LIBFILE): $(LIB_OBJS) | |||
25 | 26 | ||
26 | $(LIB_OBJS): $(LIB_H) | 27 | $(LIB_OBJS): $(LIB_H) |
27 | 28 | ||
28 | $(OUTPUT)%.o: %.c | 29 | libapi_dirs: |
30 | $(QUIET_MKDIR)mkdir -p $(OUTPUT)fs/ | ||
31 | |||
32 | $(OUTPUT)%.o: %.c libapi_dirs | ||
29 | $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) $< | 33 | $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) $< |
30 | $(OUTPUT)%.s: %.c | 34 | $(OUTPUT)%.s: %.c libapi_dirs |
31 | $(QUIET_CC)$(CC) -S $(ALL_CFLAGS) $< | 35 | $(QUIET_CC)$(CC) -S $(ALL_CFLAGS) $< |
32 | $(OUTPUT)%.o: %.S | 36 | $(OUTPUT)%.o: %.S libapi_dirs |
33 | $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) $< | 37 | $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) $< |
34 | 38 | ||
35 | clean: | 39 | clean: |
36 | $(RM) $(LIB_OBJS) $(LIBFILE) | 40 | $(call QUIET_CLEAN, libapi) $(RM) $(LIB_OBJS) $(LIBFILE) |
37 | 41 | ||
38 | .PHONY: clean | 42 | .PHONY: clean |
diff --git a/tools/lib/lk/debugfs.c b/tools/lib/api/fs/debugfs.c index 7c4347962353..7c4347962353 100644 --- a/tools/lib/lk/debugfs.c +++ b/tools/lib/api/fs/debugfs.c | |||
diff --git a/tools/lib/lk/debugfs.h b/tools/lib/api/fs/debugfs.h index 935c59bdb442..f19d3df9609d 100644 --- a/tools/lib/lk/debugfs.h +++ b/tools/lib/api/fs/debugfs.h | |||
@@ -1,5 +1,5 @@ | |||
1 | #ifndef __LK_DEBUGFS_H__ | 1 | #ifndef __API_DEBUGFS_H__ |
2 | #define __LK_DEBUGFS_H__ | 2 | #define __API_DEBUGFS_H__ |
3 | 3 | ||
4 | #define _STR(x) #x | 4 | #define _STR(x) #x |
5 | #define STR(x) _STR(x) | 5 | #define STR(x) _STR(x) |
@@ -26,4 +26,4 @@ char *debugfs_mount(const char *mountpoint); | |||
26 | 26 | ||
27 | extern char debugfs_mountpoint[]; | 27 | extern char debugfs_mountpoint[]; |
28 | 28 | ||
29 | #endif /* __LK_DEBUGFS_H__ */ | 29 | #endif /* __API_DEBUGFS_H__ */ |
diff --git a/tools/lib/lockdep/Makefile b/tools/lib/lockdep/Makefile new file mode 100644 index 000000000000..07b0b7542511 --- /dev/null +++ b/tools/lib/lockdep/Makefile | |||
@@ -0,0 +1,251 @@ | |||
1 | # liblockdep version | ||
2 | LL_VERSION = 0 | ||
3 | LL_PATCHLEVEL = 0 | ||
4 | LL_EXTRAVERSION = 1 | ||
5 | |||
6 | # file format version | ||
7 | FILE_VERSION = 1 | ||
8 | |||
9 | MAKEFLAGS += --no-print-directory | ||
10 | |||
11 | |||
12 | # Makefiles suck: This macro sets a default value of $(2) for the | ||
13 | # variable named by $(1), unless the variable has been set by | ||
14 | # environment or command line. This is necessary for CC and AR | ||
15 | # because make sets default values, so the simpler ?= approach | ||
16 | # won't work as expected. | ||
17 | define allow-override | ||
18 | $(if $(or $(findstring environment,$(origin $(1))),\ | ||
19 | $(findstring command line,$(origin $(1)))),,\ | ||
20 | $(eval $(1) = $(2))) | ||
21 | endef | ||
22 | |||
23 | # Allow setting CC and AR, or setting CROSS_COMPILE as a prefix. | ||
24 | $(call allow-override,CC,$(CROSS_COMPILE)gcc) | ||
25 | $(call allow-override,AR,$(CROSS_COMPILE)ar) | ||
26 | |||
27 | INSTALL = install | ||
28 | |||
29 | # Use DESTDIR for installing into a different root directory. | ||
30 | # This is useful for building a package. The program will be | ||
31 | # installed in this directory as if it was the root directory. | ||
32 | # Then the build tool can move it later. | ||
33 | DESTDIR ?= | ||
34 | DESTDIR_SQ = '$(subst ','\'',$(DESTDIR))' | ||
35 | |||
36 | prefix ?= /usr/local | ||
37 | libdir_relative = lib | ||
38 | libdir = $(prefix)/$(libdir_relative) | ||
39 | bindir_relative = bin | ||
40 | bindir = $(prefix)/$(bindir_relative) | ||
41 | |||
42 | export DESTDIR DESTDIR_SQ INSTALL | ||
43 | |||
44 | # copy a bit from Linux kbuild | ||
45 | |||
46 | ifeq ("$(origin V)", "command line") | ||
47 | VERBOSE = $(V) | ||
48 | endif | ||
49 | ifndef VERBOSE | ||
50 | VERBOSE = 0 | ||
51 | endif | ||
52 | |||
53 | ifeq ("$(origin O)", "command line") | ||
54 | BUILD_OUTPUT := $(O) | ||
55 | endif | ||
56 | |||
57 | ifeq ($(BUILD_SRC),) | ||
58 | ifneq ($(BUILD_OUTPUT),) | ||
59 | |||
60 | define build_output | ||
61 | $(if $(VERBOSE:1=),@)$(MAKE) -C $(BUILD_OUTPUT) \ | ||
62 | BUILD_SRC=$(CURDIR) -f $(CURDIR)/Makefile $1 | ||
63 | endef | ||
64 | |||
65 | saved-output := $(BUILD_OUTPUT) | ||
66 | BUILD_OUTPUT := $(shell cd $(BUILD_OUTPUT) && /bin/pwd) | ||
67 | $(if $(BUILD_OUTPUT),, \ | ||
68 | $(error output directory "$(saved-output)" does not exist)) | ||
69 | |||
70 | all: sub-make | ||
71 | |||
72 | gui: force | ||
73 | $(call build_output, all_cmd) | ||
74 | |||
75 | $(filter-out gui,$(MAKECMDGOALS)): sub-make | ||
76 | |||
77 | sub-make: force | ||
78 | $(call build_output, $(MAKECMDGOALS)) | ||
79 | |||
80 | |||
81 | # Leave processing to above invocation of make | ||
82 | skip-makefile := 1 | ||
83 | |||
84 | endif # BUILD_OUTPUT | ||
85 | endif # BUILD_SRC | ||
86 | |||
87 | # We process the rest of the Makefile if this is the final invocation of make | ||
88 | ifeq ($(skip-makefile),) | ||
89 | |||
90 | srctree := $(realpath $(if $(BUILD_SRC),$(BUILD_SRC),$(CURDIR))) | ||
91 | objtree := $(realpath $(CURDIR)) | ||
92 | src := $(srctree) | ||
93 | obj := $(objtree) | ||
94 | |||
95 | export prefix libdir bindir src obj | ||
96 | |||
97 | # Shell quotes | ||
98 | libdir_SQ = $(subst ','\'',$(libdir)) | ||
99 | bindir_SQ = $(subst ','\'',$(bindir)) | ||
100 | |||
101 | LIB_FILE = liblockdep.a liblockdep.so | ||
102 | BIN_FILE = lockdep | ||
103 | |||
104 | CONFIG_INCLUDES = | ||
105 | CONFIG_LIBS = | ||
106 | CONFIG_FLAGS = | ||
107 | |||
108 | OBJ = $@ | ||
109 | N = | ||
110 | |||
111 | export Q VERBOSE | ||
112 | |||
113 | LIBLOCKDEP_VERSION = $(LL_VERSION).$(LL_PATCHLEVEL).$(LL_EXTRAVERSION) | ||
114 | |||
115 | INCLUDES = -I. -I/usr/local/include -I./uinclude -I./include $(CONFIG_INCLUDES) | ||
116 | |||
117 | # Set compile option CFLAGS if not set elsewhere | ||
118 | CFLAGS ?= -g -DCONFIG_LOCKDEP -DCONFIG_STACKTRACE -DCONFIG_PROVE_LOCKING -DBITS_PER_LONG=__WORDSIZE -DLIBLOCKDEP_VERSION='"$(LIBLOCKDEP_VERSION)"' -rdynamic -O0 -g | ||
119 | |||
120 | override CFLAGS += $(CONFIG_FLAGS) $(INCLUDES) $(PLUGIN_DIR_SQ) | ||
121 | |||
122 | ifeq ($(VERBOSE),1) | ||
123 | Q = | ||
124 | print_compile = | ||
125 | print_app_build = | ||
126 | print_fpic_compile = | ||
127 | print_shared_lib_compile = | ||
128 | print_install = | ||
129 | else | ||
130 | Q = @ | ||
131 | print_compile = echo ' CC '$(OBJ); | ||
132 | print_app_build = echo ' BUILD '$(OBJ); | ||
133 | print_fpic_compile = echo ' CC FPIC '$(OBJ); | ||
134 | print_shared_lib_compile = echo ' BUILD SHARED LIB '$(OBJ); | ||
135 | print_static_lib_build = echo ' BUILD STATIC LIB '$(OBJ); | ||
136 | print_install = echo ' INSTALL '$1' to $(DESTDIR_SQ)$2'; | ||
137 | endif | ||
138 | |||
139 | do_fpic_compile = \ | ||
140 | ($(print_fpic_compile) \ | ||
141 | $(CC) -c $(CFLAGS) $(EXT) -fPIC $< -o $@) | ||
142 | |||
143 | do_app_build = \ | ||
144 | ($(print_app_build) \ | ||
145 | $(CC) $^ -rdynamic -o $@ $(CONFIG_LIBS) $(LIBS)) | ||
146 | |||
147 | do_compile_shared_library = \ | ||
148 | ($(print_shared_lib_compile) \ | ||
149 | $(CC) --shared $^ -o $@ -lpthread -ldl) | ||
150 | |||
151 | do_build_static_lib = \ | ||
152 | ($(print_static_lib_build) \ | ||
153 | $(RM) $@; $(AR) rcs $@ $^) | ||
154 | |||
155 | |||
156 | define do_compile | ||
157 | $(print_compile) \ | ||
158 | $(CC) -c $(CFLAGS) $(EXT) $< -o $(obj)/$@; | ||
159 | endef | ||
160 | |||
161 | $(obj)/%.o: $(src)/%.c | ||
162 | $(Q)$(call do_compile) | ||
163 | |||
164 | %.o: $(src)/%.c | ||
165 | $(Q)$(call do_compile) | ||
166 | |||
167 | PEVENT_LIB_OBJS = common.o lockdep.o preload.o rbtree.o | ||
168 | |||
169 | ALL_OBJS = $(PEVENT_LIB_OBJS) | ||
170 | |||
171 | CMD_TARGETS = $(LIB_FILE) | ||
172 | |||
173 | TARGETS = $(CMD_TARGETS) | ||
174 | |||
175 | |||
176 | all: all_cmd | ||
177 | |||
178 | all_cmd: $(CMD_TARGETS) | ||
179 | |||
180 | liblockdep.so: $(PEVENT_LIB_OBJS) | ||
181 | $(Q)$(do_compile_shared_library) | ||
182 | |||
183 | liblockdep.a: $(PEVENT_LIB_OBJS) | ||
184 | $(Q)$(do_build_static_lib) | ||
185 | |||
186 | $(PEVENT_LIB_OBJS): %.o: $(src)/%.c | ||
187 | $(Q)$(do_fpic_compile) | ||
188 | |||
189 | ## make deps | ||
190 | |||
191 | all_objs := $(sort $(ALL_OBJS)) | ||
192 | all_deps := $(all_objs:%.o=.%.d) | ||
193 | |||
194 | # let .d file also depends on the source and header files | ||
195 | define check_deps | ||
196 | @set -e; $(RM) $@; \ | ||
197 | $(CC) -MM $(CFLAGS) $< > $@.$$$$; \ | ||
198 | sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \ | ||
199 | $(RM) $@.$$$$ | ||
200 | endef | ||
201 | |||
202 | $(all_deps): .%.d: $(src)/%.c | ||
203 | $(Q)$(call check_deps) | ||
204 | |||
205 | $(all_objs) : %.o : .%.d | ||
206 | |||
207 | dep_includes := $(wildcard $(all_deps)) | ||
208 | |||
209 | ifneq ($(dep_includes),) | ||
210 | include $(dep_includes) | ||
211 | endif | ||
212 | |||
213 | ### Detect environment changes | ||
214 | TRACK_CFLAGS = $(subst ','\'',$(CFLAGS)):$(ARCH):$(CROSS_COMPILE) | ||
215 | |||
216 | tags: force | ||
217 | $(RM) tags | ||
218 | find . -name '*.[ch]' | xargs ctags --extra=+f --c-kinds=+px \ | ||
219 | --regex-c++='/_PE\(([^,)]*).*/PEVENT_ERRNO__\1/' | ||
220 | |||
221 | TAGS: force | ||
222 | $(RM) TAGS | ||
223 | find . -name '*.[ch]' | xargs etags \ | ||
224 | --regex='/_PE(\([^,)]*\).*/PEVENT_ERRNO__\1/' | ||
225 | |||
226 | define do_install | ||
227 | $(print_install) \ | ||
228 | if [ ! -d '$(DESTDIR_SQ)$2' ]; then \ | ||
229 | $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$2'; \ | ||
230 | fi; \ | ||
231 | $(INSTALL) $1 '$(DESTDIR_SQ)$2' | ||
232 | endef | ||
233 | |||
234 | install_lib: all_cmd | ||
235 | $(Q)$(call do_install,$(LIB_FILE),$(libdir_SQ)) | ||
236 | $(Q)$(call do_install,$(BIN_FILE),$(bindir_SQ)) | ||
237 | |||
238 | install: install_lib | ||
239 | |||
240 | clean: | ||
241 | $(RM) *.o *~ $(TARGETS) *.a *.so $(VERSION_FILES) .*.d | ||
242 | $(RM) tags TAGS | ||
243 | |||
244 | endif # skip-makefile | ||
245 | |||
246 | PHONY += force | ||
247 | force: | ||
248 | |||
249 | # Declare the contents of the .PHONY variable as phony. We keep that | ||
250 | # information in a variable so we can use it in if_changed and friends. | ||
251 | .PHONY: $(PHONY) | ||
diff --git a/tools/lib/lockdep/common.c b/tools/lib/lockdep/common.c new file mode 100644 index 000000000000..8ef602f18a32 --- /dev/null +++ b/tools/lib/lockdep/common.c | |||
@@ -0,0 +1,33 @@ | |||
1 | #include <stddef.h> | ||
2 | #include <stdbool.h> | ||
3 | #include <linux/compiler.h> | ||
4 | #include <linux/lockdep.h> | ||
5 | #include <unistd.h> | ||
6 | #include <sys/syscall.h> | ||
7 | |||
8 | static __thread struct task_struct current_obj; | ||
9 | |||
10 | /* lockdep wants these */ | ||
11 | bool debug_locks = true; | ||
12 | bool debug_locks_silent; | ||
13 | |||
14 | __attribute__((constructor)) static void liblockdep_init(void) | ||
15 | { | ||
16 | lockdep_init(); | ||
17 | } | ||
18 | |||
19 | __attribute__((destructor)) static void liblockdep_exit(void) | ||
20 | { | ||
21 | debug_check_no_locks_held(¤t_obj); | ||
22 | } | ||
23 | |||
24 | struct task_struct *__curr(void) | ||
25 | { | ||
26 | if (current_obj.pid == 0) { | ||
27 | /* Makes lockdep output pretty */ | ||
28 | prctl(PR_GET_NAME, current_obj.comm); | ||
29 | current_obj.pid = syscall(__NR_gettid); | ||
30 | } | ||
31 | |||
32 | return ¤t_obj; | ||
33 | } | ||
diff --git a/tools/lib/lockdep/include/liblockdep/common.h b/tools/lib/lockdep/include/liblockdep/common.h new file mode 100644 index 000000000000..0bda630027c3 --- /dev/null +++ b/tools/lib/lockdep/include/liblockdep/common.h | |||
@@ -0,0 +1,50 @@ | |||
1 | #ifndef _LIBLOCKDEP_COMMON_H | ||
2 | #define _LIBLOCKDEP_COMMON_H | ||
3 | |||
4 | #include <pthread.h> | ||
5 | |||
6 | #define NR_LOCKDEP_CACHING_CLASSES 2 | ||
7 | #define MAX_LOCKDEP_SUBCLASSES 8UL | ||
8 | |||
9 | #ifndef CALLER_ADDR0 | ||
10 | #define CALLER_ADDR0 ((unsigned long)__builtin_return_address(0)) | ||
11 | #endif | ||
12 | |||
13 | #ifndef _RET_IP_ | ||
14 | #define _RET_IP_ CALLER_ADDR0 | ||
15 | #endif | ||
16 | |||
17 | #ifndef _THIS_IP_ | ||
18 | #define _THIS_IP_ ({ __label__ __here; __here: (unsigned long)&&__here; }) | ||
19 | #endif | ||
20 | |||
21 | struct lockdep_subclass_key { | ||
22 | char __one_byte; | ||
23 | }; | ||
24 | |||
25 | struct lock_class_key { | ||
26 | struct lockdep_subclass_key subkeys[MAX_LOCKDEP_SUBCLASSES]; | ||
27 | }; | ||
28 | |||
29 | struct lockdep_map { | ||
30 | struct lock_class_key *key; | ||
31 | struct lock_class *class_cache[NR_LOCKDEP_CACHING_CLASSES]; | ||
32 | const char *name; | ||
33 | #ifdef CONFIG_LOCK_STAT | ||
34 | int cpu; | ||
35 | unsigned long ip; | ||
36 | #endif | ||
37 | }; | ||
38 | |||
39 | void lockdep_init_map(struct lockdep_map *lock, const char *name, | ||
40 | struct lock_class_key *key, int subclass); | ||
41 | void lock_acquire(struct lockdep_map *lock, unsigned int subclass, | ||
42 | int trylock, int read, int check, | ||
43 | struct lockdep_map *nest_lock, unsigned long ip); | ||
44 | void lock_release(struct lockdep_map *lock, int nested, | ||
45 | unsigned long ip); | ||
46 | |||
47 | #define STATIC_LOCKDEP_MAP_INIT(_name, _key) \ | ||
48 | { .name = (_name), .key = (void *)(_key), } | ||
49 | |||
50 | #endif | ||
diff --git a/tools/lib/lockdep/include/liblockdep/mutex.h b/tools/lib/lockdep/include/liblockdep/mutex.h new file mode 100644 index 000000000000..c342f7087147 --- /dev/null +++ b/tools/lib/lockdep/include/liblockdep/mutex.h | |||
@@ -0,0 +1,70 @@ | |||
1 | #ifndef _LIBLOCKDEP_MUTEX_H | ||
2 | #define _LIBLOCKDEP_MUTEX_H | ||
3 | |||
4 | #include <pthread.h> | ||
5 | #include "common.h" | ||
6 | |||
7 | struct liblockdep_pthread_mutex { | ||
8 | pthread_mutex_t mutex; | ||
9 | struct lockdep_map dep_map; | ||
10 | }; | ||
11 | |||
12 | typedef struct liblockdep_pthread_mutex liblockdep_pthread_mutex_t; | ||
13 | |||
14 | #define LIBLOCKDEP_PTHREAD_MUTEX_INITIALIZER(mtx) \ | ||
15 | (const struct liblockdep_pthread_mutex) { \ | ||
16 | .mutex = PTHREAD_MUTEX_INITIALIZER, \ | ||
17 | .dep_map = STATIC_LOCKDEP_MAP_INIT(#mtx, &((&(mtx))->dep_map)), \ | ||
18 | } | ||
19 | |||
20 | static inline int __mutex_init(liblockdep_pthread_mutex_t *lock, | ||
21 | const char *name, | ||
22 | struct lock_class_key *key, | ||
23 | const pthread_mutexattr_t *__mutexattr) | ||
24 | { | ||
25 | lockdep_init_map(&lock->dep_map, name, key, 0); | ||
26 | return pthread_mutex_init(&lock->mutex, __mutexattr); | ||
27 | } | ||
28 | |||
29 | #define liblockdep_pthread_mutex_init(mutex, mutexattr) \ | ||
30 | ({ \ | ||
31 | static struct lock_class_key __key; \ | ||
32 | \ | ||
33 | __mutex_init((mutex), #mutex, &__key, (mutexattr)); \ | ||
34 | }) | ||
35 | |||
36 | static inline int liblockdep_pthread_mutex_lock(liblockdep_pthread_mutex_t *lock) | ||
37 | { | ||
38 | lock_acquire(&lock->dep_map, 0, 0, 0, 2, NULL, (unsigned long)_RET_IP_); | ||
39 | return pthread_mutex_lock(&lock->mutex); | ||
40 | } | ||
41 | |||
42 | static inline int liblockdep_pthread_mutex_unlock(liblockdep_pthread_mutex_t *lock) | ||
43 | { | ||
44 | lock_release(&lock->dep_map, 0, (unsigned long)_RET_IP_); | ||
45 | return pthread_mutex_unlock(&lock->mutex); | ||
46 | } | ||
47 | |||
48 | static inline int liblockdep_pthread_mutex_trylock(liblockdep_pthread_mutex_t *lock) | ||
49 | { | ||
50 | lock_acquire(&lock->dep_map, 0, 1, 0, 2, NULL, (unsigned long)_RET_IP_); | ||
51 | return pthread_mutex_trylock(&lock->mutex) == 0 ? 1 : 0; | ||
52 | } | ||
53 | |||
54 | static inline int liblockdep_pthread_mutex_destroy(liblockdep_pthread_mutex_t *lock) | ||
55 | { | ||
56 | return pthread_mutex_destroy(&lock->mutex); | ||
57 | } | ||
58 | |||
59 | #ifdef __USE_LIBLOCKDEP | ||
60 | |||
61 | #define pthread_mutex_t liblockdep_pthread_mutex_t | ||
62 | #define pthread_mutex_init liblockdep_pthread_mutex_init | ||
63 | #define pthread_mutex_lock liblockdep_pthread_mutex_lock | ||
64 | #define pthread_mutex_unlock liblockdep_pthread_mutex_unlock | ||
65 | #define pthread_mutex_trylock liblockdep_pthread_mutex_trylock | ||
66 | #define pthread_mutex_destroy liblockdep_pthread_mutex_destroy | ||
67 | |||
68 | #endif | ||
69 | |||
70 | #endif | ||
diff --git a/tools/lib/lockdep/include/liblockdep/rwlock.h b/tools/lib/lockdep/include/liblockdep/rwlock.h new file mode 100644 index 000000000000..a680ab8c2e36 --- /dev/null +++ b/tools/lib/lockdep/include/liblockdep/rwlock.h | |||
@@ -0,0 +1,86 @@ | |||
1 | #ifndef _LIBLOCKDEP_RWLOCK_H | ||
2 | #define _LIBLOCKDEP_RWLOCK_H | ||
3 | |||
4 | #include <pthread.h> | ||
5 | #include "common.h" | ||
6 | |||
7 | struct liblockdep_pthread_rwlock { | ||
8 | pthread_rwlock_t rwlock; | ||
9 | struct lockdep_map dep_map; | ||
10 | }; | ||
11 | |||
12 | typedef struct liblockdep_pthread_rwlock liblockdep_pthread_rwlock_t; | ||
13 | |||
14 | #define LIBLOCKDEP_PTHREAD_RWLOCK_INITIALIZER(rwl) \ | ||
15 | (struct liblockdep_pthread_rwlock) { \ | ||
16 | .rwlock = PTHREAD_RWLOCK_INITIALIZER, \ | ||
17 | .dep_map = STATIC_LOCKDEP_MAP_INIT(#rwl, &((&(rwl))->dep_map)), \ | ||
18 | } | ||
19 | |||
20 | static inline int __rwlock_init(liblockdep_pthread_rwlock_t *lock, | ||
21 | const char *name, | ||
22 | struct lock_class_key *key, | ||
23 | const pthread_rwlockattr_t *attr) | ||
24 | { | ||
25 | lockdep_init_map(&lock->dep_map, name, key, 0); | ||
26 | |||
27 | return pthread_rwlock_init(&lock->rwlock, attr); | ||
28 | } | ||
29 | |||
30 | #define liblockdep_pthread_rwlock_init(lock, attr) \ | ||
31 | ({ \ | ||
32 | static struct lock_class_key __key; \ | ||
33 | \ | ||
34 | __rwlock_init((lock), #lock, &__key, (attr)); \ | ||
35 | }) | ||
36 | |||
37 | static inline int liblockdep_pthread_rwlock_rdlock(liblockdep_pthread_rwlock_t *lock) | ||
38 | { | ||
39 | lock_acquire(&lock->dep_map, 0, 0, 2, 2, NULL, (unsigned long)_RET_IP_); | ||
40 | return pthread_rwlock_rdlock(&lock->rwlock); | ||
41 | |||
42 | } | ||
43 | |||
44 | static inline int liblockdep_pthread_rwlock_unlock(liblockdep_pthread_rwlock_t *lock) | ||
45 | { | ||
46 | lock_release(&lock->dep_map, 0, (unsigned long)_RET_IP_); | ||
47 | return pthread_rwlock_unlock(&lock->rwlock); | ||
48 | } | ||
49 | |||
50 | static inline int liblockdep_pthread_rwlock_wrlock(liblockdep_pthread_rwlock_t *lock) | ||
51 | { | ||
52 | lock_acquire(&lock->dep_map, 0, 0, 0, 2, NULL, (unsigned long)_RET_IP_); | ||
53 | return pthread_rwlock_wrlock(&lock->rwlock); | ||
54 | } | ||
55 | |||
56 | static inline int liblockdep_pthread_rwlock_tryrdlock(liblockdep_pthread_rwlock_t *lock) | ||
57 | { | ||
58 | lock_acquire(&lock->dep_map, 0, 1, 2, 2, NULL, (unsigned long)_RET_IP_); | ||
59 | return pthread_rwlock_tryrdlock(&lock->rwlock) == 0 ? 1 : 0; | ||
60 | } | ||
61 | |||
62 | static inline int liblockdep_pthread_rwlock_trywlock(liblockdep_pthread_rwlock_t *lock) | ||
63 | { | ||
64 | lock_acquire(&lock->dep_map, 0, 1, 0, 2, NULL, (unsigned long)_RET_IP_); | ||
65 | return pthread_rwlock_trywlock(&lock->rwlock) == 0 ? 1 : 0; | ||
66 | } | ||
67 | |||
68 | static inline int liblockdep_rwlock_destroy(liblockdep_pthread_rwlock_t *lock) | ||
69 | { | ||
70 | return pthread_rwlock_destroy(&lock->rwlock); | ||
71 | } | ||
72 | |||
73 | #ifdef __USE_LIBLOCKDEP | ||
74 | |||
75 | #define pthread_rwlock_t liblockdep_pthread_rwlock_t | ||
76 | #define pthread_rwlock_init liblockdep_pthread_rwlock_init | ||
77 | #define pthread_rwlock_rdlock liblockdep_pthread_rwlock_rdlock | ||
78 | #define pthread_rwlock_unlock liblockdep_pthread_rwlock_unlock | ||
79 | #define pthread_rwlock_wrlock liblockdep_pthread_rwlock_wrlock | ||
80 | #define pthread_rwlock_tryrdlock liblockdep_pthread_rwlock_tryrdlock | ||
81 | #define pthread_rwlock_trywlock liblockdep_pthread_rwlock_trywlock | ||
82 | #define pthread_rwlock_destroy liblockdep_rwlock_destroy | ||
83 | |||
84 | #endif | ||
85 | |||
86 | #endif | ||
diff --git a/tools/lib/lockdep/lockdep b/tools/lib/lockdep/lockdep new file mode 100755 index 000000000000..49af9fe19f5b --- /dev/null +++ b/tools/lib/lockdep/lockdep | |||
@@ -0,0 +1,3 @@ | |||
1 | #!/bin/bash | ||
2 | |||
3 | LD_PRELOAD="./liblockdep.so $LD_PRELOAD" "$@" | ||
diff --git a/tools/lib/lockdep/lockdep.c b/tools/lib/lockdep/lockdep.c new file mode 100644 index 000000000000..f42b7e9aa48f --- /dev/null +++ b/tools/lib/lockdep/lockdep.c | |||
@@ -0,0 +1,2 @@ | |||
1 | #include <linux/lockdep.h> | ||
2 | #include "../../../kernel/locking/lockdep.c" | ||
diff --git a/tools/lib/lockdep/lockdep_internals.h b/tools/lib/lockdep/lockdep_internals.h new file mode 100644 index 000000000000..29d0c954cc24 --- /dev/null +++ b/tools/lib/lockdep/lockdep_internals.h | |||
@@ -0,0 +1 @@ | |||
#include "../../../kernel/locking/lockdep_internals.h" | |||
diff --git a/tools/lib/lockdep/lockdep_states.h b/tools/lib/lockdep/lockdep_states.h new file mode 100644 index 000000000000..248d235efda9 --- /dev/null +++ b/tools/lib/lockdep/lockdep_states.h | |||
@@ -0,0 +1 @@ | |||
#include "../../../kernel/locking/lockdep_states.h" | |||
diff --git a/tools/lib/lockdep/preload.c b/tools/lib/lockdep/preload.c new file mode 100644 index 000000000000..23bd69cb5ade --- /dev/null +++ b/tools/lib/lockdep/preload.c | |||
@@ -0,0 +1,447 @@ | |||
1 | #define _GNU_SOURCE | ||
2 | #include <pthread.h> | ||
3 | #include <stdio.h> | ||
4 | #include <dlfcn.h> | ||
5 | #include <stdlib.h> | ||
6 | #include <sysexits.h> | ||
7 | #include "include/liblockdep/mutex.h" | ||
8 | #include "../../../include/linux/rbtree.h" | ||
9 | |||
10 | /** | ||
11 | * struct lock_lookup - liblockdep's view of a single unique lock | ||
12 | * @orig: pointer to the original pthread lock, used for lookups | ||
13 | * @dep_map: lockdep's dep_map structure | ||
14 | * @key: lockdep's key structure | ||
15 | * @node: rb-tree node used to store the lock in a global tree | ||
16 | * @name: a unique name for the lock | ||
17 | */ | ||
18 | struct lock_lookup { | ||
19 | void *orig; /* Original pthread lock, used for lookups */ | ||
20 | struct lockdep_map dep_map; /* Since all locks are dynamic, we need | ||
21 | * a dep_map and a key for each lock */ | ||
22 | /* | ||
23 | * Wait, there's no support for key classes? Yup :( | ||
24 | * Most big projects wrap the pthread api with their own calls to | ||
25 | * be compatible with different locking methods. This means that | ||
26 | * "classes" will be brokes since the function that creates all | ||
27 | * locks will point to a generic locking function instead of the | ||
28 | * actual code that wants to do the locking. | ||
29 | */ | ||
30 | struct lock_class_key key; | ||
31 | struct rb_node node; | ||
32 | #define LIBLOCKDEP_MAX_LOCK_NAME 22 | ||
33 | char name[LIBLOCKDEP_MAX_LOCK_NAME]; | ||
34 | }; | ||
35 | |||
36 | /* This is where we store our locks */ | ||
37 | static struct rb_root locks = RB_ROOT; | ||
38 | static pthread_rwlock_t locks_rwlock = PTHREAD_RWLOCK_INITIALIZER; | ||
39 | |||
40 | /* pthread mutex API */ | ||
41 | |||
42 | #ifdef __GLIBC__ | ||
43 | extern int __pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *attr); | ||
44 | extern int __pthread_mutex_lock(pthread_mutex_t *mutex); | ||
45 | extern int __pthread_mutex_trylock(pthread_mutex_t *mutex); | ||
46 | extern int __pthread_mutex_unlock(pthread_mutex_t *mutex); | ||
47 | extern int __pthread_mutex_destroy(pthread_mutex_t *mutex); | ||
48 | #else | ||
49 | #define __pthread_mutex_init NULL | ||
50 | #define __pthread_mutex_lock NULL | ||
51 | #define __pthread_mutex_trylock NULL | ||
52 | #define __pthread_mutex_unlock NULL | ||
53 | #define __pthread_mutex_destroy NULL | ||
54 | #endif | ||
55 | static int (*ll_pthread_mutex_init)(pthread_mutex_t *mutex, | ||
56 | const pthread_mutexattr_t *attr) = __pthread_mutex_init; | ||
57 | static int (*ll_pthread_mutex_lock)(pthread_mutex_t *mutex) = __pthread_mutex_lock; | ||
58 | static int (*ll_pthread_mutex_trylock)(pthread_mutex_t *mutex) = __pthread_mutex_trylock; | ||
59 | static int (*ll_pthread_mutex_unlock)(pthread_mutex_t *mutex) = __pthread_mutex_unlock; | ||
60 | static int (*ll_pthread_mutex_destroy)(pthread_mutex_t *mutex) = __pthread_mutex_destroy; | ||
61 | |||
62 | /* pthread rwlock API */ | ||
63 | |||
64 | #ifdef __GLIBC__ | ||
65 | extern int __pthread_rwlock_init(pthread_rwlock_t *rwlock, const pthread_rwlockattr_t *attr); | ||
66 | extern int __pthread_rwlock_destroy(pthread_rwlock_t *rwlock); | ||
67 | extern int __pthread_rwlock_wrlock(pthread_rwlock_t *rwlock); | ||
68 | extern int __pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock); | ||
69 | extern int __pthread_rwlock_rdlock(pthread_rwlock_t *rwlock); | ||
70 | extern int __pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock); | ||
71 | extern int __pthread_rwlock_unlock(pthread_rwlock_t *rwlock); | ||
72 | #else | ||
73 | #define __pthread_rwlock_init NULL | ||
74 | #define __pthread_rwlock_destroy NULL | ||
75 | #define __pthread_rwlock_wrlock NULL | ||
76 | #define __pthread_rwlock_trywrlock NULL | ||
77 | #define __pthread_rwlock_rdlock NULL | ||
78 | #define __pthread_rwlock_tryrdlock NULL | ||
79 | #define __pthread_rwlock_unlock NULL | ||
80 | #endif | ||
81 | |||
82 | static int (*ll_pthread_rwlock_init)(pthread_rwlock_t *rwlock, | ||
83 | const pthread_rwlockattr_t *attr) = __pthread_rwlock_init; | ||
84 | static int (*ll_pthread_rwlock_destroy)(pthread_rwlock_t *rwlock) = __pthread_rwlock_destroy; | ||
85 | static int (*ll_pthread_rwlock_rdlock)(pthread_rwlock_t *rwlock) = __pthread_rwlock_rdlock; | ||
86 | static int (*ll_pthread_rwlock_tryrdlock)(pthread_rwlock_t *rwlock) = __pthread_rwlock_tryrdlock; | ||
87 | static int (*ll_pthread_rwlock_trywrlock)(pthread_rwlock_t *rwlock) = __pthread_rwlock_trywrlock; | ||
88 | static int (*ll_pthread_rwlock_wrlock)(pthread_rwlock_t *rwlock) = __pthread_rwlock_wrlock; | ||
89 | static int (*ll_pthread_rwlock_unlock)(pthread_rwlock_t *rwlock) = __pthread_rwlock_unlock; | ||
90 | |||
91 | enum { none, prepare, done, } __init_state; | ||
92 | static void init_preload(void); | ||
93 | static void try_init_preload(void) | ||
94 | { | ||
95 | if (!__init_state != done) | ||
96 | init_preload(); | ||
97 | } | ||
98 | |||
99 | static struct rb_node **__get_lock_node(void *lock, struct rb_node **parent) | ||
100 | { | ||
101 | struct rb_node **node = &locks.rb_node; | ||
102 | struct lock_lookup *l; | ||
103 | |||
104 | *parent = NULL; | ||
105 | |||
106 | while (*node) { | ||
107 | l = rb_entry(*node, struct lock_lookup, node); | ||
108 | |||
109 | *parent = *node; | ||
110 | if (lock < l->orig) | ||
111 | node = &l->node.rb_left; | ||
112 | else if (lock > l->orig) | ||
113 | node = &l->node.rb_right; | ||
114 | else | ||
115 | return node; | ||
116 | } | ||
117 | |||
118 | return node; | ||
119 | } | ||
120 | |||
121 | #ifndef LIBLOCKDEP_STATIC_ENTRIES | ||
122 | #define LIBLOCKDEP_STATIC_ENTRIES 1024 | ||
123 | #endif | ||
124 | |||
125 | #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) | ||
126 | |||
127 | static struct lock_lookup __locks[LIBLOCKDEP_STATIC_ENTRIES]; | ||
128 | static int __locks_nr; | ||
129 | |||
130 | static inline bool is_static_lock(struct lock_lookup *lock) | ||
131 | { | ||
132 | return lock >= __locks && lock < __locks + ARRAY_SIZE(__locks); | ||
133 | } | ||
134 | |||
135 | static struct lock_lookup *alloc_lock(void) | ||
136 | { | ||
137 | if (__init_state != done) { | ||
138 | /* | ||
139 | * Some programs attempt to initialize and use locks in their | ||
140 | * allocation path. This means that a call to malloc() would | ||
141 | * result in locks being initialized and locked. | ||
142 | * | ||
143 | * Why is it an issue for us? dlsym() below will try allocating | ||
144 | * to give us the original function. Since this allocation will | ||
145 | * result in a locking operations, we have to let pthread deal | ||
146 | * with it, but we can't! we don't have the pointer to the | ||
147 | * original API since we're inside dlsym() trying to get it | ||
148 | */ | ||
149 | |||
150 | int idx = __locks_nr++; | ||
151 | if (idx >= ARRAY_SIZE(__locks)) { | ||
152 | fprintf(stderr, | ||
153 | "LOCKDEP error: insufficient LIBLOCKDEP_STATIC_ENTRIES\n"); | ||
154 | exit(EX_UNAVAILABLE); | ||
155 | } | ||
156 | return __locks + idx; | ||
157 | } | ||
158 | |||
159 | return malloc(sizeof(struct lock_lookup)); | ||
160 | } | ||
161 | |||
162 | static inline void free_lock(struct lock_lookup *lock) | ||
163 | { | ||
164 | if (likely(!is_static_lock(lock))) | ||
165 | free(lock); | ||
166 | } | ||
167 | |||
168 | /** | ||
169 | * __get_lock - find or create a lock instance | ||
170 | * @lock: pointer to a pthread lock function | ||
171 | * | ||
172 | * Try to find an existing lock in the rbtree using the provided pointer. If | ||
173 | * one wasn't found - create it. | ||
174 | */ | ||
175 | static struct lock_lookup *__get_lock(void *lock) | ||
176 | { | ||
177 | struct rb_node **node, *parent; | ||
178 | struct lock_lookup *l; | ||
179 | |||
180 | ll_pthread_rwlock_rdlock(&locks_rwlock); | ||
181 | node = __get_lock_node(lock, &parent); | ||
182 | ll_pthread_rwlock_unlock(&locks_rwlock); | ||
183 | if (*node) { | ||
184 | return rb_entry(*node, struct lock_lookup, node); | ||
185 | } | ||
186 | |||
187 | /* We didn't find the lock, let's create it */ | ||
188 | l = alloc_lock(); | ||
189 | if (l == NULL) | ||
190 | return NULL; | ||
191 | |||
192 | l->orig = lock; | ||
193 | /* | ||
194 | * Currently the name of the lock is the ptr value of the pthread lock, | ||
195 | * while not optimal, it makes debugging a bit easier. | ||
196 | * | ||
197 | * TODO: Get the real name of the lock using libdwarf | ||
198 | */ | ||
199 | sprintf(l->name, "%p", lock); | ||
200 | lockdep_init_map(&l->dep_map, l->name, &l->key, 0); | ||
201 | |||
202 | ll_pthread_rwlock_wrlock(&locks_rwlock); | ||
203 | /* This might have changed since the last time we fetched it */ | ||
204 | node = __get_lock_node(lock, &parent); | ||
205 | rb_link_node(&l->node, parent, node); | ||
206 | rb_insert_color(&l->node, &locks); | ||
207 | ll_pthread_rwlock_unlock(&locks_rwlock); | ||
208 | |||
209 | return l; | ||
210 | } | ||
211 | |||
212 | static void __del_lock(struct lock_lookup *lock) | ||
213 | { | ||
214 | ll_pthread_rwlock_wrlock(&locks_rwlock); | ||
215 | rb_erase(&lock->node, &locks); | ||
216 | ll_pthread_rwlock_unlock(&locks_rwlock); | ||
217 | free_lock(lock); | ||
218 | } | ||
219 | |||
220 | int pthread_mutex_init(pthread_mutex_t *mutex, | ||
221 | const pthread_mutexattr_t *attr) | ||
222 | { | ||
223 | int r; | ||
224 | |||
225 | /* | ||
226 | * We keep trying to init our preload module because there might be | ||
227 | * code in init sections that tries to touch locks before we are | ||
228 | * initialized, in that case we'll need to manually call preload | ||
229 | * to get us going. | ||
230 | * | ||
231 | * Funny enough, kernel's lockdep had the same issue, and used | ||
232 | * (almost) the same solution. See look_up_lock_class() in | ||
233 | * kernel/locking/lockdep.c for details. | ||
234 | */ | ||
235 | try_init_preload(); | ||
236 | |||
237 | r = ll_pthread_mutex_init(mutex, attr); | ||
238 | if (r == 0) | ||
239 | /* | ||
240 | * We do a dummy initialization here so that lockdep could | ||
241 | * warn us if something fishy is going on - such as | ||
242 | * initializing a held lock. | ||
243 | */ | ||
244 | __get_lock(mutex); | ||
245 | |||
246 | return r; | ||
247 | } | ||
248 | |||
249 | int pthread_mutex_lock(pthread_mutex_t *mutex) | ||
250 | { | ||
251 | int r; | ||
252 | |||
253 | try_init_preload(); | ||
254 | |||
255 | lock_acquire(&__get_lock(mutex)->dep_map, 0, 0, 0, 2, NULL, | ||
256 | (unsigned long)_RET_IP_); | ||
257 | /* | ||
258 | * Here's the thing with pthread mutexes: unlike the kernel variant, | ||
259 | * they can fail. | ||
260 | * | ||
261 | * This means that the behaviour here is a bit different from what's | ||
262 | * going on in the kernel: there we just tell lockdep that we took the | ||
263 | * lock before actually taking it, but here we must deal with the case | ||
264 | * that locking failed. | ||
265 | * | ||
266 | * To do that we'll "release" the lock if locking failed - this way | ||
267 | * we'll get lockdep doing the correct checks when we try to take | ||
268 | * the lock, and if that fails - we'll be back to the correct | ||
269 | * state by releasing it. | ||
270 | */ | ||
271 | r = ll_pthread_mutex_lock(mutex); | ||
272 | if (r) | ||
273 | lock_release(&__get_lock(mutex)->dep_map, 0, (unsigned long)_RET_IP_); | ||
274 | |||
275 | return r; | ||
276 | } | ||
277 | |||
278 | int pthread_mutex_trylock(pthread_mutex_t *mutex) | ||
279 | { | ||
280 | int r; | ||
281 | |||
282 | try_init_preload(); | ||
283 | |||
284 | lock_acquire(&__get_lock(mutex)->dep_map, 0, 1, 0, 2, NULL, (unsigned long)_RET_IP_); | ||
285 | r = ll_pthread_mutex_trylock(mutex); | ||
286 | if (r) | ||
287 | lock_release(&__get_lock(mutex)->dep_map, 0, (unsigned long)_RET_IP_); | ||
288 | |||
289 | return r; | ||
290 | } | ||
291 | |||
292 | int pthread_mutex_unlock(pthread_mutex_t *mutex) | ||
293 | { | ||
294 | int r; | ||
295 | |||
296 | try_init_preload(); | ||
297 | |||
298 | lock_release(&__get_lock(mutex)->dep_map, 0, (unsigned long)_RET_IP_); | ||
299 | /* | ||
300 | * Just like taking a lock, only in reverse! | ||
301 | * | ||
302 | * If we fail releasing the lock, tell lockdep we're holding it again. | ||
303 | */ | ||
304 | r = ll_pthread_mutex_unlock(mutex); | ||
305 | if (r) | ||
306 | lock_acquire(&__get_lock(mutex)->dep_map, 0, 0, 0, 2, NULL, (unsigned long)_RET_IP_); | ||
307 | |||
308 | return r; | ||
309 | } | ||
310 | |||
311 | int pthread_mutex_destroy(pthread_mutex_t *mutex) | ||
312 | { | ||
313 | try_init_preload(); | ||
314 | |||
315 | /* | ||
316 | * Let's see if we're releasing a lock that's held. | ||
317 | * | ||
318 | * TODO: Hook into free() and add that check there as well. | ||
319 | */ | ||
320 | debug_check_no_locks_freed(mutex, mutex + sizeof(*mutex)); | ||
321 | __del_lock(__get_lock(mutex)); | ||
322 | return ll_pthread_mutex_destroy(mutex); | ||
323 | } | ||
324 | |||
325 | /* This is the rwlock part, very similar to what happened with mutex above */ | ||
326 | int pthread_rwlock_init(pthread_rwlock_t *rwlock, | ||
327 | const pthread_rwlockattr_t *attr) | ||
328 | { | ||
329 | int r; | ||
330 | |||
331 | try_init_preload(); | ||
332 | |||
333 | r = ll_pthread_rwlock_init(rwlock, attr); | ||
334 | if (r == 0) | ||
335 | __get_lock(rwlock); | ||
336 | |||
337 | return r; | ||
338 | } | ||
339 | |||
340 | int pthread_rwlock_destroy(pthread_rwlock_t *rwlock) | ||
341 | { | ||
342 | try_init_preload(); | ||
343 | |||
344 | debug_check_no_locks_freed(rwlock, rwlock + sizeof(*rwlock)); | ||
345 | __del_lock(__get_lock(rwlock)); | ||
346 | return ll_pthread_rwlock_destroy(rwlock); | ||
347 | } | ||
348 | |||
349 | int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock) | ||
350 | { | ||
351 | int r; | ||
352 | |||
353 | init_preload(); | ||
354 | |||
355 | lock_acquire(&__get_lock(rwlock)->dep_map, 0, 0, 2, 2, NULL, (unsigned long)_RET_IP_); | ||
356 | r = ll_pthread_rwlock_rdlock(rwlock); | ||
357 | if (r) | ||
358 | lock_release(&__get_lock(rwlock)->dep_map, 0, (unsigned long)_RET_IP_); | ||
359 | |||
360 | return r; | ||
361 | } | ||
362 | |||
363 | int pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock) | ||
364 | { | ||
365 | int r; | ||
366 | |||
367 | init_preload(); | ||
368 | |||
369 | lock_acquire(&__get_lock(rwlock)->dep_map, 0, 1, 2, 2, NULL, (unsigned long)_RET_IP_); | ||
370 | r = ll_pthread_rwlock_tryrdlock(rwlock); | ||
371 | if (r) | ||
372 | lock_release(&__get_lock(rwlock)->dep_map, 0, (unsigned long)_RET_IP_); | ||
373 | |||
374 | return r; | ||
375 | } | ||
376 | |||
377 | int pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock) | ||
378 | { | ||
379 | int r; | ||
380 | |||
381 | init_preload(); | ||
382 | |||
383 | lock_acquire(&__get_lock(rwlock)->dep_map, 0, 1, 0, 2, NULL, (unsigned long)_RET_IP_); | ||
384 | r = ll_pthread_rwlock_trywrlock(rwlock); | ||
385 | if (r) | ||
386 | lock_release(&__get_lock(rwlock)->dep_map, 0, (unsigned long)_RET_IP_); | ||
387 | |||
388 | return r; | ||
389 | } | ||
390 | |||
391 | int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock) | ||
392 | { | ||
393 | int r; | ||
394 | |||
395 | init_preload(); | ||
396 | |||
397 | lock_acquire(&__get_lock(rwlock)->dep_map, 0, 0, 0, 2, NULL, (unsigned long)_RET_IP_); | ||
398 | r = ll_pthread_rwlock_wrlock(rwlock); | ||
399 | if (r) | ||
400 | lock_release(&__get_lock(rwlock)->dep_map, 0, (unsigned long)_RET_IP_); | ||
401 | |||
402 | return r; | ||
403 | } | ||
404 | |||
405 | int pthread_rwlock_unlock(pthread_rwlock_t *rwlock) | ||
406 | { | ||
407 | int r; | ||
408 | |||
409 | init_preload(); | ||
410 | |||
411 | lock_release(&__get_lock(rwlock)->dep_map, 0, (unsigned long)_RET_IP_); | ||
412 | r = ll_pthread_rwlock_unlock(rwlock); | ||
413 | if (r) | ||
414 | lock_acquire(&__get_lock(rwlock)->dep_map, 0, 0, 0, 2, NULL, (unsigned long)_RET_IP_); | ||
415 | |||
416 | return r; | ||
417 | } | ||
418 | |||
419 | __attribute__((constructor)) static void init_preload(void) | ||
420 | { | ||
421 | if (__init_state == done) | ||
422 | return; | ||
423 | |||
424 | #ifndef __GLIBC__ | ||
425 | __init_state = prepare; | ||
426 | |||
427 | ll_pthread_mutex_init = dlsym(RTLD_NEXT, "pthread_mutex_init"); | ||
428 | ll_pthread_mutex_lock = dlsym(RTLD_NEXT, "pthread_mutex_lock"); | ||
429 | ll_pthread_mutex_trylock = dlsym(RTLD_NEXT, "pthread_mutex_trylock"); | ||
430 | ll_pthread_mutex_unlock = dlsym(RTLD_NEXT, "pthread_mutex_unlock"); | ||
431 | ll_pthread_mutex_destroy = dlsym(RTLD_NEXT, "pthread_mutex_destroy"); | ||
432 | |||
433 | ll_pthread_rwlock_init = dlsym(RTLD_NEXT, "pthread_rwlock_init"); | ||
434 | ll_pthread_rwlock_destroy = dlsym(RTLD_NEXT, "pthread_rwlock_destroy"); | ||
435 | ll_pthread_rwlock_rdlock = dlsym(RTLD_NEXT, "pthread_rwlock_rdlock"); | ||
436 | ll_pthread_rwlock_tryrdlock = dlsym(RTLD_NEXT, "pthread_rwlock_tryrdlock"); | ||
437 | ll_pthread_rwlock_wrlock = dlsym(RTLD_NEXT, "pthread_rwlock_wrlock"); | ||
438 | ll_pthread_rwlock_trywrlock = dlsym(RTLD_NEXT, "pthread_rwlock_trywrlock"); | ||
439 | ll_pthread_rwlock_unlock = dlsym(RTLD_NEXT, "pthread_rwlock_unlock"); | ||
440 | #endif | ||
441 | |||
442 | printf("%p\n", ll_pthread_mutex_trylock);fflush(stdout); | ||
443 | |||
444 | lockdep_init(); | ||
445 | |||
446 | __init_state = done; | ||
447 | } | ||
diff --git a/tools/lib/lockdep/rbtree.c b/tools/lib/lockdep/rbtree.c new file mode 100644 index 000000000000..f7f43033c8b7 --- /dev/null +++ b/tools/lib/lockdep/rbtree.c | |||
@@ -0,0 +1 @@ | |||
#include "../../../lib/rbtree.c" | |||
diff --git a/tools/lib/lockdep/run_tests.sh b/tools/lib/lockdep/run_tests.sh new file mode 100755 index 000000000000..5334ad9d39b7 --- /dev/null +++ b/tools/lib/lockdep/run_tests.sh | |||
@@ -0,0 +1,27 @@ | |||
1 | #! /bin/bash | ||
2 | |||
3 | make &> /dev/null | ||
4 | |||
5 | for i in `ls tests/*.c`; do | ||
6 | testname=$(basename -s .c "$i") | ||
7 | gcc -o tests/$testname -pthread -lpthread $i liblockdep.a -Iinclude -D__USE_LIBLOCKDEP &> /dev/null | ||
8 | echo -ne "$testname... " | ||
9 | if [ $(timeout 1 ./tests/$testname | wc -l) -gt 0 ]; then | ||
10 | echo "PASSED!" | ||
11 | else | ||
12 | echo "FAILED!" | ||
13 | fi | ||
14 | rm tests/$testname | ||
15 | done | ||
16 | |||
17 | for i in `ls tests/*.c`; do | ||
18 | testname=$(basename -s .c "$i") | ||
19 | gcc -o tests/$testname -pthread -lpthread -Iinclude $i &> /dev/null | ||
20 | echo -ne "(PRELOAD) $testname... " | ||
21 | if [ $(timeout 1 ./lockdep ./tests/$testname | wc -l) -gt 0 ]; then | ||
22 | echo "PASSED!" | ||
23 | else | ||
24 | echo "FAILED!" | ||
25 | fi | ||
26 | rm tests/$testname | ||
27 | done | ||
diff --git a/tools/lib/lockdep/tests/AA.c b/tools/lib/lockdep/tests/AA.c new file mode 100644 index 000000000000..0f782ff404ac --- /dev/null +++ b/tools/lib/lockdep/tests/AA.c | |||
@@ -0,0 +1,13 @@ | |||
1 | #include <liblockdep/mutex.h> | ||
2 | |||
3 | void main(void) | ||
4 | { | ||
5 | pthread_mutex_t a, b; | ||
6 | |||
7 | pthread_mutex_init(&a, NULL); | ||
8 | pthread_mutex_init(&b, NULL); | ||
9 | |||
10 | pthread_mutex_lock(&a); | ||
11 | pthread_mutex_lock(&b); | ||
12 | pthread_mutex_lock(&a); | ||
13 | } | ||
diff --git a/tools/lib/lockdep/tests/ABBA.c b/tools/lib/lockdep/tests/ABBA.c new file mode 100644 index 000000000000..07f0e29d5485 --- /dev/null +++ b/tools/lib/lockdep/tests/ABBA.c | |||
@@ -0,0 +1,13 @@ | |||
1 | #include <liblockdep/mutex.h> | ||
2 | #include "common.h" | ||
3 | |||
4 | void main(void) | ||
5 | { | ||
6 | pthread_mutex_t a, b; | ||
7 | |||
8 | pthread_mutex_init(&a, NULL); | ||
9 | pthread_mutex_init(&b, NULL); | ||
10 | |||
11 | LOCK_UNLOCK_2(a, b); | ||
12 | LOCK_UNLOCK_2(b, a); | ||
13 | } | ||
diff --git a/tools/lib/lockdep/tests/ABBCCA.c b/tools/lib/lockdep/tests/ABBCCA.c new file mode 100644 index 000000000000..843db09ac666 --- /dev/null +++ b/tools/lib/lockdep/tests/ABBCCA.c | |||
@@ -0,0 +1,15 @@ | |||
1 | #include <liblockdep/mutex.h> | ||
2 | #include "common.h" | ||
3 | |||
4 | void main(void) | ||
5 | { | ||
6 | pthread_mutex_t a, b, c; | ||
7 | |||
8 | pthread_mutex_init(&a, NULL); | ||
9 | pthread_mutex_init(&b, NULL); | ||
10 | pthread_mutex_init(&c, NULL); | ||
11 | |||
12 | LOCK_UNLOCK_2(a, b); | ||
13 | LOCK_UNLOCK_2(b, c); | ||
14 | LOCK_UNLOCK_2(c, a); | ||
15 | } | ||
diff --git a/tools/lib/lockdep/tests/ABBCCDDA.c b/tools/lib/lockdep/tests/ABBCCDDA.c new file mode 100644 index 000000000000..33620e268f85 --- /dev/null +++ b/tools/lib/lockdep/tests/ABBCCDDA.c | |||
@@ -0,0 +1,17 @@ | |||
1 | #include <liblockdep/mutex.h> | ||
2 | #include "common.h" | ||
3 | |||
4 | void main(void) | ||
5 | { | ||
6 | pthread_mutex_t a, b, c, d; | ||
7 | |||
8 | pthread_mutex_init(&a, NULL); | ||
9 | pthread_mutex_init(&b, NULL); | ||
10 | pthread_mutex_init(&c, NULL); | ||
11 | pthread_mutex_init(&d, NULL); | ||
12 | |||
13 | LOCK_UNLOCK_2(a, b); | ||
14 | LOCK_UNLOCK_2(b, c); | ||
15 | LOCK_UNLOCK_2(c, d); | ||
16 | LOCK_UNLOCK_2(d, a); | ||
17 | } | ||
diff --git a/tools/lib/lockdep/tests/ABCABC.c b/tools/lib/lockdep/tests/ABCABC.c new file mode 100644 index 000000000000..3fee51e3a68a --- /dev/null +++ b/tools/lib/lockdep/tests/ABCABC.c | |||
@@ -0,0 +1,15 @@ | |||
1 | #include <liblockdep/mutex.h> | ||
2 | #include "common.h" | ||
3 | |||
4 | void main(void) | ||
5 | { | ||
6 | pthread_mutex_t a, b, c; | ||
7 | |||
8 | pthread_mutex_init(&a, NULL); | ||
9 | pthread_mutex_init(&b, NULL); | ||
10 | pthread_mutex_init(&c, NULL); | ||
11 | |||
12 | LOCK_UNLOCK_2(a, b); | ||
13 | LOCK_UNLOCK_2(c, a); | ||
14 | LOCK_UNLOCK_2(b, c); | ||
15 | } | ||
diff --git a/tools/lib/lockdep/tests/ABCDBCDA.c b/tools/lib/lockdep/tests/ABCDBCDA.c new file mode 100644 index 000000000000..427ba562c75b --- /dev/null +++ b/tools/lib/lockdep/tests/ABCDBCDA.c | |||
@@ -0,0 +1,17 @@ | |||
1 | #include <liblockdep/mutex.h> | ||
2 | #include "common.h" | ||
3 | |||
4 | void main(void) | ||
5 | { | ||
6 | pthread_mutex_t a, b, c, d; | ||
7 | |||
8 | pthread_mutex_init(&a, NULL); | ||
9 | pthread_mutex_init(&b, NULL); | ||
10 | pthread_mutex_init(&c, NULL); | ||
11 | pthread_mutex_init(&d, NULL); | ||
12 | |||
13 | LOCK_UNLOCK_2(a, b); | ||
14 | LOCK_UNLOCK_2(c, d); | ||
15 | LOCK_UNLOCK_2(b, c); | ||
16 | LOCK_UNLOCK_2(d, a); | ||
17 | } | ||
diff --git a/tools/lib/lockdep/tests/ABCDBDDA.c b/tools/lib/lockdep/tests/ABCDBDDA.c new file mode 100644 index 000000000000..680c6cf3e919 --- /dev/null +++ b/tools/lib/lockdep/tests/ABCDBDDA.c | |||
@@ -0,0 +1,17 @@ | |||
1 | #include <liblockdep/mutex.h> | ||
2 | #include "common.h" | ||
3 | |||
4 | void main(void) | ||
5 | { | ||
6 | pthread_mutex_t a, b, c, d; | ||
7 | |||
8 | pthread_mutex_init(&a, NULL); | ||
9 | pthread_mutex_init(&b, NULL); | ||
10 | pthread_mutex_init(&c, NULL); | ||
11 | pthread_mutex_init(&d, NULL); | ||
12 | |||
13 | LOCK_UNLOCK_2(a, b); | ||
14 | LOCK_UNLOCK_2(c, d); | ||
15 | LOCK_UNLOCK_2(b, d); | ||
16 | LOCK_UNLOCK_2(d, a); | ||
17 | } | ||
diff --git a/tools/lib/lockdep/tests/WW.c b/tools/lib/lockdep/tests/WW.c new file mode 100644 index 000000000000..d44f77d71029 --- /dev/null +++ b/tools/lib/lockdep/tests/WW.c | |||
@@ -0,0 +1,13 @@ | |||
1 | #include <liblockdep/rwlock.h> | ||
2 | |||
3 | void main(void) | ||
4 | { | ||
5 | pthread_rwlock_t a, b; | ||
6 | |||
7 | pthread_rwlock_init(&a, NULL); | ||
8 | pthread_rwlock_init(&b, NULL); | ||
9 | |||
10 | pthread_rwlock_wrlock(&a); | ||
11 | pthread_rwlock_rdlock(&b); | ||
12 | pthread_rwlock_wrlock(&a); | ||
13 | } | ||
diff --git a/tools/lib/lockdep/tests/common.h b/tools/lib/lockdep/tests/common.h new file mode 100644 index 000000000000..d89e94d47d86 --- /dev/null +++ b/tools/lib/lockdep/tests/common.h | |||
@@ -0,0 +1,12 @@ | |||
1 | #ifndef _LIBLOCKDEP_TEST_COMMON_H | ||
2 | #define _LIBLOCKDEP_TEST_COMMON_H | ||
3 | |||
4 | #define LOCK_UNLOCK_2(a, b) \ | ||
5 | do { \ | ||
6 | pthread_mutex_lock(&(a)); \ | ||
7 | pthread_mutex_lock(&(b)); \ | ||
8 | pthread_mutex_unlock(&(b)); \ | ||
9 | pthread_mutex_unlock(&(a)); \ | ||
10 | } while(0) | ||
11 | |||
12 | #endif | ||
diff --git a/tools/lib/lockdep/tests/unlock_balance.c b/tools/lib/lockdep/tests/unlock_balance.c new file mode 100644 index 000000000000..0bc62de686f7 --- /dev/null +++ b/tools/lib/lockdep/tests/unlock_balance.c | |||
@@ -0,0 +1,12 @@ | |||
1 | #include <liblockdep/mutex.h> | ||
2 | |||
3 | void main(void) | ||
4 | { | ||
5 | pthread_mutex_t a; | ||
6 | |||
7 | pthread_mutex_init(&a, NULL); | ||
8 | |||
9 | pthread_mutex_lock(&a); | ||
10 | pthread_mutex_unlock(&a); | ||
11 | pthread_mutex_unlock(&a); | ||
12 | } | ||
diff --git a/tools/lib/lockdep/uinclude/asm/hash.h b/tools/lib/lockdep/uinclude/asm/hash.h new file mode 100644 index 000000000000..d82b170bb216 --- /dev/null +++ b/tools/lib/lockdep/uinclude/asm/hash.h | |||
@@ -0,0 +1,6 @@ | |||
1 | #ifndef __ASM_GENERIC_HASH_H | ||
2 | #define __ASM_GENERIC_HASH_H | ||
3 | |||
4 | /* Stub */ | ||
5 | |||
6 | #endif /* __ASM_GENERIC_HASH_H */ | ||
diff --git a/tools/lib/lockdep/uinclude/asm/hweight.h b/tools/lib/lockdep/uinclude/asm/hweight.h new file mode 100644 index 000000000000..fab00ff936d1 --- /dev/null +++ b/tools/lib/lockdep/uinclude/asm/hweight.h | |||
@@ -0,0 +1,3 @@ | |||
1 | |||
2 | /* empty file */ | ||
3 | |||
diff --git a/tools/lib/lockdep/uinclude/asm/sections.h b/tools/lib/lockdep/uinclude/asm/sections.h new file mode 100644 index 000000000000..fab00ff936d1 --- /dev/null +++ b/tools/lib/lockdep/uinclude/asm/sections.h | |||
@@ -0,0 +1,3 @@ | |||
1 | |||
2 | /* empty file */ | ||
3 | |||
diff --git a/tools/lib/lockdep/uinclude/linux/bitops.h b/tools/lib/lockdep/uinclude/linux/bitops.h new file mode 100644 index 000000000000..fab00ff936d1 --- /dev/null +++ b/tools/lib/lockdep/uinclude/linux/bitops.h | |||
@@ -0,0 +1,3 @@ | |||
1 | |||
2 | /* empty file */ | ||
3 | |||
diff --git a/tools/lib/lockdep/uinclude/linux/compiler.h b/tools/lib/lockdep/uinclude/linux/compiler.h new file mode 100644 index 000000000000..7ac838a1f196 --- /dev/null +++ b/tools/lib/lockdep/uinclude/linux/compiler.h | |||
@@ -0,0 +1,7 @@ | |||
1 | #ifndef _LIBLOCKDEP_LINUX_COMPILER_H_ | ||
2 | #define _LIBLOCKDEP_LINUX_COMPILER_H_ | ||
3 | |||
4 | #define __used __attribute__((__unused__)) | ||
5 | #define unlikely | ||
6 | |||
7 | #endif | ||
diff --git a/tools/lib/lockdep/uinclude/linux/debug_locks.h b/tools/lib/lockdep/uinclude/linux/debug_locks.h new file mode 100644 index 000000000000..f38eb64df794 --- /dev/null +++ b/tools/lib/lockdep/uinclude/linux/debug_locks.h | |||
@@ -0,0 +1,12 @@ | |||
1 | #ifndef _LIBLOCKDEP_DEBUG_LOCKS_H_ | ||
2 | #define _LIBLOCKDEP_DEBUG_LOCKS_H_ | ||
3 | |||
4 | #include <stddef.h> | ||
5 | #include <linux/compiler.h> | ||
6 | |||
7 | #define DEBUG_LOCKS_WARN_ON(x) (x) | ||
8 | |||
9 | extern bool debug_locks; | ||
10 | extern bool debug_locks_silent; | ||
11 | |||
12 | #endif | ||
diff --git a/tools/lib/lockdep/uinclude/linux/delay.h b/tools/lib/lockdep/uinclude/linux/delay.h new file mode 100644 index 000000000000..fab00ff936d1 --- /dev/null +++ b/tools/lib/lockdep/uinclude/linux/delay.h | |||
@@ -0,0 +1,3 @@ | |||
1 | |||
2 | /* empty file */ | ||
3 | |||
diff --git a/tools/lib/lockdep/uinclude/linux/export.h b/tools/lib/lockdep/uinclude/linux/export.h new file mode 100644 index 000000000000..6bdf3492c535 --- /dev/null +++ b/tools/lib/lockdep/uinclude/linux/export.h | |||
@@ -0,0 +1,7 @@ | |||
1 | #ifndef _LIBLOCKDEP_LINUX_EXPORT_H_ | ||
2 | #define _LIBLOCKDEP_LINUX_EXPORT_H_ | ||
3 | |||
4 | #define EXPORT_SYMBOL(sym) | ||
5 | #define EXPORT_SYMBOL_GPL(sym) | ||
6 | |||
7 | #endif | ||
diff --git a/tools/lib/lockdep/uinclude/linux/ftrace.h b/tools/lib/lockdep/uinclude/linux/ftrace.h new file mode 100644 index 000000000000..fab00ff936d1 --- /dev/null +++ b/tools/lib/lockdep/uinclude/linux/ftrace.h | |||
@@ -0,0 +1,3 @@ | |||
1 | |||
2 | /* empty file */ | ||
3 | |||
diff --git a/tools/lib/lockdep/uinclude/linux/gfp.h b/tools/lib/lockdep/uinclude/linux/gfp.h new file mode 100644 index 000000000000..fab00ff936d1 --- /dev/null +++ b/tools/lib/lockdep/uinclude/linux/gfp.h | |||
@@ -0,0 +1,3 @@ | |||
1 | |||
2 | /* empty file */ | ||
3 | |||
diff --git a/tools/lib/lockdep/uinclude/linux/hardirq.h b/tools/lib/lockdep/uinclude/linux/hardirq.h new file mode 100644 index 000000000000..c8f3f8f58729 --- /dev/null +++ b/tools/lib/lockdep/uinclude/linux/hardirq.h | |||
@@ -0,0 +1,11 @@ | |||
1 | #ifndef _LIBLOCKDEP_LINUX_HARDIRQ_H_ | ||
2 | #define _LIBLOCKDEP_LINUX_HARDIRQ_H_ | ||
3 | |||
4 | #define SOFTIRQ_BITS 0UL | ||
5 | #define HARDIRQ_BITS 0UL | ||
6 | #define SOFTIRQ_SHIFT 0UL | ||
7 | #define HARDIRQ_SHIFT 0UL | ||
8 | #define hardirq_count() 0UL | ||
9 | #define softirq_count() 0UL | ||
10 | |||
11 | #endif | ||
diff --git a/tools/lib/lockdep/uinclude/linux/hash.h b/tools/lib/lockdep/uinclude/linux/hash.h new file mode 100644 index 000000000000..0f8479858dc0 --- /dev/null +++ b/tools/lib/lockdep/uinclude/linux/hash.h | |||
@@ -0,0 +1 @@ | |||
#include "../../../include/linux/hash.h" | |||
diff --git a/tools/lib/lockdep/uinclude/linux/interrupt.h b/tools/lib/lockdep/uinclude/linux/interrupt.h new file mode 100644 index 000000000000..fab00ff936d1 --- /dev/null +++ b/tools/lib/lockdep/uinclude/linux/interrupt.h | |||
@@ -0,0 +1,3 @@ | |||
1 | |||
2 | /* empty file */ | ||
3 | |||
diff --git a/tools/lib/lockdep/uinclude/linux/irqflags.h b/tools/lib/lockdep/uinclude/linux/irqflags.h new file mode 100644 index 000000000000..6cc296f0fad0 --- /dev/null +++ b/tools/lib/lockdep/uinclude/linux/irqflags.h | |||
@@ -0,0 +1,38 @@ | |||
1 | #ifndef _LIBLOCKDEP_LINUX_TRACE_IRQFLAGS_H_ | ||
2 | #define _LIBLOCKDEP_LINUX_TRACE_IRQFLAGS_H_ | ||
3 | |||
4 | # define trace_hardirq_context(p) 0 | ||
5 | # define trace_softirq_context(p) 0 | ||
6 | # define trace_hardirqs_enabled(p) 0 | ||
7 | # define trace_softirqs_enabled(p) 0 | ||
8 | # define trace_hardirq_enter() do { } while (0) | ||
9 | # define trace_hardirq_exit() do { } while (0) | ||
10 | # define lockdep_softirq_enter() do { } while (0) | ||
11 | # define lockdep_softirq_exit() do { } while (0) | ||
12 | # define INIT_TRACE_IRQFLAGS | ||
13 | |||
14 | # define stop_critical_timings() do { } while (0) | ||
15 | # define start_critical_timings() do { } while (0) | ||
16 | |||
17 | #define raw_local_irq_disable() do { } while (0) | ||
18 | #define raw_local_irq_enable() do { } while (0) | ||
19 | #define raw_local_irq_save(flags) ((flags) = 0) | ||
20 | #define raw_local_irq_restore(flags) do { } while (0) | ||
21 | #define raw_local_save_flags(flags) ((flags) = 0) | ||
22 | #define raw_irqs_disabled_flags(flags) do { } while (0) | ||
23 | #define raw_irqs_disabled() 0 | ||
24 | #define raw_safe_halt() | ||
25 | |||
26 | #define local_irq_enable() do { } while (0) | ||
27 | #define local_irq_disable() do { } while (0) | ||
28 | #define local_irq_save(flags) ((flags) = 0) | ||
29 | #define local_irq_restore(flags) do { } while (0) | ||
30 | #define local_save_flags(flags) ((flags) = 0) | ||
31 | #define irqs_disabled() (1) | ||
32 | #define irqs_disabled_flags(flags) (0) | ||
33 | #define safe_halt() do { } while (0) | ||
34 | |||
35 | #define trace_lock_release(x, y) | ||
36 | #define trace_lock_acquire(a, b, c, d, e, f, g) | ||
37 | |||
38 | #endif | ||
diff --git a/tools/lib/lockdep/uinclude/linux/kallsyms.h b/tools/lib/lockdep/uinclude/linux/kallsyms.h new file mode 100644 index 000000000000..b0f2dbdf1a15 --- /dev/null +++ b/tools/lib/lockdep/uinclude/linux/kallsyms.h | |||
@@ -0,0 +1,32 @@ | |||
1 | #ifndef _LIBLOCKDEP_LINUX_KALLSYMS_H_ | ||
2 | #define _LIBLOCKDEP_LINUX_KALLSYMS_H_ | ||
3 | |||
4 | #include <linux/kernel.h> | ||
5 | #include <stdio.h> | ||
6 | |||
7 | #define KSYM_NAME_LEN 128 | ||
8 | |||
9 | struct module; | ||
10 | |||
11 | static inline const char *kallsyms_lookup(unsigned long addr, | ||
12 | unsigned long *symbolsize, | ||
13 | unsigned long *offset, | ||
14 | char **modname, char *namebuf) | ||
15 | { | ||
16 | return NULL; | ||
17 | } | ||
18 | |||
19 | #include <execinfo.h> | ||
20 | #include <stdlib.h> | ||
21 | static inline void print_ip_sym(unsigned long ip) | ||
22 | { | ||
23 | char **name; | ||
24 | |||
25 | name = backtrace_symbols((void **)&ip, 1); | ||
26 | |||
27 | printf("%s\n", *name); | ||
28 | |||
29 | free(name); | ||
30 | } | ||
31 | |||
32 | #endif | ||
diff --git a/tools/lib/lockdep/uinclude/linux/kern_levels.h b/tools/lib/lockdep/uinclude/linux/kern_levels.h new file mode 100644 index 000000000000..3b9bade28698 --- /dev/null +++ b/tools/lib/lockdep/uinclude/linux/kern_levels.h | |||
@@ -0,0 +1,25 @@ | |||
1 | #ifndef __KERN_LEVELS_H__ | ||
2 | #define __KERN_LEVELS_H__ | ||
3 | |||
4 | #define KERN_SOH "" /* ASCII Start Of Header */ | ||
5 | #define KERN_SOH_ASCII '' | ||
6 | |||
7 | #define KERN_EMERG KERN_SOH "" /* system is unusable */ | ||
8 | #define KERN_ALERT KERN_SOH "" /* action must be taken immediately */ | ||
9 | #define KERN_CRIT KERN_SOH "" /* critical conditions */ | ||
10 | #define KERN_ERR KERN_SOH "" /* error conditions */ | ||
11 | #define KERN_WARNING KERN_SOH "" /* warning conditions */ | ||
12 | #define KERN_NOTICE KERN_SOH "" /* normal but significant condition */ | ||
13 | #define KERN_INFO KERN_SOH "" /* informational */ | ||
14 | #define KERN_DEBUG KERN_SOH "" /* debug-level messages */ | ||
15 | |||
16 | #define KERN_DEFAULT KERN_SOH "" /* the default kernel loglevel */ | ||
17 | |||
18 | /* | ||
19 | * Annotation for a "continued" line of log printout (only done after a | ||
20 | * line that had no enclosing \n). Only to be used by core/arch code | ||
21 | * during early bootup (a continued line is not SMP-safe otherwise). | ||
22 | */ | ||
23 | #define KERN_CONT "" | ||
24 | |||
25 | #endif | ||
diff --git a/tools/lib/lockdep/uinclude/linux/kernel.h b/tools/lib/lockdep/uinclude/linux/kernel.h new file mode 100644 index 000000000000..a11e3c357be7 --- /dev/null +++ b/tools/lib/lockdep/uinclude/linux/kernel.h | |||
@@ -0,0 +1,44 @@ | |||
1 | #ifndef _LIBLOCKDEP_LINUX_KERNEL_H_ | ||
2 | #define _LIBLOCKDEP_LINUX_KERNEL_H_ | ||
3 | |||
4 | #include <linux/export.h> | ||
5 | #include <linux/types.h> | ||
6 | #include <linux/rcu.h> | ||
7 | #include <linux/hardirq.h> | ||
8 | #include <linux/kern_levels.h> | ||
9 | |||
10 | #ifndef container_of | ||
11 | #define container_of(ptr, type, member) ({ \ | ||
12 | const typeof(((type *)0)->member) * __mptr = (ptr); \ | ||
13 | (type *)((char *)__mptr - offsetof(type, member)); }) | ||
14 | #endif | ||
15 | |||
16 | #define max(x, y) ({ \ | ||
17 | typeof(x) _max1 = (x); \ | ||
18 | typeof(y) _max2 = (y); \ | ||
19 | (void) (&_max1 == &_max2); \ | ||
20 | _max1 > _max2 ? _max1 : _max2; }) | ||
21 | |||
22 | #define BUILD_BUG_ON(condition) ((void)sizeof(char[1 - 2*!!(condition)])) | ||
23 | #define WARN_ON(x) (x) | ||
24 | #define WARN_ON_ONCE(x) (x) | ||
25 | #define likely(x) (x) | ||
26 | #define WARN(x, y, z) (x) | ||
27 | #define uninitialized_var(x) x | ||
28 | #define __init | ||
29 | #define noinline | ||
30 | #define list_add_tail_rcu list_add_tail | ||
31 | |||
32 | #ifndef CALLER_ADDR0 | ||
33 | #define CALLER_ADDR0 ((unsigned long)__builtin_return_address(0)) | ||
34 | #endif | ||
35 | |||
36 | #ifndef _RET_IP_ | ||
37 | #define _RET_IP_ CALLER_ADDR0 | ||
38 | #endif | ||
39 | |||
40 | #ifndef _THIS_IP_ | ||
41 | #define _THIS_IP_ ({ __label__ __here; __here: (unsigned long)&&__here; }) | ||
42 | #endif | ||
43 | |||
44 | #endif | ||
diff --git a/tools/lib/lockdep/uinclude/linux/kmemcheck.h b/tools/lib/lockdep/uinclude/linux/kmemcheck.h new file mode 100644 index 000000000000..94d598bc6abe --- /dev/null +++ b/tools/lib/lockdep/uinclude/linux/kmemcheck.h | |||
@@ -0,0 +1,8 @@ | |||
1 | #ifndef _LIBLOCKDEP_LINUX_KMEMCHECK_H_ | ||
2 | #define _LIBLOCKDEP_LINUX_KMEMCHECK_H_ | ||
3 | |||
4 | static inline void kmemcheck_mark_initialized(void *address, unsigned int n) | ||
5 | { | ||
6 | } | ||
7 | |||
8 | #endif | ||
diff --git a/tools/lib/lockdep/uinclude/linux/linkage.h b/tools/lib/lockdep/uinclude/linux/linkage.h new file mode 100644 index 000000000000..fab00ff936d1 --- /dev/null +++ b/tools/lib/lockdep/uinclude/linux/linkage.h | |||
@@ -0,0 +1,3 @@ | |||
1 | |||
2 | /* empty file */ | ||
3 | |||
diff --git a/tools/lib/lockdep/uinclude/linux/list.h b/tools/lib/lockdep/uinclude/linux/list.h new file mode 100644 index 000000000000..6e9ef31ed82e --- /dev/null +++ b/tools/lib/lockdep/uinclude/linux/list.h | |||
@@ -0,0 +1 @@ | |||
#include "../../../include/linux/list.h" | |||
diff --git a/tools/lib/lockdep/uinclude/linux/lockdep.h b/tools/lib/lockdep/uinclude/linux/lockdep.h new file mode 100644 index 000000000000..d0f5d6e50214 --- /dev/null +++ b/tools/lib/lockdep/uinclude/linux/lockdep.h | |||
@@ -0,0 +1,55 @@ | |||
1 | #ifndef _LIBLOCKDEP_LOCKDEP_H_ | ||
2 | #define _LIBLOCKDEP_LOCKDEP_H_ | ||
3 | |||
4 | #include <sys/prctl.h> | ||
5 | #include <sys/syscall.h> | ||
6 | #include <string.h> | ||
7 | #include <limits.h> | ||
8 | #include <linux/utsname.h> | ||
9 | |||
10 | |||
11 | #define MAX_LOCK_DEPTH 2000UL | ||
12 | |||
13 | #include "../../../include/linux/lockdep.h" | ||
14 | |||
15 | struct task_struct { | ||
16 | u64 curr_chain_key; | ||
17 | int lockdep_depth; | ||
18 | unsigned int lockdep_recursion; | ||
19 | struct held_lock held_locks[MAX_LOCK_DEPTH]; | ||
20 | gfp_t lockdep_reclaim_gfp; | ||
21 | int pid; | ||
22 | char comm[17]; | ||
23 | }; | ||
24 | |||
25 | extern struct task_struct *__curr(void); | ||
26 | |||
27 | #define current (__curr()) | ||
28 | |||
29 | #define debug_locks_off() 1 | ||
30 | #define task_pid_nr(tsk) ((tsk)->pid) | ||
31 | |||
32 | #define KSYM_NAME_LEN 128 | ||
33 | #define printk printf | ||
34 | |||
35 | #define list_del_rcu list_del | ||
36 | |||
37 | #define atomic_t unsigned long | ||
38 | #define atomic_inc(x) ((*(x))++) | ||
39 | |||
40 | static struct new_utsname *init_utsname(void) | ||
41 | { | ||
42 | static struct new_utsname n = (struct new_utsname) { | ||
43 | .release = "liblockdep", | ||
44 | .version = LIBLOCKDEP_VERSION, | ||
45 | }; | ||
46 | |||
47 | return &n; | ||
48 | } | ||
49 | |||
50 | #define print_tainted() "" | ||
51 | #define static_obj(x) 1 | ||
52 | |||
53 | #define debug_show_all_locks() | ||
54 | |||
55 | #endif | ||
diff --git a/tools/lib/lockdep/uinclude/linux/module.h b/tools/lib/lockdep/uinclude/linux/module.h new file mode 100644 index 000000000000..09c7a7be8ccc --- /dev/null +++ b/tools/lib/lockdep/uinclude/linux/module.h | |||
@@ -0,0 +1,6 @@ | |||
1 | #ifndef _LIBLOCKDEP_LINUX_MODULE_H_ | ||
2 | #define _LIBLOCKDEP_LINUX_MODULE_H_ | ||
3 | |||
4 | #define module_param(name, type, perm) | ||
5 | |||
6 | #endif | ||
diff --git a/tools/lib/lockdep/uinclude/linux/mutex.h b/tools/lib/lockdep/uinclude/linux/mutex.h new file mode 100644 index 000000000000..fab00ff936d1 --- /dev/null +++ b/tools/lib/lockdep/uinclude/linux/mutex.h | |||
@@ -0,0 +1,3 @@ | |||
1 | |||
2 | /* empty file */ | ||
3 | |||
diff --git a/tools/lib/lockdep/uinclude/linux/poison.h b/tools/lib/lockdep/uinclude/linux/poison.h new file mode 100644 index 000000000000..0c27bdf14233 --- /dev/null +++ b/tools/lib/lockdep/uinclude/linux/poison.h | |||
@@ -0,0 +1 @@ | |||
#include "../../../include/linux/poison.h" | |||
diff --git a/tools/lib/lockdep/uinclude/linux/prefetch.h b/tools/lib/lockdep/uinclude/linux/prefetch.h new file mode 100644 index 000000000000..d73fe6f850ac --- /dev/null +++ b/tools/lib/lockdep/uinclude/linux/prefetch.h | |||
@@ -0,0 +1,6 @@ | |||
1 | #ifndef _LIBLOCKDEP_LINUX_PREFETCH_H_ | ||
2 | #define _LIBLOCKDEP_LINUX_PREFETCH_H | ||
3 | |||
4 | static inline void prefetch(void *a __attribute__((unused))) { } | ||
5 | |||
6 | #endif | ||
diff --git a/tools/lib/lockdep/uinclude/linux/proc_fs.h b/tools/lib/lockdep/uinclude/linux/proc_fs.h new file mode 100644 index 000000000000..fab00ff936d1 --- /dev/null +++ b/tools/lib/lockdep/uinclude/linux/proc_fs.h | |||
@@ -0,0 +1,3 @@ | |||
1 | |||
2 | /* empty file */ | ||
3 | |||
diff --git a/tools/lib/lockdep/uinclude/linux/rbtree.h b/tools/lib/lockdep/uinclude/linux/rbtree.h new file mode 100644 index 000000000000..965901db4862 --- /dev/null +++ b/tools/lib/lockdep/uinclude/linux/rbtree.h | |||
@@ -0,0 +1 @@ | |||
#include "../../../include/linux/rbtree.h" | |||
diff --git a/tools/lib/lockdep/uinclude/linux/rbtree_augmented.h b/tools/lib/lockdep/uinclude/linux/rbtree_augmented.h new file mode 100644 index 000000000000..c3759477379c --- /dev/null +++ b/tools/lib/lockdep/uinclude/linux/rbtree_augmented.h | |||
@@ -0,0 +1,2 @@ | |||
1 | #define __always_inline | ||
2 | #include "../../../include/linux/rbtree_augmented.h" | ||
diff --git a/tools/lib/lockdep/uinclude/linux/rcu.h b/tools/lib/lockdep/uinclude/linux/rcu.h new file mode 100644 index 000000000000..042ee8e463c9 --- /dev/null +++ b/tools/lib/lockdep/uinclude/linux/rcu.h | |||
@@ -0,0 +1,21 @@ | |||
1 | #ifndef _LIBLOCKDEP_RCU_H_ | ||
2 | #define _LIBLOCKDEP_RCU_H_ | ||
3 | |||
4 | int rcu_scheduler_active; | ||
5 | |||
6 | static inline int rcu_lockdep_current_cpu_online(void) | ||
7 | { | ||
8 | return 1; | ||
9 | } | ||
10 | |||
11 | static inline int rcu_is_cpu_idle(void) | ||
12 | { | ||
13 | return 1; | ||
14 | } | ||
15 | |||
16 | static inline bool rcu_is_watching(void) | ||
17 | { | ||
18 | return false; | ||
19 | } | ||
20 | |||
21 | #endif | ||
diff --git a/tools/lib/lockdep/uinclude/linux/seq_file.h b/tools/lib/lockdep/uinclude/linux/seq_file.h new file mode 100644 index 000000000000..fab00ff936d1 --- /dev/null +++ b/tools/lib/lockdep/uinclude/linux/seq_file.h | |||
@@ -0,0 +1,3 @@ | |||
1 | |||
2 | /* empty file */ | ||
3 | |||
diff --git a/tools/lib/lockdep/uinclude/linux/spinlock.h b/tools/lib/lockdep/uinclude/linux/spinlock.h new file mode 100644 index 000000000000..68c1aa2bcba5 --- /dev/null +++ b/tools/lib/lockdep/uinclude/linux/spinlock.h | |||
@@ -0,0 +1,25 @@ | |||
1 | #ifndef _LIBLOCKDEP_SPINLOCK_H_ | ||
2 | #define _LIBLOCKDEP_SPINLOCK_H_ | ||
3 | |||
4 | #include <pthread.h> | ||
5 | #include <stdbool.h> | ||
6 | |||
7 | #define arch_spinlock_t pthread_mutex_t | ||
8 | #define __ARCH_SPIN_LOCK_UNLOCKED PTHREAD_MUTEX_INITIALIZER | ||
9 | |||
10 | static inline void arch_spin_lock(arch_spinlock_t *mutex) | ||
11 | { | ||
12 | pthread_mutex_lock(mutex); | ||
13 | } | ||
14 | |||
15 | static inline void arch_spin_unlock(arch_spinlock_t *mutex) | ||
16 | { | ||
17 | pthread_mutex_unlock(mutex); | ||
18 | } | ||
19 | |||
20 | static inline bool arch_spin_is_locked(arch_spinlock_t *mutex) | ||
21 | { | ||
22 | return true; | ||
23 | } | ||
24 | |||
25 | #endif | ||
diff --git a/tools/lib/lockdep/uinclude/linux/stacktrace.h b/tools/lib/lockdep/uinclude/linux/stacktrace.h new file mode 100644 index 000000000000..39aecc6b19d1 --- /dev/null +++ b/tools/lib/lockdep/uinclude/linux/stacktrace.h | |||
@@ -0,0 +1,32 @@ | |||
1 | #ifndef _LIBLOCKDEP_LINUX_STACKTRACE_H_ | ||
2 | #define _LIBLOCKDEP_LINUX_STACKTRACE_H_ | ||
3 | |||
4 | #include <execinfo.h> | ||
5 | |||
6 | struct stack_trace { | ||
7 | unsigned int nr_entries, max_entries; | ||
8 | unsigned long *entries; | ||
9 | int skip; | ||
10 | }; | ||
11 | |||
12 | static inline void print_stack_trace(struct stack_trace *trace, int spaces) | ||
13 | { | ||
14 | backtrace_symbols_fd((void **)trace->entries, trace->nr_entries, 1); | ||
15 | } | ||
16 | |||
17 | #define save_stack_trace(trace) \ | ||
18 | ((trace)->nr_entries = \ | ||
19 | backtrace((void **)(trace)->entries, (trace)->max_entries)) | ||
20 | |||
21 | static inline int dump_stack(void) | ||
22 | { | ||
23 | void *array[64]; | ||
24 | size_t size; | ||
25 | |||
26 | size = backtrace(array, 64); | ||
27 | backtrace_symbols_fd(array, size, 1); | ||
28 | |||
29 | return 0; | ||
30 | } | ||
31 | |||
32 | #endif | ||
diff --git a/tools/lib/lockdep/uinclude/linux/stringify.h b/tools/lib/lockdep/uinclude/linux/stringify.h new file mode 100644 index 000000000000..05dfcd1ac118 --- /dev/null +++ b/tools/lib/lockdep/uinclude/linux/stringify.h | |||
@@ -0,0 +1,7 @@ | |||
1 | #ifndef _LIBLOCKDEP_LINUX_STRINGIFY_H_ | ||
2 | #define _LIBLOCKDEP_LINUX_STRINGIFY_H_ | ||
3 | |||
4 | #define __stringify_1(x...) #x | ||
5 | #define __stringify(x...) __stringify_1(x) | ||
6 | |||
7 | #endif | ||
diff --git a/tools/lib/lockdep/uinclude/linux/types.h b/tools/lib/lockdep/uinclude/linux/types.h new file mode 100644 index 000000000000..929938f426de --- /dev/null +++ b/tools/lib/lockdep/uinclude/linux/types.h | |||
@@ -0,0 +1,58 @@ | |||
1 | #ifndef _LIBLOCKDEP_LINUX_TYPES_H_ | ||
2 | #define _LIBLOCKDEP_LINUX_TYPES_H_ | ||
3 | |||
4 | #include <stdbool.h> | ||
5 | #include <stddef.h> | ||
6 | |||
7 | #define __SANE_USERSPACE_TYPES__ /* For PPC64, to get LL64 types */ | ||
8 | #include <asm/types.h> | ||
9 | |||
10 | struct page; | ||
11 | struct kmem_cache; | ||
12 | |||
13 | typedef unsigned gfp_t; | ||
14 | |||
15 | typedef __u64 u64; | ||
16 | typedef __s64 s64; | ||
17 | |||
18 | typedef __u32 u32; | ||
19 | typedef __s32 s32; | ||
20 | |||
21 | typedef __u16 u16; | ||
22 | typedef __s16 s16; | ||
23 | |||
24 | typedef __u8 u8; | ||
25 | typedef __s8 s8; | ||
26 | |||
27 | #ifdef __CHECKER__ | ||
28 | #define __bitwise__ __attribute__((bitwise)) | ||
29 | #else | ||
30 | #define __bitwise__ | ||
31 | #endif | ||
32 | #ifdef __CHECK_ENDIAN__ | ||
33 | #define __bitwise __bitwise__ | ||
34 | #else | ||
35 | #define __bitwise | ||
36 | #endif | ||
37 | |||
38 | |||
39 | typedef __u16 __bitwise __le16; | ||
40 | typedef __u16 __bitwise __be16; | ||
41 | typedef __u32 __bitwise __le32; | ||
42 | typedef __u32 __bitwise __be32; | ||
43 | typedef __u64 __bitwise __le64; | ||
44 | typedef __u64 __bitwise __be64; | ||
45 | |||
46 | struct list_head { | ||
47 | struct list_head *next, *prev; | ||
48 | }; | ||
49 | |||
50 | struct hlist_head { | ||
51 | struct hlist_node *first; | ||
52 | }; | ||
53 | |||
54 | struct hlist_node { | ||
55 | struct hlist_node *next, **pprev; | ||
56 | }; | ||
57 | |||
58 | #endif | ||
diff --git a/tools/lib/lockdep/uinclude/trace/events/lock.h b/tools/lib/lockdep/uinclude/trace/events/lock.h new file mode 100644 index 000000000000..fab00ff936d1 --- /dev/null +++ b/tools/lib/lockdep/uinclude/trace/events/lock.h | |||
@@ -0,0 +1,3 @@ | |||
1 | |||
2 | /* empty file */ | ||
3 | |||
diff --git a/tools/lib/symbol/kallsyms.c b/tools/lib/symbol/kallsyms.c new file mode 100644 index 000000000000..18bc271a4bbc --- /dev/null +++ b/tools/lib/symbol/kallsyms.c | |||
@@ -0,0 +1,58 @@ | |||
1 | #include "symbol/kallsyms.h" | ||
2 | #include <stdio.h> | ||
3 | #include <stdlib.h> | ||
4 | |||
5 | int kallsyms__parse(const char *filename, void *arg, | ||
6 | int (*process_symbol)(void *arg, const char *name, | ||
7 | char type, u64 start)) | ||
8 | { | ||
9 | char *line = NULL; | ||
10 | size_t n; | ||
11 | int err = -1; | ||
12 | FILE *file = fopen(filename, "r"); | ||
13 | |||
14 | if (file == NULL) | ||
15 | goto out_failure; | ||
16 | |||
17 | err = 0; | ||
18 | |||
19 | while (!feof(file)) { | ||
20 | u64 start; | ||
21 | int line_len, len; | ||
22 | char symbol_type; | ||
23 | char *symbol_name; | ||
24 | |||
25 | line_len = getline(&line, &n, file); | ||
26 | if (line_len < 0 || !line) | ||
27 | break; | ||
28 | |||
29 | line[--line_len] = '\0'; /* \n */ | ||
30 | |||
31 | len = hex2u64(line, &start); | ||
32 | |||
33 | len++; | ||
34 | if (len + 2 >= line_len) | ||
35 | continue; | ||
36 | |||
37 | symbol_type = line[len]; | ||
38 | len += 2; | ||
39 | symbol_name = line + len; | ||
40 | len = line_len - len; | ||
41 | |||
42 | if (len >= KSYM_NAME_LEN) { | ||
43 | err = -1; | ||
44 | break; | ||
45 | } | ||
46 | |||
47 | err = process_symbol(arg, symbol_name, symbol_type, start); | ||
48 | if (err) | ||
49 | break; | ||
50 | } | ||
51 | |||
52 | free(line); | ||
53 | fclose(file); | ||
54 | return err; | ||
55 | |||
56 | out_failure: | ||
57 | return -1; | ||
58 | } | ||
diff --git a/tools/lib/symbol/kallsyms.h b/tools/lib/symbol/kallsyms.h new file mode 100644 index 000000000000..6084f5e18b3c --- /dev/null +++ b/tools/lib/symbol/kallsyms.h | |||
@@ -0,0 +1,24 @@ | |||
1 | #ifndef __TOOLS_KALLSYMS_H_ | ||
2 | #define __TOOLS_KALLSYMS_H_ 1 | ||
3 | |||
4 | #include <elf.h> | ||
5 | #include <linux/ctype.h> | ||
6 | #include <linux/types.h> | ||
7 | |||
8 | #ifndef KSYM_NAME_LEN | ||
9 | #define KSYM_NAME_LEN 256 | ||
10 | #endif | ||
11 | |||
12 | static inline u8 kallsyms2elf_type(char type) | ||
13 | { | ||
14 | if (type == 'W') | ||
15 | return STB_WEAK; | ||
16 | |||
17 | return isupper(type) ? STB_GLOBAL : STB_LOCAL; | ||
18 | } | ||
19 | |||
20 | int kallsyms__parse(const char *filename, void *arg, | ||
21 | int (*process_symbol)(void *arg, const char *name, | ||
22 | char type, u64 start)); | ||
23 | |||
24 | #endif /* __TOOLS_KALLSYMS_H_ */ | ||
diff --git a/tools/lib/traceevent/Makefile b/tools/lib/traceevent/Makefile index fc1502098595..005c9cc06935 100644 --- a/tools/lib/traceevent/Makefile +++ b/tools/lib/traceevent/Makefile | |||
@@ -43,6 +43,32 @@ man_dir_SQ = '$(subst ','\'',$(man_dir))' | |||
43 | export man_dir man_dir_SQ INSTALL | 43 | export man_dir man_dir_SQ INSTALL |
44 | export DESTDIR DESTDIR_SQ | 44 | export DESTDIR DESTDIR_SQ |
45 | 45 | ||
46 | set_plugin_dir := 1 | ||
47 | |||
48 | # Set plugin_dir to preffered global plugin location | ||
49 | # If we install under $HOME directory we go under | ||
50 | # $(HOME)/.traceevent/plugins | ||
51 | # | ||
52 | # We dont set PLUGIN_DIR in case we install under $HOME | ||
53 | # directory, because by default the code looks under: | ||
54 | # $(HOME)/.traceevent/plugins by default. | ||
55 | # | ||
56 | ifeq ($(plugin_dir),) | ||
57 | ifeq ($(prefix),$(HOME)) | ||
58 | override plugin_dir = $(HOME)/.traceevent/plugins | ||
59 | set_plugin_dir := 0 | ||
60 | else | ||
61 | override plugin_dir = $(prefix)/lib/traceevent/plugins | ||
62 | endif | ||
63 | endif | ||
64 | |||
65 | ifeq ($(set_plugin_dir),1) | ||
66 | PLUGIN_DIR = -DPLUGIN_DIR="$(plugin_dir)" | ||
67 | PLUGIN_DIR_SQ = '$(subst ','\'',$(PLUGIN_DIR))' | ||
68 | endif | ||
69 | |||
70 | include $(if $(BUILD_SRC),$(BUILD_SRC)/)../../scripts/Makefile.include | ||
71 | |||
46 | # copy a bit from Linux kbuild | 72 | # copy a bit from Linux kbuild |
47 | 73 | ||
48 | ifeq ("$(origin V)", "command line") | 74 | ifeq ("$(origin V)", "command line") |
@@ -57,18 +83,13 @@ ifeq ("$(origin O)", "command line") | |||
57 | endif | 83 | endif |
58 | 84 | ||
59 | ifeq ($(BUILD_SRC),) | 85 | ifeq ($(BUILD_SRC),) |
60 | ifneq ($(BUILD_OUTPUT),) | 86 | ifneq ($(OUTPUT),) |
61 | 87 | ||
62 | define build_output | 88 | define build_output |
63 | $(if $(VERBOSE:1=),@)+$(MAKE) -C $(BUILD_OUTPUT) \ | 89 | $(if $(VERBOSE:1=),@)+$(MAKE) -C $(OUTPUT) \ |
64 | BUILD_SRC=$(CURDIR) -f $(CURDIR)/Makefile $1 | 90 | BUILD_SRC=$(CURDIR)/ -f $(CURDIR)/Makefile $1 |
65 | endef | 91 | endef |
66 | 92 | ||
67 | saved-output := $(BUILD_OUTPUT) | ||
68 | BUILD_OUTPUT := $(shell cd $(BUILD_OUTPUT) && /bin/pwd) | ||
69 | $(if $(BUILD_OUTPUT),, \ | ||
70 | $(error output directory "$(saved-output)" does not exist)) | ||
71 | |||
72 | all: sub-make | 93 | all: sub-make |
73 | 94 | ||
74 | $(MAKECMDGOALS): sub-make | 95 | $(MAKECMDGOALS): sub-make |
@@ -80,7 +101,7 @@ sub-make: force | |||
80 | # Leave processing to above invocation of make | 101 | # Leave processing to above invocation of make |
81 | skip-makefile := 1 | 102 | skip-makefile := 1 |
82 | 103 | ||
83 | endif # BUILD_OUTPUT | 104 | endif # OUTPUT |
84 | endif # BUILD_SRC | 105 | endif # BUILD_SRC |
85 | 106 | ||
86 | # We process the rest of the Makefile if this is the final invocation of make | 107 | # We process the rest of the Makefile if this is the final invocation of make |
@@ -96,6 +117,7 @@ export prefix bindir src obj | |||
96 | # Shell quotes | 117 | # Shell quotes |
97 | bindir_SQ = $(subst ','\'',$(bindir)) | 118 | bindir_SQ = $(subst ','\'',$(bindir)) |
98 | bindir_relative_SQ = $(subst ','\'',$(bindir_relative)) | 119 | bindir_relative_SQ = $(subst ','\'',$(bindir_relative)) |
120 | plugin_dir_SQ = $(subst ','\'',$(plugin_dir)) | ||
99 | 121 | ||
100 | LIB_FILE = libtraceevent.a libtraceevent.so | 122 | LIB_FILE = libtraceevent.a libtraceevent.so |
101 | 123 | ||
@@ -114,7 +136,7 @@ export Q VERBOSE | |||
114 | 136 | ||
115 | EVENT_PARSE_VERSION = $(EP_VERSION).$(EP_PATCHLEVEL).$(EP_EXTRAVERSION) | 137 | EVENT_PARSE_VERSION = $(EP_VERSION).$(EP_PATCHLEVEL).$(EP_EXTRAVERSION) |
116 | 138 | ||
117 | INCLUDES = -I. $(CONFIG_INCLUDES) | 139 | INCLUDES = -I. -I $(srctree)/../../include $(CONFIG_INCLUDES) |
118 | 140 | ||
119 | # Set compile option CFLAGS if not set elsewhere | 141 | # Set compile option CFLAGS if not set elsewhere |
120 | CFLAGS ?= -g -Wall | 142 | CFLAGS ?= -g -Wall |
@@ -125,41 +147,14 @@ override CFLAGS += $(udis86-flags) -D_GNU_SOURCE | |||
125 | 147 | ||
126 | ifeq ($(VERBOSE),1) | 148 | ifeq ($(VERBOSE),1) |
127 | Q = | 149 | Q = |
128 | print_compile = | ||
129 | print_app_build = | ||
130 | print_fpic_compile = | ||
131 | print_shared_lib_compile = | ||
132 | print_plugin_obj_compile = | ||
133 | print_plugin_build = | ||
134 | print_install = | ||
135 | else | 150 | else |
136 | Q = @ | 151 | Q = @ |
137 | print_compile = echo ' CC '$(OBJ); | ||
138 | print_app_build = echo ' BUILD '$(OBJ); | ||
139 | print_fpic_compile = echo ' CC FPIC '$(OBJ); | ||
140 | print_shared_lib_compile = echo ' BUILD SHARED LIB '$(OBJ); | ||
141 | print_plugin_obj_compile = echo ' BUILD PLUGIN OBJ '$(OBJ); | ||
142 | print_plugin_build = echo ' BUILD PLUGIN '$(OBJ); | ||
143 | print_static_lib_build = echo ' BUILD STATIC LIB '$(OBJ); | ||
144 | print_install = echo ' INSTALL '$1' to $(DESTDIR_SQ)$2'; | ||
145 | endif | 152 | endif |
146 | 153 | ||
147 | do_fpic_compile = \ | ||
148 | ($(print_fpic_compile) \ | ||
149 | $(CC) -c $(CFLAGS) $(EXT) -fPIC $< -o $@) | ||
150 | |||
151 | do_app_build = \ | ||
152 | ($(print_app_build) \ | ||
153 | $(CC) $^ -rdynamic -o $@ $(CONFIG_LIBS) $(LIBS)) | ||
154 | |||
155 | do_compile_shared_library = \ | 154 | do_compile_shared_library = \ |
156 | ($(print_shared_lib_compile) \ | 155 | ($(print_shared_lib_compile) \ |
157 | $(CC) --shared $^ -o $@) | 156 | $(CC) --shared $^ -o $@) |
158 | 157 | ||
159 | do_compile_plugin_obj = \ | ||
160 | ($(print_plugin_obj_compile) \ | ||
161 | $(CC) -c $(CFLAGS) -fPIC -o $@ $<) | ||
162 | |||
163 | do_plugin_build = \ | 158 | do_plugin_build = \ |
164 | ($(print_plugin_build) \ | 159 | ($(print_plugin_build) \ |
165 | $(CC) $(CFLAGS) -shared -nostartfiles -o $@ $<) | 160 | $(CC) $(CFLAGS) -shared -nostartfiles -o $@ $<) |
@@ -169,23 +164,37 @@ do_build_static_lib = \ | |||
169 | $(RM) $@; $(AR) rcs $@ $^) | 164 | $(RM) $@; $(AR) rcs $@ $^) |
170 | 165 | ||
171 | 166 | ||
172 | define do_compile | 167 | do_compile = $(QUIET_CC)$(CC) -c $(CFLAGS) $(EXT) $< -o $(obj)/$@; |
173 | $(print_compile) \ | ||
174 | $(CC) -c $(CFLAGS) $(EXT) $< -o $(obj)/$@; | ||
175 | endef | ||
176 | 168 | ||
177 | $(obj)/%.o: $(src)/%.c | 169 | $(obj)/%.o: $(src)/%.c |
178 | $(Q)$(call do_compile) | 170 | $(call do_compile) |
179 | 171 | ||
180 | %.o: $(src)/%.c | 172 | %.o: $(src)/%.c |
181 | $(Q)$(call do_compile) | 173 | $(call do_compile) |
182 | 174 | ||
183 | PEVENT_LIB_OBJS = event-parse.o trace-seq.o parse-filter.o parse-utils.o | 175 | PEVENT_LIB_OBJS = event-parse.o |
176 | PEVENT_LIB_OBJS += event-plugin.o | ||
177 | PEVENT_LIB_OBJS += trace-seq.o | ||
178 | PEVENT_LIB_OBJS += parse-filter.o | ||
179 | PEVENT_LIB_OBJS += parse-utils.o | ||
184 | PEVENT_LIB_OBJS += kbuffer-parse.o | 180 | PEVENT_LIB_OBJS += kbuffer-parse.o |
185 | 181 | ||
186 | ALL_OBJS = $(PEVENT_LIB_OBJS) | 182 | PLUGIN_OBJS = plugin_jbd2.o |
183 | PLUGIN_OBJS += plugin_hrtimer.o | ||
184 | PLUGIN_OBJS += plugin_kmem.o | ||
185 | PLUGIN_OBJS += plugin_kvm.o | ||
186 | PLUGIN_OBJS += plugin_mac80211.o | ||
187 | PLUGIN_OBJS += plugin_sched_switch.o | ||
188 | PLUGIN_OBJS += plugin_function.o | ||
189 | PLUGIN_OBJS += plugin_xen.o | ||
190 | PLUGIN_OBJS += plugin_scsi.o | ||
191 | PLUGIN_OBJS += plugin_cfg80211.o | ||
192 | |||
193 | PLUGINS := $(PLUGIN_OBJS:.o=.so) | ||
194 | |||
195 | ALL_OBJS = $(PEVENT_LIB_OBJS) $(PLUGIN_OBJS) | ||
187 | 196 | ||
188 | CMD_TARGETS = $(LIB_FILE) | 197 | CMD_TARGETS = $(LIB_FILE) $(PLUGINS) |
189 | 198 | ||
190 | TARGETS = $(CMD_TARGETS) | 199 | TARGETS = $(CMD_TARGETS) |
191 | 200 | ||
@@ -195,32 +204,40 @@ all: all_cmd | |||
195 | all_cmd: $(CMD_TARGETS) | 204 | all_cmd: $(CMD_TARGETS) |
196 | 205 | ||
197 | libtraceevent.so: $(PEVENT_LIB_OBJS) | 206 | libtraceevent.so: $(PEVENT_LIB_OBJS) |
198 | $(Q)$(do_compile_shared_library) | 207 | $(QUIET_LINK)$(CC) --shared $^ -o $@ |
199 | 208 | ||
200 | libtraceevent.a: $(PEVENT_LIB_OBJS) | 209 | libtraceevent.a: $(PEVENT_LIB_OBJS) |
201 | $(Q)$(do_build_static_lib) | 210 | $(QUIET_LINK)$(RM) $@; $(AR) rcs $@ $^ |
211 | |||
212 | plugins: $(PLUGINS) | ||
202 | 213 | ||
203 | $(PEVENT_LIB_OBJS): %.o: $(src)/%.c TRACEEVENT-CFLAGS | 214 | $(PEVENT_LIB_OBJS): %.o: $(src)/%.c TRACEEVENT-CFLAGS |
204 | $(Q)$(do_fpic_compile) | 215 | $(QUIET_CC_FPIC)$(CC) -c $(CFLAGS) $(EXT) -fPIC $< -o $@ |
216 | |||
217 | $(PLUGIN_OBJS): %.o : $(src)/%.c | ||
218 | $(QUIET_CC_FPIC)$(CC) -c $(CFLAGS) -fPIC -o $@ $< | ||
219 | |||
220 | $(PLUGINS): %.so: %.o | ||
221 | $(QUIET_LINK)$(CC) $(CFLAGS) -shared -nostartfiles -o $@ $< | ||
205 | 222 | ||
206 | define make_version.h | 223 | define make_version.h |
207 | (echo '/* This file is automatically generated. Do not modify. */'; \ | 224 | (echo '/* This file is automatically generated. Do not modify. */'; \ |
208 | echo \#define VERSION_CODE $(shell \ | 225 | echo \#define VERSION_CODE $(shell \ |
209 | expr $(VERSION) \* 256 + $(PATCHLEVEL)); \ | 226 | expr $(VERSION) \* 256 + $(PATCHLEVEL)); \ |
210 | echo '#define EXTRAVERSION ' $(EXTRAVERSION); \ | 227 | echo '#define EXTRAVERSION ' $(EXTRAVERSION); \ |
211 | echo '#define VERSION_STRING "'$(VERSION).$(PATCHLEVEL).$(EXTRAVERSION)'"'; \ | 228 | echo '#define VERSION_STRING "'$(VERSION).$(PATCHLEVEL).$(EXTRAVERSION)'"'; \ |
212 | echo '#define FILE_VERSION '$(FILE_VERSION); \ | 229 | echo '#define FILE_VERSION '$(FILE_VERSION); \ |
213 | ) > $1 | 230 | ) > $1 |
214 | endef | 231 | endef |
215 | 232 | ||
216 | define update_version.h | 233 | define update_version.h |
217 | ($(call make_version.h, $@.tmp); \ | 234 | ($(call make_version.h, $@.tmp); \ |
218 | if [ -r $@ ] && cmp -s $@ $@.tmp; then \ | 235 | if [ -r $@ ] && cmp -s $@ $@.tmp; then \ |
219 | rm -f $@.tmp; \ | 236 | rm -f $@.tmp; \ |
220 | else \ | 237 | else \ |
221 | echo ' UPDATE $@'; \ | 238 | echo ' UPDATE $@'; \ |
222 | mv -f $@.tmp $@; \ | 239 | mv -f $@.tmp $@; \ |
223 | fi); | 240 | fi); |
224 | endef | 241 | endef |
225 | 242 | ||
226 | ep_version.h: force | 243 | ep_version.h: force |
@@ -229,13 +246,13 @@ ep_version.h: force | |||
229 | VERSION_FILES = ep_version.h | 246 | VERSION_FILES = ep_version.h |
230 | 247 | ||
231 | define update_dir | 248 | define update_dir |
232 | (echo $1 > $@.tmp; \ | 249 | (echo $1 > $@.tmp; \ |
233 | if [ -r $@ ] && cmp -s $@ $@.tmp; then \ | 250 | if [ -r $@ ] && cmp -s $@ $@.tmp; then \ |
234 | rm -f $@.tmp; \ | 251 | rm -f $@.tmp; \ |
235 | else \ | 252 | else \ |
236 | echo ' UPDATE $@'; \ | 253 | echo ' UPDATE $@'; \ |
237 | mv -f $@.tmp $@; \ | 254 | mv -f $@.tmp $@; \ |
238 | fi); | 255 | fi); |
239 | endef | 256 | endef |
240 | 257 | ||
241 | ## make deps | 258 | ## make deps |
@@ -245,10 +262,10 @@ all_deps := $(all_objs:%.o=.%.d) | |||
245 | 262 | ||
246 | # let .d file also depends on the source and header files | 263 | # let .d file also depends on the source and header files |
247 | define check_deps | 264 | define check_deps |
248 | @set -e; $(RM) $@; \ | 265 | @set -e; $(RM) $@; \ |
249 | $(CC) -MM $(CFLAGS) $< > $@.$$$$; \ | 266 | $(CC) -MM $(CFLAGS) $< > $@.$$$$; \ |
250 | sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \ | 267 | sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \ |
251 | $(RM) $@.$$$$ | 268 | $(RM) $@.$$$$ |
252 | endef | 269 | endef |
253 | 270 | ||
254 | $(all_deps): .%.d: $(src)/%.c | 271 | $(all_deps): .%.d: $(src)/%.c |
@@ -283,27 +300,41 @@ TAGS: force | |||
283 | --regex='/_PE(\([^,)]*\).*/PEVENT_ERRNO__\1/' | 300 | --regex='/_PE(\([^,)]*\).*/PEVENT_ERRNO__\1/' |
284 | 301 | ||
285 | define do_install | 302 | define do_install |
286 | $(print_install) \ | ||
287 | if [ ! -d '$(DESTDIR_SQ)$2' ]; then \ | 303 | if [ ! -d '$(DESTDIR_SQ)$2' ]; then \ |
288 | $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$2'; \ | 304 | $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$2'; \ |
289 | fi; \ | 305 | fi; \ |
290 | $(INSTALL) $1 '$(DESTDIR_SQ)$2' | 306 | $(INSTALL) $1 '$(DESTDIR_SQ)$2' |
291 | endef | 307 | endef |
292 | 308 | ||
293 | install_lib: all_cmd | 309 | define do_install_plugins |
294 | $(Q)$(call do_install,$(LIB_FILE),$(bindir_SQ)) | 310 | for plugin in $1; do \ |
311 | $(call do_install,$$plugin,$(plugin_dir_SQ)); \ | ||
312 | done | ||
313 | endef | ||
314 | |||
315 | install_lib: all_cmd install_plugins | ||
316 | $(call QUIET_INSTALL, $(LIB_FILE)) \ | ||
317 | $(call do_install,$(LIB_FILE),$(bindir_SQ)) | ||
318 | |||
319 | install_plugins: $(PLUGINS) | ||
320 | $(call QUIET_INSTALL, trace_plugins) \ | ||
321 | $(call do_install_plugins, $(PLUGINS)) | ||
295 | 322 | ||
296 | install: install_lib | 323 | install: install_lib |
297 | 324 | ||
298 | clean: | 325 | clean: |
299 | $(RM) *.o *~ $(TARGETS) *.a *.so $(VERSION_FILES) .*.d | 326 | $(call QUIET_CLEAN, libtraceevent) \ |
300 | $(RM) TRACEEVENT-CFLAGS tags TAGS | 327 | $(RM) *.o *~ $(TARGETS) *.a *.so $(VERSION_FILES) .*.d \ |
328 | $(RM) TRACEEVENT-CFLAGS tags TAGS | ||
301 | 329 | ||
302 | endif # skip-makefile | 330 | endif # skip-makefile |
303 | 331 | ||
304 | PHONY += force | 332 | PHONY += force plugins |
305 | force: | 333 | force: |
306 | 334 | ||
335 | plugins: | ||
336 | @echo > /dev/null | ||
337 | |||
307 | # Declare the contents of the .PHONY variable as phony. We keep that | 338 | # Declare the contents of the .PHONY variable as phony. We keep that |
308 | # information in a variable so we can use it in if_changed and friends. | 339 | # information in a variable so we can use it in if_changed and friends. |
309 | .PHONY: $(PHONY) | 340 | .PHONY: $(PHONY) |
diff --git a/tools/lib/traceevent/event-parse.c b/tools/lib/traceevent/event-parse.c index 217c82ee3665..1587ea392ad6 100644 --- a/tools/lib/traceevent/event-parse.c +++ b/tools/lib/traceevent/event-parse.c | |||
@@ -2710,7 +2710,6 @@ process_func_handler(struct event_format *event, struct pevent_function_handler | |||
2710 | struct print_arg *farg; | 2710 | struct print_arg *farg; |
2711 | enum event_type type; | 2711 | enum event_type type; |
2712 | char *token; | 2712 | char *token; |
2713 | const char *test; | ||
2714 | int i; | 2713 | int i; |
2715 | 2714 | ||
2716 | arg->type = PRINT_FUNC; | 2715 | arg->type = PRINT_FUNC; |
@@ -2727,15 +2726,19 @@ process_func_handler(struct event_format *event, struct pevent_function_handler | |||
2727 | } | 2726 | } |
2728 | 2727 | ||
2729 | type = process_arg(event, farg, &token); | 2728 | type = process_arg(event, farg, &token); |
2730 | if (i < (func->nr_args - 1)) | 2729 | if (i < (func->nr_args - 1)) { |
2731 | test = ","; | 2730 | if (type != EVENT_DELIM || strcmp(token, ",") != 0) { |
2732 | else | 2731 | warning("Error: function '%s()' expects %d arguments but event %s only uses %d", |
2733 | test = ")"; | 2732 | func->name, func->nr_args, |
2734 | 2733 | event->name, i + 1); | |
2735 | if (test_type_token(type, token, EVENT_DELIM, test)) { | 2734 | goto err; |
2736 | free_arg(farg); | 2735 | } |
2737 | free_token(token); | 2736 | } else { |
2738 | return EVENT_ERROR; | 2737 | if (type != EVENT_DELIM || strcmp(token, ")") != 0) { |
2738 | warning("Error: function '%s()' only expects %d arguments but event %s has more", | ||
2739 | func->name, func->nr_args, event->name); | ||
2740 | goto err; | ||
2741 | } | ||
2739 | } | 2742 | } |
2740 | 2743 | ||
2741 | *next_arg = farg; | 2744 | *next_arg = farg; |
@@ -2747,6 +2750,11 @@ process_func_handler(struct event_format *event, struct pevent_function_handler | |||
2747 | *tok = token; | 2750 | *tok = token; |
2748 | 2751 | ||
2749 | return type; | 2752 | return type; |
2753 | |||
2754 | err: | ||
2755 | free_arg(farg); | ||
2756 | free_token(token); | ||
2757 | return EVENT_ERROR; | ||
2750 | } | 2758 | } |
2751 | 2759 | ||
2752 | static enum event_type | 2760 | static enum event_type |
@@ -4099,6 +4107,7 @@ static void pretty_print(struct trace_seq *s, void *data, int size, struct event | |||
4099 | unsigned long long val; | 4107 | unsigned long long val; |
4100 | struct func_map *func; | 4108 | struct func_map *func; |
4101 | const char *saveptr; | 4109 | const char *saveptr; |
4110 | struct trace_seq p; | ||
4102 | char *bprint_fmt = NULL; | 4111 | char *bprint_fmt = NULL; |
4103 | char format[32]; | 4112 | char format[32]; |
4104 | int show_func; | 4113 | int show_func; |
@@ -4306,8 +4315,12 @@ static void pretty_print(struct trace_seq *s, void *data, int size, struct event | |||
4306 | format[len] = 0; | 4315 | format[len] = 0; |
4307 | if (!len_as_arg) | 4316 | if (!len_as_arg) |
4308 | len_arg = -1; | 4317 | len_arg = -1; |
4309 | print_str_arg(s, data, size, event, | 4318 | /* Use helper trace_seq */ |
4319 | trace_seq_init(&p); | ||
4320 | print_str_arg(&p, data, size, event, | ||
4310 | format, len_arg, arg); | 4321 | format, len_arg, arg); |
4322 | trace_seq_terminate(&p); | ||
4323 | trace_seq_puts(s, p.buffer); | ||
4311 | arg = arg->next; | 4324 | arg = arg->next; |
4312 | break; | 4325 | break; |
4313 | default: | 4326 | default: |
@@ -5116,8 +5129,38 @@ enum pevent_errno __pevent_parse_format(struct event_format **eventp, | |||
5116 | return ret; | 5129 | return ret; |
5117 | } | 5130 | } |
5118 | 5131 | ||
5132 | static enum pevent_errno | ||
5133 | __pevent_parse_event(struct pevent *pevent, | ||
5134 | struct event_format **eventp, | ||
5135 | const char *buf, unsigned long size, | ||
5136 | const char *sys) | ||
5137 | { | ||
5138 | int ret = __pevent_parse_format(eventp, pevent, buf, size, sys); | ||
5139 | struct event_format *event = *eventp; | ||
5140 | |||
5141 | if (event == NULL) | ||
5142 | return ret; | ||
5143 | |||
5144 | if (pevent && add_event(pevent, event)) { | ||
5145 | ret = PEVENT_ERRNO__MEM_ALLOC_FAILED; | ||
5146 | goto event_add_failed; | ||
5147 | } | ||
5148 | |||
5149 | #define PRINT_ARGS 0 | ||
5150 | if (PRINT_ARGS && event->print_fmt.args) | ||
5151 | print_args(event->print_fmt.args); | ||
5152 | |||
5153 | return 0; | ||
5154 | |||
5155 | event_add_failed: | ||
5156 | pevent_free_format(event); | ||
5157 | return ret; | ||
5158 | } | ||
5159 | |||
5119 | /** | 5160 | /** |
5120 | * pevent_parse_format - parse the event format | 5161 | * pevent_parse_format - parse the event format |
5162 | * @pevent: the handle to the pevent | ||
5163 | * @eventp: returned format | ||
5121 | * @buf: the buffer storing the event format string | 5164 | * @buf: the buffer storing the event format string |
5122 | * @size: the size of @buf | 5165 | * @size: the size of @buf |
5123 | * @sys: the system the event belongs to | 5166 | * @sys: the system the event belongs to |
@@ -5129,10 +5172,12 @@ enum pevent_errno __pevent_parse_format(struct event_format **eventp, | |||
5129 | * | 5172 | * |
5130 | * /sys/kernel/debug/tracing/events/.../.../format | 5173 | * /sys/kernel/debug/tracing/events/.../.../format |
5131 | */ | 5174 | */ |
5132 | enum pevent_errno pevent_parse_format(struct event_format **eventp, const char *buf, | 5175 | enum pevent_errno pevent_parse_format(struct pevent *pevent, |
5176 | struct event_format **eventp, | ||
5177 | const char *buf, | ||
5133 | unsigned long size, const char *sys) | 5178 | unsigned long size, const char *sys) |
5134 | { | 5179 | { |
5135 | return __pevent_parse_format(eventp, NULL, buf, size, sys); | 5180 | return __pevent_parse_event(pevent, eventp, buf, size, sys); |
5136 | } | 5181 | } |
5137 | 5182 | ||
5138 | /** | 5183 | /** |
@@ -5153,25 +5198,7 @@ enum pevent_errno pevent_parse_event(struct pevent *pevent, const char *buf, | |||
5153 | unsigned long size, const char *sys) | 5198 | unsigned long size, const char *sys) |
5154 | { | 5199 | { |
5155 | struct event_format *event = NULL; | 5200 | struct event_format *event = NULL; |
5156 | int ret = __pevent_parse_format(&event, pevent, buf, size, sys); | 5201 | return __pevent_parse_event(pevent, &event, buf, size, sys); |
5157 | |||
5158 | if (event == NULL) | ||
5159 | return ret; | ||
5160 | |||
5161 | if (add_event(pevent, event)) { | ||
5162 | ret = PEVENT_ERRNO__MEM_ALLOC_FAILED; | ||
5163 | goto event_add_failed; | ||
5164 | } | ||
5165 | |||
5166 | #define PRINT_ARGS 0 | ||
5167 | if (PRINT_ARGS && event->print_fmt.args) | ||
5168 | print_args(event->print_fmt.args); | ||
5169 | |||
5170 | return 0; | ||
5171 | |||
5172 | event_add_failed: | ||
5173 | pevent_free_format(event); | ||
5174 | return ret; | ||
5175 | } | 5202 | } |
5176 | 5203 | ||
5177 | #undef _PE | 5204 | #undef _PE |
@@ -5203,22 +5230,7 @@ int pevent_strerror(struct pevent *pevent __maybe_unused, | |||
5203 | 5230 | ||
5204 | idx = errnum - __PEVENT_ERRNO__START - 1; | 5231 | idx = errnum - __PEVENT_ERRNO__START - 1; |
5205 | msg = pevent_error_str[idx]; | 5232 | msg = pevent_error_str[idx]; |
5206 | 5233 | snprintf(buf, buflen, "%s", msg); | |
5207 | switch (errnum) { | ||
5208 | case PEVENT_ERRNO__MEM_ALLOC_FAILED: | ||
5209 | case PEVENT_ERRNO__PARSE_EVENT_FAILED: | ||
5210 | case PEVENT_ERRNO__READ_ID_FAILED: | ||
5211 | case PEVENT_ERRNO__READ_FORMAT_FAILED: | ||
5212 | case PEVENT_ERRNO__READ_PRINT_FAILED: | ||
5213 | case PEVENT_ERRNO__OLD_FTRACE_ARG_FAILED: | ||
5214 | case PEVENT_ERRNO__INVALID_ARG_TYPE: | ||
5215 | snprintf(buf, buflen, "%s", msg); | ||
5216 | break; | ||
5217 | |||
5218 | default: | ||
5219 | /* cannot reach here */ | ||
5220 | break; | ||
5221 | } | ||
5222 | 5234 | ||
5223 | return 0; | 5235 | return 0; |
5224 | } | 5236 | } |
@@ -5549,6 +5561,52 @@ int pevent_register_print_function(struct pevent *pevent, | |||
5549 | } | 5561 | } |
5550 | 5562 | ||
5551 | /** | 5563 | /** |
5564 | * pevent_unregister_print_function - unregister a helper function | ||
5565 | * @pevent: the handle to the pevent | ||
5566 | * @func: the function to process the helper function | ||
5567 | * @name: the name of the helper function | ||
5568 | * | ||
5569 | * This function removes existing print handler for function @name. | ||
5570 | * | ||
5571 | * Returns 0 if the handler was removed successully, -1 otherwise. | ||
5572 | */ | ||
5573 | int pevent_unregister_print_function(struct pevent *pevent, | ||
5574 | pevent_func_handler func, char *name) | ||
5575 | { | ||
5576 | struct pevent_function_handler *func_handle; | ||
5577 | |||
5578 | func_handle = find_func_handler(pevent, name); | ||
5579 | if (func_handle && func_handle->func == func) { | ||
5580 | remove_func_handler(pevent, name); | ||
5581 | return 0; | ||
5582 | } | ||
5583 | return -1; | ||
5584 | } | ||
5585 | |||
5586 | static struct event_format *pevent_search_event(struct pevent *pevent, int id, | ||
5587 | const char *sys_name, | ||
5588 | const char *event_name) | ||
5589 | { | ||
5590 | struct event_format *event; | ||
5591 | |||
5592 | if (id >= 0) { | ||
5593 | /* search by id */ | ||
5594 | event = pevent_find_event(pevent, id); | ||
5595 | if (!event) | ||
5596 | return NULL; | ||
5597 | if (event_name && (strcmp(event_name, event->name) != 0)) | ||
5598 | return NULL; | ||
5599 | if (sys_name && (strcmp(sys_name, event->system) != 0)) | ||
5600 | return NULL; | ||
5601 | } else { | ||
5602 | event = pevent_find_event_by_name(pevent, sys_name, event_name); | ||
5603 | if (!event) | ||
5604 | return NULL; | ||
5605 | } | ||
5606 | return event; | ||
5607 | } | ||
5608 | |||
5609 | /** | ||
5552 | * pevent_register_event_handler - register a way to parse an event | 5610 | * pevent_register_event_handler - register a way to parse an event |
5553 | * @pevent: the handle to the pevent | 5611 | * @pevent: the handle to the pevent |
5554 | * @id: the id of the event to register | 5612 | * @id: the id of the event to register |
@@ -5572,20 +5630,9 @@ int pevent_register_event_handler(struct pevent *pevent, int id, | |||
5572 | struct event_format *event; | 5630 | struct event_format *event; |
5573 | struct event_handler *handle; | 5631 | struct event_handler *handle; |
5574 | 5632 | ||
5575 | if (id >= 0) { | 5633 | event = pevent_search_event(pevent, id, sys_name, event_name); |
5576 | /* search by id */ | 5634 | if (event == NULL) |
5577 | event = pevent_find_event(pevent, id); | 5635 | goto not_found; |
5578 | if (!event) | ||
5579 | goto not_found; | ||
5580 | if (event_name && (strcmp(event_name, event->name) != 0)) | ||
5581 | goto not_found; | ||
5582 | if (sys_name && (strcmp(sys_name, event->system) != 0)) | ||
5583 | goto not_found; | ||
5584 | } else { | ||
5585 | event = pevent_find_event_by_name(pevent, sys_name, event_name); | ||
5586 | if (!event) | ||
5587 | goto not_found; | ||
5588 | } | ||
5589 | 5636 | ||
5590 | pr_stat("overriding event (%d) %s:%s with new print handler", | 5637 | pr_stat("overriding event (%d) %s:%s with new print handler", |
5591 | event->id, event->system, event->name); | 5638 | event->id, event->system, event->name); |
@@ -5625,6 +5672,79 @@ int pevent_register_event_handler(struct pevent *pevent, int id, | |||
5625 | return -1; | 5672 | return -1; |
5626 | } | 5673 | } |
5627 | 5674 | ||
5675 | static int handle_matches(struct event_handler *handler, int id, | ||
5676 | const char *sys_name, const char *event_name, | ||
5677 | pevent_event_handler_func func, void *context) | ||
5678 | { | ||
5679 | if (id >= 0 && id != handler->id) | ||
5680 | return 0; | ||
5681 | |||
5682 | if (event_name && (strcmp(event_name, handler->event_name) != 0)) | ||
5683 | return 0; | ||
5684 | |||
5685 | if (sys_name && (strcmp(sys_name, handler->sys_name) != 0)) | ||
5686 | return 0; | ||
5687 | |||
5688 | if (func != handler->func || context != handler->context) | ||
5689 | return 0; | ||
5690 | |||
5691 | return 1; | ||
5692 | } | ||
5693 | |||
5694 | /** | ||
5695 | * pevent_unregister_event_handler - unregister an existing event handler | ||
5696 | * @pevent: the handle to the pevent | ||
5697 | * @id: the id of the event to unregister | ||
5698 | * @sys_name: the system name the handler belongs to | ||
5699 | * @event_name: the name of the event handler | ||
5700 | * @func: the function to call to parse the event information | ||
5701 | * @context: the data to be passed to @func | ||
5702 | * | ||
5703 | * This function removes existing event handler (parser). | ||
5704 | * | ||
5705 | * If @id is >= 0, then it is used to find the event. | ||
5706 | * else @sys_name and @event_name are used. | ||
5707 | * | ||
5708 | * Returns 0 if handler was removed successfully, -1 if event was not found. | ||
5709 | */ | ||
5710 | int pevent_unregister_event_handler(struct pevent *pevent, int id, | ||
5711 | const char *sys_name, const char *event_name, | ||
5712 | pevent_event_handler_func func, void *context) | ||
5713 | { | ||
5714 | struct event_format *event; | ||
5715 | struct event_handler *handle; | ||
5716 | struct event_handler **next; | ||
5717 | |||
5718 | event = pevent_search_event(pevent, id, sys_name, event_name); | ||
5719 | if (event == NULL) | ||
5720 | goto not_found; | ||
5721 | |||
5722 | if (event->handler == func && event->context == context) { | ||
5723 | pr_stat("removing override handler for event (%d) %s:%s. Going back to default handler.", | ||
5724 | event->id, event->system, event->name); | ||
5725 | |||
5726 | event->handler = NULL; | ||
5727 | event->context = NULL; | ||
5728 | return 0; | ||
5729 | } | ||
5730 | |||
5731 | not_found: | ||
5732 | for (next = &pevent->handlers; *next; next = &(*next)->next) { | ||
5733 | handle = *next; | ||
5734 | if (handle_matches(handle, id, sys_name, event_name, | ||
5735 | func, context)) | ||
5736 | break; | ||
5737 | } | ||
5738 | |||
5739 | if (!(*next)) | ||
5740 | return -1; | ||
5741 | |||
5742 | *next = handle->next; | ||
5743 | free_handler(handle); | ||
5744 | |||
5745 | return 0; | ||
5746 | } | ||
5747 | |||
5628 | /** | 5748 | /** |
5629 | * pevent_alloc - create a pevent handle | 5749 | * pevent_alloc - create a pevent handle |
5630 | */ | 5750 | */ |
diff --git a/tools/lib/traceevent/event-parse.h b/tools/lib/traceevent/event-parse.h index 8d73d2594f65..791c539374c7 100644 --- a/tools/lib/traceevent/event-parse.h +++ b/tools/lib/traceevent/event-parse.h | |||
@@ -23,6 +23,7 @@ | |||
23 | #include <stdbool.h> | 23 | #include <stdbool.h> |
24 | #include <stdarg.h> | 24 | #include <stdarg.h> |
25 | #include <regex.h> | 25 | #include <regex.h> |
26 | #include <string.h> | ||
26 | 27 | ||
27 | #ifndef __maybe_unused | 28 | #ifndef __maybe_unused |
28 | #define __maybe_unused __attribute__((unused)) | 29 | #define __maybe_unused __attribute__((unused)) |
@@ -57,6 +58,12 @@ struct pevent_record { | |||
57 | #endif | 58 | #endif |
58 | }; | 59 | }; |
59 | 60 | ||
61 | enum trace_seq_fail { | ||
62 | TRACE_SEQ__GOOD, | ||
63 | TRACE_SEQ__BUFFER_POISONED, | ||
64 | TRACE_SEQ__MEM_ALLOC_FAILED, | ||
65 | }; | ||
66 | |||
60 | /* | 67 | /* |
61 | * Trace sequences are used to allow a function to call several other functions | 68 | * Trace sequences are used to allow a function to call several other functions |
62 | * to create a string of data to use (up to a max of PAGE_SIZE). | 69 | * to create a string of data to use (up to a max of PAGE_SIZE). |
@@ -67,6 +74,7 @@ struct trace_seq { | |||
67 | unsigned int buffer_size; | 74 | unsigned int buffer_size; |
68 | unsigned int len; | 75 | unsigned int len; |
69 | unsigned int readpos; | 76 | unsigned int readpos; |
77 | enum trace_seq_fail state; | ||
70 | }; | 78 | }; |
71 | 79 | ||
72 | void trace_seq_init(struct trace_seq *s); | 80 | void trace_seq_init(struct trace_seq *s); |
@@ -97,7 +105,7 @@ typedef int (*pevent_event_handler_func)(struct trace_seq *s, | |||
97 | void *context); | 105 | void *context); |
98 | 106 | ||
99 | typedef int (*pevent_plugin_load_func)(struct pevent *pevent); | 107 | typedef int (*pevent_plugin_load_func)(struct pevent *pevent); |
100 | typedef int (*pevent_plugin_unload_func)(void); | 108 | typedef int (*pevent_plugin_unload_func)(struct pevent *pevent); |
101 | 109 | ||
102 | struct plugin_option { | 110 | struct plugin_option { |
103 | struct plugin_option *next; | 111 | struct plugin_option *next; |
@@ -122,7 +130,7 @@ struct plugin_option { | |||
122 | * PEVENT_PLUGIN_UNLOADER: (optional) | 130 | * PEVENT_PLUGIN_UNLOADER: (optional) |
123 | * The function called just before unloading | 131 | * The function called just before unloading |
124 | * | 132 | * |
125 | * int PEVENT_PLUGIN_UNLOADER(void) | 133 | * int PEVENT_PLUGIN_UNLOADER(struct pevent *pevent) |
126 | * | 134 | * |
127 | * PEVENT_PLUGIN_OPTIONS: (optional) | 135 | * PEVENT_PLUGIN_OPTIONS: (optional) |
128 | * Plugin options that can be set before loading | 136 | * Plugin options that can be set before loading |
@@ -355,12 +363,35 @@ enum pevent_flag { | |||
355 | _PE(READ_FORMAT_FAILED, "failed to read event format"), \ | 363 | _PE(READ_FORMAT_FAILED, "failed to read event format"), \ |
356 | _PE(READ_PRINT_FAILED, "failed to read event print fmt"), \ | 364 | _PE(READ_PRINT_FAILED, "failed to read event print fmt"), \ |
357 | _PE(OLD_FTRACE_ARG_FAILED,"failed to allocate field name for ftrace"),\ | 365 | _PE(OLD_FTRACE_ARG_FAILED,"failed to allocate field name for ftrace"),\ |
358 | _PE(INVALID_ARG_TYPE, "invalid argument type") | 366 | _PE(INVALID_ARG_TYPE, "invalid argument type"), \ |
367 | _PE(INVALID_EXP_TYPE, "invalid expression type"), \ | ||
368 | _PE(INVALID_OP_TYPE, "invalid operator type"), \ | ||
369 | _PE(INVALID_EVENT_NAME, "invalid event name"), \ | ||
370 | _PE(EVENT_NOT_FOUND, "no event found"), \ | ||
371 | _PE(SYNTAX_ERROR, "syntax error"), \ | ||
372 | _PE(ILLEGAL_RVALUE, "illegal rvalue"), \ | ||
373 | _PE(ILLEGAL_LVALUE, "illegal lvalue for string comparison"), \ | ||
374 | _PE(INVALID_REGEX, "regex did not compute"), \ | ||
375 | _PE(ILLEGAL_STRING_CMP, "illegal comparison for string"), \ | ||
376 | _PE(ILLEGAL_INTEGER_CMP,"illegal comparison for integer"), \ | ||
377 | _PE(REPARENT_NOT_OP, "cannot reparent other than OP"), \ | ||
378 | _PE(REPARENT_FAILED, "failed to reparent filter OP"), \ | ||
379 | _PE(BAD_FILTER_ARG, "bad arg in filter tree"), \ | ||
380 | _PE(UNEXPECTED_TYPE, "unexpected type (not a value)"), \ | ||
381 | _PE(ILLEGAL_TOKEN, "illegal token"), \ | ||
382 | _PE(INVALID_PAREN, "open parenthesis cannot come here"), \ | ||
383 | _PE(UNBALANCED_PAREN, "unbalanced number of parenthesis"), \ | ||
384 | _PE(UNKNOWN_TOKEN, "unknown token"), \ | ||
385 | _PE(FILTER_NOT_FOUND, "no filter found"), \ | ||
386 | _PE(NOT_A_NUMBER, "must have number field"), \ | ||
387 | _PE(NO_FILTER, "no filters exists"), \ | ||
388 | _PE(FILTER_MISS, "record does not match to filter") | ||
359 | 389 | ||
360 | #undef _PE | 390 | #undef _PE |
361 | #define _PE(__code, __str) PEVENT_ERRNO__ ## __code | 391 | #define _PE(__code, __str) PEVENT_ERRNO__ ## __code |
362 | enum pevent_errno { | 392 | enum pevent_errno { |
363 | PEVENT_ERRNO__SUCCESS = 0, | 393 | PEVENT_ERRNO__SUCCESS = 0, |
394 | PEVENT_ERRNO__FILTER_MATCH = PEVENT_ERRNO__SUCCESS, | ||
364 | 395 | ||
365 | /* | 396 | /* |
366 | * Choose an arbitrary negative big number not to clash with standard | 397 | * Choose an arbitrary negative big number not to clash with standard |
@@ -377,6 +408,12 @@ enum pevent_errno { | |||
377 | }; | 408 | }; |
378 | #undef _PE | 409 | #undef _PE |
379 | 410 | ||
411 | struct plugin_list; | ||
412 | |||
413 | struct plugin_list *traceevent_load_plugins(struct pevent *pevent); | ||
414 | void traceevent_unload_plugins(struct plugin_list *plugin_list, | ||
415 | struct pevent *pevent); | ||
416 | |||
380 | struct cmdline; | 417 | struct cmdline; |
381 | struct cmdline_list; | 418 | struct cmdline_list; |
382 | struct func_map; | 419 | struct func_map; |
@@ -522,6 +559,15 @@ __data2host8(struct pevent *pevent, unsigned long long data) | |||
522 | __data2host8(pevent, __val); \ | 559 | __data2host8(pevent, __val); \ |
523 | }) | 560 | }) |
524 | 561 | ||
562 | static inline int traceevent_host_bigendian(void) | ||
563 | { | ||
564 | unsigned char str[] = { 0x1, 0x2, 0x3, 0x4 }; | ||
565 | unsigned int val; | ||
566 | |||
567 | memcpy(&val, str, 4); | ||
568 | return val == 0x01020304; | ||
569 | } | ||
570 | |||
525 | /* taken from kernel/trace/trace.h */ | 571 | /* taken from kernel/trace/trace.h */ |
526 | enum trace_flag_type { | 572 | enum trace_flag_type { |
527 | TRACE_FLAG_IRQS_OFF = 0x01, | 573 | TRACE_FLAG_IRQS_OFF = 0x01, |
@@ -547,7 +593,9 @@ int pevent_parse_header_page(struct pevent *pevent, char *buf, unsigned long siz | |||
547 | 593 | ||
548 | enum pevent_errno pevent_parse_event(struct pevent *pevent, const char *buf, | 594 | enum pevent_errno pevent_parse_event(struct pevent *pevent, const char *buf, |
549 | unsigned long size, const char *sys); | 595 | unsigned long size, const char *sys); |
550 | enum pevent_errno pevent_parse_format(struct event_format **eventp, const char *buf, | 596 | enum pevent_errno pevent_parse_format(struct pevent *pevent, |
597 | struct event_format **eventp, | ||
598 | const char *buf, | ||
551 | unsigned long size, const char *sys); | 599 | unsigned long size, const char *sys); |
552 | void pevent_free_format(struct event_format *event); | 600 | void pevent_free_format(struct event_format *event); |
553 | 601 | ||
@@ -576,10 +624,15 @@ int pevent_print_func_field(struct trace_seq *s, const char *fmt, | |||
576 | int pevent_register_event_handler(struct pevent *pevent, int id, | 624 | int pevent_register_event_handler(struct pevent *pevent, int id, |
577 | const char *sys_name, const char *event_name, | 625 | const char *sys_name, const char *event_name, |
578 | pevent_event_handler_func func, void *context); | 626 | pevent_event_handler_func func, void *context); |
627 | int pevent_unregister_event_handler(struct pevent *pevent, int id, | ||
628 | const char *sys_name, const char *event_name, | ||
629 | pevent_event_handler_func func, void *context); | ||
579 | int pevent_register_print_function(struct pevent *pevent, | 630 | int pevent_register_print_function(struct pevent *pevent, |
580 | pevent_func_handler func, | 631 | pevent_func_handler func, |
581 | enum pevent_func_arg_type ret_type, | 632 | enum pevent_func_arg_type ret_type, |
582 | char *name, ...); | 633 | char *name, ...); |
634 | int pevent_unregister_print_function(struct pevent *pevent, | ||
635 | pevent_func_handler func, char *name); | ||
583 | 636 | ||
584 | struct format_field *pevent_find_common_field(struct event_format *event, const char *name); | 637 | struct format_field *pevent_find_common_field(struct event_format *event, const char *name); |
585 | struct format_field *pevent_find_field(struct event_format *event, const char *name); | 638 | struct format_field *pevent_find_field(struct event_format *event, const char *name); |
@@ -811,18 +864,22 @@ struct filter_type { | |||
811 | struct filter_arg *filter; | 864 | struct filter_arg *filter; |
812 | }; | 865 | }; |
813 | 866 | ||
867 | #define PEVENT_FILTER_ERROR_BUFSZ 1024 | ||
868 | |||
814 | struct event_filter { | 869 | struct event_filter { |
815 | struct pevent *pevent; | 870 | struct pevent *pevent; |
816 | int filters; | 871 | int filters; |
817 | struct filter_type *event_filters; | 872 | struct filter_type *event_filters; |
873 | char error_buffer[PEVENT_FILTER_ERROR_BUFSZ]; | ||
818 | }; | 874 | }; |
819 | 875 | ||
820 | struct event_filter *pevent_filter_alloc(struct pevent *pevent); | 876 | struct event_filter *pevent_filter_alloc(struct pevent *pevent); |
821 | 877 | ||
822 | #define FILTER_NONE -2 | 878 | /* for backward compatibility */ |
823 | #define FILTER_NOEXIST -1 | 879 | #define FILTER_NONE PEVENT_ERRNO__FILTER_NOT_FOUND |
824 | #define FILTER_MISS 0 | 880 | #define FILTER_NOEXIST PEVENT_ERRNO__NO_FILTER |
825 | #define FILTER_MATCH 1 | 881 | #define FILTER_MISS PEVENT_ERRNO__FILTER_MISS |
882 | #define FILTER_MATCH PEVENT_ERRNO__FILTER_MATCH | ||
826 | 883 | ||
827 | enum filter_trivial_type { | 884 | enum filter_trivial_type { |
828 | FILTER_TRIVIAL_FALSE, | 885 | FILTER_TRIVIAL_FALSE, |
@@ -830,20 +887,21 @@ enum filter_trivial_type { | |||
830 | FILTER_TRIVIAL_BOTH, | 887 | FILTER_TRIVIAL_BOTH, |
831 | }; | 888 | }; |
832 | 889 | ||
833 | int pevent_filter_add_filter_str(struct event_filter *filter, | 890 | enum pevent_errno pevent_filter_add_filter_str(struct event_filter *filter, |
834 | const char *filter_str, | 891 | const char *filter_str); |
835 | char **error_str); | ||
836 | 892 | ||
893 | enum pevent_errno pevent_filter_match(struct event_filter *filter, | ||
894 | struct pevent_record *record); | ||
837 | 895 | ||
838 | int pevent_filter_match(struct event_filter *filter, | 896 | int pevent_filter_strerror(struct event_filter *filter, enum pevent_errno err, |
839 | struct pevent_record *record); | 897 | char *buf, size_t buflen); |
840 | 898 | ||
841 | int pevent_event_filtered(struct event_filter *filter, | 899 | int pevent_event_filtered(struct event_filter *filter, |
842 | int event_id); | 900 | int event_id); |
843 | 901 | ||
844 | void pevent_filter_reset(struct event_filter *filter); | 902 | void pevent_filter_reset(struct event_filter *filter); |
845 | 903 | ||
846 | void pevent_filter_clear_trivial(struct event_filter *filter, | 904 | int pevent_filter_clear_trivial(struct event_filter *filter, |
847 | enum filter_trivial_type type); | 905 | enum filter_trivial_type type); |
848 | 906 | ||
849 | void pevent_filter_free(struct event_filter *filter); | 907 | void pevent_filter_free(struct event_filter *filter); |
diff --git a/tools/lib/traceevent/event-plugin.c b/tools/lib/traceevent/event-plugin.c new file mode 100644 index 000000000000..0c8bf6780e4d --- /dev/null +++ b/tools/lib/traceevent/event-plugin.c | |||
@@ -0,0 +1,215 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2009, 2010 Red Hat Inc, Steven Rostedt <srostedt@redhat.com> | ||
3 | * | ||
4 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
5 | * This program is free software; you can redistribute it and/or | ||
6 | * modify it under the terms of the GNU Lesser General Public | ||
7 | * License as published by the Free Software Foundation; | ||
8 | * version 2.1 of the License (not later!) | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU Lesser General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU Lesser General Public | ||
16 | * License along with this program; if not, see <http://www.gnu.org/licenses> | ||
17 | * | ||
18 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
19 | */ | ||
20 | |||
21 | #include <string.h> | ||
22 | #include <dlfcn.h> | ||
23 | #include <stdlib.h> | ||
24 | #include <sys/types.h> | ||
25 | #include <sys/stat.h> | ||
26 | #include <unistd.h> | ||
27 | #include <dirent.h> | ||
28 | #include "event-parse.h" | ||
29 | #include "event-utils.h" | ||
30 | |||
31 | #define LOCAL_PLUGIN_DIR ".traceevent/plugins" | ||
32 | |||
33 | struct plugin_list { | ||
34 | struct plugin_list *next; | ||
35 | char *name; | ||
36 | void *handle; | ||
37 | }; | ||
38 | |||
39 | static void | ||
40 | load_plugin(struct pevent *pevent, const char *path, | ||
41 | const char *file, void *data) | ||
42 | { | ||
43 | struct plugin_list **plugin_list = data; | ||
44 | pevent_plugin_load_func func; | ||
45 | struct plugin_list *list; | ||
46 | const char *alias; | ||
47 | char *plugin; | ||
48 | void *handle; | ||
49 | |||
50 | plugin = malloc(strlen(path) + strlen(file) + 2); | ||
51 | if (!plugin) { | ||
52 | warning("could not allocate plugin memory\n"); | ||
53 | return; | ||
54 | } | ||
55 | |||
56 | strcpy(plugin, path); | ||
57 | strcat(plugin, "/"); | ||
58 | strcat(plugin, file); | ||
59 | |||
60 | handle = dlopen(plugin, RTLD_NOW | RTLD_GLOBAL); | ||
61 | if (!handle) { | ||
62 | warning("could not load plugin '%s'\n%s\n", | ||
63 | plugin, dlerror()); | ||
64 | goto out_free; | ||
65 | } | ||
66 | |||
67 | alias = dlsym(handle, PEVENT_PLUGIN_ALIAS_NAME); | ||
68 | if (!alias) | ||
69 | alias = file; | ||
70 | |||
71 | func = dlsym(handle, PEVENT_PLUGIN_LOADER_NAME); | ||
72 | if (!func) { | ||
73 | warning("could not find func '%s' in plugin '%s'\n%s\n", | ||
74 | PEVENT_PLUGIN_LOADER_NAME, plugin, dlerror()); | ||
75 | goto out_free; | ||
76 | } | ||
77 | |||
78 | list = malloc(sizeof(*list)); | ||
79 | if (!list) { | ||
80 | warning("could not allocate plugin memory\n"); | ||
81 | goto out_free; | ||
82 | } | ||
83 | |||
84 | list->next = *plugin_list; | ||
85 | list->handle = handle; | ||
86 | list->name = plugin; | ||
87 | *plugin_list = list; | ||
88 | |||
89 | pr_stat("registering plugin: %s", plugin); | ||
90 | func(pevent); | ||
91 | return; | ||
92 | |||
93 | out_free: | ||
94 | free(plugin); | ||
95 | } | ||
96 | |||
97 | static void | ||
98 | load_plugins_dir(struct pevent *pevent, const char *suffix, | ||
99 | const char *path, | ||
100 | void (*load_plugin)(struct pevent *pevent, | ||
101 | const char *path, | ||
102 | const char *name, | ||
103 | void *data), | ||
104 | void *data) | ||
105 | { | ||
106 | struct dirent *dent; | ||
107 | struct stat st; | ||
108 | DIR *dir; | ||
109 | int ret; | ||
110 | |||
111 | ret = stat(path, &st); | ||
112 | if (ret < 0) | ||
113 | return; | ||
114 | |||
115 | if (!S_ISDIR(st.st_mode)) | ||
116 | return; | ||
117 | |||
118 | dir = opendir(path); | ||
119 | if (!dir) | ||
120 | return; | ||
121 | |||
122 | while ((dent = readdir(dir))) { | ||
123 | const char *name = dent->d_name; | ||
124 | |||
125 | if (strcmp(name, ".") == 0 || | ||
126 | strcmp(name, "..") == 0) | ||
127 | continue; | ||
128 | |||
129 | /* Only load plugins that end in suffix */ | ||
130 | if (strcmp(name + (strlen(name) - strlen(suffix)), suffix) != 0) | ||
131 | continue; | ||
132 | |||
133 | load_plugin(pevent, path, name, data); | ||
134 | } | ||
135 | |||
136 | closedir(dir); | ||
137 | } | ||
138 | |||
139 | static void | ||
140 | load_plugins(struct pevent *pevent, const char *suffix, | ||
141 | void (*load_plugin)(struct pevent *pevent, | ||
142 | const char *path, | ||
143 | const char *name, | ||
144 | void *data), | ||
145 | void *data) | ||
146 | { | ||
147 | char *home; | ||
148 | char *path; | ||
149 | char *envdir; | ||
150 | |||
151 | /* | ||
152 | * If a system plugin directory was defined, | ||
153 | * check that first. | ||
154 | */ | ||
155 | #ifdef PLUGIN_DIR | ||
156 | load_plugins_dir(pevent, suffix, PLUGIN_DIR, load_plugin, data); | ||
157 | #endif | ||
158 | |||
159 | /* | ||
160 | * Next let the environment-set plugin directory | ||
161 | * override the system defaults. | ||
162 | */ | ||
163 | envdir = getenv("TRACEEVENT_PLUGIN_DIR"); | ||
164 | if (envdir) | ||
165 | load_plugins_dir(pevent, suffix, envdir, load_plugin, data); | ||
166 | |||
167 | /* | ||
168 | * Now let the home directory override the environment | ||
169 | * or system defaults. | ||
170 | */ | ||
171 | home = getenv("HOME"); | ||
172 | if (!home) | ||
173 | return; | ||
174 | |||
175 | path = malloc(strlen(home) + strlen(LOCAL_PLUGIN_DIR) + 2); | ||
176 | if (!path) { | ||
177 | warning("could not allocate plugin memory\n"); | ||
178 | return; | ||
179 | } | ||
180 | |||
181 | strcpy(path, home); | ||
182 | strcat(path, "/"); | ||
183 | strcat(path, LOCAL_PLUGIN_DIR); | ||
184 | |||
185 | load_plugins_dir(pevent, suffix, path, load_plugin, data); | ||
186 | |||
187 | free(path); | ||
188 | } | ||
189 | |||
190 | struct plugin_list* | ||
191 | traceevent_load_plugins(struct pevent *pevent) | ||
192 | { | ||
193 | struct plugin_list *list = NULL; | ||
194 | |||
195 | load_plugins(pevent, ".so", load_plugin, &list); | ||
196 | return list; | ||
197 | } | ||
198 | |||
199 | void | ||
200 | traceevent_unload_plugins(struct plugin_list *plugin_list, struct pevent *pevent) | ||
201 | { | ||
202 | pevent_plugin_unload_func func; | ||
203 | struct plugin_list *list; | ||
204 | |||
205 | while (plugin_list) { | ||
206 | list = plugin_list; | ||
207 | plugin_list = list->next; | ||
208 | func = dlsym(list->handle, PEVENT_PLUGIN_UNLOADER_NAME); | ||
209 | if (func) | ||
210 | func(pevent); | ||
211 | dlclose(list->handle); | ||
212 | free(list->name); | ||
213 | free(list); | ||
214 | } | ||
215 | } | ||
diff --git a/tools/lib/traceevent/event-utils.h b/tools/lib/traceevent/event-utils.h index e76c9acb92cd..d1dc2170e402 100644 --- a/tools/lib/traceevent/event-utils.h +++ b/tools/lib/traceevent/event-utils.h | |||
@@ -23,18 +23,14 @@ | |||
23 | #include <ctype.h> | 23 | #include <ctype.h> |
24 | 24 | ||
25 | /* Can be overridden */ | 25 | /* Can be overridden */ |
26 | void die(const char *fmt, ...); | ||
27 | void *malloc_or_die(unsigned int size); | ||
28 | void warning(const char *fmt, ...); | 26 | void warning(const char *fmt, ...); |
29 | void pr_stat(const char *fmt, ...); | 27 | void pr_stat(const char *fmt, ...); |
30 | void vpr_stat(const char *fmt, va_list ap); | 28 | void vpr_stat(const char *fmt, va_list ap); |
31 | 29 | ||
32 | /* Always available */ | 30 | /* Always available */ |
33 | void __die(const char *fmt, ...); | ||
34 | void __warning(const char *fmt, ...); | 31 | void __warning(const char *fmt, ...); |
35 | void __pr_stat(const char *fmt, ...); | 32 | void __pr_stat(const char *fmt, ...); |
36 | 33 | ||
37 | void __vdie(const char *fmt, ...); | ||
38 | void __vwarning(const char *fmt, ...); | 34 | void __vwarning(const char *fmt, ...); |
39 | void __vpr_stat(const char *fmt, ...); | 35 | void __vpr_stat(const char *fmt, ...); |
40 | 36 | ||
diff --git a/tools/lib/traceevent/parse-filter.c b/tools/lib/traceevent/parse-filter.c index 2500e75583fc..b50234402fc2 100644 --- a/tools/lib/traceevent/parse-filter.c +++ b/tools/lib/traceevent/parse-filter.c | |||
@@ -38,41 +38,31 @@ struct event_list { | |||
38 | struct event_format *event; | 38 | struct event_format *event; |
39 | }; | 39 | }; |
40 | 40 | ||
41 | #define MAX_ERR_STR_SIZE 256 | 41 | static void show_error(char *error_buf, const char *fmt, ...) |
42 | |||
43 | static void show_error(char **error_str, const char *fmt, ...) | ||
44 | { | 42 | { |
45 | unsigned long long index; | 43 | unsigned long long index; |
46 | const char *input; | 44 | const char *input; |
47 | char *error; | ||
48 | va_list ap; | 45 | va_list ap; |
49 | int len; | 46 | int len; |
50 | int i; | 47 | int i; |
51 | 48 | ||
52 | if (!error_str) | ||
53 | return; | ||
54 | |||
55 | input = pevent_get_input_buf(); | 49 | input = pevent_get_input_buf(); |
56 | index = pevent_get_input_buf_ptr(); | 50 | index = pevent_get_input_buf_ptr(); |
57 | len = input ? strlen(input) : 0; | 51 | len = input ? strlen(input) : 0; |
58 | 52 | ||
59 | error = malloc_or_die(MAX_ERR_STR_SIZE + (len*2) + 3); | ||
60 | |||
61 | if (len) { | 53 | if (len) { |
62 | strcpy(error, input); | 54 | strcpy(error_buf, input); |
63 | error[len] = '\n'; | 55 | error_buf[len] = '\n'; |
64 | for (i = 1; i < len && i < index; i++) | 56 | for (i = 1; i < len && i < index; i++) |
65 | error[len+i] = ' '; | 57 | error_buf[len+i] = ' '; |
66 | error[len + i] = '^'; | 58 | error_buf[len + i] = '^'; |
67 | error[len + i + 1] = '\n'; | 59 | error_buf[len + i + 1] = '\n'; |
68 | len += i+2; | 60 | len += i+2; |
69 | } | 61 | } |
70 | 62 | ||
71 | va_start(ap, fmt); | 63 | va_start(ap, fmt); |
72 | vsnprintf(error + len, MAX_ERR_STR_SIZE, fmt, ap); | 64 | vsnprintf(error_buf + len, PEVENT_FILTER_ERROR_BUFSZ - len, fmt, ap); |
73 | va_end(ap); | 65 | va_end(ap); |
74 | |||
75 | *error_str = error; | ||
76 | } | 66 | } |
77 | 67 | ||
78 | static void free_token(char *token) | 68 | static void free_token(char *token) |
@@ -95,7 +85,11 @@ static enum event_type read_token(char **tok) | |||
95 | (strcmp(token, "=") == 0 || strcmp(token, "!") == 0) && | 85 | (strcmp(token, "=") == 0 || strcmp(token, "!") == 0) && |
96 | pevent_peek_char() == '~') { | 86 | pevent_peek_char() == '~') { |
97 | /* append it */ | 87 | /* append it */ |
98 | *tok = malloc_or_die(3); | 88 | *tok = malloc(3); |
89 | if (*tok == NULL) { | ||
90 | free_token(token); | ||
91 | return EVENT_ERROR; | ||
92 | } | ||
99 | sprintf(*tok, "%c%c", *token, '~'); | 93 | sprintf(*tok, "%c%c", *token, '~'); |
100 | free_token(token); | 94 | free_token(token); |
101 | /* Now remove the '~' from the buffer */ | 95 | /* Now remove the '~' from the buffer */ |
@@ -147,11 +141,13 @@ add_filter_type(struct event_filter *filter, int id) | |||
147 | if (filter_type) | 141 | if (filter_type) |
148 | return filter_type; | 142 | return filter_type; |
149 | 143 | ||
150 | filter->event_filters = realloc(filter->event_filters, | 144 | filter_type = realloc(filter->event_filters, |
151 | sizeof(*filter->event_filters) * | 145 | sizeof(*filter->event_filters) * |
152 | (filter->filters + 1)); | 146 | (filter->filters + 1)); |
153 | if (!filter->event_filters) | 147 | if (!filter_type) |
154 | die("Could not allocate filter"); | 148 | return NULL; |
149 | |||
150 | filter->event_filters = filter_type; | ||
155 | 151 | ||
156 | for (i = 0; i < filter->filters; i++) { | 152 | for (i = 0; i < filter->filters; i++) { |
157 | if (filter->event_filters[i].event_id > id) | 153 | if (filter->event_filters[i].event_id > id) |
@@ -182,7 +178,10 @@ struct event_filter *pevent_filter_alloc(struct pevent *pevent) | |||
182 | { | 178 | { |
183 | struct event_filter *filter; | 179 | struct event_filter *filter; |
184 | 180 | ||
185 | filter = malloc_or_die(sizeof(*filter)); | 181 | filter = malloc(sizeof(*filter)); |
182 | if (filter == NULL) | ||
183 | return NULL; | ||
184 | |||
186 | memset(filter, 0, sizeof(*filter)); | 185 | memset(filter, 0, sizeof(*filter)); |
187 | filter->pevent = pevent; | 186 | filter->pevent = pevent; |
188 | pevent_ref(pevent); | 187 | pevent_ref(pevent); |
@@ -192,12 +191,7 @@ struct event_filter *pevent_filter_alloc(struct pevent *pevent) | |||
192 | 191 | ||
193 | static struct filter_arg *allocate_arg(void) | 192 | static struct filter_arg *allocate_arg(void) |
194 | { | 193 | { |
195 | struct filter_arg *arg; | 194 | return calloc(1, sizeof(struct filter_arg)); |
196 | |||
197 | arg = malloc_or_die(sizeof(*arg)); | ||
198 | memset(arg, 0, sizeof(*arg)); | ||
199 | |||
200 | return arg; | ||
201 | } | 195 | } |
202 | 196 | ||
203 | static void free_arg(struct filter_arg *arg) | 197 | static void free_arg(struct filter_arg *arg) |
@@ -242,15 +236,19 @@ static void free_arg(struct filter_arg *arg) | |||
242 | free(arg); | 236 | free(arg); |
243 | } | 237 | } |
244 | 238 | ||
245 | static void add_event(struct event_list **events, | 239 | static int add_event(struct event_list **events, |
246 | struct event_format *event) | 240 | struct event_format *event) |
247 | { | 241 | { |
248 | struct event_list *list; | 242 | struct event_list *list; |
249 | 243 | ||
250 | list = malloc_or_die(sizeof(*list)); | 244 | list = malloc(sizeof(*list)); |
245 | if (list == NULL) | ||
246 | return -1; | ||
247 | |||
251 | list->next = *events; | 248 | list->next = *events; |
252 | *events = list; | 249 | *events = list; |
253 | list->event = event; | 250 | list->event = event; |
251 | return 0; | ||
254 | } | 252 | } |
255 | 253 | ||
256 | static int event_match(struct event_format *event, | 254 | static int event_match(struct event_format *event, |
@@ -265,7 +263,7 @@ static int event_match(struct event_format *event, | |||
265 | !regexec(ereg, event->name, 0, NULL, 0); | 263 | !regexec(ereg, event->name, 0, NULL, 0); |
266 | } | 264 | } |
267 | 265 | ||
268 | static int | 266 | static enum pevent_errno |
269 | find_event(struct pevent *pevent, struct event_list **events, | 267 | find_event(struct pevent *pevent, struct event_list **events, |
270 | char *sys_name, char *event_name) | 268 | char *sys_name, char *event_name) |
271 | { | 269 | { |
@@ -273,6 +271,7 @@ find_event(struct pevent *pevent, struct event_list **events, | |||
273 | regex_t ereg; | 271 | regex_t ereg; |
274 | regex_t sreg; | 272 | regex_t sreg; |
275 | int match = 0; | 273 | int match = 0; |
274 | int fail = 0; | ||
276 | char *reg; | 275 | char *reg; |
277 | int ret; | 276 | int ret; |
278 | int i; | 277 | int i; |
@@ -283,23 +282,31 @@ find_event(struct pevent *pevent, struct event_list **events, | |||
283 | sys_name = NULL; | 282 | sys_name = NULL; |
284 | } | 283 | } |
285 | 284 | ||
286 | reg = malloc_or_die(strlen(event_name) + 3); | 285 | reg = malloc(strlen(event_name) + 3); |
286 | if (reg == NULL) | ||
287 | return PEVENT_ERRNO__MEM_ALLOC_FAILED; | ||
288 | |||
287 | sprintf(reg, "^%s$", event_name); | 289 | sprintf(reg, "^%s$", event_name); |
288 | 290 | ||
289 | ret = regcomp(&ereg, reg, REG_ICASE|REG_NOSUB); | 291 | ret = regcomp(&ereg, reg, REG_ICASE|REG_NOSUB); |
290 | free(reg); | 292 | free(reg); |
291 | 293 | ||
292 | if (ret) | 294 | if (ret) |
293 | return -1; | 295 | return PEVENT_ERRNO__INVALID_EVENT_NAME; |
294 | 296 | ||
295 | if (sys_name) { | 297 | if (sys_name) { |
296 | reg = malloc_or_die(strlen(sys_name) + 3); | 298 | reg = malloc(strlen(sys_name) + 3); |
299 | if (reg == NULL) { | ||
300 | regfree(&ereg); | ||
301 | return PEVENT_ERRNO__MEM_ALLOC_FAILED; | ||
302 | } | ||
303 | |||
297 | sprintf(reg, "^%s$", sys_name); | 304 | sprintf(reg, "^%s$", sys_name); |
298 | ret = regcomp(&sreg, reg, REG_ICASE|REG_NOSUB); | 305 | ret = regcomp(&sreg, reg, REG_ICASE|REG_NOSUB); |
299 | free(reg); | 306 | free(reg); |
300 | if (ret) { | 307 | if (ret) { |
301 | regfree(&ereg); | 308 | regfree(&ereg); |
302 | return -1; | 309 | return PEVENT_ERRNO__INVALID_EVENT_NAME; |
303 | } | 310 | } |
304 | } | 311 | } |
305 | 312 | ||
@@ -307,7 +314,10 @@ find_event(struct pevent *pevent, struct event_list **events, | |||
307 | event = pevent->events[i]; | 314 | event = pevent->events[i]; |
308 | if (event_match(event, sys_name ? &sreg : NULL, &ereg)) { | 315 | if (event_match(event, sys_name ? &sreg : NULL, &ereg)) { |
309 | match = 1; | 316 | match = 1; |
310 | add_event(events, event); | 317 | if (add_event(events, event) < 0) { |
318 | fail = 1; | ||
319 | break; | ||
320 | } | ||
311 | } | 321 | } |
312 | } | 322 | } |
313 | 323 | ||
@@ -316,7 +326,9 @@ find_event(struct pevent *pevent, struct event_list **events, | |||
316 | regfree(&sreg); | 326 | regfree(&sreg); |
317 | 327 | ||
318 | if (!match) | 328 | if (!match) |
319 | return -1; | 329 | return PEVENT_ERRNO__EVENT_NOT_FOUND; |
330 | if (fail) | ||
331 | return PEVENT_ERRNO__MEM_ALLOC_FAILED; | ||
320 | 332 | ||
321 | return 0; | 333 | return 0; |
322 | } | 334 | } |
@@ -332,14 +344,18 @@ static void free_events(struct event_list *events) | |||
332 | } | 344 | } |
333 | } | 345 | } |
334 | 346 | ||
335 | static struct filter_arg * | 347 | static enum pevent_errno |
336 | create_arg_item(struct event_format *event, const char *token, | 348 | create_arg_item(struct event_format *event, const char *token, |
337 | enum event_type type, char **error_str) | 349 | enum event_type type, struct filter_arg **parg, char *error_str) |
338 | { | 350 | { |
339 | struct format_field *field; | 351 | struct format_field *field; |
340 | struct filter_arg *arg; | 352 | struct filter_arg *arg; |
341 | 353 | ||
342 | arg = allocate_arg(); | 354 | arg = allocate_arg(); |
355 | if (arg == NULL) { | ||
356 | show_error(error_str, "failed to allocate filter arg"); | ||
357 | return PEVENT_ERRNO__MEM_ALLOC_FAILED; | ||
358 | } | ||
343 | 359 | ||
344 | switch (type) { | 360 | switch (type) { |
345 | 361 | ||
@@ -349,8 +365,11 @@ create_arg_item(struct event_format *event, const char *token, | |||
349 | arg->value.type = | 365 | arg->value.type = |
350 | type == EVENT_DQUOTE ? FILTER_STRING : FILTER_CHAR; | 366 | type == EVENT_DQUOTE ? FILTER_STRING : FILTER_CHAR; |
351 | arg->value.str = strdup(token); | 367 | arg->value.str = strdup(token); |
352 | if (!arg->value.str) | 368 | if (!arg->value.str) { |
353 | die("malloc string"); | 369 | free_arg(arg); |
370 | show_error(error_str, "failed to allocate string filter arg"); | ||
371 | return PEVENT_ERRNO__MEM_ALLOC_FAILED; | ||
372 | } | ||
354 | break; | 373 | break; |
355 | case EVENT_ITEM: | 374 | case EVENT_ITEM: |
356 | /* if it is a number, then convert it */ | 375 | /* if it is a number, then convert it */ |
@@ -377,11 +396,11 @@ create_arg_item(struct event_format *event, const char *token, | |||
377 | break; | 396 | break; |
378 | default: | 397 | default: |
379 | free_arg(arg); | 398 | free_arg(arg); |
380 | show_error(error_str, "expected a value but found %s", | 399 | show_error(error_str, "expected a value but found %s", token); |
381 | token); | 400 | return PEVENT_ERRNO__UNEXPECTED_TYPE; |
382 | return NULL; | ||
383 | } | 401 | } |
384 | return arg; | 402 | *parg = arg; |
403 | return 0; | ||
385 | } | 404 | } |
386 | 405 | ||
387 | static struct filter_arg * | 406 | static struct filter_arg * |
@@ -390,6 +409,9 @@ create_arg_op(enum filter_op_type btype) | |||
390 | struct filter_arg *arg; | 409 | struct filter_arg *arg; |
391 | 410 | ||
392 | arg = allocate_arg(); | 411 | arg = allocate_arg(); |
412 | if (!arg) | ||
413 | return NULL; | ||
414 | |||
393 | arg->type = FILTER_ARG_OP; | 415 | arg->type = FILTER_ARG_OP; |
394 | arg->op.type = btype; | 416 | arg->op.type = btype; |
395 | 417 | ||
@@ -402,6 +424,9 @@ create_arg_exp(enum filter_exp_type etype) | |||
402 | struct filter_arg *arg; | 424 | struct filter_arg *arg; |
403 | 425 | ||
404 | arg = allocate_arg(); | 426 | arg = allocate_arg(); |
427 | if (!arg) | ||
428 | return NULL; | ||
429 | |||
405 | arg->type = FILTER_ARG_EXP; | 430 | arg->type = FILTER_ARG_EXP; |
406 | arg->op.type = etype; | 431 | arg->op.type = etype; |
407 | 432 | ||
@@ -414,6 +439,9 @@ create_arg_cmp(enum filter_exp_type etype) | |||
414 | struct filter_arg *arg; | 439 | struct filter_arg *arg; |
415 | 440 | ||
416 | arg = allocate_arg(); | 441 | arg = allocate_arg(); |
442 | if (!arg) | ||
443 | return NULL; | ||
444 | |||
417 | /* Use NUM and change if necessary */ | 445 | /* Use NUM and change if necessary */ |
418 | arg->type = FILTER_ARG_NUM; | 446 | arg->type = FILTER_ARG_NUM; |
419 | arg->op.type = etype; | 447 | arg->op.type = etype; |
@@ -421,8 +449,8 @@ create_arg_cmp(enum filter_exp_type etype) | |||
421 | return arg; | 449 | return arg; |
422 | } | 450 | } |
423 | 451 | ||
424 | static int add_right(struct filter_arg *op, struct filter_arg *arg, | 452 | static enum pevent_errno |
425 | char **error_str) | 453 | add_right(struct filter_arg *op, struct filter_arg *arg, char *error_str) |
426 | { | 454 | { |
427 | struct filter_arg *left; | 455 | struct filter_arg *left; |
428 | char *str; | 456 | char *str; |
@@ -453,9 +481,8 @@ static int add_right(struct filter_arg *op, struct filter_arg *arg, | |||
453 | case FILTER_ARG_FIELD: | 481 | case FILTER_ARG_FIELD: |
454 | break; | 482 | break; |
455 | default: | 483 | default: |
456 | show_error(error_str, | 484 | show_error(error_str, "Illegal rvalue"); |
457 | "Illegal rvalue"); | 485 | return PEVENT_ERRNO__ILLEGAL_RVALUE; |
458 | return -1; | ||
459 | } | 486 | } |
460 | 487 | ||
461 | /* | 488 | /* |
@@ -502,7 +529,7 @@ static int add_right(struct filter_arg *op, struct filter_arg *arg, | |||
502 | if (left->type != FILTER_ARG_FIELD) { | 529 | if (left->type != FILTER_ARG_FIELD) { |
503 | show_error(error_str, | 530 | show_error(error_str, |
504 | "Illegal lvalue for string comparison"); | 531 | "Illegal lvalue for string comparison"); |
505 | return -1; | 532 | return PEVENT_ERRNO__ILLEGAL_LVALUE; |
506 | } | 533 | } |
507 | 534 | ||
508 | /* Make sure this is a valid string compare */ | 535 | /* Make sure this is a valid string compare */ |
@@ -521,25 +548,31 @@ static int add_right(struct filter_arg *op, struct filter_arg *arg, | |||
521 | show_error(error_str, | 548 | show_error(error_str, |
522 | "RegEx '%s' did not compute", | 549 | "RegEx '%s' did not compute", |
523 | str); | 550 | str); |
524 | return -1; | 551 | return PEVENT_ERRNO__INVALID_REGEX; |
525 | } | 552 | } |
526 | break; | 553 | break; |
527 | default: | 554 | default: |
528 | show_error(error_str, | 555 | show_error(error_str, |
529 | "Illegal comparison for string"); | 556 | "Illegal comparison for string"); |
530 | return -1; | 557 | return PEVENT_ERRNO__ILLEGAL_STRING_CMP; |
531 | } | 558 | } |
532 | 559 | ||
533 | op->type = FILTER_ARG_STR; | 560 | op->type = FILTER_ARG_STR; |
534 | op->str.type = op_type; | 561 | op->str.type = op_type; |
535 | op->str.field = left->field.field; | 562 | op->str.field = left->field.field; |
536 | op->str.val = strdup(str); | 563 | op->str.val = strdup(str); |
537 | if (!op->str.val) | 564 | if (!op->str.val) { |
538 | die("malloc string"); | 565 | show_error(error_str, "Failed to allocate string filter"); |
566 | return PEVENT_ERRNO__MEM_ALLOC_FAILED; | ||
567 | } | ||
539 | /* | 568 | /* |
540 | * Need a buffer to copy data for tests | 569 | * Need a buffer to copy data for tests |
541 | */ | 570 | */ |
542 | op->str.buffer = malloc_or_die(op->str.field->size + 1); | 571 | op->str.buffer = malloc(op->str.field->size + 1); |
572 | if (!op->str.buffer) { | ||
573 | show_error(error_str, "Failed to allocate string filter"); | ||
574 | return PEVENT_ERRNO__MEM_ALLOC_FAILED; | ||
575 | } | ||
543 | /* Null terminate this buffer */ | 576 | /* Null terminate this buffer */ |
544 | op->str.buffer[op->str.field->size] = 0; | 577 | op->str.buffer[op->str.field->size] = 0; |
545 | 578 | ||
@@ -557,7 +590,7 @@ static int add_right(struct filter_arg *op, struct filter_arg *arg, | |||
557 | case FILTER_CMP_NOT_REGEX: | 590 | case FILTER_CMP_NOT_REGEX: |
558 | show_error(error_str, | 591 | show_error(error_str, |
559 | "Op not allowed with integers"); | 592 | "Op not allowed with integers"); |
560 | return -1; | 593 | return PEVENT_ERRNO__ILLEGAL_INTEGER_CMP; |
561 | 594 | ||
562 | default: | 595 | default: |
563 | break; | 596 | break; |
@@ -577,9 +610,8 @@ static int add_right(struct filter_arg *op, struct filter_arg *arg, | |||
577 | return 0; | 610 | return 0; |
578 | 611 | ||
579 | out_fail: | 612 | out_fail: |
580 | show_error(error_str, | 613 | show_error(error_str, "Syntax error"); |
581 | "Syntax error"); | 614 | return PEVENT_ERRNO__SYNTAX_ERROR; |
582 | return -1; | ||
583 | } | 615 | } |
584 | 616 | ||
585 | static struct filter_arg * | 617 | static struct filter_arg * |
@@ -592,7 +624,7 @@ rotate_op_right(struct filter_arg *a, struct filter_arg *b) | |||
592 | return arg; | 624 | return arg; |
593 | } | 625 | } |
594 | 626 | ||
595 | static int add_left(struct filter_arg *op, struct filter_arg *arg) | 627 | static enum pevent_errno add_left(struct filter_arg *op, struct filter_arg *arg) |
596 | { | 628 | { |
597 | switch (op->type) { | 629 | switch (op->type) { |
598 | case FILTER_ARG_EXP: | 630 | case FILTER_ARG_EXP: |
@@ -611,11 +643,11 @@ static int add_left(struct filter_arg *op, struct filter_arg *arg) | |||
611 | /* left arg of compares must be a field */ | 643 | /* left arg of compares must be a field */ |
612 | if (arg->type != FILTER_ARG_FIELD && | 644 | if (arg->type != FILTER_ARG_FIELD && |
613 | arg->type != FILTER_ARG_BOOLEAN) | 645 | arg->type != FILTER_ARG_BOOLEAN) |
614 | return -1; | 646 | return PEVENT_ERRNO__INVALID_ARG_TYPE; |
615 | op->num.left = arg; | 647 | op->num.left = arg; |
616 | break; | 648 | break; |
617 | default: | 649 | default: |
618 | return -1; | 650 | return PEVENT_ERRNO__INVALID_ARG_TYPE; |
619 | } | 651 | } |
620 | return 0; | 652 | return 0; |
621 | } | 653 | } |
@@ -728,15 +760,18 @@ enum filter_vals { | |||
728 | FILTER_VAL_TRUE, | 760 | FILTER_VAL_TRUE, |
729 | }; | 761 | }; |
730 | 762 | ||
731 | void reparent_op_arg(struct filter_arg *parent, struct filter_arg *old_child, | 763 | static enum pevent_errno |
732 | struct filter_arg *arg) | 764 | reparent_op_arg(struct filter_arg *parent, struct filter_arg *old_child, |
765 | struct filter_arg *arg, char *error_str) | ||
733 | { | 766 | { |
734 | struct filter_arg *other_child; | 767 | struct filter_arg *other_child; |
735 | struct filter_arg **ptr; | 768 | struct filter_arg **ptr; |
736 | 769 | ||
737 | if (parent->type != FILTER_ARG_OP && | 770 | if (parent->type != FILTER_ARG_OP && |
738 | arg->type != FILTER_ARG_OP) | 771 | arg->type != FILTER_ARG_OP) { |
739 | die("can not reparent other than OP"); | 772 | show_error(error_str, "can not reparent other than OP"); |
773 | return PEVENT_ERRNO__REPARENT_NOT_OP; | ||
774 | } | ||
740 | 775 | ||
741 | /* Get the sibling */ | 776 | /* Get the sibling */ |
742 | if (old_child->op.right == arg) { | 777 | if (old_child->op.right == arg) { |
@@ -745,8 +780,10 @@ void reparent_op_arg(struct filter_arg *parent, struct filter_arg *old_child, | |||
745 | } else if (old_child->op.left == arg) { | 780 | } else if (old_child->op.left == arg) { |
746 | ptr = &old_child->op.left; | 781 | ptr = &old_child->op.left; |
747 | other_child = old_child->op.right; | 782 | other_child = old_child->op.right; |
748 | } else | 783 | } else { |
749 | die("Error in reparent op, find other child"); | 784 | show_error(error_str, "Error in reparent op, find other child"); |
785 | return PEVENT_ERRNO__REPARENT_FAILED; | ||
786 | } | ||
750 | 787 | ||
751 | /* Detach arg from old_child */ | 788 | /* Detach arg from old_child */ |
752 | *ptr = NULL; | 789 | *ptr = NULL; |
@@ -757,23 +794,29 @@ void reparent_op_arg(struct filter_arg *parent, struct filter_arg *old_child, | |||
757 | *parent = *arg; | 794 | *parent = *arg; |
758 | /* Free arg without recussion */ | 795 | /* Free arg without recussion */ |
759 | free(arg); | 796 | free(arg); |
760 | return; | 797 | return 0; |
761 | } | 798 | } |
762 | 799 | ||
763 | if (parent->op.right == old_child) | 800 | if (parent->op.right == old_child) |
764 | ptr = &parent->op.right; | 801 | ptr = &parent->op.right; |
765 | else if (parent->op.left == old_child) | 802 | else if (parent->op.left == old_child) |
766 | ptr = &parent->op.left; | 803 | ptr = &parent->op.left; |
767 | else | 804 | else { |
768 | die("Error in reparent op"); | 805 | show_error(error_str, "Error in reparent op"); |
806 | return PEVENT_ERRNO__REPARENT_FAILED; | ||
807 | } | ||
808 | |||
769 | *ptr = arg; | 809 | *ptr = arg; |
770 | 810 | ||
771 | free_arg(old_child); | 811 | free_arg(old_child); |
812 | return 0; | ||
772 | } | 813 | } |
773 | 814 | ||
774 | enum filter_vals test_arg(struct filter_arg *parent, struct filter_arg *arg) | 815 | /* Returns either filter_vals (success) or pevent_errno (failfure) */ |
816 | static int test_arg(struct filter_arg *parent, struct filter_arg *arg, | ||
817 | char *error_str) | ||
775 | { | 818 | { |
776 | enum filter_vals lval, rval; | 819 | int lval, rval; |
777 | 820 | ||
778 | switch (arg->type) { | 821 | switch (arg->type) { |
779 | 822 | ||
@@ -788,63 +831,68 @@ enum filter_vals test_arg(struct filter_arg *parent, struct filter_arg *arg) | |||
788 | return FILTER_VAL_NORM; | 831 | return FILTER_VAL_NORM; |
789 | 832 | ||
790 | case FILTER_ARG_EXP: | 833 | case FILTER_ARG_EXP: |
791 | lval = test_arg(arg, arg->exp.left); | 834 | lval = test_arg(arg, arg->exp.left, error_str); |
792 | if (lval != FILTER_VAL_NORM) | 835 | if (lval != FILTER_VAL_NORM) |
793 | return lval; | 836 | return lval; |
794 | rval = test_arg(arg, arg->exp.right); | 837 | rval = test_arg(arg, arg->exp.right, error_str); |
795 | if (rval != FILTER_VAL_NORM) | 838 | if (rval != FILTER_VAL_NORM) |
796 | return rval; | 839 | return rval; |
797 | return FILTER_VAL_NORM; | 840 | return FILTER_VAL_NORM; |
798 | 841 | ||
799 | case FILTER_ARG_NUM: | 842 | case FILTER_ARG_NUM: |
800 | lval = test_arg(arg, arg->num.left); | 843 | lval = test_arg(arg, arg->num.left, error_str); |
801 | if (lval != FILTER_VAL_NORM) | 844 | if (lval != FILTER_VAL_NORM) |
802 | return lval; | 845 | return lval; |
803 | rval = test_arg(arg, arg->num.right); | 846 | rval = test_arg(arg, arg->num.right, error_str); |
804 | if (rval != FILTER_VAL_NORM) | 847 | if (rval != FILTER_VAL_NORM) |
805 | return rval; | 848 | return rval; |
806 | return FILTER_VAL_NORM; | 849 | return FILTER_VAL_NORM; |
807 | 850 | ||
808 | case FILTER_ARG_OP: | 851 | case FILTER_ARG_OP: |
809 | if (arg->op.type != FILTER_OP_NOT) { | 852 | if (arg->op.type != FILTER_OP_NOT) { |
810 | lval = test_arg(arg, arg->op.left); | 853 | lval = test_arg(arg, arg->op.left, error_str); |
811 | switch (lval) { | 854 | switch (lval) { |
812 | case FILTER_VAL_NORM: | 855 | case FILTER_VAL_NORM: |
813 | break; | 856 | break; |
814 | case FILTER_VAL_TRUE: | 857 | case FILTER_VAL_TRUE: |
815 | if (arg->op.type == FILTER_OP_OR) | 858 | if (arg->op.type == FILTER_OP_OR) |
816 | return FILTER_VAL_TRUE; | 859 | return FILTER_VAL_TRUE; |
817 | rval = test_arg(arg, arg->op.right); | 860 | rval = test_arg(arg, arg->op.right, error_str); |
818 | if (rval != FILTER_VAL_NORM) | 861 | if (rval != FILTER_VAL_NORM) |
819 | return rval; | 862 | return rval; |
820 | 863 | ||
821 | reparent_op_arg(parent, arg, arg->op.right); | 864 | return reparent_op_arg(parent, arg, arg->op.right, |
822 | return FILTER_VAL_NORM; | 865 | error_str); |
823 | 866 | ||
824 | case FILTER_VAL_FALSE: | 867 | case FILTER_VAL_FALSE: |
825 | if (arg->op.type == FILTER_OP_AND) | 868 | if (arg->op.type == FILTER_OP_AND) |
826 | return FILTER_VAL_FALSE; | 869 | return FILTER_VAL_FALSE; |
827 | rval = test_arg(arg, arg->op.right); | 870 | rval = test_arg(arg, arg->op.right, error_str); |
828 | if (rval != FILTER_VAL_NORM) | 871 | if (rval != FILTER_VAL_NORM) |
829 | return rval; | 872 | return rval; |
830 | 873 | ||
831 | reparent_op_arg(parent, arg, arg->op.right); | 874 | return reparent_op_arg(parent, arg, arg->op.right, |
832 | return FILTER_VAL_NORM; | 875 | error_str); |
876 | |||
877 | default: | ||
878 | return lval; | ||
833 | } | 879 | } |
834 | } | 880 | } |
835 | 881 | ||
836 | rval = test_arg(arg, arg->op.right); | 882 | rval = test_arg(arg, arg->op.right, error_str); |
837 | switch (rval) { | 883 | switch (rval) { |
838 | case FILTER_VAL_NORM: | 884 | case FILTER_VAL_NORM: |
885 | default: | ||
839 | break; | 886 | break; |
887 | |||
840 | case FILTER_VAL_TRUE: | 888 | case FILTER_VAL_TRUE: |
841 | if (arg->op.type == FILTER_OP_OR) | 889 | if (arg->op.type == FILTER_OP_OR) |
842 | return FILTER_VAL_TRUE; | 890 | return FILTER_VAL_TRUE; |
843 | if (arg->op.type == FILTER_OP_NOT) | 891 | if (arg->op.type == FILTER_OP_NOT) |
844 | return FILTER_VAL_FALSE; | 892 | return FILTER_VAL_FALSE; |
845 | 893 | ||
846 | reparent_op_arg(parent, arg, arg->op.left); | 894 | return reparent_op_arg(parent, arg, arg->op.left, |
847 | return FILTER_VAL_NORM; | 895 | error_str); |
848 | 896 | ||
849 | case FILTER_VAL_FALSE: | 897 | case FILTER_VAL_FALSE: |
850 | if (arg->op.type == FILTER_OP_AND) | 898 | if (arg->op.type == FILTER_OP_AND) |
@@ -852,41 +900,56 @@ enum filter_vals test_arg(struct filter_arg *parent, struct filter_arg *arg) | |||
852 | if (arg->op.type == FILTER_OP_NOT) | 900 | if (arg->op.type == FILTER_OP_NOT) |
853 | return FILTER_VAL_TRUE; | 901 | return FILTER_VAL_TRUE; |
854 | 902 | ||
855 | reparent_op_arg(parent, arg, arg->op.left); | 903 | return reparent_op_arg(parent, arg, arg->op.left, |
856 | return FILTER_VAL_NORM; | 904 | error_str); |
857 | } | 905 | } |
858 | 906 | ||
859 | return FILTER_VAL_NORM; | 907 | return rval; |
860 | default: | 908 | default: |
861 | die("bad arg in filter tree"); | 909 | show_error(error_str, "bad arg in filter tree"); |
910 | return PEVENT_ERRNO__BAD_FILTER_ARG; | ||
862 | } | 911 | } |
863 | return FILTER_VAL_NORM; | 912 | return FILTER_VAL_NORM; |
864 | } | 913 | } |
865 | 914 | ||
866 | /* Remove any unknown event fields */ | 915 | /* Remove any unknown event fields */ |
867 | static struct filter_arg *collapse_tree(struct filter_arg *arg) | 916 | static int collapse_tree(struct filter_arg *arg, |
917 | struct filter_arg **arg_collapsed, char *error_str) | ||
868 | { | 918 | { |
869 | enum filter_vals ret; | 919 | int ret; |
870 | 920 | ||
871 | ret = test_arg(arg, arg); | 921 | ret = test_arg(arg, arg, error_str); |
872 | switch (ret) { | 922 | switch (ret) { |
873 | case FILTER_VAL_NORM: | 923 | case FILTER_VAL_NORM: |
874 | return arg; | 924 | break; |
875 | 925 | ||
876 | case FILTER_VAL_TRUE: | 926 | case FILTER_VAL_TRUE: |
877 | case FILTER_VAL_FALSE: | 927 | case FILTER_VAL_FALSE: |
878 | free_arg(arg); | 928 | free_arg(arg); |
879 | arg = allocate_arg(); | 929 | arg = allocate_arg(); |
880 | arg->type = FILTER_ARG_BOOLEAN; | 930 | if (arg) { |
881 | arg->boolean.value = ret == FILTER_VAL_TRUE; | 931 | arg->type = FILTER_ARG_BOOLEAN; |
932 | arg->boolean.value = ret == FILTER_VAL_TRUE; | ||
933 | } else { | ||
934 | show_error(error_str, "Failed to allocate filter arg"); | ||
935 | ret = PEVENT_ERRNO__MEM_ALLOC_FAILED; | ||
936 | } | ||
937 | break; | ||
938 | |||
939 | default: | ||
940 | /* test_arg() already set the error_str */ | ||
941 | free_arg(arg); | ||
942 | arg = NULL; | ||
943 | break; | ||
882 | } | 944 | } |
883 | 945 | ||
884 | return arg; | 946 | *arg_collapsed = arg; |
947 | return ret; | ||
885 | } | 948 | } |
886 | 949 | ||
887 | static int | 950 | static enum pevent_errno |
888 | process_filter(struct event_format *event, struct filter_arg **parg, | 951 | process_filter(struct event_format *event, struct filter_arg **parg, |
889 | char **error_str, int not) | 952 | char *error_str, int not) |
890 | { | 953 | { |
891 | enum event_type type; | 954 | enum event_type type; |
892 | char *token = NULL; | 955 | char *token = NULL; |
@@ -898,7 +961,7 @@ process_filter(struct event_format *event, struct filter_arg **parg, | |||
898 | enum filter_op_type btype; | 961 | enum filter_op_type btype; |
899 | enum filter_exp_type etype; | 962 | enum filter_exp_type etype; |
900 | enum filter_cmp_type ctype; | 963 | enum filter_cmp_type ctype; |
901 | int ret; | 964 | enum pevent_errno ret; |
902 | 965 | ||
903 | *parg = NULL; | 966 | *parg = NULL; |
904 | 967 | ||
@@ -909,8 +972,8 @@ process_filter(struct event_format *event, struct filter_arg **parg, | |||
909 | case EVENT_SQUOTE: | 972 | case EVENT_SQUOTE: |
910 | case EVENT_DQUOTE: | 973 | case EVENT_DQUOTE: |
911 | case EVENT_ITEM: | 974 | case EVENT_ITEM: |
912 | arg = create_arg_item(event, token, type, error_str); | 975 | ret = create_arg_item(event, token, type, &arg, error_str); |
913 | if (!arg) | 976 | if (ret < 0) |
914 | goto fail; | 977 | goto fail; |
915 | if (!left_item) | 978 | if (!left_item) |
916 | left_item = arg; | 979 | left_item = arg; |
@@ -923,20 +986,20 @@ process_filter(struct event_format *event, struct filter_arg **parg, | |||
923 | if (not) { | 986 | if (not) { |
924 | arg = NULL; | 987 | arg = NULL; |
925 | if (current_op) | 988 | if (current_op) |
926 | goto fail_print; | 989 | goto fail_syntax; |
927 | free(token); | 990 | free(token); |
928 | *parg = current_exp; | 991 | *parg = current_exp; |
929 | return 0; | 992 | return 0; |
930 | } | 993 | } |
931 | } else | 994 | } else |
932 | goto fail_print; | 995 | goto fail_syntax; |
933 | arg = NULL; | 996 | arg = NULL; |
934 | break; | 997 | break; |
935 | 998 | ||
936 | case EVENT_DELIM: | 999 | case EVENT_DELIM: |
937 | if (*token == ',') { | 1000 | if (*token == ',') { |
938 | show_error(error_str, | 1001 | show_error(error_str, "Illegal token ','"); |
939 | "Illegal token ','"); | 1002 | ret = PEVENT_ERRNO__ILLEGAL_TOKEN; |
940 | goto fail; | 1003 | goto fail; |
941 | } | 1004 | } |
942 | 1005 | ||
@@ -944,19 +1007,23 @@ process_filter(struct event_format *event, struct filter_arg **parg, | |||
944 | if (left_item) { | 1007 | if (left_item) { |
945 | show_error(error_str, | 1008 | show_error(error_str, |
946 | "Open paren can not come after item"); | 1009 | "Open paren can not come after item"); |
1010 | ret = PEVENT_ERRNO__INVALID_PAREN; | ||
947 | goto fail; | 1011 | goto fail; |
948 | } | 1012 | } |
949 | if (current_exp) { | 1013 | if (current_exp) { |
950 | show_error(error_str, | 1014 | show_error(error_str, |
951 | "Open paren can not come after expression"); | 1015 | "Open paren can not come after expression"); |
1016 | ret = PEVENT_ERRNO__INVALID_PAREN; | ||
952 | goto fail; | 1017 | goto fail; |
953 | } | 1018 | } |
954 | 1019 | ||
955 | ret = process_filter(event, &arg, error_str, 0); | 1020 | ret = process_filter(event, &arg, error_str, 0); |
956 | if (ret != 1) { | 1021 | if (ret != PEVENT_ERRNO__UNBALANCED_PAREN) { |
957 | if (ret == 0) | 1022 | if (ret == 0) { |
958 | show_error(error_str, | 1023 | show_error(error_str, |
959 | "Unbalanced number of '('"); | 1024 | "Unbalanced number of '('"); |
1025 | ret = PEVENT_ERRNO__UNBALANCED_PAREN; | ||
1026 | } | ||
960 | goto fail; | 1027 | goto fail; |
961 | } | 1028 | } |
962 | ret = 0; | 1029 | ret = 0; |
@@ -964,7 +1031,7 @@ process_filter(struct event_format *event, struct filter_arg **parg, | |||
964 | /* A not wants just one expression */ | 1031 | /* A not wants just one expression */ |
965 | if (not) { | 1032 | if (not) { |
966 | if (current_op) | 1033 | if (current_op) |
967 | goto fail_print; | 1034 | goto fail_syntax; |
968 | *parg = arg; | 1035 | *parg = arg; |
969 | return 0; | 1036 | return 0; |
970 | } | 1037 | } |
@@ -979,19 +1046,19 @@ process_filter(struct event_format *event, struct filter_arg **parg, | |||
979 | 1046 | ||
980 | } else { /* ')' */ | 1047 | } else { /* ')' */ |
981 | if (!current_op && !current_exp) | 1048 | if (!current_op && !current_exp) |
982 | goto fail_print; | 1049 | goto fail_syntax; |
983 | 1050 | ||
984 | /* Make sure everything is finished at this level */ | 1051 | /* Make sure everything is finished at this level */ |
985 | if (current_exp && !check_op_done(current_exp)) | 1052 | if (current_exp && !check_op_done(current_exp)) |
986 | goto fail_print; | 1053 | goto fail_syntax; |
987 | if (current_op && !check_op_done(current_op)) | 1054 | if (current_op && !check_op_done(current_op)) |
988 | goto fail_print; | 1055 | goto fail_syntax; |
989 | 1056 | ||
990 | if (current_op) | 1057 | if (current_op) |
991 | *parg = current_op; | 1058 | *parg = current_op; |
992 | else | 1059 | else |
993 | *parg = current_exp; | 1060 | *parg = current_exp; |
994 | return 1; | 1061 | return PEVENT_ERRNO__UNBALANCED_PAREN; |
995 | } | 1062 | } |
996 | break; | 1063 | break; |
997 | 1064 | ||
@@ -1003,21 +1070,22 @@ process_filter(struct event_format *event, struct filter_arg **parg, | |||
1003 | case OP_BOOL: | 1070 | case OP_BOOL: |
1004 | /* Logic ops need a left expression */ | 1071 | /* Logic ops need a left expression */ |
1005 | if (!current_exp && !current_op) | 1072 | if (!current_exp && !current_op) |
1006 | goto fail_print; | 1073 | goto fail_syntax; |
1007 | /* fall through */ | 1074 | /* fall through */ |
1008 | case OP_NOT: | 1075 | case OP_NOT: |
1009 | /* logic only processes ops and exp */ | 1076 | /* logic only processes ops and exp */ |
1010 | if (left_item) | 1077 | if (left_item) |
1011 | goto fail_print; | 1078 | goto fail_syntax; |
1012 | break; | 1079 | break; |
1013 | case OP_EXP: | 1080 | case OP_EXP: |
1014 | case OP_CMP: | 1081 | case OP_CMP: |
1015 | if (!left_item) | 1082 | if (!left_item) |
1016 | goto fail_print; | 1083 | goto fail_syntax; |
1017 | break; | 1084 | break; |
1018 | case OP_NONE: | 1085 | case OP_NONE: |
1019 | show_error(error_str, | 1086 | show_error(error_str, |
1020 | "Unknown op token %s", token); | 1087 | "Unknown op token %s", token); |
1088 | ret = PEVENT_ERRNO__UNKNOWN_TOKEN; | ||
1021 | goto fail; | 1089 | goto fail; |
1022 | } | 1090 | } |
1023 | 1091 | ||
@@ -1025,6 +1093,8 @@ process_filter(struct event_format *event, struct filter_arg **parg, | |||
1025 | switch (op_type) { | 1093 | switch (op_type) { |
1026 | case OP_BOOL: | 1094 | case OP_BOOL: |
1027 | arg = create_arg_op(btype); | 1095 | arg = create_arg_op(btype); |
1096 | if (arg == NULL) | ||
1097 | goto fail_alloc; | ||
1028 | if (current_op) | 1098 | if (current_op) |
1029 | ret = add_left(arg, current_op); | 1099 | ret = add_left(arg, current_op); |
1030 | else | 1100 | else |
@@ -1035,6 +1105,8 @@ process_filter(struct event_format *event, struct filter_arg **parg, | |||
1035 | 1105 | ||
1036 | case OP_NOT: | 1106 | case OP_NOT: |
1037 | arg = create_arg_op(btype); | 1107 | arg = create_arg_op(btype); |
1108 | if (arg == NULL) | ||
1109 | goto fail_alloc; | ||
1038 | if (current_op) | 1110 | if (current_op) |
1039 | ret = add_right(current_op, arg, error_str); | 1111 | ret = add_right(current_op, arg, error_str); |
1040 | if (ret < 0) | 1112 | if (ret < 0) |
@@ -1054,6 +1126,8 @@ process_filter(struct event_format *event, struct filter_arg **parg, | |||
1054 | arg = create_arg_exp(etype); | 1126 | arg = create_arg_exp(etype); |
1055 | else | 1127 | else |
1056 | arg = create_arg_cmp(ctype); | 1128 | arg = create_arg_cmp(ctype); |
1129 | if (arg == NULL) | ||
1130 | goto fail_alloc; | ||
1057 | 1131 | ||
1058 | if (current_op) | 1132 | if (current_op) |
1059 | ret = add_right(current_op, arg, error_str); | 1133 | ret = add_right(current_op, arg, error_str); |
@@ -1062,7 +1136,7 @@ process_filter(struct event_format *event, struct filter_arg **parg, | |||
1062 | ret = add_left(arg, left_item); | 1136 | ret = add_left(arg, left_item); |
1063 | if (ret < 0) { | 1137 | if (ret < 0) { |
1064 | arg = NULL; | 1138 | arg = NULL; |
1065 | goto fail_print; | 1139 | goto fail_syntax; |
1066 | } | 1140 | } |
1067 | current_exp = arg; | 1141 | current_exp = arg; |
1068 | break; | 1142 | break; |
@@ -1071,57 +1145,64 @@ process_filter(struct event_format *event, struct filter_arg **parg, | |||
1071 | } | 1145 | } |
1072 | arg = NULL; | 1146 | arg = NULL; |
1073 | if (ret < 0) | 1147 | if (ret < 0) |
1074 | goto fail_print; | 1148 | goto fail_syntax; |
1075 | break; | 1149 | break; |
1076 | case EVENT_NONE: | 1150 | case EVENT_NONE: |
1077 | break; | 1151 | break; |
1152 | case EVENT_ERROR: | ||
1153 | goto fail_alloc; | ||
1078 | default: | 1154 | default: |
1079 | goto fail_print; | 1155 | goto fail_syntax; |
1080 | } | 1156 | } |
1081 | } while (type != EVENT_NONE); | 1157 | } while (type != EVENT_NONE); |
1082 | 1158 | ||
1083 | if (!current_op && !current_exp) | 1159 | if (!current_op && !current_exp) |
1084 | goto fail_print; | 1160 | goto fail_syntax; |
1085 | 1161 | ||
1086 | if (!current_op) | 1162 | if (!current_op) |
1087 | current_op = current_exp; | 1163 | current_op = current_exp; |
1088 | 1164 | ||
1089 | current_op = collapse_tree(current_op); | 1165 | ret = collapse_tree(current_op, parg, error_str); |
1166 | if (ret < 0) | ||
1167 | goto fail; | ||
1090 | 1168 | ||
1091 | *parg = current_op; | 1169 | *parg = current_op; |
1092 | 1170 | ||
1093 | return 0; | 1171 | return 0; |
1094 | 1172 | ||
1095 | fail_print: | 1173 | fail_alloc: |
1174 | show_error(error_str, "failed to allocate filter arg"); | ||
1175 | ret = PEVENT_ERRNO__MEM_ALLOC_FAILED; | ||
1176 | goto fail; | ||
1177 | fail_syntax: | ||
1096 | show_error(error_str, "Syntax error"); | 1178 | show_error(error_str, "Syntax error"); |
1179 | ret = PEVENT_ERRNO__SYNTAX_ERROR; | ||
1097 | fail: | 1180 | fail: |
1098 | free_arg(current_op); | 1181 | free_arg(current_op); |
1099 | free_arg(current_exp); | 1182 | free_arg(current_exp); |
1100 | free_arg(arg); | 1183 | free_arg(arg); |
1101 | free(token); | 1184 | free(token); |
1102 | return -1; | 1185 | return ret; |
1103 | } | 1186 | } |
1104 | 1187 | ||
1105 | static int | 1188 | static enum pevent_errno |
1106 | process_event(struct event_format *event, const char *filter_str, | 1189 | process_event(struct event_format *event, const char *filter_str, |
1107 | struct filter_arg **parg, char **error_str) | 1190 | struct filter_arg **parg, char *error_str) |
1108 | { | 1191 | { |
1109 | int ret; | 1192 | int ret; |
1110 | 1193 | ||
1111 | pevent_buffer_init(filter_str, strlen(filter_str)); | 1194 | pevent_buffer_init(filter_str, strlen(filter_str)); |
1112 | 1195 | ||
1113 | ret = process_filter(event, parg, error_str, 0); | 1196 | ret = process_filter(event, parg, error_str, 0); |
1114 | if (ret == 1) { | ||
1115 | show_error(error_str, | ||
1116 | "Unbalanced number of ')'"); | ||
1117 | return -1; | ||
1118 | } | ||
1119 | if (ret < 0) | 1197 | if (ret < 0) |
1120 | return ret; | 1198 | return ret; |
1121 | 1199 | ||
1122 | /* If parg is NULL, then make it into FALSE */ | 1200 | /* If parg is NULL, then make it into FALSE */ |
1123 | if (!*parg) { | 1201 | if (!*parg) { |
1124 | *parg = allocate_arg(); | 1202 | *parg = allocate_arg(); |
1203 | if (*parg == NULL) | ||
1204 | return PEVENT_ERRNO__MEM_ALLOC_FAILED; | ||
1205 | |||
1125 | (*parg)->type = FILTER_ARG_BOOLEAN; | 1206 | (*parg)->type = FILTER_ARG_BOOLEAN; |
1126 | (*parg)->boolean.value = FILTER_FALSE; | 1207 | (*parg)->boolean.value = FILTER_FALSE; |
1127 | } | 1208 | } |
@@ -1129,13 +1210,13 @@ process_event(struct event_format *event, const char *filter_str, | |||
1129 | return 0; | 1210 | return 0; |
1130 | } | 1211 | } |
1131 | 1212 | ||
1132 | static int filter_event(struct event_filter *filter, | 1213 | static enum pevent_errno |
1133 | struct event_format *event, | 1214 | filter_event(struct event_filter *filter, struct event_format *event, |
1134 | const char *filter_str, char **error_str) | 1215 | const char *filter_str, char *error_str) |
1135 | { | 1216 | { |
1136 | struct filter_type *filter_type; | 1217 | struct filter_type *filter_type; |
1137 | struct filter_arg *arg; | 1218 | struct filter_arg *arg; |
1138 | int ret; | 1219 | enum pevent_errno ret; |
1139 | 1220 | ||
1140 | if (filter_str) { | 1221 | if (filter_str) { |
1141 | ret = process_event(event, filter_str, &arg, error_str); | 1222 | ret = process_event(event, filter_str, &arg, error_str); |
@@ -1145,11 +1226,17 @@ static int filter_event(struct event_filter *filter, | |||
1145 | } else { | 1226 | } else { |
1146 | /* just add a TRUE arg */ | 1227 | /* just add a TRUE arg */ |
1147 | arg = allocate_arg(); | 1228 | arg = allocate_arg(); |
1229 | if (arg == NULL) | ||
1230 | return PEVENT_ERRNO__MEM_ALLOC_FAILED; | ||
1231 | |||
1148 | arg->type = FILTER_ARG_BOOLEAN; | 1232 | arg->type = FILTER_ARG_BOOLEAN; |
1149 | arg->boolean.value = FILTER_TRUE; | 1233 | arg->boolean.value = FILTER_TRUE; |
1150 | } | 1234 | } |
1151 | 1235 | ||
1152 | filter_type = add_filter_type(filter, event->id); | 1236 | filter_type = add_filter_type(filter, event->id); |
1237 | if (filter_type == NULL) | ||
1238 | return PEVENT_ERRNO__MEM_ALLOC_FAILED; | ||
1239 | |||
1153 | if (filter_type->filter) | 1240 | if (filter_type->filter) |
1154 | free_arg(filter_type->filter); | 1241 | free_arg(filter_type->filter); |
1155 | filter_type->filter = arg; | 1242 | filter_type->filter = arg; |
@@ -1157,22 +1244,24 @@ static int filter_event(struct event_filter *filter, | |||
1157 | return 0; | 1244 | return 0; |
1158 | } | 1245 | } |
1159 | 1246 | ||
1247 | static void filter_init_error_buf(struct event_filter *filter) | ||
1248 | { | ||
1249 | /* clear buffer to reset show error */ | ||
1250 | pevent_buffer_init("", 0); | ||
1251 | filter->error_buffer[0] = '\0'; | ||
1252 | } | ||
1253 | |||
1160 | /** | 1254 | /** |
1161 | * pevent_filter_add_filter_str - add a new filter | 1255 | * pevent_filter_add_filter_str - add a new filter |
1162 | * @filter: the event filter to add to | 1256 | * @filter: the event filter to add to |
1163 | * @filter_str: the filter string that contains the filter | 1257 | * @filter_str: the filter string that contains the filter |
1164 | * @error_str: string containing reason for failed filter | ||
1165 | * | ||
1166 | * Returns 0 if the filter was successfully added | ||
1167 | * -1 if there was an error. | ||
1168 | * | 1258 | * |
1169 | * On error, if @error_str points to a string pointer, | 1259 | * Returns 0 if the filter was successfully added or a |
1170 | * it is set to the reason that the filter failed. | 1260 | * negative error code. Use pevent_filter_strerror() to see |
1171 | * This string must be freed with "free". | 1261 | * actual error message in case of error. |
1172 | */ | 1262 | */ |
1173 | int pevent_filter_add_filter_str(struct event_filter *filter, | 1263 | enum pevent_errno pevent_filter_add_filter_str(struct event_filter *filter, |
1174 | const char *filter_str, | 1264 | const char *filter_str) |
1175 | char **error_str) | ||
1176 | { | 1265 | { |
1177 | struct pevent *pevent = filter->pevent; | 1266 | struct pevent *pevent = filter->pevent; |
1178 | struct event_list *event; | 1267 | struct event_list *event; |
@@ -1183,15 +1272,11 @@ int pevent_filter_add_filter_str(struct event_filter *filter, | |||
1183 | char *event_name = NULL; | 1272 | char *event_name = NULL; |
1184 | char *sys_name = NULL; | 1273 | char *sys_name = NULL; |
1185 | char *sp; | 1274 | char *sp; |
1186 | int rtn = 0; | 1275 | enum pevent_errno rtn = 0; /* PEVENT_ERRNO__SUCCESS */ |
1187 | int len; | 1276 | int len; |
1188 | int ret; | 1277 | int ret; |
1189 | 1278 | ||
1190 | /* clear buffer to reset show error */ | 1279 | filter_init_error_buf(filter); |
1191 | pevent_buffer_init("", 0); | ||
1192 | |||
1193 | if (error_str) | ||
1194 | *error_str = NULL; | ||
1195 | 1280 | ||
1196 | filter_start = strchr(filter_str, ':'); | 1281 | filter_start = strchr(filter_str, ':'); |
1197 | if (filter_start) | 1282 | if (filter_start) |
@@ -1199,7 +1284,6 @@ int pevent_filter_add_filter_str(struct event_filter *filter, | |||
1199 | else | 1284 | else |
1200 | len = strlen(filter_str); | 1285 | len = strlen(filter_str); |
1201 | 1286 | ||
1202 | |||
1203 | do { | 1287 | do { |
1204 | next_event = strchr(filter_str, ','); | 1288 | next_event = strchr(filter_str, ','); |
1205 | if (next_event && | 1289 | if (next_event && |
@@ -1210,7 +1294,12 @@ int pevent_filter_add_filter_str(struct event_filter *filter, | |||
1210 | else | 1294 | else |
1211 | len = strlen(filter_str); | 1295 | len = strlen(filter_str); |
1212 | 1296 | ||
1213 | this_event = malloc_or_die(len + 1); | 1297 | this_event = malloc(len + 1); |
1298 | if (this_event == NULL) { | ||
1299 | /* This can only happen when events is NULL, but still */ | ||
1300 | free_events(events); | ||
1301 | return PEVENT_ERRNO__MEM_ALLOC_FAILED; | ||
1302 | } | ||
1214 | memcpy(this_event, filter_str, len); | 1303 | memcpy(this_event, filter_str, len); |
1215 | this_event[len] = 0; | 1304 | this_event[len] = 0; |
1216 | 1305 | ||
@@ -1223,27 +1312,18 @@ int pevent_filter_add_filter_str(struct event_filter *filter, | |||
1223 | event_name = strtok_r(NULL, "/", &sp); | 1312 | event_name = strtok_r(NULL, "/", &sp); |
1224 | 1313 | ||
1225 | if (!sys_name) { | 1314 | if (!sys_name) { |
1226 | show_error(error_str, "No filter found"); | ||
1227 | /* This can only happen when events is NULL, but still */ | 1315 | /* This can only happen when events is NULL, but still */ |
1228 | free_events(events); | 1316 | free_events(events); |
1229 | free(this_event); | 1317 | free(this_event); |
1230 | return -1; | 1318 | return PEVENT_ERRNO__FILTER_NOT_FOUND; |
1231 | } | 1319 | } |
1232 | 1320 | ||
1233 | /* Find this event */ | 1321 | /* Find this event */ |
1234 | ret = find_event(pevent, &events, strim(sys_name), strim(event_name)); | 1322 | ret = find_event(pevent, &events, strim(sys_name), strim(event_name)); |
1235 | if (ret < 0) { | 1323 | if (ret < 0) { |
1236 | if (event_name) | ||
1237 | show_error(error_str, | ||
1238 | "No event found under '%s.%s'", | ||
1239 | sys_name, event_name); | ||
1240 | else | ||
1241 | show_error(error_str, | ||
1242 | "No event found under '%s'", | ||
1243 | sys_name); | ||
1244 | free_events(events); | 1324 | free_events(events); |
1245 | free(this_event); | 1325 | free(this_event); |
1246 | return -1; | 1326 | return ret; |
1247 | } | 1327 | } |
1248 | free(this_event); | 1328 | free(this_event); |
1249 | } while (filter_str); | 1329 | } while (filter_str); |
@@ -1255,7 +1335,7 @@ int pevent_filter_add_filter_str(struct event_filter *filter, | |||
1255 | /* filter starts here */ | 1335 | /* filter starts here */ |
1256 | for (event = events; event; event = event->next) { | 1336 | for (event = events; event; event = event->next) { |
1257 | ret = filter_event(filter, event->event, filter_start, | 1337 | ret = filter_event(filter, event->event, filter_start, |
1258 | error_str); | 1338 | filter->error_buffer); |
1259 | /* Failures are returned if a parse error happened */ | 1339 | /* Failures are returned if a parse error happened */ |
1260 | if (ret < 0) | 1340 | if (ret < 0) |
1261 | rtn = ret; | 1341 | rtn = ret; |
@@ -1263,8 +1343,10 @@ int pevent_filter_add_filter_str(struct event_filter *filter, | |||
1263 | if (ret >= 0 && pevent->test_filters) { | 1343 | if (ret >= 0 && pevent->test_filters) { |
1264 | char *test; | 1344 | char *test; |
1265 | test = pevent_filter_make_string(filter, event->event->id); | 1345 | test = pevent_filter_make_string(filter, event->event->id); |
1266 | printf(" '%s: %s'\n", event->event->name, test); | 1346 | if (test) { |
1267 | free(test); | 1347 | printf(" '%s: %s'\n", event->event->name, test); |
1348 | free(test); | ||
1349 | } | ||
1268 | } | 1350 | } |
1269 | } | 1351 | } |
1270 | 1352 | ||
@@ -1282,6 +1364,32 @@ static void free_filter_type(struct filter_type *filter_type) | |||
1282 | } | 1364 | } |
1283 | 1365 | ||
1284 | /** | 1366 | /** |
1367 | * pevent_filter_strerror - fill error message in a buffer | ||
1368 | * @filter: the event filter contains error | ||
1369 | * @err: the error code | ||
1370 | * @buf: the buffer to be filled in | ||
1371 | * @buflen: the size of the buffer | ||
1372 | * | ||
1373 | * Returns 0 if message was filled successfully, -1 if error | ||
1374 | */ | ||
1375 | int pevent_filter_strerror(struct event_filter *filter, enum pevent_errno err, | ||
1376 | char *buf, size_t buflen) | ||
1377 | { | ||
1378 | if (err <= __PEVENT_ERRNO__START || err >= __PEVENT_ERRNO__END) | ||
1379 | return -1; | ||
1380 | |||
1381 | if (strlen(filter->error_buffer) > 0) { | ||
1382 | size_t len = snprintf(buf, buflen, "%s", filter->error_buffer); | ||
1383 | |||
1384 | if (len > buflen) | ||
1385 | return -1; | ||
1386 | return 0; | ||
1387 | } | ||
1388 | |||
1389 | return pevent_strerror(filter->pevent, err, buf, buflen); | ||
1390 | } | ||
1391 | |||
1392 | /** | ||
1285 | * pevent_filter_remove_event - remove a filter for an event | 1393 | * pevent_filter_remove_event - remove a filter for an event |
1286 | * @filter: the event filter to remove from | 1394 | * @filter: the event filter to remove from |
1287 | * @event_id: the event to remove a filter for | 1395 | * @event_id: the event to remove a filter for |
@@ -1374,6 +1482,9 @@ static int copy_filter_type(struct event_filter *filter, | |||
1374 | if (strcmp(str, "TRUE") == 0 || strcmp(str, "FALSE") == 0) { | 1482 | if (strcmp(str, "TRUE") == 0 || strcmp(str, "FALSE") == 0) { |
1375 | /* Add trivial event */ | 1483 | /* Add trivial event */ |
1376 | arg = allocate_arg(); | 1484 | arg = allocate_arg(); |
1485 | if (arg == NULL) | ||
1486 | return -1; | ||
1487 | |||
1377 | arg->type = FILTER_ARG_BOOLEAN; | 1488 | arg->type = FILTER_ARG_BOOLEAN; |
1378 | if (strcmp(str, "TRUE") == 0) | 1489 | if (strcmp(str, "TRUE") == 0) |
1379 | arg->boolean.value = 1; | 1490 | arg->boolean.value = 1; |
@@ -1381,6 +1492,9 @@ static int copy_filter_type(struct event_filter *filter, | |||
1381 | arg->boolean.value = 0; | 1492 | arg->boolean.value = 0; |
1382 | 1493 | ||
1383 | filter_type = add_filter_type(filter, event->id); | 1494 | filter_type = add_filter_type(filter, event->id); |
1495 | if (filter_type == NULL) | ||
1496 | return -1; | ||
1497 | |||
1384 | filter_type->filter = arg; | 1498 | filter_type->filter = arg; |
1385 | 1499 | ||
1386 | free(str); | 1500 | free(str); |
@@ -1482,8 +1596,10 @@ int pevent_update_trivial(struct event_filter *dest, struct event_filter *source | |||
1482 | * @type: remove only true, false, or both | 1596 | * @type: remove only true, false, or both |
1483 | * | 1597 | * |
1484 | * Removes filters that only contain a TRUE or FALES boolean arg. | 1598 | * Removes filters that only contain a TRUE or FALES boolean arg. |
1599 | * | ||
1600 | * Returns 0 on success and -1 if there was a problem. | ||
1485 | */ | 1601 | */ |
1486 | void pevent_filter_clear_trivial(struct event_filter *filter, | 1602 | int pevent_filter_clear_trivial(struct event_filter *filter, |
1487 | enum filter_trivial_type type) | 1603 | enum filter_trivial_type type) |
1488 | { | 1604 | { |
1489 | struct filter_type *filter_type; | 1605 | struct filter_type *filter_type; |
@@ -1492,13 +1608,15 @@ void pevent_filter_clear_trivial(struct event_filter *filter, | |||
1492 | int i; | 1608 | int i; |
1493 | 1609 | ||
1494 | if (!filter->filters) | 1610 | if (!filter->filters) |
1495 | return; | 1611 | return 0; |
1496 | 1612 | ||
1497 | /* | 1613 | /* |
1498 | * Two steps, first get all ids with trivial filters. | 1614 | * Two steps, first get all ids with trivial filters. |
1499 | * then remove those ids. | 1615 | * then remove those ids. |
1500 | */ | 1616 | */ |
1501 | for (i = 0; i < filter->filters; i++) { | 1617 | for (i = 0; i < filter->filters; i++) { |
1618 | int *new_ids; | ||
1619 | |||
1502 | filter_type = &filter->event_filters[i]; | 1620 | filter_type = &filter->event_filters[i]; |
1503 | if (filter_type->filter->type != FILTER_ARG_BOOLEAN) | 1621 | if (filter_type->filter->type != FILTER_ARG_BOOLEAN) |
1504 | continue; | 1622 | continue; |
@@ -1513,19 +1631,24 @@ void pevent_filter_clear_trivial(struct event_filter *filter, | |||
1513 | break; | 1631 | break; |
1514 | } | 1632 | } |
1515 | 1633 | ||
1516 | ids = realloc(ids, sizeof(*ids) * (count + 1)); | 1634 | new_ids = realloc(ids, sizeof(*ids) * (count + 1)); |
1517 | if (!ids) | 1635 | if (!new_ids) { |
1518 | die("Can't allocate ids"); | 1636 | free(ids); |
1637 | return -1; | ||
1638 | } | ||
1639 | |||
1640 | ids = new_ids; | ||
1519 | ids[count++] = filter_type->event_id; | 1641 | ids[count++] = filter_type->event_id; |
1520 | } | 1642 | } |
1521 | 1643 | ||
1522 | if (!count) | 1644 | if (!count) |
1523 | return; | 1645 | return 0; |
1524 | 1646 | ||
1525 | for (i = 0; i < count; i++) | 1647 | for (i = 0; i < count; i++) |
1526 | pevent_filter_remove_event(filter, ids[i]); | 1648 | pevent_filter_remove_event(filter, ids[i]); |
1527 | 1649 | ||
1528 | free(ids); | 1650 | free(ids); |
1651 | return 0; | ||
1529 | } | 1652 | } |
1530 | 1653 | ||
1531 | /** | 1654 | /** |
@@ -1565,8 +1688,8 @@ int pevent_filter_event_has_trivial(struct event_filter *filter, | |||
1565 | } | 1688 | } |
1566 | } | 1689 | } |
1567 | 1690 | ||
1568 | static int test_filter(struct event_format *event, | 1691 | static int test_filter(struct event_format *event, struct filter_arg *arg, |
1569 | struct filter_arg *arg, struct pevent_record *record); | 1692 | struct pevent_record *record, enum pevent_errno *err); |
1570 | 1693 | ||
1571 | static const char * | 1694 | static const char * |
1572 | get_comm(struct event_format *event, struct pevent_record *record) | 1695 | get_comm(struct event_format *event, struct pevent_record *record) |
@@ -1612,15 +1735,24 @@ get_value(struct event_format *event, | |||
1612 | } | 1735 | } |
1613 | 1736 | ||
1614 | static unsigned long long | 1737 | static unsigned long long |
1615 | get_arg_value(struct event_format *event, struct filter_arg *arg, struct pevent_record *record); | 1738 | get_arg_value(struct event_format *event, struct filter_arg *arg, |
1739 | struct pevent_record *record, enum pevent_errno *err); | ||
1616 | 1740 | ||
1617 | static unsigned long long | 1741 | static unsigned long long |
1618 | get_exp_value(struct event_format *event, struct filter_arg *arg, struct pevent_record *record) | 1742 | get_exp_value(struct event_format *event, struct filter_arg *arg, |
1743 | struct pevent_record *record, enum pevent_errno *err) | ||
1619 | { | 1744 | { |
1620 | unsigned long long lval, rval; | 1745 | unsigned long long lval, rval; |
1621 | 1746 | ||
1622 | lval = get_arg_value(event, arg->exp.left, record); | 1747 | lval = get_arg_value(event, arg->exp.left, record, err); |
1623 | rval = get_arg_value(event, arg->exp.right, record); | 1748 | rval = get_arg_value(event, arg->exp.right, record, err); |
1749 | |||
1750 | if (*err) { | ||
1751 | /* | ||
1752 | * There was an error, no need to process anymore. | ||
1753 | */ | ||
1754 | return 0; | ||
1755 | } | ||
1624 | 1756 | ||
1625 | switch (arg->exp.type) { | 1757 | switch (arg->exp.type) { |
1626 | case FILTER_EXP_ADD: | 1758 | case FILTER_EXP_ADD: |
@@ -1655,39 +1787,51 @@ get_exp_value(struct event_format *event, struct filter_arg *arg, struct pevent_ | |||
1655 | 1787 | ||
1656 | case FILTER_EXP_NOT: | 1788 | case FILTER_EXP_NOT: |
1657 | default: | 1789 | default: |
1658 | die("error in exp"); | 1790 | if (!*err) |
1791 | *err = PEVENT_ERRNO__INVALID_EXP_TYPE; | ||
1659 | } | 1792 | } |
1660 | return 0; | 1793 | return 0; |
1661 | } | 1794 | } |
1662 | 1795 | ||
1663 | static unsigned long long | 1796 | static unsigned long long |
1664 | get_arg_value(struct event_format *event, struct filter_arg *arg, struct pevent_record *record) | 1797 | get_arg_value(struct event_format *event, struct filter_arg *arg, |
1798 | struct pevent_record *record, enum pevent_errno *err) | ||
1665 | { | 1799 | { |
1666 | switch (arg->type) { | 1800 | switch (arg->type) { |
1667 | case FILTER_ARG_FIELD: | 1801 | case FILTER_ARG_FIELD: |
1668 | return get_value(event, arg->field.field, record); | 1802 | return get_value(event, arg->field.field, record); |
1669 | 1803 | ||
1670 | case FILTER_ARG_VALUE: | 1804 | case FILTER_ARG_VALUE: |
1671 | if (arg->value.type != FILTER_NUMBER) | 1805 | if (arg->value.type != FILTER_NUMBER) { |
1672 | die("must have number field!"); | 1806 | if (!*err) |
1807 | *err = PEVENT_ERRNO__NOT_A_NUMBER; | ||
1808 | } | ||
1673 | return arg->value.val; | 1809 | return arg->value.val; |
1674 | 1810 | ||
1675 | case FILTER_ARG_EXP: | 1811 | case FILTER_ARG_EXP: |
1676 | return get_exp_value(event, arg, record); | 1812 | return get_exp_value(event, arg, record, err); |
1677 | 1813 | ||
1678 | default: | 1814 | default: |
1679 | die("oops in filter"); | 1815 | if (!*err) |
1816 | *err = PEVENT_ERRNO__INVALID_ARG_TYPE; | ||
1680 | } | 1817 | } |
1681 | return 0; | 1818 | return 0; |
1682 | } | 1819 | } |
1683 | 1820 | ||
1684 | static int test_num(struct event_format *event, | 1821 | static int test_num(struct event_format *event, struct filter_arg *arg, |
1685 | struct filter_arg *arg, struct pevent_record *record) | 1822 | struct pevent_record *record, enum pevent_errno *err) |
1686 | { | 1823 | { |
1687 | unsigned long long lval, rval; | 1824 | unsigned long long lval, rval; |
1688 | 1825 | ||
1689 | lval = get_arg_value(event, arg->num.left, record); | 1826 | lval = get_arg_value(event, arg->num.left, record, err); |
1690 | rval = get_arg_value(event, arg->num.right, record); | 1827 | rval = get_arg_value(event, arg->num.right, record, err); |
1828 | |||
1829 | if (*err) { | ||
1830 | /* | ||
1831 | * There was an error, no need to process anymore. | ||
1832 | */ | ||
1833 | return 0; | ||
1834 | } | ||
1691 | 1835 | ||
1692 | switch (arg->num.type) { | 1836 | switch (arg->num.type) { |
1693 | case FILTER_CMP_EQ: | 1837 | case FILTER_CMP_EQ: |
@@ -1709,7 +1853,8 @@ static int test_num(struct event_format *event, | |||
1709 | return lval <= rval; | 1853 | return lval <= rval; |
1710 | 1854 | ||
1711 | default: | 1855 | default: |
1712 | /* ?? */ | 1856 | if (!*err) |
1857 | *err = PEVENT_ERRNO__ILLEGAL_INTEGER_CMP; | ||
1713 | return 0; | 1858 | return 0; |
1714 | } | 1859 | } |
1715 | } | 1860 | } |
@@ -1756,8 +1901,8 @@ static const char *get_field_str(struct filter_arg *arg, struct pevent_record *r | |||
1756 | return val; | 1901 | return val; |
1757 | } | 1902 | } |
1758 | 1903 | ||
1759 | static int test_str(struct event_format *event, | 1904 | static int test_str(struct event_format *event, struct filter_arg *arg, |
1760 | struct filter_arg *arg, struct pevent_record *record) | 1905 | struct pevent_record *record, enum pevent_errno *err) |
1761 | { | 1906 | { |
1762 | const char *val; | 1907 | const char *val; |
1763 | 1908 | ||
@@ -1781,48 +1926,57 @@ static int test_str(struct event_format *event, | |||
1781 | return regexec(&arg->str.reg, val, 0, NULL, 0); | 1926 | return regexec(&arg->str.reg, val, 0, NULL, 0); |
1782 | 1927 | ||
1783 | default: | 1928 | default: |
1784 | /* ?? */ | 1929 | if (!*err) |
1930 | *err = PEVENT_ERRNO__ILLEGAL_STRING_CMP; | ||
1785 | return 0; | 1931 | return 0; |
1786 | } | 1932 | } |
1787 | } | 1933 | } |
1788 | 1934 | ||
1789 | static int test_op(struct event_format *event, | 1935 | static int test_op(struct event_format *event, struct filter_arg *arg, |
1790 | struct filter_arg *arg, struct pevent_record *record) | 1936 | struct pevent_record *record, enum pevent_errno *err) |
1791 | { | 1937 | { |
1792 | switch (arg->op.type) { | 1938 | switch (arg->op.type) { |
1793 | case FILTER_OP_AND: | 1939 | case FILTER_OP_AND: |
1794 | return test_filter(event, arg->op.left, record) && | 1940 | return test_filter(event, arg->op.left, record, err) && |
1795 | test_filter(event, arg->op.right, record); | 1941 | test_filter(event, arg->op.right, record, err); |
1796 | 1942 | ||
1797 | case FILTER_OP_OR: | 1943 | case FILTER_OP_OR: |
1798 | return test_filter(event, arg->op.left, record) || | 1944 | return test_filter(event, arg->op.left, record, err) || |
1799 | test_filter(event, arg->op.right, record); | 1945 | test_filter(event, arg->op.right, record, err); |
1800 | 1946 | ||
1801 | case FILTER_OP_NOT: | 1947 | case FILTER_OP_NOT: |
1802 | return !test_filter(event, arg->op.right, record); | 1948 | return !test_filter(event, arg->op.right, record, err); |
1803 | 1949 | ||
1804 | default: | 1950 | default: |
1805 | /* ?? */ | 1951 | if (!*err) |
1952 | *err = PEVENT_ERRNO__INVALID_OP_TYPE; | ||
1806 | return 0; | 1953 | return 0; |
1807 | } | 1954 | } |
1808 | } | 1955 | } |
1809 | 1956 | ||
1810 | static int test_filter(struct event_format *event, | 1957 | static int test_filter(struct event_format *event, struct filter_arg *arg, |
1811 | struct filter_arg *arg, struct pevent_record *record) | 1958 | struct pevent_record *record, enum pevent_errno *err) |
1812 | { | 1959 | { |
1960 | if (*err) { | ||
1961 | /* | ||
1962 | * There was an error, no need to process anymore. | ||
1963 | */ | ||
1964 | return 0; | ||
1965 | } | ||
1966 | |||
1813 | switch (arg->type) { | 1967 | switch (arg->type) { |
1814 | case FILTER_ARG_BOOLEAN: | 1968 | case FILTER_ARG_BOOLEAN: |
1815 | /* easy case */ | 1969 | /* easy case */ |
1816 | return arg->boolean.value; | 1970 | return arg->boolean.value; |
1817 | 1971 | ||
1818 | case FILTER_ARG_OP: | 1972 | case FILTER_ARG_OP: |
1819 | return test_op(event, arg, record); | 1973 | return test_op(event, arg, record, err); |
1820 | 1974 | ||
1821 | case FILTER_ARG_NUM: | 1975 | case FILTER_ARG_NUM: |
1822 | return test_num(event, arg, record); | 1976 | return test_num(event, arg, record, err); |
1823 | 1977 | ||
1824 | case FILTER_ARG_STR: | 1978 | case FILTER_ARG_STR: |
1825 | return test_str(event, arg, record); | 1979 | return test_str(event, arg, record, err); |
1826 | 1980 | ||
1827 | case FILTER_ARG_EXP: | 1981 | case FILTER_ARG_EXP: |
1828 | case FILTER_ARG_VALUE: | 1982 | case FILTER_ARG_VALUE: |
@@ -1831,11 +1985,11 @@ static int test_filter(struct event_format *event, | |||
1831 | * Expressions, fields and values evaluate | 1985 | * Expressions, fields and values evaluate |
1832 | * to true if they return non zero | 1986 | * to true if they return non zero |
1833 | */ | 1987 | */ |
1834 | return !!get_arg_value(event, arg, record); | 1988 | return !!get_arg_value(event, arg, record, err); |
1835 | 1989 | ||
1836 | default: | 1990 | default: |
1837 | die("oops!"); | 1991 | if (!*err) |
1838 | /* ?? */ | 1992 | *err = PEVENT_ERRNO__INVALID_ARG_TYPE; |
1839 | return 0; | 1993 | return 0; |
1840 | } | 1994 | } |
1841 | } | 1995 | } |
@@ -1848,8 +2002,7 @@ static int test_filter(struct event_format *event, | |||
1848 | * Returns 1 if filter found for @event_id | 2002 | * Returns 1 if filter found for @event_id |
1849 | * otherwise 0; | 2003 | * otherwise 0; |
1850 | */ | 2004 | */ |
1851 | int pevent_event_filtered(struct event_filter *filter, | 2005 | int pevent_event_filtered(struct event_filter *filter, int event_id) |
1852 | int event_id) | ||
1853 | { | 2006 | { |
1854 | struct filter_type *filter_type; | 2007 | struct filter_type *filter_type; |
1855 | 2008 | ||
@@ -1866,31 +2019,38 @@ int pevent_event_filtered(struct event_filter *filter, | |||
1866 | * @filter: filter struct with filter information | 2019 | * @filter: filter struct with filter information |
1867 | * @record: the record to test against the filter | 2020 | * @record: the record to test against the filter |
1868 | * | 2021 | * |
1869 | * Returns: | 2022 | * Returns: match result or error code (prefixed with PEVENT_ERRNO__) |
1870 | * 1 - filter found for event and @record matches | 2023 | * FILTER_MATCH - filter found for event and @record matches |
1871 | * 0 - filter found for event and @record does not match | 2024 | * FILTER_MISS - filter found for event and @record does not match |
1872 | * -1 - no filter found for @record's event | 2025 | * FILTER_NOT_FOUND - no filter found for @record's event |
1873 | * -2 - if no filters exist | 2026 | * NO_FILTER - if no filters exist |
2027 | * otherwise - error occurred during test | ||
1874 | */ | 2028 | */ |
1875 | int pevent_filter_match(struct event_filter *filter, | 2029 | enum pevent_errno pevent_filter_match(struct event_filter *filter, |
1876 | struct pevent_record *record) | 2030 | struct pevent_record *record) |
1877 | { | 2031 | { |
1878 | struct pevent *pevent = filter->pevent; | 2032 | struct pevent *pevent = filter->pevent; |
1879 | struct filter_type *filter_type; | 2033 | struct filter_type *filter_type; |
1880 | int event_id; | 2034 | int event_id; |
2035 | int ret; | ||
2036 | enum pevent_errno err = 0; | ||
2037 | |||
2038 | filter_init_error_buf(filter); | ||
1881 | 2039 | ||
1882 | if (!filter->filters) | 2040 | if (!filter->filters) |
1883 | return FILTER_NONE; | 2041 | return PEVENT_ERRNO__NO_FILTER; |
1884 | 2042 | ||
1885 | event_id = pevent_data_type(pevent, record); | 2043 | event_id = pevent_data_type(pevent, record); |
1886 | 2044 | ||
1887 | filter_type = find_filter_type(filter, event_id); | 2045 | filter_type = find_filter_type(filter, event_id); |
1888 | |||
1889 | if (!filter_type) | 2046 | if (!filter_type) |
1890 | return FILTER_NOEXIST; | 2047 | return PEVENT_ERRNO__FILTER_NOT_FOUND; |
2048 | |||
2049 | ret = test_filter(filter_type->event, filter_type->filter, record, &err); | ||
2050 | if (err) | ||
2051 | return err; | ||
1891 | 2052 | ||
1892 | return test_filter(filter_type->event, filter_type->filter, record) ? | 2053 | return ret ? PEVENT_ERRNO__FILTER_MATCH : PEVENT_ERRNO__FILTER_MISS; |
1893 | FILTER_MATCH : FILTER_MISS; | ||
1894 | } | 2054 | } |
1895 | 2055 | ||
1896 | static char *op_to_str(struct event_filter *filter, struct filter_arg *arg) | 2056 | static char *op_to_str(struct event_filter *filter, struct filter_arg *arg) |
@@ -1902,7 +2062,6 @@ static char *op_to_str(struct event_filter *filter, struct filter_arg *arg) | |||
1902 | int left_val = -1; | 2062 | int left_val = -1; |
1903 | int right_val = -1; | 2063 | int right_val = -1; |
1904 | int val; | 2064 | int val; |
1905 | int len; | ||
1906 | 2065 | ||
1907 | switch (arg->op.type) { | 2066 | switch (arg->op.type) { |
1908 | case FILTER_OP_AND: | 2067 | case FILTER_OP_AND: |
@@ -1949,11 +2108,7 @@ static char *op_to_str(struct event_filter *filter, struct filter_arg *arg) | |||
1949 | default: | 2108 | default: |
1950 | break; | 2109 | break; |
1951 | } | 2110 | } |
1952 | str = malloc_or_die(6); | 2111 | asprintf(&str, val ? "TRUE" : "FALSE"); |
1953 | if (val) | ||
1954 | strcpy(str, "TRUE"); | ||
1955 | else | ||
1956 | strcpy(str, "FALSE"); | ||
1957 | break; | 2112 | break; |
1958 | } | 2113 | } |
1959 | } | 2114 | } |
@@ -1971,10 +2126,7 @@ static char *op_to_str(struct event_filter *filter, struct filter_arg *arg) | |||
1971 | break; | 2126 | break; |
1972 | } | 2127 | } |
1973 | 2128 | ||
1974 | len = strlen(left) + strlen(right) + strlen(op) + 10; | 2129 | asprintf(&str, "(%s) %s (%s)", left, op, right); |
1975 | str = malloc_or_die(len); | ||
1976 | snprintf(str, len, "(%s) %s (%s)", | ||
1977 | left, op, right); | ||
1978 | break; | 2130 | break; |
1979 | 2131 | ||
1980 | case FILTER_OP_NOT: | 2132 | case FILTER_OP_NOT: |
@@ -1990,16 +2142,10 @@ static char *op_to_str(struct event_filter *filter, struct filter_arg *arg) | |||
1990 | right_val = 0; | 2142 | right_val = 0; |
1991 | if (right_val >= 0) { | 2143 | if (right_val >= 0) { |
1992 | /* just return the opposite */ | 2144 | /* just return the opposite */ |
1993 | str = malloc_or_die(6); | 2145 | asprintf(&str, right_val ? "FALSE" : "TRUE"); |
1994 | if (right_val) | ||
1995 | strcpy(str, "FALSE"); | ||
1996 | else | ||
1997 | strcpy(str, "TRUE"); | ||
1998 | break; | 2146 | break; |
1999 | } | 2147 | } |
2000 | len = strlen(right) + strlen(op) + 3; | 2148 | asprintf(&str, "%s(%s)", op, right); |
2001 | str = malloc_or_die(len); | ||
2002 | snprintf(str, len, "%s(%s)", op, right); | ||
2003 | break; | 2149 | break; |
2004 | 2150 | ||
2005 | default: | 2151 | default: |
@@ -2013,11 +2159,9 @@ static char *op_to_str(struct event_filter *filter, struct filter_arg *arg) | |||
2013 | 2159 | ||
2014 | static char *val_to_str(struct event_filter *filter, struct filter_arg *arg) | 2160 | static char *val_to_str(struct event_filter *filter, struct filter_arg *arg) |
2015 | { | 2161 | { |
2016 | char *str; | 2162 | char *str = NULL; |
2017 | |||
2018 | str = malloc_or_die(30); | ||
2019 | 2163 | ||
2020 | snprintf(str, 30, "%lld", arg->value.val); | 2164 | asprintf(&str, "%lld", arg->value.val); |
2021 | 2165 | ||
2022 | return str; | 2166 | return str; |
2023 | } | 2167 | } |
@@ -2033,7 +2177,6 @@ static char *exp_to_str(struct event_filter *filter, struct filter_arg *arg) | |||
2033 | char *rstr; | 2177 | char *rstr; |
2034 | char *op; | 2178 | char *op; |
2035 | char *str = NULL; | 2179 | char *str = NULL; |
2036 | int len; | ||
2037 | 2180 | ||
2038 | lstr = arg_to_str(filter, arg->exp.left); | 2181 | lstr = arg_to_str(filter, arg->exp.left); |
2039 | rstr = arg_to_str(filter, arg->exp.right); | 2182 | rstr = arg_to_str(filter, arg->exp.right); |
@@ -2072,12 +2215,11 @@ static char *exp_to_str(struct event_filter *filter, struct filter_arg *arg) | |||
2072 | op = "^"; | 2215 | op = "^"; |
2073 | break; | 2216 | break; |
2074 | default: | 2217 | default: |
2075 | die("oops in exp"); | 2218 | op = "[ERROR IN EXPRESSION TYPE]"; |
2219 | break; | ||
2076 | } | 2220 | } |
2077 | 2221 | ||
2078 | len = strlen(op) + strlen(lstr) + strlen(rstr) + 4; | 2222 | asprintf(&str, "%s %s %s", lstr, op, rstr); |
2079 | str = malloc_or_die(len); | ||
2080 | snprintf(str, len, "%s %s %s", lstr, op, rstr); | ||
2081 | out: | 2223 | out: |
2082 | free(lstr); | 2224 | free(lstr); |
2083 | free(rstr); | 2225 | free(rstr); |
@@ -2091,7 +2233,6 @@ static char *num_to_str(struct event_filter *filter, struct filter_arg *arg) | |||
2091 | char *rstr; | 2233 | char *rstr; |
2092 | char *str = NULL; | 2234 | char *str = NULL; |
2093 | char *op = NULL; | 2235 | char *op = NULL; |
2094 | int len; | ||
2095 | 2236 | ||
2096 | lstr = arg_to_str(filter, arg->num.left); | 2237 | lstr = arg_to_str(filter, arg->num.left); |
2097 | rstr = arg_to_str(filter, arg->num.right); | 2238 | rstr = arg_to_str(filter, arg->num.right); |
@@ -2122,10 +2263,7 @@ static char *num_to_str(struct event_filter *filter, struct filter_arg *arg) | |||
2122 | if (!op) | 2263 | if (!op) |
2123 | op = "<="; | 2264 | op = "<="; |
2124 | 2265 | ||
2125 | len = strlen(lstr) + strlen(op) + strlen(rstr) + 4; | 2266 | asprintf(&str, "%s %s %s", lstr, op, rstr); |
2126 | str = malloc_or_die(len); | ||
2127 | sprintf(str, "%s %s %s", lstr, op, rstr); | ||
2128 | |||
2129 | break; | 2267 | break; |
2130 | 2268 | ||
2131 | default: | 2269 | default: |
@@ -2143,7 +2281,6 @@ static char *str_to_str(struct event_filter *filter, struct filter_arg *arg) | |||
2143 | { | 2281 | { |
2144 | char *str = NULL; | 2282 | char *str = NULL; |
2145 | char *op = NULL; | 2283 | char *op = NULL; |
2146 | int len; | ||
2147 | 2284 | ||
2148 | switch (arg->str.type) { | 2285 | switch (arg->str.type) { |
2149 | case FILTER_CMP_MATCH: | 2286 | case FILTER_CMP_MATCH: |
@@ -2161,12 +2298,8 @@ static char *str_to_str(struct event_filter *filter, struct filter_arg *arg) | |||
2161 | if (!op) | 2298 | if (!op) |
2162 | op = "!~"; | 2299 | op = "!~"; |
2163 | 2300 | ||
2164 | len = strlen(arg->str.field->name) + strlen(op) + | 2301 | asprintf(&str, "%s %s \"%s\"", |
2165 | strlen(arg->str.val) + 6; | 2302 | arg->str.field->name, op, arg->str.val); |
2166 | str = malloc_or_die(len); | ||
2167 | snprintf(str, len, "%s %s \"%s\"", | ||
2168 | arg->str.field->name, | ||
2169 | op, arg->str.val); | ||
2170 | break; | 2303 | break; |
2171 | 2304 | ||
2172 | default: | 2305 | default: |
@@ -2178,15 +2311,11 @@ static char *str_to_str(struct event_filter *filter, struct filter_arg *arg) | |||
2178 | 2311 | ||
2179 | static char *arg_to_str(struct event_filter *filter, struct filter_arg *arg) | 2312 | static char *arg_to_str(struct event_filter *filter, struct filter_arg *arg) |
2180 | { | 2313 | { |
2181 | char *str; | 2314 | char *str = NULL; |
2182 | 2315 | ||
2183 | switch (arg->type) { | 2316 | switch (arg->type) { |
2184 | case FILTER_ARG_BOOLEAN: | 2317 | case FILTER_ARG_BOOLEAN: |
2185 | str = malloc_or_die(6); | 2318 | asprintf(&str, arg->boolean.value ? "TRUE" : "FALSE"); |
2186 | if (arg->boolean.value) | ||
2187 | strcpy(str, "TRUE"); | ||
2188 | else | ||
2189 | strcpy(str, "FALSE"); | ||
2190 | return str; | 2319 | return str; |
2191 | 2320 | ||
2192 | case FILTER_ARG_OP: | 2321 | case FILTER_ARG_OP: |
@@ -2221,7 +2350,7 @@ static char *arg_to_str(struct event_filter *filter, struct filter_arg *arg) | |||
2221 | * | 2350 | * |
2222 | * Returns a string that displays the filter contents. | 2351 | * Returns a string that displays the filter contents. |
2223 | * This string must be freed with free(str). | 2352 | * This string must be freed with free(str). |
2224 | * NULL is returned if no filter is found. | 2353 | * NULL is returned if no filter is found or allocation failed. |
2225 | */ | 2354 | */ |
2226 | char * | 2355 | char * |
2227 | pevent_filter_make_string(struct event_filter *filter, int event_id) | 2356 | pevent_filter_make_string(struct event_filter *filter, int event_id) |
diff --git a/tools/lib/traceevent/parse-utils.c b/tools/lib/traceevent/parse-utils.c index bba701cf10e6..eda07fa31dca 100644 --- a/tools/lib/traceevent/parse-utils.c +++ b/tools/lib/traceevent/parse-utils.c | |||
@@ -25,40 +25,6 @@ | |||
25 | 25 | ||
26 | #define __weak __attribute__((weak)) | 26 | #define __weak __attribute__((weak)) |
27 | 27 | ||
28 | void __vdie(const char *fmt, va_list ap) | ||
29 | { | ||
30 | int ret = errno; | ||
31 | |||
32 | if (errno) | ||
33 | perror("trace-cmd"); | ||
34 | else | ||
35 | ret = -1; | ||
36 | |||
37 | fprintf(stderr, " "); | ||
38 | vfprintf(stderr, fmt, ap); | ||
39 | |||
40 | fprintf(stderr, "\n"); | ||
41 | exit(ret); | ||
42 | } | ||
43 | |||
44 | void __die(const char *fmt, ...) | ||
45 | { | ||
46 | va_list ap; | ||
47 | |||
48 | va_start(ap, fmt); | ||
49 | __vdie(fmt, ap); | ||
50 | va_end(ap); | ||
51 | } | ||
52 | |||
53 | void __weak die(const char *fmt, ...) | ||
54 | { | ||
55 | va_list ap; | ||
56 | |||
57 | va_start(ap, fmt); | ||
58 | __vdie(fmt, ap); | ||
59 | va_end(ap); | ||
60 | } | ||
61 | |||
62 | void __vwarning(const char *fmt, va_list ap) | 28 | void __vwarning(const char *fmt, va_list ap) |
63 | { | 29 | { |
64 | if (errno) | 30 | if (errno) |
@@ -117,13 +83,3 @@ void __weak pr_stat(const char *fmt, ...) | |||
117 | __vpr_stat(fmt, ap); | 83 | __vpr_stat(fmt, ap); |
118 | va_end(ap); | 84 | va_end(ap); |
119 | } | 85 | } |
120 | |||
121 | void __weak *malloc_or_die(unsigned int size) | ||
122 | { | ||
123 | void *data; | ||
124 | |||
125 | data = malloc(size); | ||
126 | if (!data) | ||
127 | die("malloc"); | ||
128 | return data; | ||
129 | } | ||
diff --git a/tools/lib/traceevent/plugin_cfg80211.c b/tools/lib/traceevent/plugin_cfg80211.c new file mode 100644 index 000000000000..c066b25905f8 --- /dev/null +++ b/tools/lib/traceevent/plugin_cfg80211.c | |||
@@ -0,0 +1,30 @@ | |||
1 | #include <stdio.h> | ||
2 | #include <string.h> | ||
3 | #include <inttypes.h> | ||
4 | #include <endian.h> | ||
5 | #include "event-parse.h" | ||
6 | |||
7 | static unsigned long long | ||
8 | process___le16_to_cpup(struct trace_seq *s, | ||
9 | unsigned long long *args) | ||
10 | { | ||
11 | uint16_t *val = (uint16_t *) (unsigned long) args[0]; | ||
12 | return val ? (long long) le16toh(*val) : 0; | ||
13 | } | ||
14 | |||
15 | int PEVENT_PLUGIN_LOADER(struct pevent *pevent) | ||
16 | { | ||
17 | pevent_register_print_function(pevent, | ||
18 | process___le16_to_cpup, | ||
19 | PEVENT_FUNC_ARG_INT, | ||
20 | "__le16_to_cpup", | ||
21 | PEVENT_FUNC_ARG_PTR, | ||
22 | PEVENT_FUNC_ARG_VOID); | ||
23 | return 0; | ||
24 | } | ||
25 | |||
26 | void PEVENT_PLUGIN_UNLOADER(struct pevent *pevent) | ||
27 | { | ||
28 | pevent_unregister_print_function(pevent, process___le16_to_cpup, | ||
29 | "__le16_to_cpup"); | ||
30 | } | ||
diff --git a/tools/lib/traceevent/plugin_function.c b/tools/lib/traceevent/plugin_function.c new file mode 100644 index 000000000000..80ba4ff1fe84 --- /dev/null +++ b/tools/lib/traceevent/plugin_function.c | |||
@@ -0,0 +1,163 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2009, 2010 Red Hat Inc, Steven Rostedt <srostedt@redhat.com> | ||
3 | * | ||
4 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
5 | * This program is free software; you can redistribute it and/or | ||
6 | * modify it under the terms of the GNU Lesser General Public | ||
7 | * License as published by the Free Software Foundation; | ||
8 | * version 2.1 of the License (not later!) | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU Lesser General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU Lesser General Public | ||
16 | * License along with this program; if not, see <http://www.gnu.org/licenses> | ||
17 | * | ||
18 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
19 | */ | ||
20 | #include <stdio.h> | ||
21 | #include <stdlib.h> | ||
22 | #include <string.h> | ||
23 | |||
24 | #include "event-parse.h" | ||
25 | #include "event-utils.h" | ||
26 | |||
27 | static struct func_stack { | ||
28 | int size; | ||
29 | char **stack; | ||
30 | } *fstack; | ||
31 | |||
32 | static int cpus = -1; | ||
33 | |||
34 | #define STK_BLK 10 | ||
35 | |||
36 | static void add_child(struct func_stack *stack, const char *child, int pos) | ||
37 | { | ||
38 | int i; | ||
39 | |||
40 | if (!child) | ||
41 | return; | ||
42 | |||
43 | if (pos < stack->size) | ||
44 | free(stack->stack[pos]); | ||
45 | else { | ||
46 | char **ptr; | ||
47 | |||
48 | ptr = realloc(stack->stack, sizeof(char *) * | ||
49 | (stack->size + STK_BLK)); | ||
50 | if (!ptr) { | ||
51 | warning("could not allocate plugin memory\n"); | ||
52 | return; | ||
53 | } | ||
54 | |||
55 | stack->stack = ptr; | ||
56 | |||
57 | for (i = stack->size; i < stack->size + STK_BLK; i++) | ||
58 | stack->stack[i] = NULL; | ||
59 | stack->size += STK_BLK; | ||
60 | } | ||
61 | |||
62 | stack->stack[pos] = strdup(child); | ||
63 | } | ||
64 | |||
65 | static int add_and_get_index(const char *parent, const char *child, int cpu) | ||
66 | { | ||
67 | int i; | ||
68 | |||
69 | if (cpu < 0) | ||
70 | return 0; | ||
71 | |||
72 | if (cpu > cpus) { | ||
73 | struct func_stack *ptr; | ||
74 | |||
75 | ptr = realloc(fstack, sizeof(*fstack) * (cpu + 1)); | ||
76 | if (!ptr) { | ||
77 | warning("could not allocate plugin memory\n"); | ||
78 | return 0; | ||
79 | } | ||
80 | |||
81 | fstack = ptr; | ||
82 | |||
83 | /* Account for holes in the cpu count */ | ||
84 | for (i = cpus + 1; i <= cpu; i++) | ||
85 | memset(&fstack[i], 0, sizeof(fstack[i])); | ||
86 | cpus = cpu; | ||
87 | } | ||
88 | |||
89 | for (i = 0; i < fstack[cpu].size && fstack[cpu].stack[i]; i++) { | ||
90 | if (strcmp(parent, fstack[cpu].stack[i]) == 0) { | ||
91 | add_child(&fstack[cpu], child, i+1); | ||
92 | return i; | ||
93 | } | ||
94 | } | ||
95 | |||
96 | /* Not found */ | ||
97 | add_child(&fstack[cpu], parent, 0); | ||
98 | add_child(&fstack[cpu], child, 1); | ||
99 | return 0; | ||
100 | } | ||
101 | |||
102 | static int function_handler(struct trace_seq *s, struct pevent_record *record, | ||
103 | struct event_format *event, void *context) | ||
104 | { | ||
105 | struct pevent *pevent = event->pevent; | ||
106 | unsigned long long function; | ||
107 | unsigned long long pfunction; | ||
108 | const char *func; | ||
109 | const char *parent; | ||
110 | int index; | ||
111 | |||
112 | if (pevent_get_field_val(s, event, "ip", record, &function, 1)) | ||
113 | return trace_seq_putc(s, '!'); | ||
114 | |||
115 | func = pevent_find_function(pevent, function); | ||
116 | |||
117 | if (pevent_get_field_val(s, event, "parent_ip", record, &pfunction, 1)) | ||
118 | return trace_seq_putc(s, '!'); | ||
119 | |||
120 | parent = pevent_find_function(pevent, pfunction); | ||
121 | |||
122 | index = add_and_get_index(parent, func, record->cpu); | ||
123 | |||
124 | trace_seq_printf(s, "%*s", index*3, ""); | ||
125 | |||
126 | if (func) | ||
127 | trace_seq_printf(s, "%s", func); | ||
128 | else | ||
129 | trace_seq_printf(s, "0x%llx", function); | ||
130 | |||
131 | trace_seq_printf(s, " <-- "); | ||
132 | if (parent) | ||
133 | trace_seq_printf(s, "%s", parent); | ||
134 | else | ||
135 | trace_seq_printf(s, "0x%llx", pfunction); | ||
136 | |||
137 | return 0; | ||
138 | } | ||
139 | |||
140 | int PEVENT_PLUGIN_LOADER(struct pevent *pevent) | ||
141 | { | ||
142 | pevent_register_event_handler(pevent, -1, "ftrace", "function", | ||
143 | function_handler, NULL); | ||
144 | return 0; | ||
145 | } | ||
146 | |||
147 | void PEVENT_PLUGIN_UNLOADER(struct pevent *pevent) | ||
148 | { | ||
149 | int i, x; | ||
150 | |||
151 | pevent_unregister_event_handler(pevent, -1, "ftrace", "function", | ||
152 | function_handler, NULL); | ||
153 | |||
154 | for (i = 0; i <= cpus; i++) { | ||
155 | for (x = 0; x < fstack[i].size && fstack[i].stack[x]; x++) | ||
156 | free(fstack[i].stack[x]); | ||
157 | free(fstack[i].stack); | ||
158 | } | ||
159 | |||
160 | free(fstack); | ||
161 | fstack = NULL; | ||
162 | cpus = -1; | ||
163 | } | ||
diff --git a/tools/lib/traceevent/plugin_hrtimer.c b/tools/lib/traceevent/plugin_hrtimer.c new file mode 100644 index 000000000000..12bf14cc1152 --- /dev/null +++ b/tools/lib/traceevent/plugin_hrtimer.c | |||
@@ -0,0 +1,88 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2009 Red Hat Inc, Steven Rostedt <srostedt@redhat.com> | ||
3 | * Copyright (C) 2009 Johannes Berg <johannes@sipsolutions.net> | ||
4 | * | ||
5 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU Lesser General Public | ||
8 | * License as published by the Free Software Foundation; | ||
9 | * version 2.1 of the License (not later!) | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU Lesser General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU Lesser General Public | ||
17 | * License along with this program; if not, see <http://www.gnu.org/licenses> | ||
18 | * | ||
19 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
20 | */ | ||
21 | #include <stdio.h> | ||
22 | #include <stdlib.h> | ||
23 | #include <string.h> | ||
24 | |||
25 | #include "event-parse.h" | ||
26 | |||
27 | static int timer_expire_handler(struct trace_seq *s, | ||
28 | struct pevent_record *record, | ||
29 | struct event_format *event, void *context) | ||
30 | { | ||
31 | trace_seq_printf(s, "hrtimer="); | ||
32 | |||
33 | if (pevent_print_num_field(s, "0x%llx", event, "timer", | ||
34 | record, 0) == -1) | ||
35 | pevent_print_num_field(s, "0x%llx", event, "hrtimer", | ||
36 | record, 1); | ||
37 | |||
38 | trace_seq_printf(s, " now="); | ||
39 | |||
40 | pevent_print_num_field(s, "%llu", event, "now", record, 1); | ||
41 | |||
42 | pevent_print_func_field(s, " function=%s", event, "function", | ||
43 | record, 0); | ||
44 | return 0; | ||
45 | } | ||
46 | |||
47 | static int timer_start_handler(struct trace_seq *s, | ||
48 | struct pevent_record *record, | ||
49 | struct event_format *event, void *context) | ||
50 | { | ||
51 | trace_seq_printf(s, "hrtimer="); | ||
52 | |||
53 | if (pevent_print_num_field(s, "0x%llx", event, "timer", | ||
54 | record, 0) == -1) | ||
55 | pevent_print_num_field(s, "0x%llx", event, "hrtimer", | ||
56 | record, 1); | ||
57 | |||
58 | pevent_print_func_field(s, " function=%s", event, "function", | ||
59 | record, 0); | ||
60 | |||
61 | trace_seq_printf(s, " expires="); | ||
62 | pevent_print_num_field(s, "%llu", event, "expires", record, 1); | ||
63 | |||
64 | trace_seq_printf(s, " softexpires="); | ||
65 | pevent_print_num_field(s, "%llu", event, "softexpires", record, 1); | ||
66 | return 0; | ||
67 | } | ||
68 | |||
69 | int PEVENT_PLUGIN_LOADER(struct pevent *pevent) | ||
70 | { | ||
71 | pevent_register_event_handler(pevent, -1, | ||
72 | "timer", "hrtimer_expire_entry", | ||
73 | timer_expire_handler, NULL); | ||
74 | |||
75 | pevent_register_event_handler(pevent, -1, "timer", "hrtimer_start", | ||
76 | timer_start_handler, NULL); | ||
77 | return 0; | ||
78 | } | ||
79 | |||
80 | void PEVENT_PLUGIN_UNLOADER(struct pevent *pevent) | ||
81 | { | ||
82 | pevent_unregister_event_handler(pevent, -1, | ||
83 | "timer", "hrtimer_expire_entry", | ||
84 | timer_expire_handler, NULL); | ||
85 | |||
86 | pevent_unregister_event_handler(pevent, -1, "timer", "hrtimer_start", | ||
87 | timer_start_handler, NULL); | ||
88 | } | ||
diff --git a/tools/lib/traceevent/plugin_jbd2.c b/tools/lib/traceevent/plugin_jbd2.c new file mode 100644 index 000000000000..0db714c721be --- /dev/null +++ b/tools/lib/traceevent/plugin_jbd2.c | |||
@@ -0,0 +1,77 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2010 Red Hat Inc, Steven Rostedt <srostedt@redhat.com> | ||
3 | * | ||
4 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
5 | * This program is free software; you can redistribute it and/or | ||
6 | * modify it under the terms of the GNU Lesser General Public | ||
7 | * License as published by the Free Software Foundation; | ||
8 | * version 2.1 of the License (not later!) | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU Lesser General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU Lesser General Public | ||
16 | * License along with this program; if not, see <http://www.gnu.org/licenses> | ||
17 | * | ||
18 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
19 | */ | ||
20 | #include <stdio.h> | ||
21 | #include <stdlib.h> | ||
22 | #include <string.h> | ||
23 | |||
24 | #include "event-parse.h" | ||
25 | |||
26 | #define MINORBITS 20 | ||
27 | #define MINORMASK ((1U << MINORBITS) - 1) | ||
28 | |||
29 | #define MAJOR(dev) ((unsigned int) ((dev) >> MINORBITS)) | ||
30 | #define MINOR(dev) ((unsigned int) ((dev) & MINORMASK)) | ||
31 | |||
32 | static unsigned long long | ||
33 | process_jbd2_dev_to_name(struct trace_seq *s, | ||
34 | unsigned long long *args) | ||
35 | { | ||
36 | unsigned int dev = args[0]; | ||
37 | |||
38 | trace_seq_printf(s, "%d:%d", MAJOR(dev), MINOR(dev)); | ||
39 | return 0; | ||
40 | } | ||
41 | |||
42 | static unsigned long long | ||
43 | process_jiffies_to_msecs(struct trace_seq *s, | ||
44 | unsigned long long *args) | ||
45 | { | ||
46 | unsigned long long jiffies = args[0]; | ||
47 | |||
48 | trace_seq_printf(s, "%lld", jiffies); | ||
49 | return jiffies; | ||
50 | } | ||
51 | |||
52 | int PEVENT_PLUGIN_LOADER(struct pevent *pevent) | ||
53 | { | ||
54 | pevent_register_print_function(pevent, | ||
55 | process_jbd2_dev_to_name, | ||
56 | PEVENT_FUNC_ARG_STRING, | ||
57 | "jbd2_dev_to_name", | ||
58 | PEVENT_FUNC_ARG_INT, | ||
59 | PEVENT_FUNC_ARG_VOID); | ||
60 | |||
61 | pevent_register_print_function(pevent, | ||
62 | process_jiffies_to_msecs, | ||
63 | PEVENT_FUNC_ARG_LONG, | ||
64 | "jiffies_to_msecs", | ||
65 | PEVENT_FUNC_ARG_LONG, | ||
66 | PEVENT_FUNC_ARG_VOID); | ||
67 | return 0; | ||
68 | } | ||
69 | |||
70 | void PEVENT_PLUGIN_UNLOADER(struct pevent *pevent) | ||
71 | { | ||
72 | pevent_unregister_print_function(pevent, process_jbd2_dev_to_name, | ||
73 | "jbd2_dev_to_name"); | ||
74 | |||
75 | pevent_unregister_print_function(pevent, process_jiffies_to_msecs, | ||
76 | "jiffies_to_msecs"); | ||
77 | } | ||
diff --git a/tools/lib/traceevent/plugin_kmem.c b/tools/lib/traceevent/plugin_kmem.c new file mode 100644 index 000000000000..70650ff48d78 --- /dev/null +++ b/tools/lib/traceevent/plugin_kmem.c | |||
@@ -0,0 +1,94 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2009 Red Hat Inc, Steven Rostedt <srostedt@redhat.com> | ||
3 | * | ||
4 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
5 | * This program is free software; you can redistribute it and/or | ||
6 | * modify it under the terms of the GNU Lesser General Public | ||
7 | * License as published by the Free Software Foundation; | ||
8 | * version 2.1 of the License (not later!) | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU Lesser General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU Lesser General Public | ||
16 | * License along with this program; if not, see <http://www.gnu.org/licenses> | ||
17 | * | ||
18 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
19 | */ | ||
20 | #include <stdio.h> | ||
21 | #include <stdlib.h> | ||
22 | #include <string.h> | ||
23 | |||
24 | #include "event-parse.h" | ||
25 | |||
26 | static int call_site_handler(struct trace_seq *s, struct pevent_record *record, | ||
27 | struct event_format *event, void *context) | ||
28 | { | ||
29 | struct format_field *field; | ||
30 | unsigned long long val, addr; | ||
31 | void *data = record->data; | ||
32 | const char *func; | ||
33 | |||
34 | field = pevent_find_field(event, "call_site"); | ||
35 | if (!field) | ||
36 | return 1; | ||
37 | |||
38 | if (pevent_read_number_field(field, data, &val)) | ||
39 | return 1; | ||
40 | |||
41 | func = pevent_find_function(event->pevent, val); | ||
42 | if (!func) | ||
43 | return 1; | ||
44 | |||
45 | addr = pevent_find_function_address(event->pevent, val); | ||
46 | |||
47 | trace_seq_printf(s, "(%s+0x%x) ", func, (int)(val - addr)); | ||
48 | return 1; | ||
49 | } | ||
50 | |||
51 | int PEVENT_PLUGIN_LOADER(struct pevent *pevent) | ||
52 | { | ||
53 | pevent_register_event_handler(pevent, -1, "kmem", "kfree", | ||
54 | call_site_handler, NULL); | ||
55 | |||
56 | pevent_register_event_handler(pevent, -1, "kmem", "kmalloc", | ||
57 | call_site_handler, NULL); | ||
58 | |||
59 | pevent_register_event_handler(pevent, -1, "kmem", "kmalloc_node", | ||
60 | call_site_handler, NULL); | ||
61 | |||
62 | pevent_register_event_handler(pevent, -1, "kmem", "kmem_cache_alloc", | ||
63 | call_site_handler, NULL); | ||
64 | |||
65 | pevent_register_event_handler(pevent, -1, "kmem", | ||
66 | "kmem_cache_alloc_node", | ||
67 | call_site_handler, NULL); | ||
68 | |||
69 | pevent_register_event_handler(pevent, -1, "kmem", "kmem_cache_free", | ||
70 | call_site_handler, NULL); | ||
71 | return 0; | ||
72 | } | ||
73 | |||
74 | void PEVENT_PLUGIN_UNLOADER(struct pevent *pevent) | ||
75 | { | ||
76 | pevent_unregister_event_handler(pevent, -1, "kmem", "kfree", | ||
77 | call_site_handler, NULL); | ||
78 | |||
79 | pevent_unregister_event_handler(pevent, -1, "kmem", "kmalloc", | ||
80 | call_site_handler, NULL); | ||
81 | |||
82 | pevent_unregister_event_handler(pevent, -1, "kmem", "kmalloc_node", | ||
83 | call_site_handler, NULL); | ||
84 | |||
85 | pevent_unregister_event_handler(pevent, -1, "kmem", "kmem_cache_alloc", | ||
86 | call_site_handler, NULL); | ||
87 | |||
88 | pevent_unregister_event_handler(pevent, -1, "kmem", | ||
89 | "kmem_cache_alloc_node", | ||
90 | call_site_handler, NULL); | ||
91 | |||
92 | pevent_unregister_event_handler(pevent, -1, "kmem", "kmem_cache_free", | ||
93 | call_site_handler, NULL); | ||
94 | } | ||
diff --git a/tools/lib/traceevent/plugin_kvm.c b/tools/lib/traceevent/plugin_kvm.c new file mode 100644 index 000000000000..9e0e8c61b43b --- /dev/null +++ b/tools/lib/traceevent/plugin_kvm.c | |||
@@ -0,0 +1,465 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2009 Red Hat Inc, Steven Rostedt <srostedt@redhat.com> | ||
3 | * | ||
4 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
5 | * This program is free software; you can redistribute it and/or | ||
6 | * modify it under the terms of the GNU Lesser General Public | ||
7 | * License as published by the Free Software Foundation; | ||
8 | * version 2.1 of the License (not later!) | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU Lesser General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU Lesser General Public | ||
16 | * License along with this program; if not, see <http://www.gnu.org/licenses> | ||
17 | * | ||
18 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
19 | */ | ||
20 | #include <stdio.h> | ||
21 | #include <stdlib.h> | ||
22 | #include <string.h> | ||
23 | #include <stdint.h> | ||
24 | |||
25 | #include "event-parse.h" | ||
26 | |||
27 | #ifdef HAVE_UDIS86 | ||
28 | |||
29 | #include <udis86.h> | ||
30 | |||
31 | static ud_t ud; | ||
32 | |||
33 | static void init_disassembler(void) | ||
34 | { | ||
35 | ud_init(&ud); | ||
36 | ud_set_syntax(&ud, UD_SYN_ATT); | ||
37 | } | ||
38 | |||
39 | static const char *disassemble(unsigned char *insn, int len, uint64_t rip, | ||
40 | int cr0_pe, int eflags_vm, | ||
41 | int cs_d, int cs_l) | ||
42 | { | ||
43 | int mode; | ||
44 | |||
45 | if (!cr0_pe) | ||
46 | mode = 16; | ||
47 | else if (eflags_vm) | ||
48 | mode = 16; | ||
49 | else if (cs_l) | ||
50 | mode = 64; | ||
51 | else if (cs_d) | ||
52 | mode = 32; | ||
53 | else | ||
54 | mode = 16; | ||
55 | |||
56 | ud_set_pc(&ud, rip); | ||
57 | ud_set_mode(&ud, mode); | ||
58 | ud_set_input_buffer(&ud, insn, len); | ||
59 | ud_disassemble(&ud); | ||
60 | return ud_insn_asm(&ud); | ||
61 | } | ||
62 | |||
63 | #else | ||
64 | |||
65 | static void init_disassembler(void) | ||
66 | { | ||
67 | } | ||
68 | |||
69 | static const char *disassemble(unsigned char *insn, int len, uint64_t rip, | ||
70 | int cr0_pe, int eflags_vm, | ||
71 | int cs_d, int cs_l) | ||
72 | { | ||
73 | static char out[15*3+1]; | ||
74 | int i; | ||
75 | |||
76 | for (i = 0; i < len; ++i) | ||
77 | sprintf(out + i * 3, "%02x ", insn[i]); | ||
78 | out[len*3-1] = '\0'; | ||
79 | return out; | ||
80 | } | ||
81 | |||
82 | #endif | ||
83 | |||
84 | |||
85 | #define VMX_EXIT_REASONS \ | ||
86 | _ER(EXCEPTION_NMI, 0) \ | ||
87 | _ER(EXTERNAL_INTERRUPT, 1) \ | ||
88 | _ER(TRIPLE_FAULT, 2) \ | ||
89 | _ER(PENDING_INTERRUPT, 7) \ | ||
90 | _ER(NMI_WINDOW, 8) \ | ||
91 | _ER(TASK_SWITCH, 9) \ | ||
92 | _ER(CPUID, 10) \ | ||
93 | _ER(HLT, 12) \ | ||
94 | _ER(INVD, 13) \ | ||
95 | _ER(INVLPG, 14) \ | ||
96 | _ER(RDPMC, 15) \ | ||
97 | _ER(RDTSC, 16) \ | ||
98 | _ER(VMCALL, 18) \ | ||
99 | _ER(VMCLEAR, 19) \ | ||
100 | _ER(VMLAUNCH, 20) \ | ||
101 | _ER(VMPTRLD, 21) \ | ||
102 | _ER(VMPTRST, 22) \ | ||
103 | _ER(VMREAD, 23) \ | ||
104 | _ER(VMRESUME, 24) \ | ||
105 | _ER(VMWRITE, 25) \ | ||
106 | _ER(VMOFF, 26) \ | ||
107 | _ER(VMON, 27) \ | ||
108 | _ER(CR_ACCESS, 28) \ | ||
109 | _ER(DR_ACCESS, 29) \ | ||
110 | _ER(IO_INSTRUCTION, 30) \ | ||
111 | _ER(MSR_READ, 31) \ | ||
112 | _ER(MSR_WRITE, 32) \ | ||
113 | _ER(MWAIT_INSTRUCTION, 36) \ | ||
114 | _ER(MONITOR_INSTRUCTION, 39) \ | ||
115 | _ER(PAUSE_INSTRUCTION, 40) \ | ||
116 | _ER(MCE_DURING_VMENTRY, 41) \ | ||
117 | _ER(TPR_BELOW_THRESHOLD, 43) \ | ||
118 | _ER(APIC_ACCESS, 44) \ | ||
119 | _ER(EOI_INDUCED, 45) \ | ||
120 | _ER(EPT_VIOLATION, 48) \ | ||
121 | _ER(EPT_MISCONFIG, 49) \ | ||
122 | _ER(INVEPT, 50) \ | ||
123 | _ER(PREEMPTION_TIMER, 52) \ | ||
124 | _ER(WBINVD, 54) \ | ||
125 | _ER(XSETBV, 55) \ | ||
126 | _ER(APIC_WRITE, 56) \ | ||
127 | _ER(INVPCID, 58) | ||
128 | |||
129 | #define SVM_EXIT_REASONS \ | ||
130 | _ER(EXIT_READ_CR0, 0x000) \ | ||
131 | _ER(EXIT_READ_CR3, 0x003) \ | ||
132 | _ER(EXIT_READ_CR4, 0x004) \ | ||
133 | _ER(EXIT_READ_CR8, 0x008) \ | ||
134 | _ER(EXIT_WRITE_CR0, 0x010) \ | ||
135 | _ER(EXIT_WRITE_CR3, 0x013) \ | ||
136 | _ER(EXIT_WRITE_CR4, 0x014) \ | ||
137 | _ER(EXIT_WRITE_CR8, 0x018) \ | ||
138 | _ER(EXIT_READ_DR0, 0x020) \ | ||
139 | _ER(EXIT_READ_DR1, 0x021) \ | ||
140 | _ER(EXIT_READ_DR2, 0x022) \ | ||
141 | _ER(EXIT_READ_DR3, 0x023) \ | ||
142 | _ER(EXIT_READ_DR4, 0x024) \ | ||
143 | _ER(EXIT_READ_DR5, 0x025) \ | ||
144 | _ER(EXIT_READ_DR6, 0x026) \ | ||
145 | _ER(EXIT_READ_DR7, 0x027) \ | ||
146 | _ER(EXIT_WRITE_DR0, 0x030) \ | ||
147 | _ER(EXIT_WRITE_DR1, 0x031) \ | ||
148 | _ER(EXIT_WRITE_DR2, 0x032) \ | ||
149 | _ER(EXIT_WRITE_DR3, 0x033) \ | ||
150 | _ER(EXIT_WRITE_DR4, 0x034) \ | ||
151 | _ER(EXIT_WRITE_DR5, 0x035) \ | ||
152 | _ER(EXIT_WRITE_DR6, 0x036) \ | ||
153 | _ER(EXIT_WRITE_DR7, 0x037) \ | ||
154 | _ER(EXIT_EXCP_BASE, 0x040) \ | ||
155 | _ER(EXIT_INTR, 0x060) \ | ||
156 | _ER(EXIT_NMI, 0x061) \ | ||
157 | _ER(EXIT_SMI, 0x062) \ | ||
158 | _ER(EXIT_INIT, 0x063) \ | ||
159 | _ER(EXIT_VINTR, 0x064) \ | ||
160 | _ER(EXIT_CR0_SEL_WRITE, 0x065) \ | ||
161 | _ER(EXIT_IDTR_READ, 0x066) \ | ||
162 | _ER(EXIT_GDTR_READ, 0x067) \ | ||
163 | _ER(EXIT_LDTR_READ, 0x068) \ | ||
164 | _ER(EXIT_TR_READ, 0x069) \ | ||
165 | _ER(EXIT_IDTR_WRITE, 0x06a) \ | ||
166 | _ER(EXIT_GDTR_WRITE, 0x06b) \ | ||
167 | _ER(EXIT_LDTR_WRITE, 0x06c) \ | ||
168 | _ER(EXIT_TR_WRITE, 0x06d) \ | ||
169 | _ER(EXIT_RDTSC, 0x06e) \ | ||
170 | _ER(EXIT_RDPMC, 0x06f) \ | ||
171 | _ER(EXIT_PUSHF, 0x070) \ | ||
172 | _ER(EXIT_POPF, 0x071) \ | ||
173 | _ER(EXIT_CPUID, 0x072) \ | ||
174 | _ER(EXIT_RSM, 0x073) \ | ||
175 | _ER(EXIT_IRET, 0x074) \ | ||
176 | _ER(EXIT_SWINT, 0x075) \ | ||
177 | _ER(EXIT_INVD, 0x076) \ | ||
178 | _ER(EXIT_PAUSE, 0x077) \ | ||
179 | _ER(EXIT_HLT, 0x078) \ | ||
180 | _ER(EXIT_INVLPG, 0x079) \ | ||
181 | _ER(EXIT_INVLPGA, 0x07a) \ | ||
182 | _ER(EXIT_IOIO, 0x07b) \ | ||
183 | _ER(EXIT_MSR, 0x07c) \ | ||
184 | _ER(EXIT_TASK_SWITCH, 0x07d) \ | ||
185 | _ER(EXIT_FERR_FREEZE, 0x07e) \ | ||
186 | _ER(EXIT_SHUTDOWN, 0x07f) \ | ||
187 | _ER(EXIT_VMRUN, 0x080) \ | ||
188 | _ER(EXIT_VMMCALL, 0x081) \ | ||
189 | _ER(EXIT_VMLOAD, 0x082) \ | ||
190 | _ER(EXIT_VMSAVE, 0x083) \ | ||
191 | _ER(EXIT_STGI, 0x084) \ | ||
192 | _ER(EXIT_CLGI, 0x085) \ | ||
193 | _ER(EXIT_SKINIT, 0x086) \ | ||
194 | _ER(EXIT_RDTSCP, 0x087) \ | ||
195 | _ER(EXIT_ICEBP, 0x088) \ | ||
196 | _ER(EXIT_WBINVD, 0x089) \ | ||
197 | _ER(EXIT_MONITOR, 0x08a) \ | ||
198 | _ER(EXIT_MWAIT, 0x08b) \ | ||
199 | _ER(EXIT_MWAIT_COND, 0x08c) \ | ||
200 | _ER(EXIT_NPF, 0x400) \ | ||
201 | _ER(EXIT_ERR, -1) | ||
202 | |||
203 | #define _ER(reason, val) { #reason, val }, | ||
204 | struct str_values { | ||
205 | const char *str; | ||
206 | int val; | ||
207 | }; | ||
208 | |||
209 | static struct str_values vmx_exit_reasons[] = { | ||
210 | VMX_EXIT_REASONS | ||
211 | { NULL, -1} | ||
212 | }; | ||
213 | |||
214 | static struct str_values svm_exit_reasons[] = { | ||
215 | SVM_EXIT_REASONS | ||
216 | { NULL, -1} | ||
217 | }; | ||
218 | |||
219 | static struct isa_exit_reasons { | ||
220 | unsigned isa; | ||
221 | struct str_values *strings; | ||
222 | } isa_exit_reasons[] = { | ||
223 | { .isa = 1, .strings = vmx_exit_reasons }, | ||
224 | { .isa = 2, .strings = svm_exit_reasons }, | ||
225 | { } | ||
226 | }; | ||
227 | |||
228 | static const char *find_exit_reason(unsigned isa, int val) | ||
229 | { | ||
230 | struct str_values *strings = NULL; | ||
231 | int i; | ||
232 | |||
233 | for (i = 0; isa_exit_reasons[i].strings; ++i) | ||
234 | if (isa_exit_reasons[i].isa == isa) { | ||
235 | strings = isa_exit_reasons[i].strings; | ||
236 | break; | ||
237 | } | ||
238 | if (!strings) | ||
239 | return "UNKNOWN-ISA"; | ||
240 | for (i = 0; strings[i].val >= 0; i++) | ||
241 | if (strings[i].val == val) | ||
242 | break; | ||
243 | if (strings[i].str) | ||
244 | return strings[i].str; | ||
245 | return "UNKNOWN"; | ||
246 | } | ||
247 | |||
248 | static int kvm_exit_handler(struct trace_seq *s, struct pevent_record *record, | ||
249 | struct event_format *event, void *context) | ||
250 | { | ||
251 | unsigned long long isa; | ||
252 | unsigned long long val; | ||
253 | unsigned long long info1 = 0, info2 = 0; | ||
254 | |||
255 | if (pevent_get_field_val(s, event, "exit_reason", record, &val, 1) < 0) | ||
256 | return -1; | ||
257 | |||
258 | if (pevent_get_field_val(s, event, "isa", record, &isa, 0) < 0) | ||
259 | isa = 1; | ||
260 | |||
261 | trace_seq_printf(s, "reason %s", find_exit_reason(isa, val)); | ||
262 | |||
263 | pevent_print_num_field(s, " rip 0x%lx", event, "guest_rip", record, 1); | ||
264 | |||
265 | if (pevent_get_field_val(s, event, "info1", record, &info1, 0) >= 0 | ||
266 | && pevent_get_field_val(s, event, "info2", record, &info2, 0) >= 0) | ||
267 | trace_seq_printf(s, " info %llx %llx", info1, info2); | ||
268 | |||
269 | return 0; | ||
270 | } | ||
271 | |||
272 | #define KVM_EMUL_INSN_F_CR0_PE (1 << 0) | ||
273 | #define KVM_EMUL_INSN_F_EFL_VM (1 << 1) | ||
274 | #define KVM_EMUL_INSN_F_CS_D (1 << 2) | ||
275 | #define KVM_EMUL_INSN_F_CS_L (1 << 3) | ||
276 | |||
277 | static int kvm_emulate_insn_handler(struct trace_seq *s, | ||
278 | struct pevent_record *record, | ||
279 | struct event_format *event, void *context) | ||
280 | { | ||
281 | unsigned long long rip, csbase, len, flags, failed; | ||
282 | int llen; | ||
283 | uint8_t *insn; | ||
284 | const char *disasm; | ||
285 | |||
286 | if (pevent_get_field_val(s, event, "rip", record, &rip, 1) < 0) | ||
287 | return -1; | ||
288 | |||
289 | if (pevent_get_field_val(s, event, "csbase", record, &csbase, 1) < 0) | ||
290 | return -1; | ||
291 | |||
292 | if (pevent_get_field_val(s, event, "len", record, &len, 1) < 0) | ||
293 | return -1; | ||
294 | |||
295 | if (pevent_get_field_val(s, event, "flags", record, &flags, 1) < 0) | ||
296 | return -1; | ||
297 | |||
298 | if (pevent_get_field_val(s, event, "failed", record, &failed, 1) < 0) | ||
299 | return -1; | ||
300 | |||
301 | insn = pevent_get_field_raw(s, event, "insn", record, &llen, 1); | ||
302 | if (!insn) | ||
303 | return -1; | ||
304 | |||
305 | disasm = disassemble(insn, len, rip, | ||
306 | flags & KVM_EMUL_INSN_F_CR0_PE, | ||
307 | flags & KVM_EMUL_INSN_F_EFL_VM, | ||
308 | flags & KVM_EMUL_INSN_F_CS_D, | ||
309 | flags & KVM_EMUL_INSN_F_CS_L); | ||
310 | |||
311 | trace_seq_printf(s, "%llx:%llx: %s%s", csbase, rip, disasm, | ||
312 | failed ? " FAIL" : ""); | ||
313 | return 0; | ||
314 | } | ||
315 | |||
316 | union kvm_mmu_page_role { | ||
317 | unsigned word; | ||
318 | struct { | ||
319 | unsigned glevels:4; | ||
320 | unsigned level:4; | ||
321 | unsigned quadrant:2; | ||
322 | unsigned pad_for_nice_hex_output:6; | ||
323 | unsigned direct:1; | ||
324 | unsigned access:3; | ||
325 | unsigned invalid:1; | ||
326 | unsigned cr4_pge:1; | ||
327 | unsigned nxe:1; | ||
328 | }; | ||
329 | }; | ||
330 | |||
331 | static int kvm_mmu_print_role(struct trace_seq *s, struct pevent_record *record, | ||
332 | struct event_format *event, void *context) | ||
333 | { | ||
334 | unsigned long long val; | ||
335 | static const char *access_str[] = { | ||
336 | "---", "--x", "w--", "w-x", "-u-", "-ux", "wu-", "wux" | ||
337 | }; | ||
338 | union kvm_mmu_page_role role; | ||
339 | |||
340 | if (pevent_get_field_val(s, event, "role", record, &val, 1) < 0) | ||
341 | return -1; | ||
342 | |||
343 | role.word = (int)val; | ||
344 | |||
345 | /* | ||
346 | * We can only use the structure if file is of the same | ||
347 | * endianess. | ||
348 | */ | ||
349 | if (pevent_is_file_bigendian(event->pevent) == | ||
350 | pevent_is_host_bigendian(event->pevent)) { | ||
351 | |||
352 | trace_seq_printf(s, "%u/%u q%u%s %s%s %spge %snxe", | ||
353 | role.level, | ||
354 | role.glevels, | ||
355 | role.quadrant, | ||
356 | role.direct ? " direct" : "", | ||
357 | access_str[role.access], | ||
358 | role.invalid ? " invalid" : "", | ||
359 | role.cr4_pge ? "" : "!", | ||
360 | role.nxe ? "" : "!"); | ||
361 | } else | ||
362 | trace_seq_printf(s, "WORD: %08x", role.word); | ||
363 | |||
364 | pevent_print_num_field(s, " root %u ", event, | ||
365 | "root_count", record, 1); | ||
366 | |||
367 | if (pevent_get_field_val(s, event, "unsync", record, &val, 1) < 0) | ||
368 | return -1; | ||
369 | |||
370 | trace_seq_printf(s, "%s%c", val ? "unsync" : "sync", 0); | ||
371 | return 0; | ||
372 | } | ||
373 | |||
374 | static int kvm_mmu_get_page_handler(struct trace_seq *s, | ||
375 | struct pevent_record *record, | ||
376 | struct event_format *event, void *context) | ||
377 | { | ||
378 | unsigned long long val; | ||
379 | |||
380 | if (pevent_get_field_val(s, event, "created", record, &val, 1) < 0) | ||
381 | return -1; | ||
382 | |||
383 | trace_seq_printf(s, "%s ", val ? "new" : "existing"); | ||
384 | |||
385 | if (pevent_get_field_val(s, event, "gfn", record, &val, 1) < 0) | ||
386 | return -1; | ||
387 | |||
388 | trace_seq_printf(s, "sp gfn %llx ", val); | ||
389 | return kvm_mmu_print_role(s, record, event, context); | ||
390 | } | ||
391 | |||
392 | #define PT_WRITABLE_SHIFT 1 | ||
393 | #define PT_WRITABLE_MASK (1ULL << PT_WRITABLE_SHIFT) | ||
394 | |||
395 | static unsigned long long | ||
396 | process_is_writable_pte(struct trace_seq *s, unsigned long long *args) | ||
397 | { | ||
398 | unsigned long pte = args[0]; | ||
399 | return pte & PT_WRITABLE_MASK; | ||
400 | } | ||
401 | |||
402 | int PEVENT_PLUGIN_LOADER(struct pevent *pevent) | ||
403 | { | ||
404 | init_disassembler(); | ||
405 | |||
406 | pevent_register_event_handler(pevent, -1, "kvm", "kvm_exit", | ||
407 | kvm_exit_handler, NULL); | ||
408 | |||
409 | pevent_register_event_handler(pevent, -1, "kvm", "kvm_emulate_insn", | ||
410 | kvm_emulate_insn_handler, NULL); | ||
411 | |||
412 | pevent_register_event_handler(pevent, -1, "kvmmmu", "kvm_mmu_get_page", | ||
413 | kvm_mmu_get_page_handler, NULL); | ||
414 | |||
415 | pevent_register_event_handler(pevent, -1, "kvmmmu", "kvm_mmu_sync_page", | ||
416 | kvm_mmu_print_role, NULL); | ||
417 | |||
418 | pevent_register_event_handler(pevent, -1, | ||
419 | "kvmmmu", "kvm_mmu_unsync_page", | ||
420 | kvm_mmu_print_role, NULL); | ||
421 | |||
422 | pevent_register_event_handler(pevent, -1, "kvmmmu", "kvm_mmu_zap_page", | ||
423 | kvm_mmu_print_role, NULL); | ||
424 | |||
425 | pevent_register_event_handler(pevent, -1, "kvmmmu", | ||
426 | "kvm_mmu_prepare_zap_page", kvm_mmu_print_role, | ||
427 | NULL); | ||
428 | |||
429 | pevent_register_print_function(pevent, | ||
430 | process_is_writable_pte, | ||
431 | PEVENT_FUNC_ARG_INT, | ||
432 | "is_writable_pte", | ||
433 | PEVENT_FUNC_ARG_LONG, | ||
434 | PEVENT_FUNC_ARG_VOID); | ||
435 | return 0; | ||
436 | } | ||
437 | |||
438 | void PEVENT_PLUGIN_UNLOADER(struct pevent *pevent) | ||
439 | { | ||
440 | pevent_unregister_event_handler(pevent, -1, "kvm", "kvm_exit", | ||
441 | kvm_exit_handler, NULL); | ||
442 | |||
443 | pevent_unregister_event_handler(pevent, -1, "kvm", "kvm_emulate_insn", | ||
444 | kvm_emulate_insn_handler, NULL); | ||
445 | |||
446 | pevent_unregister_event_handler(pevent, -1, "kvmmmu", "kvm_mmu_get_page", | ||
447 | kvm_mmu_get_page_handler, NULL); | ||
448 | |||
449 | pevent_unregister_event_handler(pevent, -1, "kvmmmu", "kvm_mmu_sync_page", | ||
450 | kvm_mmu_print_role, NULL); | ||
451 | |||
452 | pevent_unregister_event_handler(pevent, -1, | ||
453 | "kvmmmu", "kvm_mmu_unsync_page", | ||
454 | kvm_mmu_print_role, NULL); | ||
455 | |||
456 | pevent_unregister_event_handler(pevent, -1, "kvmmmu", "kvm_mmu_zap_page", | ||
457 | kvm_mmu_print_role, NULL); | ||
458 | |||
459 | pevent_unregister_event_handler(pevent, -1, "kvmmmu", | ||
460 | "kvm_mmu_prepare_zap_page", kvm_mmu_print_role, | ||
461 | NULL); | ||
462 | |||
463 | pevent_unregister_print_function(pevent, process_is_writable_pte, | ||
464 | "is_writable_pte"); | ||
465 | } | ||
diff --git a/tools/lib/traceevent/plugin_mac80211.c b/tools/lib/traceevent/plugin_mac80211.c new file mode 100644 index 000000000000..7e15a0f1c2fd --- /dev/null +++ b/tools/lib/traceevent/plugin_mac80211.c | |||
@@ -0,0 +1,102 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2009 Johannes Berg <johannes@sipsolutions.net> | ||
3 | * | ||
4 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
5 | * This program is free software; you can redistribute it and/or | ||
6 | * modify it under the terms of the GNU Lesser General Public | ||
7 | * License as published by the Free Software Foundation; | ||
8 | * version 2.1 of the License (not later!) | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU Lesser General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU Lesser General Public | ||
16 | * License along with this program; if not, see <http://www.gnu.org/licenses> | ||
17 | * | ||
18 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
19 | */ | ||
20 | #include <stdio.h> | ||
21 | #include <stdlib.h> | ||
22 | #include <string.h> | ||
23 | |||
24 | #include "event-parse.h" | ||
25 | |||
26 | #define INDENT 65 | ||
27 | |||
28 | static void print_string(struct trace_seq *s, struct event_format *event, | ||
29 | const char *name, const void *data) | ||
30 | { | ||
31 | struct format_field *f = pevent_find_field(event, name); | ||
32 | int offset; | ||
33 | int length; | ||
34 | |||
35 | if (!f) { | ||
36 | trace_seq_printf(s, "NOTFOUND:%s", name); | ||
37 | return; | ||
38 | } | ||
39 | |||
40 | offset = f->offset; | ||
41 | length = f->size; | ||
42 | |||
43 | if (!strncmp(f->type, "__data_loc", 10)) { | ||
44 | unsigned long long v; | ||
45 | if (pevent_read_number_field(f, data, &v)) { | ||
46 | trace_seq_printf(s, "invalid_data_loc"); | ||
47 | return; | ||
48 | } | ||
49 | offset = v & 0xffff; | ||
50 | length = v >> 16; | ||
51 | } | ||
52 | |||
53 | trace_seq_printf(s, "%.*s", length, (char *)data + offset); | ||
54 | } | ||
55 | |||
56 | #define SF(fn) pevent_print_num_field(s, fn ":%d", event, fn, record, 0) | ||
57 | #define SFX(fn) pevent_print_num_field(s, fn ":%#x", event, fn, record, 0) | ||
58 | #define SP() trace_seq_putc(s, ' ') | ||
59 | |||
60 | static int drv_bss_info_changed(struct trace_seq *s, | ||
61 | struct pevent_record *record, | ||
62 | struct event_format *event, void *context) | ||
63 | { | ||
64 | void *data = record->data; | ||
65 | |||
66 | print_string(s, event, "wiphy_name", data); | ||
67 | trace_seq_printf(s, " vif:"); | ||
68 | print_string(s, event, "vif_name", data); | ||
69 | pevent_print_num_field(s, "(%d)", event, "vif_type", record, 1); | ||
70 | |||
71 | trace_seq_printf(s, "\n%*s", INDENT, ""); | ||
72 | SF("assoc"); SP(); | ||
73 | SF("aid"); SP(); | ||
74 | SF("cts"); SP(); | ||
75 | SF("shortpre"); SP(); | ||
76 | SF("shortslot"); SP(); | ||
77 | SF("dtimper"); SP(); | ||
78 | trace_seq_printf(s, "\n%*s", INDENT, ""); | ||
79 | SF("bcnint"); SP(); | ||
80 | SFX("assoc_cap"); SP(); | ||
81 | SFX("basic_rates"); SP(); | ||
82 | SF("enable_beacon"); | ||
83 | trace_seq_printf(s, "\n%*s", INDENT, ""); | ||
84 | SF("ht_operation_mode"); | ||
85 | |||
86 | return 0; | ||
87 | } | ||
88 | |||
89 | int PEVENT_PLUGIN_LOADER(struct pevent *pevent) | ||
90 | { | ||
91 | pevent_register_event_handler(pevent, -1, "mac80211", | ||
92 | "drv_bss_info_changed", | ||
93 | drv_bss_info_changed, NULL); | ||
94 | return 0; | ||
95 | } | ||
96 | |||
97 | void PEVENT_PLUGIN_UNLOADER(struct pevent *pevent) | ||
98 | { | ||
99 | pevent_unregister_event_handler(pevent, -1, "mac80211", | ||
100 | "drv_bss_info_changed", | ||
101 | drv_bss_info_changed, NULL); | ||
102 | } | ||
diff --git a/tools/lib/traceevent/plugin_sched_switch.c b/tools/lib/traceevent/plugin_sched_switch.c new file mode 100644 index 000000000000..f1ce60065258 --- /dev/null +++ b/tools/lib/traceevent/plugin_sched_switch.c | |||
@@ -0,0 +1,160 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2009, 2010 Red Hat Inc, Steven Rostedt <srostedt@redhat.com> | ||
3 | * | ||
4 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
5 | * This program is free software; you can redistribute it and/or | ||
6 | * modify it under the terms of the GNU Lesser General Public | ||
7 | * License as published by the Free Software Foundation; | ||
8 | * version 2.1 of the License (not later!) | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU Lesser General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU Lesser General Public | ||
16 | * License along with this program; if not, see <http://www.gnu.org/licenses> | ||
17 | * | ||
18 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
19 | */ | ||
20 | #include <stdio.h> | ||
21 | #include <stdlib.h> | ||
22 | #include <string.h> | ||
23 | |||
24 | #include "event-parse.h" | ||
25 | |||
26 | static void write_state(struct trace_seq *s, int val) | ||
27 | { | ||
28 | const char states[] = "SDTtZXxW"; | ||
29 | int found = 0; | ||
30 | int i; | ||
31 | |||
32 | for (i = 0; i < (sizeof(states) - 1); i++) { | ||
33 | if (!(val & (1 << i))) | ||
34 | continue; | ||
35 | |||
36 | if (found) | ||
37 | trace_seq_putc(s, '|'); | ||
38 | |||
39 | found = 1; | ||
40 | trace_seq_putc(s, states[i]); | ||
41 | } | ||
42 | |||
43 | if (!found) | ||
44 | trace_seq_putc(s, 'R'); | ||
45 | } | ||
46 | |||
47 | static void write_and_save_comm(struct format_field *field, | ||
48 | struct pevent_record *record, | ||
49 | struct trace_seq *s, int pid) | ||
50 | { | ||
51 | const char *comm; | ||
52 | int len; | ||
53 | |||
54 | comm = (char *)(record->data + field->offset); | ||
55 | len = s->len; | ||
56 | trace_seq_printf(s, "%.*s", | ||
57 | field->size, comm); | ||
58 | |||
59 | /* make sure the comm has a \0 at the end. */ | ||
60 | trace_seq_terminate(s); | ||
61 | comm = &s->buffer[len]; | ||
62 | |||
63 | /* Help out the comm to ids. This will handle dups */ | ||
64 | pevent_register_comm(field->event->pevent, comm, pid); | ||
65 | } | ||
66 | |||
67 | static int sched_wakeup_handler(struct trace_seq *s, | ||
68 | struct pevent_record *record, | ||
69 | struct event_format *event, void *context) | ||
70 | { | ||
71 | struct format_field *field; | ||
72 | unsigned long long val; | ||
73 | |||
74 | if (pevent_get_field_val(s, event, "pid", record, &val, 1)) | ||
75 | return trace_seq_putc(s, '!'); | ||
76 | |||
77 | field = pevent_find_any_field(event, "comm"); | ||
78 | if (field) { | ||
79 | write_and_save_comm(field, record, s, val); | ||
80 | trace_seq_putc(s, ':'); | ||
81 | } | ||
82 | trace_seq_printf(s, "%lld", val); | ||
83 | |||
84 | if (pevent_get_field_val(s, event, "prio", record, &val, 0) == 0) | ||
85 | trace_seq_printf(s, " [%lld]", val); | ||
86 | |||
87 | if (pevent_get_field_val(s, event, "success", record, &val, 1) == 0) | ||
88 | trace_seq_printf(s, " success=%lld", val); | ||
89 | |||
90 | if (pevent_get_field_val(s, event, "target_cpu", record, &val, 0) == 0) | ||
91 | trace_seq_printf(s, " CPU:%03llu", val); | ||
92 | |||
93 | return 0; | ||
94 | } | ||
95 | |||
96 | static int sched_switch_handler(struct trace_seq *s, | ||
97 | struct pevent_record *record, | ||
98 | struct event_format *event, void *context) | ||
99 | { | ||
100 | struct format_field *field; | ||
101 | unsigned long long val; | ||
102 | |||
103 | if (pevent_get_field_val(s, event, "prev_pid", record, &val, 1)) | ||
104 | return trace_seq_putc(s, '!'); | ||
105 | |||
106 | field = pevent_find_any_field(event, "prev_comm"); | ||
107 | if (field) { | ||
108 | write_and_save_comm(field, record, s, val); | ||
109 | trace_seq_putc(s, ':'); | ||
110 | } | ||
111 | trace_seq_printf(s, "%lld ", val); | ||
112 | |||
113 | if (pevent_get_field_val(s, event, "prev_prio", record, &val, 0) == 0) | ||
114 | trace_seq_printf(s, "[%lld] ", val); | ||
115 | |||
116 | if (pevent_get_field_val(s, event, "prev_state", record, &val, 0) == 0) | ||
117 | write_state(s, val); | ||
118 | |||
119 | trace_seq_puts(s, " ==> "); | ||
120 | |||
121 | if (pevent_get_field_val(s, event, "next_pid", record, &val, 1)) | ||
122 | return trace_seq_putc(s, '!'); | ||
123 | |||
124 | field = pevent_find_any_field(event, "next_comm"); | ||
125 | if (field) { | ||
126 | write_and_save_comm(field, record, s, val); | ||
127 | trace_seq_putc(s, ':'); | ||
128 | } | ||
129 | trace_seq_printf(s, "%lld", val); | ||
130 | |||
131 | if (pevent_get_field_val(s, event, "next_prio", record, &val, 0) == 0) | ||
132 | trace_seq_printf(s, " [%lld]", val); | ||
133 | |||
134 | return 0; | ||
135 | } | ||
136 | |||
137 | int PEVENT_PLUGIN_LOADER(struct pevent *pevent) | ||
138 | { | ||
139 | pevent_register_event_handler(pevent, -1, "sched", "sched_switch", | ||
140 | sched_switch_handler, NULL); | ||
141 | |||
142 | pevent_register_event_handler(pevent, -1, "sched", "sched_wakeup", | ||
143 | sched_wakeup_handler, NULL); | ||
144 | |||
145 | pevent_register_event_handler(pevent, -1, "sched", "sched_wakeup_new", | ||
146 | sched_wakeup_handler, NULL); | ||
147 | return 0; | ||
148 | } | ||
149 | |||
150 | void PEVENT_PLUGIN_UNLOADER(struct pevent *pevent) | ||
151 | { | ||
152 | pevent_unregister_event_handler(pevent, -1, "sched", "sched_switch", | ||
153 | sched_switch_handler, NULL); | ||
154 | |||
155 | pevent_unregister_event_handler(pevent, -1, "sched", "sched_wakeup", | ||
156 | sched_wakeup_handler, NULL); | ||
157 | |||
158 | pevent_unregister_event_handler(pevent, -1, "sched", "sched_wakeup_new", | ||
159 | sched_wakeup_handler, NULL); | ||
160 | } | ||
diff --git a/tools/lib/traceevent/plugin_scsi.c b/tools/lib/traceevent/plugin_scsi.c new file mode 100644 index 000000000000..eda326fc8620 --- /dev/null +++ b/tools/lib/traceevent/plugin_scsi.c | |||
@@ -0,0 +1,429 @@ | |||
1 | #include <stdio.h> | ||
2 | #include <string.h> | ||
3 | #include <inttypes.h> | ||
4 | #include "event-parse.h" | ||
5 | |||
6 | typedef unsigned long sector_t; | ||
7 | typedef uint64_t u64; | ||
8 | typedef unsigned int u32; | ||
9 | |||
10 | /* | ||
11 | * SCSI opcodes | ||
12 | */ | ||
13 | #define TEST_UNIT_READY 0x00 | ||
14 | #define REZERO_UNIT 0x01 | ||
15 | #define REQUEST_SENSE 0x03 | ||
16 | #define FORMAT_UNIT 0x04 | ||
17 | #define READ_BLOCK_LIMITS 0x05 | ||
18 | #define REASSIGN_BLOCKS 0x07 | ||
19 | #define INITIALIZE_ELEMENT_STATUS 0x07 | ||
20 | #define READ_6 0x08 | ||
21 | #define WRITE_6 0x0a | ||
22 | #define SEEK_6 0x0b | ||
23 | #define READ_REVERSE 0x0f | ||
24 | #define WRITE_FILEMARKS 0x10 | ||
25 | #define SPACE 0x11 | ||
26 | #define INQUIRY 0x12 | ||
27 | #define RECOVER_BUFFERED_DATA 0x14 | ||
28 | #define MODE_SELECT 0x15 | ||
29 | #define RESERVE 0x16 | ||
30 | #define RELEASE 0x17 | ||
31 | #define COPY 0x18 | ||
32 | #define ERASE 0x19 | ||
33 | #define MODE_SENSE 0x1a | ||
34 | #define START_STOP 0x1b | ||
35 | #define RECEIVE_DIAGNOSTIC 0x1c | ||
36 | #define SEND_DIAGNOSTIC 0x1d | ||
37 | #define ALLOW_MEDIUM_REMOVAL 0x1e | ||
38 | |||
39 | #define READ_FORMAT_CAPACITIES 0x23 | ||
40 | #define SET_WINDOW 0x24 | ||
41 | #define READ_CAPACITY 0x25 | ||
42 | #define READ_10 0x28 | ||
43 | #define WRITE_10 0x2a | ||
44 | #define SEEK_10 0x2b | ||
45 | #define POSITION_TO_ELEMENT 0x2b | ||
46 | #define WRITE_VERIFY 0x2e | ||
47 | #define VERIFY 0x2f | ||
48 | #define SEARCH_HIGH 0x30 | ||
49 | #define SEARCH_EQUAL 0x31 | ||
50 | #define SEARCH_LOW 0x32 | ||
51 | #define SET_LIMITS 0x33 | ||
52 | #define PRE_FETCH 0x34 | ||
53 | #define READ_POSITION 0x34 | ||
54 | #define SYNCHRONIZE_CACHE 0x35 | ||
55 | #define LOCK_UNLOCK_CACHE 0x36 | ||
56 | #define READ_DEFECT_DATA 0x37 | ||
57 | #define MEDIUM_SCAN 0x38 | ||
58 | #define COMPARE 0x39 | ||
59 | #define COPY_VERIFY 0x3a | ||
60 | #define WRITE_BUFFER 0x3b | ||
61 | #define READ_BUFFER 0x3c | ||
62 | #define UPDATE_BLOCK 0x3d | ||
63 | #define READ_LONG 0x3e | ||
64 | #define WRITE_LONG 0x3f | ||
65 | #define CHANGE_DEFINITION 0x40 | ||
66 | #define WRITE_SAME 0x41 | ||
67 | #define UNMAP 0x42 | ||
68 | #define READ_TOC 0x43 | ||
69 | #define READ_HEADER 0x44 | ||
70 | #define GET_EVENT_STATUS_NOTIFICATION 0x4a | ||
71 | #define LOG_SELECT 0x4c | ||
72 | #define LOG_SENSE 0x4d | ||
73 | #define XDWRITEREAD_10 0x53 | ||
74 | #define MODE_SELECT_10 0x55 | ||
75 | #define RESERVE_10 0x56 | ||
76 | #define RELEASE_10 0x57 | ||
77 | #define MODE_SENSE_10 0x5a | ||
78 | #define PERSISTENT_RESERVE_IN 0x5e | ||
79 | #define PERSISTENT_RESERVE_OUT 0x5f | ||
80 | #define VARIABLE_LENGTH_CMD 0x7f | ||
81 | #define REPORT_LUNS 0xa0 | ||
82 | #define SECURITY_PROTOCOL_IN 0xa2 | ||
83 | #define MAINTENANCE_IN 0xa3 | ||
84 | #define MAINTENANCE_OUT 0xa4 | ||
85 | #define MOVE_MEDIUM 0xa5 | ||
86 | #define EXCHANGE_MEDIUM 0xa6 | ||
87 | #define READ_12 0xa8 | ||
88 | #define WRITE_12 0xaa | ||
89 | #define READ_MEDIA_SERIAL_NUMBER 0xab | ||
90 | #define WRITE_VERIFY_12 0xae | ||
91 | #define VERIFY_12 0xaf | ||
92 | #define SEARCH_HIGH_12 0xb0 | ||
93 | #define SEARCH_EQUAL_12 0xb1 | ||
94 | #define SEARCH_LOW_12 0xb2 | ||
95 | #define SECURITY_PROTOCOL_OUT 0xb5 | ||
96 | #define READ_ELEMENT_STATUS 0xb8 | ||
97 | #define SEND_VOLUME_TAG 0xb6 | ||
98 | #define WRITE_LONG_2 0xea | ||
99 | #define EXTENDED_COPY 0x83 | ||
100 | #define RECEIVE_COPY_RESULTS 0x84 | ||
101 | #define ACCESS_CONTROL_IN 0x86 | ||
102 | #define ACCESS_CONTROL_OUT 0x87 | ||
103 | #define READ_16 0x88 | ||
104 | #define WRITE_16 0x8a | ||
105 | #define READ_ATTRIBUTE 0x8c | ||
106 | #define WRITE_ATTRIBUTE 0x8d | ||
107 | #define VERIFY_16 0x8f | ||
108 | #define SYNCHRONIZE_CACHE_16 0x91 | ||
109 | #define WRITE_SAME_16 0x93 | ||
110 | #define SERVICE_ACTION_IN 0x9e | ||
111 | /* values for service action in */ | ||
112 | #define SAI_READ_CAPACITY_16 0x10 | ||
113 | #define SAI_GET_LBA_STATUS 0x12 | ||
114 | /* values for VARIABLE_LENGTH_CMD service action codes | ||
115 | * see spc4r17 Section D.3.5, table D.7 and D.8 */ | ||
116 | #define VLC_SA_RECEIVE_CREDENTIAL 0x1800 | ||
117 | /* values for maintenance in */ | ||
118 | #define MI_REPORT_IDENTIFYING_INFORMATION 0x05 | ||
119 | #define MI_REPORT_TARGET_PGS 0x0a | ||
120 | #define MI_REPORT_ALIASES 0x0b | ||
121 | #define MI_REPORT_SUPPORTED_OPERATION_CODES 0x0c | ||
122 | #define MI_REPORT_SUPPORTED_TASK_MANAGEMENT_FUNCTIONS 0x0d | ||
123 | #define MI_REPORT_PRIORITY 0x0e | ||
124 | #define MI_REPORT_TIMESTAMP 0x0f | ||
125 | #define MI_MANAGEMENT_PROTOCOL_IN 0x10 | ||
126 | /* value for MI_REPORT_TARGET_PGS ext header */ | ||
127 | #define MI_EXT_HDR_PARAM_FMT 0x20 | ||
128 | /* values for maintenance out */ | ||
129 | #define MO_SET_IDENTIFYING_INFORMATION 0x06 | ||
130 | #define MO_SET_TARGET_PGS 0x0a | ||
131 | #define MO_CHANGE_ALIASES 0x0b | ||
132 | #define MO_SET_PRIORITY 0x0e | ||
133 | #define MO_SET_TIMESTAMP 0x0f | ||
134 | #define MO_MANAGEMENT_PROTOCOL_OUT 0x10 | ||
135 | /* values for variable length command */ | ||
136 | #define XDREAD_32 0x03 | ||
137 | #define XDWRITE_32 0x04 | ||
138 | #define XPWRITE_32 0x06 | ||
139 | #define XDWRITEREAD_32 0x07 | ||
140 | #define READ_32 0x09 | ||
141 | #define VERIFY_32 0x0a | ||
142 | #define WRITE_32 0x0b | ||
143 | #define WRITE_SAME_32 0x0d | ||
144 | |||
145 | #define SERVICE_ACTION16(cdb) (cdb[1] & 0x1f) | ||
146 | #define SERVICE_ACTION32(cdb) ((cdb[8] << 8) | cdb[9]) | ||
147 | |||
148 | static const char * | ||
149 | scsi_trace_misc(struct trace_seq *, unsigned char *, int); | ||
150 | |||
151 | static const char * | ||
152 | scsi_trace_rw6(struct trace_seq *p, unsigned char *cdb, int len) | ||
153 | { | ||
154 | const char *ret = p->buffer + p->len; | ||
155 | sector_t lba = 0, txlen = 0; | ||
156 | |||
157 | lba |= ((cdb[1] & 0x1F) << 16); | ||
158 | lba |= (cdb[2] << 8); | ||
159 | lba |= cdb[3]; | ||
160 | txlen = cdb[4]; | ||
161 | |||
162 | trace_seq_printf(p, "lba=%llu txlen=%llu", | ||
163 | (unsigned long long)lba, (unsigned long long)txlen); | ||
164 | trace_seq_putc(p, 0); | ||
165 | return ret; | ||
166 | } | ||
167 | |||
168 | static const char * | ||
169 | scsi_trace_rw10(struct trace_seq *p, unsigned char *cdb, int len) | ||
170 | { | ||
171 | const char *ret = p->buffer + p->len; | ||
172 | sector_t lba = 0, txlen = 0; | ||
173 | |||
174 | lba |= (cdb[2] << 24); | ||
175 | lba |= (cdb[3] << 16); | ||
176 | lba |= (cdb[4] << 8); | ||
177 | lba |= cdb[5]; | ||
178 | txlen |= (cdb[7] << 8); | ||
179 | txlen |= cdb[8]; | ||
180 | |||
181 | trace_seq_printf(p, "lba=%llu txlen=%llu protect=%u", | ||
182 | (unsigned long long)lba, (unsigned long long)txlen, | ||
183 | cdb[1] >> 5); | ||
184 | |||
185 | if (cdb[0] == WRITE_SAME) | ||
186 | trace_seq_printf(p, " unmap=%u", cdb[1] >> 3 & 1); | ||
187 | |||
188 | trace_seq_putc(p, 0); | ||
189 | return ret; | ||
190 | } | ||
191 | |||
192 | static const char * | ||
193 | scsi_trace_rw12(struct trace_seq *p, unsigned char *cdb, int len) | ||
194 | { | ||
195 | const char *ret = p->buffer + p->len; | ||
196 | sector_t lba = 0, txlen = 0; | ||
197 | |||
198 | lba |= (cdb[2] << 24); | ||
199 | lba |= (cdb[3] << 16); | ||
200 | lba |= (cdb[4] << 8); | ||
201 | lba |= cdb[5]; | ||
202 | txlen |= (cdb[6] << 24); | ||
203 | txlen |= (cdb[7] << 16); | ||
204 | txlen |= (cdb[8] << 8); | ||
205 | txlen |= cdb[9]; | ||
206 | |||
207 | trace_seq_printf(p, "lba=%llu txlen=%llu protect=%u", | ||
208 | (unsigned long long)lba, (unsigned long long)txlen, | ||
209 | cdb[1] >> 5); | ||
210 | trace_seq_putc(p, 0); | ||
211 | return ret; | ||
212 | } | ||
213 | |||
214 | static const char * | ||
215 | scsi_trace_rw16(struct trace_seq *p, unsigned char *cdb, int len) | ||
216 | { | ||
217 | const char *ret = p->buffer + p->len; | ||
218 | sector_t lba = 0, txlen = 0; | ||
219 | |||
220 | lba |= ((u64)cdb[2] << 56); | ||
221 | lba |= ((u64)cdb[3] << 48); | ||
222 | lba |= ((u64)cdb[4] << 40); | ||
223 | lba |= ((u64)cdb[5] << 32); | ||
224 | lba |= (cdb[6] << 24); | ||
225 | lba |= (cdb[7] << 16); | ||
226 | lba |= (cdb[8] << 8); | ||
227 | lba |= cdb[9]; | ||
228 | txlen |= (cdb[10] << 24); | ||
229 | txlen |= (cdb[11] << 16); | ||
230 | txlen |= (cdb[12] << 8); | ||
231 | txlen |= cdb[13]; | ||
232 | |||
233 | trace_seq_printf(p, "lba=%llu txlen=%llu protect=%u", | ||
234 | (unsigned long long)lba, (unsigned long long)txlen, | ||
235 | cdb[1] >> 5); | ||
236 | |||
237 | if (cdb[0] == WRITE_SAME_16) | ||
238 | trace_seq_printf(p, " unmap=%u", cdb[1] >> 3 & 1); | ||
239 | |||
240 | trace_seq_putc(p, 0); | ||
241 | return ret; | ||
242 | } | ||
243 | |||
244 | static const char * | ||
245 | scsi_trace_rw32(struct trace_seq *p, unsigned char *cdb, int len) | ||
246 | { | ||
247 | const char *ret = p->buffer + p->len, *cmd; | ||
248 | sector_t lba = 0, txlen = 0; | ||
249 | u32 ei_lbrt = 0; | ||
250 | |||
251 | switch (SERVICE_ACTION32(cdb)) { | ||
252 | case READ_32: | ||
253 | cmd = "READ"; | ||
254 | break; | ||
255 | case VERIFY_32: | ||
256 | cmd = "VERIFY"; | ||
257 | break; | ||
258 | case WRITE_32: | ||
259 | cmd = "WRITE"; | ||
260 | break; | ||
261 | case WRITE_SAME_32: | ||
262 | cmd = "WRITE_SAME"; | ||
263 | break; | ||
264 | default: | ||
265 | trace_seq_printf(p, "UNKNOWN"); | ||
266 | goto out; | ||
267 | } | ||
268 | |||
269 | lba |= ((u64)cdb[12] << 56); | ||
270 | lba |= ((u64)cdb[13] << 48); | ||
271 | lba |= ((u64)cdb[14] << 40); | ||
272 | lba |= ((u64)cdb[15] << 32); | ||
273 | lba |= (cdb[16] << 24); | ||
274 | lba |= (cdb[17] << 16); | ||
275 | lba |= (cdb[18] << 8); | ||
276 | lba |= cdb[19]; | ||
277 | ei_lbrt |= (cdb[20] << 24); | ||
278 | ei_lbrt |= (cdb[21] << 16); | ||
279 | ei_lbrt |= (cdb[22] << 8); | ||
280 | ei_lbrt |= cdb[23]; | ||
281 | txlen |= (cdb[28] << 24); | ||
282 | txlen |= (cdb[29] << 16); | ||
283 | txlen |= (cdb[30] << 8); | ||
284 | txlen |= cdb[31]; | ||
285 | |||
286 | trace_seq_printf(p, "%s_32 lba=%llu txlen=%llu protect=%u ei_lbrt=%u", | ||
287 | cmd, (unsigned long long)lba, | ||
288 | (unsigned long long)txlen, cdb[10] >> 5, ei_lbrt); | ||
289 | |||
290 | if (SERVICE_ACTION32(cdb) == WRITE_SAME_32) | ||
291 | trace_seq_printf(p, " unmap=%u", cdb[10] >> 3 & 1); | ||
292 | |||
293 | out: | ||
294 | trace_seq_putc(p, 0); | ||
295 | return ret; | ||
296 | } | ||
297 | |||
298 | static const char * | ||
299 | scsi_trace_unmap(struct trace_seq *p, unsigned char *cdb, int len) | ||
300 | { | ||
301 | const char *ret = p->buffer + p->len; | ||
302 | unsigned int regions = cdb[7] << 8 | cdb[8]; | ||
303 | |||
304 | trace_seq_printf(p, "regions=%u", (regions - 8) / 16); | ||
305 | trace_seq_putc(p, 0); | ||
306 | return ret; | ||
307 | } | ||
308 | |||
309 | static const char * | ||
310 | scsi_trace_service_action_in(struct trace_seq *p, unsigned char *cdb, int len) | ||
311 | { | ||
312 | const char *ret = p->buffer + p->len, *cmd; | ||
313 | sector_t lba = 0; | ||
314 | u32 alloc_len = 0; | ||
315 | |||
316 | switch (SERVICE_ACTION16(cdb)) { | ||
317 | case SAI_READ_CAPACITY_16: | ||
318 | cmd = "READ_CAPACITY_16"; | ||
319 | break; | ||
320 | case SAI_GET_LBA_STATUS: | ||
321 | cmd = "GET_LBA_STATUS"; | ||
322 | break; | ||
323 | default: | ||
324 | trace_seq_printf(p, "UNKNOWN"); | ||
325 | goto out; | ||
326 | } | ||
327 | |||
328 | lba |= ((u64)cdb[2] << 56); | ||
329 | lba |= ((u64)cdb[3] << 48); | ||
330 | lba |= ((u64)cdb[4] << 40); | ||
331 | lba |= ((u64)cdb[5] << 32); | ||
332 | lba |= (cdb[6] << 24); | ||
333 | lba |= (cdb[7] << 16); | ||
334 | lba |= (cdb[8] << 8); | ||
335 | lba |= cdb[9]; | ||
336 | alloc_len |= (cdb[10] << 24); | ||
337 | alloc_len |= (cdb[11] << 16); | ||
338 | alloc_len |= (cdb[12] << 8); | ||
339 | alloc_len |= cdb[13]; | ||
340 | |||
341 | trace_seq_printf(p, "%s lba=%llu alloc_len=%u", cmd, | ||
342 | (unsigned long long)lba, alloc_len); | ||
343 | |||
344 | out: | ||
345 | trace_seq_putc(p, 0); | ||
346 | return ret; | ||
347 | } | ||
348 | |||
349 | static const char * | ||
350 | scsi_trace_varlen(struct trace_seq *p, unsigned char *cdb, int len) | ||
351 | { | ||
352 | switch (SERVICE_ACTION32(cdb)) { | ||
353 | case READ_32: | ||
354 | case VERIFY_32: | ||
355 | case WRITE_32: | ||
356 | case WRITE_SAME_32: | ||
357 | return scsi_trace_rw32(p, cdb, len); | ||
358 | default: | ||
359 | return scsi_trace_misc(p, cdb, len); | ||
360 | } | ||
361 | } | ||
362 | |||
363 | static const char * | ||
364 | scsi_trace_misc(struct trace_seq *p, unsigned char *cdb, int len) | ||
365 | { | ||
366 | const char *ret = p->buffer + p->len; | ||
367 | |||
368 | trace_seq_printf(p, "-"); | ||
369 | trace_seq_putc(p, 0); | ||
370 | return ret; | ||
371 | } | ||
372 | |||
373 | const char * | ||
374 | scsi_trace_parse_cdb(struct trace_seq *p, unsigned char *cdb, int len) | ||
375 | { | ||
376 | switch (cdb[0]) { | ||
377 | case READ_6: | ||
378 | case WRITE_6: | ||
379 | return scsi_trace_rw6(p, cdb, len); | ||
380 | case READ_10: | ||
381 | case VERIFY: | ||
382 | case WRITE_10: | ||
383 | case WRITE_SAME: | ||
384 | return scsi_trace_rw10(p, cdb, len); | ||
385 | case READ_12: | ||
386 | case VERIFY_12: | ||
387 | case WRITE_12: | ||
388 | return scsi_trace_rw12(p, cdb, len); | ||
389 | case READ_16: | ||
390 | case VERIFY_16: | ||
391 | case WRITE_16: | ||
392 | case WRITE_SAME_16: | ||
393 | return scsi_trace_rw16(p, cdb, len); | ||
394 | case UNMAP: | ||
395 | return scsi_trace_unmap(p, cdb, len); | ||
396 | case SERVICE_ACTION_IN: | ||
397 | return scsi_trace_service_action_in(p, cdb, len); | ||
398 | case VARIABLE_LENGTH_CMD: | ||
399 | return scsi_trace_varlen(p, cdb, len); | ||
400 | default: | ||
401 | return scsi_trace_misc(p, cdb, len); | ||
402 | } | ||
403 | } | ||
404 | |||
405 | unsigned long long process_scsi_trace_parse_cdb(struct trace_seq *s, | ||
406 | unsigned long long *args) | ||
407 | { | ||
408 | scsi_trace_parse_cdb(s, (unsigned char *) (unsigned long) args[1], args[2]); | ||
409 | return 0; | ||
410 | } | ||
411 | |||
412 | int PEVENT_PLUGIN_LOADER(struct pevent *pevent) | ||
413 | { | ||
414 | pevent_register_print_function(pevent, | ||
415 | process_scsi_trace_parse_cdb, | ||
416 | PEVENT_FUNC_ARG_STRING, | ||
417 | "scsi_trace_parse_cdb", | ||
418 | PEVENT_FUNC_ARG_PTR, | ||
419 | PEVENT_FUNC_ARG_PTR, | ||
420 | PEVENT_FUNC_ARG_INT, | ||
421 | PEVENT_FUNC_ARG_VOID); | ||
422 | return 0; | ||
423 | } | ||
424 | |||
425 | void PEVENT_PLUGIN_UNLOADER(struct pevent *pevent) | ||
426 | { | ||
427 | pevent_unregister_print_function(pevent, process_scsi_trace_parse_cdb, | ||
428 | "scsi_trace_parse_cdb"); | ||
429 | } | ||
diff --git a/tools/lib/traceevent/plugin_xen.c b/tools/lib/traceevent/plugin_xen.c new file mode 100644 index 000000000000..3a413eaada68 --- /dev/null +++ b/tools/lib/traceevent/plugin_xen.c | |||
@@ -0,0 +1,136 @@ | |||
1 | #include <stdio.h> | ||
2 | #include <stdlib.h> | ||
3 | #include <string.h> | ||
4 | #include "event-parse.h" | ||
5 | |||
6 | #define __HYPERVISOR_set_trap_table 0 | ||
7 | #define __HYPERVISOR_mmu_update 1 | ||
8 | #define __HYPERVISOR_set_gdt 2 | ||
9 | #define __HYPERVISOR_stack_switch 3 | ||
10 | #define __HYPERVISOR_set_callbacks 4 | ||
11 | #define __HYPERVISOR_fpu_taskswitch 5 | ||
12 | #define __HYPERVISOR_sched_op_compat 6 | ||
13 | #define __HYPERVISOR_dom0_op 7 | ||
14 | #define __HYPERVISOR_set_debugreg 8 | ||
15 | #define __HYPERVISOR_get_debugreg 9 | ||
16 | #define __HYPERVISOR_update_descriptor 10 | ||
17 | #define __HYPERVISOR_memory_op 12 | ||
18 | #define __HYPERVISOR_multicall 13 | ||
19 | #define __HYPERVISOR_update_va_mapping 14 | ||
20 | #define __HYPERVISOR_set_timer_op 15 | ||
21 | #define __HYPERVISOR_event_channel_op_compat 16 | ||
22 | #define __HYPERVISOR_xen_version 17 | ||
23 | #define __HYPERVISOR_console_io 18 | ||
24 | #define __HYPERVISOR_physdev_op_compat 19 | ||
25 | #define __HYPERVISOR_grant_table_op 20 | ||
26 | #define __HYPERVISOR_vm_assist 21 | ||
27 | #define __HYPERVISOR_update_va_mapping_otherdomain 22 | ||
28 | #define __HYPERVISOR_iret 23 /* x86 only */ | ||
29 | #define __HYPERVISOR_vcpu_op 24 | ||
30 | #define __HYPERVISOR_set_segment_base 25 /* x86/64 only */ | ||
31 | #define __HYPERVISOR_mmuext_op 26 | ||
32 | #define __HYPERVISOR_acm_op 27 | ||
33 | #define __HYPERVISOR_nmi_op 28 | ||
34 | #define __HYPERVISOR_sched_op 29 | ||
35 | #define __HYPERVISOR_callback_op 30 | ||
36 | #define __HYPERVISOR_xenoprof_op 31 | ||
37 | #define __HYPERVISOR_event_channel_op 32 | ||
38 | #define __HYPERVISOR_physdev_op 33 | ||
39 | #define __HYPERVISOR_hvm_op 34 | ||
40 | #define __HYPERVISOR_tmem_op 38 | ||
41 | |||
42 | /* Architecture-specific hypercall definitions. */ | ||
43 | #define __HYPERVISOR_arch_0 48 | ||
44 | #define __HYPERVISOR_arch_1 49 | ||
45 | #define __HYPERVISOR_arch_2 50 | ||
46 | #define __HYPERVISOR_arch_3 51 | ||
47 | #define __HYPERVISOR_arch_4 52 | ||
48 | #define __HYPERVISOR_arch_5 53 | ||
49 | #define __HYPERVISOR_arch_6 54 | ||
50 | #define __HYPERVISOR_arch_7 55 | ||
51 | |||
52 | #define N(x) [__HYPERVISOR_##x] = "("#x")" | ||
53 | static const char *xen_hypercall_names[] = { | ||
54 | N(set_trap_table), | ||
55 | N(mmu_update), | ||
56 | N(set_gdt), | ||
57 | N(stack_switch), | ||
58 | N(set_callbacks), | ||
59 | N(fpu_taskswitch), | ||
60 | N(sched_op_compat), | ||
61 | N(dom0_op), | ||
62 | N(set_debugreg), | ||
63 | N(get_debugreg), | ||
64 | N(update_descriptor), | ||
65 | N(memory_op), | ||
66 | N(multicall), | ||
67 | N(update_va_mapping), | ||
68 | N(set_timer_op), | ||
69 | N(event_channel_op_compat), | ||
70 | N(xen_version), | ||
71 | N(console_io), | ||
72 | N(physdev_op_compat), | ||
73 | N(grant_table_op), | ||
74 | N(vm_assist), | ||
75 | N(update_va_mapping_otherdomain), | ||
76 | N(iret), | ||
77 | N(vcpu_op), | ||
78 | N(set_segment_base), | ||
79 | N(mmuext_op), | ||
80 | N(acm_op), | ||
81 | N(nmi_op), | ||
82 | N(sched_op), | ||
83 | N(callback_op), | ||
84 | N(xenoprof_op), | ||
85 | N(event_channel_op), | ||
86 | N(physdev_op), | ||
87 | N(hvm_op), | ||
88 | |||
89 | /* Architecture-specific hypercall definitions. */ | ||
90 | N(arch_0), | ||
91 | N(arch_1), | ||
92 | N(arch_2), | ||
93 | N(arch_3), | ||
94 | N(arch_4), | ||
95 | N(arch_5), | ||
96 | N(arch_6), | ||
97 | N(arch_7), | ||
98 | }; | ||
99 | #undef N | ||
100 | |||
101 | #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) | ||
102 | |||
103 | static const char *xen_hypercall_name(unsigned op) | ||
104 | { | ||
105 | if (op < ARRAY_SIZE(xen_hypercall_names) && | ||
106 | xen_hypercall_names[op] != NULL) | ||
107 | return xen_hypercall_names[op]; | ||
108 | |||
109 | return ""; | ||
110 | } | ||
111 | |||
112 | unsigned long long process_xen_hypercall_name(struct trace_seq *s, | ||
113 | unsigned long long *args) | ||
114 | { | ||
115 | unsigned int op = args[0]; | ||
116 | |||
117 | trace_seq_printf(s, "%s", xen_hypercall_name(op)); | ||
118 | return 0; | ||
119 | } | ||
120 | |||
121 | int PEVENT_PLUGIN_LOADER(struct pevent *pevent) | ||
122 | { | ||
123 | pevent_register_print_function(pevent, | ||
124 | process_xen_hypercall_name, | ||
125 | PEVENT_FUNC_ARG_STRING, | ||
126 | "xen_hypercall_name", | ||
127 | PEVENT_FUNC_ARG_INT, | ||
128 | PEVENT_FUNC_ARG_VOID); | ||
129 | return 0; | ||
130 | } | ||
131 | |||
132 | void PEVENT_PLUGIN_UNLOADER(struct pevent *pevent) | ||
133 | { | ||
134 | pevent_unregister_print_function(pevent, process_xen_hypercall_name, | ||
135 | "xen_hypercall_name"); | ||
136 | } | ||
diff --git a/tools/lib/traceevent/trace-seq.c b/tools/lib/traceevent/trace-seq.c index d7f2e68bc5b9..ec3bd16a5488 100644 --- a/tools/lib/traceevent/trace-seq.c +++ b/tools/lib/traceevent/trace-seq.c | |||
@@ -22,6 +22,7 @@ | |||
22 | #include <string.h> | 22 | #include <string.h> |
23 | #include <stdarg.h> | 23 | #include <stdarg.h> |
24 | 24 | ||
25 | #include <asm/bug.h> | ||
25 | #include "event-parse.h" | 26 | #include "event-parse.h" |
26 | #include "event-utils.h" | 27 | #include "event-utils.h" |
27 | 28 | ||
@@ -32,10 +33,21 @@ | |||
32 | #define TRACE_SEQ_POISON ((void *)0xdeadbeef) | 33 | #define TRACE_SEQ_POISON ((void *)0xdeadbeef) |
33 | #define TRACE_SEQ_CHECK(s) \ | 34 | #define TRACE_SEQ_CHECK(s) \ |
34 | do { \ | 35 | do { \ |
35 | if ((s)->buffer == TRACE_SEQ_POISON) \ | 36 | if (WARN_ONCE((s)->buffer == TRACE_SEQ_POISON, \ |
36 | die("Usage of trace_seq after it was destroyed"); \ | 37 | "Usage of trace_seq after it was destroyed")) \ |
38 | (s)->state = TRACE_SEQ__BUFFER_POISONED; \ | ||
37 | } while (0) | 39 | } while (0) |
38 | 40 | ||
41 | #define TRACE_SEQ_CHECK_RET_N(s, n) \ | ||
42 | do { \ | ||
43 | TRACE_SEQ_CHECK(s); \ | ||
44 | if ((s)->state != TRACE_SEQ__GOOD) \ | ||
45 | return n; \ | ||
46 | } while (0) | ||
47 | |||
48 | #define TRACE_SEQ_CHECK_RET(s) TRACE_SEQ_CHECK_RET_N(s, ) | ||
49 | #define TRACE_SEQ_CHECK_RET0(s) TRACE_SEQ_CHECK_RET_N(s, 0) | ||
50 | |||
39 | /** | 51 | /** |
40 | * trace_seq_init - initialize the trace_seq structure | 52 | * trace_seq_init - initialize the trace_seq structure |
41 | * @s: a pointer to the trace_seq structure to initialize | 53 | * @s: a pointer to the trace_seq structure to initialize |
@@ -45,7 +57,11 @@ void trace_seq_init(struct trace_seq *s) | |||
45 | s->len = 0; | 57 | s->len = 0; |
46 | s->readpos = 0; | 58 | s->readpos = 0; |
47 | s->buffer_size = TRACE_SEQ_BUF_SIZE; | 59 | s->buffer_size = TRACE_SEQ_BUF_SIZE; |
48 | s->buffer = malloc_or_die(s->buffer_size); | 60 | s->buffer = malloc(s->buffer_size); |
61 | if (s->buffer != NULL) | ||
62 | s->state = TRACE_SEQ__GOOD; | ||
63 | else | ||
64 | s->state = TRACE_SEQ__MEM_ALLOC_FAILED; | ||
49 | } | 65 | } |
50 | 66 | ||
51 | /** | 67 | /** |
@@ -71,17 +87,23 @@ void trace_seq_destroy(struct trace_seq *s) | |||
71 | { | 87 | { |
72 | if (!s) | 88 | if (!s) |
73 | return; | 89 | return; |
74 | TRACE_SEQ_CHECK(s); | 90 | TRACE_SEQ_CHECK_RET(s); |
75 | free(s->buffer); | 91 | free(s->buffer); |
76 | s->buffer = TRACE_SEQ_POISON; | 92 | s->buffer = TRACE_SEQ_POISON; |
77 | } | 93 | } |
78 | 94 | ||
79 | static void expand_buffer(struct trace_seq *s) | 95 | static void expand_buffer(struct trace_seq *s) |
80 | { | 96 | { |
97 | char *buf; | ||
98 | |||
99 | buf = realloc(s->buffer, s->buffer_size + TRACE_SEQ_BUF_SIZE); | ||
100 | if (WARN_ONCE(!buf, "Can't allocate trace_seq buffer memory")) { | ||
101 | s->state = TRACE_SEQ__MEM_ALLOC_FAILED; | ||
102 | return; | ||
103 | } | ||
104 | |||
105 | s->buffer = buf; | ||
81 | s->buffer_size += TRACE_SEQ_BUF_SIZE; | 106 | s->buffer_size += TRACE_SEQ_BUF_SIZE; |
82 | s->buffer = realloc(s->buffer, s->buffer_size); | ||
83 | if (!s->buffer) | ||
84 | die("Can't allocate trace_seq buffer memory"); | ||
85 | } | 107 | } |
86 | 108 | ||
87 | /** | 109 | /** |
@@ -105,9 +127,9 @@ trace_seq_printf(struct trace_seq *s, const char *fmt, ...) | |||
105 | int len; | 127 | int len; |
106 | int ret; | 128 | int ret; |
107 | 129 | ||
108 | TRACE_SEQ_CHECK(s); | ||
109 | |||
110 | try_again: | 130 | try_again: |
131 | TRACE_SEQ_CHECK_RET0(s); | ||
132 | |||
111 | len = (s->buffer_size - 1) - s->len; | 133 | len = (s->buffer_size - 1) - s->len; |
112 | 134 | ||
113 | va_start(ap, fmt); | 135 | va_start(ap, fmt); |
@@ -141,9 +163,9 @@ trace_seq_vprintf(struct trace_seq *s, const char *fmt, va_list args) | |||
141 | int len; | 163 | int len; |
142 | int ret; | 164 | int ret; |
143 | 165 | ||
144 | TRACE_SEQ_CHECK(s); | ||
145 | |||
146 | try_again: | 166 | try_again: |
167 | TRACE_SEQ_CHECK_RET0(s); | ||
168 | |||
147 | len = (s->buffer_size - 1) - s->len; | 169 | len = (s->buffer_size - 1) - s->len; |
148 | 170 | ||
149 | ret = vsnprintf(s->buffer + s->len, len, fmt, args); | 171 | ret = vsnprintf(s->buffer + s->len, len, fmt, args); |
@@ -172,13 +194,15 @@ int trace_seq_puts(struct trace_seq *s, const char *str) | |||
172 | { | 194 | { |
173 | int len; | 195 | int len; |
174 | 196 | ||
175 | TRACE_SEQ_CHECK(s); | 197 | TRACE_SEQ_CHECK_RET0(s); |
176 | 198 | ||
177 | len = strlen(str); | 199 | len = strlen(str); |
178 | 200 | ||
179 | while (len > ((s->buffer_size - 1) - s->len)) | 201 | while (len > ((s->buffer_size - 1) - s->len)) |
180 | expand_buffer(s); | 202 | expand_buffer(s); |
181 | 203 | ||
204 | TRACE_SEQ_CHECK_RET0(s); | ||
205 | |||
182 | memcpy(s->buffer + s->len, str, len); | 206 | memcpy(s->buffer + s->len, str, len); |
183 | s->len += len; | 207 | s->len += len; |
184 | 208 | ||
@@ -187,11 +211,13 @@ int trace_seq_puts(struct trace_seq *s, const char *str) | |||
187 | 211 | ||
188 | int trace_seq_putc(struct trace_seq *s, unsigned char c) | 212 | int trace_seq_putc(struct trace_seq *s, unsigned char c) |
189 | { | 213 | { |
190 | TRACE_SEQ_CHECK(s); | 214 | TRACE_SEQ_CHECK_RET0(s); |
191 | 215 | ||
192 | while (s->len >= (s->buffer_size - 1)) | 216 | while (s->len >= (s->buffer_size - 1)) |
193 | expand_buffer(s); | 217 | expand_buffer(s); |
194 | 218 | ||
219 | TRACE_SEQ_CHECK_RET0(s); | ||
220 | |||
195 | s->buffer[s->len++] = c; | 221 | s->buffer[s->len++] = c; |
196 | 222 | ||
197 | return 1; | 223 | return 1; |
@@ -199,7 +225,7 @@ int trace_seq_putc(struct trace_seq *s, unsigned char c) | |||
199 | 225 | ||
200 | void trace_seq_terminate(struct trace_seq *s) | 226 | void trace_seq_terminate(struct trace_seq *s) |
201 | { | 227 | { |
202 | TRACE_SEQ_CHECK(s); | 228 | TRACE_SEQ_CHECK_RET(s); |
203 | 229 | ||
204 | /* There's always one character left on the buffer */ | 230 | /* There's always one character left on the buffer */ |
205 | s->buffer[s->len] = 0; | 231 | s->buffer[s->len] = 0; |
@@ -208,5 +234,16 @@ void trace_seq_terminate(struct trace_seq *s) | |||
208 | int trace_seq_do_printf(struct trace_seq *s) | 234 | int trace_seq_do_printf(struct trace_seq *s) |
209 | { | 235 | { |
210 | TRACE_SEQ_CHECK(s); | 236 | TRACE_SEQ_CHECK(s); |
211 | return printf("%.*s", s->len, s->buffer); | 237 | |
238 | switch (s->state) { | ||
239 | case TRACE_SEQ__GOOD: | ||
240 | return printf("%.*s", s->len, s->buffer); | ||
241 | case TRACE_SEQ__BUFFER_POISONED: | ||
242 | puts("Usage of trace_seq after it was destroyed"); | ||
243 | break; | ||
244 | case TRACE_SEQ__MEM_ALLOC_FAILED: | ||
245 | puts("Can't allocate trace_seq buffer memory"); | ||
246 | break; | ||
247 | } | ||
248 | return -1; | ||
212 | } | 249 | } |
diff --git a/tools/net/Makefile b/tools/net/Makefile index b4444d53b73f..ee577ea03ba5 100644 --- a/tools/net/Makefile +++ b/tools/net/Makefile | |||
@@ -1,15 +1,34 @@ | |||
1 | prefix = /usr | 1 | prefix = /usr |
2 | 2 | ||
3 | CC = gcc | 3 | CC = gcc |
4 | LEX = flex | ||
5 | YACC = bison | ||
4 | 6 | ||
5 | all : bpf_jit_disasm | 7 | %.yacc.c: %.y |
8 | $(YACC) -o $@ -d $< | ||
6 | 9 | ||
7 | bpf_jit_disasm : CFLAGS = -Wall -O2 | 10 | %.lex.c: %.l |
11 | $(LEX) -o $@ $< | ||
12 | |||
13 | all : bpf_jit_disasm bpf_dbg bpf_asm | ||
14 | |||
15 | bpf_jit_disasm : CFLAGS = -Wall -O2 -DPACKAGE='bpf_jit_disasm' | ||
8 | bpf_jit_disasm : LDLIBS = -lopcodes -lbfd -ldl | 16 | bpf_jit_disasm : LDLIBS = -lopcodes -lbfd -ldl |
9 | bpf_jit_disasm : bpf_jit_disasm.o | 17 | bpf_jit_disasm : bpf_jit_disasm.o |
10 | 18 | ||
19 | bpf_dbg : CFLAGS = -Wall -O2 | ||
20 | bpf_dbg : LDLIBS = -lreadline | ||
21 | bpf_dbg : bpf_dbg.o | ||
22 | |||
23 | bpf_asm : CFLAGS = -Wall -O2 -I. | ||
24 | bpf_asm : LDLIBS = | ||
25 | bpf_asm : bpf_asm.o bpf_exp.yacc.o bpf_exp.lex.o | ||
26 | bpf_exp.lex.o : bpf_exp.yacc.c | ||
27 | |||
11 | clean : | 28 | clean : |
12 | rm -rf *.o bpf_jit_disasm | 29 | rm -rf *.o bpf_jit_disasm bpf_dbg bpf_asm bpf_exp.yacc.* bpf_exp.lex.* |
13 | 30 | ||
14 | install : | 31 | install : |
15 | install bpf_jit_disasm $(prefix)/bin/bpf_jit_disasm | 32 | install bpf_jit_disasm $(prefix)/bin/bpf_jit_disasm |
33 | install bpf_dbg $(prefix)/bin/bpf_dbg | ||
34 | install bpf_asm $(prefix)/bin/bpf_asm | ||
diff --git a/tools/net/bpf_asm.c b/tools/net/bpf_asm.c new file mode 100644 index 000000000000..c15aef097b04 --- /dev/null +++ b/tools/net/bpf_asm.c | |||
@@ -0,0 +1,52 @@ | |||
1 | /* | ||
2 | * Minimal BPF assembler | ||
3 | * | ||
4 | * Instead of libpcap high-level filter expressions, it can be quite | ||
5 | * useful to define filters in low-level BPF assembler (that is kept | ||
6 | * close to Steven McCanne and Van Jacobson's original BPF paper). | ||
7 | * In particular for BPF JIT implementors, JIT security auditors, or | ||
8 | * just for defining BPF expressions that contain extensions which are | ||
9 | * not supported by compilers. | ||
10 | * | ||
11 | * How to get into it: | ||
12 | * | ||
13 | * 1) read Documentation/networking/filter.txt | ||
14 | * 2) Run `bpf_asm [-c] <filter-prog file>` to translate into binary | ||
15 | * blob that is loadable with xt_bpf, cls_bpf et al. Note: -c will | ||
16 | * pretty print a C-like construct. | ||
17 | * | ||
18 | * Copyright 2013 Daniel Borkmann <borkmann@redhat.com> | ||
19 | * Licensed under the GNU General Public License, version 2.0 (GPLv2) | ||
20 | */ | ||
21 | |||
22 | #include <stdbool.h> | ||
23 | #include <stdio.h> | ||
24 | #include <string.h> | ||
25 | |||
26 | extern void bpf_asm_compile(FILE *fp, bool cstyle); | ||
27 | |||
28 | int main(int argc, char **argv) | ||
29 | { | ||
30 | FILE *fp = stdin; | ||
31 | bool cstyle = false; | ||
32 | int i; | ||
33 | |||
34 | for (i = 1; i < argc; i++) { | ||
35 | if (!strncmp("-c", argv[i], 2)) { | ||
36 | cstyle = true; | ||
37 | continue; | ||
38 | } | ||
39 | |||
40 | fp = fopen(argv[i], "r"); | ||
41 | if (!fp) { | ||
42 | fp = stdin; | ||
43 | continue; | ||
44 | } | ||
45 | |||
46 | break; | ||
47 | } | ||
48 | |||
49 | bpf_asm_compile(fp, cstyle); | ||
50 | |||
51 | return 0; | ||
52 | } | ||
diff --git a/tools/net/bpf_dbg.c b/tools/net/bpf_dbg.c new file mode 100644 index 000000000000..65dc757f7f7b --- /dev/null +++ b/tools/net/bpf_dbg.c | |||
@@ -0,0 +1,1404 @@ | |||
1 | /* | ||
2 | * Minimal BPF debugger | ||
3 | * | ||
4 | * Minimal BPF debugger that mimics the kernel's engine (w/o extensions) | ||
5 | * and allows for single stepping through selected packets from a pcap | ||
6 | * with a provided user filter in order to facilitate verification of a | ||
7 | * BPF program. Besides others, this is useful to verify BPF programs | ||
8 | * before attaching to a live system, and can be used in socket filters, | ||
9 | * cls_bpf, xt_bpf, team driver and e.g. PTP code; in particular when a | ||
10 | * single more complex BPF program is being used. Reasons for a more | ||
11 | * complex BPF program are likely primarily to optimize execution time | ||
12 | * for making a verdict when multiple simple BPF programs are combined | ||
13 | * into one in order to prevent parsing same headers multiple times. | ||
14 | * | ||
15 | * More on how to debug BPF opcodes see Documentation/networking/filter.txt | ||
16 | * which is the main document on BPF. Mini howto for getting started: | ||
17 | * | ||
18 | * 1) `./bpf_dbg` to enter the shell (shell cmds denoted with '>'): | ||
19 | * 2) > load bpf 6,40 0 0 12,21 0 3 20... (output from `bpf_asm` or | ||
20 | * `tcpdump -iem1 -ddd port 22 | tr '\n' ','` to load as filter) | ||
21 | * 3) > load pcap foo.pcap | ||
22 | * 4) > run <n>/disassemble/dump/quit (self-explanatory) | ||
23 | * 5) > breakpoint 2 (sets bp at loaded BPF insns 2, do `run` then; | ||
24 | * multiple bps can be set, of course, a call to `breakpoint` | ||
25 | * w/o args shows currently loaded bps, `breakpoint reset` for | ||
26 | * resetting all breakpoints) | ||
27 | * 6) > select 3 (`run` etc will start from the 3rd packet in the pcap) | ||
28 | * 7) > step [-<n>, +<n>] (performs single stepping through the BPF) | ||
29 | * | ||
30 | * Copyright 2013 Daniel Borkmann <borkmann@redhat.com> | ||
31 | * Licensed under the GNU General Public License, version 2.0 (GPLv2) | ||
32 | */ | ||
33 | |||
34 | #include <stdio.h> | ||
35 | #include <unistd.h> | ||
36 | #include <stdlib.h> | ||
37 | #include <ctype.h> | ||
38 | #include <stdbool.h> | ||
39 | #include <stdarg.h> | ||
40 | #include <setjmp.h> | ||
41 | #include <linux/filter.h> | ||
42 | #include <linux/if_packet.h> | ||
43 | #include <readline/readline.h> | ||
44 | #include <readline/history.h> | ||
45 | #include <sys/types.h> | ||
46 | #include <sys/socket.h> | ||
47 | #include <sys/stat.h> | ||
48 | #include <sys/mman.h> | ||
49 | #include <fcntl.h> | ||
50 | #include <errno.h> | ||
51 | #include <signal.h> | ||
52 | #include <arpa/inet.h> | ||
53 | #include <net/ethernet.h> | ||
54 | |||
55 | #define TCPDUMP_MAGIC 0xa1b2c3d4 | ||
56 | |||
57 | #define BPF_LDX_B (BPF_LDX | BPF_B) | ||
58 | #define BPF_LDX_W (BPF_LDX | BPF_W) | ||
59 | #define BPF_JMP_JA (BPF_JMP | BPF_JA) | ||
60 | #define BPF_JMP_JEQ (BPF_JMP | BPF_JEQ) | ||
61 | #define BPF_JMP_JGT (BPF_JMP | BPF_JGT) | ||
62 | #define BPF_JMP_JGE (BPF_JMP | BPF_JGE) | ||
63 | #define BPF_JMP_JSET (BPF_JMP | BPF_JSET) | ||
64 | #define BPF_ALU_ADD (BPF_ALU | BPF_ADD) | ||
65 | #define BPF_ALU_SUB (BPF_ALU | BPF_SUB) | ||
66 | #define BPF_ALU_MUL (BPF_ALU | BPF_MUL) | ||
67 | #define BPF_ALU_DIV (BPF_ALU | BPF_DIV) | ||
68 | #define BPF_ALU_MOD (BPF_ALU | BPF_MOD) | ||
69 | #define BPF_ALU_NEG (BPF_ALU | BPF_NEG) | ||
70 | #define BPF_ALU_AND (BPF_ALU | BPF_AND) | ||
71 | #define BPF_ALU_OR (BPF_ALU | BPF_OR) | ||
72 | #define BPF_ALU_XOR (BPF_ALU | BPF_XOR) | ||
73 | #define BPF_ALU_LSH (BPF_ALU | BPF_LSH) | ||
74 | #define BPF_ALU_RSH (BPF_ALU | BPF_RSH) | ||
75 | #define BPF_MISC_TAX (BPF_MISC | BPF_TAX) | ||
76 | #define BPF_MISC_TXA (BPF_MISC | BPF_TXA) | ||
77 | #define BPF_LD_B (BPF_LD | BPF_B) | ||
78 | #define BPF_LD_H (BPF_LD | BPF_H) | ||
79 | #define BPF_LD_W (BPF_LD | BPF_W) | ||
80 | |||
81 | #ifndef array_size | ||
82 | # define array_size(x) (sizeof(x) / sizeof((x)[0])) | ||
83 | #endif | ||
84 | |||
85 | #ifndef __check_format_printf | ||
86 | # define __check_format_printf(pos_fmtstr, pos_fmtargs) \ | ||
87 | __attribute__ ((format (printf, (pos_fmtstr), (pos_fmtargs)))) | ||
88 | #endif | ||
89 | |||
90 | #define CMD(_name, _func) { .name = _name, .func = _func, } | ||
91 | #define OP(_op, _name) [_op] = _name | ||
92 | |||
93 | enum { | ||
94 | CMD_OK, | ||
95 | CMD_ERR, | ||
96 | CMD_EX, | ||
97 | }; | ||
98 | |||
99 | struct shell_cmd { | ||
100 | const char *name; | ||
101 | int (*func)(char *args); | ||
102 | }; | ||
103 | |||
104 | struct pcap_filehdr { | ||
105 | uint32_t magic; | ||
106 | uint16_t version_major; | ||
107 | uint16_t version_minor; | ||
108 | int32_t thiszone; | ||
109 | uint32_t sigfigs; | ||
110 | uint32_t snaplen; | ||
111 | uint32_t linktype; | ||
112 | }; | ||
113 | |||
114 | struct pcap_timeval { | ||
115 | int32_t tv_sec; | ||
116 | int32_t tv_usec; | ||
117 | }; | ||
118 | |||
119 | struct pcap_pkthdr { | ||
120 | struct pcap_timeval ts; | ||
121 | uint32_t caplen; | ||
122 | uint32_t len; | ||
123 | }; | ||
124 | |||
125 | struct bpf_regs { | ||
126 | uint32_t A; | ||
127 | uint32_t X; | ||
128 | uint32_t M[BPF_MEMWORDS]; | ||
129 | uint32_t R; | ||
130 | bool Rs; | ||
131 | uint16_t Pc; | ||
132 | }; | ||
133 | |||
134 | static struct sock_filter bpf_image[BPF_MAXINSNS + 1]; | ||
135 | static unsigned int bpf_prog_len = 0; | ||
136 | |||
137 | static int bpf_breakpoints[64]; | ||
138 | static struct bpf_regs bpf_regs[BPF_MAXINSNS + 1]; | ||
139 | static struct bpf_regs bpf_curr; | ||
140 | static unsigned int bpf_regs_len = 0; | ||
141 | |||
142 | static int pcap_fd = -1; | ||
143 | static unsigned int pcap_packet = 0; | ||
144 | static size_t pcap_map_size = 0; | ||
145 | static char *pcap_ptr_va_start, *pcap_ptr_va_curr; | ||
146 | |||
147 | static const char * const op_table[] = { | ||
148 | OP(BPF_ST, "st"), | ||
149 | OP(BPF_STX, "stx"), | ||
150 | OP(BPF_LD_B, "ldb"), | ||
151 | OP(BPF_LD_H, "ldh"), | ||
152 | OP(BPF_LD_W, "ld"), | ||
153 | OP(BPF_LDX, "ldx"), | ||
154 | OP(BPF_LDX_B, "ldxb"), | ||
155 | OP(BPF_JMP_JA, "ja"), | ||
156 | OP(BPF_JMP_JEQ, "jeq"), | ||
157 | OP(BPF_JMP_JGT, "jgt"), | ||
158 | OP(BPF_JMP_JGE, "jge"), | ||
159 | OP(BPF_JMP_JSET, "jset"), | ||
160 | OP(BPF_ALU_ADD, "add"), | ||
161 | OP(BPF_ALU_SUB, "sub"), | ||
162 | OP(BPF_ALU_MUL, "mul"), | ||
163 | OP(BPF_ALU_DIV, "div"), | ||
164 | OP(BPF_ALU_MOD, "mod"), | ||
165 | OP(BPF_ALU_NEG, "neg"), | ||
166 | OP(BPF_ALU_AND, "and"), | ||
167 | OP(BPF_ALU_OR, "or"), | ||
168 | OP(BPF_ALU_XOR, "xor"), | ||
169 | OP(BPF_ALU_LSH, "lsh"), | ||
170 | OP(BPF_ALU_RSH, "rsh"), | ||
171 | OP(BPF_MISC_TAX, "tax"), | ||
172 | OP(BPF_MISC_TXA, "txa"), | ||
173 | OP(BPF_RET, "ret"), | ||
174 | }; | ||
175 | |||
176 | static __check_format_printf(1, 2) int rl_printf(const char *fmt, ...) | ||
177 | { | ||
178 | int ret; | ||
179 | va_list vl; | ||
180 | |||
181 | va_start(vl, fmt); | ||
182 | ret = vfprintf(rl_outstream, fmt, vl); | ||
183 | va_end(vl); | ||
184 | |||
185 | return ret; | ||
186 | } | ||
187 | |||
188 | static int matches(const char *cmd, const char *pattern) | ||
189 | { | ||
190 | int len = strlen(cmd); | ||
191 | |||
192 | if (len > strlen(pattern)) | ||
193 | return -1; | ||
194 | |||
195 | return memcmp(pattern, cmd, len); | ||
196 | } | ||
197 | |||
198 | static void hex_dump(const uint8_t *buf, size_t len) | ||
199 | { | ||
200 | int i; | ||
201 | |||
202 | rl_printf("%3u: ", 0); | ||
203 | for (i = 0; i < len; i++) { | ||
204 | if (i && !(i % 16)) | ||
205 | rl_printf("\n%3u: ", i); | ||
206 | rl_printf("%02x ", buf[i]); | ||
207 | } | ||
208 | rl_printf("\n"); | ||
209 | } | ||
210 | |||
211 | static bool bpf_prog_loaded(void) | ||
212 | { | ||
213 | if (bpf_prog_len == 0) | ||
214 | rl_printf("no bpf program loaded!\n"); | ||
215 | |||
216 | return bpf_prog_len > 0; | ||
217 | } | ||
218 | |||
219 | static void bpf_disasm(const struct sock_filter f, unsigned int i) | ||
220 | { | ||
221 | const char *op, *fmt; | ||
222 | int val = f.k; | ||
223 | char buf[256]; | ||
224 | |||
225 | switch (f.code) { | ||
226 | case BPF_RET | BPF_K: | ||
227 | op = op_table[BPF_RET]; | ||
228 | fmt = "#%#x"; | ||
229 | break; | ||
230 | case BPF_RET | BPF_A: | ||
231 | op = op_table[BPF_RET]; | ||
232 | fmt = "a"; | ||
233 | break; | ||
234 | case BPF_RET | BPF_X: | ||
235 | op = op_table[BPF_RET]; | ||
236 | fmt = "x"; | ||
237 | break; | ||
238 | case BPF_MISC_TAX: | ||
239 | op = op_table[BPF_MISC_TAX]; | ||
240 | fmt = ""; | ||
241 | break; | ||
242 | case BPF_MISC_TXA: | ||
243 | op = op_table[BPF_MISC_TXA]; | ||
244 | fmt = ""; | ||
245 | break; | ||
246 | case BPF_ST: | ||
247 | op = op_table[BPF_ST]; | ||
248 | fmt = "M[%d]"; | ||
249 | break; | ||
250 | case BPF_STX: | ||
251 | op = op_table[BPF_STX]; | ||
252 | fmt = "M[%d]"; | ||
253 | break; | ||
254 | case BPF_LD_W | BPF_ABS: | ||
255 | op = op_table[BPF_LD_W]; | ||
256 | fmt = "[%d]"; | ||
257 | break; | ||
258 | case BPF_LD_H | BPF_ABS: | ||
259 | op = op_table[BPF_LD_H]; | ||
260 | fmt = "[%d]"; | ||
261 | break; | ||
262 | case BPF_LD_B | BPF_ABS: | ||
263 | op = op_table[BPF_LD_B]; | ||
264 | fmt = "[%d]"; | ||
265 | break; | ||
266 | case BPF_LD_W | BPF_LEN: | ||
267 | op = op_table[BPF_LD_W]; | ||
268 | fmt = "#len"; | ||
269 | break; | ||
270 | case BPF_LD_W | BPF_IND: | ||
271 | op = op_table[BPF_LD_W]; | ||
272 | fmt = "[x+%d]"; | ||
273 | break; | ||
274 | case BPF_LD_H | BPF_IND: | ||
275 | op = op_table[BPF_LD_H]; | ||
276 | fmt = "[x+%d]"; | ||
277 | break; | ||
278 | case BPF_LD_B | BPF_IND: | ||
279 | op = op_table[BPF_LD_B]; | ||
280 | fmt = "[x+%d]"; | ||
281 | break; | ||
282 | case BPF_LD | BPF_IMM: | ||
283 | op = op_table[BPF_LD_W]; | ||
284 | fmt = "#%#x"; | ||
285 | break; | ||
286 | case BPF_LDX | BPF_IMM: | ||
287 | op = op_table[BPF_LDX]; | ||
288 | fmt = "#%#x"; | ||
289 | break; | ||
290 | case BPF_LDX_B | BPF_MSH: | ||
291 | op = op_table[BPF_LDX_B]; | ||
292 | fmt = "4*([%d]&0xf)"; | ||
293 | break; | ||
294 | case BPF_LD | BPF_MEM: | ||
295 | op = op_table[BPF_LD_W]; | ||
296 | fmt = "M[%d]"; | ||
297 | break; | ||
298 | case BPF_LDX | BPF_MEM: | ||
299 | op = op_table[BPF_LDX]; | ||
300 | fmt = "M[%d]"; | ||
301 | break; | ||
302 | case BPF_JMP_JA: | ||
303 | op = op_table[BPF_JMP_JA]; | ||
304 | fmt = "%d"; | ||
305 | val = i + 1 + f.k; | ||
306 | break; | ||
307 | case BPF_JMP_JGT | BPF_X: | ||
308 | op = op_table[BPF_JMP_JGT]; | ||
309 | fmt = "x"; | ||
310 | break; | ||
311 | case BPF_JMP_JGT | BPF_K: | ||
312 | op = op_table[BPF_JMP_JGT]; | ||
313 | fmt = "#%#x"; | ||
314 | break; | ||
315 | case BPF_JMP_JGE | BPF_X: | ||
316 | op = op_table[BPF_JMP_JGE]; | ||
317 | fmt = "x"; | ||
318 | break; | ||
319 | case BPF_JMP_JGE | BPF_K: | ||
320 | op = op_table[BPF_JMP_JGE]; | ||
321 | fmt = "#%#x"; | ||
322 | break; | ||
323 | case BPF_JMP_JEQ | BPF_X: | ||
324 | op = op_table[BPF_JMP_JEQ]; | ||
325 | fmt = "x"; | ||
326 | break; | ||
327 | case BPF_JMP_JEQ | BPF_K: | ||
328 | op = op_table[BPF_JMP_JEQ]; | ||
329 | fmt = "#%#x"; | ||
330 | break; | ||
331 | case BPF_JMP_JSET | BPF_X: | ||
332 | op = op_table[BPF_JMP_JSET]; | ||
333 | fmt = "x"; | ||
334 | break; | ||
335 | case BPF_JMP_JSET | BPF_K: | ||
336 | op = op_table[BPF_JMP_JSET]; | ||
337 | fmt = "#%#x"; | ||
338 | break; | ||
339 | case BPF_ALU_NEG: | ||
340 | op = op_table[BPF_ALU_NEG]; | ||
341 | fmt = ""; | ||
342 | break; | ||
343 | case BPF_ALU_LSH | BPF_X: | ||
344 | op = op_table[BPF_ALU_LSH]; | ||
345 | fmt = "x"; | ||
346 | break; | ||
347 | case BPF_ALU_LSH | BPF_K: | ||
348 | op = op_table[BPF_ALU_LSH]; | ||
349 | fmt = "#%d"; | ||
350 | break; | ||
351 | case BPF_ALU_RSH | BPF_X: | ||
352 | op = op_table[BPF_ALU_RSH]; | ||
353 | fmt = "x"; | ||
354 | break; | ||
355 | case BPF_ALU_RSH | BPF_K: | ||
356 | op = op_table[BPF_ALU_RSH]; | ||
357 | fmt = "#%d"; | ||
358 | break; | ||
359 | case BPF_ALU_ADD | BPF_X: | ||
360 | op = op_table[BPF_ALU_ADD]; | ||
361 | fmt = "x"; | ||
362 | break; | ||
363 | case BPF_ALU_ADD | BPF_K: | ||
364 | op = op_table[BPF_ALU_ADD]; | ||
365 | fmt = "#%d"; | ||
366 | break; | ||
367 | case BPF_ALU_SUB | BPF_X: | ||
368 | op = op_table[BPF_ALU_SUB]; | ||
369 | fmt = "x"; | ||
370 | break; | ||
371 | case BPF_ALU_SUB | BPF_K: | ||
372 | op = op_table[BPF_ALU_SUB]; | ||
373 | fmt = "#%d"; | ||
374 | break; | ||
375 | case BPF_ALU_MUL | BPF_X: | ||
376 | op = op_table[BPF_ALU_MUL]; | ||
377 | fmt = "x"; | ||
378 | break; | ||
379 | case BPF_ALU_MUL | BPF_K: | ||
380 | op = op_table[BPF_ALU_MUL]; | ||
381 | fmt = "#%d"; | ||
382 | break; | ||
383 | case BPF_ALU_DIV | BPF_X: | ||
384 | op = op_table[BPF_ALU_DIV]; | ||
385 | fmt = "x"; | ||
386 | break; | ||
387 | case BPF_ALU_DIV | BPF_K: | ||
388 | op = op_table[BPF_ALU_DIV]; | ||
389 | fmt = "#%d"; | ||
390 | break; | ||
391 | case BPF_ALU_MOD | BPF_X: | ||
392 | op = op_table[BPF_ALU_MOD]; | ||
393 | fmt = "x"; | ||
394 | break; | ||
395 | case BPF_ALU_MOD | BPF_K: | ||
396 | op = op_table[BPF_ALU_MOD]; | ||
397 | fmt = "#%d"; | ||
398 | break; | ||
399 | case BPF_ALU_AND | BPF_X: | ||
400 | op = op_table[BPF_ALU_AND]; | ||
401 | fmt = "x"; | ||
402 | break; | ||
403 | case BPF_ALU_AND | BPF_K: | ||
404 | op = op_table[BPF_ALU_AND]; | ||
405 | fmt = "#%#x"; | ||
406 | break; | ||
407 | case BPF_ALU_OR | BPF_X: | ||
408 | op = op_table[BPF_ALU_OR]; | ||
409 | fmt = "x"; | ||
410 | break; | ||
411 | case BPF_ALU_OR | BPF_K: | ||
412 | op = op_table[BPF_ALU_OR]; | ||
413 | fmt = "#%#x"; | ||
414 | break; | ||
415 | case BPF_ALU_XOR | BPF_X: | ||
416 | op = op_table[BPF_ALU_XOR]; | ||
417 | fmt = "x"; | ||
418 | break; | ||
419 | case BPF_ALU_XOR | BPF_K: | ||
420 | op = op_table[BPF_ALU_XOR]; | ||
421 | fmt = "#%#x"; | ||
422 | break; | ||
423 | default: | ||
424 | op = "nosup"; | ||
425 | fmt = "%#x"; | ||
426 | val = f.code; | ||
427 | break; | ||
428 | } | ||
429 | |||
430 | memset(buf, 0, sizeof(buf)); | ||
431 | snprintf(buf, sizeof(buf), fmt, val); | ||
432 | buf[sizeof(buf) - 1] = 0; | ||
433 | |||
434 | if ((BPF_CLASS(f.code) == BPF_JMP && BPF_OP(f.code) != BPF_JA)) | ||
435 | rl_printf("l%d:\t%s %s, l%d, l%d\n", i, op, buf, | ||
436 | i + 1 + f.jt, i + 1 + f.jf); | ||
437 | else | ||
438 | rl_printf("l%d:\t%s %s\n", i, op, buf); | ||
439 | } | ||
440 | |||
441 | static void bpf_dump_curr(struct bpf_regs *r, struct sock_filter *f) | ||
442 | { | ||
443 | int i, m = 0; | ||
444 | |||
445 | rl_printf("pc: [%u]\n", r->Pc); | ||
446 | rl_printf("code: [%u] jt[%u] jf[%u] k[%u]\n", | ||
447 | f->code, f->jt, f->jf, f->k); | ||
448 | rl_printf("curr: "); | ||
449 | bpf_disasm(*f, r->Pc); | ||
450 | |||
451 | if (f->jt || f->jf) { | ||
452 | rl_printf("jt: "); | ||
453 | bpf_disasm(*(f + f->jt + 1), r->Pc + f->jt + 1); | ||
454 | rl_printf("jf: "); | ||
455 | bpf_disasm(*(f + f->jf + 1), r->Pc + f->jf + 1); | ||
456 | } | ||
457 | |||
458 | rl_printf("A: [%#08x][%u]\n", r->A, r->A); | ||
459 | rl_printf("X: [%#08x][%u]\n", r->X, r->X); | ||
460 | if (r->Rs) | ||
461 | rl_printf("ret: [%#08x][%u]!\n", r->R, r->R); | ||
462 | |||
463 | for (i = 0; i < BPF_MEMWORDS; i++) { | ||
464 | if (r->M[i]) { | ||
465 | m++; | ||
466 | rl_printf("M[%d]: [%#08x][%u]\n", i, r->M[i], r->M[i]); | ||
467 | } | ||
468 | } | ||
469 | if (m == 0) | ||
470 | rl_printf("M[0,%d]: [%#08x][%u]\n", BPF_MEMWORDS - 1, 0, 0); | ||
471 | } | ||
472 | |||
473 | static void bpf_dump_pkt(uint8_t *pkt, uint32_t pkt_caplen, uint32_t pkt_len) | ||
474 | { | ||
475 | if (pkt_caplen != pkt_len) | ||
476 | rl_printf("cap: %u, len: %u\n", pkt_caplen, pkt_len); | ||
477 | else | ||
478 | rl_printf("len: %u\n", pkt_len); | ||
479 | |||
480 | hex_dump(pkt, pkt_caplen); | ||
481 | } | ||
482 | |||
483 | static void bpf_disasm_all(const struct sock_filter *f, unsigned int len) | ||
484 | { | ||
485 | unsigned int i; | ||
486 | |||
487 | for (i = 0; i < len; i++) | ||
488 | bpf_disasm(f[i], i); | ||
489 | } | ||
490 | |||
491 | static void bpf_dump_all(const struct sock_filter *f, unsigned int len) | ||
492 | { | ||
493 | unsigned int i; | ||
494 | |||
495 | rl_printf("/* { op, jt, jf, k }, */\n"); | ||
496 | for (i = 0; i < len; i++) | ||
497 | rl_printf("{ %#04x, %2u, %2u, %#010x },\n", | ||
498 | f[i].code, f[i].jt, f[i].jf, f[i].k); | ||
499 | } | ||
500 | |||
501 | static bool bpf_runnable(struct sock_filter *f, unsigned int len) | ||
502 | { | ||
503 | int sock, ret, i; | ||
504 | struct sock_fprog bpf = { | ||
505 | .filter = f, | ||
506 | .len = len, | ||
507 | }; | ||
508 | |||
509 | sock = socket(AF_INET, SOCK_DGRAM, 0); | ||
510 | if (sock < 0) { | ||
511 | rl_printf("cannot open socket!\n"); | ||
512 | return false; | ||
513 | } | ||
514 | ret = setsockopt(sock, SOL_SOCKET, SO_ATTACH_FILTER, &bpf, sizeof(bpf)); | ||
515 | close(sock); | ||
516 | if (ret < 0) { | ||
517 | rl_printf("program not allowed to run by kernel!\n"); | ||
518 | return false; | ||
519 | } | ||
520 | for (i = 0; i < len; i++) { | ||
521 | if (BPF_CLASS(f[i].code) == BPF_LD && | ||
522 | f[i].k > SKF_AD_OFF) { | ||
523 | rl_printf("extensions currently not supported!\n"); | ||
524 | return false; | ||
525 | } | ||
526 | } | ||
527 | |||
528 | return true; | ||
529 | } | ||
530 | |||
531 | static void bpf_reset_breakpoints(void) | ||
532 | { | ||
533 | int i; | ||
534 | |||
535 | for (i = 0; i < array_size(bpf_breakpoints); i++) | ||
536 | bpf_breakpoints[i] = -1; | ||
537 | } | ||
538 | |||
539 | static void bpf_set_breakpoints(unsigned int where) | ||
540 | { | ||
541 | int i; | ||
542 | bool set = false; | ||
543 | |||
544 | for (i = 0; i < array_size(bpf_breakpoints); i++) { | ||
545 | if (bpf_breakpoints[i] == (int) where) { | ||
546 | rl_printf("breakpoint already set!\n"); | ||
547 | set = true; | ||
548 | break; | ||
549 | } | ||
550 | |||
551 | if (bpf_breakpoints[i] == -1 && set == false) { | ||
552 | bpf_breakpoints[i] = where; | ||
553 | set = true; | ||
554 | } | ||
555 | } | ||
556 | |||
557 | if (!set) | ||
558 | rl_printf("too many breakpoints set, reset first!\n"); | ||
559 | } | ||
560 | |||
561 | static void bpf_dump_breakpoints(void) | ||
562 | { | ||
563 | int i; | ||
564 | |||
565 | rl_printf("breakpoints: "); | ||
566 | |||
567 | for (i = 0; i < array_size(bpf_breakpoints); i++) { | ||
568 | if (bpf_breakpoints[i] < 0) | ||
569 | continue; | ||
570 | rl_printf("%d ", bpf_breakpoints[i]); | ||
571 | } | ||
572 | |||
573 | rl_printf("\n"); | ||
574 | } | ||
575 | |||
576 | static void bpf_reset(void) | ||
577 | { | ||
578 | bpf_regs_len = 0; | ||
579 | |||
580 | memset(bpf_regs, 0, sizeof(bpf_regs)); | ||
581 | memset(&bpf_curr, 0, sizeof(bpf_curr)); | ||
582 | } | ||
583 | |||
584 | static void bpf_safe_regs(void) | ||
585 | { | ||
586 | memcpy(&bpf_regs[bpf_regs_len++], &bpf_curr, sizeof(bpf_curr)); | ||
587 | } | ||
588 | |||
589 | static bool bpf_restore_regs(int off) | ||
590 | { | ||
591 | unsigned int index = bpf_regs_len - 1 + off; | ||
592 | |||
593 | if (index == 0) { | ||
594 | bpf_reset(); | ||
595 | return true; | ||
596 | } else if (index < bpf_regs_len) { | ||
597 | memcpy(&bpf_curr, &bpf_regs[index], sizeof(bpf_curr)); | ||
598 | bpf_regs_len = index; | ||
599 | return true; | ||
600 | } else { | ||
601 | rl_printf("reached bottom of register history stack!\n"); | ||
602 | return false; | ||
603 | } | ||
604 | } | ||
605 | |||
606 | static uint32_t extract_u32(uint8_t *pkt, uint32_t off) | ||
607 | { | ||
608 | uint32_t r; | ||
609 | |||
610 | memcpy(&r, &pkt[off], sizeof(r)); | ||
611 | |||
612 | return ntohl(r); | ||
613 | } | ||
614 | |||
615 | static uint16_t extract_u16(uint8_t *pkt, uint32_t off) | ||
616 | { | ||
617 | uint16_t r; | ||
618 | |||
619 | memcpy(&r, &pkt[off], sizeof(r)); | ||
620 | |||
621 | return ntohs(r); | ||
622 | } | ||
623 | |||
624 | static uint8_t extract_u8(uint8_t *pkt, uint32_t off) | ||
625 | { | ||
626 | return pkt[off]; | ||
627 | } | ||
628 | |||
629 | static void set_return(struct bpf_regs *r) | ||
630 | { | ||
631 | r->R = 0; | ||
632 | r->Rs = true; | ||
633 | } | ||
634 | |||
635 | static void bpf_single_step(struct bpf_regs *r, struct sock_filter *f, | ||
636 | uint8_t *pkt, uint32_t pkt_caplen, | ||
637 | uint32_t pkt_len) | ||
638 | { | ||
639 | uint32_t K = f->k; | ||
640 | int d; | ||
641 | |||
642 | switch (f->code) { | ||
643 | case BPF_RET | BPF_K: | ||
644 | r->R = K; | ||
645 | r->Rs = true; | ||
646 | break; | ||
647 | case BPF_RET | BPF_A: | ||
648 | r->R = r->A; | ||
649 | r->Rs = true; | ||
650 | break; | ||
651 | case BPF_RET | BPF_X: | ||
652 | r->R = r->X; | ||
653 | r->Rs = true; | ||
654 | break; | ||
655 | case BPF_MISC_TAX: | ||
656 | r->X = r->A; | ||
657 | break; | ||
658 | case BPF_MISC_TXA: | ||
659 | r->A = r->X; | ||
660 | break; | ||
661 | case BPF_ST: | ||
662 | r->M[K] = r->A; | ||
663 | break; | ||
664 | case BPF_STX: | ||
665 | r->M[K] = r->X; | ||
666 | break; | ||
667 | case BPF_LD_W | BPF_ABS: | ||
668 | d = pkt_caplen - K; | ||
669 | if (d >= sizeof(uint32_t)) | ||
670 | r->A = extract_u32(pkt, K); | ||
671 | else | ||
672 | set_return(r); | ||
673 | break; | ||
674 | case BPF_LD_H | BPF_ABS: | ||
675 | d = pkt_caplen - K; | ||
676 | if (d >= sizeof(uint16_t)) | ||
677 | r->A = extract_u16(pkt, K); | ||
678 | else | ||
679 | set_return(r); | ||
680 | break; | ||
681 | case BPF_LD_B | BPF_ABS: | ||
682 | d = pkt_caplen - K; | ||
683 | if (d >= sizeof(uint8_t)) | ||
684 | r->A = extract_u8(pkt, K); | ||
685 | else | ||
686 | set_return(r); | ||
687 | break; | ||
688 | case BPF_LD_W | BPF_IND: | ||
689 | d = pkt_caplen - (r->X + K); | ||
690 | if (d >= sizeof(uint32_t)) | ||
691 | r->A = extract_u32(pkt, r->X + K); | ||
692 | break; | ||
693 | case BPF_LD_H | BPF_IND: | ||
694 | d = pkt_caplen - (r->X + K); | ||
695 | if (d >= sizeof(uint16_t)) | ||
696 | r->A = extract_u16(pkt, r->X + K); | ||
697 | else | ||
698 | set_return(r); | ||
699 | break; | ||
700 | case BPF_LD_B | BPF_IND: | ||
701 | d = pkt_caplen - (r->X + K); | ||
702 | if (d >= sizeof(uint8_t)) | ||
703 | r->A = extract_u8(pkt, r->X + K); | ||
704 | else | ||
705 | set_return(r); | ||
706 | break; | ||
707 | case BPF_LDX_B | BPF_MSH: | ||
708 | d = pkt_caplen - K; | ||
709 | if (d >= sizeof(uint8_t)) { | ||
710 | r->X = extract_u8(pkt, K); | ||
711 | r->X = (r->X & 0xf) << 2; | ||
712 | } else | ||
713 | set_return(r); | ||
714 | break; | ||
715 | case BPF_LD_W | BPF_LEN: | ||
716 | r->A = pkt_len; | ||
717 | break; | ||
718 | case BPF_LDX_W | BPF_LEN: | ||
719 | r->A = pkt_len; | ||
720 | break; | ||
721 | case BPF_LD | BPF_IMM: | ||
722 | r->A = K; | ||
723 | break; | ||
724 | case BPF_LDX | BPF_IMM: | ||
725 | r->X = K; | ||
726 | break; | ||
727 | case BPF_LD | BPF_MEM: | ||
728 | r->A = r->M[K]; | ||
729 | break; | ||
730 | case BPF_LDX | BPF_MEM: | ||
731 | r->X = r->M[K]; | ||
732 | break; | ||
733 | case BPF_JMP_JA: | ||
734 | r->Pc += K; | ||
735 | break; | ||
736 | case BPF_JMP_JGT | BPF_X: | ||
737 | r->Pc += r->A > r->X ? f->jt : f->jf; | ||
738 | break; | ||
739 | case BPF_JMP_JGT | BPF_K: | ||
740 | r->Pc += r->A > K ? f->jt : f->jf; | ||
741 | break; | ||
742 | case BPF_JMP_JGE | BPF_X: | ||
743 | r->Pc += r->A >= r->X ? f->jt : f->jf; | ||
744 | break; | ||
745 | case BPF_JMP_JGE | BPF_K: | ||
746 | r->Pc += r->A >= K ? f->jt : f->jf; | ||
747 | break; | ||
748 | case BPF_JMP_JEQ | BPF_X: | ||
749 | r->Pc += r->A == r->X ? f->jt : f->jf; | ||
750 | break; | ||
751 | case BPF_JMP_JEQ | BPF_K: | ||
752 | r->Pc += r->A == K ? f->jt : f->jf; | ||
753 | break; | ||
754 | case BPF_JMP_JSET | BPF_X: | ||
755 | r->Pc += r->A & r->X ? f->jt : f->jf; | ||
756 | break; | ||
757 | case BPF_JMP_JSET | BPF_K: | ||
758 | r->Pc += r->A & K ? f->jt : f->jf; | ||
759 | break; | ||
760 | case BPF_ALU_NEG: | ||
761 | r->A = -r->A; | ||
762 | break; | ||
763 | case BPF_ALU_LSH | BPF_X: | ||
764 | r->A <<= r->X; | ||
765 | break; | ||
766 | case BPF_ALU_LSH | BPF_K: | ||
767 | r->A <<= K; | ||
768 | break; | ||
769 | case BPF_ALU_RSH | BPF_X: | ||
770 | r->A >>= r->X; | ||
771 | break; | ||
772 | case BPF_ALU_RSH | BPF_K: | ||
773 | r->A >>= K; | ||
774 | break; | ||
775 | case BPF_ALU_ADD | BPF_X: | ||
776 | r->A += r->X; | ||
777 | break; | ||
778 | case BPF_ALU_ADD | BPF_K: | ||
779 | r->A += K; | ||
780 | break; | ||
781 | case BPF_ALU_SUB | BPF_X: | ||
782 | r->A -= r->X; | ||
783 | break; | ||
784 | case BPF_ALU_SUB | BPF_K: | ||
785 | r->A -= K; | ||
786 | break; | ||
787 | case BPF_ALU_MUL | BPF_X: | ||
788 | r->A *= r->X; | ||
789 | break; | ||
790 | case BPF_ALU_MUL | BPF_K: | ||
791 | r->A *= K; | ||
792 | break; | ||
793 | case BPF_ALU_DIV | BPF_X: | ||
794 | case BPF_ALU_MOD | BPF_X: | ||
795 | if (r->X == 0) { | ||
796 | set_return(r); | ||
797 | break; | ||
798 | } | ||
799 | goto do_div; | ||
800 | case BPF_ALU_DIV | BPF_K: | ||
801 | case BPF_ALU_MOD | BPF_K: | ||
802 | if (K == 0) { | ||
803 | set_return(r); | ||
804 | break; | ||
805 | } | ||
806 | do_div: | ||
807 | switch (f->code) { | ||
808 | case BPF_ALU_DIV | BPF_X: | ||
809 | r->A /= r->X; | ||
810 | break; | ||
811 | case BPF_ALU_DIV | BPF_K: | ||
812 | r->A /= K; | ||
813 | break; | ||
814 | case BPF_ALU_MOD | BPF_X: | ||
815 | r->A %= r->X; | ||
816 | break; | ||
817 | case BPF_ALU_MOD | BPF_K: | ||
818 | r->A %= K; | ||
819 | break; | ||
820 | } | ||
821 | break; | ||
822 | case BPF_ALU_AND | BPF_X: | ||
823 | r->A &= r->X; | ||
824 | break; | ||
825 | case BPF_ALU_AND | BPF_K: | ||
826 | r->A &= r->X; | ||
827 | break; | ||
828 | case BPF_ALU_OR | BPF_X: | ||
829 | r->A |= r->X; | ||
830 | break; | ||
831 | case BPF_ALU_OR | BPF_K: | ||
832 | r->A |= K; | ||
833 | break; | ||
834 | case BPF_ALU_XOR | BPF_X: | ||
835 | r->A ^= r->X; | ||
836 | break; | ||
837 | case BPF_ALU_XOR | BPF_K: | ||
838 | r->A ^= K; | ||
839 | break; | ||
840 | } | ||
841 | } | ||
842 | |||
843 | static bool bpf_pc_has_breakpoint(uint16_t pc) | ||
844 | { | ||
845 | int i; | ||
846 | |||
847 | for (i = 0; i < array_size(bpf_breakpoints); i++) { | ||
848 | if (bpf_breakpoints[i] < 0) | ||
849 | continue; | ||
850 | if (bpf_breakpoints[i] == pc) | ||
851 | return true; | ||
852 | } | ||
853 | |||
854 | return false; | ||
855 | } | ||
856 | |||
857 | static bool bpf_handle_breakpoint(struct bpf_regs *r, struct sock_filter *f, | ||
858 | uint8_t *pkt, uint32_t pkt_caplen, | ||
859 | uint32_t pkt_len) | ||
860 | { | ||
861 | rl_printf("-- register dump --\n"); | ||
862 | bpf_dump_curr(r, &f[r->Pc]); | ||
863 | rl_printf("-- packet dump --\n"); | ||
864 | bpf_dump_pkt(pkt, pkt_caplen, pkt_len); | ||
865 | rl_printf("(breakpoint)\n"); | ||
866 | return true; | ||
867 | } | ||
868 | |||
869 | static int bpf_run_all(struct sock_filter *f, uint16_t bpf_len, uint8_t *pkt, | ||
870 | uint32_t pkt_caplen, uint32_t pkt_len) | ||
871 | { | ||
872 | bool stop = false; | ||
873 | |||
874 | while (bpf_curr.Rs == false && stop == false) { | ||
875 | bpf_safe_regs(); | ||
876 | |||
877 | if (bpf_pc_has_breakpoint(bpf_curr.Pc)) | ||
878 | stop = bpf_handle_breakpoint(&bpf_curr, f, pkt, | ||
879 | pkt_caplen, pkt_len); | ||
880 | |||
881 | bpf_single_step(&bpf_curr, &f[bpf_curr.Pc], pkt, pkt_caplen, | ||
882 | pkt_len); | ||
883 | bpf_curr.Pc++; | ||
884 | } | ||
885 | |||
886 | return stop ? -1 : bpf_curr.R; | ||
887 | } | ||
888 | |||
889 | static int bpf_run_stepping(struct sock_filter *f, uint16_t bpf_len, | ||
890 | uint8_t *pkt, uint32_t pkt_caplen, | ||
891 | uint32_t pkt_len, int next) | ||
892 | { | ||
893 | bool stop = false; | ||
894 | int i = 1; | ||
895 | |||
896 | while (bpf_curr.Rs == false && stop == false) { | ||
897 | bpf_safe_regs(); | ||
898 | |||
899 | if (i++ == next) | ||
900 | stop = bpf_handle_breakpoint(&bpf_curr, f, pkt, | ||
901 | pkt_caplen, pkt_len); | ||
902 | |||
903 | bpf_single_step(&bpf_curr, &f[bpf_curr.Pc], pkt, pkt_caplen, | ||
904 | pkt_len); | ||
905 | bpf_curr.Pc++; | ||
906 | } | ||
907 | |||
908 | return stop ? -1 : bpf_curr.R; | ||
909 | } | ||
910 | |||
911 | static bool pcap_loaded(void) | ||
912 | { | ||
913 | if (pcap_fd < 0) | ||
914 | rl_printf("no pcap file loaded!\n"); | ||
915 | |||
916 | return pcap_fd >= 0; | ||
917 | } | ||
918 | |||
919 | static struct pcap_pkthdr *pcap_curr_pkt(void) | ||
920 | { | ||
921 | return (void *) pcap_ptr_va_curr; | ||
922 | } | ||
923 | |||
924 | static bool pcap_next_pkt(void) | ||
925 | { | ||
926 | struct pcap_pkthdr *hdr = pcap_curr_pkt(); | ||
927 | |||
928 | if (pcap_ptr_va_curr + sizeof(*hdr) - | ||
929 | pcap_ptr_va_start >= pcap_map_size) | ||
930 | return false; | ||
931 | if (hdr->caplen == 0 || hdr->len == 0 || hdr->caplen > hdr->len) | ||
932 | return false; | ||
933 | if (pcap_ptr_va_curr + sizeof(*hdr) + hdr->caplen - | ||
934 | pcap_ptr_va_start >= pcap_map_size) | ||
935 | return false; | ||
936 | |||
937 | pcap_ptr_va_curr += (sizeof(*hdr) + hdr->caplen); | ||
938 | return true; | ||
939 | } | ||
940 | |||
941 | static void pcap_reset_pkt(void) | ||
942 | { | ||
943 | pcap_ptr_va_curr = pcap_ptr_va_start + sizeof(struct pcap_filehdr); | ||
944 | } | ||
945 | |||
946 | static int try_load_pcap(const char *file) | ||
947 | { | ||
948 | struct pcap_filehdr *hdr; | ||
949 | struct stat sb; | ||
950 | int ret; | ||
951 | |||
952 | pcap_fd = open(file, O_RDONLY); | ||
953 | if (pcap_fd < 0) { | ||
954 | rl_printf("cannot open pcap [%s]!\n", strerror(errno)); | ||
955 | return CMD_ERR; | ||
956 | } | ||
957 | |||
958 | ret = fstat(pcap_fd, &sb); | ||
959 | if (ret < 0) { | ||
960 | rl_printf("cannot fstat pcap file!\n"); | ||
961 | return CMD_ERR; | ||
962 | } | ||
963 | |||
964 | if (!S_ISREG(sb.st_mode)) { | ||
965 | rl_printf("not a regular pcap file, duh!\n"); | ||
966 | return CMD_ERR; | ||
967 | } | ||
968 | |||
969 | pcap_map_size = sb.st_size; | ||
970 | if (pcap_map_size <= sizeof(struct pcap_filehdr)) { | ||
971 | rl_printf("pcap file too small!\n"); | ||
972 | return CMD_ERR; | ||
973 | } | ||
974 | |||
975 | pcap_ptr_va_start = mmap(NULL, pcap_map_size, PROT_READ, | ||
976 | MAP_SHARED | MAP_LOCKED, pcap_fd, 0); | ||
977 | if (pcap_ptr_va_start == MAP_FAILED) { | ||
978 | rl_printf("mmap of file failed!"); | ||
979 | return CMD_ERR; | ||
980 | } | ||
981 | |||
982 | hdr = (void *) pcap_ptr_va_start; | ||
983 | if (hdr->magic != TCPDUMP_MAGIC) { | ||
984 | rl_printf("wrong pcap magic!\n"); | ||
985 | return CMD_ERR; | ||
986 | } | ||
987 | |||
988 | pcap_reset_pkt(); | ||
989 | |||
990 | return CMD_OK; | ||
991 | |||
992 | } | ||
993 | |||
994 | static void try_close_pcap(void) | ||
995 | { | ||
996 | if (pcap_fd >= 0) { | ||
997 | munmap(pcap_ptr_va_start, pcap_map_size); | ||
998 | close(pcap_fd); | ||
999 | |||
1000 | pcap_ptr_va_start = pcap_ptr_va_curr = NULL; | ||
1001 | pcap_map_size = 0; | ||
1002 | pcap_packet = 0; | ||
1003 | pcap_fd = -1; | ||
1004 | } | ||
1005 | } | ||
1006 | |||
1007 | static int cmd_load_bpf(char *bpf_string) | ||
1008 | { | ||
1009 | char sp, *token, separator = ','; | ||
1010 | unsigned short bpf_len, i = 0; | ||
1011 | struct sock_filter tmp; | ||
1012 | |||
1013 | bpf_prog_len = 0; | ||
1014 | memset(bpf_image, 0, sizeof(bpf_image)); | ||
1015 | |||
1016 | if (sscanf(bpf_string, "%hu%c", &bpf_len, &sp) != 2 || | ||
1017 | sp != separator || bpf_len > BPF_MAXINSNS || bpf_len == 0) { | ||
1018 | rl_printf("syntax error in head length encoding!\n"); | ||
1019 | return CMD_ERR; | ||
1020 | } | ||
1021 | |||
1022 | token = bpf_string; | ||
1023 | while ((token = strchr(token, separator)) && (++token)[0]) { | ||
1024 | if (i >= bpf_len) { | ||
1025 | rl_printf("program exceeds encoded length!\n"); | ||
1026 | return CMD_ERR; | ||
1027 | } | ||
1028 | |||
1029 | if (sscanf(token, "%hu %hhu %hhu %u,", | ||
1030 | &tmp.code, &tmp.jt, &tmp.jf, &tmp.k) != 4) { | ||
1031 | rl_printf("syntax error at instruction %d!\n", i); | ||
1032 | return CMD_ERR; | ||
1033 | } | ||
1034 | |||
1035 | bpf_image[i].code = tmp.code; | ||
1036 | bpf_image[i].jt = tmp.jt; | ||
1037 | bpf_image[i].jf = tmp.jf; | ||
1038 | bpf_image[i].k = tmp.k; | ||
1039 | |||
1040 | i++; | ||
1041 | } | ||
1042 | |||
1043 | if (i != bpf_len) { | ||
1044 | rl_printf("syntax error exceeding encoded length!\n"); | ||
1045 | return CMD_ERR; | ||
1046 | } else | ||
1047 | bpf_prog_len = bpf_len; | ||
1048 | if (!bpf_runnable(bpf_image, bpf_prog_len)) | ||
1049 | bpf_prog_len = 0; | ||
1050 | |||
1051 | return CMD_OK; | ||
1052 | } | ||
1053 | |||
1054 | static int cmd_load_pcap(char *file) | ||
1055 | { | ||
1056 | char *file_trim, *tmp; | ||
1057 | |||
1058 | file_trim = strtok_r(file, " ", &tmp); | ||
1059 | if (file_trim == NULL) | ||
1060 | return CMD_ERR; | ||
1061 | |||
1062 | try_close_pcap(); | ||
1063 | |||
1064 | return try_load_pcap(file_trim); | ||
1065 | } | ||
1066 | |||
1067 | static int cmd_load(char *arg) | ||
1068 | { | ||
1069 | char *subcmd, *cont, *tmp = strdup(arg); | ||
1070 | int ret = CMD_OK; | ||
1071 | |||
1072 | subcmd = strtok_r(tmp, " ", &cont); | ||
1073 | if (subcmd == NULL) | ||
1074 | goto out; | ||
1075 | if (matches(subcmd, "bpf") == 0) { | ||
1076 | bpf_reset(); | ||
1077 | bpf_reset_breakpoints(); | ||
1078 | |||
1079 | ret = cmd_load_bpf(cont); | ||
1080 | } else if (matches(subcmd, "pcap") == 0) { | ||
1081 | ret = cmd_load_pcap(cont); | ||
1082 | } else { | ||
1083 | out: | ||
1084 | rl_printf("bpf <code>: load bpf code\n"); | ||
1085 | rl_printf("pcap <file>: load pcap file\n"); | ||
1086 | ret = CMD_ERR; | ||
1087 | } | ||
1088 | |||
1089 | free(tmp); | ||
1090 | return ret; | ||
1091 | } | ||
1092 | |||
1093 | static int cmd_step(char *num) | ||
1094 | { | ||
1095 | struct pcap_pkthdr *hdr; | ||
1096 | int steps, ret; | ||
1097 | |||
1098 | if (!bpf_prog_loaded() || !pcap_loaded()) | ||
1099 | return CMD_ERR; | ||
1100 | |||
1101 | steps = strtol(num, NULL, 10); | ||
1102 | if (steps == 0 || strlen(num) == 0) | ||
1103 | steps = 1; | ||
1104 | if (steps < 0) { | ||
1105 | if (!bpf_restore_regs(steps)) | ||
1106 | return CMD_ERR; | ||
1107 | steps = 1; | ||
1108 | } | ||
1109 | |||
1110 | hdr = pcap_curr_pkt(); | ||
1111 | ret = bpf_run_stepping(bpf_image, bpf_prog_len, | ||
1112 | (uint8_t *) hdr + sizeof(*hdr), | ||
1113 | hdr->caplen, hdr->len, steps); | ||
1114 | if (ret >= 0 || bpf_curr.Rs) { | ||
1115 | bpf_reset(); | ||
1116 | if (!pcap_next_pkt()) { | ||
1117 | rl_printf("(going back to first packet)\n"); | ||
1118 | pcap_reset_pkt(); | ||
1119 | } else { | ||
1120 | rl_printf("(next packet)\n"); | ||
1121 | } | ||
1122 | } | ||
1123 | |||
1124 | return CMD_OK; | ||
1125 | } | ||
1126 | |||
1127 | static int cmd_select(char *num) | ||
1128 | { | ||
1129 | unsigned int which, i; | ||
1130 | struct pcap_pkthdr *hdr; | ||
1131 | bool have_next = true; | ||
1132 | |||
1133 | if (!pcap_loaded() || strlen(num) == 0) | ||
1134 | return CMD_ERR; | ||
1135 | |||
1136 | which = strtoul(num, NULL, 10); | ||
1137 | if (which == 0) { | ||
1138 | rl_printf("packet count starts with 1, clamping!\n"); | ||
1139 | which = 1; | ||
1140 | } | ||
1141 | |||
1142 | pcap_reset_pkt(); | ||
1143 | bpf_reset(); | ||
1144 | |||
1145 | for (i = 0; i < which && (have_next = pcap_next_pkt()); i++) | ||
1146 | /* noop */; | ||
1147 | if (!have_next || (hdr = pcap_curr_pkt()) == NULL) { | ||
1148 | rl_printf("no packet #%u available!\n", which); | ||
1149 | pcap_reset_pkt(); | ||
1150 | return CMD_ERR; | ||
1151 | } | ||
1152 | |||
1153 | return CMD_OK; | ||
1154 | } | ||
1155 | |||
1156 | static int cmd_breakpoint(char *subcmd) | ||
1157 | { | ||
1158 | if (!bpf_prog_loaded()) | ||
1159 | return CMD_ERR; | ||
1160 | if (strlen(subcmd) == 0) | ||
1161 | bpf_dump_breakpoints(); | ||
1162 | else if (matches(subcmd, "reset") == 0) | ||
1163 | bpf_reset_breakpoints(); | ||
1164 | else { | ||
1165 | unsigned int where = strtoul(subcmd, NULL, 10); | ||
1166 | |||
1167 | if (where < bpf_prog_len) { | ||
1168 | bpf_set_breakpoints(where); | ||
1169 | rl_printf("breakpoint at: "); | ||
1170 | bpf_disasm(bpf_image[where], where); | ||
1171 | } | ||
1172 | } | ||
1173 | |||
1174 | return CMD_OK; | ||
1175 | } | ||
1176 | |||
1177 | static int cmd_run(char *num) | ||
1178 | { | ||
1179 | static uint32_t pass = 0, fail = 0; | ||
1180 | struct pcap_pkthdr *hdr; | ||
1181 | bool has_limit = true; | ||
1182 | int ret, pkts = 0, i = 0; | ||
1183 | |||
1184 | if (!bpf_prog_loaded() || !pcap_loaded()) | ||
1185 | return CMD_ERR; | ||
1186 | |||
1187 | pkts = strtol(num, NULL, 10); | ||
1188 | if (pkts == 0 || strlen(num) == 0) | ||
1189 | has_limit = false; | ||
1190 | |||
1191 | do { | ||
1192 | hdr = pcap_curr_pkt(); | ||
1193 | ret = bpf_run_all(bpf_image, bpf_prog_len, | ||
1194 | (uint8_t *) hdr + sizeof(*hdr), | ||
1195 | hdr->caplen, hdr->len); | ||
1196 | if (ret > 0) | ||
1197 | pass++; | ||
1198 | else if (ret == 0) | ||
1199 | fail++; | ||
1200 | else | ||
1201 | return CMD_OK; | ||
1202 | bpf_reset(); | ||
1203 | } while (pcap_next_pkt() && (!has_limit || (has_limit && ++i < pkts))); | ||
1204 | |||
1205 | rl_printf("bpf passes:%u fails:%u\n", pass, fail); | ||
1206 | |||
1207 | pcap_reset_pkt(); | ||
1208 | bpf_reset(); | ||
1209 | |||
1210 | pass = fail = 0; | ||
1211 | return CMD_OK; | ||
1212 | } | ||
1213 | |||
1214 | static int cmd_disassemble(char *line_string) | ||
1215 | { | ||
1216 | bool single_line = false; | ||
1217 | unsigned long line; | ||
1218 | |||
1219 | if (!bpf_prog_loaded()) | ||
1220 | return CMD_ERR; | ||
1221 | if (strlen(line_string) > 0 && | ||
1222 | (line = strtoul(line_string, NULL, 10)) < bpf_prog_len) | ||
1223 | single_line = true; | ||
1224 | if (single_line) | ||
1225 | bpf_disasm(bpf_image[line], line); | ||
1226 | else | ||
1227 | bpf_disasm_all(bpf_image, bpf_prog_len); | ||
1228 | |||
1229 | return CMD_OK; | ||
1230 | } | ||
1231 | |||
1232 | static int cmd_dump(char *dontcare) | ||
1233 | { | ||
1234 | if (!bpf_prog_loaded()) | ||
1235 | return CMD_ERR; | ||
1236 | |||
1237 | bpf_dump_all(bpf_image, bpf_prog_len); | ||
1238 | |||
1239 | return CMD_OK; | ||
1240 | } | ||
1241 | |||
1242 | static int cmd_quit(char *dontcare) | ||
1243 | { | ||
1244 | return CMD_EX; | ||
1245 | } | ||
1246 | |||
1247 | static const struct shell_cmd cmds[] = { | ||
1248 | CMD("load", cmd_load), | ||
1249 | CMD("select", cmd_select), | ||
1250 | CMD("step", cmd_step), | ||
1251 | CMD("run", cmd_run), | ||
1252 | CMD("breakpoint", cmd_breakpoint), | ||
1253 | CMD("disassemble", cmd_disassemble), | ||
1254 | CMD("dump", cmd_dump), | ||
1255 | CMD("quit", cmd_quit), | ||
1256 | }; | ||
1257 | |||
1258 | static int execf(char *arg) | ||
1259 | { | ||
1260 | char *cmd, *cont, *tmp = strdup(arg); | ||
1261 | int i, ret = 0, len; | ||
1262 | |||
1263 | cmd = strtok_r(tmp, " ", &cont); | ||
1264 | if (cmd == NULL) | ||
1265 | goto out; | ||
1266 | len = strlen(cmd); | ||
1267 | for (i = 0; i < array_size(cmds); i++) { | ||
1268 | if (len != strlen(cmds[i].name)) | ||
1269 | continue; | ||
1270 | if (strncmp(cmds[i].name, cmd, len) == 0) { | ||
1271 | ret = cmds[i].func(cont); | ||
1272 | break; | ||
1273 | } | ||
1274 | } | ||
1275 | out: | ||
1276 | free(tmp); | ||
1277 | return ret; | ||
1278 | } | ||
1279 | |||
1280 | static char *shell_comp_gen(const char *buf, int state) | ||
1281 | { | ||
1282 | static int list_index, len; | ||
1283 | const char *name; | ||
1284 | |||
1285 | if (!state) { | ||
1286 | list_index = 0; | ||
1287 | len = strlen(buf); | ||
1288 | } | ||
1289 | |||
1290 | for (; list_index < array_size(cmds); ) { | ||
1291 | name = cmds[list_index].name; | ||
1292 | list_index++; | ||
1293 | |||
1294 | if (strncmp(name, buf, len) == 0) | ||
1295 | return strdup(name); | ||
1296 | } | ||
1297 | |||
1298 | return NULL; | ||
1299 | } | ||
1300 | |||
1301 | static char **shell_completion(const char *buf, int start, int end) | ||
1302 | { | ||
1303 | char **matches = NULL; | ||
1304 | |||
1305 | if (start == 0) | ||
1306 | matches = rl_completion_matches(buf, shell_comp_gen); | ||
1307 | |||
1308 | return matches; | ||
1309 | } | ||
1310 | |||
1311 | static void intr_shell(int sig) | ||
1312 | { | ||
1313 | if (rl_end) | ||
1314 | rl_kill_line(-1, 0); | ||
1315 | |||
1316 | rl_crlf(); | ||
1317 | rl_refresh_line(0, 0); | ||
1318 | rl_free_line_state(); | ||
1319 | } | ||
1320 | |||
1321 | static void init_shell(FILE *fin, FILE *fout) | ||
1322 | { | ||
1323 | char file[128]; | ||
1324 | |||
1325 | memset(file, 0, sizeof(file)); | ||
1326 | snprintf(file, sizeof(file) - 1, | ||
1327 | "%s/.bpf_dbg_history", getenv("HOME")); | ||
1328 | |||
1329 | read_history(file); | ||
1330 | |||
1331 | memset(file, 0, sizeof(file)); | ||
1332 | snprintf(file, sizeof(file) - 1, | ||
1333 | "%s/.bpf_dbg_init", getenv("HOME")); | ||
1334 | |||
1335 | rl_instream = fin; | ||
1336 | rl_outstream = fout; | ||
1337 | |||
1338 | rl_readline_name = "bpf_dbg"; | ||
1339 | rl_terminal_name = getenv("TERM"); | ||
1340 | |||
1341 | rl_catch_signals = 0; | ||
1342 | rl_catch_sigwinch = 1; | ||
1343 | |||
1344 | rl_attempted_completion_function = shell_completion; | ||
1345 | |||
1346 | rl_bind_key('\t', rl_complete); | ||
1347 | |||
1348 | rl_bind_key_in_map('\t', rl_complete, emacs_meta_keymap); | ||
1349 | rl_bind_key_in_map('\033', rl_complete, emacs_meta_keymap); | ||
1350 | |||
1351 | rl_read_init_file(file); | ||
1352 | rl_prep_terminal(0); | ||
1353 | rl_set_signals(); | ||
1354 | |||
1355 | signal(SIGINT, intr_shell); | ||
1356 | } | ||
1357 | |||
1358 | static void exit_shell(void) | ||
1359 | { | ||
1360 | char file[128]; | ||
1361 | |||
1362 | memset(file, 0, sizeof(file)); | ||
1363 | snprintf(file, sizeof(file) - 1, | ||
1364 | "%s/.bpf_dbg_history", getenv("HOME")); | ||
1365 | |||
1366 | write_history(file); | ||
1367 | clear_history(); | ||
1368 | rl_deprep_terminal(); | ||
1369 | |||
1370 | try_close_pcap(); | ||
1371 | } | ||
1372 | |||
1373 | static int run_shell_loop(FILE *fin, FILE *fout) | ||
1374 | { | ||
1375 | char *buf; | ||
1376 | int ret; | ||
1377 | |||
1378 | init_shell(fin, fout); | ||
1379 | |||
1380 | while ((buf = readline("> ")) != NULL) { | ||
1381 | ret = execf(buf); | ||
1382 | if (ret == CMD_EX) | ||
1383 | break; | ||
1384 | if (ret == CMD_OK && strlen(buf) > 0) | ||
1385 | add_history(buf); | ||
1386 | |||
1387 | free(buf); | ||
1388 | } | ||
1389 | |||
1390 | exit_shell(); | ||
1391 | return 0; | ||
1392 | } | ||
1393 | |||
1394 | int main(int argc, char **argv) | ||
1395 | { | ||
1396 | FILE *fin = NULL, *fout = NULL; | ||
1397 | |||
1398 | if (argc >= 2) | ||
1399 | fin = fopen(argv[1], "r"); | ||
1400 | if (argc >= 3) | ||
1401 | fout = fopen(argv[2], "w"); | ||
1402 | |||
1403 | return run_shell_loop(fin ? : stdin, fout ? : stdout); | ||
1404 | } | ||
diff --git a/tools/net/bpf_exp.l b/tools/net/bpf_exp.l new file mode 100644 index 000000000000..bf7be77ddd62 --- /dev/null +++ b/tools/net/bpf_exp.l | |||
@@ -0,0 +1,143 @@ | |||
1 | /* | ||
2 | * BPF asm code lexer | ||
3 | * | ||
4 | * This program is free software; you can distribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License as published | ||
6 | * by the Free Software Foundation; either version 2 of the License, | ||
7 | * or (at your option) any later version. | ||
8 | * | ||
9 | * Syntax kept close to: | ||
10 | * | ||
11 | * Steven McCanne and Van Jacobson. 1993. The BSD packet filter: a new | ||
12 | * architecture for user-level packet capture. In Proceedings of the | ||
13 | * USENIX Winter 1993 Conference Proceedings on USENIX Winter 1993 | ||
14 | * Conference Proceedings (USENIX'93). USENIX Association, Berkeley, | ||
15 | * CA, USA, 2-2. | ||
16 | * | ||
17 | * Copyright 2013 Daniel Borkmann <borkmann@redhat.com> | ||
18 | * Licensed under the GNU General Public License, version 2.0 (GPLv2) | ||
19 | */ | ||
20 | |||
21 | %{ | ||
22 | |||
23 | #include <stdio.h> | ||
24 | #include <stdint.h> | ||
25 | #include <stdlib.h> | ||
26 | |||
27 | #include "bpf_exp.yacc.h" | ||
28 | |||
29 | extern void yyerror(const char *str); | ||
30 | |||
31 | %} | ||
32 | |||
33 | %option align | ||
34 | %option ecs | ||
35 | |||
36 | %option nounput | ||
37 | %option noreject | ||
38 | %option noinput | ||
39 | %option noyywrap | ||
40 | |||
41 | %option 8bit | ||
42 | %option caseless | ||
43 | %option yylineno | ||
44 | |||
45 | %% | ||
46 | |||
47 | "ldb" { return OP_LDB; } | ||
48 | "ldh" { return OP_LDH; } | ||
49 | "ld" { return OP_LD; } | ||
50 | "ldi" { return OP_LDI; } | ||
51 | "ldx" { return OP_LDX; } | ||
52 | "ldxi" { return OP_LDXI; } | ||
53 | "ldxb" { return OP_LDXB; } | ||
54 | "st" { return OP_ST; } | ||
55 | "stx" { return OP_STX; } | ||
56 | "jmp" { return OP_JMP; } | ||
57 | "ja" { return OP_JMP; } | ||
58 | "jeq" { return OP_JEQ; } | ||
59 | "jneq" { return OP_JNEQ; } | ||
60 | "jne" { return OP_JNEQ; } | ||
61 | "jlt" { return OP_JLT; } | ||
62 | "jle" { return OP_JLE; } | ||
63 | "jgt" { return OP_JGT; } | ||
64 | "jge" { return OP_JGE; } | ||
65 | "jset" { return OP_JSET; } | ||
66 | "add" { return OP_ADD; } | ||
67 | "sub" { return OP_SUB; } | ||
68 | "mul" { return OP_MUL; } | ||
69 | "div" { return OP_DIV; } | ||
70 | "mod" { return OP_MOD; } | ||
71 | "neg" { return OP_NEG; } | ||
72 | "and" { return OP_AND; } | ||
73 | "xor" { return OP_XOR; } | ||
74 | "or" { return OP_OR; } | ||
75 | "lsh" { return OP_LSH; } | ||
76 | "rsh" { return OP_RSH; } | ||
77 | "ret" { return OP_RET; } | ||
78 | "tax" { return OP_TAX; } | ||
79 | "txa" { return OP_TXA; } | ||
80 | |||
81 | "#"?("len") { return K_PKT_LEN; } | ||
82 | "#"?("proto") { return K_PROTO; } | ||
83 | "#"?("type") { return K_TYPE; } | ||
84 | "#"?("poff") { return K_POFF; } | ||
85 | "#"?("ifidx") { return K_IFIDX; } | ||
86 | "#"?("nla") { return K_NLATTR; } | ||
87 | "#"?("nlan") { return K_NLATTR_NEST; } | ||
88 | "#"?("mark") { return K_MARK; } | ||
89 | "#"?("queue") { return K_QUEUE; } | ||
90 | "#"?("hatype") { return K_HATYPE; } | ||
91 | "#"?("rxhash") { return K_RXHASH; } | ||
92 | "#"?("cpu") { return K_CPU; } | ||
93 | "#"?("vlan_tci") { return K_VLANT; } | ||
94 | "#"?("vlan_pr") { return K_VLANP; } | ||
95 | |||
96 | ":" { return ':'; } | ||
97 | "," { return ','; } | ||
98 | "#" { return '#'; } | ||
99 | "%" { return '%'; } | ||
100 | "[" { return '['; } | ||
101 | "]" { return ']'; } | ||
102 | "(" { return '('; } | ||
103 | ")" { return ')'; } | ||
104 | "x" { return 'x'; } | ||
105 | "a" { return 'a'; } | ||
106 | "+" { return '+'; } | ||
107 | "M" { return 'M'; } | ||
108 | "*" { return '*'; } | ||
109 | "&" { return '&'; } | ||
110 | |||
111 | ([0][x][a-fA-F0-9]+) { | ||
112 | yylval.number = strtoul(yytext, NULL, 16); | ||
113 | return number; | ||
114 | } | ||
115 | ([0][b][0-1]+) { | ||
116 | yylval.number = strtol(yytext + 2, NULL, 2); | ||
117 | return number; | ||
118 | } | ||
119 | (([0])|([-+]?[1-9][0-9]*)) { | ||
120 | yylval.number = strtol(yytext, NULL, 10); | ||
121 | return number; | ||
122 | } | ||
123 | ([0][0-9]+) { | ||
124 | yylval.number = strtol(yytext + 1, NULL, 8); | ||
125 | return number; | ||
126 | } | ||
127 | [a-zA-Z_][a-zA-Z0-9_]+ { | ||
128 | yylval.label = strdup(yytext); | ||
129 | return label; | ||
130 | } | ||
131 | |||
132 | "/*"([^\*]|\*[^/])*"*/" { /* NOP */ } | ||
133 | ";"[^\n]* { /* NOP */ } | ||
134 | ^#.* { /* NOP */ } | ||
135 | [ \t]+ { /* NOP */ } | ||
136 | [ \n]+ { /* NOP */ } | ||
137 | |||
138 | . { | ||
139 | printf("unknown character \'%s\'", yytext); | ||
140 | yyerror("lex unknown character"); | ||
141 | } | ||
142 | |||
143 | %% | ||
diff --git a/tools/net/bpf_exp.y b/tools/net/bpf_exp.y new file mode 100644 index 000000000000..d15efc989ef5 --- /dev/null +++ b/tools/net/bpf_exp.y | |||
@@ -0,0 +1,762 @@ | |||
1 | /* | ||
2 | * BPF asm code parser | ||
3 | * | ||
4 | * This program is free software; you can distribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License as published | ||
6 | * by the Free Software Foundation; either version 2 of the License, | ||
7 | * or (at your option) any later version. | ||
8 | * | ||
9 | * Syntax kept close to: | ||
10 | * | ||
11 | * Steven McCanne and Van Jacobson. 1993. The BSD packet filter: a new | ||
12 | * architecture for user-level packet capture. In Proceedings of the | ||
13 | * USENIX Winter 1993 Conference Proceedings on USENIX Winter 1993 | ||
14 | * Conference Proceedings (USENIX'93). USENIX Association, Berkeley, | ||
15 | * CA, USA, 2-2. | ||
16 | * | ||
17 | * Copyright 2013 Daniel Borkmann <borkmann@redhat.com> | ||
18 | * Licensed under the GNU General Public License, version 2.0 (GPLv2) | ||
19 | */ | ||
20 | |||
21 | %{ | ||
22 | |||
23 | #include <stdio.h> | ||
24 | #include <string.h> | ||
25 | #include <stdint.h> | ||
26 | #include <stdlib.h> | ||
27 | #include <stdbool.h> | ||
28 | #include <unistd.h> | ||
29 | #include <errno.h> | ||
30 | #include <assert.h> | ||
31 | #include <linux/filter.h> | ||
32 | |||
33 | #include "bpf_exp.yacc.h" | ||
34 | |||
35 | enum jmp_type { JTL, JFL, JKL }; | ||
36 | |||
37 | extern FILE *yyin; | ||
38 | extern int yylex(void); | ||
39 | extern void yyerror(const char *str); | ||
40 | |||
41 | extern void bpf_asm_compile(FILE *fp, bool cstyle); | ||
42 | static void bpf_set_curr_instr(uint16_t op, uint8_t jt, uint8_t jf, uint32_t k); | ||
43 | static void bpf_set_curr_label(char *label); | ||
44 | static void bpf_set_jmp_label(char *label, enum jmp_type type); | ||
45 | |||
46 | %} | ||
47 | |||
48 | %union { | ||
49 | char *label; | ||
50 | uint32_t number; | ||
51 | } | ||
52 | |||
53 | %token OP_LDB OP_LDH OP_LD OP_LDX OP_ST OP_STX OP_JMP OP_JEQ OP_JGT OP_JGE | ||
54 | %token OP_JSET OP_ADD OP_SUB OP_MUL OP_DIV OP_AND OP_OR OP_XOR OP_LSH OP_RSH | ||
55 | %token OP_RET OP_TAX OP_TXA OP_LDXB OP_MOD OP_NEG OP_JNEQ OP_JLT OP_JLE OP_LDI | ||
56 | %token OP_LDXI | ||
57 | |||
58 | %token K_PKT_LEN K_PROTO K_TYPE K_NLATTR K_NLATTR_NEST K_MARK K_QUEUE K_HATYPE | ||
59 | %token K_RXHASH K_CPU K_IFIDX K_VLANT K_VLANP K_POFF | ||
60 | |||
61 | %token ':' ',' '[' ']' '(' ')' 'x' 'a' '+' 'M' '*' '&' '#' '%' | ||
62 | |||
63 | %token number label | ||
64 | |||
65 | %type <label> label | ||
66 | %type <number> number | ||
67 | |||
68 | %% | ||
69 | |||
70 | prog | ||
71 | : line | ||
72 | | prog line | ||
73 | ; | ||
74 | |||
75 | line | ||
76 | : instr | ||
77 | | labelled_instr | ||
78 | ; | ||
79 | |||
80 | labelled_instr | ||
81 | : labelled instr | ||
82 | ; | ||
83 | |||
84 | instr | ||
85 | : ldb | ||
86 | | ldh | ||
87 | | ld | ||
88 | | ldi | ||
89 | | ldx | ||
90 | | ldxi | ||
91 | | st | ||
92 | | stx | ||
93 | | jmp | ||
94 | | jeq | ||
95 | | jneq | ||
96 | | jlt | ||
97 | | jle | ||
98 | | jgt | ||
99 | | jge | ||
100 | | jset | ||
101 | | add | ||
102 | | sub | ||
103 | | mul | ||
104 | | div | ||
105 | | mod | ||
106 | | neg | ||
107 | | and | ||
108 | | or | ||
109 | | xor | ||
110 | | lsh | ||
111 | | rsh | ||
112 | | ret | ||
113 | | tax | ||
114 | | txa | ||
115 | ; | ||
116 | |||
117 | labelled | ||
118 | : label ':' { bpf_set_curr_label($1); } | ||
119 | ; | ||
120 | |||
121 | ldb | ||
122 | : OP_LDB '[' 'x' '+' number ']' { | ||
123 | bpf_set_curr_instr(BPF_LD | BPF_B | BPF_IND, 0, 0, $5); } | ||
124 | | OP_LDB '[' '%' 'x' '+' number ']' { | ||
125 | bpf_set_curr_instr(BPF_LD | BPF_B | BPF_IND, 0, 0, $6); } | ||
126 | | OP_LDB '[' number ']' { | ||
127 | bpf_set_curr_instr(BPF_LD | BPF_B | BPF_ABS, 0, 0, $3); } | ||
128 | | OP_LDB K_PROTO { | ||
129 | bpf_set_curr_instr(BPF_LD | BPF_B | BPF_ABS, 0, 0, | ||
130 | SKF_AD_OFF + SKF_AD_PROTOCOL); } | ||
131 | | OP_LDB K_TYPE { | ||
132 | bpf_set_curr_instr(BPF_LD | BPF_B | BPF_ABS, 0, 0, | ||
133 | SKF_AD_OFF + SKF_AD_PKTTYPE); } | ||
134 | | OP_LDB K_IFIDX { | ||
135 | bpf_set_curr_instr(BPF_LD | BPF_B | BPF_ABS, 0, 0, | ||
136 | SKF_AD_OFF + SKF_AD_IFINDEX); } | ||
137 | | OP_LDB K_NLATTR { | ||
138 | bpf_set_curr_instr(BPF_LD | BPF_B | BPF_ABS, 0, 0, | ||
139 | SKF_AD_OFF + SKF_AD_NLATTR); } | ||
140 | | OP_LDB K_NLATTR_NEST { | ||
141 | bpf_set_curr_instr(BPF_LD | BPF_B | BPF_ABS, 0, 0, | ||
142 | SKF_AD_OFF + SKF_AD_NLATTR_NEST); } | ||
143 | | OP_LDB K_MARK { | ||
144 | bpf_set_curr_instr(BPF_LD | BPF_B | BPF_ABS, 0, 0, | ||
145 | SKF_AD_OFF + SKF_AD_MARK); } | ||
146 | | OP_LDB K_QUEUE { | ||
147 | bpf_set_curr_instr(BPF_LD | BPF_B | BPF_ABS, 0, 0, | ||
148 | SKF_AD_OFF + SKF_AD_QUEUE); } | ||
149 | | OP_LDB K_HATYPE { | ||
150 | bpf_set_curr_instr(BPF_LD | BPF_B | BPF_ABS, 0, 0, | ||
151 | SKF_AD_OFF + SKF_AD_HATYPE); } | ||
152 | | OP_LDB K_RXHASH { | ||
153 | bpf_set_curr_instr(BPF_LD | BPF_B | BPF_ABS, 0, 0, | ||
154 | SKF_AD_OFF + SKF_AD_RXHASH); } | ||
155 | | OP_LDB K_CPU { | ||
156 | bpf_set_curr_instr(BPF_LD | BPF_B | BPF_ABS, 0, 0, | ||
157 | SKF_AD_OFF + SKF_AD_CPU); } | ||
158 | | OP_LDB K_VLANT { | ||
159 | bpf_set_curr_instr(BPF_LD | BPF_B | BPF_ABS, 0, 0, | ||
160 | SKF_AD_OFF + SKF_AD_VLAN_TAG); } | ||
161 | | OP_LDB K_VLANP { | ||
162 | bpf_set_curr_instr(BPF_LD | BPF_B | BPF_ABS, 0, 0, | ||
163 | SKF_AD_OFF + SKF_AD_VLAN_TAG_PRESENT); } | ||
164 | | OP_LDB K_POFF { | ||
165 | bpf_set_curr_instr(BPF_LD | BPF_B | BPF_ABS, 0, 0, | ||
166 | SKF_AD_OFF + SKF_AD_PAY_OFFSET); } | ||
167 | ; | ||
168 | |||
169 | ldh | ||
170 | : OP_LDH '[' 'x' '+' number ']' { | ||
171 | bpf_set_curr_instr(BPF_LD | BPF_H | BPF_IND, 0, 0, $5); } | ||
172 | | OP_LDH '[' '%' 'x' '+' number ']' { | ||
173 | bpf_set_curr_instr(BPF_LD | BPF_H | BPF_IND, 0, 0, $6); } | ||
174 | | OP_LDH '[' number ']' { | ||
175 | bpf_set_curr_instr(BPF_LD | BPF_H | BPF_ABS, 0, 0, $3); } | ||
176 | | OP_LDH K_PROTO { | ||
177 | bpf_set_curr_instr(BPF_LD | BPF_H | BPF_ABS, 0, 0, | ||
178 | SKF_AD_OFF + SKF_AD_PROTOCOL); } | ||
179 | | OP_LDH K_TYPE { | ||
180 | bpf_set_curr_instr(BPF_LD | BPF_H | BPF_ABS, 0, 0, | ||
181 | SKF_AD_OFF + SKF_AD_PKTTYPE); } | ||
182 | | OP_LDH K_IFIDX { | ||
183 | bpf_set_curr_instr(BPF_LD | BPF_H | BPF_ABS, 0, 0, | ||
184 | SKF_AD_OFF + SKF_AD_IFINDEX); } | ||
185 | | OP_LDH K_NLATTR { | ||
186 | bpf_set_curr_instr(BPF_LD | BPF_H | BPF_ABS, 0, 0, | ||
187 | SKF_AD_OFF + SKF_AD_NLATTR); } | ||
188 | | OP_LDH K_NLATTR_NEST { | ||
189 | bpf_set_curr_instr(BPF_LD | BPF_H | BPF_ABS, 0, 0, | ||
190 | SKF_AD_OFF + SKF_AD_NLATTR_NEST); } | ||
191 | | OP_LDH K_MARK { | ||
192 | bpf_set_curr_instr(BPF_LD | BPF_H | BPF_ABS, 0, 0, | ||
193 | SKF_AD_OFF + SKF_AD_MARK); } | ||
194 | | OP_LDH K_QUEUE { | ||
195 | bpf_set_curr_instr(BPF_LD | BPF_H | BPF_ABS, 0, 0, | ||
196 | SKF_AD_OFF + SKF_AD_QUEUE); } | ||
197 | | OP_LDH K_HATYPE { | ||
198 | bpf_set_curr_instr(BPF_LD | BPF_H | BPF_ABS, 0, 0, | ||
199 | SKF_AD_OFF + SKF_AD_HATYPE); } | ||
200 | | OP_LDH K_RXHASH { | ||
201 | bpf_set_curr_instr(BPF_LD | BPF_H | BPF_ABS, 0, 0, | ||
202 | SKF_AD_OFF + SKF_AD_RXHASH); } | ||
203 | | OP_LDH K_CPU { | ||
204 | bpf_set_curr_instr(BPF_LD | BPF_H | BPF_ABS, 0, 0, | ||
205 | SKF_AD_OFF + SKF_AD_CPU); } | ||
206 | | OP_LDH K_VLANT { | ||
207 | bpf_set_curr_instr(BPF_LD | BPF_H | BPF_ABS, 0, 0, | ||
208 | SKF_AD_OFF + SKF_AD_VLAN_TAG); } | ||
209 | | OP_LDH K_VLANP { | ||
210 | bpf_set_curr_instr(BPF_LD | BPF_H | BPF_ABS, 0, 0, | ||
211 | SKF_AD_OFF + SKF_AD_VLAN_TAG_PRESENT); } | ||
212 | | OP_LDH K_POFF { | ||
213 | bpf_set_curr_instr(BPF_LD | BPF_H | BPF_ABS, 0, 0, | ||
214 | SKF_AD_OFF + SKF_AD_PAY_OFFSET); } | ||
215 | ; | ||
216 | |||
217 | ldi | ||
218 | : OP_LDI '#' number { | ||
219 | bpf_set_curr_instr(BPF_LD | BPF_IMM, 0, 0, $3); } | ||
220 | | OP_LDI number { | ||
221 | bpf_set_curr_instr(BPF_LD | BPF_IMM, 0, 0, $2); } | ||
222 | ; | ||
223 | |||
224 | ld | ||
225 | : OP_LD '#' number { | ||
226 | bpf_set_curr_instr(BPF_LD | BPF_IMM, 0, 0, $3); } | ||
227 | | OP_LD K_PKT_LEN { | ||
228 | bpf_set_curr_instr(BPF_LD | BPF_W | BPF_LEN, 0, 0, 0); } | ||
229 | | OP_LD K_PROTO { | ||
230 | bpf_set_curr_instr(BPF_LD | BPF_W | BPF_ABS, 0, 0, | ||
231 | SKF_AD_OFF + SKF_AD_PROTOCOL); } | ||
232 | | OP_LD K_TYPE { | ||
233 | bpf_set_curr_instr(BPF_LD | BPF_W | BPF_ABS, 0, 0, | ||
234 | SKF_AD_OFF + SKF_AD_PKTTYPE); } | ||
235 | | OP_LD K_IFIDX { | ||
236 | bpf_set_curr_instr(BPF_LD | BPF_W | BPF_ABS, 0, 0, | ||
237 | SKF_AD_OFF + SKF_AD_IFINDEX); } | ||
238 | | OP_LD K_NLATTR { | ||
239 | bpf_set_curr_instr(BPF_LD | BPF_W | BPF_ABS, 0, 0, | ||
240 | SKF_AD_OFF + SKF_AD_NLATTR); } | ||
241 | | OP_LD K_NLATTR_NEST { | ||
242 | bpf_set_curr_instr(BPF_LD | BPF_W | BPF_ABS, 0, 0, | ||
243 | SKF_AD_OFF + SKF_AD_NLATTR_NEST); } | ||
244 | | OP_LD K_MARK { | ||
245 | bpf_set_curr_instr(BPF_LD | BPF_W | BPF_ABS, 0, 0, | ||
246 | SKF_AD_OFF + SKF_AD_MARK); } | ||
247 | | OP_LD K_QUEUE { | ||
248 | bpf_set_curr_instr(BPF_LD | BPF_W | BPF_ABS, 0, 0, | ||
249 | SKF_AD_OFF + SKF_AD_QUEUE); } | ||
250 | | OP_LD K_HATYPE { | ||
251 | bpf_set_curr_instr(BPF_LD | BPF_W | BPF_ABS, 0, 0, | ||
252 | SKF_AD_OFF + SKF_AD_HATYPE); } | ||
253 | | OP_LD K_RXHASH { | ||
254 | bpf_set_curr_instr(BPF_LD | BPF_W | BPF_ABS, 0, 0, | ||
255 | SKF_AD_OFF + SKF_AD_RXHASH); } | ||
256 | | OP_LD K_CPU { | ||
257 | bpf_set_curr_instr(BPF_LD | BPF_W | BPF_ABS, 0, 0, | ||
258 | SKF_AD_OFF + SKF_AD_CPU); } | ||
259 | | OP_LD K_VLANT { | ||
260 | bpf_set_curr_instr(BPF_LD | BPF_W | BPF_ABS, 0, 0, | ||
261 | SKF_AD_OFF + SKF_AD_VLAN_TAG); } | ||
262 | | OP_LD K_VLANP { | ||
263 | bpf_set_curr_instr(BPF_LD | BPF_W | BPF_ABS, 0, 0, | ||
264 | SKF_AD_OFF + SKF_AD_VLAN_TAG_PRESENT); } | ||
265 | | OP_LD K_POFF { | ||
266 | bpf_set_curr_instr(BPF_LD | BPF_W | BPF_ABS, 0, 0, | ||
267 | SKF_AD_OFF + SKF_AD_PAY_OFFSET); } | ||
268 | | OP_LD 'M' '[' number ']' { | ||
269 | bpf_set_curr_instr(BPF_LD | BPF_MEM, 0, 0, $4); } | ||
270 | | OP_LD '[' 'x' '+' number ']' { | ||
271 | bpf_set_curr_instr(BPF_LD | BPF_W | BPF_IND, 0, 0, $5); } | ||
272 | | OP_LD '[' '%' 'x' '+' number ']' { | ||
273 | bpf_set_curr_instr(BPF_LD | BPF_W | BPF_IND, 0, 0, $6); } | ||
274 | | OP_LD '[' number ']' { | ||
275 | bpf_set_curr_instr(BPF_LD | BPF_W | BPF_ABS, 0, 0, $3); } | ||
276 | ; | ||
277 | |||
278 | ldxi | ||
279 | : OP_LDXI '#' number { | ||
280 | bpf_set_curr_instr(BPF_LDX | BPF_IMM, 0, 0, $3); } | ||
281 | | OP_LDXI number { | ||
282 | bpf_set_curr_instr(BPF_LDX | BPF_IMM, 0, 0, $2); } | ||
283 | ; | ||
284 | |||
285 | ldx | ||
286 | : OP_LDX '#' number { | ||
287 | bpf_set_curr_instr(BPF_LDX | BPF_IMM, 0, 0, $3); } | ||
288 | | OP_LDX K_PKT_LEN { | ||
289 | bpf_set_curr_instr(BPF_LDX | BPF_W | BPF_LEN, 0, 0, 0); } | ||
290 | | OP_LDX 'M' '[' number ']' { | ||
291 | bpf_set_curr_instr(BPF_LDX | BPF_MEM, 0, 0, $4); } | ||
292 | | OP_LDXB number '*' '(' '[' number ']' '&' number ')' { | ||
293 | if ($2 != 4 || $9 != 0xf) { | ||
294 | fprintf(stderr, "ldxb offset not supported!\n"); | ||
295 | exit(0); | ||
296 | } else { | ||
297 | bpf_set_curr_instr(BPF_LDX | BPF_MSH | BPF_B, 0, 0, $6); } } | ||
298 | | OP_LDX number '*' '(' '[' number ']' '&' number ')' { | ||
299 | if ($2 != 4 || $9 != 0xf) { | ||
300 | fprintf(stderr, "ldxb offset not supported!\n"); | ||
301 | exit(0); | ||
302 | } else { | ||
303 | bpf_set_curr_instr(BPF_LDX | BPF_MSH | BPF_B, 0, 0, $6); } } | ||
304 | ; | ||
305 | |||
306 | st | ||
307 | : OP_ST 'M' '[' number ']' { | ||
308 | bpf_set_curr_instr(BPF_ST, 0, 0, $4); } | ||
309 | ; | ||
310 | |||
311 | stx | ||
312 | : OP_STX 'M' '[' number ']' { | ||
313 | bpf_set_curr_instr(BPF_STX, 0, 0, $4); } | ||
314 | ; | ||
315 | |||
316 | jmp | ||
317 | : OP_JMP label { | ||
318 | bpf_set_jmp_label($2, JKL); | ||
319 | bpf_set_curr_instr(BPF_JMP | BPF_JA, 0, 0, 0); } | ||
320 | ; | ||
321 | |||
322 | jeq | ||
323 | : OP_JEQ '#' number ',' label ',' label { | ||
324 | bpf_set_jmp_label($5, JTL); | ||
325 | bpf_set_jmp_label($7, JFL); | ||
326 | bpf_set_curr_instr(BPF_JMP | BPF_JEQ | BPF_K, 0, 0, $3); } | ||
327 | | OP_JEQ 'x' ',' label ',' label { | ||
328 | bpf_set_jmp_label($4, JTL); | ||
329 | bpf_set_jmp_label($6, JFL); | ||
330 | bpf_set_curr_instr(BPF_JMP | BPF_JEQ | BPF_X, 0, 0, 0); } | ||
331 | | OP_JEQ '%' 'x' ',' label ',' label { | ||
332 | bpf_set_jmp_label($5, JTL); | ||
333 | bpf_set_jmp_label($7, JFL); | ||
334 | bpf_set_curr_instr(BPF_JMP | BPF_JEQ | BPF_X, 0, 0, 0); } | ||
335 | | OP_JEQ '#' number ',' label { | ||
336 | bpf_set_jmp_label($5, JTL); | ||
337 | bpf_set_curr_instr(BPF_JMP | BPF_JEQ | BPF_K, 0, 0, $3); } | ||
338 | | OP_JEQ 'x' ',' label { | ||
339 | bpf_set_jmp_label($4, JTL); | ||
340 | bpf_set_curr_instr(BPF_JMP | BPF_JEQ | BPF_X, 0, 0, 0); } | ||
341 | | OP_JEQ '%' 'x' ',' label { | ||
342 | bpf_set_jmp_label($5, JTL); | ||
343 | bpf_set_curr_instr(BPF_JMP | BPF_JEQ | BPF_X, 0, 0, 0); } | ||
344 | ; | ||
345 | |||
346 | jneq | ||
347 | : OP_JNEQ '#' number ',' label { | ||
348 | bpf_set_jmp_label($5, JFL); | ||
349 | bpf_set_curr_instr(BPF_JMP | BPF_JEQ | BPF_K, 0, 0, $3); } | ||
350 | | OP_JNEQ 'x' ',' label { | ||
351 | bpf_set_jmp_label($4, JFL); | ||
352 | bpf_set_curr_instr(BPF_JMP | BPF_JEQ | BPF_X, 0, 0, 0); } | ||
353 | | OP_JNEQ '%' 'x' ',' label { | ||
354 | bpf_set_jmp_label($5, JFL); | ||
355 | bpf_set_curr_instr(BPF_JMP | BPF_JEQ | BPF_X, 0, 0, 0); } | ||
356 | ; | ||
357 | |||
358 | jlt | ||
359 | : OP_JLT '#' number ',' label { | ||
360 | bpf_set_jmp_label($5, JFL); | ||
361 | bpf_set_curr_instr(BPF_JMP | BPF_JGE | BPF_K, 0, 0, $3); } | ||
362 | | OP_JLT 'x' ',' label { | ||
363 | bpf_set_jmp_label($4, JFL); | ||
364 | bpf_set_curr_instr(BPF_JMP | BPF_JGE | BPF_X, 0, 0, 0); } | ||
365 | | OP_JLT '%' 'x' ',' label { | ||
366 | bpf_set_jmp_label($5, JFL); | ||
367 | bpf_set_curr_instr(BPF_JMP | BPF_JGE | BPF_X, 0, 0, 0); } | ||
368 | ; | ||
369 | |||
370 | jle | ||
371 | : OP_JLE '#' number ',' label { | ||
372 | bpf_set_jmp_label($5, JFL); | ||
373 | bpf_set_curr_instr(BPF_JMP | BPF_JGT | BPF_K, 0, 0, $3); } | ||
374 | | OP_JLE 'x' ',' label { | ||
375 | bpf_set_jmp_label($4, JFL); | ||
376 | bpf_set_curr_instr(BPF_JMP | BPF_JGT | BPF_X, 0, 0, 0); } | ||
377 | | OP_JLE '%' 'x' ',' label { | ||
378 | bpf_set_jmp_label($5, JFL); | ||
379 | bpf_set_curr_instr(BPF_JMP | BPF_JGT | BPF_X, 0, 0, 0); } | ||
380 | ; | ||
381 | |||
382 | jgt | ||
383 | : OP_JGT '#' number ',' label ',' label { | ||
384 | bpf_set_jmp_label($5, JTL); | ||
385 | bpf_set_jmp_label($7, JFL); | ||
386 | bpf_set_curr_instr(BPF_JMP | BPF_JGT | BPF_K, 0, 0, $3); } | ||
387 | | OP_JGT 'x' ',' label ',' label { | ||
388 | bpf_set_jmp_label($4, JTL); | ||
389 | bpf_set_jmp_label($6, JFL); | ||
390 | bpf_set_curr_instr(BPF_JMP | BPF_JGT | BPF_X, 0, 0, 0); } | ||
391 | | OP_JGT '%' 'x' ',' label ',' label { | ||
392 | bpf_set_jmp_label($5, JTL); | ||
393 | bpf_set_jmp_label($7, JFL); | ||
394 | bpf_set_curr_instr(BPF_JMP | BPF_JGT | BPF_X, 0, 0, 0); } | ||
395 | | OP_JGT '#' number ',' label { | ||
396 | bpf_set_jmp_label($5, JTL); | ||
397 | bpf_set_curr_instr(BPF_JMP | BPF_JGT | BPF_K, 0, 0, $3); } | ||
398 | | OP_JGT 'x' ',' label { | ||
399 | bpf_set_jmp_label($4, JTL); | ||
400 | bpf_set_curr_instr(BPF_JMP | BPF_JGT | BPF_X, 0, 0, 0); } | ||
401 | | OP_JGT '%' 'x' ',' label { | ||
402 | bpf_set_jmp_label($5, JTL); | ||
403 | bpf_set_curr_instr(BPF_JMP | BPF_JGT | BPF_X, 0, 0, 0); } | ||
404 | ; | ||
405 | |||
406 | jge | ||
407 | : OP_JGE '#' number ',' label ',' label { | ||
408 | bpf_set_jmp_label($5, JTL); | ||
409 | bpf_set_jmp_label($7, JFL); | ||
410 | bpf_set_curr_instr(BPF_JMP | BPF_JGE | BPF_K, 0, 0, $3); } | ||
411 | | OP_JGE 'x' ',' label ',' label { | ||
412 | bpf_set_jmp_label($4, JTL); | ||
413 | bpf_set_jmp_label($6, JFL); | ||
414 | bpf_set_curr_instr(BPF_JMP | BPF_JGE | BPF_X, 0, 0, 0); } | ||
415 | | OP_JGE '%' 'x' ',' label ',' label { | ||
416 | bpf_set_jmp_label($5, JTL); | ||
417 | bpf_set_jmp_label($7, JFL); | ||
418 | bpf_set_curr_instr(BPF_JMP | BPF_JGE | BPF_X, 0, 0, 0); } | ||
419 | | OP_JGE '#' number ',' label { | ||
420 | bpf_set_jmp_label($5, JTL); | ||
421 | bpf_set_curr_instr(BPF_JMP | BPF_JGE | BPF_K, 0, 0, $3); } | ||
422 | | OP_JGE 'x' ',' label { | ||
423 | bpf_set_jmp_label($4, JTL); | ||
424 | bpf_set_curr_instr(BPF_JMP | BPF_JGE | BPF_X, 0, 0, 0); } | ||
425 | | OP_JGE '%' 'x' ',' label { | ||
426 | bpf_set_jmp_label($5, JTL); | ||
427 | bpf_set_curr_instr(BPF_JMP | BPF_JGE | BPF_X, 0, 0, 0); } | ||
428 | ; | ||
429 | |||
430 | jset | ||
431 | : OP_JSET '#' number ',' label ',' label { | ||
432 | bpf_set_jmp_label($5, JTL); | ||
433 | bpf_set_jmp_label($7, JFL); | ||
434 | bpf_set_curr_instr(BPF_JMP | BPF_JSET | BPF_K, 0, 0, $3); } | ||
435 | | OP_JSET 'x' ',' label ',' label { | ||
436 | bpf_set_jmp_label($4, JTL); | ||
437 | bpf_set_jmp_label($6, JFL); | ||
438 | bpf_set_curr_instr(BPF_JMP | BPF_JSET | BPF_X, 0, 0, 0); } | ||
439 | | OP_JSET '%' 'x' ',' label ',' label { | ||
440 | bpf_set_jmp_label($5, JTL); | ||
441 | bpf_set_jmp_label($7, JFL); | ||
442 | bpf_set_curr_instr(BPF_JMP | BPF_JSET | BPF_X, 0, 0, 0); } | ||
443 | | OP_JSET '#' number ',' label { | ||
444 | bpf_set_jmp_label($5, JTL); | ||
445 | bpf_set_curr_instr(BPF_JMP | BPF_JSET | BPF_K, 0, 0, $3); } | ||
446 | | OP_JSET 'x' ',' label { | ||
447 | bpf_set_jmp_label($4, JTL); | ||
448 | bpf_set_curr_instr(BPF_JMP | BPF_JSET | BPF_X, 0, 0, 0); } | ||
449 | | OP_JSET '%' 'x' ',' label { | ||
450 | bpf_set_jmp_label($5, JTL); | ||
451 | bpf_set_curr_instr(BPF_JMP | BPF_JSET | BPF_X, 0, 0, 0); } | ||
452 | ; | ||
453 | |||
454 | add | ||
455 | : OP_ADD '#' number { | ||
456 | bpf_set_curr_instr(BPF_ALU | BPF_ADD | BPF_K, 0, 0, $3); } | ||
457 | | OP_ADD 'x' { | ||
458 | bpf_set_curr_instr(BPF_ALU | BPF_ADD | BPF_X, 0, 0, 0); } | ||
459 | | OP_ADD '%' 'x' { | ||
460 | bpf_set_curr_instr(BPF_ALU | BPF_ADD | BPF_X, 0, 0, 0); } | ||
461 | ; | ||
462 | |||
463 | sub | ||
464 | : OP_SUB '#' number { | ||
465 | bpf_set_curr_instr(BPF_ALU | BPF_SUB | BPF_K, 0, 0, $3); } | ||
466 | | OP_SUB 'x' { | ||
467 | bpf_set_curr_instr(BPF_ALU | BPF_SUB | BPF_X, 0, 0, 0); } | ||
468 | | OP_SUB '%' 'x' { | ||
469 | bpf_set_curr_instr(BPF_ALU | BPF_SUB | BPF_X, 0, 0, 0); } | ||
470 | ; | ||
471 | |||
472 | mul | ||
473 | : OP_MUL '#' number { | ||
474 | bpf_set_curr_instr(BPF_ALU | BPF_MUL | BPF_K, 0, 0, $3); } | ||
475 | | OP_MUL 'x' { | ||
476 | bpf_set_curr_instr(BPF_ALU | BPF_MUL | BPF_X, 0, 0, 0); } | ||
477 | | OP_MUL '%' 'x' { | ||
478 | bpf_set_curr_instr(BPF_ALU | BPF_MUL | BPF_X, 0, 0, 0); } | ||
479 | ; | ||
480 | |||
481 | div | ||
482 | : OP_DIV '#' number { | ||
483 | bpf_set_curr_instr(BPF_ALU | BPF_DIV | BPF_K, 0, 0, $3); } | ||
484 | | OP_DIV 'x' { | ||
485 | bpf_set_curr_instr(BPF_ALU | BPF_DIV | BPF_X, 0, 0, 0); } | ||
486 | | OP_DIV '%' 'x' { | ||
487 | bpf_set_curr_instr(BPF_ALU | BPF_DIV | BPF_X, 0, 0, 0); } | ||
488 | ; | ||
489 | |||
490 | mod | ||
491 | : OP_MOD '#' number { | ||
492 | bpf_set_curr_instr(BPF_ALU | BPF_MOD | BPF_K, 0, 0, $3); } | ||
493 | | OP_MOD 'x' { | ||
494 | bpf_set_curr_instr(BPF_ALU | BPF_MOD | BPF_X, 0, 0, 0); } | ||
495 | | OP_MOD '%' 'x' { | ||
496 | bpf_set_curr_instr(BPF_ALU | BPF_MOD | BPF_X, 0, 0, 0); } | ||
497 | ; | ||
498 | |||
499 | neg | ||
500 | : OP_NEG { | ||
501 | bpf_set_curr_instr(BPF_ALU | BPF_NEG, 0, 0, 0); } | ||
502 | ; | ||
503 | |||
504 | and | ||
505 | : OP_AND '#' number { | ||
506 | bpf_set_curr_instr(BPF_ALU | BPF_AND | BPF_K, 0, 0, $3); } | ||
507 | | OP_AND 'x' { | ||
508 | bpf_set_curr_instr(BPF_ALU | BPF_AND | BPF_X, 0, 0, 0); } | ||
509 | | OP_AND '%' 'x' { | ||
510 | bpf_set_curr_instr(BPF_ALU | BPF_AND | BPF_X, 0, 0, 0); } | ||
511 | ; | ||
512 | |||
513 | or | ||
514 | : OP_OR '#' number { | ||
515 | bpf_set_curr_instr(BPF_ALU | BPF_OR | BPF_K, 0, 0, $3); } | ||
516 | | OP_OR 'x' { | ||
517 | bpf_set_curr_instr(BPF_ALU | BPF_OR | BPF_X, 0, 0, 0); } | ||
518 | | OP_OR '%' 'x' { | ||
519 | bpf_set_curr_instr(BPF_ALU | BPF_OR | BPF_X, 0, 0, 0); } | ||
520 | ; | ||
521 | |||
522 | xor | ||
523 | : OP_XOR '#' number { | ||
524 | bpf_set_curr_instr(BPF_ALU | BPF_XOR | BPF_K, 0, 0, $3); } | ||
525 | | OP_XOR 'x' { | ||
526 | bpf_set_curr_instr(BPF_ALU | BPF_XOR | BPF_X, 0, 0, 0); } | ||
527 | | OP_XOR '%' 'x' { | ||
528 | bpf_set_curr_instr(BPF_ALU | BPF_XOR | BPF_X, 0, 0, 0); } | ||
529 | ; | ||
530 | |||
531 | lsh | ||
532 | : OP_LSH '#' number { | ||
533 | bpf_set_curr_instr(BPF_ALU | BPF_LSH | BPF_K, 0, 0, $3); } | ||
534 | | OP_LSH 'x' { | ||
535 | bpf_set_curr_instr(BPF_ALU | BPF_LSH | BPF_X, 0, 0, 0); } | ||
536 | | OP_LSH '%' 'x' { | ||
537 | bpf_set_curr_instr(BPF_ALU | BPF_LSH | BPF_X, 0, 0, 0); } | ||
538 | ; | ||
539 | |||
540 | rsh | ||
541 | : OP_RSH '#' number { | ||
542 | bpf_set_curr_instr(BPF_ALU | BPF_RSH | BPF_K, 0, 0, $3); } | ||
543 | | OP_RSH 'x' { | ||
544 | bpf_set_curr_instr(BPF_ALU | BPF_RSH | BPF_X, 0, 0, 0); } | ||
545 | | OP_RSH '%' 'x' { | ||
546 | bpf_set_curr_instr(BPF_ALU | BPF_RSH | BPF_X, 0, 0, 0); } | ||
547 | ; | ||
548 | |||
549 | ret | ||
550 | : OP_RET 'a' { | ||
551 | bpf_set_curr_instr(BPF_RET | BPF_A, 0, 0, 0); } | ||
552 | | OP_RET '%' 'a' { | ||
553 | bpf_set_curr_instr(BPF_RET | BPF_A, 0, 0, 0); } | ||
554 | | OP_RET 'x' { | ||
555 | bpf_set_curr_instr(BPF_RET | BPF_X, 0, 0, 0); } | ||
556 | | OP_RET '%' 'x' { | ||
557 | bpf_set_curr_instr(BPF_RET | BPF_X, 0, 0, 0); } | ||
558 | | OP_RET '#' number { | ||
559 | bpf_set_curr_instr(BPF_RET | BPF_K, 0, 0, $3); } | ||
560 | ; | ||
561 | |||
562 | tax | ||
563 | : OP_TAX { | ||
564 | bpf_set_curr_instr(BPF_MISC | BPF_TAX, 0, 0, 0); } | ||
565 | ; | ||
566 | |||
567 | txa | ||
568 | : OP_TXA { | ||
569 | bpf_set_curr_instr(BPF_MISC | BPF_TXA, 0, 0, 0); } | ||
570 | ; | ||
571 | |||
572 | %% | ||
573 | |||
574 | static int curr_instr = 0; | ||
575 | static struct sock_filter out[BPF_MAXINSNS]; | ||
576 | static char **labels, **labels_jt, **labels_jf, **labels_k; | ||
577 | |||
578 | static void bpf_assert_max(void) | ||
579 | { | ||
580 | if (curr_instr >= BPF_MAXINSNS) { | ||
581 | fprintf(stderr, "only max %u insns allowed!\n", BPF_MAXINSNS); | ||
582 | exit(0); | ||
583 | } | ||
584 | } | ||
585 | |||
586 | static void bpf_set_curr_instr(uint16_t code, uint8_t jt, uint8_t jf, | ||
587 | uint32_t k) | ||
588 | { | ||
589 | bpf_assert_max(); | ||
590 | out[curr_instr].code = code; | ||
591 | out[curr_instr].jt = jt; | ||
592 | out[curr_instr].jf = jf; | ||
593 | out[curr_instr].k = k; | ||
594 | curr_instr++; | ||
595 | } | ||
596 | |||
597 | static void bpf_set_curr_label(char *label) | ||
598 | { | ||
599 | bpf_assert_max(); | ||
600 | labels[curr_instr] = label; | ||
601 | } | ||
602 | |||
603 | static void bpf_set_jmp_label(char *label, enum jmp_type type) | ||
604 | { | ||
605 | bpf_assert_max(); | ||
606 | switch (type) { | ||
607 | case JTL: | ||
608 | labels_jt[curr_instr] = label; | ||
609 | break; | ||
610 | case JFL: | ||
611 | labels_jf[curr_instr] = label; | ||
612 | break; | ||
613 | case JKL: | ||
614 | labels_k[curr_instr] = label; | ||
615 | break; | ||
616 | } | ||
617 | } | ||
618 | |||
619 | static int bpf_find_insns_offset(const char *label) | ||
620 | { | ||
621 | int i, max = curr_instr, ret = -ENOENT; | ||
622 | |||
623 | for (i = 0; i < max; i++) { | ||
624 | if (labels[i] && !strcmp(label, labels[i])) { | ||
625 | ret = i; | ||
626 | break; | ||
627 | } | ||
628 | } | ||
629 | |||
630 | if (ret == -ENOENT) { | ||
631 | fprintf(stderr, "no such label \'%s\'!\n", label); | ||
632 | exit(0); | ||
633 | } | ||
634 | |||
635 | return ret; | ||
636 | } | ||
637 | |||
638 | static void bpf_stage_1_insert_insns(void) | ||
639 | { | ||
640 | yyparse(); | ||
641 | } | ||
642 | |||
643 | static void bpf_reduce_k_jumps(void) | ||
644 | { | ||
645 | int i; | ||
646 | |||
647 | for (i = 0; i < curr_instr; i++) { | ||
648 | if (labels_k[i]) { | ||
649 | int off = bpf_find_insns_offset(labels_k[i]); | ||
650 | out[i].k = (uint32_t) (off - i - 1); | ||
651 | } | ||
652 | } | ||
653 | } | ||
654 | |||
655 | static void bpf_reduce_jt_jumps(void) | ||
656 | { | ||
657 | int i; | ||
658 | |||
659 | for (i = 0; i < curr_instr; i++) { | ||
660 | if (labels_jt[i]) { | ||
661 | int off = bpf_find_insns_offset(labels_jt[i]); | ||
662 | out[i].jt = (uint8_t) (off - i -1); | ||
663 | } | ||
664 | } | ||
665 | } | ||
666 | |||
667 | static void bpf_reduce_jf_jumps(void) | ||
668 | { | ||
669 | int i; | ||
670 | |||
671 | for (i = 0; i < curr_instr; i++) { | ||
672 | if (labels_jf[i]) { | ||
673 | int off = bpf_find_insns_offset(labels_jf[i]); | ||
674 | out[i].jf = (uint8_t) (off - i - 1); | ||
675 | } | ||
676 | } | ||
677 | } | ||
678 | |||
679 | static void bpf_stage_2_reduce_labels(void) | ||
680 | { | ||
681 | bpf_reduce_k_jumps(); | ||
682 | bpf_reduce_jt_jumps(); | ||
683 | bpf_reduce_jf_jumps(); | ||
684 | } | ||
685 | |||
686 | static void bpf_pretty_print_c(void) | ||
687 | { | ||
688 | int i; | ||
689 | |||
690 | for (i = 0; i < curr_instr; i++) | ||
691 | printf("{ %#04x, %2u, %2u, %#010x },\n", out[i].code, | ||
692 | out[i].jt, out[i].jf, out[i].k); | ||
693 | } | ||
694 | |||
695 | static void bpf_pretty_print(void) | ||
696 | { | ||
697 | int i; | ||
698 | |||
699 | printf("%u,", curr_instr); | ||
700 | for (i = 0; i < curr_instr; i++) | ||
701 | printf("%u %u %u %u,", out[i].code, | ||
702 | out[i].jt, out[i].jf, out[i].k); | ||
703 | printf("\n"); | ||
704 | } | ||
705 | |||
706 | static void bpf_init(void) | ||
707 | { | ||
708 | memset(out, 0, sizeof(out)); | ||
709 | |||
710 | labels = calloc(BPF_MAXINSNS, sizeof(*labels)); | ||
711 | assert(labels); | ||
712 | labels_jt = calloc(BPF_MAXINSNS, sizeof(*labels_jt)); | ||
713 | assert(labels_jt); | ||
714 | labels_jf = calloc(BPF_MAXINSNS, sizeof(*labels_jf)); | ||
715 | assert(labels_jf); | ||
716 | labels_k = calloc(BPF_MAXINSNS, sizeof(*labels_k)); | ||
717 | assert(labels_k); | ||
718 | } | ||
719 | |||
720 | static void bpf_destroy_labels(void) | ||
721 | { | ||
722 | int i; | ||
723 | |||
724 | for (i = 0; i < curr_instr; i++) { | ||
725 | free(labels_jf[i]); | ||
726 | free(labels_jt[i]); | ||
727 | free(labels_k[i]); | ||
728 | free(labels[i]); | ||
729 | } | ||
730 | } | ||
731 | |||
732 | static void bpf_destroy(void) | ||
733 | { | ||
734 | bpf_destroy_labels(); | ||
735 | free(labels_jt); | ||
736 | free(labels_jf); | ||
737 | free(labels_k); | ||
738 | free(labels); | ||
739 | } | ||
740 | |||
741 | void bpf_asm_compile(FILE *fp, bool cstyle) | ||
742 | { | ||
743 | yyin = fp; | ||
744 | |||
745 | bpf_init(); | ||
746 | bpf_stage_1_insert_insns(); | ||
747 | bpf_stage_2_reduce_labels(); | ||
748 | bpf_destroy(); | ||
749 | |||
750 | if (cstyle) | ||
751 | bpf_pretty_print_c(); | ||
752 | else | ||
753 | bpf_pretty_print(); | ||
754 | |||
755 | if (fp != stdin) | ||
756 | fclose(yyin); | ||
757 | } | ||
758 | |||
759 | void yyerror(const char *str) | ||
760 | { | ||
761 | exit(1); | ||
762 | } | ||
diff --git a/tools/perf/Documentation/perf-archive.txt b/tools/perf/Documentation/perf-archive.txt index 5032a142853e..ac6ecbb3e669 100644 --- a/tools/perf/Documentation/perf-archive.txt +++ b/tools/perf/Documentation/perf-archive.txt | |||
@@ -12,9 +12,9 @@ SYNOPSIS | |||
12 | 12 | ||
13 | DESCRIPTION | 13 | DESCRIPTION |
14 | ----------- | 14 | ----------- |
15 | This command runs runs perf-buildid-list --with-hits, and collects the files | 15 | This command runs perf-buildid-list --with-hits, and collects the files with the |
16 | with the buildids found so that analysis of perf.data contents can be possible | 16 | buildids found so that analysis of perf.data contents can be possible on another |
17 | on another machine. | 17 | machine. |
18 | 18 | ||
19 | 19 | ||
20 | SEE ALSO | 20 | SEE ALSO |
diff --git a/tools/perf/Documentation/perf-kvm.txt b/tools/perf/Documentation/perf-kvm.txt index 6a06cefe9642..52276a6d2b75 100644 --- a/tools/perf/Documentation/perf-kvm.txt +++ b/tools/perf/Documentation/perf-kvm.txt | |||
@@ -10,9 +10,9 @@ SYNOPSIS | |||
10 | [verse] | 10 | [verse] |
11 | 'perf kvm' [--host] [--guest] [--guestmount=<path> | 11 | 'perf kvm' [--host] [--guest] [--guestmount=<path> |
12 | [--guestkallsyms=<path> --guestmodules=<path> | --guestvmlinux=<path>]] | 12 | [--guestkallsyms=<path> --guestmodules=<path> | --guestvmlinux=<path>]] |
13 | {top|record|report|diff|buildid-list} | 13 | {top|record|report|diff|buildid-list} [<options>] |
14 | 'perf kvm' [--host] [--guest] [--guestkallsyms=<path> --guestmodules=<path> | 14 | 'perf kvm' [--host] [--guest] [--guestkallsyms=<path> --guestmodules=<path> |
15 | | --guestvmlinux=<path>] {top|record|report|diff|buildid-list|stat} | 15 | | --guestvmlinux=<path>] {top|record|report|diff|buildid-list|stat} [<options>] |
16 | 'perf kvm stat [record|report|live] [<options>] | 16 | 'perf kvm stat [record|report|live] [<options>] |
17 | 17 | ||
18 | DESCRIPTION | 18 | DESCRIPTION |
@@ -24,10 +24,17 @@ There are a couple of variants of perf kvm: | |||
24 | of an arbitrary workload. | 24 | of an arbitrary workload. |
25 | 25 | ||
26 | 'perf kvm record <command>' to record the performance counter profile | 26 | 'perf kvm record <command>' to record the performance counter profile |
27 | of an arbitrary workload and save it into a perf data file. If both | 27 | of an arbitrary workload and save it into a perf data file. We set the |
28 | --host and --guest are input, the perf data file name is perf.data.kvm. | 28 | default behavior of perf kvm as --guest, so if neither --host nor --guest |
29 | If there is no --host but --guest, the file name is perf.data.guest. | 29 | is input, the perf data file name is perf.data.guest. If --host is input, |
30 | If there is no --guest but --host, the file name is perf.data.host. | 30 | the perf data file name is perf.data.kvm. If you want to record data into |
31 | perf.data.host, please input --host --no-guest. The behaviors are shown as | ||
32 | following: | ||
33 | Default('') -> perf.data.guest | ||
34 | --host -> perf.data.kvm | ||
35 | --guest -> perf.data.guest | ||
36 | --host --guest -> perf.data.kvm | ||
37 | --host --no-guest -> perf.data.host | ||
31 | 38 | ||
32 | 'perf kvm report' to display the performance counter profile information | 39 | 'perf kvm report' to display the performance counter profile information |
33 | recorded via perf kvm record. | 40 | recorded via perf kvm record. |
@@ -37,7 +44,9 @@ There are a couple of variants of perf kvm: | |||
37 | 44 | ||
38 | 'perf kvm buildid-list' to display the buildids found in a perf data file, | 45 | 'perf kvm buildid-list' to display the buildids found in a perf data file, |
39 | so that other tools can be used to fetch packages with matching symbol tables | 46 | so that other tools can be used to fetch packages with matching symbol tables |
40 | for use by perf report. | 47 | for use by perf report. As buildid is read from /sys/kernel/notes in os, then |
48 | if you want to list the buildid for guest, please make sure your perf data file | ||
49 | was captured with --guestmount in perf kvm record. | ||
41 | 50 | ||
42 | 'perf kvm stat <command>' to run a command and gather performance counter | 51 | 'perf kvm stat <command>' to run a command and gather performance counter |
43 | statistics. | 52 | statistics. |
@@ -58,14 +67,14 @@ There are a couple of variants of perf kvm: | |||
58 | OPTIONS | 67 | OPTIONS |
59 | ------- | 68 | ------- |
60 | -i:: | 69 | -i:: |
61 | --input=:: | 70 | --input=<path>:: |
62 | Input file name. | 71 | Input file name. |
63 | -o:: | 72 | -o:: |
64 | --output:: | 73 | --output=<path>:: |
65 | Output file name. | 74 | Output file name. |
66 | --host=:: | 75 | --host:: |
67 | Collect host side performance profile. | 76 | Collect host side performance profile. |
68 | --guest=:: | 77 | --guest:: |
69 | Collect guest side performance profile. | 78 | Collect guest side performance profile. |
70 | --guestmount=<path>:: | 79 | --guestmount=<path>:: |
71 | Guest os root file system mount directory. Users mounts guest os | 80 | Guest os root file system mount directory. Users mounts guest os |
@@ -84,6 +93,9 @@ OPTIONS | |||
84 | kernel module information. Users copy it out from guest os. | 93 | kernel module information. Users copy it out from guest os. |
85 | --guestvmlinux=<path>:: | 94 | --guestvmlinux=<path>:: |
86 | Guest os kernel vmlinux. | 95 | Guest os kernel vmlinux. |
96 | -v:: | ||
97 | --verbose:: | ||
98 | Be more verbose (show counter open errors, etc). | ||
87 | 99 | ||
88 | STAT REPORT OPTIONS | 100 | STAT REPORT OPTIONS |
89 | ------------------- | 101 | ------------------- |
diff --git a/tools/perf/Documentation/perf-record.txt b/tools/perf/Documentation/perf-record.txt index 43b42c4f4a91..c71b0f36d9e8 100644 --- a/tools/perf/Documentation/perf-record.txt +++ b/tools/perf/Documentation/perf-record.txt | |||
@@ -57,6 +57,8 @@ OPTIONS | |||
57 | -t:: | 57 | -t:: |
58 | --tid=:: | 58 | --tid=:: |
59 | Record events on existing thread ID (comma separated list). | 59 | Record events on existing thread ID (comma separated list). |
60 | This option also disables inheritance by default. Enable it by adding | ||
61 | --inherit. | ||
60 | 62 | ||
61 | -u:: | 63 | -u:: |
62 | --uid=:: | 64 | --uid=:: |
@@ -66,8 +68,7 @@ OPTIONS | |||
66 | --realtime=:: | 68 | --realtime=:: |
67 | Collect data with this RT SCHED_FIFO priority. | 69 | Collect data with this RT SCHED_FIFO priority. |
68 | 70 | ||
69 | -D:: | 71 | --no-buffering:: |
70 | --no-delay:: | ||
71 | Collect data without buffering. | 72 | Collect data without buffering. |
72 | 73 | ||
73 | -c:: | 74 | -c:: |
@@ -201,11 +202,16 @@ abort events and some memory events in precise mode on modern Intel CPUs. | |||
201 | --transaction:: | 202 | --transaction:: |
202 | Record transaction flags for transaction related events. | 203 | Record transaction flags for transaction related events. |
203 | 204 | ||
204 | --force-per-cpu:: | 205 | --per-thread:: |
205 | Force the use of per-cpu mmaps. By default, when tasks are specified (i.e. -p, | 206 | Use per-thread mmaps. By default per-cpu mmaps are created. This option |
206 | -t or -u options) per-thread mmaps are created. This option overrides that and | 207 | overrides that and uses per-thread mmaps. A side-effect of that is that |
207 | forces per-cpu mmaps. A side-effect of that is that inheritance is | 208 | inheritance is automatically disabled. --per-thread is ignored with a warning |
208 | automatically enabled. Add the -i option also to disable inheritance. | 209 | if combined with -a or -C options. |
210 | |||
211 | -D:: | ||
212 | --delay=:: | ||
213 | After starting the program, wait msecs before measuring. This is useful to | ||
214 | filter out the startup phase of the program, which is often very different. | ||
209 | 215 | ||
210 | SEE ALSO | 216 | SEE ALSO |
211 | -------- | 217 | -------- |
diff --git a/tools/perf/Documentation/perf-report.txt b/tools/perf/Documentation/perf-report.txt index 10a279871251..8eab8a4bdeb8 100644 --- a/tools/perf/Documentation/perf-report.txt +++ b/tools/perf/Documentation/perf-report.txt | |||
@@ -237,6 +237,15 @@ OPTIONS | |||
237 | Do not show entries which have an overhead under that percent. | 237 | Do not show entries which have an overhead under that percent. |
238 | (Default: 0). | 238 | (Default: 0). |
239 | 239 | ||
240 | --header:: | ||
241 | Show header information in the perf.data file. This includes | ||
242 | various information like hostname, OS and perf version, cpu/mem | ||
243 | info, perf command line, event list and so on. Currently only | ||
244 | --stdio output supports this feature. | ||
245 | |||
246 | --header-only:: | ||
247 | Show only perf.data header (forces --stdio). | ||
248 | |||
240 | SEE ALSO | 249 | SEE ALSO |
241 | -------- | 250 | -------- |
242 | linkperf:perf-stat[1], linkperf:perf-annotate[1] | 251 | linkperf:perf-stat[1], linkperf:perf-annotate[1] |
diff --git a/tools/perf/Documentation/perf-script.txt b/tools/perf/Documentation/perf-script.txt index e9cbfcddfa3f..05f9a0a6784c 100644 --- a/tools/perf/Documentation/perf-script.txt +++ b/tools/perf/Documentation/perf-script.txt | |||
@@ -115,7 +115,7 @@ OPTIONS | |||
115 | -f:: | 115 | -f:: |
116 | --fields:: | 116 | --fields:: |
117 | Comma separated list of fields to print. Options are: | 117 | Comma separated list of fields to print. Options are: |
118 | comm, tid, pid, time, cpu, event, trace, ip, sym, dso, addr, symoff. | 118 | comm, tid, pid, time, cpu, event, trace, ip, sym, dso, addr, symoff, srcline. |
119 | Field list can be prepended with the type, trace, sw or hw, | 119 | Field list can be prepended with the type, trace, sw or hw, |
120 | to indicate to which event type the field list applies. | 120 | to indicate to which event type the field list applies. |
121 | e.g., -f sw:comm,tid,time,ip,sym and -f trace:time,cpu,trace | 121 | e.g., -f sw:comm,tid,time,ip,sym and -f trace:time,cpu,trace |
@@ -203,6 +203,18 @@ OPTIONS | |||
203 | --show-kernel-path:: | 203 | --show-kernel-path:: |
204 | Try to resolve the path of [kernel.kallsyms] | 204 | Try to resolve the path of [kernel.kallsyms] |
205 | 205 | ||
206 | --show-task-events | ||
207 | Display task related events (e.g. FORK, COMM, EXIT). | ||
208 | |||
209 | --show-mmap-events | ||
210 | Display mmap related events (e.g. MMAP, MMAP2). | ||
211 | |||
212 | --header | ||
213 | Show perf.data header. | ||
214 | |||
215 | --header-only | ||
216 | Show only perf.data header. | ||
217 | |||
206 | SEE ALSO | 218 | SEE ALSO |
207 | -------- | 219 | -------- |
208 | linkperf:perf-record[1], linkperf:perf-script-perl[1], | 220 | linkperf:perf-record[1], linkperf:perf-script-perl[1], |
diff --git a/tools/perf/Documentation/perf-stat.txt b/tools/perf/Documentation/perf-stat.txt index 80c7da6732f2..29ee857c09c6 100644 --- a/tools/perf/Documentation/perf-stat.txt +++ b/tools/perf/Documentation/perf-stat.txt | |||
@@ -133,7 +133,7 @@ use --per-core in addition to -a. (system-wide). The output includes the | |||
133 | core number and the number of online logical processors on that physical processor. | 133 | core number and the number of online logical processors on that physical processor. |
134 | 134 | ||
135 | -D msecs:: | 135 | -D msecs:: |
136 | --initial-delay msecs:: | 136 | --delay msecs:: |
137 | After starting the program, wait msecs before measuring. This is useful to | 137 | After starting the program, wait msecs before measuring. This is useful to |
138 | filter out the startup phase of the program, which is often very different. | 138 | filter out the startup phase of the program, which is often very different. |
139 | 139 | ||
diff --git a/tools/perf/Documentation/perf-timechart.txt b/tools/perf/Documentation/perf-timechart.txt index 3ff8bd4f0b4d..bc5990c33dc0 100644 --- a/tools/perf/Documentation/perf-timechart.txt +++ b/tools/perf/Documentation/perf-timechart.txt | |||
@@ -8,8 +8,7 @@ perf-timechart - Tool to visualize total system behavior during a workload | |||
8 | SYNOPSIS | 8 | SYNOPSIS |
9 | -------- | 9 | -------- |
10 | [verse] | 10 | [verse] |
11 | 'perf timechart' record <command> | 11 | 'perf timechart' [<timechart options>] {record} [<record options>] |
12 | 'perf timechart' [<options>] | ||
13 | 12 | ||
14 | DESCRIPTION | 13 | DESCRIPTION |
15 | ----------- | 14 | ----------- |
@@ -21,8 +20,8 @@ There are two variants of perf timechart: | |||
21 | 'perf timechart' to turn a trace into a Scalable Vector Graphics file, | 20 | 'perf timechart' to turn a trace into a Scalable Vector Graphics file, |
22 | that can be viewed with popular SVG viewers such as 'Inkscape'. | 21 | that can be viewed with popular SVG viewers such as 'Inkscape'. |
23 | 22 | ||
24 | OPTIONS | 23 | TIMECHART OPTIONS |
25 | ------- | 24 | ----------------- |
26 | -o:: | 25 | -o:: |
27 | --output=:: | 26 | --output=:: |
28 | Select the output file (default: output.svg) | 27 | Select the output file (default: output.svg) |
@@ -35,6 +34,9 @@ OPTIONS | |||
35 | -P:: | 34 | -P:: |
36 | --power-only:: | 35 | --power-only:: |
37 | Only output the CPU power section of the diagram | 36 | Only output the CPU power section of the diagram |
37 | -T:: | ||
38 | --tasks-only:: | ||
39 | Don't output processor state transitions | ||
38 | -p:: | 40 | -p:: |
39 | --process:: | 41 | --process:: |
40 | Select the processes to display, by name or PID | 42 | Select the processes to display, by name or PID |
@@ -54,6 +56,38 @@ $ perf timechart | |||
54 | 56 | ||
55 | Written 10.2 seconds of trace to output.svg. | 57 | Written 10.2 seconds of trace to output.svg. |
56 | 58 | ||
59 | Record system-wide timechart: | ||
60 | |||
61 | $ perf timechart record | ||
62 | |||
63 | then generate timechart and highlight 'gcc' tasks: | ||
64 | |||
65 | $ perf timechart --highlight gcc | ||
66 | |||
67 | -n:: | ||
68 | --proc-num:: | ||
69 | Print task info for at least given number of tasks. | ||
70 | -t:: | ||
71 | --topology:: | ||
72 | Sort CPUs according to topology. | ||
73 | --highlight=<duration_nsecs|task_name>:: | ||
74 | Highlight tasks (using different color) that run more than given | ||
75 | duration or tasks with given name. If number is given it's interpreted | ||
76 | as number of nanoseconds. If non-numeric string is given it's | ||
77 | interpreted as task name. | ||
78 | |||
79 | RECORD OPTIONS | ||
80 | -------------- | ||
81 | -P:: | ||
82 | --power-only:: | ||
83 | Record only power-related events | ||
84 | -T:: | ||
85 | --tasks-only:: | ||
86 | Record only tasks-related events | ||
87 | -g:: | ||
88 | --callchain:: | ||
89 | Do call-graph (stack chain/backtrace) recording | ||
90 | |||
57 | SEE ALSO | 91 | SEE ALSO |
58 | -------- | 92 | -------- |
59 | linkperf:perf-record[1] | 93 | linkperf:perf-record[1] |
diff --git a/tools/perf/Documentation/perf-top.txt b/tools/perf/Documentation/perf-top.txt index 7de01dd79688..cdd8d4946dba 100644 --- a/tools/perf/Documentation/perf-top.txt +++ b/tools/perf/Documentation/perf-top.txt | |||
@@ -50,7 +50,6 @@ Default is to monitor all CPUS. | |||
50 | --count-filter=<count>:: | 50 | --count-filter=<count>:: |
51 | Only display functions with more events than this. | 51 | Only display functions with more events than this. |
52 | 52 | ||
53 | -g:: | ||
54 | --group:: | 53 | --group:: |
55 | Put the counters into a counter group. | 54 | Put the counters into a counter group. |
56 | 55 | ||
@@ -143,12 +142,12 @@ Default is to monitor all CPUS. | |||
143 | --asm-raw:: | 142 | --asm-raw:: |
144 | Show raw instruction encoding of assembly instructions. | 143 | Show raw instruction encoding of assembly instructions. |
145 | 144 | ||
146 | -G:: | 145 | -g:: |
147 | Enables call-graph (stack chain/backtrace) recording. | 146 | Enables call-graph (stack chain/backtrace) recording. |
148 | 147 | ||
149 | --call-graph:: | 148 | --call-graph:: |
150 | Setup and enable call-graph (stack chain/backtrace) recording, | 149 | Setup and enable call-graph (stack chain/backtrace) recording, |
151 | implies -G. | 150 | implies -g. |
152 | 151 | ||
153 | --max-stack:: | 152 | --max-stack:: |
154 | Set the stack depth limit when parsing the callchain, anything | 153 | Set the stack depth limit when parsing the callchain, anything |
diff --git a/tools/perf/MANIFEST b/tools/perf/MANIFEST index 025de796067c..f41572d0dd76 100644 --- a/tools/perf/MANIFEST +++ b/tools/perf/MANIFEST | |||
@@ -1,7 +1,11 @@ | |||
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 | tools/lib/api |
5 | tools/lib/symbol/kallsyms.c | ||
6 | tools/lib/symbol/kallsyms.h | ||
7 | tools/include/asm/bug.h | ||
8 | tools/include/linux/compiler.h | ||
5 | include/linux/const.h | 9 | include/linux/const.h |
6 | include/linux/perf_event.h | 10 | include/linux/perf_event.h |
7 | include/linux/rbtree.h | 11 | include/linux/rbtree.h |
diff --git a/tools/perf/Makefile b/tools/perf/Makefile index 4835618a5608..cb2e5868c8e8 100644 --- a/tools/perf/Makefile +++ b/tools/perf/Makefile | |||
@@ -60,8 +60,11 @@ endef | |||
60 | 60 | ||
61 | # | 61 | # |
62 | # Needed if no target specified: | 62 | # Needed if no target specified: |
63 | # (Except for tags and TAGS targets. The reason is that the | ||
64 | # Makefile does not treat tags/TAGS as targets but as files | ||
65 | # and thus won't rebuilt them once they are in place.) | ||
63 | # | 66 | # |
64 | all: | 67 | all tags TAGS: |
65 | $(print_msg) | 68 | $(print_msg) |
66 | $(make) | 69 | $(make) |
67 | 70 | ||
@@ -72,8 +75,16 @@ clean: | |||
72 | $(make) | 75 | $(make) |
73 | 76 | ||
74 | # | 77 | # |
78 | # The build-test target is not really parallel, don't print the jobs info: | ||
79 | # | ||
80 | build-test: | ||
81 | @$(MAKE) -f tests/make --no-print-directory | ||
82 | |||
83 | # | ||
75 | # All other targets get passed through: | 84 | # All other targets get passed through: |
76 | # | 85 | # |
77 | %: | 86 | %: |
78 | $(print_msg) | 87 | $(print_msg) |
79 | $(make) | 88 | $(make) |
89 | |||
90 | .PHONY: tags TAGS | ||
diff --git a/tools/perf/Makefile.perf b/tools/perf/Makefile.perf index 7fc8f179cae7..7257e7e9e38a 100644 --- a/tools/perf/Makefile.perf +++ b/tools/perf/Makefile.perf | |||
@@ -76,6 +76,7 @@ $(OUTPUT)PERF-VERSION-FILE: ../../.git/HEAD | |||
76 | 76 | ||
77 | CC = $(CROSS_COMPILE)gcc | 77 | CC = $(CROSS_COMPILE)gcc |
78 | AR = $(CROSS_COMPILE)ar | 78 | AR = $(CROSS_COMPILE)ar |
79 | PKG_CONFIG = $(CROSS_COMPILE)pkg-config | ||
79 | 80 | ||
80 | RM = rm -f | 81 | RM = rm -f |
81 | LN = ln -f | 82 | LN = ln -f |
@@ -86,7 +87,7 @@ FLEX = flex | |||
86 | BISON = bison | 87 | BISON = bison |
87 | STRIP = strip | 88 | STRIP = strip |
88 | 89 | ||
89 | LK_DIR = $(srctree)/tools/lib/lk/ | 90 | LIB_DIR = $(srctree)/tools/lib/api/ |
90 | TRACE_EVENT_DIR = $(srctree)/tools/lib/traceevent/ | 91 | TRACE_EVENT_DIR = $(srctree)/tools/lib/traceevent/ |
91 | 92 | ||
92 | # include config/Makefile by default and rule out | 93 | # include config/Makefile by default and rule out |
@@ -105,7 +106,7 @@ ifeq ($(config),1) | |||
105 | include config/Makefile | 106 | include config/Makefile |
106 | endif | 107 | endif |
107 | 108 | ||
108 | export prefix bindir sharedir sysconfdir | 109 | export prefix bindir sharedir sysconfdir DESTDIR |
109 | 110 | ||
110 | # sparse is architecture-neutral, which means that we need to tell it | 111 | # sparse is architecture-neutral, which means that we need to tell it |
111 | # explicitly what architecture to check for. Fix this up for yours.. | 112 | # explicitly what architecture to check for. Fix this up for yours.. |
@@ -127,20 +128,20 @@ strip-libs = $(filter-out -l%,$(1)) | |||
127 | ifneq ($(OUTPUT),) | 128 | ifneq ($(OUTPUT),) |
128 | TE_PATH=$(OUTPUT) | 129 | TE_PATH=$(OUTPUT) |
129 | ifneq ($(subdir),) | 130 | ifneq ($(subdir),) |
130 | LK_PATH=$(OUTPUT)/../lib/lk/ | 131 | LIB_PATH=$(OUTPUT)/../lib/api/ |
131 | else | 132 | else |
132 | LK_PATH=$(OUTPUT) | 133 | LIB_PATH=$(OUTPUT) |
133 | endif | 134 | endif |
134 | else | 135 | else |
135 | TE_PATH=$(TRACE_EVENT_DIR) | 136 | TE_PATH=$(TRACE_EVENT_DIR) |
136 | LK_PATH=$(LK_DIR) | 137 | LIB_PATH=$(LIB_DIR) |
137 | endif | 138 | endif |
138 | 139 | ||
139 | LIBTRACEEVENT = $(TE_PATH)libtraceevent.a | 140 | LIBTRACEEVENT = $(TE_PATH)libtraceevent.a |
140 | export LIBTRACEEVENT | 141 | export LIBTRACEEVENT |
141 | 142 | ||
142 | LIBLK = $(LK_PATH)liblk.a | 143 | LIBAPIKFS = $(LIB_PATH)libapikfs.a |
143 | export LIBLK | 144 | export LIBAPIKFS |
144 | 145 | ||
145 | # python extension build directories | 146 | # python extension build directories |
146 | PYTHON_EXTBUILD := $(OUTPUT)python_ext_build/ | 147 | PYTHON_EXTBUILD := $(OUTPUT)python_ext_build/ |
@@ -151,7 +152,7 @@ export PYTHON_EXTBUILD_LIB PYTHON_EXTBUILD_TMP | |||
151 | python-clean := $(call QUIET_CLEAN, python) $(RM) -r $(PYTHON_EXTBUILD) $(OUTPUT)python/perf.so | 152 | python-clean := $(call QUIET_CLEAN, python) $(RM) -r $(PYTHON_EXTBUILD) $(OUTPUT)python/perf.so |
152 | 153 | ||
153 | PYTHON_EXT_SRCS := $(shell grep -v ^\# util/python-ext-sources) | 154 | PYTHON_EXT_SRCS := $(shell grep -v ^\# util/python-ext-sources) |
154 | PYTHON_EXT_DEPS := util/python-ext-sources util/setup.py $(LIBTRACEEVENT) $(LIBLK) | 155 | PYTHON_EXT_DEPS := util/python-ext-sources util/setup.py $(LIBTRACEEVENT) $(LIBAPIKFS) |
155 | 156 | ||
156 | $(OUTPUT)python/perf.so: $(PYTHON_EXT_SRCS) $(PYTHON_EXT_DEPS) | 157 | $(OUTPUT)python/perf.so: $(PYTHON_EXT_SRCS) $(PYTHON_EXT_DEPS) |
157 | $(QUIET_GEN)CFLAGS='$(CFLAGS)' $(PYTHON_WORD) util/setup.py \ | 158 | $(QUIET_GEN)CFLAGS='$(CFLAGS)' $(PYTHON_WORD) util/setup.py \ |
@@ -202,6 +203,7 @@ $(OUTPUT)util/pmu.o: $(OUTPUT)util/pmu-flex.c $(OUTPUT)util/pmu-bison.c | |||
202 | 203 | ||
203 | LIB_FILE=$(OUTPUT)libperf.a | 204 | LIB_FILE=$(OUTPUT)libperf.a |
204 | 205 | ||
206 | LIB_H += ../lib/symbol/kallsyms.h | ||
205 | LIB_H += ../../include/uapi/linux/perf_event.h | 207 | LIB_H += ../../include/uapi/linux/perf_event.h |
206 | LIB_H += ../../include/linux/rbtree.h | 208 | LIB_H += ../../include/linux/rbtree.h |
207 | LIB_H += ../../include/linux/list.h | 209 | LIB_H += ../../include/linux/list.h |
@@ -210,7 +212,7 @@ LIB_H += ../../include/linux/hash.h | |||
210 | LIB_H += ../../include/linux/stringify.h | 212 | LIB_H += ../../include/linux/stringify.h |
211 | LIB_H += util/include/linux/bitmap.h | 213 | LIB_H += util/include/linux/bitmap.h |
212 | LIB_H += util/include/linux/bitops.h | 214 | LIB_H += util/include/linux/bitops.h |
213 | LIB_H += util/include/linux/compiler.h | 215 | LIB_H += ../include/linux/compiler.h |
214 | LIB_H += util/include/linux/const.h | 216 | LIB_H += util/include/linux/const.h |
215 | LIB_H += util/include/linux/ctype.h | 217 | LIB_H += util/include/linux/ctype.h |
216 | LIB_H += util/include/linux/kernel.h | 218 | LIB_H += util/include/linux/kernel.h |
@@ -225,7 +227,7 @@ LIB_H += util/include/linux/string.h | |||
225 | LIB_H += util/include/linux/types.h | 227 | LIB_H += util/include/linux/types.h |
226 | LIB_H += util/include/linux/linkage.h | 228 | LIB_H += util/include/linux/linkage.h |
227 | LIB_H += util/include/asm/asm-offsets.h | 229 | LIB_H += util/include/asm/asm-offsets.h |
228 | LIB_H += util/include/asm/bug.h | 230 | LIB_H += ../include/asm/bug.h |
229 | LIB_H += util/include/asm/byteorder.h | 231 | LIB_H += util/include/asm/byteorder.h |
230 | LIB_H += util/include/asm/hweight.h | 232 | LIB_H += util/include/asm/hweight.h |
231 | LIB_H += util/include/asm/swab.h | 233 | LIB_H += util/include/asm/swab.h |
@@ -312,6 +314,7 @@ LIB_OBJS += $(OUTPUT)util/evlist.o | |||
312 | LIB_OBJS += $(OUTPUT)util/evsel.o | 314 | LIB_OBJS += $(OUTPUT)util/evsel.o |
313 | LIB_OBJS += $(OUTPUT)util/exec_cmd.o | 315 | LIB_OBJS += $(OUTPUT)util/exec_cmd.o |
314 | LIB_OBJS += $(OUTPUT)util/help.o | 316 | LIB_OBJS += $(OUTPUT)util/help.o |
317 | LIB_OBJS += $(OUTPUT)util/kallsyms.o | ||
315 | LIB_OBJS += $(OUTPUT)util/levenshtein.o | 318 | LIB_OBJS += $(OUTPUT)util/levenshtein.o |
316 | LIB_OBJS += $(OUTPUT)util/parse-options.o | 319 | LIB_OBJS += $(OUTPUT)util/parse-options.o |
317 | LIB_OBJS += $(OUTPUT)util/parse-events.o | 320 | LIB_OBJS += $(OUTPUT)util/parse-events.o |
@@ -353,6 +356,7 @@ LIB_OBJS += $(OUTPUT)util/pmu-bison.o | |||
353 | LIB_OBJS += $(OUTPUT)util/trace-event-read.o | 356 | LIB_OBJS += $(OUTPUT)util/trace-event-read.o |
354 | LIB_OBJS += $(OUTPUT)util/trace-event-info.o | 357 | LIB_OBJS += $(OUTPUT)util/trace-event-info.o |
355 | LIB_OBJS += $(OUTPUT)util/trace-event-scripting.o | 358 | LIB_OBJS += $(OUTPUT)util/trace-event-scripting.o |
359 | LIB_OBJS += $(OUTPUT)util/trace-event.o | ||
356 | LIB_OBJS += $(OUTPUT)util/svghelper.o | 360 | LIB_OBJS += $(OUTPUT)util/svghelper.o |
357 | LIB_OBJS += $(OUTPUT)util/sort.o | 361 | LIB_OBJS += $(OUTPUT)util/sort.o |
358 | LIB_OBJS += $(OUTPUT)util/hist.o | 362 | LIB_OBJS += $(OUTPUT)util/hist.o |
@@ -438,7 +442,7 @@ BUILTIN_OBJS += $(OUTPUT)builtin-inject.o | |||
438 | BUILTIN_OBJS += $(OUTPUT)tests/builtin-test.o | 442 | BUILTIN_OBJS += $(OUTPUT)tests/builtin-test.o |
439 | BUILTIN_OBJS += $(OUTPUT)builtin-mem.o | 443 | BUILTIN_OBJS += $(OUTPUT)builtin-mem.o |
440 | 444 | ||
441 | PERFLIBS = $(LIB_FILE) $(LIBLK) $(LIBTRACEEVENT) | 445 | PERFLIBS = $(LIB_FILE) $(LIBAPIKFS) $(LIBTRACEEVENT) |
442 | 446 | ||
443 | # We choose to avoid "if .. else if .. else .. endif endif" | 447 | # We choose to avoid "if .. else if .. else .. endif endif" |
444 | # because maintaining the nesting to match is a pain. If | 448 | # because maintaining the nesting to match is a pain. If |
@@ -486,6 +490,7 @@ ifndef NO_SLANG | |||
486 | LIB_OBJS += $(OUTPUT)ui/browsers/hists.o | 490 | LIB_OBJS += $(OUTPUT)ui/browsers/hists.o |
487 | LIB_OBJS += $(OUTPUT)ui/browsers/map.o | 491 | LIB_OBJS += $(OUTPUT)ui/browsers/map.o |
488 | LIB_OBJS += $(OUTPUT)ui/browsers/scripts.o | 492 | LIB_OBJS += $(OUTPUT)ui/browsers/scripts.o |
493 | LIB_OBJS += $(OUTPUT)ui/browsers/header.o | ||
489 | LIB_OBJS += $(OUTPUT)ui/tui/setup.o | 494 | LIB_OBJS += $(OUTPUT)ui/tui/setup.o |
490 | LIB_OBJS += $(OUTPUT)ui/tui/util.o | 495 | LIB_OBJS += $(OUTPUT)ui/tui/util.o |
491 | LIB_OBJS += $(OUTPUT)ui/tui/helpline.o | 496 | LIB_OBJS += $(OUTPUT)ui/tui/helpline.o |
@@ -671,6 +676,9 @@ $(OUTPUT)ui/browsers/map.o: ui/browsers/map.c $(OUTPUT)PERF-CFLAGS | |||
671 | $(OUTPUT)ui/browsers/scripts.o: ui/browsers/scripts.c $(OUTPUT)PERF-CFLAGS | 676 | $(OUTPUT)ui/browsers/scripts.o: ui/browsers/scripts.c $(OUTPUT)PERF-CFLAGS |
672 | $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) -DENABLE_SLFUTURE_CONST $< | 677 | $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) -DENABLE_SLFUTURE_CONST $< |
673 | 678 | ||
679 | $(OUTPUT)util/kallsyms.o: ../lib/symbol/kallsyms.c $(OUTPUT)PERF-CFLAGS | ||
680 | $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) $< | ||
681 | |||
674 | $(OUTPUT)util/rbtree.o: ../../lib/rbtree.c $(OUTPUT)PERF-CFLAGS | 682 | $(OUTPUT)util/rbtree.o: ../../lib/rbtree.c $(OUTPUT)PERF-CFLAGS |
675 | $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) -Wno-unused-parameter -DETC_PERFCONFIG='"$(ETC_PERFCONFIG_SQ)"' $< | 683 | $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) -Wno-unused-parameter -DETC_PERFCONFIG='"$(ETC_PERFCONFIG_SQ)"' $< |
676 | 684 | ||
@@ -710,26 +718,33 @@ $(LIB_FILE): $(LIB_OBJS) | |||
710 | # libtraceevent.a | 718 | # libtraceevent.a |
711 | TE_SOURCES = $(wildcard $(TRACE_EVENT_DIR)*.[ch]) | 719 | TE_SOURCES = $(wildcard $(TRACE_EVENT_DIR)*.[ch]) |
712 | 720 | ||
713 | $(LIBTRACEEVENT): $(TE_SOURCES) | 721 | LIBTRACEEVENT_FLAGS = $(QUIET_SUBDIR1) O=$(OUTPUT) |
714 | $(QUIET_SUBDIR0)$(TRACE_EVENT_DIR) $(QUIET_SUBDIR1) O=$(OUTPUT) CFLAGS="-g -Wall $(EXTRA_CFLAGS)" libtraceevent.a | 722 | LIBTRACEEVENT_FLAGS += CFLAGS="-g -Wall $(EXTRA_CFLAGS)" |
723 | LIBTRACEEVENT_FLAGS += plugin_dir=$(plugindir_SQ) | ||
724 | |||
725 | $(LIBTRACEEVENT): $(TE_SOURCES) $(OUTPUT)PERF-CFLAGS | ||
726 | $(QUIET_SUBDIR0)$(TRACE_EVENT_DIR) $(LIBTRACEEVENT_FLAGS) libtraceevent.a plugins | ||
715 | 727 | ||
716 | $(LIBTRACEEVENT)-clean: | 728 | $(LIBTRACEEVENT)-clean: |
717 | $(call QUIET_CLEAN, libtraceevent) | 729 | $(call QUIET_CLEAN, libtraceevent) |
718 | @$(MAKE) -C $(TRACE_EVENT_DIR) O=$(OUTPUT) clean >/dev/null | 730 | @$(MAKE) -C $(TRACE_EVENT_DIR) O=$(OUTPUT) clean >/dev/null |
719 | 731 | ||
720 | LIBLK_SOURCES = $(wildcard $(LK_PATH)*.[ch]) | 732 | install-traceevent-plugins: $(LIBTRACEEVENT) |
733 | $(QUIET_SUBDIR0)$(TRACE_EVENT_DIR) $(LIBTRACEEVENT_FLAGS) install_plugins | ||
734 | |||
735 | LIBAPIKFS_SOURCES = $(wildcard $(LIB_PATH)fs/*.[ch]) | ||
721 | 736 | ||
722 | # if subdir is set, we've been called from above so target has been built | 737 | # if subdir is set, we've been called from above so target has been built |
723 | # already | 738 | # already |
724 | $(LIBLK): $(LIBLK_SOURCES) | 739 | $(LIBAPIKFS): $(LIBAPIKFS_SOURCES) |
725 | ifeq ($(subdir),) | 740 | ifeq ($(subdir),) |
726 | $(QUIET_SUBDIR0)$(LK_DIR) $(QUIET_SUBDIR1) O=$(OUTPUT) liblk.a | 741 | $(QUIET_SUBDIR0)$(LIB_DIR) $(QUIET_SUBDIR1) O=$(OUTPUT) libapikfs.a |
727 | endif | 742 | endif |
728 | 743 | ||
729 | $(LIBLK)-clean: | 744 | $(LIBAPIKFS)-clean: |
730 | ifeq ($(subdir),) | 745 | ifeq ($(subdir),) |
731 | $(call QUIET_CLEAN, liblk) | 746 | $(call QUIET_CLEAN, libapikfs) |
732 | @$(MAKE) -C $(LK_DIR) O=$(OUTPUT) clean >/dev/null | 747 | @$(MAKE) -C $(LIB_DIR) O=$(OUTPUT) clean >/dev/null |
733 | endif | 748 | endif |
734 | 749 | ||
735 | help: | 750 | help: |
@@ -785,7 +800,7 @@ cscope: | |||
785 | 800 | ||
786 | ### Detect prefix changes | 801 | ### Detect prefix changes |
787 | TRACK_CFLAGS = $(subst ','\'',$(CFLAGS)):\ | 802 | TRACK_CFLAGS = $(subst ','\'',$(CFLAGS)):\ |
788 | $(bindir_SQ):$(perfexecdir_SQ):$(template_dir_SQ):$(prefix_SQ) | 803 | $(bindir_SQ):$(perfexecdir_SQ):$(template_dir_SQ):$(prefix_SQ):$(plugindir_SQ) |
789 | 804 | ||
790 | $(OUTPUT)PERF-CFLAGS: .FORCE-PERF-CFLAGS | 805 | $(OUTPUT)PERF-CFLAGS: .FORCE-PERF-CFLAGS |
791 | @FLAGS='$(TRACK_CFLAGS)'; \ | 806 | @FLAGS='$(TRACK_CFLAGS)'; \ |
@@ -840,16 +855,16 @@ ifndef NO_LIBPYTHON | |||
840 | $(INSTALL) scripts/python/*.py -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/python'; \ | 855 | $(INSTALL) scripts/python/*.py -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/python'; \ |
841 | $(INSTALL) scripts/python/bin/* -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/python/bin' | 856 | $(INSTALL) scripts/python/bin/* -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/python/bin' |
842 | endif | 857 | endif |
843 | $(call QUIET_INSTALL, bash_completion-script) \ | 858 | $(call QUIET_INSTALL, perf_completion-script) \ |
844 | $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(sysconfdir_SQ)/bash_completion.d'; \ | 859 | $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(sysconfdir_SQ)/bash_completion.d'; \ |
845 | $(INSTALL) bash_completion '$(DESTDIR_SQ)$(sysconfdir_SQ)/bash_completion.d/perf' | 860 | $(INSTALL) perf-completion.sh '$(DESTDIR_SQ)$(sysconfdir_SQ)/bash_completion.d/perf' |
846 | $(call QUIET_INSTALL, tests) \ | 861 | $(call QUIET_INSTALL, tests) \ |
847 | $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests'; \ | 862 | $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests'; \ |
848 | $(INSTALL) tests/attr.py '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests'; \ | 863 | $(INSTALL) tests/attr.py '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests'; \ |
849 | $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests/attr'; \ | 864 | $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests/attr'; \ |
850 | $(INSTALL) tests/attr/* '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests/attr' | 865 | $(INSTALL) tests/attr/* '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests/attr' |
851 | 866 | ||
852 | install: install-bin try-install-man | 867 | install: install-bin try-install-man install-traceevent-plugins |
853 | 868 | ||
854 | install-python_ext: | 869 | install-python_ext: |
855 | $(PYTHON_WORD) util/setup.py --quiet install --root='/$(DESTDIR_SQ)' | 870 | $(PYTHON_WORD) util/setup.py --quiet install --root='/$(DESTDIR_SQ)' |
@@ -868,12 +883,11 @@ config-clean: | |||
868 | $(call QUIET_CLEAN, config) | 883 | $(call QUIET_CLEAN, config) |
869 | @$(MAKE) -C config/feature-checks clean >/dev/null | 884 | @$(MAKE) -C config/feature-checks clean >/dev/null |
870 | 885 | ||
871 | clean: $(LIBTRACEEVENT)-clean $(LIBLK)-clean config-clean | 886 | clean: $(LIBTRACEEVENT)-clean $(LIBAPIKFS)-clean config-clean |
872 | $(call QUIET_CLEAN, core-objs) $(RM) $(LIB_OBJS) $(BUILTIN_OBJS) $(LIB_FILE) $(OUTPUT)perf-archive $(OUTPUT)perf.o $(LANG_BINDINGS) $(GTK_OBJS) | 887 | $(call QUIET_CLEAN, core-objs) $(RM) $(LIB_OBJS) $(BUILTIN_OBJS) $(LIB_FILE) $(OUTPUT)perf-archive $(OUTPUT)perf.o $(LANG_BINDINGS) $(GTK_OBJS) |
873 | $(call QUIET_CLEAN, core-progs) $(RM) $(ALL_PROGRAMS) perf | 888 | $(call QUIET_CLEAN, core-progs) $(RM) $(ALL_PROGRAMS) perf |
874 | $(call QUIET_CLEAN, core-gen) $(RM) *.spec *.pyc *.pyo */*.pyc */*.pyo $(OUTPUT)common-cmds.h TAGS tags cscope* $(OUTPUT)PERF-VERSION-FILE $(OUTPUT)PERF-CFLAGS $(OUTPUT)util/*-bison* $(OUTPUT)util/*-flex* | 889 | $(call QUIET_CLEAN, core-gen) $(RM) *.spec *.pyc *.pyo */*.pyc */*.pyo $(OUTPUT)common-cmds.h TAGS tags cscope* $(OUTPUT)PERF-VERSION-FILE $(OUTPUT)PERF-CFLAGS $(OUTPUT)util/*-bison* $(OUTPUT)util/*-flex* |
875 | $(call QUIET_CLEAN, Documentation) | 890 | $(QUIET_SUBDIR0)Documentation $(QUIET_SUBDIR1) clean |
876 | @$(MAKE) -C Documentation O=$(OUTPUT) clean >/dev/null | ||
877 | $(python-clean) | 891 | $(python-clean) |
878 | 892 | ||
879 | # | 893 | # |
diff --git a/tools/perf/arch/common.c b/tools/perf/arch/common.c index aacef07ebf31..42faf369211c 100644 --- a/tools/perf/arch/common.c +++ b/tools/perf/arch/common.c | |||
@@ -154,8 +154,7 @@ static int perf_session_env__lookup_binutils_path(struct perf_session_env *env, | |||
154 | } | 154 | } |
155 | if (lookup_path(buf)) | 155 | if (lookup_path(buf)) |
156 | goto out; | 156 | goto out; |
157 | free(buf); | 157 | zfree(&buf); |
158 | buf = NULL; | ||
159 | } | 158 | } |
160 | 159 | ||
161 | if (!strcmp(arch, "arm")) | 160 | if (!strcmp(arch, "arm")) |
diff --git a/tools/perf/bench/numa.c b/tools/perf/bench/numa.c index d4c83c60b9b2..97d86d828190 100644 --- a/tools/perf/bench/numa.c +++ b/tools/perf/bench/numa.c | |||
@@ -1593,6 +1593,7 @@ static void init_params(struct params *p, const char *name, int argc, const char | |||
1593 | p->data_rand_walk = true; | 1593 | p->data_rand_walk = true; |
1594 | p->nr_loops = -1; | 1594 | p->nr_loops = -1; |
1595 | p->init_random = true; | 1595 | p->init_random = true; |
1596 | p->run_all = argc == 1; | ||
1596 | } | 1597 | } |
1597 | 1598 | ||
1598 | static int run_bench_numa(const char *name, const char **argv) | 1599 | static int run_bench_numa(const char *name, const char **argv) |
diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c index 4087ab19823c..0da603b79b61 100644 --- a/tools/perf/builtin-annotate.c +++ b/tools/perf/builtin-annotate.c | |||
@@ -69,15 +69,7 @@ static int perf_evsel__add_sample(struct perf_evsel *evsel, | |||
69 | if (he == NULL) | 69 | if (he == NULL) |
70 | return -ENOMEM; | 70 | return -ENOMEM; |
71 | 71 | ||
72 | ret = 0; | 72 | ret = hist_entry__inc_addr_samples(he, evsel->idx, al->addr); |
73 | if (he->ms.sym != NULL) { | ||
74 | struct annotation *notes = symbol__annotation(he->ms.sym); | ||
75 | if (notes->src == NULL && symbol__alloc_hist(he->ms.sym) < 0) | ||
76 | return -ENOMEM; | ||
77 | |||
78 | ret = hist_entry__inc_addr_samples(he, evsel->idx, al->addr); | ||
79 | } | ||
80 | |||
81 | evsel->hists.stats.total_period += sample->period; | 73 | evsel->hists.stats.total_period += sample->period; |
82 | hists__inc_nr_events(&evsel->hists, PERF_RECORD_SAMPLE); | 74 | hists__inc_nr_events(&evsel->hists, PERF_RECORD_SAMPLE); |
83 | return ret; | 75 | return ret; |
@@ -188,8 +180,7 @@ find_next: | |||
188 | * symbol, free he->ms.sym->src to signal we already | 180 | * symbol, free he->ms.sym->src to signal we already |
189 | * processed this symbol. | 181 | * processed this symbol. |
190 | */ | 182 | */ |
191 | free(notes->src); | 183 | zfree(¬es->src); |
192 | notes->src = NULL; | ||
193 | } | 184 | } |
194 | } | 185 | } |
195 | } | 186 | } |
@@ -241,7 +232,7 @@ static int __cmd_annotate(struct perf_annotate *ann) | |||
241 | perf_session__fprintf_dsos(session, stdout); | 232 | perf_session__fprintf_dsos(session, stdout); |
242 | 233 | ||
243 | total_nr_samples = 0; | 234 | total_nr_samples = 0; |
244 | list_for_each_entry(pos, &session->evlist->entries, node) { | 235 | evlist__for_each(session->evlist, pos) { |
245 | struct hists *hists = &pos->hists; | 236 | struct hists *hists = &pos->hists; |
246 | u32 nr_samples = hists->stats.nr_events[PERF_RECORD_SAMPLE]; | 237 | u32 nr_samples = hists->stats.nr_events[PERF_RECORD_SAMPLE]; |
247 | 238 | ||
@@ -373,7 +364,7 @@ int cmd_annotate(int argc, const char **argv, const char *prefix __maybe_unused) | |||
373 | 364 | ||
374 | if (argc) { | 365 | if (argc) { |
375 | /* | 366 | /* |
376 | * Special case: if there's an argument left then assume tha | 367 | * Special case: if there's an argument left then assume that |
377 | * it's a symbol filter: | 368 | * it's a symbol filter: |
378 | */ | 369 | */ |
379 | if (argc > 1) | 370 | if (argc > 1) |
diff --git a/tools/perf/builtin-bench.c b/tools/perf/builtin-bench.c index e47f90cc7b98..8a987d252780 100644 --- a/tools/perf/builtin-bench.c +++ b/tools/perf/builtin-bench.c | |||
@@ -76,7 +76,7 @@ static struct collection collections[] = { | |||
76 | 76 | ||
77 | /* Iterate over all benchmarks within a collection: */ | 77 | /* Iterate over all benchmarks within a collection: */ |
78 | #define for_each_bench(coll, bench) \ | 78 | #define for_each_bench(coll, bench) \ |
79 | for (bench = coll->benchmarks; bench->name; bench++) | 79 | for (bench = coll->benchmarks; bench && bench->name; bench++) |
80 | 80 | ||
81 | static void dump_benchmarks(struct collection *coll) | 81 | static void dump_benchmarks(struct collection *coll) |
82 | { | 82 | { |
diff --git a/tools/perf/builtin-buildid-cache.c b/tools/perf/builtin-buildid-cache.c index cfede86161d8..b22dbb16f877 100644 --- a/tools/perf/builtin-buildid-cache.c +++ b/tools/perf/builtin-buildid-cache.c | |||
@@ -63,11 +63,35 @@ static int build_id_cache__kcore_dir(char *dir, size_t sz) | |||
63 | return 0; | 63 | return 0; |
64 | } | 64 | } |
65 | 65 | ||
66 | static bool same_kallsyms_reloc(const char *from_dir, char *to_dir) | ||
67 | { | ||
68 | char from[PATH_MAX]; | ||
69 | char to[PATH_MAX]; | ||
70 | const char *name; | ||
71 | u64 addr1 = 0, addr2 = 0; | ||
72 | int i; | ||
73 | |||
74 | scnprintf(from, sizeof(from), "%s/kallsyms", from_dir); | ||
75 | scnprintf(to, sizeof(to), "%s/kallsyms", to_dir); | ||
76 | |||
77 | for (i = 0; (name = ref_reloc_sym_names[i]) != NULL; i++) { | ||
78 | addr1 = kallsyms__get_function_start(from, name); | ||
79 | if (addr1) | ||
80 | break; | ||
81 | } | ||
82 | |||
83 | if (name) | ||
84 | addr2 = kallsyms__get_function_start(to, name); | ||
85 | |||
86 | return addr1 == addr2; | ||
87 | } | ||
88 | |||
66 | static int build_id_cache__kcore_existing(const char *from_dir, char *to_dir, | 89 | static int build_id_cache__kcore_existing(const char *from_dir, char *to_dir, |
67 | size_t to_dir_sz) | 90 | size_t to_dir_sz) |
68 | { | 91 | { |
69 | char from[PATH_MAX]; | 92 | char from[PATH_MAX]; |
70 | char to[PATH_MAX]; | 93 | char to[PATH_MAX]; |
94 | char to_subdir[PATH_MAX]; | ||
71 | struct dirent *dent; | 95 | struct dirent *dent; |
72 | int ret = -1; | 96 | int ret = -1; |
73 | DIR *d; | 97 | DIR *d; |
@@ -86,10 +110,11 @@ static int build_id_cache__kcore_existing(const char *from_dir, char *to_dir, | |||
86 | continue; | 110 | continue; |
87 | scnprintf(to, sizeof(to), "%s/%s/modules", to_dir, | 111 | scnprintf(to, sizeof(to), "%s/%s/modules", to_dir, |
88 | dent->d_name); | 112 | dent->d_name); |
89 | if (!compare_proc_modules(from, to)) { | 113 | scnprintf(to_subdir, sizeof(to_subdir), "%s/%s", |
90 | scnprintf(to, sizeof(to), "%s/%s", to_dir, | 114 | to_dir, dent->d_name); |
91 | dent->d_name); | 115 | if (!compare_proc_modules(from, to) && |
92 | strlcpy(to_dir, to, to_dir_sz); | 116 | same_kallsyms_reloc(from_dir, to_subdir)) { |
117 | strlcpy(to_dir, to_subdir, to_dir_sz); | ||
93 | ret = 0; | 118 | ret = 0; |
94 | break; | 119 | break; |
95 | } | 120 | } |
diff --git a/tools/perf/builtin-diff.c b/tools/perf/builtin-diff.c index 3b67ea2444bd..a77e31246c00 100644 --- a/tools/perf/builtin-diff.c +++ b/tools/perf/builtin-diff.c | |||
@@ -356,9 +356,10 @@ static struct perf_evsel *evsel_match(struct perf_evsel *evsel, | |||
356 | { | 356 | { |
357 | struct perf_evsel *e; | 357 | struct perf_evsel *e; |
358 | 358 | ||
359 | list_for_each_entry(e, &evlist->entries, node) | 359 | evlist__for_each(evlist, e) { |
360 | if (perf_evsel__match2(evsel, e)) | 360 | if (perf_evsel__match2(evsel, e)) |
361 | return e; | 361 | return e; |
362 | } | ||
362 | 363 | ||
363 | return NULL; | 364 | return NULL; |
364 | } | 365 | } |
@@ -367,7 +368,7 @@ static void perf_evlist__collapse_resort(struct perf_evlist *evlist) | |||
367 | { | 368 | { |
368 | struct perf_evsel *evsel; | 369 | struct perf_evsel *evsel; |
369 | 370 | ||
370 | list_for_each_entry(evsel, &evlist->entries, node) { | 371 | evlist__for_each(evlist, evsel) { |
371 | struct hists *hists = &evsel->hists; | 372 | struct hists *hists = &evsel->hists; |
372 | 373 | ||
373 | hists__collapse_resort(hists, NULL); | 374 | hists__collapse_resort(hists, NULL); |
@@ -614,7 +615,7 @@ static void data_process(void) | |||
614 | struct perf_evsel *evsel_base; | 615 | struct perf_evsel *evsel_base; |
615 | bool first = true; | 616 | bool first = true; |
616 | 617 | ||
617 | list_for_each_entry(evsel_base, &evlist_base->entries, node) { | 618 | evlist__for_each(evlist_base, evsel_base) { |
618 | struct data__file *d; | 619 | struct data__file *d; |
619 | int i; | 620 | int i; |
620 | 621 | ||
@@ -654,7 +655,7 @@ static void data__free(struct data__file *d) | |||
654 | for (col = 0; col < PERF_HPP_DIFF__MAX_INDEX; col++) { | 655 | for (col = 0; col < PERF_HPP_DIFF__MAX_INDEX; col++) { |
655 | struct diff_hpp_fmt *fmt = &d->fmt[col]; | 656 | struct diff_hpp_fmt *fmt = &d->fmt[col]; |
656 | 657 | ||
657 | free(fmt->header); | 658 | zfree(&fmt->header); |
658 | } | 659 | } |
659 | } | 660 | } |
660 | 661 | ||
@@ -769,6 +770,81 @@ static int hpp__entry_baseline(struct hist_entry *he, char *buf, size_t size) | |||
769 | return ret; | 770 | return ret; |
770 | } | 771 | } |
771 | 772 | ||
773 | static int __hpp__color_compare(struct perf_hpp_fmt *fmt, | ||
774 | struct perf_hpp *hpp, struct hist_entry *he, | ||
775 | int comparison_method) | ||
776 | { | ||
777 | struct diff_hpp_fmt *dfmt = | ||
778 | container_of(fmt, struct diff_hpp_fmt, fmt); | ||
779 | struct hist_entry *pair = get_pair_fmt(he, dfmt); | ||
780 | double diff; | ||
781 | s64 wdiff; | ||
782 | char pfmt[20] = " "; | ||
783 | |||
784 | if (!pair) | ||
785 | goto dummy_print; | ||
786 | |||
787 | switch (comparison_method) { | ||
788 | case COMPUTE_DELTA: | ||
789 | if (pair->diff.computed) | ||
790 | diff = pair->diff.period_ratio_delta; | ||
791 | else | ||
792 | diff = compute_delta(he, pair); | ||
793 | |||
794 | if (fabs(diff) < 0.01) | ||
795 | goto dummy_print; | ||
796 | scnprintf(pfmt, 20, "%%%+d.2f%%%%", dfmt->header_width - 1); | ||
797 | return percent_color_snprintf(hpp->buf, hpp->size, | ||
798 | pfmt, diff); | ||
799 | case COMPUTE_RATIO: | ||
800 | if (he->dummy) | ||
801 | goto dummy_print; | ||
802 | if (pair->diff.computed) | ||
803 | diff = pair->diff.period_ratio; | ||
804 | else | ||
805 | diff = compute_ratio(he, pair); | ||
806 | |||
807 | scnprintf(pfmt, 20, "%%%d.6f", dfmt->header_width); | ||
808 | return value_color_snprintf(hpp->buf, hpp->size, | ||
809 | pfmt, diff); | ||
810 | case COMPUTE_WEIGHTED_DIFF: | ||
811 | if (he->dummy) | ||
812 | goto dummy_print; | ||
813 | if (pair->diff.computed) | ||
814 | wdiff = pair->diff.wdiff; | ||
815 | else | ||
816 | wdiff = compute_wdiff(he, pair); | ||
817 | |||
818 | scnprintf(pfmt, 20, "%%14ld", dfmt->header_width); | ||
819 | return color_snprintf(hpp->buf, hpp->size, | ||
820 | get_percent_color(wdiff), | ||
821 | pfmt, wdiff); | ||
822 | default: | ||
823 | BUG_ON(1); | ||
824 | } | ||
825 | dummy_print: | ||
826 | return scnprintf(hpp->buf, hpp->size, "%*s", | ||
827 | dfmt->header_width, pfmt); | ||
828 | } | ||
829 | |||
830 | static int hpp__color_delta(struct perf_hpp_fmt *fmt, | ||
831 | struct perf_hpp *hpp, struct hist_entry *he) | ||
832 | { | ||
833 | return __hpp__color_compare(fmt, hpp, he, COMPUTE_DELTA); | ||
834 | } | ||
835 | |||
836 | static int hpp__color_ratio(struct perf_hpp_fmt *fmt, | ||
837 | struct perf_hpp *hpp, struct hist_entry *he) | ||
838 | { | ||
839 | return __hpp__color_compare(fmt, hpp, he, COMPUTE_RATIO); | ||
840 | } | ||
841 | |||
842 | static int hpp__color_wdiff(struct perf_hpp_fmt *fmt, | ||
843 | struct perf_hpp *hpp, struct hist_entry *he) | ||
844 | { | ||
845 | return __hpp__color_compare(fmt, hpp, he, COMPUTE_WEIGHTED_DIFF); | ||
846 | } | ||
847 | |||
772 | static void | 848 | static void |
773 | hpp__entry_unpair(struct hist_entry *he, int idx, char *buf, size_t size) | 849 | hpp__entry_unpair(struct hist_entry *he, int idx, char *buf, size_t size) |
774 | { | 850 | { |
@@ -940,8 +1016,22 @@ static void data__hpp_register(struct data__file *d, int idx) | |||
940 | fmt->entry = hpp__entry_global; | 1016 | fmt->entry = hpp__entry_global; |
941 | 1017 | ||
942 | /* TODO more colors */ | 1018 | /* TODO more colors */ |
943 | if (idx == PERF_HPP_DIFF__BASELINE) | 1019 | switch (idx) { |
1020 | case PERF_HPP_DIFF__BASELINE: | ||
944 | fmt->color = hpp__color_baseline; | 1021 | fmt->color = hpp__color_baseline; |
1022 | break; | ||
1023 | case PERF_HPP_DIFF__DELTA: | ||
1024 | fmt->color = hpp__color_delta; | ||
1025 | break; | ||
1026 | case PERF_HPP_DIFF__RATIO: | ||
1027 | fmt->color = hpp__color_ratio; | ||
1028 | break; | ||
1029 | case PERF_HPP_DIFF__WEIGHTED_DIFF: | ||
1030 | fmt->color = hpp__color_wdiff; | ||
1031 | break; | ||
1032 | default: | ||
1033 | break; | ||
1034 | } | ||
945 | 1035 | ||
946 | init_header(d, dfmt); | 1036 | init_header(d, dfmt); |
947 | perf_hpp__column_register(fmt); | 1037 | perf_hpp__column_register(fmt); |
@@ -1000,8 +1090,7 @@ static int data_init(int argc, const char **argv) | |||
1000 | data__files_cnt = argc; | 1090 | data__files_cnt = argc; |
1001 | use_default = false; | 1091 | use_default = false; |
1002 | } | 1092 | } |
1003 | } else if (symbol_conf.default_guest_vmlinux_name || | 1093 | } else if (perf_guest) { |
1004 | symbol_conf.default_guest_kallsyms) { | ||
1005 | defaults[0] = "perf.data.host"; | 1094 | defaults[0] = "perf.data.host"; |
1006 | defaults[1] = "perf.data.guest"; | 1095 | defaults[1] = "perf.data.guest"; |
1007 | } | 1096 | } |
diff --git a/tools/perf/builtin-evlist.c b/tools/perf/builtin-evlist.c index 20b0f12763b0..c99e0de7e54a 100644 --- a/tools/perf/builtin-evlist.c +++ b/tools/perf/builtin-evlist.c | |||
@@ -29,7 +29,7 @@ static int __cmd_evlist(const char *file_name, struct perf_attr_details *details | |||
29 | if (session == NULL) | 29 | if (session == NULL) |
30 | return -ENOMEM; | 30 | return -ENOMEM; |
31 | 31 | ||
32 | list_for_each_entry(pos, &session->evlist->entries, node) | 32 | evlist__for_each(session->evlist, pos) |
33 | perf_evsel__fprintf(pos, details, stdout); | 33 | perf_evsel__fprintf(pos, details, stdout); |
34 | 34 | ||
35 | perf_session__delete(session); | 35 | perf_session__delete(session); |
diff --git a/tools/perf/builtin-inject.c b/tools/perf/builtin-inject.c index 6a2508589460..b3466018bbd7 100644 --- a/tools/perf/builtin-inject.c +++ b/tools/perf/builtin-inject.c | |||
@@ -22,14 +22,13 @@ | |||
22 | #include <linux/list.h> | 22 | #include <linux/list.h> |
23 | 23 | ||
24 | struct perf_inject { | 24 | struct perf_inject { |
25 | struct perf_tool tool; | 25 | struct perf_tool tool; |
26 | bool build_ids; | 26 | bool build_ids; |
27 | bool sched_stat; | 27 | bool sched_stat; |
28 | const char *input_name; | 28 | const char *input_name; |
29 | int pipe_output, | 29 | struct perf_data_file output; |
30 | output; | 30 | u64 bytes_written; |
31 | u64 bytes_written; | 31 | struct list_head samples; |
32 | struct list_head samples; | ||
33 | }; | 32 | }; |
34 | 33 | ||
35 | struct event_entry { | 34 | struct event_entry { |
@@ -42,21 +41,14 @@ static int perf_event__repipe_synth(struct perf_tool *tool, | |||
42 | union perf_event *event) | 41 | union perf_event *event) |
43 | { | 42 | { |
44 | struct perf_inject *inject = container_of(tool, struct perf_inject, tool); | 43 | struct perf_inject *inject = container_of(tool, struct perf_inject, tool); |
45 | uint32_t size; | 44 | ssize_t size; |
46 | void *buf = event; | ||
47 | 45 | ||
48 | size = event->header.size; | 46 | size = perf_data_file__write(&inject->output, event, |
49 | 47 | event->header.size); | |
50 | while (size) { | 48 | if (size < 0) |
51 | int ret = write(inject->output, buf, size); | 49 | return -errno; |
52 | if (ret < 0) | ||
53 | return -errno; | ||
54 | |||
55 | size -= ret; | ||
56 | buf += ret; | ||
57 | inject->bytes_written += ret; | ||
58 | } | ||
59 | 50 | ||
51 | inject->bytes_written += size; | ||
60 | return 0; | 52 | return 0; |
61 | } | 53 | } |
62 | 54 | ||
@@ -80,7 +72,7 @@ static int perf_event__repipe_attr(struct perf_tool *tool, | |||
80 | if (ret) | 72 | if (ret) |
81 | return ret; | 73 | return ret; |
82 | 74 | ||
83 | if (!inject->pipe_output) | 75 | if (&inject->output.is_pipe) |
84 | return 0; | 76 | return 0; |
85 | 77 | ||
86 | return perf_event__repipe_synth(tool, event); | 78 | return perf_event__repipe_synth(tool, event); |
@@ -355,6 +347,7 @@ static int __cmd_inject(struct perf_inject *inject) | |||
355 | .path = inject->input_name, | 347 | .path = inject->input_name, |
356 | .mode = PERF_DATA_MODE_READ, | 348 | .mode = PERF_DATA_MODE_READ, |
357 | }; | 349 | }; |
350 | struct perf_data_file *file_out = &inject->output; | ||
358 | 351 | ||
359 | signal(SIGINT, sig_handler); | 352 | signal(SIGINT, sig_handler); |
360 | 353 | ||
@@ -376,7 +369,7 @@ static int __cmd_inject(struct perf_inject *inject) | |||
376 | 369 | ||
377 | inject->tool.ordered_samples = true; | 370 | inject->tool.ordered_samples = true; |
378 | 371 | ||
379 | list_for_each_entry(evsel, &session->evlist->entries, node) { | 372 | evlist__for_each(session->evlist, evsel) { |
380 | const char *name = perf_evsel__name(evsel); | 373 | const char *name = perf_evsel__name(evsel); |
381 | 374 | ||
382 | if (!strcmp(name, "sched:sched_switch")) { | 375 | if (!strcmp(name, "sched:sched_switch")) { |
@@ -391,14 +384,14 @@ static int __cmd_inject(struct perf_inject *inject) | |||
391 | } | 384 | } |
392 | } | 385 | } |
393 | 386 | ||
394 | if (!inject->pipe_output) | 387 | if (!file_out->is_pipe) |
395 | lseek(inject->output, session->header.data_offset, SEEK_SET); | 388 | lseek(file_out->fd, session->header.data_offset, SEEK_SET); |
396 | 389 | ||
397 | ret = perf_session__process_events(session, &inject->tool); | 390 | ret = perf_session__process_events(session, &inject->tool); |
398 | 391 | ||
399 | if (!inject->pipe_output) { | 392 | if (!file_out->is_pipe) { |
400 | session->header.data_size = inject->bytes_written; | 393 | session->header.data_size = inject->bytes_written; |
401 | perf_session__write_header(session, session->evlist, inject->output, true); | 394 | perf_session__write_header(session, session->evlist, file_out->fd, true); |
402 | } | 395 | } |
403 | 396 | ||
404 | perf_session__delete(session); | 397 | perf_session__delete(session); |
@@ -427,14 +420,17 @@ int cmd_inject(int argc, const char **argv, const char *prefix __maybe_unused) | |||
427 | }, | 420 | }, |
428 | .input_name = "-", | 421 | .input_name = "-", |
429 | .samples = LIST_HEAD_INIT(inject.samples), | 422 | .samples = LIST_HEAD_INIT(inject.samples), |
423 | .output = { | ||
424 | .path = "-", | ||
425 | .mode = PERF_DATA_MODE_WRITE, | ||
426 | }, | ||
430 | }; | 427 | }; |
431 | const char *output_name = "-"; | ||
432 | const struct option options[] = { | 428 | const struct option options[] = { |
433 | OPT_BOOLEAN('b', "build-ids", &inject.build_ids, | 429 | OPT_BOOLEAN('b', "build-ids", &inject.build_ids, |
434 | "Inject build-ids into the output stream"), | 430 | "Inject build-ids into the output stream"), |
435 | OPT_STRING('i', "input", &inject.input_name, "file", | 431 | OPT_STRING('i', "input", &inject.input_name, "file", |
436 | "input file name"), | 432 | "input file name"), |
437 | OPT_STRING('o', "output", &output_name, "file", | 433 | OPT_STRING('o', "output", &inject.output.path, "file", |
438 | "output file name"), | 434 | "output file name"), |
439 | OPT_BOOLEAN('s', "sched-stat", &inject.sched_stat, | 435 | OPT_BOOLEAN('s', "sched-stat", &inject.sched_stat, |
440 | "Merge sched-stat and sched-switch for getting events " | 436 | "Merge sched-stat and sched-switch for getting events " |
@@ -456,16 +452,9 @@ int cmd_inject(int argc, const char **argv, const char *prefix __maybe_unused) | |||
456 | if (argc) | 452 | if (argc) |
457 | usage_with_options(inject_usage, options); | 453 | usage_with_options(inject_usage, options); |
458 | 454 | ||
459 | if (!strcmp(output_name, "-")) { | 455 | if (perf_data_file__open(&inject.output)) { |
460 | inject.pipe_output = 1; | 456 | perror("failed to create output file"); |
461 | inject.output = STDOUT_FILENO; | 457 | return -1; |
462 | } else { | ||
463 | inject.output = open(output_name, O_CREAT | O_WRONLY | O_TRUNC, | ||
464 | S_IRUSR | S_IWUSR); | ||
465 | if (inject.output < 0) { | ||
466 | perror("failed to create output file"); | ||
467 | return -1; | ||
468 | } | ||
469 | } | 458 | } |
470 | 459 | ||
471 | if (symbol__init() < 0) | 460 | if (symbol__init() < 0) |
diff --git a/tools/perf/builtin-kvm.c b/tools/perf/builtin-kvm.c index f8bf5f244d77..a7350519c63f 100644 --- a/tools/perf/builtin-kvm.c +++ b/tools/perf/builtin-kvm.c | |||
@@ -13,7 +13,7 @@ | |||
13 | #include "util/parse-options.h" | 13 | #include "util/parse-options.h" |
14 | #include "util/trace-event.h" | 14 | #include "util/trace-event.h" |
15 | #include "util/debug.h" | 15 | #include "util/debug.h" |
16 | #include <lk/debugfs.h> | 16 | #include <api/fs/debugfs.h> |
17 | #include "util/tool.h" | 17 | #include "util/tool.h" |
18 | #include "util/stat.h" | 18 | #include "util/stat.h" |
19 | #include "util/top.h" | 19 | #include "util/top.h" |
@@ -89,7 +89,7 @@ struct exit_reasons_table { | |||
89 | 89 | ||
90 | struct perf_kvm_stat { | 90 | struct perf_kvm_stat { |
91 | struct perf_tool tool; | 91 | struct perf_tool tool; |
92 | struct perf_record_opts opts; | 92 | struct record_opts opts; |
93 | struct perf_evlist *evlist; | 93 | struct perf_evlist *evlist; |
94 | struct perf_session *session; | 94 | struct perf_session *session; |
95 | 95 | ||
@@ -1158,9 +1158,7 @@ out: | |||
1158 | if (kvm->timerfd >= 0) | 1158 | if (kvm->timerfd >= 0) |
1159 | close(kvm->timerfd); | 1159 | close(kvm->timerfd); |
1160 | 1160 | ||
1161 | if (pollfds) | 1161 | free(pollfds); |
1162 | free(pollfds); | ||
1163 | |||
1164 | return err; | 1162 | return err; |
1165 | } | 1163 | } |
1166 | 1164 | ||
@@ -1176,7 +1174,7 @@ static int kvm_live_open_events(struct perf_kvm_stat *kvm) | |||
1176 | * Note: exclude_{guest,host} do not apply here. | 1174 | * Note: exclude_{guest,host} do not apply here. |
1177 | * This command processes KVM tracepoints from host only | 1175 | * This command processes KVM tracepoints from host only |
1178 | */ | 1176 | */ |
1179 | list_for_each_entry(pos, &evlist->entries, node) { | 1177 | evlist__for_each(evlist, pos) { |
1180 | struct perf_event_attr *attr = &pos->attr; | 1178 | struct perf_event_attr *attr = &pos->attr; |
1181 | 1179 | ||
1182 | /* make sure these *are* set */ | 1180 | /* make sure these *are* set */ |
@@ -1232,7 +1230,7 @@ static int read_events(struct perf_kvm_stat *kvm) | |||
1232 | .ordered_samples = true, | 1230 | .ordered_samples = true, |
1233 | }; | 1231 | }; |
1234 | struct perf_data_file file = { | 1232 | struct perf_data_file file = { |
1235 | .path = input_name, | 1233 | .path = kvm->file_name, |
1236 | .mode = PERF_DATA_MODE_READ, | 1234 | .mode = PERF_DATA_MODE_READ, |
1237 | }; | 1235 | }; |
1238 | 1236 | ||
@@ -1558,10 +1556,8 @@ out: | |||
1558 | if (kvm->session) | 1556 | if (kvm->session) |
1559 | perf_session__delete(kvm->session); | 1557 | perf_session__delete(kvm->session); |
1560 | kvm->session = NULL; | 1558 | kvm->session = NULL; |
1561 | if (kvm->evlist) { | 1559 | if (kvm->evlist) |
1562 | perf_evlist__delete_maps(kvm->evlist); | ||
1563 | perf_evlist__delete(kvm->evlist); | 1560 | perf_evlist__delete(kvm->evlist); |
1564 | } | ||
1565 | 1561 | ||
1566 | return err; | 1562 | return err; |
1567 | } | 1563 | } |
@@ -1690,6 +1686,8 @@ int cmd_kvm(int argc, const char **argv, const char *prefix __maybe_unused) | |||
1690 | "file", "file saving guest os /proc/kallsyms"), | 1686 | "file", "file saving guest os /proc/kallsyms"), |
1691 | OPT_STRING(0, "guestmodules", &symbol_conf.default_guest_modules, | 1687 | OPT_STRING(0, "guestmodules", &symbol_conf.default_guest_modules, |
1692 | "file", "file saving guest os /proc/modules"), | 1688 | "file", "file saving guest os /proc/modules"), |
1689 | OPT_INCR('v', "verbose", &verbose, | ||
1690 | "be more verbose (show counter open errors, etc)"), | ||
1693 | OPT_END() | 1691 | OPT_END() |
1694 | }; | 1692 | }; |
1695 | 1693 | ||
@@ -1711,12 +1709,7 @@ int cmd_kvm(int argc, const char **argv, const char *prefix __maybe_unused) | |||
1711 | perf_guest = 1; | 1709 | perf_guest = 1; |
1712 | 1710 | ||
1713 | if (!file_name) { | 1711 | if (!file_name) { |
1714 | if (perf_host && !perf_guest) | 1712 | file_name = get_filename_for_perf_kvm(); |
1715 | file_name = strdup("perf.data.host"); | ||
1716 | else if (!perf_host && perf_guest) | ||
1717 | file_name = strdup("perf.data.guest"); | ||
1718 | else | ||
1719 | file_name = strdup("perf.data.kvm"); | ||
1720 | 1713 | ||
1721 | if (!file_name) { | 1714 | if (!file_name) { |
1722 | pr_err("Failed to allocate memory for filename\n"); | 1715 | pr_err("Failed to allocate memory for filename\n"); |
diff --git a/tools/perf/builtin-mem.c b/tools/perf/builtin-mem.c index 31c00f186da1..2e3ade69a58e 100644 --- a/tools/perf/builtin-mem.c +++ b/tools/perf/builtin-mem.c | |||
@@ -62,7 +62,6 @@ static int | |||
62 | dump_raw_samples(struct perf_tool *tool, | 62 | dump_raw_samples(struct perf_tool *tool, |
63 | union perf_event *event, | 63 | union perf_event *event, |
64 | struct perf_sample *sample, | 64 | struct perf_sample *sample, |
65 | struct perf_evsel *evsel __maybe_unused, | ||
66 | struct machine *machine) | 65 | struct machine *machine) |
67 | { | 66 | { |
68 | struct perf_mem *mem = container_of(tool, struct perf_mem, tool); | 67 | struct perf_mem *mem = container_of(tool, struct perf_mem, tool); |
@@ -112,10 +111,10 @@ dump_raw_samples(struct perf_tool *tool, | |||
112 | static int process_sample_event(struct perf_tool *tool, | 111 | static int process_sample_event(struct perf_tool *tool, |
113 | union perf_event *event, | 112 | union perf_event *event, |
114 | struct perf_sample *sample, | 113 | struct perf_sample *sample, |
115 | struct perf_evsel *evsel, | 114 | struct perf_evsel *evsel __maybe_unused, |
116 | struct machine *machine) | 115 | struct machine *machine) |
117 | { | 116 | { |
118 | return dump_raw_samples(tool, event, sample, evsel, machine); | 117 | return dump_raw_samples(tool, event, sample, machine); |
119 | } | 118 | } |
120 | 119 | ||
121 | static int report_raw_events(struct perf_mem *mem) | 120 | static int report_raw_events(struct perf_mem *mem) |
diff --git a/tools/perf/builtin-probe.c b/tools/perf/builtin-probe.c index 6ea9e85bdc00..78948882e3de 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 <lk/debugfs.h> | 40 | #include <api/fs/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" |
@@ -59,7 +59,7 @@ static struct { | |||
59 | struct perf_probe_event events[MAX_PROBES]; | 59 | struct perf_probe_event events[MAX_PROBES]; |
60 | struct strlist *dellist; | 60 | struct strlist *dellist; |
61 | struct line_range line_range; | 61 | struct line_range line_range; |
62 | const char *target; | 62 | char *target; |
63 | int max_probe_points; | 63 | int max_probe_points; |
64 | struct strfilter *filter; | 64 | struct strfilter *filter; |
65 | } params; | 65 | } params; |
@@ -98,7 +98,10 @@ static int set_target(const char *ptr) | |||
98 | * short module name. | 98 | * short module name. |
99 | */ | 99 | */ |
100 | if (!params.target && ptr && *ptr == '/') { | 100 | if (!params.target && ptr && *ptr == '/') { |
101 | params.target = ptr; | 101 | params.target = strdup(ptr); |
102 | if (!params.target) | ||
103 | return -ENOMEM; | ||
104 | |||
102 | found = 1; | 105 | found = 1; |
103 | buf = ptr + (strlen(ptr) - 3); | 106 | buf = ptr + (strlen(ptr) - 3); |
104 | 107 | ||
@@ -116,6 +119,9 @@ static int parse_probe_event_argv(int argc, const char **argv) | |||
116 | char *buf; | 119 | char *buf; |
117 | 120 | ||
118 | found_target = set_target(argv[0]); | 121 | found_target = set_target(argv[0]); |
122 | if (found_target < 0) | ||
123 | return found_target; | ||
124 | |||
119 | if (found_target && argc == 1) | 125 | if (found_target && argc == 1) |
120 | return 0; | 126 | return 0; |
121 | 127 | ||
@@ -169,6 +175,7 @@ static int opt_set_target(const struct option *opt, const char *str, | |||
169 | int unset __maybe_unused) | 175 | int unset __maybe_unused) |
170 | { | 176 | { |
171 | int ret = -ENOENT; | 177 | int ret = -ENOENT; |
178 | char *tmp; | ||
172 | 179 | ||
173 | if (str && !params.target) { | 180 | if (str && !params.target) { |
174 | if (!strcmp(opt->long_name, "exec")) | 181 | if (!strcmp(opt->long_name, "exec")) |
@@ -180,7 +187,19 @@ static int opt_set_target(const struct option *opt, const char *str, | |||
180 | else | 187 | else |
181 | return ret; | 188 | return ret; |
182 | 189 | ||
183 | params.target = str; | 190 | /* Expand given path to absolute path, except for modulename */ |
191 | if (params.uprobes || strchr(str, '/')) { | ||
192 | tmp = realpath(str, NULL); | ||
193 | if (!tmp) { | ||
194 | pr_warning("Failed to get the absolute path of %s: %m\n", str); | ||
195 | return ret; | ||
196 | } | ||
197 | } else { | ||
198 | tmp = strdup(str); | ||
199 | if (!tmp) | ||
200 | return -ENOMEM; | ||
201 | } | ||
202 | params.target = tmp; | ||
184 | ret = 0; | 203 | ret = 0; |
185 | } | 204 | } |
186 | 205 | ||
@@ -204,7 +223,6 @@ static int opt_show_lines(const struct option *opt __maybe_unused, | |||
204 | 223 | ||
205 | params.show_lines = true; | 224 | params.show_lines = true; |
206 | ret = parse_line_range_desc(str, ¶ms.line_range); | 225 | ret = parse_line_range_desc(str, ¶ms.line_range); |
207 | INIT_LIST_HEAD(¶ms.line_range.line_list); | ||
208 | 226 | ||
209 | return ret; | 227 | return ret; |
210 | } | 228 | } |
@@ -250,7 +268,28 @@ static int opt_set_filter(const struct option *opt __maybe_unused, | |||
250 | return 0; | 268 | return 0; |
251 | } | 269 | } |
252 | 270 | ||
253 | int cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused) | 271 | static void init_params(void) |
272 | { | ||
273 | line_range__init(¶ms.line_range); | ||
274 | } | ||
275 | |||
276 | static void cleanup_params(void) | ||
277 | { | ||
278 | int i; | ||
279 | |||
280 | for (i = 0; i < params.nevents; i++) | ||
281 | clear_perf_probe_event(params.events + i); | ||
282 | if (params.dellist) | ||
283 | strlist__delete(params.dellist); | ||
284 | line_range__clear(¶ms.line_range); | ||
285 | free(params.target); | ||
286 | if (params.filter) | ||
287 | strfilter__delete(params.filter); | ||
288 | memset(¶ms, 0, sizeof(params)); | ||
289 | } | ||
290 | |||
291 | static int | ||
292 | __cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused) | ||
254 | { | 293 | { |
255 | const char * const probe_usage[] = { | 294 | const char * const probe_usage[] = { |
256 | "perf probe [<options>] 'PROBEDEF' ['PROBEDEF' ...]", | 295 | "perf probe [<options>] 'PROBEDEF' ['PROBEDEF' ...]", |
@@ -404,6 +443,7 @@ int cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused) | |||
404 | ret = show_available_funcs(params.target, params.filter, | 443 | ret = show_available_funcs(params.target, params.filter, |
405 | params.uprobes); | 444 | params.uprobes); |
406 | strfilter__delete(params.filter); | 445 | strfilter__delete(params.filter); |
446 | params.filter = NULL; | ||
407 | if (ret < 0) | 447 | if (ret < 0) |
408 | pr_err(" Error: Failed to show functions." | 448 | pr_err(" Error: Failed to show functions." |
409 | " (%d)\n", ret); | 449 | " (%d)\n", ret); |
@@ -411,7 +451,7 @@ int cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused) | |||
411 | } | 451 | } |
412 | 452 | ||
413 | #ifdef HAVE_DWARF_SUPPORT | 453 | #ifdef HAVE_DWARF_SUPPORT |
414 | if (params.show_lines && !params.uprobes) { | 454 | if (params.show_lines) { |
415 | if (params.mod_events) { | 455 | if (params.mod_events) { |
416 | pr_err(" Error: Don't use --line with" | 456 | pr_err(" Error: Don't use --line with" |
417 | " --add/--del.\n"); | 457 | " --add/--del.\n"); |
@@ -443,6 +483,7 @@ int cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused) | |||
443 | params.filter, | 483 | params.filter, |
444 | params.show_ext_vars); | 484 | params.show_ext_vars); |
445 | strfilter__delete(params.filter); | 485 | strfilter__delete(params.filter); |
486 | params.filter = NULL; | ||
446 | if (ret < 0) | 487 | if (ret < 0) |
447 | pr_err(" Error: Failed to show vars. (%d)\n", ret); | 488 | pr_err(" Error: Failed to show vars. (%d)\n", ret); |
448 | return ret; | 489 | return ret; |
@@ -451,7 +492,6 @@ int cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused) | |||
451 | 492 | ||
452 | if (params.dellist) { | 493 | if (params.dellist) { |
453 | ret = del_perf_probe_events(params.dellist); | 494 | ret = del_perf_probe_events(params.dellist); |
454 | strlist__delete(params.dellist); | ||
455 | if (ret < 0) { | 495 | if (ret < 0) { |
456 | pr_err(" Error: Failed to delete events. (%d)\n", ret); | 496 | pr_err(" Error: Failed to delete events. (%d)\n", ret); |
457 | return ret; | 497 | return ret; |
@@ -470,3 +510,14 @@ int cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused) | |||
470 | } | 510 | } |
471 | return 0; | 511 | return 0; |
472 | } | 512 | } |
513 | |||
514 | int cmd_probe(int argc, const char **argv, const char *prefix) | ||
515 | { | ||
516 | int ret; | ||
517 | |||
518 | init_params(); | ||
519 | ret = __cmd_probe(argc, argv, prefix); | ||
520 | cleanup_params(); | ||
521 | |||
522 | return ret; | ||
523 | } | ||
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index 7c8020a32784..af47531b82ec 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c | |||
@@ -62,9 +62,9 @@ static void __handle_on_exit_funcs(void) | |||
62 | } | 62 | } |
63 | #endif | 63 | #endif |
64 | 64 | ||
65 | struct perf_record { | 65 | struct record { |
66 | struct perf_tool tool; | 66 | struct perf_tool tool; |
67 | struct perf_record_opts opts; | 67 | struct record_opts opts; |
68 | u64 bytes_written; | 68 | u64 bytes_written; |
69 | struct perf_data_file file; | 69 | struct perf_data_file file; |
70 | struct perf_evlist *evlist; | 70 | struct perf_evlist *evlist; |
@@ -76,46 +76,27 @@ struct perf_record { | |||
76 | long samples; | 76 | long samples; |
77 | }; | 77 | }; |
78 | 78 | ||
79 | static int do_write_output(struct perf_record *rec, void *buf, size_t size) | 79 | static int record__write(struct record *rec, void *bf, size_t size) |
80 | { | 80 | { |
81 | struct perf_data_file *file = &rec->file; | 81 | if (perf_data_file__write(rec->session->file, bf, size) < 0) { |
82 | 82 | pr_err("failed to write perf data, error: %m\n"); | |
83 | while (size) { | 83 | return -1; |
84 | ssize_t ret = write(file->fd, buf, size); | ||
85 | |||
86 | if (ret < 0) { | ||
87 | pr_err("failed to write perf data, error: %m\n"); | ||
88 | return -1; | ||
89 | } | ||
90 | |||
91 | size -= ret; | ||
92 | buf += ret; | ||
93 | |||
94 | rec->bytes_written += ret; | ||
95 | } | 84 | } |
96 | 85 | ||
86 | rec->bytes_written += size; | ||
97 | return 0; | 87 | return 0; |
98 | } | 88 | } |
99 | 89 | ||
100 | static int write_output(struct perf_record *rec, void *buf, size_t size) | ||
101 | { | ||
102 | return do_write_output(rec, buf, size); | ||
103 | } | ||
104 | |||
105 | static int process_synthesized_event(struct perf_tool *tool, | 90 | static int process_synthesized_event(struct perf_tool *tool, |
106 | union perf_event *event, | 91 | union perf_event *event, |
107 | struct perf_sample *sample __maybe_unused, | 92 | struct perf_sample *sample __maybe_unused, |
108 | struct machine *machine __maybe_unused) | 93 | struct machine *machine __maybe_unused) |
109 | { | 94 | { |
110 | struct perf_record *rec = container_of(tool, struct perf_record, tool); | 95 | struct record *rec = container_of(tool, struct record, tool); |
111 | if (write_output(rec, event, event->header.size) < 0) | 96 | return record__write(rec, event, event->header.size); |
112 | return -1; | ||
113 | |||
114 | return 0; | ||
115 | } | 97 | } |
116 | 98 | ||
117 | static int perf_record__mmap_read(struct perf_record *rec, | 99 | static int record__mmap_read(struct record *rec, struct perf_mmap *md) |
118 | struct perf_mmap *md) | ||
119 | { | 100 | { |
120 | unsigned int head = perf_mmap__read_head(md); | 101 | unsigned int head = perf_mmap__read_head(md); |
121 | unsigned int old = md->prev; | 102 | unsigned int old = md->prev; |
@@ -136,7 +117,7 @@ static int perf_record__mmap_read(struct perf_record *rec, | |||
136 | size = md->mask + 1 - (old & md->mask); | 117 | size = md->mask + 1 - (old & md->mask); |
137 | old += size; | 118 | old += size; |
138 | 119 | ||
139 | if (write_output(rec, buf, size) < 0) { | 120 | if (record__write(rec, buf, size) < 0) { |
140 | rc = -1; | 121 | rc = -1; |
141 | goto out; | 122 | goto out; |
142 | } | 123 | } |
@@ -146,7 +127,7 @@ static int perf_record__mmap_read(struct perf_record *rec, | |||
146 | size = head - old; | 127 | size = head - old; |
147 | old += size; | 128 | old += size; |
148 | 129 | ||
149 | if (write_output(rec, buf, size) < 0) { | 130 | if (record__write(rec, buf, size) < 0) { |
150 | rc = -1; | 131 | rc = -1; |
151 | goto out; | 132 | goto out; |
152 | } | 133 | } |
@@ -171,9 +152,9 @@ static void sig_handler(int sig) | |||
171 | signr = sig; | 152 | signr = sig; |
172 | } | 153 | } |
173 | 154 | ||
174 | static void perf_record__sig_exit(int exit_status __maybe_unused, void *arg) | 155 | static void record__sig_exit(int exit_status __maybe_unused, void *arg) |
175 | { | 156 | { |
176 | struct perf_record *rec = arg; | 157 | struct record *rec = arg; |
177 | int status; | 158 | int status; |
178 | 159 | ||
179 | if (rec->evlist->workload.pid > 0) { | 160 | if (rec->evlist->workload.pid > 0) { |
@@ -191,18 +172,18 @@ static void perf_record__sig_exit(int exit_status __maybe_unused, void *arg) | |||
191 | signal(signr, SIG_DFL); | 172 | signal(signr, SIG_DFL); |
192 | } | 173 | } |
193 | 174 | ||
194 | static int perf_record__open(struct perf_record *rec) | 175 | static int record__open(struct record *rec) |
195 | { | 176 | { |
196 | char msg[512]; | 177 | char msg[512]; |
197 | struct perf_evsel *pos; | 178 | struct perf_evsel *pos; |
198 | struct perf_evlist *evlist = rec->evlist; | 179 | struct perf_evlist *evlist = rec->evlist; |
199 | struct perf_session *session = rec->session; | 180 | struct perf_session *session = rec->session; |
200 | struct perf_record_opts *opts = &rec->opts; | 181 | struct record_opts *opts = &rec->opts; |
201 | int rc = 0; | 182 | int rc = 0; |
202 | 183 | ||
203 | perf_evlist__config(evlist, opts); | 184 | perf_evlist__config(evlist, opts); |
204 | 185 | ||
205 | list_for_each_entry(pos, &evlist->entries, node) { | 186 | evlist__for_each(evlist, pos) { |
206 | try_again: | 187 | try_again: |
207 | if (perf_evsel__open(pos, evlist->cpus, evlist->threads) < 0) { | 188 | if (perf_evsel__open(pos, evlist->cpus, evlist->threads) < 0) { |
208 | if (perf_evsel__fallback(pos, errno, msg, sizeof(msg))) { | 189 | if (perf_evsel__fallback(pos, errno, msg, sizeof(msg))) { |
@@ -232,7 +213,7 @@ try_again: | |||
232 | "Consider increasing " | 213 | "Consider increasing " |
233 | "/proc/sys/kernel/perf_event_mlock_kb,\n" | 214 | "/proc/sys/kernel/perf_event_mlock_kb,\n" |
234 | "or try again with a smaller value of -m/--mmap_pages.\n" | 215 | "or try again with a smaller value of -m/--mmap_pages.\n" |
235 | "(current value: %d)\n", opts->mmap_pages); | 216 | "(current value: %u)\n", opts->mmap_pages); |
236 | rc = -errno; | 217 | rc = -errno; |
237 | } else { | 218 | } else { |
238 | pr_err("failed to mmap with %d (%s)\n", errno, strerror(errno)); | 219 | pr_err("failed to mmap with %d (%s)\n", errno, strerror(errno)); |
@@ -247,7 +228,7 @@ out: | |||
247 | return rc; | 228 | return rc; |
248 | } | 229 | } |
249 | 230 | ||
250 | static int process_buildids(struct perf_record *rec) | 231 | static int process_buildids(struct record *rec) |
251 | { | 232 | { |
252 | struct perf_data_file *file = &rec->file; | 233 | struct perf_data_file *file = &rec->file; |
253 | struct perf_session *session = rec->session; | 234 | struct perf_session *session = rec->session; |
@@ -262,9 +243,9 @@ static int process_buildids(struct perf_record *rec) | |||
262 | size, &build_id__mark_dso_hit_ops); | 243 | size, &build_id__mark_dso_hit_ops); |
263 | } | 244 | } |
264 | 245 | ||
265 | static void perf_record__exit(int status, void *arg) | 246 | static void record__exit(int status, void *arg) |
266 | { | 247 | { |
267 | struct perf_record *rec = arg; | 248 | struct record *rec = arg; |
268 | struct perf_data_file *file = &rec->file; | 249 | struct perf_data_file *file = &rec->file; |
269 | 250 | ||
270 | if (status != 0) | 251 | if (status != 0) |
@@ -306,10 +287,7 @@ static void perf_event__synthesize_guest_os(struct machine *machine, void *data) | |||
306 | * have no _text sometimes. | 287 | * have no _text sometimes. |
307 | */ | 288 | */ |
308 | err = perf_event__synthesize_kernel_mmap(tool, process_synthesized_event, | 289 | err = perf_event__synthesize_kernel_mmap(tool, process_synthesized_event, |
309 | machine, "_text"); | 290 | machine); |
310 | if (err < 0) | ||
311 | err = perf_event__synthesize_kernel_mmap(tool, process_synthesized_event, | ||
312 | machine, "_stext"); | ||
313 | if (err < 0) | 291 | if (err < 0) |
314 | pr_err("Couldn't record guest kernel [%d]'s reference" | 292 | pr_err("Couldn't record guest kernel [%d]'s reference" |
315 | " relocation symbol.\n", machine->pid); | 293 | " relocation symbol.\n", machine->pid); |
@@ -320,14 +298,14 @@ static struct perf_event_header finished_round_event = { | |||
320 | .type = PERF_RECORD_FINISHED_ROUND, | 298 | .type = PERF_RECORD_FINISHED_ROUND, |
321 | }; | 299 | }; |
322 | 300 | ||
323 | static int perf_record__mmap_read_all(struct perf_record *rec) | 301 | static int record__mmap_read_all(struct record *rec) |
324 | { | 302 | { |
325 | int i; | 303 | int i; |
326 | int rc = 0; | 304 | int rc = 0; |
327 | 305 | ||
328 | for (i = 0; i < rec->evlist->nr_mmaps; i++) { | 306 | for (i = 0; i < rec->evlist->nr_mmaps; i++) { |
329 | if (rec->evlist->mmap[i].base) { | 307 | if (rec->evlist->mmap[i].base) { |
330 | if (perf_record__mmap_read(rec, &rec->evlist->mmap[i]) != 0) { | 308 | if (record__mmap_read(rec, &rec->evlist->mmap[i]) != 0) { |
331 | rc = -1; | 309 | rc = -1; |
332 | goto out; | 310 | goto out; |
333 | } | 311 | } |
@@ -335,16 +313,14 @@ static int perf_record__mmap_read_all(struct perf_record *rec) | |||
335 | } | 313 | } |
336 | 314 | ||
337 | if (perf_header__has_feat(&rec->session->header, HEADER_TRACING_DATA)) | 315 | if (perf_header__has_feat(&rec->session->header, HEADER_TRACING_DATA)) |
338 | rc = write_output(rec, &finished_round_event, | 316 | rc = record__write(rec, &finished_round_event, sizeof(finished_round_event)); |
339 | sizeof(finished_round_event)); | ||
340 | 317 | ||
341 | out: | 318 | out: |
342 | return rc; | 319 | return rc; |
343 | } | 320 | } |
344 | 321 | ||
345 | static void perf_record__init_features(struct perf_record *rec) | 322 | static void record__init_features(struct record *rec) |
346 | { | 323 | { |
347 | struct perf_evlist *evsel_list = rec->evlist; | ||
348 | struct perf_session *session = rec->session; | 324 | struct perf_session *session = rec->session; |
349 | int feat; | 325 | int feat; |
350 | 326 | ||
@@ -354,32 +330,46 @@ static void perf_record__init_features(struct perf_record *rec) | |||
354 | if (rec->no_buildid) | 330 | if (rec->no_buildid) |
355 | perf_header__clear_feat(&session->header, HEADER_BUILD_ID); | 331 | perf_header__clear_feat(&session->header, HEADER_BUILD_ID); |
356 | 332 | ||
357 | if (!have_tracepoints(&evsel_list->entries)) | 333 | if (!have_tracepoints(&rec->evlist->entries)) |
358 | perf_header__clear_feat(&session->header, HEADER_TRACING_DATA); | 334 | perf_header__clear_feat(&session->header, HEADER_TRACING_DATA); |
359 | 335 | ||
360 | if (!rec->opts.branch_stack) | 336 | if (!rec->opts.branch_stack) |
361 | perf_header__clear_feat(&session->header, HEADER_BRANCH_STACK); | 337 | perf_header__clear_feat(&session->header, HEADER_BRANCH_STACK); |
362 | } | 338 | } |
363 | 339 | ||
364 | static int __cmd_record(struct perf_record *rec, int argc, const char **argv) | 340 | static volatile int workload_exec_errno; |
341 | |||
342 | /* | ||
343 | * perf_evlist__prepare_workload will send a SIGUSR1 | ||
344 | * if the fork fails, since we asked by setting its | ||
345 | * want_signal to true. | ||
346 | */ | ||
347 | static void workload_exec_failed_signal(int signo, siginfo_t *info, | ||
348 | void *ucontext __maybe_unused) | ||
349 | { | ||
350 | workload_exec_errno = info->si_value.sival_int; | ||
351 | done = 1; | ||
352 | signr = signo; | ||
353 | child_finished = 1; | ||
354 | } | ||
355 | |||
356 | static int __cmd_record(struct record *rec, int argc, const char **argv) | ||
365 | { | 357 | { |
366 | int err; | 358 | int err; |
367 | unsigned long waking = 0; | 359 | unsigned long waking = 0; |
368 | const bool forks = argc > 0; | 360 | const bool forks = argc > 0; |
369 | struct machine *machine; | 361 | struct machine *machine; |
370 | struct perf_tool *tool = &rec->tool; | 362 | struct perf_tool *tool = &rec->tool; |
371 | struct perf_record_opts *opts = &rec->opts; | 363 | struct record_opts *opts = &rec->opts; |
372 | struct perf_evlist *evsel_list = rec->evlist; | ||
373 | struct perf_data_file *file = &rec->file; | 364 | struct perf_data_file *file = &rec->file; |
374 | struct perf_session *session; | 365 | struct perf_session *session; |
375 | bool disabled = false; | 366 | bool disabled = false; |
376 | 367 | ||
377 | rec->progname = argv[0]; | 368 | rec->progname = argv[0]; |
378 | 369 | ||
379 | on_exit(perf_record__sig_exit, rec); | 370 | on_exit(record__sig_exit, rec); |
380 | signal(SIGCHLD, sig_handler); | 371 | signal(SIGCHLD, sig_handler); |
381 | signal(SIGINT, sig_handler); | 372 | signal(SIGINT, sig_handler); |
382 | signal(SIGUSR1, sig_handler); | ||
383 | signal(SIGTERM, sig_handler); | 373 | signal(SIGTERM, sig_handler); |
384 | 374 | ||
385 | session = perf_session__new(file, false, NULL); | 375 | session = perf_session__new(file, false, NULL); |
@@ -390,37 +380,37 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv) | |||
390 | 380 | ||
391 | rec->session = session; | 381 | rec->session = session; |
392 | 382 | ||
393 | perf_record__init_features(rec); | 383 | record__init_features(rec); |
394 | 384 | ||
395 | if (forks) { | 385 | if (forks) { |
396 | err = perf_evlist__prepare_workload(evsel_list, &opts->target, | 386 | err = perf_evlist__prepare_workload(rec->evlist, &opts->target, |
397 | argv, file->is_pipe, | 387 | argv, file->is_pipe, |
398 | true); | 388 | workload_exec_failed_signal); |
399 | if (err < 0) { | 389 | if (err < 0) { |
400 | pr_err("Couldn't run the workload!\n"); | 390 | pr_err("Couldn't run the workload!\n"); |
401 | goto out_delete_session; | 391 | goto out_delete_session; |
402 | } | 392 | } |
403 | } | 393 | } |
404 | 394 | ||
405 | if (perf_record__open(rec) != 0) { | 395 | if (record__open(rec) != 0) { |
406 | err = -1; | 396 | err = -1; |
407 | goto out_delete_session; | 397 | goto out_delete_session; |
408 | } | 398 | } |
409 | 399 | ||
410 | if (!evsel_list->nr_groups) | 400 | if (!rec->evlist->nr_groups) |
411 | perf_header__clear_feat(&session->header, HEADER_GROUP_DESC); | 401 | perf_header__clear_feat(&session->header, HEADER_GROUP_DESC); |
412 | 402 | ||
413 | /* | 403 | /* |
414 | * perf_session__delete(session) will be called at perf_record__exit() | 404 | * perf_session__delete(session) will be called at record__exit() |
415 | */ | 405 | */ |
416 | on_exit(perf_record__exit, rec); | 406 | on_exit(record__exit, rec); |
417 | 407 | ||
418 | if (file->is_pipe) { | 408 | if (file->is_pipe) { |
419 | err = perf_header__write_pipe(file->fd); | 409 | err = perf_header__write_pipe(file->fd); |
420 | if (err < 0) | 410 | if (err < 0) |
421 | goto out_delete_session; | 411 | goto out_delete_session; |
422 | } else { | 412 | } else { |
423 | err = perf_session__write_header(session, evsel_list, | 413 | err = perf_session__write_header(session, rec->evlist, |
424 | file->fd, false); | 414 | file->fd, false); |
425 | if (err < 0) | 415 | if (err < 0) |
426 | goto out_delete_session; | 416 | goto out_delete_session; |
@@ -444,7 +434,7 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv) | |||
444 | goto out_delete_session; | 434 | goto out_delete_session; |
445 | } | 435 | } |
446 | 436 | ||
447 | if (have_tracepoints(&evsel_list->entries)) { | 437 | if (have_tracepoints(&rec->evlist->entries)) { |
448 | /* | 438 | /* |
449 | * FIXME err <= 0 here actually means that | 439 | * FIXME err <= 0 here actually means that |
450 | * there were no tracepoints so its not really | 440 | * there were no tracepoints so its not really |
@@ -453,7 +443,7 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv) | |||
453 | * return this more properly and also | 443 | * return this more properly and also |
454 | * propagate errors that now are calling die() | 444 | * propagate errors that now are calling die() |
455 | */ | 445 | */ |
456 | err = perf_event__synthesize_tracing_data(tool, file->fd, evsel_list, | 446 | err = perf_event__synthesize_tracing_data(tool, file->fd, rec->evlist, |
457 | process_synthesized_event); | 447 | process_synthesized_event); |
458 | if (err <= 0) { | 448 | if (err <= 0) { |
459 | pr_err("Couldn't record tracing data.\n"); | 449 | pr_err("Couldn't record tracing data.\n"); |
@@ -464,10 +454,7 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv) | |||
464 | } | 454 | } |
465 | 455 | ||
466 | err = perf_event__synthesize_kernel_mmap(tool, process_synthesized_event, | 456 | err = perf_event__synthesize_kernel_mmap(tool, process_synthesized_event, |
467 | machine, "_text"); | 457 | machine); |
468 | if (err < 0) | ||
469 | err = perf_event__synthesize_kernel_mmap(tool, process_synthesized_event, | ||
470 | machine, "_stext"); | ||
471 | if (err < 0) | 458 | if (err < 0) |
472 | pr_err("Couldn't record kernel reference relocation symbol\n" | 459 | pr_err("Couldn't record kernel reference relocation symbol\n" |
473 | "Symbol resolution may be skewed if relocation was used (e.g. kexec).\n" | 460 | "Symbol resolution may be skewed if relocation was used (e.g. kexec).\n" |
@@ -485,7 +472,7 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv) | |||
485 | perf_event__synthesize_guest_os, tool); | 472 | perf_event__synthesize_guest_os, tool); |
486 | } | 473 | } |
487 | 474 | ||
488 | err = __machine__synthesize_threads(machine, tool, &opts->target, evsel_list->threads, | 475 | err = __machine__synthesize_threads(machine, tool, &opts->target, rec->evlist->threads, |
489 | process_synthesized_event, opts->sample_address); | 476 | process_synthesized_event, opts->sample_address); |
490 | if (err != 0) | 477 | if (err != 0) |
491 | goto out_delete_session; | 478 | goto out_delete_session; |
@@ -506,19 +493,24 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv) | |||
506 | * (apart from group members) have enable_on_exec=1 set, | 493 | * (apart from group members) have enable_on_exec=1 set, |
507 | * so don't spoil it by prematurely enabling them. | 494 | * so don't spoil it by prematurely enabling them. |
508 | */ | 495 | */ |
509 | if (!target__none(&opts->target)) | 496 | if (!target__none(&opts->target) && !opts->initial_delay) |
510 | perf_evlist__enable(evsel_list); | 497 | perf_evlist__enable(rec->evlist); |
511 | 498 | ||
512 | /* | 499 | /* |
513 | * Let the child rip | 500 | * Let the child rip |
514 | */ | 501 | */ |
515 | if (forks) | 502 | if (forks) |
516 | perf_evlist__start_workload(evsel_list); | 503 | perf_evlist__start_workload(rec->evlist); |
504 | |||
505 | if (opts->initial_delay) { | ||
506 | usleep(opts->initial_delay * 1000); | ||
507 | perf_evlist__enable(rec->evlist); | ||
508 | } | ||
517 | 509 | ||
518 | for (;;) { | 510 | for (;;) { |
519 | int hits = rec->samples; | 511 | int hits = rec->samples; |
520 | 512 | ||
521 | if (perf_record__mmap_read_all(rec) < 0) { | 513 | if (record__mmap_read_all(rec) < 0) { |
522 | err = -1; | 514 | err = -1; |
523 | goto out_delete_session; | 515 | goto out_delete_session; |
524 | } | 516 | } |
@@ -526,7 +518,7 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv) | |||
526 | if (hits == rec->samples) { | 518 | if (hits == rec->samples) { |
527 | if (done) | 519 | if (done) |
528 | break; | 520 | break; |
529 | err = poll(evsel_list->pollfd, evsel_list->nr_fds, -1); | 521 | err = poll(rec->evlist->pollfd, rec->evlist->nr_fds, -1); |
530 | waking++; | 522 | waking++; |
531 | } | 523 | } |
532 | 524 | ||
@@ -536,11 +528,19 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv) | |||
536 | * disable events in this case. | 528 | * disable events in this case. |
537 | */ | 529 | */ |
538 | if (done && !disabled && !target__none(&opts->target)) { | 530 | if (done && !disabled && !target__none(&opts->target)) { |
539 | perf_evlist__disable(evsel_list); | 531 | perf_evlist__disable(rec->evlist); |
540 | disabled = true; | 532 | disabled = true; |
541 | } | 533 | } |
542 | } | 534 | } |
543 | 535 | ||
536 | if (forks && workload_exec_errno) { | ||
537 | char msg[512]; | ||
538 | const char *emsg = strerror_r(workload_exec_errno, msg, sizeof(msg)); | ||
539 | pr_err("Workload failed: %s\n", emsg); | ||
540 | err = -1; | ||
541 | goto out_delete_session; | ||
542 | } | ||
543 | |||
544 | if (quiet || signr == SIGUSR1) | 544 | if (quiet || signr == SIGUSR1) |
545 | return 0; | 545 | return 0; |
546 | 546 | ||
@@ -677,7 +677,7 @@ static int get_stack_size(char *str, unsigned long *_size) | |||
677 | } | 677 | } |
678 | #endif /* HAVE_LIBUNWIND_SUPPORT */ | 678 | #endif /* HAVE_LIBUNWIND_SUPPORT */ |
679 | 679 | ||
680 | int record_parse_callchain(const char *arg, struct perf_record_opts *opts) | 680 | int record_parse_callchain(const char *arg, struct record_opts *opts) |
681 | { | 681 | { |
682 | char *tok, *name, *saveptr = NULL; | 682 | char *tok, *name, *saveptr = NULL; |
683 | char *buf; | 683 | char *buf; |
@@ -733,7 +733,7 @@ int record_parse_callchain(const char *arg, struct perf_record_opts *opts) | |||
733 | return ret; | 733 | return ret; |
734 | } | 734 | } |
735 | 735 | ||
736 | static void callchain_debug(struct perf_record_opts *opts) | 736 | static void callchain_debug(struct record_opts *opts) |
737 | { | 737 | { |
738 | pr_debug("callchain: type %d\n", opts->call_graph); | 738 | pr_debug("callchain: type %d\n", opts->call_graph); |
739 | 739 | ||
@@ -746,7 +746,7 @@ int record_parse_callchain_opt(const struct option *opt, | |||
746 | const char *arg, | 746 | const char *arg, |
747 | int unset) | 747 | int unset) |
748 | { | 748 | { |
749 | struct perf_record_opts *opts = opt->value; | 749 | struct record_opts *opts = opt->value; |
750 | int ret; | 750 | int ret; |
751 | 751 | ||
752 | /* --no-call-graph */ | 752 | /* --no-call-graph */ |
@@ -767,7 +767,7 @@ int record_callchain_opt(const struct option *opt, | |||
767 | const char *arg __maybe_unused, | 767 | const char *arg __maybe_unused, |
768 | int unset __maybe_unused) | 768 | int unset __maybe_unused) |
769 | { | 769 | { |
770 | struct perf_record_opts *opts = opt->value; | 770 | struct record_opts *opts = opt->value; |
771 | 771 | ||
772 | if (opts->call_graph == CALLCHAIN_NONE) | 772 | if (opts->call_graph == CALLCHAIN_NONE) |
773 | opts->call_graph = CALLCHAIN_FP; | 773 | opts->call_graph = CALLCHAIN_FP; |
@@ -783,8 +783,8 @@ static const char * const record_usage[] = { | |||
783 | }; | 783 | }; |
784 | 784 | ||
785 | /* | 785 | /* |
786 | * XXX Ideally would be local to cmd_record() and passed to a perf_record__new | 786 | * XXX Ideally would be local to cmd_record() and passed to a record__new |
787 | * because we need to have access to it in perf_record__exit, that is called | 787 | * because we need to have access to it in record__exit, that is called |
788 | * after cmd_record() exits, but since record_options need to be accessible to | 788 | * after cmd_record() exits, but since record_options need to be accessible to |
789 | * builtin-script, leave it here. | 789 | * builtin-script, leave it here. |
790 | * | 790 | * |
@@ -792,7 +792,7 @@ static const char * const record_usage[] = { | |||
792 | * | 792 | * |
793 | * Just say no to tons of global variables, sigh. | 793 | * Just say no to tons of global variables, sigh. |
794 | */ | 794 | */ |
795 | static struct perf_record record = { | 795 | static struct record record = { |
796 | .opts = { | 796 | .opts = { |
797 | .mmap_pages = UINT_MAX, | 797 | .mmap_pages = UINT_MAX, |
798 | .user_freq = UINT_MAX, | 798 | .user_freq = UINT_MAX, |
@@ -800,6 +800,7 @@ static struct perf_record record = { | |||
800 | .freq = 4000, | 800 | .freq = 4000, |
801 | .target = { | 801 | .target = { |
802 | .uses_mmap = true, | 802 | .uses_mmap = true, |
803 | .default_per_cpu = true, | ||
803 | }, | 804 | }, |
804 | }, | 805 | }, |
805 | }; | 806 | }; |
@@ -815,7 +816,7 @@ const char record_callchain_help[] = CALLCHAIN_HELP "fp"; | |||
815 | /* | 816 | /* |
816 | * XXX Will stay a global variable till we fix builtin-script.c to stop messing | 817 | * XXX Will stay a global variable till we fix builtin-script.c to stop messing |
817 | * with it and switch to use the library functions in perf_evlist that came | 818 | * with it and switch to use the library functions in perf_evlist that came |
818 | * from builtin-record.c, i.e. use perf_record_opts, | 819 | * from builtin-record.c, i.e. use record_opts, |
819 | * perf_evlist__prepare_workload, etc instead of fork+exec'in 'perf record', | 820 | * perf_evlist__prepare_workload, etc instead of fork+exec'in 'perf record', |
820 | * using pipes, etc. | 821 | * using pipes, etc. |
821 | */ | 822 | */ |
@@ -831,7 +832,7 @@ const struct option record_options[] = { | |||
831 | "record events on existing thread id"), | 832 | "record events on existing thread id"), |
832 | OPT_INTEGER('r', "realtime", &record.realtime_prio, | 833 | OPT_INTEGER('r', "realtime", &record.realtime_prio, |
833 | "collect data with this RT SCHED_FIFO priority"), | 834 | "collect data with this RT SCHED_FIFO priority"), |
834 | OPT_BOOLEAN('D', "no-delay", &record.opts.no_delay, | 835 | OPT_BOOLEAN(0, "no-buffering", &record.opts.no_buffering, |
835 | "collect data without buffering"), | 836 | "collect data without buffering"), |
836 | OPT_BOOLEAN('R', "raw-samples", &record.opts.raw_samples, | 837 | OPT_BOOLEAN('R', "raw-samples", &record.opts.raw_samples, |
837 | "collect raw sample records from all opened counters"), | 838 | "collect raw sample records from all opened counters"), |
@@ -842,8 +843,9 @@ const struct option record_options[] = { | |||
842 | OPT_U64('c', "count", &record.opts.user_interval, "event period to sample"), | 843 | OPT_U64('c', "count", &record.opts.user_interval, "event period to sample"), |
843 | OPT_STRING('o', "output", &record.file.path, "file", | 844 | OPT_STRING('o', "output", &record.file.path, "file", |
844 | "output file name"), | 845 | "output file name"), |
845 | OPT_BOOLEAN('i', "no-inherit", &record.opts.no_inherit, | 846 | OPT_BOOLEAN_SET('i', "no-inherit", &record.opts.no_inherit, |
846 | "child tasks do not inherit counters"), | 847 | &record.opts.no_inherit_set, |
848 | "child tasks do not inherit counters"), | ||
847 | OPT_UINTEGER('F', "freq", &record.opts.user_freq, "profile at this frequency"), | 849 | OPT_UINTEGER('F', "freq", &record.opts.user_freq, "profile at this frequency"), |
848 | OPT_CALLBACK('m', "mmap-pages", &record.opts.mmap_pages, "pages", | 850 | OPT_CALLBACK('m', "mmap-pages", &record.opts.mmap_pages, "pages", |
849 | "number of mmap data pages", | 851 | "number of mmap data pages", |
@@ -874,6 +876,8 @@ const struct option record_options[] = { | |||
874 | OPT_CALLBACK('G', "cgroup", &record.evlist, "name", | 876 | OPT_CALLBACK('G', "cgroup", &record.evlist, "name", |
875 | "monitor event in cgroup name only", | 877 | "monitor event in cgroup name only", |
876 | parse_cgroups), | 878 | parse_cgroups), |
879 | OPT_UINTEGER('D', "delay", &record.opts.initial_delay, | ||
880 | "ms to wait before starting measurement after program start"), | ||
877 | OPT_STRING('u', "uid", &record.opts.target.uid_str, "user", | 881 | OPT_STRING('u', "uid", &record.opts.target.uid_str, "user", |
878 | "user to profile"), | 882 | "user to profile"), |
879 | 883 | ||
@@ -888,24 +892,21 @@ const struct option record_options[] = { | |||
888 | "sample by weight (on special events only)"), | 892 | "sample by weight (on special events only)"), |
889 | OPT_BOOLEAN(0, "transaction", &record.opts.sample_transaction, | 893 | OPT_BOOLEAN(0, "transaction", &record.opts.sample_transaction, |
890 | "sample transaction flags (special events only)"), | 894 | "sample transaction flags (special events only)"), |
891 | OPT_BOOLEAN(0, "force-per-cpu", &record.opts.target.force_per_cpu, | 895 | OPT_BOOLEAN(0, "per-thread", &record.opts.target.per_thread, |
892 | "force the use of per-cpu mmaps"), | 896 | "use per-thread mmaps"), |
893 | OPT_END() | 897 | OPT_END() |
894 | }; | 898 | }; |
895 | 899 | ||
896 | int cmd_record(int argc, const char **argv, const char *prefix __maybe_unused) | 900 | int cmd_record(int argc, const char **argv, const char *prefix __maybe_unused) |
897 | { | 901 | { |
898 | int err = -ENOMEM; | 902 | int err = -ENOMEM; |
899 | struct perf_evlist *evsel_list; | 903 | struct record *rec = &record; |
900 | struct perf_record *rec = &record; | ||
901 | char errbuf[BUFSIZ]; | 904 | char errbuf[BUFSIZ]; |
902 | 905 | ||
903 | evsel_list = perf_evlist__new(); | 906 | rec->evlist = perf_evlist__new(); |
904 | if (evsel_list == NULL) | 907 | if (rec->evlist == NULL) |
905 | return -ENOMEM; | 908 | return -ENOMEM; |
906 | 909 | ||
907 | rec->evlist = evsel_list; | ||
908 | |||
909 | argc = parse_options(argc, argv, record_options, record_usage, | 910 | argc = parse_options(argc, argv, record_options, record_usage, |
910 | PARSE_OPT_STOP_AT_NON_OPTION); | 911 | PARSE_OPT_STOP_AT_NON_OPTION); |
911 | if (!argc && target__none(&rec->opts.target)) | 912 | if (!argc && target__none(&rec->opts.target)) |
@@ -932,12 +933,15 @@ int cmd_record(int argc, const char **argv, const char *prefix __maybe_unused) | |||
932 | if (rec->no_buildid_cache || rec->no_buildid) | 933 | if (rec->no_buildid_cache || rec->no_buildid) |
933 | disable_buildid_cache(); | 934 | disable_buildid_cache(); |
934 | 935 | ||
935 | if (evsel_list->nr_entries == 0 && | 936 | if (rec->evlist->nr_entries == 0 && |
936 | perf_evlist__add_default(evsel_list) < 0) { | 937 | perf_evlist__add_default(rec->evlist) < 0) { |
937 | pr_err("Not enough memory for event selector list\n"); | 938 | pr_err("Not enough memory for event selector list\n"); |
938 | goto out_symbol_exit; | 939 | goto out_symbol_exit; |
939 | } | 940 | } |
940 | 941 | ||
942 | if (rec->opts.target.tid && !rec->opts.no_inherit_set) | ||
943 | rec->opts.no_inherit = true; | ||
944 | |||
941 | err = target__validate(&rec->opts.target); | 945 | err = target__validate(&rec->opts.target); |
942 | if (err) { | 946 | if (err) { |
943 | target__strerror(&rec->opts.target, err, errbuf, BUFSIZ); | 947 | target__strerror(&rec->opts.target, err, errbuf, BUFSIZ); |
@@ -956,20 +960,15 @@ int cmd_record(int argc, const char **argv, const char *prefix __maybe_unused) | |||
956 | } | 960 | } |
957 | 961 | ||
958 | err = -ENOMEM; | 962 | err = -ENOMEM; |
959 | if (perf_evlist__create_maps(evsel_list, &rec->opts.target) < 0) | 963 | if (perf_evlist__create_maps(rec->evlist, &rec->opts.target) < 0) |
960 | usage_with_options(record_usage, record_options); | 964 | usage_with_options(record_usage, record_options); |
961 | 965 | ||
962 | if (perf_record_opts__config(&rec->opts)) { | 966 | if (record_opts__config(&rec->opts)) { |
963 | err = -EINVAL; | 967 | err = -EINVAL; |
964 | goto out_free_fd; | 968 | goto out_symbol_exit; |
965 | } | 969 | } |
966 | 970 | ||
967 | err = __cmd_record(&record, argc, argv); | 971 | err = __cmd_record(&record, argc, argv); |
968 | |||
969 | perf_evlist__munmap(evsel_list); | ||
970 | perf_evlist__close(evsel_list); | ||
971 | out_free_fd: | ||
972 | perf_evlist__delete_maps(evsel_list); | ||
973 | out_symbol_exit: | 972 | out_symbol_exit: |
974 | symbol__exit(); | 973 | symbol__exit(); |
975 | return err; | 974 | return err; |
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index 8cf8e66ba594..02f985f3a396 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c | |||
@@ -39,7 +39,7 @@ | |||
39 | #include <dlfcn.h> | 39 | #include <dlfcn.h> |
40 | #include <linux/bitmap.h> | 40 | #include <linux/bitmap.h> |
41 | 41 | ||
42 | struct perf_report { | 42 | struct report { |
43 | struct perf_tool tool; | 43 | struct perf_tool tool; |
44 | struct perf_session *session; | 44 | struct perf_session *session; |
45 | bool force, use_tui, use_gtk, use_stdio; | 45 | bool force, use_tui, use_gtk, use_stdio; |
@@ -49,6 +49,8 @@ struct perf_report { | |||
49 | bool show_threads; | 49 | bool show_threads; |
50 | bool inverted_callchain; | 50 | bool inverted_callchain; |
51 | bool mem_mode; | 51 | bool mem_mode; |
52 | bool header; | ||
53 | bool header_only; | ||
52 | int max_stack; | 54 | int max_stack; |
53 | struct perf_read_values show_threads_values; | 55 | struct perf_read_values show_threads_values; |
54 | const char *pretty_printing_style; | 56 | const char *pretty_printing_style; |
@@ -58,14 +60,14 @@ struct perf_report { | |||
58 | DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS); | 60 | DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS); |
59 | }; | 61 | }; |
60 | 62 | ||
61 | static int perf_report_config(const char *var, const char *value, void *cb) | 63 | static int report__config(const char *var, const char *value, void *cb) |
62 | { | 64 | { |
63 | if (!strcmp(var, "report.group")) { | 65 | if (!strcmp(var, "report.group")) { |
64 | symbol_conf.event_group = perf_config_bool(var, value); | 66 | symbol_conf.event_group = perf_config_bool(var, value); |
65 | return 0; | 67 | return 0; |
66 | } | 68 | } |
67 | if (!strcmp(var, "report.percent-limit")) { | 69 | if (!strcmp(var, "report.percent-limit")) { |
68 | struct perf_report *rep = cb; | 70 | struct report *rep = cb; |
69 | rep->min_percent = strtof(value, NULL); | 71 | rep->min_percent = strtof(value, NULL); |
70 | return 0; | 72 | return 0; |
71 | } | 73 | } |
@@ -73,31 +75,22 @@ static int perf_report_config(const char *var, const char *value, void *cb) | |||
73 | return perf_default_config(var, value, cb); | 75 | return perf_default_config(var, value, cb); |
74 | } | 76 | } |
75 | 77 | ||
76 | static int perf_report__add_mem_hist_entry(struct perf_tool *tool, | 78 | static int report__add_mem_hist_entry(struct perf_tool *tool, struct addr_location *al, |
77 | struct addr_location *al, | 79 | struct perf_sample *sample, struct perf_evsel *evsel, |
78 | struct perf_sample *sample, | 80 | union perf_event *event) |
79 | struct perf_evsel *evsel, | ||
80 | struct machine *machine, | ||
81 | union perf_event *event) | ||
82 | { | 81 | { |
83 | struct perf_report *rep = container_of(tool, struct perf_report, tool); | 82 | struct report *rep = container_of(tool, struct report, tool); |
84 | struct symbol *parent = NULL; | 83 | struct symbol *parent = NULL; |
85 | u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; | 84 | u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; |
86 | int err = 0; | ||
87 | struct hist_entry *he; | 85 | struct hist_entry *he; |
88 | struct mem_info *mi, *mx; | 86 | struct mem_info *mi, *mx; |
89 | uint64_t cost; | 87 | uint64_t cost; |
88 | int err = sample__resolve_callchain(sample, &parent, evsel, al, rep->max_stack); | ||
90 | 89 | ||
91 | if ((sort__has_parent || symbol_conf.use_callchain) && | 90 | if (err) |
92 | sample->callchain) { | 91 | return err; |
93 | err = machine__resolve_callchain(machine, evsel, al->thread, | ||
94 | sample, &parent, al, | ||
95 | rep->max_stack); | ||
96 | if (err) | ||
97 | return err; | ||
98 | } | ||
99 | 92 | ||
100 | mi = machine__resolve_mem(machine, al->thread, sample, cpumode); | 93 | mi = machine__resolve_mem(al->machine, al->thread, sample, cpumode); |
101 | if (!mi) | 94 | if (!mi) |
102 | return -ENOMEM; | 95 | return -ENOMEM; |
103 | 96 | ||
@@ -120,77 +113,38 @@ static int perf_report__add_mem_hist_entry(struct perf_tool *tool, | |||
120 | if (!he) | 113 | if (!he) |
121 | return -ENOMEM; | 114 | return -ENOMEM; |
122 | 115 | ||
123 | /* | 116 | if (ui__has_annotation()) { |
124 | * In the TUI browser, we are doing integrated annotation, | ||
125 | * so we don't allocate the extra space needed because the stdio | ||
126 | * code will not use it. | ||
127 | */ | ||
128 | if (sort__has_sym && he->ms.sym && use_browser > 0) { | ||
129 | struct annotation *notes = symbol__annotation(he->ms.sym); | ||
130 | |||
131 | assert(evsel != NULL); | ||
132 | |||
133 | if (notes->src == NULL && symbol__alloc_hist(he->ms.sym) < 0) | ||
134 | goto out; | ||
135 | |||
136 | err = hist_entry__inc_addr_samples(he, evsel->idx, al->addr); | 117 | err = hist_entry__inc_addr_samples(he, evsel->idx, al->addr); |
137 | if (err) | 118 | if (err) |
138 | goto out; | 119 | goto out; |
139 | } | ||
140 | |||
141 | if (sort__has_sym && he->mem_info->daddr.sym && use_browser > 0) { | ||
142 | struct annotation *notes; | ||
143 | 120 | ||
144 | mx = he->mem_info; | 121 | mx = he->mem_info; |
145 | 122 | err = addr_map_symbol__inc_samples(&mx->daddr, evsel->idx); | |
146 | notes = symbol__annotation(mx->daddr.sym); | ||
147 | if (notes->src == NULL && symbol__alloc_hist(mx->daddr.sym) < 0) | ||
148 | goto out; | ||
149 | |||
150 | err = symbol__inc_addr_samples(mx->daddr.sym, | ||
151 | mx->daddr.map, | ||
152 | evsel->idx, | ||
153 | mx->daddr.al_addr); | ||
154 | if (err) | 123 | if (err) |
155 | goto out; | 124 | goto out; |
156 | } | 125 | } |
157 | 126 | ||
158 | evsel->hists.stats.total_period += cost; | 127 | evsel->hists.stats.total_period += cost; |
159 | hists__inc_nr_events(&evsel->hists, PERF_RECORD_SAMPLE); | 128 | hists__inc_nr_events(&evsel->hists, PERF_RECORD_SAMPLE); |
160 | err = 0; | 129 | err = hist_entry__append_callchain(he, sample); |
161 | |||
162 | if (symbol_conf.use_callchain) { | ||
163 | err = callchain_append(he->callchain, | ||
164 | &callchain_cursor, | ||
165 | sample->period); | ||
166 | } | ||
167 | out: | 130 | out: |
168 | return err; | 131 | return err; |
169 | } | 132 | } |
170 | 133 | ||
171 | static int perf_report__add_branch_hist_entry(struct perf_tool *tool, | 134 | static int report__add_branch_hist_entry(struct perf_tool *tool, struct addr_location *al, |
172 | struct addr_location *al, | 135 | struct perf_sample *sample, struct perf_evsel *evsel) |
173 | struct perf_sample *sample, | ||
174 | struct perf_evsel *evsel, | ||
175 | struct machine *machine) | ||
176 | { | 136 | { |
177 | struct perf_report *rep = container_of(tool, struct perf_report, tool); | 137 | struct report *rep = container_of(tool, struct report, tool); |
178 | struct symbol *parent = NULL; | 138 | struct symbol *parent = NULL; |
179 | int err = 0; | ||
180 | unsigned i; | 139 | unsigned i; |
181 | struct hist_entry *he; | 140 | struct hist_entry *he; |
182 | struct branch_info *bi, *bx; | 141 | struct branch_info *bi, *bx; |
142 | int err = sample__resolve_callchain(sample, &parent, evsel, al, rep->max_stack); | ||
183 | 143 | ||
184 | if ((sort__has_parent || symbol_conf.use_callchain) | 144 | if (err) |
185 | && sample->callchain) { | 145 | return err; |
186 | err = machine__resolve_callchain(machine, evsel, al->thread, | ||
187 | sample, &parent, al, | ||
188 | rep->max_stack); | ||
189 | if (err) | ||
190 | return err; | ||
191 | } | ||
192 | 146 | ||
193 | bi = machine__resolve_bstack(machine, al->thread, | 147 | bi = machine__resolve_bstack(al->machine, al->thread, |
194 | sample->branch_stack); | 148 | sample->branch_stack); |
195 | if (!bi) | 149 | if (!bi) |
196 | return -ENOMEM; | 150 | return -ENOMEM; |
@@ -212,35 +166,19 @@ static int perf_report__add_branch_hist_entry(struct perf_tool *tool, | |||
212 | he = __hists__add_entry(&evsel->hists, al, parent, &bi[i], NULL, | 166 | he = __hists__add_entry(&evsel->hists, al, parent, &bi[i], NULL, |
213 | 1, 1, 0); | 167 | 1, 1, 0); |
214 | if (he) { | 168 | if (he) { |
215 | struct annotation *notes; | 169 | if (ui__has_annotation()) { |
216 | bx = he->branch_info; | 170 | bx = he->branch_info; |
217 | if (bx->from.sym && use_browser == 1 && sort__has_sym) { | 171 | err = addr_map_symbol__inc_samples(&bx->from, |
218 | notes = symbol__annotation(bx->from.sym); | 172 | evsel->idx); |
219 | if (!notes->src | ||
220 | && symbol__alloc_hist(bx->from.sym) < 0) | ||
221 | goto out; | ||
222 | |||
223 | err = symbol__inc_addr_samples(bx->from.sym, | ||
224 | bx->from.map, | ||
225 | evsel->idx, | ||
226 | bx->from.al_addr); | ||
227 | if (err) | 173 | if (err) |
228 | goto out; | 174 | goto out; |
229 | } | ||
230 | 175 | ||
231 | if (bx->to.sym && use_browser == 1 && sort__has_sym) { | 176 | err = addr_map_symbol__inc_samples(&bx->to, |
232 | notes = symbol__annotation(bx->to.sym); | 177 | evsel->idx); |
233 | if (!notes->src | ||
234 | && symbol__alloc_hist(bx->to.sym) < 0) | ||
235 | goto out; | ||
236 | |||
237 | err = symbol__inc_addr_samples(bx->to.sym, | ||
238 | bx->to.map, | ||
239 | evsel->idx, | ||
240 | bx->to.al_addr); | ||
241 | if (err) | 178 | if (err) |
242 | goto out; | 179 | goto out; |
243 | } | 180 | } |
181 | |||
244 | evsel->hists.stats.total_period += 1; | 182 | evsel->hists.stats.total_period += 1; |
245 | hists__inc_nr_events(&evsel->hists, PERF_RECORD_SAMPLE); | 183 | hists__inc_nr_events(&evsel->hists, PERF_RECORD_SAMPLE); |
246 | } else | 184 | } else |
@@ -252,24 +190,16 @@ out: | |||
252 | return err; | 190 | return err; |
253 | } | 191 | } |
254 | 192 | ||
255 | static int perf_evsel__add_hist_entry(struct perf_tool *tool, | 193 | static int report__add_hist_entry(struct perf_tool *tool, struct perf_evsel *evsel, |
256 | struct perf_evsel *evsel, | 194 | struct addr_location *al, struct perf_sample *sample) |
257 | struct addr_location *al, | ||
258 | struct perf_sample *sample, | ||
259 | struct machine *machine) | ||
260 | { | 195 | { |
261 | struct perf_report *rep = container_of(tool, struct perf_report, tool); | 196 | struct report *rep = container_of(tool, struct report, tool); |
262 | struct symbol *parent = NULL; | 197 | struct symbol *parent = NULL; |
263 | int err = 0; | ||
264 | struct hist_entry *he; | 198 | struct hist_entry *he; |
199 | int err = sample__resolve_callchain(sample, &parent, evsel, al, rep->max_stack); | ||
265 | 200 | ||
266 | if ((sort__has_parent || symbol_conf.use_callchain) && sample->callchain) { | 201 | if (err) |
267 | err = machine__resolve_callchain(machine, evsel, al->thread, | 202 | return err; |
268 | sample, &parent, al, | ||
269 | rep->max_stack); | ||
270 | if (err) | ||
271 | return err; | ||
272 | } | ||
273 | 203 | ||
274 | he = __hists__add_entry(&evsel->hists, al, parent, NULL, NULL, | 204 | he = __hists__add_entry(&evsel->hists, al, parent, NULL, NULL, |
275 | sample->period, sample->weight, | 205 | sample->period, sample->weight, |
@@ -277,29 +207,12 @@ static int perf_evsel__add_hist_entry(struct perf_tool *tool, | |||
277 | if (he == NULL) | 207 | if (he == NULL) |
278 | return -ENOMEM; | 208 | return -ENOMEM; |
279 | 209 | ||
280 | if (symbol_conf.use_callchain) { | 210 | err = hist_entry__append_callchain(he, sample); |
281 | err = callchain_append(he->callchain, | 211 | if (err) |
282 | &callchain_cursor, | 212 | goto out; |
283 | sample->period); | ||
284 | if (err) | ||
285 | return err; | ||
286 | } | ||
287 | /* | ||
288 | * Only in the TUI browser we are doing integrated annotation, | ||
289 | * so we don't allocated the extra space needed because the stdio | ||
290 | * code will not use it. | ||
291 | */ | ||
292 | if (he->ms.sym != NULL && use_browser == 1 && sort__has_sym) { | ||
293 | struct annotation *notes = symbol__annotation(he->ms.sym); | ||
294 | |||
295 | assert(evsel != NULL); | ||
296 | |||
297 | err = -ENOMEM; | ||
298 | if (notes->src == NULL && symbol__alloc_hist(he->ms.sym) < 0) | ||
299 | goto out; | ||
300 | 213 | ||
214 | if (ui__has_annotation()) | ||
301 | err = hist_entry__inc_addr_samples(he, evsel->idx, al->addr); | 215 | err = hist_entry__inc_addr_samples(he, evsel->idx, al->addr); |
302 | } | ||
303 | 216 | ||
304 | evsel->hists.stats.total_period += sample->period; | 217 | evsel->hists.stats.total_period += sample->period; |
305 | hists__inc_nr_events(&evsel->hists, PERF_RECORD_SAMPLE); | 218 | hists__inc_nr_events(&evsel->hists, PERF_RECORD_SAMPLE); |
@@ -314,13 +227,13 @@ static int process_sample_event(struct perf_tool *tool, | |||
314 | struct perf_evsel *evsel, | 227 | struct perf_evsel *evsel, |
315 | struct machine *machine) | 228 | struct machine *machine) |
316 | { | 229 | { |
317 | struct perf_report *rep = container_of(tool, struct perf_report, tool); | 230 | struct report *rep = container_of(tool, struct report, tool); |
318 | struct addr_location al; | 231 | struct addr_location al; |
319 | int ret; | 232 | int ret; |
320 | 233 | ||
321 | if (perf_event__preprocess_sample(event, machine, &al, sample) < 0) { | 234 | if (perf_event__preprocess_sample(event, machine, &al, sample) < 0) { |
322 | fprintf(stderr, "problem processing %d event, skipping it.\n", | 235 | pr_debug("problem processing %d event, skipping it.\n", |
323 | event->header.type); | 236 | event->header.type); |
324 | return -1; | 237 | return -1; |
325 | } | 238 | } |
326 | 239 | ||
@@ -331,21 +244,18 @@ static int process_sample_event(struct perf_tool *tool, | |||
331 | return 0; | 244 | return 0; |
332 | 245 | ||
333 | if (sort__mode == SORT_MODE__BRANCH) { | 246 | if (sort__mode == SORT_MODE__BRANCH) { |
334 | ret = perf_report__add_branch_hist_entry(tool, &al, sample, | 247 | ret = report__add_branch_hist_entry(tool, &al, sample, evsel); |
335 | evsel, machine); | ||
336 | if (ret < 0) | 248 | if (ret < 0) |
337 | pr_debug("problem adding lbr entry, skipping event\n"); | 249 | pr_debug("problem adding lbr entry, skipping event\n"); |
338 | } else if (rep->mem_mode == 1) { | 250 | } else if (rep->mem_mode == 1) { |
339 | ret = perf_report__add_mem_hist_entry(tool, &al, sample, | 251 | ret = report__add_mem_hist_entry(tool, &al, sample, evsel, event); |
340 | evsel, machine, event); | ||
341 | if (ret < 0) | 252 | if (ret < 0) |
342 | pr_debug("problem adding mem entry, skipping event\n"); | 253 | pr_debug("problem adding mem entry, skipping event\n"); |
343 | } else { | 254 | } else { |
344 | if (al.map != NULL) | 255 | if (al.map != NULL) |
345 | al.map->dso->hit = 1; | 256 | al.map->dso->hit = 1; |
346 | 257 | ||
347 | ret = perf_evsel__add_hist_entry(tool, evsel, &al, sample, | 258 | ret = report__add_hist_entry(tool, evsel, &al, sample); |
348 | machine); | ||
349 | if (ret < 0) | 259 | if (ret < 0) |
350 | pr_debug("problem incrementing symbol period, skipping event\n"); | 260 | pr_debug("problem incrementing symbol period, skipping event\n"); |
351 | } | 261 | } |
@@ -358,7 +268,7 @@ static int process_read_event(struct perf_tool *tool, | |||
358 | struct perf_evsel *evsel, | 268 | struct perf_evsel *evsel, |
359 | struct machine *machine __maybe_unused) | 269 | struct machine *machine __maybe_unused) |
360 | { | 270 | { |
361 | struct perf_report *rep = container_of(tool, struct perf_report, tool); | 271 | struct report *rep = container_of(tool, struct report, tool); |
362 | 272 | ||
363 | if (rep->show_threads) { | 273 | if (rep->show_threads) { |
364 | const char *name = evsel ? perf_evsel__name(evsel) : "unknown"; | 274 | const char *name = evsel ? perf_evsel__name(evsel) : "unknown"; |
@@ -377,7 +287,7 @@ static int process_read_event(struct perf_tool *tool, | |||
377 | } | 287 | } |
378 | 288 | ||
379 | /* For pipe mode, sample_type is not currently set */ | 289 | /* For pipe mode, sample_type is not currently set */ |
380 | static int perf_report__setup_sample_type(struct perf_report *rep) | 290 | static int report__setup_sample_type(struct report *rep) |
381 | { | 291 | { |
382 | struct perf_session *session = rep->session; | 292 | struct perf_session *session = rep->session; |
383 | u64 sample_type = perf_evlist__combined_sample_type(session->evlist); | 293 | u64 sample_type = perf_evlist__combined_sample_type(session->evlist); |
@@ -422,8 +332,7 @@ static void sig_handler(int sig __maybe_unused) | |||
422 | session_done = 1; | 332 | session_done = 1; |
423 | } | 333 | } |
424 | 334 | ||
425 | static size_t hists__fprintf_nr_sample_events(struct perf_report *rep, | 335 | static size_t hists__fprintf_nr_sample_events(struct hists *hists, struct report *rep, |
426 | struct hists *hists, | ||
427 | const char *evname, FILE *fp) | 336 | const char *evname, FILE *fp) |
428 | { | 337 | { |
429 | size_t ret; | 338 | size_t ret; |
@@ -460,12 +369,12 @@ static size_t hists__fprintf_nr_sample_events(struct perf_report *rep, | |||
460 | } | 369 | } |
461 | 370 | ||
462 | static int perf_evlist__tty_browse_hists(struct perf_evlist *evlist, | 371 | static int perf_evlist__tty_browse_hists(struct perf_evlist *evlist, |
463 | struct perf_report *rep, | 372 | struct report *rep, |
464 | const char *help) | 373 | const char *help) |
465 | { | 374 | { |
466 | struct perf_evsel *pos; | 375 | struct perf_evsel *pos; |
467 | 376 | ||
468 | list_for_each_entry(pos, &evlist->entries, node) { | 377 | evlist__for_each(evlist, pos) { |
469 | struct hists *hists = &pos->hists; | 378 | struct hists *hists = &pos->hists; |
470 | const char *evname = perf_evsel__name(pos); | 379 | const char *evname = perf_evsel__name(pos); |
471 | 380 | ||
@@ -473,7 +382,7 @@ static int perf_evlist__tty_browse_hists(struct perf_evlist *evlist, | |||
473 | !perf_evsel__is_group_leader(pos)) | 382 | !perf_evsel__is_group_leader(pos)) |
474 | continue; | 383 | continue; |
475 | 384 | ||
476 | hists__fprintf_nr_sample_events(rep, hists, evname, stdout); | 385 | hists__fprintf_nr_sample_events(hists, rep, evname, stdout); |
477 | hists__fprintf(hists, true, 0, 0, rep->min_percent, stdout); | 386 | hists__fprintf(hists, true, 0, 0, rep->min_percent, stdout); |
478 | fprintf(stdout, "\n\n"); | 387 | fprintf(stdout, "\n\n"); |
479 | } | 388 | } |
@@ -493,43 +402,11 @@ static int perf_evlist__tty_browse_hists(struct perf_evlist *evlist, | |||
493 | return 0; | 402 | return 0; |
494 | } | 403 | } |
495 | 404 | ||
496 | static int __cmd_report(struct perf_report *rep) | 405 | static void report__warn_kptr_restrict(const struct report *rep) |
497 | { | 406 | { |
498 | int ret = -EINVAL; | 407 | struct map *kernel_map = rep->session->machines.host.vmlinux_maps[MAP__FUNCTION]; |
499 | u64 nr_samples; | 408 | struct kmap *kernel_kmap = map__kmap(kernel_map); |
500 | struct perf_session *session = rep->session; | ||
501 | struct perf_evsel *pos; | ||
502 | struct map *kernel_map; | ||
503 | struct kmap *kernel_kmap; | ||
504 | const char *help = "For a higher level overview, try: perf report --sort comm,dso"; | ||
505 | struct ui_progress prog; | ||
506 | struct perf_data_file *file = session->file; | ||
507 | |||
508 | signal(SIGINT, sig_handler); | ||
509 | |||
510 | if (rep->cpu_list) { | ||
511 | ret = perf_session__cpu_bitmap(session, rep->cpu_list, | ||
512 | rep->cpu_bitmap); | ||
513 | if (ret) | ||
514 | return ret; | ||
515 | } | ||
516 | 409 | ||
517 | if (use_browser <= 0) | ||
518 | perf_session__fprintf_info(session, stdout, rep->show_full_info); | ||
519 | |||
520 | if (rep->show_threads) | ||
521 | perf_read_values_init(&rep->show_threads_values); | ||
522 | |||
523 | ret = perf_report__setup_sample_type(rep); | ||
524 | if (ret) | ||
525 | return ret; | ||
526 | |||
527 | ret = perf_session__process_events(session, &rep->tool); | ||
528 | if (ret) | ||
529 | return ret; | ||
530 | |||
531 | kernel_map = session->machines.host.vmlinux_maps[MAP__FUNCTION]; | ||
532 | kernel_kmap = map__kmap(kernel_map); | ||
533 | if (kernel_map == NULL || | 410 | if (kernel_map == NULL || |
534 | (kernel_map->dso->hit && | 411 | (kernel_map->dso->hit && |
535 | (kernel_kmap->ref_reloc_sym == NULL || | 412 | (kernel_kmap->ref_reloc_sym == NULL || |
@@ -552,26 +429,73 @@ static int __cmd_report(struct perf_report *rep) | |||
552 | "Samples in kernel modules can't be resolved as well.\n\n", | 429 | "Samples in kernel modules can't be resolved as well.\n\n", |
553 | desc); | 430 | desc); |
554 | } | 431 | } |
432 | } | ||
555 | 433 | ||
556 | if (verbose > 3) | 434 | static int report__gtk_browse_hists(struct report *rep, const char *help) |
557 | perf_session__fprintf(session, stdout); | 435 | { |
436 | int (*hist_browser)(struct perf_evlist *evlist, const char *help, | ||
437 | struct hist_browser_timer *timer, float min_pcnt); | ||
558 | 438 | ||
559 | if (verbose > 2) | 439 | hist_browser = dlsym(perf_gtk_handle, "perf_evlist__gtk_browse_hists"); |
560 | perf_session__fprintf_dsos(session, stdout); | ||
561 | 440 | ||
562 | if (dump_trace) { | 441 | if (hist_browser == NULL) { |
563 | perf_session__fprintf_nr_events(session, stdout); | 442 | ui__error("GTK browser not found!\n"); |
564 | return 0; | 443 | return -1; |
565 | } | 444 | } |
566 | 445 | ||
567 | nr_samples = 0; | 446 | return hist_browser(rep->session->evlist, help, NULL, rep->min_percent); |
568 | list_for_each_entry(pos, &session->evlist->entries, node) | 447 | } |
448 | |||
449 | static int report__browse_hists(struct report *rep) | ||
450 | { | ||
451 | int ret; | ||
452 | struct perf_session *session = rep->session; | ||
453 | struct perf_evlist *evlist = session->evlist; | ||
454 | const char *help = "For a higher level overview, try: perf report --sort comm,dso"; | ||
455 | |||
456 | switch (use_browser) { | ||
457 | case 1: | ||
458 | ret = perf_evlist__tui_browse_hists(evlist, help, NULL, | ||
459 | rep->min_percent, | ||
460 | &session->header.env); | ||
461 | /* | ||
462 | * Usually "ret" is the last pressed key, and we only | ||
463 | * care if the key notifies us to switch data file. | ||
464 | */ | ||
465 | if (ret != K_SWITCH_INPUT_DATA) | ||
466 | ret = 0; | ||
467 | break; | ||
468 | case 2: | ||
469 | ret = report__gtk_browse_hists(rep, help); | ||
470 | break; | ||
471 | default: | ||
472 | ret = perf_evlist__tty_browse_hists(evlist, rep, help); | ||
473 | break; | ||
474 | } | ||
475 | |||
476 | return ret; | ||
477 | } | ||
478 | |||
479 | static u64 report__collapse_hists(struct report *rep) | ||
480 | { | ||
481 | struct ui_progress prog; | ||
482 | struct perf_evsel *pos; | ||
483 | u64 nr_samples = 0; | ||
484 | /* | ||
485 | * Count number of histogram entries to use when showing progress, | ||
486 | * reusing nr_samples variable. | ||
487 | */ | ||
488 | evlist__for_each(rep->session->evlist, pos) | ||
569 | nr_samples += pos->hists.nr_entries; | 489 | nr_samples += pos->hists.nr_entries; |
570 | 490 | ||
571 | ui_progress__init(&prog, nr_samples, "Merging related events..."); | 491 | ui_progress__init(&prog, nr_samples, "Merging related events..."); |
572 | 492 | /* | |
493 | * Count total number of samples, will be used to check if this | ||
494 | * session had any. | ||
495 | */ | ||
573 | nr_samples = 0; | 496 | nr_samples = 0; |
574 | list_for_each_entry(pos, &session->evlist->entries, node) { | 497 | |
498 | evlist__for_each(rep->session->evlist, pos) { | ||
575 | struct hists *hists = &pos->hists; | 499 | struct hists *hists = &pos->hists; |
576 | 500 | ||
577 | if (pos->idx == 0) | 501 | if (pos->idx == 0) |
@@ -589,8 +513,57 @@ static int __cmd_report(struct perf_report *rep) | |||
589 | hists__link(leader_hists, hists); | 513 | hists__link(leader_hists, hists); |
590 | } | 514 | } |
591 | } | 515 | } |
516 | |||
592 | ui_progress__finish(); | 517 | ui_progress__finish(); |
593 | 518 | ||
519 | return nr_samples; | ||
520 | } | ||
521 | |||
522 | static int __cmd_report(struct report *rep) | ||
523 | { | ||
524 | int ret; | ||
525 | u64 nr_samples; | ||
526 | struct perf_session *session = rep->session; | ||
527 | struct perf_evsel *pos; | ||
528 | struct perf_data_file *file = session->file; | ||
529 | |||
530 | signal(SIGINT, sig_handler); | ||
531 | |||
532 | if (rep->cpu_list) { | ||
533 | ret = perf_session__cpu_bitmap(session, rep->cpu_list, | ||
534 | rep->cpu_bitmap); | ||
535 | if (ret) | ||
536 | return ret; | ||
537 | } | ||
538 | |||
539 | if (rep->show_threads) | ||
540 | perf_read_values_init(&rep->show_threads_values); | ||
541 | |||
542 | ret = report__setup_sample_type(rep); | ||
543 | if (ret) | ||
544 | return ret; | ||
545 | |||
546 | ret = perf_session__process_events(session, &rep->tool); | ||
547 | if (ret) | ||
548 | return ret; | ||
549 | |||
550 | report__warn_kptr_restrict(rep); | ||
551 | |||
552 | if (use_browser == 0) { | ||
553 | if (verbose > 3) | ||
554 | perf_session__fprintf(session, stdout); | ||
555 | |||
556 | if (verbose > 2) | ||
557 | perf_session__fprintf_dsos(session, stdout); | ||
558 | |||
559 | if (dump_trace) { | ||
560 | perf_session__fprintf_nr_events(session, stdout); | ||
561 | return 0; | ||
562 | } | ||
563 | } | ||
564 | |||
565 | nr_samples = report__collapse_hists(rep); | ||
566 | |||
594 | if (session_done()) | 567 | if (session_done()) |
595 | return 0; | 568 | return 0; |
596 | 569 | ||
@@ -599,47 +572,16 @@ static int __cmd_report(struct perf_report *rep) | |||
599 | return 0; | 572 | return 0; |
600 | } | 573 | } |
601 | 574 | ||
602 | list_for_each_entry(pos, &session->evlist->entries, node) | 575 | evlist__for_each(session->evlist, pos) |
603 | hists__output_resort(&pos->hists); | 576 | hists__output_resort(&pos->hists); |
604 | 577 | ||
605 | if (use_browser > 0) { | 578 | return report__browse_hists(rep); |
606 | if (use_browser == 1) { | ||
607 | ret = perf_evlist__tui_browse_hists(session->evlist, | ||
608 | help, NULL, | ||
609 | rep->min_percent, | ||
610 | &session->header.env); | ||
611 | /* | ||
612 | * Usually "ret" is the last pressed key, and we only | ||
613 | * care if the key notifies us to switch data file. | ||
614 | */ | ||
615 | if (ret != K_SWITCH_INPUT_DATA) | ||
616 | ret = 0; | ||
617 | |||
618 | } else if (use_browser == 2) { | ||
619 | int (*hist_browser)(struct perf_evlist *, | ||
620 | const char *, | ||
621 | struct hist_browser_timer *, | ||
622 | float min_pcnt); | ||
623 | |||
624 | hist_browser = dlsym(perf_gtk_handle, | ||
625 | "perf_evlist__gtk_browse_hists"); | ||
626 | if (hist_browser == NULL) { | ||
627 | ui__error("GTK browser not found!\n"); | ||
628 | return ret; | ||
629 | } | ||
630 | hist_browser(session->evlist, help, NULL, | ||
631 | rep->min_percent); | ||
632 | } | ||
633 | } else | ||
634 | perf_evlist__tty_browse_hists(session->evlist, rep, help); | ||
635 | |||
636 | return ret; | ||
637 | } | 579 | } |
638 | 580 | ||
639 | static int | 581 | static int |
640 | parse_callchain_opt(const struct option *opt, const char *arg, int unset) | 582 | parse_callchain_opt(const struct option *opt, const char *arg, int unset) |
641 | { | 583 | { |
642 | struct perf_report *rep = (struct perf_report *)opt->value; | 584 | struct report *rep = (struct report *)opt->value; |
643 | char *tok, *tok2; | 585 | char *tok, *tok2; |
644 | char *endptr; | 586 | char *endptr; |
645 | 587 | ||
@@ -721,7 +663,7 @@ parse_callchain_opt(const struct option *opt, const char *arg, int unset) | |||
721 | return -1; | 663 | return -1; |
722 | setup: | 664 | setup: |
723 | if (callchain_register_param(&callchain_param) < 0) { | 665 | if (callchain_register_param(&callchain_param) < 0) { |
724 | fprintf(stderr, "Can't register callchain params\n"); | 666 | pr_err("Can't register callchain params\n"); |
725 | return -1; | 667 | return -1; |
726 | } | 668 | } |
727 | return 0; | 669 | return 0; |
@@ -759,7 +701,7 @@ static int | |||
759 | parse_percent_limit(const struct option *opt, const char *str, | 701 | parse_percent_limit(const struct option *opt, const char *str, |
760 | int unset __maybe_unused) | 702 | int unset __maybe_unused) |
761 | { | 703 | { |
762 | struct perf_report *rep = opt->value; | 704 | struct report *rep = opt->value; |
763 | 705 | ||
764 | rep->min_percent = strtof(str, NULL); | 706 | rep->min_percent = strtof(str, NULL); |
765 | return 0; | 707 | return 0; |
@@ -777,7 +719,7 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused) | |||
777 | "perf report [<options>]", | 719 | "perf report [<options>]", |
778 | NULL | 720 | NULL |
779 | }; | 721 | }; |
780 | struct perf_report report = { | 722 | struct report report = { |
781 | .tool = { | 723 | .tool = { |
782 | .sample = process_sample_event, | 724 | .sample = process_sample_event, |
783 | .mmap = perf_event__process_mmap, | 725 | .mmap = perf_event__process_mmap, |
@@ -820,6 +762,9 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused) | |||
820 | OPT_BOOLEAN(0, "gtk", &report.use_gtk, "Use the GTK2 interface"), | 762 | OPT_BOOLEAN(0, "gtk", &report.use_gtk, "Use the GTK2 interface"), |
821 | OPT_BOOLEAN(0, "stdio", &report.use_stdio, | 763 | OPT_BOOLEAN(0, "stdio", &report.use_stdio, |
822 | "Use the stdio interface"), | 764 | "Use the stdio interface"), |
765 | OPT_BOOLEAN(0, "header", &report.header, "Show data header."), | ||
766 | OPT_BOOLEAN(0, "header-only", &report.header_only, | ||
767 | "Show only data header."), | ||
823 | OPT_STRING('s', "sort", &sort_order, "key[,key2...]", | 768 | OPT_STRING('s', "sort", &sort_order, "key[,key2...]", |
824 | "sort by key(s): pid, comm, dso, symbol, parent, cpu, srcline," | 769 | "sort by key(s): pid, comm, dso, symbol, parent, cpu, srcline," |
825 | " dso_to, dso_from, symbol_to, symbol_from, mispredict," | 770 | " dso_to, dso_from, symbol_to, symbol_from, mispredict," |
@@ -890,7 +835,7 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused) | |||
890 | .mode = PERF_DATA_MODE_READ, | 835 | .mode = PERF_DATA_MODE_READ, |
891 | }; | 836 | }; |
892 | 837 | ||
893 | perf_config(perf_report_config, &report); | 838 | perf_config(report__config, &report); |
894 | 839 | ||
895 | argc = parse_options(argc, argv, options, report_usage, 0); | 840 | argc = parse_options(argc, argv, options, report_usage, 0); |
896 | 841 | ||
@@ -940,7 +885,7 @@ repeat: | |||
940 | } | 885 | } |
941 | if (report.mem_mode) { | 886 | if (report.mem_mode) { |
942 | if (sort__mode == SORT_MODE__BRANCH) { | 887 | if (sort__mode == SORT_MODE__BRANCH) { |
943 | fprintf(stderr, "branch and mem mode incompatible\n"); | 888 | pr_err("branch and mem mode incompatible\n"); |
944 | goto error; | 889 | goto error; |
945 | } | 890 | } |
946 | sort__mode = SORT_MODE__MEMORY; | 891 | sort__mode = SORT_MODE__MEMORY; |
@@ -963,6 +908,10 @@ repeat: | |||
963 | goto error; | 908 | goto error; |
964 | } | 909 | } |
965 | 910 | ||
911 | /* Force tty output for header output. */ | ||
912 | if (report.header || report.header_only) | ||
913 | use_browser = 0; | ||
914 | |||
966 | if (strcmp(input_name, "-") != 0) | 915 | if (strcmp(input_name, "-") != 0) |
967 | setup_browser(true); | 916 | setup_browser(true); |
968 | else { | 917 | else { |
@@ -970,6 +919,16 @@ repeat: | |||
970 | perf_hpp__init(); | 919 | perf_hpp__init(); |
971 | } | 920 | } |
972 | 921 | ||
922 | if (report.header || report.header_only) { | ||
923 | perf_session__fprintf_info(session, stdout, | ||
924 | report.show_full_info); | ||
925 | if (report.header_only) | ||
926 | return 0; | ||
927 | } else if (use_browser == 0) { | ||
928 | fputs("# To display the perf.data header info, please use --header/--header-only options.\n#\n", | ||
929 | stdout); | ||
930 | } | ||
931 | |||
973 | /* | 932 | /* |
974 | * Only in the TUI browser we are doing integrated annotation, | 933 | * Only in the TUI browser we are doing integrated annotation, |
975 | * so don't allocate extra space that won't be used in the stdio | 934 | * so don't allocate extra space that won't be used in the stdio |
diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c index 0f3c65518a2c..6a76a07b6789 100644 --- a/tools/perf/builtin-sched.c +++ b/tools/perf/builtin-sched.c | |||
@@ -469,7 +469,7 @@ static void *thread_func(void *ctx) | |||
469 | char comm2[22]; | 469 | char comm2[22]; |
470 | int fd; | 470 | int fd; |
471 | 471 | ||
472 | free(parms); | 472 | zfree(&parms); |
473 | 473 | ||
474 | sprintf(comm2, ":%s", this_task->comm); | 474 | sprintf(comm2, ":%s", this_task->comm); |
475 | prctl(PR_SET_NAME, comm2); | 475 | prctl(PR_SET_NAME, comm2); |
diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c index baf17989a216..9e9c91f5b7fa 100644 --- a/tools/perf/builtin-script.c +++ b/tools/perf/builtin-script.c | |||
@@ -43,6 +43,7 @@ enum perf_output_field { | |||
43 | PERF_OUTPUT_DSO = 1U << 9, | 43 | PERF_OUTPUT_DSO = 1U << 9, |
44 | PERF_OUTPUT_ADDR = 1U << 10, | 44 | PERF_OUTPUT_ADDR = 1U << 10, |
45 | PERF_OUTPUT_SYMOFFSET = 1U << 11, | 45 | PERF_OUTPUT_SYMOFFSET = 1U << 11, |
46 | PERF_OUTPUT_SRCLINE = 1U << 12, | ||
46 | }; | 47 | }; |
47 | 48 | ||
48 | struct output_option { | 49 | struct output_option { |
@@ -61,6 +62,7 @@ struct output_option { | |||
61 | {.str = "dso", .field = PERF_OUTPUT_DSO}, | 62 | {.str = "dso", .field = PERF_OUTPUT_DSO}, |
62 | {.str = "addr", .field = PERF_OUTPUT_ADDR}, | 63 | {.str = "addr", .field = PERF_OUTPUT_ADDR}, |
63 | {.str = "symoff", .field = PERF_OUTPUT_SYMOFFSET}, | 64 | {.str = "symoff", .field = PERF_OUTPUT_SYMOFFSET}, |
65 | {.str = "srcline", .field = PERF_OUTPUT_SRCLINE}, | ||
64 | }; | 66 | }; |
65 | 67 | ||
66 | /* default set to maintain compatibility with current format */ | 68 | /* default set to maintain compatibility with current format */ |
@@ -210,6 +212,11 @@ static int perf_evsel__check_attr(struct perf_evsel *evsel, | |||
210 | "to DSO.\n"); | 212 | "to DSO.\n"); |
211 | return -EINVAL; | 213 | return -EINVAL; |
212 | } | 214 | } |
215 | if (PRINT_FIELD(SRCLINE) && !PRINT_FIELD(IP)) { | ||
216 | pr_err("Display of source line number requested but sample IP is not\n" | ||
217 | "selected. Hence, no address to lookup the source line number.\n"); | ||
218 | return -EINVAL; | ||
219 | } | ||
213 | 220 | ||
214 | if ((PRINT_FIELD(PID) || PRINT_FIELD(TID)) && | 221 | if ((PRINT_FIELD(PID) || PRINT_FIELD(TID)) && |
215 | perf_evsel__check_stype(evsel, PERF_SAMPLE_TID, "TID", | 222 | perf_evsel__check_stype(evsel, PERF_SAMPLE_TID, "TID", |
@@ -245,6 +252,9 @@ static void set_print_ip_opts(struct perf_event_attr *attr) | |||
245 | 252 | ||
246 | if (PRINT_FIELD(SYMOFFSET)) | 253 | if (PRINT_FIELD(SYMOFFSET)) |
247 | output[type].print_ip_opts |= PRINT_IP_OPT_SYMOFFSET; | 254 | output[type].print_ip_opts |= PRINT_IP_OPT_SYMOFFSET; |
255 | |||
256 | if (PRINT_FIELD(SRCLINE)) | ||
257 | output[type].print_ip_opts |= PRINT_IP_OPT_SRCLINE; | ||
248 | } | 258 | } |
249 | 259 | ||
250 | /* | 260 | /* |
@@ -280,6 +290,30 @@ static int perf_session__check_output_opt(struct perf_session *session) | |||
280 | set_print_ip_opts(&evsel->attr); | 290 | set_print_ip_opts(&evsel->attr); |
281 | } | 291 | } |
282 | 292 | ||
293 | /* | ||
294 | * set default for tracepoints to print symbols only | ||
295 | * if callchains are present | ||
296 | */ | ||
297 | if (symbol_conf.use_callchain && | ||
298 | !output[PERF_TYPE_TRACEPOINT].user_set) { | ||
299 | struct perf_event_attr *attr; | ||
300 | |||
301 | j = PERF_TYPE_TRACEPOINT; | ||
302 | evsel = perf_session__find_first_evtype(session, j); | ||
303 | if (evsel == NULL) | ||
304 | goto out; | ||
305 | |||
306 | attr = &evsel->attr; | ||
307 | |||
308 | if (attr->sample_type & PERF_SAMPLE_CALLCHAIN) { | ||
309 | output[j].fields |= PERF_OUTPUT_IP; | ||
310 | output[j].fields |= PERF_OUTPUT_SYM; | ||
311 | output[j].fields |= PERF_OUTPUT_DSO; | ||
312 | set_print_ip_opts(attr); | ||
313 | } | ||
314 | } | ||
315 | |||
316 | out: | ||
283 | return 0; | 317 | return 0; |
284 | } | 318 | } |
285 | 319 | ||
@@ -288,7 +322,6 @@ static void print_sample_start(struct perf_sample *sample, | |||
288 | struct perf_evsel *evsel) | 322 | struct perf_evsel *evsel) |
289 | { | 323 | { |
290 | struct perf_event_attr *attr = &evsel->attr; | 324 | struct perf_event_attr *attr = &evsel->attr; |
291 | const char *evname = NULL; | ||
292 | unsigned long secs; | 325 | unsigned long secs; |
293 | unsigned long usecs; | 326 | unsigned long usecs; |
294 | unsigned long long nsecs; | 327 | unsigned long long nsecs; |
@@ -323,11 +356,6 @@ static void print_sample_start(struct perf_sample *sample, | |||
323 | usecs = nsecs / NSECS_PER_USEC; | 356 | usecs = nsecs / NSECS_PER_USEC; |
324 | printf("%5lu.%06lu: ", secs, usecs); | 357 | printf("%5lu.%06lu: ", secs, usecs); |
325 | } | 358 | } |
326 | |||
327 | if (PRINT_FIELD(EVNAME)) { | ||
328 | evname = perf_evsel__name(evsel); | ||
329 | printf("%s: ", evname ? evname : "[unknown]"); | ||
330 | } | ||
331 | } | 359 | } |
332 | 360 | ||
333 | static bool is_bts_event(struct perf_event_attr *attr) | 361 | static bool is_bts_event(struct perf_event_attr *attr) |
@@ -395,8 +423,8 @@ static void print_sample_addr(union perf_event *event, | |||
395 | static void print_sample_bts(union perf_event *event, | 423 | static void print_sample_bts(union perf_event *event, |
396 | struct perf_sample *sample, | 424 | struct perf_sample *sample, |
397 | struct perf_evsel *evsel, | 425 | struct perf_evsel *evsel, |
398 | struct machine *machine, | 426 | struct thread *thread, |
399 | struct thread *thread) | 427 | struct addr_location *al) |
400 | { | 428 | { |
401 | struct perf_event_attr *attr = &evsel->attr; | 429 | struct perf_event_attr *attr = &evsel->attr; |
402 | 430 | ||
@@ -406,7 +434,7 @@ static void print_sample_bts(union perf_event *event, | |||
406 | printf(" "); | 434 | printf(" "); |
407 | else | 435 | else |
408 | printf("\n"); | 436 | printf("\n"); |
409 | perf_evsel__print_ip(evsel, event, sample, machine, | 437 | perf_evsel__print_ip(evsel, sample, al, |
410 | output[attr->type].print_ip_opts, | 438 | output[attr->type].print_ip_opts, |
411 | PERF_MAX_STACK_DEPTH); | 439 | PERF_MAX_STACK_DEPTH); |
412 | } | 440 | } |
@@ -417,15 +445,14 @@ static void print_sample_bts(union perf_event *event, | |||
417 | if (PRINT_FIELD(ADDR) || | 445 | if (PRINT_FIELD(ADDR) || |
418 | ((evsel->attr.sample_type & PERF_SAMPLE_ADDR) && | 446 | ((evsel->attr.sample_type & PERF_SAMPLE_ADDR) && |
419 | !output[attr->type].user_set)) | 447 | !output[attr->type].user_set)) |
420 | print_sample_addr(event, sample, machine, thread, attr); | 448 | print_sample_addr(event, sample, al->machine, thread, attr); |
421 | 449 | ||
422 | printf("\n"); | 450 | printf("\n"); |
423 | } | 451 | } |
424 | 452 | ||
425 | static void process_event(union perf_event *event, struct perf_sample *sample, | 453 | static void process_event(union perf_event *event, struct perf_sample *sample, |
426 | struct perf_evsel *evsel, struct machine *machine, | 454 | struct perf_evsel *evsel, struct thread *thread, |
427 | struct thread *thread, | 455 | struct addr_location *al) |
428 | struct addr_location *al __maybe_unused) | ||
429 | { | 456 | { |
430 | struct perf_event_attr *attr = &evsel->attr; | 457 | struct perf_event_attr *attr = &evsel->attr; |
431 | 458 | ||
@@ -434,8 +461,13 @@ static void process_event(union perf_event *event, struct perf_sample *sample, | |||
434 | 461 | ||
435 | print_sample_start(sample, thread, evsel); | 462 | print_sample_start(sample, thread, evsel); |
436 | 463 | ||
464 | if (PRINT_FIELD(EVNAME)) { | ||
465 | const char *evname = perf_evsel__name(evsel); | ||
466 | printf("%s: ", evname ? evname : "[unknown]"); | ||
467 | } | ||
468 | |||
437 | if (is_bts_event(attr)) { | 469 | if (is_bts_event(attr)) { |
438 | print_sample_bts(event, sample, evsel, machine, thread); | 470 | print_sample_bts(event, sample, evsel, thread, al); |
439 | return; | 471 | return; |
440 | } | 472 | } |
441 | 473 | ||
@@ -443,7 +475,7 @@ static void process_event(union perf_event *event, struct perf_sample *sample, | |||
443 | event_format__print(evsel->tp_format, sample->cpu, | 475 | event_format__print(evsel->tp_format, sample->cpu, |
444 | sample->raw_data, sample->raw_size); | 476 | sample->raw_data, sample->raw_size); |
445 | if (PRINT_FIELD(ADDR)) | 477 | if (PRINT_FIELD(ADDR)) |
446 | print_sample_addr(event, sample, machine, thread, attr); | 478 | print_sample_addr(event, sample, al->machine, thread, attr); |
447 | 479 | ||
448 | if (PRINT_FIELD(IP)) { | 480 | if (PRINT_FIELD(IP)) { |
449 | if (!symbol_conf.use_callchain) | 481 | if (!symbol_conf.use_callchain) |
@@ -451,7 +483,7 @@ static void process_event(union perf_event *event, struct perf_sample *sample, | |||
451 | else | 483 | else |
452 | printf("\n"); | 484 | printf("\n"); |
453 | 485 | ||
454 | perf_evsel__print_ip(evsel, event, sample, machine, | 486 | perf_evsel__print_ip(evsel, sample, al, |
455 | output[attr->type].print_ip_opts, | 487 | output[attr->type].print_ip_opts, |
456 | PERF_MAX_STACK_DEPTH); | 488 | PERF_MAX_STACK_DEPTH); |
457 | } | 489 | } |
@@ -540,7 +572,7 @@ static int process_sample_event(struct perf_tool *tool __maybe_unused, | |||
540 | if (cpu_list && !test_bit(sample->cpu, cpu_bitmap)) | 572 | if (cpu_list && !test_bit(sample->cpu, cpu_bitmap)) |
541 | return 0; | 573 | return 0; |
542 | 574 | ||
543 | scripting_ops->process_event(event, sample, evsel, machine, thread, &al); | 575 | scripting_ops->process_event(event, sample, evsel, thread, &al); |
544 | 576 | ||
545 | evsel->hists.stats.total_period += sample->period; | 577 | evsel->hists.stats.total_period += sample->period; |
546 | return 0; | 578 | return 0; |
@@ -549,6 +581,8 @@ static int process_sample_event(struct perf_tool *tool __maybe_unused, | |||
549 | struct perf_script { | 581 | struct perf_script { |
550 | struct perf_tool tool; | 582 | struct perf_tool tool; |
551 | struct perf_session *session; | 583 | struct perf_session *session; |
584 | bool show_task_events; | ||
585 | bool show_mmap_events; | ||
552 | }; | 586 | }; |
553 | 587 | ||
554 | static int process_attr(struct perf_tool *tool, union perf_event *event, | 588 | static int process_attr(struct perf_tool *tool, union perf_event *event, |
@@ -569,7 +603,7 @@ static int process_attr(struct perf_tool *tool, union perf_event *event, | |||
569 | if (evsel->attr.type >= PERF_TYPE_MAX) | 603 | if (evsel->attr.type >= PERF_TYPE_MAX) |
570 | return 0; | 604 | return 0; |
571 | 605 | ||
572 | list_for_each_entry(pos, &evlist->entries, node) { | 606 | evlist__for_each(evlist, pos) { |
573 | if (pos->attr.type == evsel->attr.type && pos != evsel) | 607 | if (pos->attr.type == evsel->attr.type && pos != evsel) |
574 | return 0; | 608 | return 0; |
575 | } | 609 | } |
@@ -579,6 +613,163 @@ static int process_attr(struct perf_tool *tool, union perf_event *event, | |||
579 | return perf_evsel__check_attr(evsel, scr->session); | 613 | return perf_evsel__check_attr(evsel, scr->session); |
580 | } | 614 | } |
581 | 615 | ||
616 | static int process_comm_event(struct perf_tool *tool, | ||
617 | union perf_event *event, | ||
618 | struct perf_sample *sample, | ||
619 | struct machine *machine) | ||
620 | { | ||
621 | struct thread *thread; | ||
622 | struct perf_script *script = container_of(tool, struct perf_script, tool); | ||
623 | struct perf_session *session = script->session; | ||
624 | struct perf_evsel *evsel = perf_evlist__first(session->evlist); | ||
625 | int ret = -1; | ||
626 | |||
627 | thread = machine__findnew_thread(machine, event->comm.pid, event->comm.tid); | ||
628 | if (thread == NULL) { | ||
629 | pr_debug("problem processing COMM event, skipping it.\n"); | ||
630 | return -1; | ||
631 | } | ||
632 | |||
633 | if (perf_event__process_comm(tool, event, sample, machine) < 0) | ||
634 | goto out; | ||
635 | |||
636 | if (!evsel->attr.sample_id_all) { | ||
637 | sample->cpu = 0; | ||
638 | sample->time = 0; | ||
639 | sample->tid = event->comm.tid; | ||
640 | sample->pid = event->comm.pid; | ||
641 | } | ||
642 | print_sample_start(sample, thread, evsel); | ||
643 | perf_event__fprintf(event, stdout); | ||
644 | ret = 0; | ||
645 | |||
646 | out: | ||
647 | return ret; | ||
648 | } | ||
649 | |||
650 | static int process_fork_event(struct perf_tool *tool, | ||
651 | union perf_event *event, | ||
652 | struct perf_sample *sample, | ||
653 | struct machine *machine) | ||
654 | { | ||
655 | struct thread *thread; | ||
656 | struct perf_script *script = container_of(tool, struct perf_script, tool); | ||
657 | struct perf_session *session = script->session; | ||
658 | struct perf_evsel *evsel = perf_evlist__first(session->evlist); | ||
659 | |||
660 | if (perf_event__process_fork(tool, event, sample, machine) < 0) | ||
661 | return -1; | ||
662 | |||
663 | thread = machine__findnew_thread(machine, event->fork.pid, event->fork.tid); | ||
664 | if (thread == NULL) { | ||
665 | pr_debug("problem processing FORK event, skipping it.\n"); | ||
666 | return -1; | ||
667 | } | ||
668 | |||
669 | if (!evsel->attr.sample_id_all) { | ||
670 | sample->cpu = 0; | ||
671 | sample->time = event->fork.time; | ||
672 | sample->tid = event->fork.tid; | ||
673 | sample->pid = event->fork.pid; | ||
674 | } | ||
675 | print_sample_start(sample, thread, evsel); | ||
676 | perf_event__fprintf(event, stdout); | ||
677 | |||
678 | return 0; | ||
679 | } | ||
680 | static int process_exit_event(struct perf_tool *tool, | ||
681 | union perf_event *event, | ||
682 | struct perf_sample *sample, | ||
683 | struct machine *machine) | ||
684 | { | ||
685 | struct thread *thread; | ||
686 | struct perf_script *script = container_of(tool, struct perf_script, tool); | ||
687 | struct perf_session *session = script->session; | ||
688 | struct perf_evsel *evsel = perf_evlist__first(session->evlist); | ||
689 | |||
690 | thread = machine__findnew_thread(machine, event->fork.pid, event->fork.tid); | ||
691 | if (thread == NULL) { | ||
692 | pr_debug("problem processing EXIT event, skipping it.\n"); | ||
693 | return -1; | ||
694 | } | ||
695 | |||
696 | if (!evsel->attr.sample_id_all) { | ||
697 | sample->cpu = 0; | ||
698 | sample->time = 0; | ||
699 | sample->tid = event->comm.tid; | ||
700 | sample->pid = event->comm.pid; | ||
701 | } | ||
702 | print_sample_start(sample, thread, evsel); | ||
703 | perf_event__fprintf(event, stdout); | ||
704 | |||
705 | if (perf_event__process_exit(tool, event, sample, machine) < 0) | ||
706 | return -1; | ||
707 | |||
708 | return 0; | ||
709 | } | ||
710 | |||
711 | static int process_mmap_event(struct perf_tool *tool, | ||
712 | union perf_event *event, | ||
713 | struct perf_sample *sample, | ||
714 | struct machine *machine) | ||
715 | { | ||
716 | struct thread *thread; | ||
717 | struct perf_script *script = container_of(tool, struct perf_script, tool); | ||
718 | struct perf_session *session = script->session; | ||
719 | struct perf_evsel *evsel = perf_evlist__first(session->evlist); | ||
720 | |||
721 | if (perf_event__process_mmap(tool, event, sample, machine) < 0) | ||
722 | return -1; | ||
723 | |||
724 | thread = machine__findnew_thread(machine, event->mmap.pid, event->mmap.tid); | ||
725 | if (thread == NULL) { | ||
726 | pr_debug("problem processing MMAP event, skipping it.\n"); | ||
727 | return -1; | ||
728 | } | ||
729 | |||
730 | if (!evsel->attr.sample_id_all) { | ||
731 | sample->cpu = 0; | ||
732 | sample->time = 0; | ||
733 | sample->tid = event->mmap.tid; | ||
734 | sample->pid = event->mmap.pid; | ||
735 | } | ||
736 | print_sample_start(sample, thread, evsel); | ||
737 | perf_event__fprintf(event, stdout); | ||
738 | |||
739 | return 0; | ||
740 | } | ||
741 | |||
742 | static int process_mmap2_event(struct perf_tool *tool, | ||
743 | union perf_event *event, | ||
744 | struct perf_sample *sample, | ||
745 | struct machine *machine) | ||
746 | { | ||
747 | struct thread *thread; | ||
748 | struct perf_script *script = container_of(tool, struct perf_script, tool); | ||
749 | struct perf_session *session = script->session; | ||
750 | struct perf_evsel *evsel = perf_evlist__first(session->evlist); | ||
751 | |||
752 | if (perf_event__process_mmap2(tool, event, sample, machine) < 0) | ||
753 | return -1; | ||
754 | |||
755 | thread = machine__findnew_thread(machine, event->mmap2.pid, event->mmap2.tid); | ||
756 | if (thread == NULL) { | ||
757 | pr_debug("problem processing MMAP2 event, skipping it.\n"); | ||
758 | return -1; | ||
759 | } | ||
760 | |||
761 | if (!evsel->attr.sample_id_all) { | ||
762 | sample->cpu = 0; | ||
763 | sample->time = 0; | ||
764 | sample->tid = event->mmap2.tid; | ||
765 | sample->pid = event->mmap2.pid; | ||
766 | } | ||
767 | print_sample_start(sample, thread, evsel); | ||
768 | perf_event__fprintf(event, stdout); | ||
769 | |||
770 | return 0; | ||
771 | } | ||
772 | |||
582 | static void sig_handler(int sig __maybe_unused) | 773 | static void sig_handler(int sig __maybe_unused) |
583 | { | 774 | { |
584 | session_done = 1; | 775 | session_done = 1; |
@@ -590,6 +781,17 @@ static int __cmd_script(struct perf_script *script) | |||
590 | 781 | ||
591 | signal(SIGINT, sig_handler); | 782 | signal(SIGINT, sig_handler); |
592 | 783 | ||
784 | /* override event processing functions */ | ||
785 | if (script->show_task_events) { | ||
786 | script->tool.comm = process_comm_event; | ||
787 | script->tool.fork = process_fork_event; | ||
788 | script->tool.exit = process_exit_event; | ||
789 | } | ||
790 | if (script->show_mmap_events) { | ||
791 | script->tool.mmap = process_mmap_event; | ||
792 | script->tool.mmap2 = process_mmap2_event; | ||
793 | } | ||
794 | |||
593 | ret = perf_session__process_events(script->session, &script->tool); | 795 | ret = perf_session__process_events(script->session, &script->tool); |
594 | 796 | ||
595 | if (debug_mode) | 797 | if (debug_mode) |
@@ -900,9 +1102,9 @@ static struct script_desc *script_desc__new(const char *name) | |||
900 | 1102 | ||
901 | static void script_desc__delete(struct script_desc *s) | 1103 | static void script_desc__delete(struct script_desc *s) |
902 | { | 1104 | { |
903 | free(s->name); | 1105 | zfree(&s->name); |
904 | free(s->half_liner); | 1106 | zfree(&s->half_liner); |
905 | free(s->args); | 1107 | zfree(&s->args); |
906 | free(s); | 1108 | free(s); |
907 | } | 1109 | } |
908 | 1110 | ||
@@ -1107,8 +1309,7 @@ static int check_ev_match(char *dir_name, char *scriptname, | |||
1107 | snprintf(evname, len + 1, "%s", p); | 1309 | snprintf(evname, len + 1, "%s", p); |
1108 | 1310 | ||
1109 | match = 0; | 1311 | match = 0; |
1110 | list_for_each_entry(pos, | 1312 | evlist__for_each(session->evlist, pos) { |
1111 | &session->evlist->entries, node) { | ||
1112 | if (!strcmp(perf_evsel__name(pos), evname)) { | 1313 | if (!strcmp(perf_evsel__name(pos), evname)) { |
1113 | match = 1; | 1314 | match = 1; |
1114 | break; | 1315 | break; |
@@ -1290,6 +1491,8 @@ static int have_cmd(int argc, const char **argv) | |||
1290 | int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused) | 1491 | int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused) |
1291 | { | 1492 | { |
1292 | bool show_full_info = false; | 1493 | bool show_full_info = false; |
1494 | bool header = false; | ||
1495 | bool header_only = false; | ||
1293 | char *rec_script_path = NULL; | 1496 | char *rec_script_path = NULL; |
1294 | char *rep_script_path = NULL; | 1497 | char *rep_script_path = NULL; |
1295 | struct perf_session *session; | 1498 | struct perf_session *session; |
@@ -1328,6 +1531,8 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused) | |||
1328 | OPT_STRING('i', "input", &input_name, "file", "input file name"), | 1531 | OPT_STRING('i', "input", &input_name, "file", "input file name"), |
1329 | OPT_BOOLEAN('d', "debug-mode", &debug_mode, | 1532 | OPT_BOOLEAN('d', "debug-mode", &debug_mode, |
1330 | "do various checks like samples ordering and lost events"), | 1533 | "do various checks like samples ordering and lost events"), |
1534 | OPT_BOOLEAN(0, "header", &header, "Show data header."), | ||
1535 | OPT_BOOLEAN(0, "header-only", &header_only, "Show only data header."), | ||
1331 | OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name, | 1536 | OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name, |
1332 | "file", "vmlinux pathname"), | 1537 | "file", "vmlinux pathname"), |
1333 | OPT_STRING(0, "kallsyms", &symbol_conf.kallsyms_name, | 1538 | OPT_STRING(0, "kallsyms", &symbol_conf.kallsyms_name, |
@@ -1352,6 +1557,10 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused) | |||
1352 | "display extended information from perf.data file"), | 1557 | "display extended information from perf.data file"), |
1353 | OPT_BOOLEAN('\0', "show-kernel-path", &symbol_conf.show_kernel_path, | 1558 | OPT_BOOLEAN('\0', "show-kernel-path", &symbol_conf.show_kernel_path, |
1354 | "Show the path of [kernel.kallsyms]"), | 1559 | "Show the path of [kernel.kallsyms]"), |
1560 | OPT_BOOLEAN('\0', "show-task-events", &script.show_task_events, | ||
1561 | "Show the fork/comm/exit events"), | ||
1562 | OPT_BOOLEAN('\0', "show-mmap-events", &script.show_mmap_events, | ||
1563 | "Show the mmap events"), | ||
1355 | OPT_END() | 1564 | OPT_END() |
1356 | }; | 1565 | }; |
1357 | const char * const script_usage[] = { | 1566 | const char * const script_usage[] = { |
@@ -1540,6 +1749,12 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused) | |||
1540 | if (session == NULL) | 1749 | if (session == NULL) |
1541 | return -ENOMEM; | 1750 | return -ENOMEM; |
1542 | 1751 | ||
1752 | if (header || header_only) { | ||
1753 | perf_session__fprintf_info(session, stdout, show_full_info); | ||
1754 | if (header_only) | ||
1755 | return 0; | ||
1756 | } | ||
1757 | |||
1543 | script.session = session; | 1758 | script.session = session; |
1544 | 1759 | ||
1545 | if (cpu_list) { | 1760 | if (cpu_list) { |
@@ -1547,9 +1762,6 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused) | |||
1547 | return -1; | 1762 | return -1; |
1548 | } | 1763 | } |
1549 | 1764 | ||
1550 | if (!script_name && !generate_script_lang) | ||
1551 | perf_session__fprintf_info(session, stdout, show_full_info); | ||
1552 | |||
1553 | if (!no_callchain) | 1765 | if (!no_callchain) |
1554 | symbol_conf.use_callchain = true; | 1766 | symbol_conf.use_callchain = true; |
1555 | else | 1767 | else |
@@ -1588,7 +1800,7 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused) | |||
1588 | return -1; | 1800 | return -1; |
1589 | } | 1801 | } |
1590 | 1802 | ||
1591 | err = scripting_ops->generate_script(session->pevent, | 1803 | err = scripting_ops->generate_script(session->tevent.pevent, |
1592 | "perf-script"); | 1804 | "perf-script"); |
1593 | goto out; | 1805 | goto out; |
1594 | } | 1806 | } |
diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index ee0d565f83e3..8b0e1c9234d9 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c | |||
@@ -138,6 +138,7 @@ static const char *post_cmd = NULL; | |||
138 | static bool sync_run = false; | 138 | static bool sync_run = false; |
139 | static unsigned int interval = 0; | 139 | static unsigned int interval = 0; |
140 | static unsigned int initial_delay = 0; | 140 | static unsigned int initial_delay = 0; |
141 | static unsigned int unit_width = 4; /* strlen("unit") */ | ||
141 | static bool forever = false; | 142 | static bool forever = false; |
142 | static struct timespec ref_time; | 143 | static struct timespec ref_time; |
143 | static struct cpu_map *aggr_map; | 144 | static struct cpu_map *aggr_map; |
@@ -184,8 +185,7 @@ static int perf_evsel__alloc_stat_priv(struct perf_evsel *evsel) | |||
184 | 185 | ||
185 | static void perf_evsel__free_stat_priv(struct perf_evsel *evsel) | 186 | static void perf_evsel__free_stat_priv(struct perf_evsel *evsel) |
186 | { | 187 | { |
187 | free(evsel->priv); | 188 | zfree(&evsel->priv); |
188 | evsel->priv = NULL; | ||
189 | } | 189 | } |
190 | 190 | ||
191 | static int perf_evsel__alloc_prev_raw_counts(struct perf_evsel *evsel) | 191 | static int perf_evsel__alloc_prev_raw_counts(struct perf_evsel *evsel) |
@@ -207,15 +207,14 @@ static int perf_evsel__alloc_prev_raw_counts(struct perf_evsel *evsel) | |||
207 | 207 | ||
208 | static void perf_evsel__free_prev_raw_counts(struct perf_evsel *evsel) | 208 | static void perf_evsel__free_prev_raw_counts(struct perf_evsel *evsel) |
209 | { | 209 | { |
210 | free(evsel->prev_raw_counts); | 210 | zfree(&evsel->prev_raw_counts); |
211 | evsel->prev_raw_counts = NULL; | ||
212 | } | 211 | } |
213 | 212 | ||
214 | static void perf_evlist__free_stats(struct perf_evlist *evlist) | 213 | static void perf_evlist__free_stats(struct perf_evlist *evlist) |
215 | { | 214 | { |
216 | struct perf_evsel *evsel; | 215 | struct perf_evsel *evsel; |
217 | 216 | ||
218 | list_for_each_entry(evsel, &evlist->entries, node) { | 217 | evlist__for_each(evlist, evsel) { |
219 | perf_evsel__free_stat_priv(evsel); | 218 | perf_evsel__free_stat_priv(evsel); |
220 | perf_evsel__free_counts(evsel); | 219 | perf_evsel__free_counts(evsel); |
221 | perf_evsel__free_prev_raw_counts(evsel); | 220 | perf_evsel__free_prev_raw_counts(evsel); |
@@ -226,7 +225,7 @@ static int perf_evlist__alloc_stats(struct perf_evlist *evlist, bool alloc_raw) | |||
226 | { | 225 | { |
227 | struct perf_evsel *evsel; | 226 | struct perf_evsel *evsel; |
228 | 227 | ||
229 | list_for_each_entry(evsel, &evlist->entries, node) { | 228 | evlist__for_each(evlist, evsel) { |
230 | if (perf_evsel__alloc_stat_priv(evsel) < 0 || | 229 | if (perf_evsel__alloc_stat_priv(evsel) < 0 || |
231 | perf_evsel__alloc_counts(evsel, perf_evsel__nr_cpus(evsel)) < 0 || | 230 | perf_evsel__alloc_counts(evsel, perf_evsel__nr_cpus(evsel)) < 0 || |
232 | (alloc_raw && perf_evsel__alloc_prev_raw_counts(evsel) < 0)) | 231 | (alloc_raw && perf_evsel__alloc_prev_raw_counts(evsel) < 0)) |
@@ -260,7 +259,7 @@ static void perf_stat__reset_stats(struct perf_evlist *evlist) | |||
260 | { | 259 | { |
261 | struct perf_evsel *evsel; | 260 | struct perf_evsel *evsel; |
262 | 261 | ||
263 | list_for_each_entry(evsel, &evlist->entries, node) { | 262 | evlist__for_each(evlist, evsel) { |
264 | perf_evsel__reset_stat_priv(evsel); | 263 | perf_evsel__reset_stat_priv(evsel); |
265 | perf_evsel__reset_counts(evsel, perf_evsel__nr_cpus(evsel)); | 264 | perf_evsel__reset_counts(evsel, perf_evsel__nr_cpus(evsel)); |
266 | } | 265 | } |
@@ -327,13 +326,13 @@ static struct perf_evsel *nth_evsel(int n) | |||
327 | 326 | ||
328 | /* Assumes this only called when evsel_list does not change anymore. */ | 327 | /* Assumes this only called when evsel_list does not change anymore. */ |
329 | if (!array) { | 328 | if (!array) { |
330 | list_for_each_entry(ev, &evsel_list->entries, node) | 329 | evlist__for_each(evsel_list, ev) |
331 | array_len++; | 330 | array_len++; |
332 | array = malloc(array_len * sizeof(void *)); | 331 | array = malloc(array_len * sizeof(void *)); |
333 | if (!array) | 332 | if (!array) |
334 | exit(ENOMEM); | 333 | exit(ENOMEM); |
335 | j = 0; | 334 | j = 0; |
336 | list_for_each_entry(ev, &evsel_list->entries, node) | 335 | evlist__for_each(evsel_list, ev) |
337 | array[j++] = ev; | 336 | array[j++] = ev; |
338 | } | 337 | } |
339 | if (n < array_len) | 338 | if (n < array_len) |
@@ -441,13 +440,13 @@ static void print_interval(void) | |||
441 | char prefix[64]; | 440 | char prefix[64]; |
442 | 441 | ||
443 | if (aggr_mode == AGGR_GLOBAL) { | 442 | if (aggr_mode == AGGR_GLOBAL) { |
444 | list_for_each_entry(counter, &evsel_list->entries, node) { | 443 | evlist__for_each(evsel_list, counter) { |
445 | ps = counter->priv; | 444 | ps = counter->priv; |
446 | memset(ps->res_stats, 0, sizeof(ps->res_stats)); | 445 | memset(ps->res_stats, 0, sizeof(ps->res_stats)); |
447 | read_counter_aggr(counter); | 446 | read_counter_aggr(counter); |
448 | } | 447 | } |
449 | } else { | 448 | } else { |
450 | list_for_each_entry(counter, &evsel_list->entries, node) { | 449 | evlist__for_each(evsel_list, counter) { |
451 | ps = counter->priv; | 450 | ps = counter->priv; |
452 | memset(ps->res_stats, 0, sizeof(ps->res_stats)); | 451 | memset(ps->res_stats, 0, sizeof(ps->res_stats)); |
453 | read_counter(counter); | 452 | read_counter(counter); |
@@ -461,17 +460,17 @@ static void print_interval(void) | |||
461 | if (num_print_interval == 0 && !csv_output) { | 460 | if (num_print_interval == 0 && !csv_output) { |
462 | switch (aggr_mode) { | 461 | switch (aggr_mode) { |
463 | case AGGR_SOCKET: | 462 | case AGGR_SOCKET: |
464 | fprintf(output, "# time socket cpus counts events\n"); | 463 | fprintf(output, "# time socket cpus counts %*s events\n", unit_width, "unit"); |
465 | break; | 464 | break; |
466 | case AGGR_CORE: | 465 | case AGGR_CORE: |
467 | fprintf(output, "# time core cpus counts events\n"); | 466 | fprintf(output, "# time core cpus counts %*s events\n", unit_width, "unit"); |
468 | break; | 467 | break; |
469 | case AGGR_NONE: | 468 | case AGGR_NONE: |
470 | fprintf(output, "# time CPU counts events\n"); | 469 | fprintf(output, "# time CPU counts %*s events\n", unit_width, "unit"); |
471 | break; | 470 | break; |
472 | case AGGR_GLOBAL: | 471 | case AGGR_GLOBAL: |
473 | default: | 472 | default: |
474 | fprintf(output, "# time counts events\n"); | 473 | fprintf(output, "# time counts %*s events\n", unit_width, "unit"); |
475 | } | 474 | } |
476 | } | 475 | } |
477 | 476 | ||
@@ -484,12 +483,12 @@ static void print_interval(void) | |||
484 | print_aggr(prefix); | 483 | print_aggr(prefix); |
485 | break; | 484 | break; |
486 | case AGGR_NONE: | 485 | case AGGR_NONE: |
487 | list_for_each_entry(counter, &evsel_list->entries, node) | 486 | evlist__for_each(evsel_list, counter) |
488 | print_counter(counter, prefix); | 487 | print_counter(counter, prefix); |
489 | break; | 488 | break; |
490 | case AGGR_GLOBAL: | 489 | case AGGR_GLOBAL: |
491 | default: | 490 | default: |
492 | list_for_each_entry(counter, &evsel_list->entries, node) | 491 | evlist__for_each(evsel_list, counter) |
493 | print_counter_aggr(counter, prefix); | 492 | print_counter_aggr(counter, prefix); |
494 | } | 493 | } |
495 | 494 | ||
@@ -505,17 +504,31 @@ static void handle_initial_delay(void) | |||
505 | nthreads = thread_map__nr(evsel_list->threads); | 504 | nthreads = thread_map__nr(evsel_list->threads); |
506 | 505 | ||
507 | usleep(initial_delay * 1000); | 506 | usleep(initial_delay * 1000); |
508 | list_for_each_entry(counter, &evsel_list->entries, node) | 507 | evlist__for_each(evsel_list, counter) |
509 | perf_evsel__enable(counter, ncpus, nthreads); | 508 | perf_evsel__enable(counter, ncpus, nthreads); |
510 | } | 509 | } |
511 | } | 510 | } |
512 | 511 | ||
512 | static volatile int workload_exec_errno; | ||
513 | |||
514 | /* | ||
515 | * perf_evlist__prepare_workload will send a SIGUSR1 | ||
516 | * if the fork fails, since we asked by setting its | ||
517 | * want_signal to true. | ||
518 | */ | ||
519 | static void workload_exec_failed_signal(int signo __maybe_unused, siginfo_t *info, | ||
520 | void *ucontext __maybe_unused) | ||
521 | { | ||
522 | workload_exec_errno = info->si_value.sival_int; | ||
523 | } | ||
524 | |||
513 | static int __run_perf_stat(int argc, const char **argv) | 525 | static int __run_perf_stat(int argc, const char **argv) |
514 | { | 526 | { |
515 | char msg[512]; | 527 | char msg[512]; |
516 | unsigned long long t0, t1; | 528 | unsigned long long t0, t1; |
517 | struct perf_evsel *counter; | 529 | struct perf_evsel *counter; |
518 | struct timespec ts; | 530 | struct timespec ts; |
531 | size_t l; | ||
519 | int status = 0; | 532 | int status = 0; |
520 | const bool forks = (argc > 0); | 533 | const bool forks = (argc > 0); |
521 | 534 | ||
@@ -528,8 +541,8 @@ static int __run_perf_stat(int argc, const char **argv) | |||
528 | } | 541 | } |
529 | 542 | ||
530 | if (forks) { | 543 | if (forks) { |
531 | if (perf_evlist__prepare_workload(evsel_list, &target, argv, | 544 | if (perf_evlist__prepare_workload(evsel_list, &target, argv, false, |
532 | false, false) < 0) { | 545 | workload_exec_failed_signal) < 0) { |
533 | perror("failed to prepare workload"); | 546 | perror("failed to prepare workload"); |
534 | return -1; | 547 | return -1; |
535 | } | 548 | } |
@@ -539,7 +552,7 @@ static int __run_perf_stat(int argc, const char **argv) | |||
539 | if (group) | 552 | if (group) |
540 | perf_evlist__set_leader(evsel_list); | 553 | perf_evlist__set_leader(evsel_list); |
541 | 554 | ||
542 | list_for_each_entry(counter, &evsel_list->entries, node) { | 555 | evlist__for_each(evsel_list, counter) { |
543 | if (create_perf_stat_counter(counter) < 0) { | 556 | if (create_perf_stat_counter(counter) < 0) { |
544 | /* | 557 | /* |
545 | * PPC returns ENXIO for HW counters until 2.6.37 | 558 | * PPC returns ENXIO for HW counters until 2.6.37 |
@@ -565,6 +578,10 @@ static int __run_perf_stat(int argc, const char **argv) | |||
565 | return -1; | 578 | return -1; |
566 | } | 579 | } |
567 | counter->supported = true; | 580 | counter->supported = true; |
581 | |||
582 | l = strlen(counter->unit); | ||
583 | if (l > unit_width) | ||
584 | unit_width = l; | ||
568 | } | 585 | } |
569 | 586 | ||
570 | if (perf_evlist__apply_filters(evsel_list)) { | 587 | if (perf_evlist__apply_filters(evsel_list)) { |
@@ -590,6 +607,13 @@ static int __run_perf_stat(int argc, const char **argv) | |||
590 | } | 607 | } |
591 | } | 608 | } |
592 | wait(&status); | 609 | wait(&status); |
610 | |||
611 | if (workload_exec_errno) { | ||
612 | const char *emsg = strerror_r(workload_exec_errno, msg, sizeof(msg)); | ||
613 | pr_err("Workload failed: %s\n", emsg); | ||
614 | return -1; | ||
615 | } | ||
616 | |||
593 | if (WIFSIGNALED(status)) | 617 | if (WIFSIGNALED(status)) |
594 | psignal(WTERMSIG(status), argv[0]); | 618 | psignal(WTERMSIG(status), argv[0]); |
595 | } else { | 619 | } else { |
@@ -606,13 +630,13 @@ static int __run_perf_stat(int argc, const char **argv) | |||
606 | update_stats(&walltime_nsecs_stats, t1 - t0); | 630 | update_stats(&walltime_nsecs_stats, t1 - t0); |
607 | 631 | ||
608 | if (aggr_mode == AGGR_GLOBAL) { | 632 | if (aggr_mode == AGGR_GLOBAL) { |
609 | list_for_each_entry(counter, &evsel_list->entries, node) { | 633 | evlist__for_each(evsel_list, counter) { |
610 | read_counter_aggr(counter); | 634 | read_counter_aggr(counter); |
611 | perf_evsel__close_fd(counter, perf_evsel__nr_cpus(counter), | 635 | perf_evsel__close_fd(counter, perf_evsel__nr_cpus(counter), |
612 | thread_map__nr(evsel_list->threads)); | 636 | thread_map__nr(evsel_list->threads)); |
613 | } | 637 | } |
614 | } else { | 638 | } else { |
615 | list_for_each_entry(counter, &evsel_list->entries, node) { | 639 | evlist__for_each(evsel_list, counter) { |
616 | read_counter(counter); | 640 | read_counter(counter); |
617 | perf_evsel__close_fd(counter, perf_evsel__nr_cpus(counter), 1); | 641 | perf_evsel__close_fd(counter, perf_evsel__nr_cpus(counter), 1); |
618 | } | 642 | } |
@@ -621,7 +645,7 @@ static int __run_perf_stat(int argc, const char **argv) | |||
621 | return WEXITSTATUS(status); | 645 | return WEXITSTATUS(status); |
622 | } | 646 | } |
623 | 647 | ||
624 | static int run_perf_stat(int argc __maybe_unused, const char **argv) | 648 | static int run_perf_stat(int argc, const char **argv) |
625 | { | 649 | { |
626 | int ret; | 650 | int ret; |
627 | 651 | ||
@@ -704,14 +728,25 @@ static void aggr_printout(struct perf_evsel *evsel, int id, int nr) | |||
704 | static void nsec_printout(int cpu, int nr, struct perf_evsel *evsel, double avg) | 728 | static void nsec_printout(int cpu, int nr, struct perf_evsel *evsel, double avg) |
705 | { | 729 | { |
706 | double msecs = avg / 1e6; | 730 | double msecs = avg / 1e6; |
707 | const char *fmt = csv_output ? "%.6f%s%s" : "%18.6f%s%-25s"; | 731 | const char *fmt_v, *fmt_n; |
708 | char name[25]; | 732 | char name[25]; |
709 | 733 | ||
734 | fmt_v = csv_output ? "%.6f%s" : "%18.6f%s"; | ||
735 | fmt_n = csv_output ? "%s" : "%-25s"; | ||
736 | |||
710 | aggr_printout(evsel, cpu, nr); | 737 | aggr_printout(evsel, cpu, nr); |
711 | 738 | ||
712 | scnprintf(name, sizeof(name), "%s%s", | 739 | scnprintf(name, sizeof(name), "%s%s", |
713 | perf_evsel__name(evsel), csv_output ? "" : " (msec)"); | 740 | perf_evsel__name(evsel), csv_output ? "" : " (msec)"); |
714 | fprintf(output, fmt, msecs, csv_sep, name); | 741 | |
742 | fprintf(output, fmt_v, msecs, csv_sep); | ||
743 | |||
744 | if (csv_output) | ||
745 | fprintf(output, "%s%s", evsel->unit, csv_sep); | ||
746 | else | ||
747 | fprintf(output, "%-*s%s", unit_width, evsel->unit, csv_sep); | ||
748 | |||
749 | fprintf(output, fmt_n, name); | ||
715 | 750 | ||
716 | if (evsel->cgrp) | 751 | if (evsel->cgrp) |
717 | fprintf(output, "%s%s", csv_sep, evsel->cgrp->name); | 752 | fprintf(output, "%s%s", csv_sep, evsel->cgrp->name); |
@@ -908,21 +943,31 @@ static void print_ll_cache_misses(int cpu, | |||
908 | static void abs_printout(int cpu, int nr, struct perf_evsel *evsel, double avg) | 943 | static void abs_printout(int cpu, int nr, struct perf_evsel *evsel, double avg) |
909 | { | 944 | { |
910 | double total, ratio = 0.0, total2; | 945 | double total, ratio = 0.0, total2; |
946 | double sc = evsel->scale; | ||
911 | const char *fmt; | 947 | const char *fmt; |
912 | 948 | ||
913 | if (csv_output) | 949 | if (csv_output) { |
914 | fmt = "%.0f%s%s"; | 950 | fmt = sc != 1.0 ? "%.2f%s" : "%.0f%s"; |
915 | else if (big_num) | 951 | } else { |
916 | fmt = "%'18.0f%s%-25s"; | 952 | if (big_num) |
917 | else | 953 | fmt = sc != 1.0 ? "%'18.2f%s" : "%'18.0f%s"; |
918 | fmt = "%18.0f%s%-25s"; | 954 | else |
955 | fmt = sc != 1.0 ? "%18.2f%s" : "%18.0f%s"; | ||
956 | } | ||
919 | 957 | ||
920 | aggr_printout(evsel, cpu, nr); | 958 | aggr_printout(evsel, cpu, nr); |
921 | 959 | ||
922 | if (aggr_mode == AGGR_GLOBAL) | 960 | if (aggr_mode == AGGR_GLOBAL) |
923 | cpu = 0; | 961 | cpu = 0; |
924 | 962 | ||
925 | fprintf(output, fmt, avg, csv_sep, perf_evsel__name(evsel)); | 963 | fprintf(output, fmt, avg, csv_sep); |
964 | |||
965 | if (evsel->unit) | ||
966 | fprintf(output, "%-*s%s", | ||
967 | csv_output ? 0 : unit_width, | ||
968 | evsel->unit, csv_sep); | ||
969 | |||
970 | fprintf(output, "%-*s", csv_output ? 0 : 25, perf_evsel__name(evsel)); | ||
926 | 971 | ||
927 | if (evsel->cgrp) | 972 | if (evsel->cgrp) |
928 | fprintf(output, "%s%s", csv_sep, evsel->cgrp->name); | 973 | fprintf(output, "%s%s", csv_sep, evsel->cgrp->name); |
@@ -941,7 +986,10 @@ static void abs_printout(int cpu, int nr, struct perf_evsel *evsel, double avg) | |||
941 | 986 | ||
942 | if (total && avg) { | 987 | if (total && avg) { |
943 | ratio = total / avg; | 988 | ratio = total / avg; |
944 | fprintf(output, "\n # %5.2f stalled cycles per insn", ratio); | 989 | fprintf(output, "\n"); |
990 | if (aggr_mode == AGGR_NONE) | ||
991 | fprintf(output, " "); | ||
992 | fprintf(output, " # %5.2f stalled cycles per insn", ratio); | ||
945 | } | 993 | } |
946 | 994 | ||
947 | } else if (perf_evsel__match(evsel, HARDWARE, HW_BRANCH_MISSES) && | 995 | } else if (perf_evsel__match(evsel, HARDWARE, HW_BRANCH_MISSES) && |
@@ -1061,6 +1109,7 @@ static void print_aggr(char *prefix) | |||
1061 | { | 1109 | { |
1062 | struct perf_evsel *counter; | 1110 | struct perf_evsel *counter; |
1063 | int cpu, cpu2, s, s2, id, nr; | 1111 | int cpu, cpu2, s, s2, id, nr; |
1112 | double uval; | ||
1064 | u64 ena, run, val; | 1113 | u64 ena, run, val; |
1065 | 1114 | ||
1066 | if (!(aggr_map || aggr_get_id)) | 1115 | if (!(aggr_map || aggr_get_id)) |
@@ -1068,7 +1117,7 @@ static void print_aggr(char *prefix) | |||
1068 | 1117 | ||
1069 | for (s = 0; s < aggr_map->nr; s++) { | 1118 | for (s = 0; s < aggr_map->nr; s++) { |
1070 | id = aggr_map->map[s]; | 1119 | id = aggr_map->map[s]; |
1071 | list_for_each_entry(counter, &evsel_list->entries, node) { | 1120 | evlist__for_each(evsel_list, counter) { |
1072 | val = ena = run = 0; | 1121 | val = ena = run = 0; |
1073 | nr = 0; | 1122 | nr = 0; |
1074 | for (cpu = 0; cpu < perf_evsel__nr_cpus(counter); cpu++) { | 1123 | for (cpu = 0; cpu < perf_evsel__nr_cpus(counter); cpu++) { |
@@ -1087,11 +1136,17 @@ static void print_aggr(char *prefix) | |||
1087 | if (run == 0 || ena == 0) { | 1136 | if (run == 0 || ena == 0) { |
1088 | aggr_printout(counter, id, nr); | 1137 | aggr_printout(counter, id, nr); |
1089 | 1138 | ||
1090 | fprintf(output, "%*s%s%*s", | 1139 | fprintf(output, "%*s%s", |
1091 | csv_output ? 0 : 18, | 1140 | csv_output ? 0 : 18, |
1092 | counter->supported ? CNTR_NOT_COUNTED : CNTR_NOT_SUPPORTED, | 1141 | counter->supported ? CNTR_NOT_COUNTED : CNTR_NOT_SUPPORTED, |
1093 | csv_sep, | 1142 | csv_sep); |
1094 | csv_output ? 0 : -24, | 1143 | |
1144 | fprintf(output, "%-*s%s", | ||
1145 | csv_output ? 0 : unit_width, | ||
1146 | counter->unit, csv_sep); | ||
1147 | |||
1148 | fprintf(output, "%*s", | ||
1149 | csv_output ? 0 : -25, | ||
1095 | perf_evsel__name(counter)); | 1150 | perf_evsel__name(counter)); |
1096 | 1151 | ||
1097 | if (counter->cgrp) | 1152 | if (counter->cgrp) |
@@ -1101,11 +1156,12 @@ static void print_aggr(char *prefix) | |||
1101 | fputc('\n', output); | 1156 | fputc('\n', output); |
1102 | continue; | 1157 | continue; |
1103 | } | 1158 | } |
1159 | uval = val * counter->scale; | ||
1104 | 1160 | ||
1105 | if (nsec_counter(counter)) | 1161 | if (nsec_counter(counter)) |
1106 | nsec_printout(id, nr, counter, val); | 1162 | nsec_printout(id, nr, counter, uval); |
1107 | else | 1163 | else |
1108 | abs_printout(id, nr, counter, val); | 1164 | abs_printout(id, nr, counter, uval); |
1109 | 1165 | ||
1110 | if (!csv_output) { | 1166 | if (!csv_output) { |
1111 | print_noise(counter, 1.0); | 1167 | print_noise(counter, 1.0); |
@@ -1128,16 +1184,21 @@ static void print_counter_aggr(struct perf_evsel *counter, char *prefix) | |||
1128 | struct perf_stat *ps = counter->priv; | 1184 | struct perf_stat *ps = counter->priv; |
1129 | double avg = avg_stats(&ps->res_stats[0]); | 1185 | double avg = avg_stats(&ps->res_stats[0]); |
1130 | int scaled = counter->counts->scaled; | 1186 | int scaled = counter->counts->scaled; |
1187 | double uval; | ||
1131 | 1188 | ||
1132 | if (prefix) | 1189 | if (prefix) |
1133 | fprintf(output, "%s", prefix); | 1190 | fprintf(output, "%s", prefix); |
1134 | 1191 | ||
1135 | if (scaled == -1) { | 1192 | if (scaled == -1) { |
1136 | fprintf(output, "%*s%s%*s", | 1193 | fprintf(output, "%*s%s", |
1137 | csv_output ? 0 : 18, | 1194 | csv_output ? 0 : 18, |
1138 | counter->supported ? CNTR_NOT_COUNTED : CNTR_NOT_SUPPORTED, | 1195 | counter->supported ? CNTR_NOT_COUNTED : CNTR_NOT_SUPPORTED, |
1139 | csv_sep, | 1196 | csv_sep); |
1140 | csv_output ? 0 : -24, | 1197 | fprintf(output, "%-*s%s", |
1198 | csv_output ? 0 : unit_width, | ||
1199 | counter->unit, csv_sep); | ||
1200 | fprintf(output, "%*s", | ||
1201 | csv_output ? 0 : -25, | ||
1141 | perf_evsel__name(counter)); | 1202 | perf_evsel__name(counter)); |
1142 | 1203 | ||
1143 | if (counter->cgrp) | 1204 | if (counter->cgrp) |
@@ -1147,10 +1208,12 @@ static void print_counter_aggr(struct perf_evsel *counter, char *prefix) | |||
1147 | return; | 1208 | return; |
1148 | } | 1209 | } |
1149 | 1210 | ||
1211 | uval = avg * counter->scale; | ||
1212 | |||
1150 | if (nsec_counter(counter)) | 1213 | if (nsec_counter(counter)) |
1151 | nsec_printout(-1, 0, counter, avg); | 1214 | nsec_printout(-1, 0, counter, uval); |
1152 | else | 1215 | else |
1153 | abs_printout(-1, 0, counter, avg); | 1216 | abs_printout(-1, 0, counter, uval); |
1154 | 1217 | ||
1155 | print_noise(counter, avg); | 1218 | print_noise(counter, avg); |
1156 | 1219 | ||
@@ -1177,6 +1240,7 @@ static void print_counter_aggr(struct perf_evsel *counter, char *prefix) | |||
1177 | static void print_counter(struct perf_evsel *counter, char *prefix) | 1240 | static void print_counter(struct perf_evsel *counter, char *prefix) |
1178 | { | 1241 | { |
1179 | u64 ena, run, val; | 1242 | u64 ena, run, val; |
1243 | double uval; | ||
1180 | int cpu; | 1244 | int cpu; |
1181 | 1245 | ||
1182 | for (cpu = 0; cpu < perf_evsel__nr_cpus(counter); cpu++) { | 1246 | for (cpu = 0; cpu < perf_evsel__nr_cpus(counter); cpu++) { |
@@ -1188,14 +1252,20 @@ static void print_counter(struct perf_evsel *counter, char *prefix) | |||
1188 | fprintf(output, "%s", prefix); | 1252 | fprintf(output, "%s", prefix); |
1189 | 1253 | ||
1190 | if (run == 0 || ena == 0) { | 1254 | if (run == 0 || ena == 0) { |
1191 | fprintf(output, "CPU%*d%s%*s%s%*s", | 1255 | fprintf(output, "CPU%*d%s%*s%s", |
1192 | csv_output ? 0 : -4, | 1256 | csv_output ? 0 : -4, |
1193 | perf_evsel__cpus(counter)->map[cpu], csv_sep, | 1257 | perf_evsel__cpus(counter)->map[cpu], csv_sep, |
1194 | csv_output ? 0 : 18, | 1258 | csv_output ? 0 : 18, |
1195 | counter->supported ? CNTR_NOT_COUNTED : CNTR_NOT_SUPPORTED, | 1259 | counter->supported ? CNTR_NOT_COUNTED : CNTR_NOT_SUPPORTED, |
1196 | csv_sep, | 1260 | csv_sep); |
1197 | csv_output ? 0 : -24, | 1261 | |
1198 | perf_evsel__name(counter)); | 1262 | fprintf(output, "%-*s%s", |
1263 | csv_output ? 0 : unit_width, | ||
1264 | counter->unit, csv_sep); | ||
1265 | |||
1266 | fprintf(output, "%*s", | ||
1267 | csv_output ? 0 : -25, | ||
1268 | perf_evsel__name(counter)); | ||
1199 | 1269 | ||
1200 | if (counter->cgrp) | 1270 | if (counter->cgrp) |
1201 | fprintf(output, "%s%s", | 1271 | fprintf(output, "%s%s", |
@@ -1205,10 +1275,12 @@ static void print_counter(struct perf_evsel *counter, char *prefix) | |||
1205 | continue; | 1275 | continue; |
1206 | } | 1276 | } |
1207 | 1277 | ||
1278 | uval = val * counter->scale; | ||
1279 | |||
1208 | if (nsec_counter(counter)) | 1280 | if (nsec_counter(counter)) |
1209 | nsec_printout(cpu, 0, counter, val); | 1281 | nsec_printout(cpu, 0, counter, uval); |
1210 | else | 1282 | else |
1211 | abs_printout(cpu, 0, counter, val); | 1283 | abs_printout(cpu, 0, counter, uval); |
1212 | 1284 | ||
1213 | if (!csv_output) { | 1285 | if (!csv_output) { |
1214 | print_noise(counter, 1.0); | 1286 | print_noise(counter, 1.0); |
@@ -1256,11 +1328,11 @@ static void print_stat(int argc, const char **argv) | |||
1256 | print_aggr(NULL); | 1328 | print_aggr(NULL); |
1257 | break; | 1329 | break; |
1258 | case AGGR_GLOBAL: | 1330 | case AGGR_GLOBAL: |
1259 | list_for_each_entry(counter, &evsel_list->entries, node) | 1331 | evlist__for_each(evsel_list, counter) |
1260 | print_counter_aggr(counter, NULL); | 1332 | print_counter_aggr(counter, NULL); |
1261 | break; | 1333 | break; |
1262 | case AGGR_NONE: | 1334 | case AGGR_NONE: |
1263 | list_for_each_entry(counter, &evsel_list->entries, node) | 1335 | evlist__for_each(evsel_list, counter) |
1264 | print_counter(counter, NULL); | 1336 | print_counter(counter, NULL); |
1265 | break; | 1337 | break; |
1266 | default: | 1338 | default: |
@@ -1710,14 +1782,14 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused) | |||
1710 | if (interval && interval < 100) { | 1782 | if (interval && interval < 100) { |
1711 | pr_err("print interval must be >= 100ms\n"); | 1783 | pr_err("print interval must be >= 100ms\n"); |
1712 | parse_options_usage(stat_usage, options, "I", 1); | 1784 | parse_options_usage(stat_usage, options, "I", 1); |
1713 | goto out_free_maps; | 1785 | goto out; |
1714 | } | 1786 | } |
1715 | 1787 | ||
1716 | if (perf_evlist__alloc_stats(evsel_list, interval)) | 1788 | if (perf_evlist__alloc_stats(evsel_list, interval)) |
1717 | goto out_free_maps; | 1789 | goto out; |
1718 | 1790 | ||
1719 | if (perf_stat_init_aggr_mode()) | 1791 | if (perf_stat_init_aggr_mode()) |
1720 | goto out_free_maps; | 1792 | goto out; |
1721 | 1793 | ||
1722 | /* | 1794 | /* |
1723 | * We dont want to block the signals - that would cause | 1795 | * We dont want to block the signals - that would cause |
@@ -1749,8 +1821,6 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused) | |||
1749 | print_stat(argc, argv); | 1821 | print_stat(argc, argv); |
1750 | 1822 | ||
1751 | perf_evlist__free_stats(evsel_list); | 1823 | perf_evlist__free_stats(evsel_list); |
1752 | out_free_maps: | ||
1753 | perf_evlist__delete_maps(evsel_list); | ||
1754 | out: | 1824 | out: |
1755 | perf_evlist__delete(evsel_list); | 1825 | perf_evlist__delete(evsel_list); |
1756 | return status; | 1826 | return status; |
diff --git a/tools/perf/builtin-timechart.c b/tools/perf/builtin-timechart.c index 41c9bde2fb67..25526d6eae59 100644 --- a/tools/perf/builtin-timechart.c +++ b/tools/perf/builtin-timechart.c | |||
@@ -41,25 +41,29 @@ | |||
41 | #define SUPPORT_OLD_POWER_EVENTS 1 | 41 | #define SUPPORT_OLD_POWER_EVENTS 1 |
42 | #define PWR_EVENT_EXIT -1 | 42 | #define PWR_EVENT_EXIT -1 |
43 | 43 | ||
44 | |||
45 | static unsigned int numcpus; | ||
46 | static u64 min_freq; /* Lowest CPU frequency seen */ | ||
47 | static u64 max_freq; /* Highest CPU frequency seen */ | ||
48 | static u64 turbo_frequency; | ||
49 | |||
50 | static u64 first_time, last_time; | ||
51 | |||
52 | static bool power_only; | ||
53 | |||
54 | |||
55 | struct per_pid; | 44 | struct per_pid; |
56 | struct per_pidcomm; | ||
57 | |||
58 | struct cpu_sample; | ||
59 | struct power_event; | 45 | struct power_event; |
60 | struct wake_event; | 46 | struct wake_event; |
61 | 47 | ||
62 | struct sample_wrapper; | 48 | struct timechart { |
49 | struct perf_tool tool; | ||
50 | struct per_pid *all_data; | ||
51 | struct power_event *power_events; | ||
52 | struct wake_event *wake_events; | ||
53 | int proc_num; | ||
54 | unsigned int numcpus; | ||
55 | u64 min_freq, /* Lowest CPU frequency seen */ | ||
56 | max_freq, /* Highest CPU frequency seen */ | ||
57 | turbo_frequency, | ||
58 | first_time, last_time; | ||
59 | bool power_only, | ||
60 | tasks_only, | ||
61 | with_backtrace, | ||
62 | topology; | ||
63 | }; | ||
64 | |||
65 | struct per_pidcomm; | ||
66 | struct cpu_sample; | ||
63 | 67 | ||
64 | /* | 68 | /* |
65 | * Datastructure layout: | 69 | * Datastructure layout: |
@@ -124,10 +128,9 @@ struct cpu_sample { | |||
124 | u64 end_time; | 128 | u64 end_time; |
125 | int type; | 129 | int type; |
126 | int cpu; | 130 | int cpu; |
131 | const char *backtrace; | ||
127 | }; | 132 | }; |
128 | 133 | ||
129 | static struct per_pid *all_data; | ||
130 | |||
131 | #define CSTATE 1 | 134 | #define CSTATE 1 |
132 | #define PSTATE 2 | 135 | #define PSTATE 2 |
133 | 136 | ||
@@ -145,12 +148,9 @@ struct wake_event { | |||
145 | int waker; | 148 | int waker; |
146 | int wakee; | 149 | int wakee; |
147 | u64 time; | 150 | u64 time; |
151 | const char *backtrace; | ||
148 | }; | 152 | }; |
149 | 153 | ||
150 | static struct power_event *power_events; | ||
151 | static struct wake_event *wake_events; | ||
152 | |||
153 | struct process_filter; | ||
154 | struct process_filter { | 154 | struct process_filter { |
155 | char *name; | 155 | char *name; |
156 | int pid; | 156 | int pid; |
@@ -160,9 +160,9 @@ struct process_filter { | |||
160 | static struct process_filter *process_filter; | 160 | static struct process_filter *process_filter; |
161 | 161 | ||
162 | 162 | ||
163 | static struct per_pid *find_create_pid(int pid) | 163 | static struct per_pid *find_create_pid(struct timechart *tchart, int pid) |
164 | { | 164 | { |
165 | struct per_pid *cursor = all_data; | 165 | struct per_pid *cursor = tchart->all_data; |
166 | 166 | ||
167 | while (cursor) { | 167 | while (cursor) { |
168 | if (cursor->pid == pid) | 168 | if (cursor->pid == pid) |
@@ -172,16 +172,16 @@ static struct per_pid *find_create_pid(int pid) | |||
172 | cursor = zalloc(sizeof(*cursor)); | 172 | cursor = zalloc(sizeof(*cursor)); |
173 | assert(cursor != NULL); | 173 | assert(cursor != NULL); |
174 | cursor->pid = pid; | 174 | cursor->pid = pid; |
175 | cursor->next = all_data; | 175 | cursor->next = tchart->all_data; |
176 | all_data = cursor; | 176 | tchart->all_data = cursor; |
177 | return cursor; | 177 | return cursor; |
178 | } | 178 | } |
179 | 179 | ||
180 | static void pid_set_comm(int pid, char *comm) | 180 | static void pid_set_comm(struct timechart *tchart, int pid, char *comm) |
181 | { | 181 | { |
182 | struct per_pid *p; | 182 | struct per_pid *p; |
183 | struct per_pidcomm *c; | 183 | struct per_pidcomm *c; |
184 | p = find_create_pid(pid); | 184 | p = find_create_pid(tchart, pid); |
185 | c = p->all; | 185 | c = p->all; |
186 | while (c) { | 186 | while (c) { |
187 | if (c->comm && strcmp(c->comm, comm) == 0) { | 187 | if (c->comm && strcmp(c->comm, comm) == 0) { |
@@ -203,14 +203,14 @@ static void pid_set_comm(int pid, char *comm) | |||
203 | p->all = c; | 203 | p->all = c; |
204 | } | 204 | } |
205 | 205 | ||
206 | static void pid_fork(int pid, int ppid, u64 timestamp) | 206 | static void pid_fork(struct timechart *tchart, int pid, int ppid, u64 timestamp) |
207 | { | 207 | { |
208 | struct per_pid *p, *pp; | 208 | struct per_pid *p, *pp; |
209 | p = find_create_pid(pid); | 209 | p = find_create_pid(tchart, pid); |
210 | pp = find_create_pid(ppid); | 210 | pp = find_create_pid(tchart, ppid); |
211 | p->ppid = ppid; | 211 | p->ppid = ppid; |
212 | if (pp->current && pp->current->comm && !p->current) | 212 | if (pp->current && pp->current->comm && !p->current) |
213 | pid_set_comm(pid, pp->current->comm); | 213 | pid_set_comm(tchart, pid, pp->current->comm); |
214 | 214 | ||
215 | p->start_time = timestamp; | 215 | p->start_time = timestamp; |
216 | if (p->current) { | 216 | if (p->current) { |
@@ -219,23 +219,24 @@ static void pid_fork(int pid, int ppid, u64 timestamp) | |||
219 | } | 219 | } |
220 | } | 220 | } |
221 | 221 | ||
222 | static void pid_exit(int pid, u64 timestamp) | 222 | static void pid_exit(struct timechart *tchart, int pid, u64 timestamp) |
223 | { | 223 | { |
224 | struct per_pid *p; | 224 | struct per_pid *p; |
225 | p = find_create_pid(pid); | 225 | p = find_create_pid(tchart, pid); |
226 | p->end_time = timestamp; | 226 | p->end_time = timestamp; |
227 | if (p->current) | 227 | if (p->current) |
228 | p->current->end_time = timestamp; | 228 | p->current->end_time = timestamp; |
229 | } | 229 | } |
230 | 230 | ||
231 | static void | 231 | static void pid_put_sample(struct timechart *tchart, int pid, int type, |
232 | pid_put_sample(int pid, int type, unsigned int cpu, u64 start, u64 end) | 232 | unsigned int cpu, u64 start, u64 end, |
233 | const char *backtrace) | ||
233 | { | 234 | { |
234 | struct per_pid *p; | 235 | struct per_pid *p; |
235 | struct per_pidcomm *c; | 236 | struct per_pidcomm *c; |
236 | struct cpu_sample *sample; | 237 | struct cpu_sample *sample; |
237 | 238 | ||
238 | p = find_create_pid(pid); | 239 | p = find_create_pid(tchart, pid); |
239 | c = p->current; | 240 | c = p->current; |
240 | if (!c) { | 241 | if (!c) { |
241 | c = zalloc(sizeof(*c)); | 242 | c = zalloc(sizeof(*c)); |
@@ -252,6 +253,7 @@ pid_put_sample(int pid, int type, unsigned int cpu, u64 start, u64 end) | |||
252 | sample->type = type; | 253 | sample->type = type; |
253 | sample->next = c->samples; | 254 | sample->next = c->samples; |
254 | sample->cpu = cpu; | 255 | sample->cpu = cpu; |
256 | sample->backtrace = backtrace; | ||
255 | c->samples = sample; | 257 | c->samples = sample; |
256 | 258 | ||
257 | if (sample->type == TYPE_RUNNING && end > start && start > 0) { | 259 | if (sample->type == TYPE_RUNNING && end > start && start > 0) { |
@@ -272,84 +274,47 @@ static int cpus_cstate_state[MAX_CPUS]; | |||
272 | static u64 cpus_pstate_start_times[MAX_CPUS]; | 274 | static u64 cpus_pstate_start_times[MAX_CPUS]; |
273 | static u64 cpus_pstate_state[MAX_CPUS]; | 275 | static u64 cpus_pstate_state[MAX_CPUS]; |
274 | 276 | ||
275 | static int process_comm_event(struct perf_tool *tool __maybe_unused, | 277 | static int process_comm_event(struct perf_tool *tool, |
276 | union perf_event *event, | 278 | union perf_event *event, |
277 | struct perf_sample *sample __maybe_unused, | 279 | struct perf_sample *sample __maybe_unused, |
278 | struct machine *machine __maybe_unused) | 280 | struct machine *machine __maybe_unused) |
279 | { | 281 | { |
280 | pid_set_comm(event->comm.tid, event->comm.comm); | 282 | struct timechart *tchart = container_of(tool, struct timechart, tool); |
283 | pid_set_comm(tchart, event->comm.tid, event->comm.comm); | ||
281 | return 0; | 284 | return 0; |
282 | } | 285 | } |
283 | 286 | ||
284 | static int process_fork_event(struct perf_tool *tool __maybe_unused, | 287 | static int process_fork_event(struct perf_tool *tool, |
285 | union perf_event *event, | 288 | union perf_event *event, |
286 | struct perf_sample *sample __maybe_unused, | 289 | struct perf_sample *sample __maybe_unused, |
287 | struct machine *machine __maybe_unused) | 290 | struct machine *machine __maybe_unused) |
288 | { | 291 | { |
289 | pid_fork(event->fork.pid, event->fork.ppid, event->fork.time); | 292 | struct timechart *tchart = container_of(tool, struct timechart, tool); |
293 | pid_fork(tchart, event->fork.pid, event->fork.ppid, event->fork.time); | ||
290 | return 0; | 294 | return 0; |
291 | } | 295 | } |
292 | 296 | ||
293 | static int process_exit_event(struct perf_tool *tool __maybe_unused, | 297 | static int process_exit_event(struct perf_tool *tool, |
294 | union perf_event *event, | 298 | union perf_event *event, |
295 | struct perf_sample *sample __maybe_unused, | 299 | struct perf_sample *sample __maybe_unused, |
296 | struct machine *machine __maybe_unused) | 300 | struct machine *machine __maybe_unused) |
297 | { | 301 | { |
298 | pid_exit(event->fork.pid, event->fork.time); | 302 | struct timechart *tchart = container_of(tool, struct timechart, tool); |
303 | pid_exit(tchart, event->fork.pid, event->fork.time); | ||
299 | return 0; | 304 | return 0; |
300 | } | 305 | } |
301 | 306 | ||
302 | struct trace_entry { | ||
303 | unsigned short type; | ||
304 | unsigned char flags; | ||
305 | unsigned char preempt_count; | ||
306 | int pid; | ||
307 | int lock_depth; | ||
308 | }; | ||
309 | |||
310 | #ifdef SUPPORT_OLD_POWER_EVENTS | 307 | #ifdef SUPPORT_OLD_POWER_EVENTS |
311 | static int use_old_power_events; | 308 | static int use_old_power_events; |
312 | struct power_entry_old { | ||
313 | struct trace_entry te; | ||
314 | u64 type; | ||
315 | u64 value; | ||
316 | u64 cpu_id; | ||
317 | }; | ||
318 | #endif | 309 | #endif |
319 | 310 | ||
320 | struct power_processor_entry { | ||
321 | struct trace_entry te; | ||
322 | u32 state; | ||
323 | u32 cpu_id; | ||
324 | }; | ||
325 | |||
326 | #define TASK_COMM_LEN 16 | ||
327 | struct wakeup_entry { | ||
328 | struct trace_entry te; | ||
329 | char comm[TASK_COMM_LEN]; | ||
330 | int pid; | ||
331 | int prio; | ||
332 | int success; | ||
333 | }; | ||
334 | |||
335 | struct sched_switch { | ||
336 | struct trace_entry te; | ||
337 | char prev_comm[TASK_COMM_LEN]; | ||
338 | int prev_pid; | ||
339 | int prev_prio; | ||
340 | long prev_state; /* Arjan weeps. */ | ||
341 | char next_comm[TASK_COMM_LEN]; | ||
342 | int next_pid; | ||
343 | int next_prio; | ||
344 | }; | ||
345 | |||
346 | static void c_state_start(int cpu, u64 timestamp, int state) | 311 | static void c_state_start(int cpu, u64 timestamp, int state) |
347 | { | 312 | { |
348 | cpus_cstate_start_times[cpu] = timestamp; | 313 | cpus_cstate_start_times[cpu] = timestamp; |
349 | cpus_cstate_state[cpu] = state; | 314 | cpus_cstate_state[cpu] = state; |
350 | } | 315 | } |
351 | 316 | ||
352 | static void c_state_end(int cpu, u64 timestamp) | 317 | static void c_state_end(struct timechart *tchart, int cpu, u64 timestamp) |
353 | { | 318 | { |
354 | struct power_event *pwr = zalloc(sizeof(*pwr)); | 319 | struct power_event *pwr = zalloc(sizeof(*pwr)); |
355 | 320 | ||
@@ -361,12 +326,12 @@ static void c_state_end(int cpu, u64 timestamp) | |||
361 | pwr->end_time = timestamp; | 326 | pwr->end_time = timestamp; |
362 | pwr->cpu = cpu; | 327 | pwr->cpu = cpu; |
363 | pwr->type = CSTATE; | 328 | pwr->type = CSTATE; |
364 | pwr->next = power_events; | 329 | pwr->next = tchart->power_events; |
365 | 330 | ||
366 | power_events = pwr; | 331 | tchart->power_events = pwr; |
367 | } | 332 | } |
368 | 333 | ||
369 | static void p_state_change(int cpu, u64 timestamp, u64 new_freq) | 334 | static void p_state_change(struct timechart *tchart, int cpu, u64 timestamp, u64 new_freq) |
370 | { | 335 | { |
371 | struct power_event *pwr; | 336 | struct power_event *pwr; |
372 | 337 | ||
@@ -382,73 +347,78 @@ static void p_state_change(int cpu, u64 timestamp, u64 new_freq) | |||
382 | pwr->end_time = timestamp; | 347 | pwr->end_time = timestamp; |
383 | pwr->cpu = cpu; | 348 | pwr->cpu = cpu; |
384 | pwr->type = PSTATE; | 349 | pwr->type = PSTATE; |
385 | pwr->next = power_events; | 350 | pwr->next = tchart->power_events; |
386 | 351 | ||
387 | if (!pwr->start_time) | 352 | if (!pwr->start_time) |
388 | pwr->start_time = first_time; | 353 | pwr->start_time = tchart->first_time; |
389 | 354 | ||
390 | power_events = pwr; | 355 | tchart->power_events = pwr; |
391 | 356 | ||
392 | cpus_pstate_state[cpu] = new_freq; | 357 | cpus_pstate_state[cpu] = new_freq; |
393 | cpus_pstate_start_times[cpu] = timestamp; | 358 | cpus_pstate_start_times[cpu] = timestamp; |
394 | 359 | ||
395 | if ((u64)new_freq > max_freq) | 360 | if ((u64)new_freq > tchart->max_freq) |
396 | max_freq = new_freq; | 361 | tchart->max_freq = new_freq; |
397 | 362 | ||
398 | if (new_freq < min_freq || min_freq == 0) | 363 | if (new_freq < tchart->min_freq || tchart->min_freq == 0) |
399 | min_freq = new_freq; | 364 | tchart->min_freq = new_freq; |
400 | 365 | ||
401 | if (new_freq == max_freq - 1000) | 366 | if (new_freq == tchart->max_freq - 1000) |
402 | turbo_frequency = max_freq; | 367 | tchart->turbo_frequency = tchart->max_freq; |
403 | } | 368 | } |
404 | 369 | ||
405 | static void | 370 | static void sched_wakeup(struct timechart *tchart, int cpu, u64 timestamp, |
406 | sched_wakeup(int cpu, u64 timestamp, int pid, struct trace_entry *te) | 371 | int waker, int wakee, u8 flags, const char *backtrace) |
407 | { | 372 | { |
408 | struct per_pid *p; | 373 | struct per_pid *p; |
409 | struct wakeup_entry *wake = (void *)te; | ||
410 | struct wake_event *we = zalloc(sizeof(*we)); | 374 | struct wake_event *we = zalloc(sizeof(*we)); |
411 | 375 | ||
412 | if (!we) | 376 | if (!we) |
413 | return; | 377 | return; |
414 | 378 | ||
415 | we->time = timestamp; | 379 | we->time = timestamp; |
416 | we->waker = pid; | 380 | we->waker = waker; |
381 | we->backtrace = backtrace; | ||
417 | 382 | ||
418 | if ((te->flags & TRACE_FLAG_HARDIRQ) || (te->flags & TRACE_FLAG_SOFTIRQ)) | 383 | if ((flags & TRACE_FLAG_HARDIRQ) || (flags & TRACE_FLAG_SOFTIRQ)) |
419 | we->waker = -1; | 384 | we->waker = -1; |
420 | 385 | ||
421 | we->wakee = wake->pid; | 386 | we->wakee = wakee; |
422 | we->next = wake_events; | 387 | we->next = tchart->wake_events; |
423 | wake_events = we; | 388 | tchart->wake_events = we; |
424 | p = find_create_pid(we->wakee); | 389 | p = find_create_pid(tchart, we->wakee); |
425 | 390 | ||
426 | if (p && p->current && p->current->state == TYPE_NONE) { | 391 | if (p && p->current && p->current->state == TYPE_NONE) { |
427 | p->current->state_since = timestamp; | 392 | p->current->state_since = timestamp; |
428 | p->current->state = TYPE_WAITING; | 393 | p->current->state = TYPE_WAITING; |
429 | } | 394 | } |
430 | if (p && p->current && p->current->state == TYPE_BLOCKED) { | 395 | if (p && p->current && p->current->state == TYPE_BLOCKED) { |
431 | pid_put_sample(p->pid, p->current->state, cpu, p->current->state_since, timestamp); | 396 | pid_put_sample(tchart, p->pid, p->current->state, cpu, |
397 | p->current->state_since, timestamp, NULL); | ||
432 | p->current->state_since = timestamp; | 398 | p->current->state_since = timestamp; |
433 | p->current->state = TYPE_WAITING; | 399 | p->current->state = TYPE_WAITING; |
434 | } | 400 | } |
435 | } | 401 | } |
436 | 402 | ||
437 | static void sched_switch(int cpu, u64 timestamp, struct trace_entry *te) | 403 | static void sched_switch(struct timechart *tchart, int cpu, u64 timestamp, |
404 | int prev_pid, int next_pid, u64 prev_state, | ||
405 | const char *backtrace) | ||
438 | { | 406 | { |
439 | struct per_pid *p = NULL, *prev_p; | 407 | struct per_pid *p = NULL, *prev_p; |
440 | struct sched_switch *sw = (void *)te; | ||
441 | 408 | ||
409 | prev_p = find_create_pid(tchart, prev_pid); | ||
442 | 410 | ||
443 | prev_p = find_create_pid(sw->prev_pid); | 411 | p = find_create_pid(tchart, next_pid); |
444 | |||
445 | p = find_create_pid(sw->next_pid); | ||
446 | 412 | ||
447 | if (prev_p->current && prev_p->current->state != TYPE_NONE) | 413 | if (prev_p->current && prev_p->current->state != TYPE_NONE) |
448 | pid_put_sample(sw->prev_pid, TYPE_RUNNING, cpu, prev_p->current->state_since, timestamp); | 414 | pid_put_sample(tchart, prev_pid, TYPE_RUNNING, cpu, |
415 | prev_p->current->state_since, timestamp, | ||
416 | backtrace); | ||
449 | if (p && p->current) { | 417 | if (p && p->current) { |
450 | if (p->current->state != TYPE_NONE) | 418 | if (p->current->state != TYPE_NONE) |
451 | pid_put_sample(sw->next_pid, p->current->state, cpu, p->current->state_since, timestamp); | 419 | pid_put_sample(tchart, next_pid, p->current->state, cpu, |
420 | p->current->state_since, timestamp, | ||
421 | backtrace); | ||
452 | 422 | ||
453 | p->current->state_since = timestamp; | 423 | p->current->state_since = timestamp; |
454 | p->current->state = TYPE_RUNNING; | 424 | p->current->state = TYPE_RUNNING; |
@@ -457,109 +427,211 @@ static void sched_switch(int cpu, u64 timestamp, struct trace_entry *te) | |||
457 | if (prev_p->current) { | 427 | if (prev_p->current) { |
458 | prev_p->current->state = TYPE_NONE; | 428 | prev_p->current->state = TYPE_NONE; |
459 | prev_p->current->state_since = timestamp; | 429 | prev_p->current->state_since = timestamp; |
460 | if (sw->prev_state & 2) | 430 | if (prev_state & 2) |
461 | prev_p->current->state = TYPE_BLOCKED; | 431 | prev_p->current->state = TYPE_BLOCKED; |
462 | if (sw->prev_state == 0) | 432 | if (prev_state == 0) |
463 | prev_p->current->state = TYPE_WAITING; | 433 | prev_p->current->state = TYPE_WAITING; |
464 | } | 434 | } |
465 | } | 435 | } |
466 | 436 | ||
467 | typedef int (*tracepoint_handler)(struct perf_evsel *evsel, | 437 | static const char *cat_backtrace(union perf_event *event, |
468 | struct perf_sample *sample); | 438 | struct perf_sample *sample, |
439 | struct machine *machine) | ||
440 | { | ||
441 | struct addr_location al; | ||
442 | unsigned int i; | ||
443 | char *p = NULL; | ||
444 | size_t p_len; | ||
445 | u8 cpumode = PERF_RECORD_MISC_USER; | ||
446 | struct addr_location tal; | ||
447 | struct ip_callchain *chain = sample->callchain; | ||
448 | FILE *f = open_memstream(&p, &p_len); | ||
449 | |||
450 | if (!f) { | ||
451 | perror("open_memstream error"); | ||
452 | return NULL; | ||
453 | } | ||
454 | |||
455 | if (!chain) | ||
456 | goto exit; | ||
457 | |||
458 | if (perf_event__preprocess_sample(event, machine, &al, sample) < 0) { | ||
459 | fprintf(stderr, "problem processing %d event, skipping it.\n", | ||
460 | event->header.type); | ||
461 | goto exit; | ||
462 | } | ||
463 | |||
464 | for (i = 0; i < chain->nr; i++) { | ||
465 | u64 ip; | ||
466 | |||
467 | if (callchain_param.order == ORDER_CALLEE) | ||
468 | ip = chain->ips[i]; | ||
469 | else | ||
470 | ip = chain->ips[chain->nr - i - 1]; | ||
471 | |||
472 | if (ip >= PERF_CONTEXT_MAX) { | ||
473 | switch (ip) { | ||
474 | case PERF_CONTEXT_HV: | ||
475 | cpumode = PERF_RECORD_MISC_HYPERVISOR; | ||
476 | break; | ||
477 | case PERF_CONTEXT_KERNEL: | ||
478 | cpumode = PERF_RECORD_MISC_KERNEL; | ||
479 | break; | ||
480 | case PERF_CONTEXT_USER: | ||
481 | cpumode = PERF_RECORD_MISC_USER; | ||
482 | break; | ||
483 | default: | ||
484 | pr_debug("invalid callchain context: " | ||
485 | "%"PRId64"\n", (s64) ip); | ||
486 | |||
487 | /* | ||
488 | * It seems the callchain is corrupted. | ||
489 | * Discard all. | ||
490 | */ | ||
491 | zfree(&p); | ||
492 | goto exit; | ||
493 | } | ||
494 | continue; | ||
495 | } | ||
496 | |||
497 | tal.filtered = false; | ||
498 | thread__find_addr_location(al.thread, machine, cpumode, | ||
499 | MAP__FUNCTION, ip, &tal); | ||
500 | |||
501 | if (tal.sym) | ||
502 | fprintf(f, "..... %016" PRIx64 " %s\n", ip, | ||
503 | tal.sym->name); | ||
504 | else | ||
505 | fprintf(f, "..... %016" PRIx64 "\n", ip); | ||
506 | } | ||
507 | |||
508 | exit: | ||
509 | fclose(f); | ||
510 | |||
511 | return p; | ||
512 | } | ||
513 | |||
514 | typedef int (*tracepoint_handler)(struct timechart *tchart, | ||
515 | struct perf_evsel *evsel, | ||
516 | struct perf_sample *sample, | ||
517 | const char *backtrace); | ||
469 | 518 | ||
470 | static int process_sample_event(struct perf_tool *tool __maybe_unused, | 519 | static int process_sample_event(struct perf_tool *tool, |
471 | union perf_event *event __maybe_unused, | 520 | union perf_event *event, |
472 | struct perf_sample *sample, | 521 | struct perf_sample *sample, |
473 | struct perf_evsel *evsel, | 522 | struct perf_evsel *evsel, |
474 | struct machine *machine __maybe_unused) | 523 | struct machine *machine) |
475 | { | 524 | { |
525 | struct timechart *tchart = container_of(tool, struct timechart, tool); | ||
526 | |||
476 | if (evsel->attr.sample_type & PERF_SAMPLE_TIME) { | 527 | if (evsel->attr.sample_type & PERF_SAMPLE_TIME) { |
477 | if (!first_time || first_time > sample->time) | 528 | if (!tchart->first_time || tchart->first_time > sample->time) |
478 | first_time = sample->time; | 529 | tchart->first_time = sample->time; |
479 | if (last_time < sample->time) | 530 | if (tchart->last_time < sample->time) |
480 | last_time = sample->time; | 531 | tchart->last_time = sample->time; |
481 | } | 532 | } |
482 | 533 | ||
483 | if (sample->cpu > numcpus) | ||
484 | numcpus = sample->cpu; | ||
485 | |||
486 | if (evsel->handler != NULL) { | 534 | if (evsel->handler != NULL) { |
487 | tracepoint_handler f = evsel->handler; | 535 | tracepoint_handler f = evsel->handler; |
488 | return f(evsel, sample); | 536 | return f(tchart, evsel, sample, |
537 | cat_backtrace(event, sample, machine)); | ||
489 | } | 538 | } |
490 | 539 | ||
491 | return 0; | 540 | return 0; |
492 | } | 541 | } |
493 | 542 | ||
494 | static int | 543 | static int |
495 | process_sample_cpu_idle(struct perf_evsel *evsel __maybe_unused, | 544 | process_sample_cpu_idle(struct timechart *tchart __maybe_unused, |
496 | struct perf_sample *sample) | 545 | struct perf_evsel *evsel, |
546 | struct perf_sample *sample, | ||
547 | const char *backtrace __maybe_unused) | ||
497 | { | 548 | { |
498 | struct power_processor_entry *ppe = sample->raw_data; | 549 | u32 state = perf_evsel__intval(evsel, sample, "state"); |
550 | u32 cpu_id = perf_evsel__intval(evsel, sample, "cpu_id"); | ||
499 | 551 | ||
500 | if (ppe->state == (u32) PWR_EVENT_EXIT) | 552 | if (state == (u32)PWR_EVENT_EXIT) |
501 | c_state_end(ppe->cpu_id, sample->time); | 553 | c_state_end(tchart, cpu_id, sample->time); |
502 | else | 554 | else |
503 | c_state_start(ppe->cpu_id, sample->time, ppe->state); | 555 | c_state_start(cpu_id, sample->time, state); |
504 | return 0; | 556 | return 0; |
505 | } | 557 | } |
506 | 558 | ||
507 | static int | 559 | static int |
508 | process_sample_cpu_frequency(struct perf_evsel *evsel __maybe_unused, | 560 | process_sample_cpu_frequency(struct timechart *tchart, |
509 | struct perf_sample *sample) | 561 | struct perf_evsel *evsel, |
562 | struct perf_sample *sample, | ||
563 | const char *backtrace __maybe_unused) | ||
510 | { | 564 | { |
511 | struct power_processor_entry *ppe = sample->raw_data; | 565 | u32 state = perf_evsel__intval(evsel, sample, "state"); |
566 | u32 cpu_id = perf_evsel__intval(evsel, sample, "cpu_id"); | ||
512 | 567 | ||
513 | p_state_change(ppe->cpu_id, sample->time, ppe->state); | 568 | p_state_change(tchart, cpu_id, sample->time, state); |
514 | return 0; | 569 | return 0; |
515 | } | 570 | } |
516 | 571 | ||
517 | static int | 572 | static int |
518 | process_sample_sched_wakeup(struct perf_evsel *evsel __maybe_unused, | 573 | process_sample_sched_wakeup(struct timechart *tchart, |
519 | struct perf_sample *sample) | 574 | struct perf_evsel *evsel, |
575 | struct perf_sample *sample, | ||
576 | const char *backtrace) | ||
520 | { | 577 | { |
521 | struct trace_entry *te = sample->raw_data; | 578 | u8 flags = perf_evsel__intval(evsel, sample, "common_flags"); |
579 | int waker = perf_evsel__intval(evsel, sample, "common_pid"); | ||
580 | int wakee = perf_evsel__intval(evsel, sample, "pid"); | ||
522 | 581 | ||
523 | sched_wakeup(sample->cpu, sample->time, sample->pid, te); | 582 | sched_wakeup(tchart, sample->cpu, sample->time, waker, wakee, flags, backtrace); |
524 | return 0; | 583 | return 0; |
525 | } | 584 | } |
526 | 585 | ||
527 | static int | 586 | static int |
528 | process_sample_sched_switch(struct perf_evsel *evsel __maybe_unused, | 587 | process_sample_sched_switch(struct timechart *tchart, |
529 | struct perf_sample *sample) | 588 | struct perf_evsel *evsel, |
589 | struct perf_sample *sample, | ||
590 | const char *backtrace) | ||
530 | { | 591 | { |
531 | struct trace_entry *te = sample->raw_data; | 592 | int prev_pid = perf_evsel__intval(evsel, sample, "prev_pid"); |
593 | int next_pid = perf_evsel__intval(evsel, sample, "next_pid"); | ||
594 | u64 prev_state = perf_evsel__intval(evsel, sample, "prev_state"); | ||
532 | 595 | ||
533 | sched_switch(sample->cpu, sample->time, te); | 596 | sched_switch(tchart, sample->cpu, sample->time, prev_pid, next_pid, |
597 | prev_state, backtrace); | ||
534 | return 0; | 598 | return 0; |
535 | } | 599 | } |
536 | 600 | ||
537 | #ifdef SUPPORT_OLD_POWER_EVENTS | 601 | #ifdef SUPPORT_OLD_POWER_EVENTS |
538 | static int | 602 | static int |
539 | process_sample_power_start(struct perf_evsel *evsel __maybe_unused, | 603 | process_sample_power_start(struct timechart *tchart __maybe_unused, |
540 | struct perf_sample *sample) | 604 | struct perf_evsel *evsel, |
605 | struct perf_sample *sample, | ||
606 | const char *backtrace __maybe_unused) | ||
541 | { | 607 | { |
542 | struct power_entry_old *peo = sample->raw_data; | 608 | u64 cpu_id = perf_evsel__intval(evsel, sample, "cpu_id"); |
609 | u64 value = perf_evsel__intval(evsel, sample, "value"); | ||
543 | 610 | ||
544 | c_state_start(peo->cpu_id, sample->time, peo->value); | 611 | c_state_start(cpu_id, sample->time, value); |
545 | return 0; | 612 | return 0; |
546 | } | 613 | } |
547 | 614 | ||
548 | static int | 615 | static int |
549 | process_sample_power_end(struct perf_evsel *evsel __maybe_unused, | 616 | process_sample_power_end(struct timechart *tchart, |
550 | struct perf_sample *sample) | 617 | struct perf_evsel *evsel __maybe_unused, |
618 | struct perf_sample *sample, | ||
619 | const char *backtrace __maybe_unused) | ||
551 | { | 620 | { |
552 | c_state_end(sample->cpu, sample->time); | 621 | c_state_end(tchart, sample->cpu, sample->time); |
553 | return 0; | 622 | return 0; |
554 | } | 623 | } |
555 | 624 | ||
556 | static int | 625 | static int |
557 | process_sample_power_frequency(struct perf_evsel *evsel __maybe_unused, | 626 | process_sample_power_frequency(struct timechart *tchart, |
558 | struct perf_sample *sample) | 627 | struct perf_evsel *evsel, |
628 | struct perf_sample *sample, | ||
629 | const char *backtrace __maybe_unused) | ||
559 | { | 630 | { |
560 | struct power_entry_old *peo = sample->raw_data; | 631 | u64 cpu_id = perf_evsel__intval(evsel, sample, "cpu_id"); |
632 | u64 value = perf_evsel__intval(evsel, sample, "value"); | ||
561 | 633 | ||
562 | p_state_change(peo->cpu_id, sample->time, peo->value); | 634 | p_state_change(tchart, cpu_id, sample->time, value); |
563 | return 0; | 635 | return 0; |
564 | } | 636 | } |
565 | #endif /* SUPPORT_OLD_POWER_EVENTS */ | 637 | #endif /* SUPPORT_OLD_POWER_EVENTS */ |
@@ -568,12 +640,12 @@ process_sample_power_frequency(struct perf_evsel *evsel __maybe_unused, | |||
568 | * After the last sample we need to wrap up the current C/P state | 640 | * After the last sample we need to wrap up the current C/P state |
569 | * and close out each CPU for these. | 641 | * and close out each CPU for these. |
570 | */ | 642 | */ |
571 | static void end_sample_processing(void) | 643 | static void end_sample_processing(struct timechart *tchart) |
572 | { | 644 | { |
573 | u64 cpu; | 645 | u64 cpu; |
574 | struct power_event *pwr; | 646 | struct power_event *pwr; |
575 | 647 | ||
576 | for (cpu = 0; cpu <= numcpus; cpu++) { | 648 | for (cpu = 0; cpu <= tchart->numcpus; cpu++) { |
577 | /* C state */ | 649 | /* C state */ |
578 | #if 0 | 650 | #if 0 |
579 | pwr = zalloc(sizeof(*pwr)); | 651 | pwr = zalloc(sizeof(*pwr)); |
@@ -582,12 +654,12 @@ static void end_sample_processing(void) | |||
582 | 654 | ||
583 | pwr->state = cpus_cstate_state[cpu]; | 655 | pwr->state = cpus_cstate_state[cpu]; |
584 | pwr->start_time = cpus_cstate_start_times[cpu]; | 656 | pwr->start_time = cpus_cstate_start_times[cpu]; |
585 | pwr->end_time = last_time; | 657 | pwr->end_time = tchart->last_time; |
586 | pwr->cpu = cpu; | 658 | pwr->cpu = cpu; |
587 | pwr->type = CSTATE; | 659 | pwr->type = CSTATE; |
588 | pwr->next = power_events; | 660 | pwr->next = tchart->power_events; |
589 | 661 | ||
590 | power_events = pwr; | 662 | tchart->power_events = pwr; |
591 | #endif | 663 | #endif |
592 | /* P state */ | 664 | /* P state */ |
593 | 665 | ||
@@ -597,32 +669,32 @@ static void end_sample_processing(void) | |||
597 | 669 | ||
598 | pwr->state = cpus_pstate_state[cpu]; | 670 | pwr->state = cpus_pstate_state[cpu]; |
599 | pwr->start_time = cpus_pstate_start_times[cpu]; | 671 | pwr->start_time = cpus_pstate_start_times[cpu]; |
600 | pwr->end_time = last_time; | 672 | pwr->end_time = tchart->last_time; |
601 | pwr->cpu = cpu; | 673 | pwr->cpu = cpu; |
602 | pwr->type = PSTATE; | 674 | pwr->type = PSTATE; |
603 | pwr->next = power_events; | 675 | pwr->next = tchart->power_events; |
604 | 676 | ||
605 | if (!pwr->start_time) | 677 | if (!pwr->start_time) |
606 | pwr->start_time = first_time; | 678 | pwr->start_time = tchart->first_time; |
607 | if (!pwr->state) | 679 | if (!pwr->state) |
608 | pwr->state = min_freq; | 680 | pwr->state = tchart->min_freq; |
609 | power_events = pwr; | 681 | tchart->power_events = pwr; |
610 | } | 682 | } |
611 | } | 683 | } |
612 | 684 | ||
613 | /* | 685 | /* |
614 | * Sort the pid datastructure | 686 | * Sort the pid datastructure |
615 | */ | 687 | */ |
616 | static void sort_pids(void) | 688 | static void sort_pids(struct timechart *tchart) |
617 | { | 689 | { |
618 | struct per_pid *new_list, *p, *cursor, *prev; | 690 | struct per_pid *new_list, *p, *cursor, *prev; |
619 | /* sort by ppid first, then by pid, lowest to highest */ | 691 | /* sort by ppid first, then by pid, lowest to highest */ |
620 | 692 | ||
621 | new_list = NULL; | 693 | new_list = NULL; |
622 | 694 | ||
623 | while (all_data) { | 695 | while (tchart->all_data) { |
624 | p = all_data; | 696 | p = tchart->all_data; |
625 | all_data = p->next; | 697 | tchart->all_data = p->next; |
626 | p->next = NULL; | 698 | p->next = NULL; |
627 | 699 | ||
628 | if (new_list == NULL) { | 700 | if (new_list == NULL) { |
@@ -655,14 +727,14 @@ static void sort_pids(void) | |||
655 | prev->next = p; | 727 | prev->next = p; |
656 | } | 728 | } |
657 | } | 729 | } |
658 | all_data = new_list; | 730 | tchart->all_data = new_list; |
659 | } | 731 | } |
660 | 732 | ||
661 | 733 | ||
662 | static void draw_c_p_states(void) | 734 | static void draw_c_p_states(struct timechart *tchart) |
663 | { | 735 | { |
664 | struct power_event *pwr; | 736 | struct power_event *pwr; |
665 | pwr = power_events; | 737 | pwr = tchart->power_events; |
666 | 738 | ||
667 | /* | 739 | /* |
668 | * two pass drawing so that the P state bars are on top of the C state blocks | 740 | * two pass drawing so that the P state bars are on top of the C state blocks |
@@ -673,30 +745,30 @@ static void draw_c_p_states(void) | |||
673 | pwr = pwr->next; | 745 | pwr = pwr->next; |
674 | } | 746 | } |
675 | 747 | ||
676 | pwr = power_events; | 748 | pwr = tchart->power_events; |
677 | while (pwr) { | 749 | while (pwr) { |
678 | if (pwr->type == PSTATE) { | 750 | if (pwr->type == PSTATE) { |
679 | if (!pwr->state) | 751 | if (!pwr->state) |
680 | pwr->state = min_freq; | 752 | pwr->state = tchart->min_freq; |
681 | svg_pstate(pwr->cpu, pwr->start_time, pwr->end_time, pwr->state); | 753 | svg_pstate(pwr->cpu, pwr->start_time, pwr->end_time, pwr->state); |
682 | } | 754 | } |
683 | pwr = pwr->next; | 755 | pwr = pwr->next; |
684 | } | 756 | } |
685 | } | 757 | } |
686 | 758 | ||
687 | static void draw_wakeups(void) | 759 | static void draw_wakeups(struct timechart *tchart) |
688 | { | 760 | { |
689 | struct wake_event *we; | 761 | struct wake_event *we; |
690 | struct per_pid *p; | 762 | struct per_pid *p; |
691 | struct per_pidcomm *c; | 763 | struct per_pidcomm *c; |
692 | 764 | ||
693 | we = wake_events; | 765 | we = tchart->wake_events; |
694 | while (we) { | 766 | while (we) { |
695 | int from = 0, to = 0; | 767 | int from = 0, to = 0; |
696 | char *task_from = NULL, *task_to = NULL; | 768 | char *task_from = NULL, *task_to = NULL; |
697 | 769 | ||
698 | /* locate the column of the waker and wakee */ | 770 | /* locate the column of the waker and wakee */ |
699 | p = all_data; | 771 | p = tchart->all_data; |
700 | while (p) { | 772 | while (p) { |
701 | if (p->pid == we->waker || p->pid == we->wakee) { | 773 | if (p->pid == we->waker || p->pid == we->wakee) { |
702 | c = p->all; | 774 | c = p->all; |
@@ -739,11 +811,12 @@ static void draw_wakeups(void) | |||
739 | } | 811 | } |
740 | 812 | ||
741 | if (we->waker == -1) | 813 | if (we->waker == -1) |
742 | svg_interrupt(we->time, to); | 814 | svg_interrupt(we->time, to, we->backtrace); |
743 | else if (from && to && abs(from - to) == 1) | 815 | else if (from && to && abs(from - to) == 1) |
744 | svg_wakeline(we->time, from, to); | 816 | svg_wakeline(we->time, from, to, we->backtrace); |
745 | else | 817 | else |
746 | svg_partial_wakeline(we->time, from, task_from, to, task_to); | 818 | svg_partial_wakeline(we->time, from, task_from, to, |
819 | task_to, we->backtrace); | ||
747 | we = we->next; | 820 | we = we->next; |
748 | 821 | ||
749 | free(task_from); | 822 | free(task_from); |
@@ -751,19 +824,25 @@ static void draw_wakeups(void) | |||
751 | } | 824 | } |
752 | } | 825 | } |
753 | 826 | ||
754 | static void draw_cpu_usage(void) | 827 | static void draw_cpu_usage(struct timechart *tchart) |
755 | { | 828 | { |
756 | struct per_pid *p; | 829 | struct per_pid *p; |
757 | struct per_pidcomm *c; | 830 | struct per_pidcomm *c; |
758 | struct cpu_sample *sample; | 831 | struct cpu_sample *sample; |
759 | p = all_data; | 832 | p = tchart->all_data; |
760 | while (p) { | 833 | while (p) { |
761 | c = p->all; | 834 | c = p->all; |
762 | while (c) { | 835 | while (c) { |
763 | sample = c->samples; | 836 | sample = c->samples; |
764 | while (sample) { | 837 | while (sample) { |
765 | if (sample->type == TYPE_RUNNING) | 838 | if (sample->type == TYPE_RUNNING) { |
766 | svg_process(sample->cpu, sample->start_time, sample->end_time, "sample", c->comm); | 839 | svg_process(sample->cpu, |
840 | sample->start_time, | ||
841 | sample->end_time, | ||
842 | p->pid, | ||
843 | c->comm, | ||
844 | sample->backtrace); | ||
845 | } | ||
767 | 846 | ||
768 | sample = sample->next; | 847 | sample = sample->next; |
769 | } | 848 | } |
@@ -773,16 +852,16 @@ static void draw_cpu_usage(void) | |||
773 | } | 852 | } |
774 | } | 853 | } |
775 | 854 | ||
776 | static void draw_process_bars(void) | 855 | static void draw_process_bars(struct timechart *tchart) |
777 | { | 856 | { |
778 | struct per_pid *p; | 857 | struct per_pid *p; |
779 | struct per_pidcomm *c; | 858 | struct per_pidcomm *c; |
780 | struct cpu_sample *sample; | 859 | struct cpu_sample *sample; |
781 | int Y = 0; | 860 | int Y = 0; |
782 | 861 | ||
783 | Y = 2 * numcpus + 2; | 862 | Y = 2 * tchart->numcpus + 2; |
784 | 863 | ||
785 | p = all_data; | 864 | p = tchart->all_data; |
786 | while (p) { | 865 | while (p) { |
787 | c = p->all; | 866 | c = p->all; |
788 | while (c) { | 867 | while (c) { |
@@ -796,11 +875,20 @@ static void draw_process_bars(void) | |||
796 | sample = c->samples; | 875 | sample = c->samples; |
797 | while (sample) { | 876 | while (sample) { |
798 | if (sample->type == TYPE_RUNNING) | 877 | if (sample->type == TYPE_RUNNING) |
799 | svg_sample(Y, sample->cpu, sample->start_time, sample->end_time); | 878 | svg_running(Y, sample->cpu, |
879 | sample->start_time, | ||
880 | sample->end_time, | ||
881 | sample->backtrace); | ||
800 | if (sample->type == TYPE_BLOCKED) | 882 | if (sample->type == TYPE_BLOCKED) |
801 | svg_box(Y, sample->start_time, sample->end_time, "blocked"); | 883 | svg_blocked(Y, sample->cpu, |
884 | sample->start_time, | ||
885 | sample->end_time, | ||
886 | sample->backtrace); | ||
802 | if (sample->type == TYPE_WAITING) | 887 | if (sample->type == TYPE_WAITING) |
803 | svg_waiting(Y, sample->start_time, sample->end_time); | 888 | svg_waiting(Y, sample->cpu, |
889 | sample->start_time, | ||
890 | sample->end_time, | ||
891 | sample->backtrace); | ||
804 | sample = sample->next; | 892 | sample = sample->next; |
805 | } | 893 | } |
806 | 894 | ||
@@ -853,21 +941,21 @@ static int passes_filter(struct per_pid *p, struct per_pidcomm *c) | |||
853 | return 0; | 941 | return 0; |
854 | } | 942 | } |
855 | 943 | ||
856 | static int determine_display_tasks_filtered(void) | 944 | static int determine_display_tasks_filtered(struct timechart *tchart) |
857 | { | 945 | { |
858 | struct per_pid *p; | 946 | struct per_pid *p; |
859 | struct per_pidcomm *c; | 947 | struct per_pidcomm *c; |
860 | int count = 0; | 948 | int count = 0; |
861 | 949 | ||
862 | p = all_data; | 950 | p = tchart->all_data; |
863 | while (p) { | 951 | while (p) { |
864 | p->display = 0; | 952 | p->display = 0; |
865 | if (p->start_time == 1) | 953 | if (p->start_time == 1) |
866 | p->start_time = first_time; | 954 | p->start_time = tchart->first_time; |
867 | 955 | ||
868 | /* no exit marker, task kept running to the end */ | 956 | /* no exit marker, task kept running to the end */ |
869 | if (p->end_time == 0) | 957 | if (p->end_time == 0) |
870 | p->end_time = last_time; | 958 | p->end_time = tchart->last_time; |
871 | 959 | ||
872 | c = p->all; | 960 | c = p->all; |
873 | 961 | ||
@@ -875,7 +963,7 @@ static int determine_display_tasks_filtered(void) | |||
875 | c->display = 0; | 963 | c->display = 0; |
876 | 964 | ||
877 | if (c->start_time == 1) | 965 | if (c->start_time == 1) |
878 | c->start_time = first_time; | 966 | c->start_time = tchart->first_time; |
879 | 967 | ||
880 | if (passes_filter(p, c)) { | 968 | if (passes_filter(p, c)) { |
881 | c->display = 1; | 969 | c->display = 1; |
@@ -884,7 +972,7 @@ static int determine_display_tasks_filtered(void) | |||
884 | } | 972 | } |
885 | 973 | ||
886 | if (c->end_time == 0) | 974 | if (c->end_time == 0) |
887 | c->end_time = last_time; | 975 | c->end_time = tchart->last_time; |
888 | 976 | ||
889 | c = c->next; | 977 | c = c->next; |
890 | } | 978 | } |
@@ -893,25 +981,25 @@ static int determine_display_tasks_filtered(void) | |||
893 | return count; | 981 | return count; |
894 | } | 982 | } |
895 | 983 | ||
896 | static int determine_display_tasks(u64 threshold) | 984 | static int determine_display_tasks(struct timechart *tchart, u64 threshold) |
897 | { | 985 | { |
898 | struct per_pid *p; | 986 | struct per_pid *p; |
899 | struct per_pidcomm *c; | 987 | struct per_pidcomm *c; |
900 | int count = 0; | 988 | int count = 0; |
901 | 989 | ||
902 | if (process_filter) | 990 | if (process_filter) |
903 | return determine_display_tasks_filtered(); | 991 | return determine_display_tasks_filtered(tchart); |
904 | 992 | ||
905 | p = all_data; | 993 | p = tchart->all_data; |
906 | while (p) { | 994 | while (p) { |
907 | p->display = 0; | 995 | p->display = 0; |
908 | if (p->start_time == 1) | 996 | if (p->start_time == 1) |
909 | p->start_time = first_time; | 997 | p->start_time = tchart->first_time; |
910 | 998 | ||
911 | /* no exit marker, task kept running to the end */ | 999 | /* no exit marker, task kept running to the end */ |
912 | if (p->end_time == 0) | 1000 | if (p->end_time == 0) |
913 | p->end_time = last_time; | 1001 | p->end_time = tchart->last_time; |
914 | if (p->total_time >= threshold && !power_only) | 1002 | if (p->total_time >= threshold) |
915 | p->display = 1; | 1003 | p->display = 1; |
916 | 1004 | ||
917 | c = p->all; | 1005 | c = p->all; |
@@ -920,15 +1008,15 @@ static int determine_display_tasks(u64 threshold) | |||
920 | c->display = 0; | 1008 | c->display = 0; |
921 | 1009 | ||
922 | if (c->start_time == 1) | 1010 | if (c->start_time == 1) |
923 | c->start_time = first_time; | 1011 | c->start_time = tchart->first_time; |
924 | 1012 | ||
925 | if (c->total_time >= threshold && !power_only) { | 1013 | if (c->total_time >= threshold) { |
926 | c->display = 1; | 1014 | c->display = 1; |
927 | count++; | 1015 | count++; |
928 | } | 1016 | } |
929 | 1017 | ||
930 | if (c->end_time == 0) | 1018 | if (c->end_time == 0) |
931 | c->end_time = last_time; | 1019 | c->end_time = tchart->last_time; |
932 | 1020 | ||
933 | c = c->next; | 1021 | c = c->next; |
934 | } | 1022 | } |
@@ -941,45 +1029,77 @@ static int determine_display_tasks(u64 threshold) | |||
941 | 1029 | ||
942 | #define TIME_THRESH 10000000 | 1030 | #define TIME_THRESH 10000000 |
943 | 1031 | ||
944 | static void write_svg_file(const char *filename) | 1032 | static void write_svg_file(struct timechart *tchart, const char *filename) |
945 | { | 1033 | { |
946 | u64 i; | 1034 | u64 i; |
947 | int count; | 1035 | int count; |
1036 | int thresh = TIME_THRESH; | ||
948 | 1037 | ||
949 | numcpus++; | 1038 | if (tchart->power_only) |
1039 | tchart->proc_num = 0; | ||
950 | 1040 | ||
1041 | /* We'd like to show at least proc_num tasks; | ||
1042 | * be less picky if we have fewer */ | ||
1043 | do { | ||
1044 | count = determine_display_tasks(tchart, thresh); | ||
1045 | thresh /= 10; | ||
1046 | } while (!process_filter && thresh && count < tchart->proc_num); | ||
951 | 1047 | ||
952 | count = determine_display_tasks(TIME_THRESH); | 1048 | if (!tchart->proc_num) |
1049 | count = 0; | ||
953 | 1050 | ||
954 | /* We'd like to show at least 15 tasks; be less picky if we have fewer */ | 1051 | open_svg(filename, tchart->numcpus, count, tchart->first_time, tchart->last_time); |
955 | if (count < 15) | ||
956 | count = determine_display_tasks(TIME_THRESH / 10); | ||
957 | |||
958 | open_svg(filename, numcpus, count, first_time, last_time); | ||
959 | 1052 | ||
960 | svg_time_grid(); | 1053 | svg_time_grid(); |
961 | svg_legenda(); | 1054 | svg_legenda(); |
962 | 1055 | ||
963 | for (i = 0; i < numcpus; i++) | 1056 | for (i = 0; i < tchart->numcpus; i++) |
964 | svg_cpu_box(i, max_freq, turbo_frequency); | 1057 | svg_cpu_box(i, tchart->max_freq, tchart->turbo_frequency); |
965 | 1058 | ||
966 | draw_cpu_usage(); | 1059 | draw_cpu_usage(tchart); |
967 | draw_process_bars(); | 1060 | if (tchart->proc_num) |
968 | draw_c_p_states(); | 1061 | draw_process_bars(tchart); |
969 | draw_wakeups(); | 1062 | if (!tchart->tasks_only) |
1063 | draw_c_p_states(tchart); | ||
1064 | if (tchart->proc_num) | ||
1065 | draw_wakeups(tchart); | ||
970 | 1066 | ||
971 | svg_close(); | 1067 | svg_close(); |
972 | } | 1068 | } |
973 | 1069 | ||
974 | static int __cmd_timechart(const char *output_name) | 1070 | static int process_header(struct perf_file_section *section __maybe_unused, |
1071 | struct perf_header *ph, | ||
1072 | int feat, | ||
1073 | int fd __maybe_unused, | ||
1074 | void *data) | ||
1075 | { | ||
1076 | struct timechart *tchart = data; | ||
1077 | |||
1078 | switch (feat) { | ||
1079 | case HEADER_NRCPUS: | ||
1080 | tchart->numcpus = ph->env.nr_cpus_avail; | ||
1081 | break; | ||
1082 | |||
1083 | case HEADER_CPU_TOPOLOGY: | ||
1084 | if (!tchart->topology) | ||
1085 | break; | ||
1086 | |||
1087 | if (svg_build_topology_map(ph->env.sibling_cores, | ||
1088 | ph->env.nr_sibling_cores, | ||
1089 | ph->env.sibling_threads, | ||
1090 | ph->env.nr_sibling_threads)) | ||
1091 | fprintf(stderr, "problem building topology\n"); | ||
1092 | break; | ||
1093 | |||
1094 | default: | ||
1095 | break; | ||
1096 | } | ||
1097 | |||
1098 | return 0; | ||
1099 | } | ||
1100 | |||
1101 | static int __cmd_timechart(struct timechart *tchart, const char *output_name) | ||
975 | { | 1102 | { |
976 | struct perf_tool perf_timechart = { | ||
977 | .comm = process_comm_event, | ||
978 | .fork = process_fork_event, | ||
979 | .exit = process_exit_event, | ||
980 | .sample = process_sample_event, | ||
981 | .ordered_samples = true, | ||
982 | }; | ||
983 | const struct perf_evsel_str_handler power_tracepoints[] = { | 1103 | const struct perf_evsel_str_handler power_tracepoints[] = { |
984 | { "power:cpu_idle", process_sample_cpu_idle }, | 1104 | { "power:cpu_idle", process_sample_cpu_idle }, |
985 | { "power:cpu_frequency", process_sample_cpu_frequency }, | 1105 | { "power:cpu_frequency", process_sample_cpu_frequency }, |
@@ -997,12 +1117,17 @@ static int __cmd_timechart(const char *output_name) | |||
997 | }; | 1117 | }; |
998 | 1118 | ||
999 | struct perf_session *session = perf_session__new(&file, false, | 1119 | struct perf_session *session = perf_session__new(&file, false, |
1000 | &perf_timechart); | 1120 | &tchart->tool); |
1001 | int ret = -EINVAL; | 1121 | int ret = -EINVAL; |
1002 | 1122 | ||
1003 | if (session == NULL) | 1123 | if (session == NULL) |
1004 | return -ENOMEM; | 1124 | return -ENOMEM; |
1005 | 1125 | ||
1126 | (void)perf_header__process_sections(&session->header, | ||
1127 | perf_data_file__fd(session->file), | ||
1128 | tchart, | ||
1129 | process_header); | ||
1130 | |||
1006 | if (!perf_session__has_traces(session, "timechart record")) | 1131 | if (!perf_session__has_traces(session, "timechart record")) |
1007 | goto out_delete; | 1132 | goto out_delete; |
1008 | 1133 | ||
@@ -1012,69 +1137,111 @@ static int __cmd_timechart(const char *output_name) | |||
1012 | goto out_delete; | 1137 | goto out_delete; |
1013 | } | 1138 | } |
1014 | 1139 | ||
1015 | ret = perf_session__process_events(session, &perf_timechart); | 1140 | ret = perf_session__process_events(session, &tchart->tool); |
1016 | if (ret) | 1141 | if (ret) |
1017 | goto out_delete; | 1142 | goto out_delete; |
1018 | 1143 | ||
1019 | end_sample_processing(); | 1144 | end_sample_processing(tchart); |
1020 | 1145 | ||
1021 | sort_pids(); | 1146 | sort_pids(tchart); |
1022 | 1147 | ||
1023 | write_svg_file(output_name); | 1148 | write_svg_file(tchart, output_name); |
1024 | 1149 | ||
1025 | pr_info("Written %2.1f seconds of trace to %s.\n", | 1150 | pr_info("Written %2.1f seconds of trace to %s.\n", |
1026 | (last_time - first_time) / 1000000000.0, output_name); | 1151 | (tchart->last_time - tchart->first_time) / 1000000000.0, output_name); |
1027 | out_delete: | 1152 | out_delete: |
1028 | perf_session__delete(session); | 1153 | perf_session__delete(session); |
1029 | return ret; | 1154 | return ret; |
1030 | } | 1155 | } |
1031 | 1156 | ||
1032 | static int __cmd_record(int argc, const char **argv) | 1157 | static int timechart__record(struct timechart *tchart, int argc, const char **argv) |
1033 | { | 1158 | { |
1034 | #ifdef SUPPORT_OLD_POWER_EVENTS | 1159 | unsigned int rec_argc, i, j; |
1035 | const char * const record_old_args[] = { | 1160 | const char **rec_argv; |
1161 | const char **p; | ||
1162 | unsigned int record_elems; | ||
1163 | |||
1164 | const char * const common_args[] = { | ||
1036 | "record", "-a", "-R", "-c", "1", | 1165 | "record", "-a", "-R", "-c", "1", |
1166 | }; | ||
1167 | unsigned int common_args_nr = ARRAY_SIZE(common_args); | ||
1168 | |||
1169 | const char * const backtrace_args[] = { | ||
1170 | "-g", | ||
1171 | }; | ||
1172 | unsigned int backtrace_args_no = ARRAY_SIZE(backtrace_args); | ||
1173 | |||
1174 | const char * const power_args[] = { | ||
1175 | "-e", "power:cpu_frequency", | ||
1176 | "-e", "power:cpu_idle", | ||
1177 | }; | ||
1178 | unsigned int power_args_nr = ARRAY_SIZE(power_args); | ||
1179 | |||
1180 | const char * const old_power_args[] = { | ||
1181 | #ifdef SUPPORT_OLD_POWER_EVENTS | ||
1037 | "-e", "power:power_start", | 1182 | "-e", "power:power_start", |
1038 | "-e", "power:power_end", | 1183 | "-e", "power:power_end", |
1039 | "-e", "power:power_frequency", | 1184 | "-e", "power:power_frequency", |
1040 | "-e", "sched:sched_wakeup", | ||
1041 | "-e", "sched:sched_switch", | ||
1042 | }; | ||
1043 | #endif | 1185 | #endif |
1044 | const char * const record_new_args[] = { | 1186 | }; |
1045 | "record", "-a", "-R", "-c", "1", | 1187 | unsigned int old_power_args_nr = ARRAY_SIZE(old_power_args); |
1046 | "-e", "power:cpu_frequency", | 1188 | |
1047 | "-e", "power:cpu_idle", | 1189 | const char * const tasks_args[] = { |
1048 | "-e", "sched:sched_wakeup", | 1190 | "-e", "sched:sched_wakeup", |
1049 | "-e", "sched:sched_switch", | 1191 | "-e", "sched:sched_switch", |
1050 | }; | 1192 | }; |
1051 | unsigned int rec_argc, i, j; | 1193 | unsigned int tasks_args_nr = ARRAY_SIZE(tasks_args); |
1052 | const char **rec_argv; | ||
1053 | const char * const *record_args = record_new_args; | ||
1054 | unsigned int record_elems = ARRAY_SIZE(record_new_args); | ||
1055 | 1194 | ||
1056 | #ifdef SUPPORT_OLD_POWER_EVENTS | 1195 | #ifdef SUPPORT_OLD_POWER_EVENTS |
1057 | if (!is_valid_tracepoint("power:cpu_idle") && | 1196 | if (!is_valid_tracepoint("power:cpu_idle") && |
1058 | is_valid_tracepoint("power:power_start")) { | 1197 | is_valid_tracepoint("power:power_start")) { |
1059 | use_old_power_events = 1; | 1198 | use_old_power_events = 1; |
1060 | record_args = record_old_args; | 1199 | power_args_nr = 0; |
1061 | record_elems = ARRAY_SIZE(record_old_args); | 1200 | } else { |
1201 | old_power_args_nr = 0; | ||
1062 | } | 1202 | } |
1063 | #endif | 1203 | #endif |
1064 | 1204 | ||
1065 | rec_argc = record_elems + argc - 1; | 1205 | if (tchart->power_only) |
1206 | tasks_args_nr = 0; | ||
1207 | |||
1208 | if (tchart->tasks_only) { | ||
1209 | power_args_nr = 0; | ||
1210 | old_power_args_nr = 0; | ||
1211 | } | ||
1212 | |||
1213 | if (!tchart->with_backtrace) | ||
1214 | backtrace_args_no = 0; | ||
1215 | |||
1216 | record_elems = common_args_nr + tasks_args_nr + | ||
1217 | power_args_nr + old_power_args_nr + backtrace_args_no; | ||
1218 | |||
1219 | rec_argc = record_elems + argc; | ||
1066 | rec_argv = calloc(rec_argc + 1, sizeof(char *)); | 1220 | rec_argv = calloc(rec_argc + 1, sizeof(char *)); |
1067 | 1221 | ||
1068 | if (rec_argv == NULL) | 1222 | if (rec_argv == NULL) |
1069 | return -ENOMEM; | 1223 | return -ENOMEM; |
1070 | 1224 | ||
1071 | for (i = 0; i < record_elems; i++) | 1225 | p = rec_argv; |
1072 | rec_argv[i] = strdup(record_args[i]); | 1226 | for (i = 0; i < common_args_nr; i++) |
1227 | *p++ = strdup(common_args[i]); | ||
1228 | |||
1229 | for (i = 0; i < backtrace_args_no; i++) | ||
1230 | *p++ = strdup(backtrace_args[i]); | ||
1231 | |||
1232 | for (i = 0; i < tasks_args_nr; i++) | ||
1233 | *p++ = strdup(tasks_args[i]); | ||
1234 | |||
1235 | for (i = 0; i < power_args_nr; i++) | ||
1236 | *p++ = strdup(power_args[i]); | ||
1073 | 1237 | ||
1074 | for (j = 1; j < (unsigned int)argc; j++, i++) | 1238 | for (i = 0; i < old_power_args_nr; i++) |
1075 | rec_argv[i] = argv[j]; | 1239 | *p++ = strdup(old_power_args[i]); |
1076 | 1240 | ||
1077 | return cmd_record(i, rec_argv, NULL); | 1241 | for (j = 1; j < (unsigned int)argc; j++) |
1242 | *p++ = argv[j]; | ||
1243 | |||
1244 | return cmd_record(rec_argc, rec_argv, NULL); | ||
1078 | } | 1245 | } |
1079 | 1246 | ||
1080 | static int | 1247 | static int |
@@ -1086,20 +1253,56 @@ parse_process(const struct option *opt __maybe_unused, const char *arg, | |||
1086 | return 0; | 1253 | return 0; |
1087 | } | 1254 | } |
1088 | 1255 | ||
1256 | static int | ||
1257 | parse_highlight(const struct option *opt __maybe_unused, const char *arg, | ||
1258 | int __maybe_unused unset) | ||
1259 | { | ||
1260 | unsigned long duration = strtoul(arg, NULL, 0); | ||
1261 | |||
1262 | if (svg_highlight || svg_highlight_name) | ||
1263 | return -1; | ||
1264 | |||
1265 | if (duration) | ||
1266 | svg_highlight = duration; | ||
1267 | else | ||
1268 | svg_highlight_name = strdup(arg); | ||
1269 | |||
1270 | return 0; | ||
1271 | } | ||
1272 | |||
1089 | int cmd_timechart(int argc, const char **argv, | 1273 | int cmd_timechart(int argc, const char **argv, |
1090 | const char *prefix __maybe_unused) | 1274 | const char *prefix __maybe_unused) |
1091 | { | 1275 | { |
1276 | struct timechart tchart = { | ||
1277 | .tool = { | ||
1278 | .comm = process_comm_event, | ||
1279 | .fork = process_fork_event, | ||
1280 | .exit = process_exit_event, | ||
1281 | .sample = process_sample_event, | ||
1282 | .ordered_samples = true, | ||
1283 | }, | ||
1284 | .proc_num = 15, | ||
1285 | }; | ||
1092 | const char *output_name = "output.svg"; | 1286 | const char *output_name = "output.svg"; |
1093 | const struct option options[] = { | 1287 | const struct option timechart_options[] = { |
1094 | OPT_STRING('i', "input", &input_name, "file", "input file name"), | 1288 | OPT_STRING('i', "input", &input_name, "file", "input file name"), |
1095 | OPT_STRING('o', "output", &output_name, "file", "output file name"), | 1289 | OPT_STRING('o', "output", &output_name, "file", "output file name"), |
1096 | OPT_INTEGER('w', "width", &svg_page_width, "page width"), | 1290 | OPT_INTEGER('w', "width", &svg_page_width, "page width"), |
1097 | OPT_BOOLEAN('P', "power-only", &power_only, "output power data only"), | 1291 | OPT_CALLBACK(0, "highlight", NULL, "duration or task name", |
1292 | "highlight tasks. Pass duration in ns or process name.", | ||
1293 | parse_highlight), | ||
1294 | OPT_BOOLEAN('P', "power-only", &tchart.power_only, "output power data only"), | ||
1295 | OPT_BOOLEAN('T', "tasks-only", &tchart.tasks_only, | ||
1296 | "output processes data only"), | ||
1098 | OPT_CALLBACK('p', "process", NULL, "process", | 1297 | OPT_CALLBACK('p', "process", NULL, "process", |
1099 | "process selector. Pass a pid or process name.", | 1298 | "process selector. Pass a pid or process name.", |
1100 | parse_process), | 1299 | parse_process), |
1101 | OPT_STRING(0, "symfs", &symbol_conf.symfs, "directory", | 1300 | OPT_STRING(0, "symfs", &symbol_conf.symfs, "directory", |
1102 | "Look for files with symbols relative to this directory"), | 1301 | "Look for files with symbols relative to this directory"), |
1302 | OPT_INTEGER('n', "proc-num", &tchart.proc_num, | ||
1303 | "min. number of tasks to print"), | ||
1304 | OPT_BOOLEAN('t', "topology", &tchart.topology, | ||
1305 | "sort CPUs according to topology"), | ||
1103 | OPT_END() | 1306 | OPT_END() |
1104 | }; | 1307 | }; |
1105 | const char * const timechart_usage[] = { | 1308 | const char * const timechart_usage[] = { |
@@ -1107,17 +1310,41 @@ int cmd_timechart(int argc, const char **argv, | |||
1107 | NULL | 1310 | NULL |
1108 | }; | 1311 | }; |
1109 | 1312 | ||
1110 | argc = parse_options(argc, argv, options, timechart_usage, | 1313 | const struct option record_options[] = { |
1314 | OPT_BOOLEAN('P', "power-only", &tchart.power_only, "output power data only"), | ||
1315 | OPT_BOOLEAN('T', "tasks-only", &tchart.tasks_only, | ||
1316 | "output processes data only"), | ||
1317 | OPT_BOOLEAN('g', "callchain", &tchart.with_backtrace, "record callchain"), | ||
1318 | OPT_END() | ||
1319 | }; | ||
1320 | const char * const record_usage[] = { | ||
1321 | "perf timechart record [<options>]", | ||
1322 | NULL | ||
1323 | }; | ||
1324 | argc = parse_options(argc, argv, timechart_options, timechart_usage, | ||
1111 | PARSE_OPT_STOP_AT_NON_OPTION); | 1325 | PARSE_OPT_STOP_AT_NON_OPTION); |
1112 | 1326 | ||
1327 | if (tchart.power_only && tchart.tasks_only) { | ||
1328 | pr_err("-P and -T options cannot be used at the same time.\n"); | ||
1329 | return -1; | ||
1330 | } | ||
1331 | |||
1113 | symbol__init(); | 1332 | symbol__init(); |
1114 | 1333 | ||
1115 | if (argc && !strncmp(argv[0], "rec", 3)) | 1334 | if (argc && !strncmp(argv[0], "rec", 3)) { |
1116 | return __cmd_record(argc, argv); | 1335 | argc = parse_options(argc, argv, record_options, record_usage, |
1117 | else if (argc) | 1336 | PARSE_OPT_STOP_AT_NON_OPTION); |
1118 | usage_with_options(timechart_usage, options); | 1337 | |
1338 | if (tchart.power_only && tchart.tasks_only) { | ||
1339 | pr_err("-P and -T options cannot be used at the same time.\n"); | ||
1340 | return -1; | ||
1341 | } | ||
1342 | |||
1343 | return timechart__record(&tchart, argc, argv); | ||
1344 | } else if (argc) | ||
1345 | usage_with_options(timechart_usage, timechart_options); | ||
1119 | 1346 | ||
1120 | setup_pager(); | 1347 | setup_pager(); |
1121 | 1348 | ||
1122 | return __cmd_timechart(output_name); | 1349 | return __cmd_timechart(&tchart, output_name); |
1123 | } | 1350 | } |
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index 71e6402729a8..5f989a7d8bc2 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c | |||
@@ -176,7 +176,7 @@ static void perf_top__record_precise_ip(struct perf_top *top, | |||
176 | { | 176 | { |
177 | struct annotation *notes; | 177 | struct annotation *notes; |
178 | struct symbol *sym; | 178 | struct symbol *sym; |
179 | int err; | 179 | int err = 0; |
180 | 180 | ||
181 | if (he == NULL || he->ms.sym == NULL || | 181 | if (he == NULL || he->ms.sym == NULL || |
182 | ((top->sym_filter_entry == NULL || | 182 | ((top->sym_filter_entry == NULL || |
@@ -189,21 +189,20 @@ static void perf_top__record_precise_ip(struct perf_top *top, | |||
189 | if (pthread_mutex_trylock(¬es->lock)) | 189 | if (pthread_mutex_trylock(¬es->lock)) |
190 | return; | 190 | return; |
191 | 191 | ||
192 | if (notes->src == NULL && symbol__alloc_hist(sym) < 0) { | ||
193 | pthread_mutex_unlock(¬es->lock); | ||
194 | pr_err("Not enough memory for annotating '%s' symbol!\n", | ||
195 | sym->name); | ||
196 | sleep(1); | ||
197 | return; | ||
198 | } | ||
199 | |||
200 | ip = he->ms.map->map_ip(he->ms.map, ip); | 192 | ip = he->ms.map->map_ip(he->ms.map, ip); |
201 | err = symbol__inc_addr_samples(sym, he->ms.map, counter, ip); | 193 | |
194 | if (ui__has_annotation()) | ||
195 | err = hist_entry__inc_addr_samples(he, counter, ip); | ||
202 | 196 | ||
203 | pthread_mutex_unlock(¬es->lock); | 197 | pthread_mutex_unlock(¬es->lock); |
204 | 198 | ||
205 | if (err == -ERANGE && !he->ms.map->erange_warned) | 199 | if (err == -ERANGE && !he->ms.map->erange_warned) |
206 | ui__warn_map_erange(he->ms.map, sym, ip); | 200 | ui__warn_map_erange(he->ms.map, sym, ip); |
201 | else if (err == -ENOMEM) { | ||
202 | pr_err("Not enough memory for annotating '%s' symbol!\n", | ||
203 | sym->name); | ||
204 | sleep(1); | ||
205 | } | ||
207 | } | 206 | } |
208 | 207 | ||
209 | static void perf_top__show_details(struct perf_top *top) | 208 | static void perf_top__show_details(struct perf_top *top) |
@@ -485,7 +484,7 @@ static bool perf_top__handle_keypress(struct perf_top *top, int c) | |||
485 | 484 | ||
486 | fprintf(stderr, "\nAvailable events:"); | 485 | fprintf(stderr, "\nAvailable events:"); |
487 | 486 | ||
488 | list_for_each_entry(top->sym_evsel, &top->evlist->entries, node) | 487 | evlist__for_each(top->evlist, top->sym_evsel) |
489 | fprintf(stderr, "\n\t%d %s", top->sym_evsel->idx, perf_evsel__name(top->sym_evsel)); | 488 | fprintf(stderr, "\n\t%d %s", top->sym_evsel->idx, perf_evsel__name(top->sym_evsel)); |
490 | 489 | ||
491 | prompt_integer(&counter, "Enter details event counter"); | 490 | prompt_integer(&counter, "Enter details event counter"); |
@@ -496,7 +495,7 @@ static bool perf_top__handle_keypress(struct perf_top *top, int c) | |||
496 | sleep(1); | 495 | sleep(1); |
497 | break; | 496 | break; |
498 | } | 497 | } |
499 | list_for_each_entry(top->sym_evsel, &top->evlist->entries, node) | 498 | evlist__for_each(top->evlist, top->sym_evsel) |
500 | if (top->sym_evsel->idx == counter) | 499 | if (top->sym_evsel->idx == counter) |
501 | break; | 500 | break; |
502 | } else | 501 | } else |
@@ -578,7 +577,7 @@ static void *display_thread_tui(void *arg) | |||
578 | * Zooming in/out UIDs. For now juse use whatever the user passed | 577 | * Zooming in/out UIDs. For now juse use whatever the user passed |
579 | * via --uid. | 578 | * via --uid. |
580 | */ | 579 | */ |
581 | list_for_each_entry(pos, &top->evlist->entries, node) | 580 | evlist__for_each(top->evlist, pos) |
582 | pos->hists.uid_filter_str = top->record_opts.target.uid_str; | 581 | pos->hists.uid_filter_str = top->record_opts.target.uid_str; |
583 | 582 | ||
584 | perf_evlist__tui_browse_hists(top->evlist, help, &hbt, top->min_percent, | 583 | perf_evlist__tui_browse_hists(top->evlist, help, &hbt, top->min_percent, |
@@ -634,26 +633,9 @@ repeat: | |||
634 | return NULL; | 633 | return NULL; |
635 | } | 634 | } |
636 | 635 | ||
637 | /* Tag samples to be skipped. */ | ||
638 | static const char *skip_symbols[] = { | ||
639 | "intel_idle", | ||
640 | "default_idle", | ||
641 | "native_safe_halt", | ||
642 | "cpu_idle", | ||
643 | "enter_idle", | ||
644 | "exit_idle", | ||
645 | "mwait_idle", | ||
646 | "mwait_idle_with_hints", | ||
647 | "poll_idle", | ||
648 | "ppc64_runlatch_off", | ||
649 | "pseries_dedicated_idle_sleep", | ||
650 | NULL | ||
651 | }; | ||
652 | |||
653 | static int symbol_filter(struct map *map __maybe_unused, struct symbol *sym) | 636 | static int symbol_filter(struct map *map __maybe_unused, struct symbol *sym) |
654 | { | 637 | { |
655 | const char *name = sym->name; | 638 | const char *name = sym->name; |
656 | int i; | ||
657 | 639 | ||
658 | /* | 640 | /* |
659 | * ppc64 uses function descriptors and appends a '.' to the | 641 | * ppc64 uses function descriptors and appends a '.' to the |
@@ -671,12 +653,8 @@ static int symbol_filter(struct map *map __maybe_unused, struct symbol *sym) | |||
671 | strstr(name, "_text_end")) | 653 | strstr(name, "_text_end")) |
672 | return 1; | 654 | return 1; |
673 | 655 | ||
674 | for (i = 0; skip_symbols[i]; i++) { | 656 | if (symbol__is_idle(sym)) |
675 | if (!strcmp(skip_symbols[i], name)) { | 657 | sym->ignore = true; |
676 | sym->ignore = true; | ||
677 | break; | ||
678 | } | ||
679 | } | ||
680 | 658 | ||
681 | return 0; | 659 | return 0; |
682 | } | 660 | } |
@@ -767,15 +745,10 @@ static void perf_event__process_sample(struct perf_tool *tool, | |||
767 | if (al.sym == NULL || !al.sym->ignore) { | 745 | if (al.sym == NULL || !al.sym->ignore) { |
768 | struct hist_entry *he; | 746 | struct hist_entry *he; |
769 | 747 | ||
770 | if ((sort__has_parent || symbol_conf.use_callchain) && | 748 | err = sample__resolve_callchain(sample, &parent, evsel, &al, |
771 | sample->callchain) { | 749 | top->max_stack); |
772 | err = machine__resolve_callchain(machine, evsel, | 750 | if (err) |
773 | al.thread, sample, | 751 | return; |
774 | &parent, &al, | ||
775 | top->max_stack); | ||
776 | if (err) | ||
777 | return; | ||
778 | } | ||
779 | 752 | ||
780 | he = perf_evsel__add_hist_entry(evsel, &al, sample); | 753 | he = perf_evsel__add_hist_entry(evsel, &al, sample); |
781 | if (he == NULL) { | 754 | if (he == NULL) { |
@@ -783,12 +756,9 @@ static void perf_event__process_sample(struct perf_tool *tool, | |||
783 | return; | 756 | return; |
784 | } | 757 | } |
785 | 758 | ||
786 | if (symbol_conf.use_callchain) { | 759 | err = hist_entry__append_callchain(he, sample); |
787 | err = callchain_append(he->callchain, &callchain_cursor, | 760 | if (err) |
788 | sample->period); | 761 | return; |
789 | if (err) | ||
790 | return; | ||
791 | } | ||
792 | 762 | ||
793 | if (sort__has_sym) | 763 | if (sort__has_sym) |
794 | perf_top__record_precise_ip(top, he, evsel->idx, ip); | 764 | perf_top__record_precise_ip(top, he, evsel->idx, ip); |
@@ -878,11 +848,11 @@ static int perf_top__start_counters(struct perf_top *top) | |||
878 | char msg[512]; | 848 | char msg[512]; |
879 | struct perf_evsel *counter; | 849 | struct perf_evsel *counter; |
880 | struct perf_evlist *evlist = top->evlist; | 850 | struct perf_evlist *evlist = top->evlist; |
881 | struct perf_record_opts *opts = &top->record_opts; | 851 | struct record_opts *opts = &top->record_opts; |
882 | 852 | ||
883 | perf_evlist__config(evlist, opts); | 853 | perf_evlist__config(evlist, opts); |
884 | 854 | ||
885 | list_for_each_entry(counter, &evlist->entries, node) { | 855 | evlist__for_each(evlist, counter) { |
886 | try_again: | 856 | try_again: |
887 | if (perf_evsel__open(counter, top->evlist->cpus, | 857 | if (perf_evsel__open(counter, top->evlist->cpus, |
888 | top->evlist->threads) < 0) { | 858 | top->evlist->threads) < 0) { |
@@ -930,7 +900,7 @@ static int perf_top__setup_sample_type(struct perf_top *top __maybe_unused) | |||
930 | 900 | ||
931 | static int __cmd_top(struct perf_top *top) | 901 | static int __cmd_top(struct perf_top *top) |
932 | { | 902 | { |
933 | struct perf_record_opts *opts = &top->record_opts; | 903 | struct record_opts *opts = &top->record_opts; |
934 | pthread_t thread; | 904 | pthread_t thread; |
935 | int ret; | 905 | int ret; |
936 | 906 | ||
@@ -1052,7 +1022,7 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused) | |||
1052 | .max_stack = PERF_MAX_STACK_DEPTH, | 1022 | .max_stack = PERF_MAX_STACK_DEPTH, |
1053 | .sym_pcnt_filter = 5, | 1023 | .sym_pcnt_filter = 5, |
1054 | }; | 1024 | }; |
1055 | struct perf_record_opts *opts = &top.record_opts; | 1025 | struct record_opts *opts = &top.record_opts; |
1056 | struct target *target = &opts->target; | 1026 | struct target *target = &opts->target; |
1057 | const struct option options[] = { | 1027 | const struct option options[] = { |
1058 | OPT_CALLBACK('e', "event", &top.evlist, "event", | 1028 | OPT_CALLBACK('e', "event", &top.evlist, "event", |
@@ -1084,7 +1054,7 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused) | |||
1084 | "dump the symbol table used for profiling"), | 1054 | "dump the symbol table used for profiling"), |
1085 | OPT_INTEGER('f', "count-filter", &top.count_filter, | 1055 | OPT_INTEGER('f', "count-filter", &top.count_filter, |
1086 | "only display functions with more events than this"), | 1056 | "only display functions with more events than this"), |
1087 | OPT_BOOLEAN('g', "group", &opts->group, | 1057 | OPT_BOOLEAN(0, "group", &opts->group, |
1088 | "put the counters into a counter group"), | 1058 | "put the counters into a counter group"), |
1089 | OPT_BOOLEAN('i', "no-inherit", &opts->no_inherit, | 1059 | OPT_BOOLEAN('i', "no-inherit", &opts->no_inherit, |
1090 | "child tasks do not inherit counters"), | 1060 | "child tasks do not inherit counters"), |
@@ -1105,7 +1075,7 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused) | |||
1105 | " abort, in_tx, transaction"), | 1075 | " abort, in_tx, transaction"), |
1106 | OPT_BOOLEAN('n', "show-nr-samples", &symbol_conf.show_nr_samples, | 1076 | OPT_BOOLEAN('n', "show-nr-samples", &symbol_conf.show_nr_samples, |
1107 | "Show a column with the number of samples"), | 1077 | "Show a column with the number of samples"), |
1108 | OPT_CALLBACK_NOOPT('G', NULL, &top.record_opts, | 1078 | OPT_CALLBACK_NOOPT('g', NULL, &top.record_opts, |
1109 | NULL, "enables call-graph recording", | 1079 | NULL, "enables call-graph recording", |
1110 | &callchain_opt), | 1080 | &callchain_opt), |
1111 | OPT_CALLBACK(0, "call-graph", &top.record_opts, | 1081 | OPT_CALLBACK(0, "call-graph", &top.record_opts, |
@@ -1195,7 +1165,7 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused) | |||
1195 | if (!top.evlist->nr_entries && | 1165 | if (!top.evlist->nr_entries && |
1196 | perf_evlist__add_default(top.evlist) < 0) { | 1166 | perf_evlist__add_default(top.evlist) < 0) { |
1197 | ui__error("Not enough memory for event selector list\n"); | 1167 | ui__error("Not enough memory for event selector list\n"); |
1198 | goto out_delete_maps; | 1168 | goto out_delete_evlist; |
1199 | } | 1169 | } |
1200 | 1170 | ||
1201 | symbol_conf.nr_events = top.evlist->nr_entries; | 1171 | symbol_conf.nr_events = top.evlist->nr_entries; |
@@ -1203,9 +1173,9 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused) | |||
1203 | if (top.delay_secs < 1) | 1173 | if (top.delay_secs < 1) |
1204 | top.delay_secs = 1; | 1174 | top.delay_secs = 1; |
1205 | 1175 | ||
1206 | if (perf_record_opts__config(opts)) { | 1176 | if (record_opts__config(opts)) { |
1207 | status = -EINVAL; | 1177 | status = -EINVAL; |
1208 | goto out_delete_maps; | 1178 | goto out_delete_evlist; |
1209 | } | 1179 | } |
1210 | 1180 | ||
1211 | top.sym_evsel = perf_evlist__first(top.evlist); | 1181 | top.sym_evsel = perf_evlist__first(top.evlist); |
@@ -1230,8 +1200,6 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused) | |||
1230 | 1200 | ||
1231 | status = __cmd_top(&top); | 1201 | status = __cmd_top(&top); |
1232 | 1202 | ||
1233 | out_delete_maps: | ||
1234 | perf_evlist__delete_maps(top.evlist); | ||
1235 | out_delete_evlist: | 1203 | out_delete_evlist: |
1236 | perf_evlist__delete(top.evlist); | 1204 | perf_evlist__delete(top.evlist); |
1237 | 1205 | ||
diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c index 8be17fc462ba..f954c26de231 100644 --- a/tools/perf/builtin-trace.c +++ b/tools/perf/builtin-trace.c | |||
@@ -11,6 +11,8 @@ | |||
11 | #include "util/intlist.h" | 11 | #include "util/intlist.h" |
12 | #include "util/thread_map.h" | 12 | #include "util/thread_map.h" |
13 | #include "util/stat.h" | 13 | #include "util/stat.h" |
14 | #include "trace-event.h" | ||
15 | #include "util/parse-events.h" | ||
14 | 16 | ||
15 | #include <libaudit.h> | 17 | #include <libaudit.h> |
16 | #include <stdlib.h> | 18 | #include <stdlib.h> |
@@ -35,6 +37,10 @@ | |||
35 | # define MADV_UNMERGEABLE 13 | 37 | # define MADV_UNMERGEABLE 13 |
36 | #endif | 38 | #endif |
37 | 39 | ||
40 | #ifndef EFD_SEMAPHORE | ||
41 | # define EFD_SEMAPHORE 1 | ||
42 | #endif | ||
43 | |||
38 | struct tp_field { | 44 | struct tp_field { |
39 | int offset; | 45 | int offset; |
40 | union { | 46 | union { |
@@ -144,8 +150,7 @@ static int perf_evsel__init_tp_ptr_field(struct perf_evsel *evsel, | |||
144 | 150 | ||
145 | static void perf_evsel__delete_priv(struct perf_evsel *evsel) | 151 | static void perf_evsel__delete_priv(struct perf_evsel *evsel) |
146 | { | 152 | { |
147 | free(evsel->priv); | 153 | zfree(&evsel->priv); |
148 | evsel->priv = NULL; | ||
149 | perf_evsel__delete(evsel); | 154 | perf_evsel__delete(evsel); |
150 | } | 155 | } |
151 | 156 | ||
@@ -163,8 +168,7 @@ static int perf_evsel__init_syscall_tp(struct perf_evsel *evsel, void *handler) | |||
163 | return -ENOMEM; | 168 | return -ENOMEM; |
164 | 169 | ||
165 | out_delete: | 170 | out_delete: |
166 | free(evsel->priv); | 171 | zfree(&evsel->priv); |
167 | evsel->priv = NULL; | ||
168 | return -ENOENT; | 172 | return -ENOENT; |
169 | } | 173 | } |
170 | 174 | ||
@@ -172,6 +176,10 @@ static struct perf_evsel *perf_evsel__syscall_newtp(const char *direction, void | |||
172 | { | 176 | { |
173 | struct perf_evsel *evsel = perf_evsel__newtp("raw_syscalls", direction); | 177 | struct perf_evsel *evsel = perf_evsel__newtp("raw_syscalls", direction); |
174 | 178 | ||
179 | /* older kernel (e.g., RHEL6) use syscalls:{enter,exit} */ | ||
180 | if (evsel == NULL) | ||
181 | evsel = perf_evsel__newtp("syscalls", direction); | ||
182 | |||
175 | if (evsel) { | 183 | if (evsel) { |
176 | if (perf_evsel__init_syscall_tp(evsel, handler)) | 184 | if (perf_evsel__init_syscall_tp(evsel, handler)) |
177 | goto out_delete; | 185 | goto out_delete; |
@@ -275,6 +283,11 @@ static size_t syscall_arg__scnprintf_strarray(char *bf, size_t size, | |||
275 | 283 | ||
276 | #define SCA_STRARRAY syscall_arg__scnprintf_strarray | 284 | #define SCA_STRARRAY syscall_arg__scnprintf_strarray |
277 | 285 | ||
286 | #if defined(__i386__) || defined(__x86_64__) | ||
287 | /* | ||
288 | * FIXME: Make this available to all arches as soon as the ioctl beautifier | ||
289 | * gets rewritten to support all arches. | ||
290 | */ | ||
278 | static size_t syscall_arg__scnprintf_strhexarray(char *bf, size_t size, | 291 | static size_t syscall_arg__scnprintf_strhexarray(char *bf, size_t size, |
279 | struct syscall_arg *arg) | 292 | struct syscall_arg *arg) |
280 | { | 293 | { |
@@ -282,6 +295,7 @@ static size_t syscall_arg__scnprintf_strhexarray(char *bf, size_t size, | |||
282 | } | 295 | } |
283 | 296 | ||
284 | #define SCA_STRHEXARRAY syscall_arg__scnprintf_strhexarray | 297 | #define SCA_STRHEXARRAY syscall_arg__scnprintf_strhexarray |
298 | #endif /* defined(__i386__) || defined(__x86_64__) */ | ||
285 | 299 | ||
286 | static size_t syscall_arg__scnprintf_fd(char *bf, size_t size, | 300 | static size_t syscall_arg__scnprintf_fd(char *bf, size_t size, |
287 | struct syscall_arg *arg); | 301 | struct syscall_arg *arg); |
@@ -811,7 +825,6 @@ static size_t syscall_arg__scnprintf_signum(char *bf, size_t size, struct syscal | |||
811 | P_SIGNUM(PIPE); | 825 | P_SIGNUM(PIPE); |
812 | P_SIGNUM(ALRM); | 826 | P_SIGNUM(ALRM); |
813 | P_SIGNUM(TERM); | 827 | P_SIGNUM(TERM); |
814 | P_SIGNUM(STKFLT); | ||
815 | P_SIGNUM(CHLD); | 828 | P_SIGNUM(CHLD); |
816 | P_SIGNUM(CONT); | 829 | P_SIGNUM(CONT); |
817 | P_SIGNUM(STOP); | 830 | P_SIGNUM(STOP); |
@@ -827,6 +840,15 @@ static size_t syscall_arg__scnprintf_signum(char *bf, size_t size, struct syscal | |||
827 | P_SIGNUM(IO); | 840 | P_SIGNUM(IO); |
828 | P_SIGNUM(PWR); | 841 | P_SIGNUM(PWR); |
829 | P_SIGNUM(SYS); | 842 | P_SIGNUM(SYS); |
843 | #ifdef SIGEMT | ||
844 | P_SIGNUM(EMT); | ||
845 | #endif | ||
846 | #ifdef SIGSTKFLT | ||
847 | P_SIGNUM(STKFLT); | ||
848 | #endif | ||
849 | #ifdef SIGSWI | ||
850 | P_SIGNUM(SWI); | ||
851 | #endif | ||
830 | default: break; | 852 | default: break; |
831 | } | 853 | } |
832 | 854 | ||
@@ -835,6 +857,10 @@ static size_t syscall_arg__scnprintf_signum(char *bf, size_t size, struct syscal | |||
835 | 857 | ||
836 | #define SCA_SIGNUM syscall_arg__scnprintf_signum | 858 | #define SCA_SIGNUM syscall_arg__scnprintf_signum |
837 | 859 | ||
860 | #if defined(__i386__) || defined(__x86_64__) | ||
861 | /* | ||
862 | * FIXME: Make this available to all arches. | ||
863 | */ | ||
838 | #define TCGETS 0x5401 | 864 | #define TCGETS 0x5401 |
839 | 865 | ||
840 | static const char *tioctls[] = { | 866 | static const char *tioctls[] = { |
@@ -856,6 +882,7 @@ static const char *tioctls[] = { | |||
856 | }; | 882 | }; |
857 | 883 | ||
858 | static DEFINE_STRARRAY_OFFSET(tioctls, 0x5401); | 884 | static DEFINE_STRARRAY_OFFSET(tioctls, 0x5401); |
885 | #endif /* defined(__i386__) || defined(__x86_64__) */ | ||
859 | 886 | ||
860 | #define STRARRAY(arg, name, array) \ | 887 | #define STRARRAY(arg, name, array) \ |
861 | .arg_scnprintf = { [arg] = SCA_STRARRAY, }, \ | 888 | .arg_scnprintf = { [arg] = SCA_STRARRAY, }, \ |
@@ -937,9 +964,16 @@ static struct syscall_fmt { | |||
937 | { .name = "getrlimit", .errmsg = true, STRARRAY(0, resource, rlimit_resources), }, | 964 | { .name = "getrlimit", .errmsg = true, STRARRAY(0, resource, rlimit_resources), }, |
938 | { .name = "ioctl", .errmsg = true, | 965 | { .name = "ioctl", .errmsg = true, |
939 | .arg_scnprintf = { [0] = SCA_FD, /* fd */ | 966 | .arg_scnprintf = { [0] = SCA_FD, /* fd */ |
967 | #if defined(__i386__) || defined(__x86_64__) | ||
968 | /* | ||
969 | * FIXME: Make this available to all arches. | ||
970 | */ | ||
940 | [1] = SCA_STRHEXARRAY, /* cmd */ | 971 | [1] = SCA_STRHEXARRAY, /* cmd */ |
941 | [2] = SCA_HEX, /* arg */ }, | 972 | [2] = SCA_HEX, /* arg */ }, |
942 | .arg_parm = { [1] = &strarray__tioctls, /* cmd */ }, }, | 973 | .arg_parm = { [1] = &strarray__tioctls, /* cmd */ }, }, |
974 | #else | ||
975 | [2] = SCA_HEX, /* arg */ }, }, | ||
976 | #endif | ||
943 | { .name = "kill", .errmsg = true, | 977 | { .name = "kill", .errmsg = true, |
944 | .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, }, | 978 | .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, }, |
945 | { .name = "linkat", .errmsg = true, | 979 | { .name = "linkat", .errmsg = true, |
@@ -1153,29 +1187,30 @@ struct trace { | |||
1153 | int max; | 1187 | int max; |
1154 | struct syscall *table; | 1188 | struct syscall *table; |
1155 | } syscalls; | 1189 | } syscalls; |
1156 | struct perf_record_opts opts; | 1190 | struct record_opts opts; |
1157 | struct machine *host; | 1191 | struct machine *host; |
1158 | u64 base_time; | 1192 | u64 base_time; |
1159 | bool full_time; | ||
1160 | FILE *output; | 1193 | FILE *output; |
1161 | unsigned long nr_events; | 1194 | unsigned long nr_events; |
1162 | struct strlist *ev_qualifier; | 1195 | struct strlist *ev_qualifier; |
1163 | bool not_ev_qualifier; | ||
1164 | bool live; | ||
1165 | const char *last_vfs_getname; | 1196 | const char *last_vfs_getname; |
1166 | struct intlist *tid_list; | 1197 | struct intlist *tid_list; |
1167 | struct intlist *pid_list; | 1198 | struct intlist *pid_list; |
1199 | double duration_filter; | ||
1200 | double runtime_ms; | ||
1201 | struct { | ||
1202 | u64 vfs_getname, | ||
1203 | proc_getname; | ||
1204 | } stats; | ||
1205 | bool not_ev_qualifier; | ||
1206 | bool live; | ||
1207 | bool full_time; | ||
1168 | bool sched; | 1208 | bool sched; |
1169 | bool multiple_threads; | 1209 | bool multiple_threads; |
1170 | bool summary; | 1210 | bool summary; |
1171 | bool summary_only; | 1211 | bool summary_only; |
1172 | bool show_comm; | 1212 | bool show_comm; |
1173 | bool show_tool_stats; | 1213 | bool show_tool_stats; |
1174 | double duration_filter; | ||
1175 | double runtime_ms; | ||
1176 | struct { | ||
1177 | u64 vfs_getname, proc_getname; | ||
1178 | } stats; | ||
1179 | }; | 1214 | }; |
1180 | 1215 | ||
1181 | static int trace__set_fd_pathname(struct thread *thread, int fd, const char *pathname) | 1216 | static int trace__set_fd_pathname(struct thread *thread, int fd, const char *pathname) |
@@ -1272,10 +1307,8 @@ static size_t syscall_arg__scnprintf_close_fd(char *bf, size_t size, | |||
1272 | size_t printed = syscall_arg__scnprintf_fd(bf, size, arg); | 1307 | size_t printed = syscall_arg__scnprintf_fd(bf, size, arg); |
1273 | struct thread_trace *ttrace = arg->thread->priv; | 1308 | struct thread_trace *ttrace = arg->thread->priv; |
1274 | 1309 | ||
1275 | if (ttrace && fd >= 0 && fd <= ttrace->paths.max) { | 1310 | if (ttrace && fd >= 0 && fd <= ttrace->paths.max) |
1276 | free(ttrace->paths.table[fd]); | 1311 | zfree(&ttrace->paths.table[fd]); |
1277 | ttrace->paths.table[fd] = NULL; | ||
1278 | } | ||
1279 | 1312 | ||
1280 | return printed; | 1313 | return printed; |
1281 | } | 1314 | } |
@@ -1430,11 +1463,11 @@ static int trace__read_syscall_info(struct trace *trace, int id) | |||
1430 | sc->fmt = syscall_fmt__find(sc->name); | 1463 | sc->fmt = syscall_fmt__find(sc->name); |
1431 | 1464 | ||
1432 | snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->name); | 1465 | snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->name); |
1433 | sc->tp_format = event_format__new("syscalls", tp_name); | 1466 | sc->tp_format = trace_event__tp_format("syscalls", tp_name); |
1434 | 1467 | ||
1435 | if (sc->tp_format == NULL && sc->fmt && sc->fmt->alias) { | 1468 | if (sc->tp_format == NULL && sc->fmt && sc->fmt->alias) { |
1436 | snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->fmt->alias); | 1469 | snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->fmt->alias); |
1437 | sc->tp_format = event_format__new("syscalls", tp_name); | 1470 | sc->tp_format = trace_event__tp_format("syscalls", tp_name); |
1438 | } | 1471 | } |
1439 | 1472 | ||
1440 | if (sc->tp_format == NULL) | 1473 | if (sc->tp_format == NULL) |
@@ -1764,8 +1797,10 @@ static int trace__process_sample(struct perf_tool *tool, | |||
1764 | if (!trace->full_time && trace->base_time == 0) | 1797 | if (!trace->full_time && trace->base_time == 0) |
1765 | trace->base_time = sample->time; | 1798 | trace->base_time = sample->time; |
1766 | 1799 | ||
1767 | if (handler) | 1800 | if (handler) { |
1801 | ++trace->nr_events; | ||
1768 | handler(trace, evsel, sample); | 1802 | handler(trace, evsel, sample); |
1803 | } | ||
1769 | 1804 | ||
1770 | return err; | 1805 | return err; |
1771 | } | 1806 | } |
@@ -1800,10 +1835,11 @@ static int trace__record(int argc, const char **argv) | |||
1800 | "-R", | 1835 | "-R", |
1801 | "-m", "1024", | 1836 | "-m", "1024", |
1802 | "-c", "1", | 1837 | "-c", "1", |
1803 | "-e", "raw_syscalls:sys_enter,raw_syscalls:sys_exit", | 1838 | "-e", |
1804 | }; | 1839 | }; |
1805 | 1840 | ||
1806 | rec_argc = ARRAY_SIZE(record_args) + argc; | 1841 | /* +1 is for the event string below */ |
1842 | rec_argc = ARRAY_SIZE(record_args) + 1 + argc; | ||
1807 | rec_argv = calloc(rec_argc + 1, sizeof(char *)); | 1843 | rec_argv = calloc(rec_argc + 1, sizeof(char *)); |
1808 | 1844 | ||
1809 | if (rec_argv == NULL) | 1845 | if (rec_argv == NULL) |
@@ -1812,6 +1848,17 @@ static int trace__record(int argc, const char **argv) | |||
1812 | for (i = 0; i < ARRAY_SIZE(record_args); i++) | 1848 | for (i = 0; i < ARRAY_SIZE(record_args); i++) |
1813 | rec_argv[i] = record_args[i]; | 1849 | rec_argv[i] = record_args[i]; |
1814 | 1850 | ||
1851 | /* event string may be different for older kernels - e.g., RHEL6 */ | ||
1852 | if (is_valid_tracepoint("raw_syscalls:sys_enter")) | ||
1853 | rec_argv[i] = "raw_syscalls:sys_enter,raw_syscalls:sys_exit"; | ||
1854 | else if (is_valid_tracepoint("syscalls:sys_enter")) | ||
1855 | rec_argv[i] = "syscalls:sys_enter,syscalls:sys_exit"; | ||
1856 | else { | ||
1857 | pr_err("Neither raw_syscalls nor syscalls events exist.\n"); | ||
1858 | return -1; | ||
1859 | } | ||
1860 | i++; | ||
1861 | |||
1815 | for (j = 0; j < (unsigned int)argc; j++, i++) | 1862 | for (j = 0; j < (unsigned int)argc; j++, i++) |
1816 | rec_argv[i] = argv[j]; | 1863 | rec_argv[i] = argv[j]; |
1817 | 1864 | ||
@@ -1869,7 +1916,7 @@ static int trace__run(struct trace *trace, int argc, const char **argv) | |||
1869 | err = trace__symbols_init(trace, evlist); | 1916 | err = trace__symbols_init(trace, evlist); |
1870 | if (err < 0) { | 1917 | if (err < 0) { |
1871 | fprintf(trace->output, "Problems initializing symbol libraries!\n"); | 1918 | fprintf(trace->output, "Problems initializing symbol libraries!\n"); |
1872 | goto out_delete_maps; | 1919 | goto out_delete_evlist; |
1873 | } | 1920 | } |
1874 | 1921 | ||
1875 | perf_evlist__config(evlist, &trace->opts); | 1922 | perf_evlist__config(evlist, &trace->opts); |
@@ -1879,10 +1926,10 @@ static int trace__run(struct trace *trace, int argc, const char **argv) | |||
1879 | 1926 | ||
1880 | if (forks) { | 1927 | if (forks) { |
1881 | err = perf_evlist__prepare_workload(evlist, &trace->opts.target, | 1928 | err = perf_evlist__prepare_workload(evlist, &trace->opts.target, |
1882 | argv, false, false); | 1929 | argv, false, NULL); |
1883 | if (err < 0) { | 1930 | if (err < 0) { |
1884 | fprintf(trace->output, "Couldn't run the workload!\n"); | 1931 | fprintf(trace->output, "Couldn't run the workload!\n"); |
1885 | goto out_delete_maps; | 1932 | goto out_delete_evlist; |
1886 | } | 1933 | } |
1887 | } | 1934 | } |
1888 | 1935 | ||
@@ -1890,10 +1937,10 @@ static int trace__run(struct trace *trace, int argc, const char **argv) | |||
1890 | if (err < 0) | 1937 | if (err < 0) |
1891 | goto out_error_open; | 1938 | goto out_error_open; |
1892 | 1939 | ||
1893 | err = perf_evlist__mmap(evlist, UINT_MAX, false); | 1940 | err = perf_evlist__mmap(evlist, trace->opts.mmap_pages, false); |
1894 | if (err < 0) { | 1941 | if (err < 0) { |
1895 | fprintf(trace->output, "Couldn't mmap the events: %s\n", strerror(errno)); | 1942 | fprintf(trace->output, "Couldn't mmap the events: %s\n", strerror(errno)); |
1896 | goto out_close_evlist; | 1943 | goto out_delete_evlist; |
1897 | } | 1944 | } |
1898 | 1945 | ||
1899 | perf_evlist__enable(evlist); | 1946 | perf_evlist__enable(evlist); |
@@ -1977,11 +2024,6 @@ out_disable: | |||
1977 | } | 2024 | } |
1978 | } | 2025 | } |
1979 | 2026 | ||
1980 | perf_evlist__munmap(evlist); | ||
1981 | out_close_evlist: | ||
1982 | perf_evlist__close(evlist); | ||
1983 | out_delete_maps: | ||
1984 | perf_evlist__delete_maps(evlist); | ||
1985 | out_delete_evlist: | 2027 | out_delete_evlist: |
1986 | perf_evlist__delete(evlist); | 2028 | perf_evlist__delete(evlist); |
1987 | out: | 2029 | out: |
@@ -2047,6 +2089,10 @@ static int trace__replay(struct trace *trace) | |||
2047 | 2089 | ||
2048 | evsel = perf_evlist__find_tracepoint_by_name(session->evlist, | 2090 | evsel = perf_evlist__find_tracepoint_by_name(session->evlist, |
2049 | "raw_syscalls:sys_enter"); | 2091 | "raw_syscalls:sys_enter"); |
2092 | /* older kernels have syscalls tp versus raw_syscalls */ | ||
2093 | if (evsel == NULL) | ||
2094 | evsel = perf_evlist__find_tracepoint_by_name(session->evlist, | ||
2095 | "syscalls:sys_enter"); | ||
2050 | if (evsel == NULL) { | 2096 | if (evsel == NULL) { |
2051 | pr_err("Data file does not have raw_syscalls:sys_enter event\n"); | 2097 | pr_err("Data file does not have raw_syscalls:sys_enter event\n"); |
2052 | goto out; | 2098 | goto out; |
@@ -2060,6 +2106,9 @@ static int trace__replay(struct trace *trace) | |||
2060 | 2106 | ||
2061 | evsel = perf_evlist__find_tracepoint_by_name(session->evlist, | 2107 | evsel = perf_evlist__find_tracepoint_by_name(session->evlist, |
2062 | "raw_syscalls:sys_exit"); | 2108 | "raw_syscalls:sys_exit"); |
2109 | if (evsel == NULL) | ||
2110 | evsel = perf_evlist__find_tracepoint_by_name(session->evlist, | ||
2111 | "syscalls:sys_exit"); | ||
2063 | if (evsel == NULL) { | 2112 | if (evsel == NULL) { |
2064 | pr_err("Data file does not have raw_syscalls:sys_exit event\n"); | 2113 | pr_err("Data file does not have raw_syscalls:sys_exit event\n"); |
2065 | goto out; | 2114 | goto out; |
@@ -2158,7 +2207,6 @@ static int trace__fprintf_one_thread(struct thread *thread, void *priv) | |||
2158 | size_t printed = data->printed; | 2207 | size_t printed = data->printed; |
2159 | struct trace *trace = data->trace; | 2208 | struct trace *trace = data->trace; |
2160 | struct thread_trace *ttrace = thread->priv; | 2209 | struct thread_trace *ttrace = thread->priv; |
2161 | const char *color; | ||
2162 | double ratio; | 2210 | double ratio; |
2163 | 2211 | ||
2164 | if (ttrace == NULL) | 2212 | if (ttrace == NULL) |
@@ -2166,17 +2214,9 @@ static int trace__fprintf_one_thread(struct thread *thread, void *priv) | |||
2166 | 2214 | ||
2167 | ratio = (double)ttrace->nr_events / trace->nr_events * 100.0; | 2215 | ratio = (double)ttrace->nr_events / trace->nr_events * 100.0; |
2168 | 2216 | ||
2169 | color = PERF_COLOR_NORMAL; | 2217 | printed += fprintf(fp, " %s (%d), ", thread__comm_str(thread), thread->tid); |
2170 | if (ratio > 50.0) | ||
2171 | color = PERF_COLOR_RED; | ||
2172 | else if (ratio > 25.0) | ||
2173 | color = PERF_COLOR_GREEN; | ||
2174 | else if (ratio > 5.0) | ||
2175 | color = PERF_COLOR_YELLOW; | ||
2176 | |||
2177 | printed += color_fprintf(fp, color, " %s (%d), ", thread__comm_str(thread), thread->tid); | ||
2178 | printed += fprintf(fp, "%lu events, ", ttrace->nr_events); | 2218 | printed += fprintf(fp, "%lu events, ", ttrace->nr_events); |
2179 | printed += color_fprintf(fp, color, "%.1f%%", ratio); | 2219 | printed += fprintf(fp, "%.1f%%", ratio); |
2180 | printed += fprintf(fp, ", %.3f msec\n", ttrace->runtime_ms); | 2220 | printed += fprintf(fp, ", %.3f msec\n", ttrace->runtime_ms); |
2181 | printed += thread__dump_stats(ttrace, trace, fp); | 2221 | printed += thread__dump_stats(ttrace, trace, fp); |
2182 | 2222 | ||
@@ -2248,7 +2288,7 @@ int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused) | |||
2248 | }, | 2288 | }, |
2249 | .user_freq = UINT_MAX, | 2289 | .user_freq = UINT_MAX, |
2250 | .user_interval = ULLONG_MAX, | 2290 | .user_interval = ULLONG_MAX, |
2251 | .no_delay = true, | 2291 | .no_buffering = true, |
2252 | .mmap_pages = 1024, | 2292 | .mmap_pages = 1024, |
2253 | }, | 2293 | }, |
2254 | .output = stdout, | 2294 | .output = stdout, |
diff --git a/tools/perf/config/Makefile b/tools/perf/config/Makefile index f7d11a811c74..0331ea2701a3 100644 --- a/tools/perf/config/Makefile +++ b/tools/perf/config/Makefile | |||
@@ -1,28 +1,26 @@ | |||
1 | uname_M := $(shell uname -m 2>/dev/null || echo not) | ||
2 | 1 | ||
3 | ARCH ?= $(shell echo $(uname_M) | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ \ | 2 | ifeq ($(src-perf),) |
4 | -e s/arm.*/arm/ -e s/sa110/arm/ \ | 3 | src-perf := $(srctree)/tools/perf |
5 | -e s/s390x/s390/ -e s/parisc64/parisc/ \ | 4 | endif |
6 | -e s/ppc.*/powerpc/ -e s/mips.*/mips/ \ | ||
7 | -e s/sh[234].*/sh/ -e s/aarch64.*/arm64/ ) | ||
8 | NO_PERF_REGS := 1 | ||
9 | CFLAGS := $(EXTRA_CFLAGS) $(EXTRA_WARNINGS) | ||
10 | 5 | ||
11 | # Additional ARCH settings for x86 | 6 | ifeq ($(obj-perf),) |
12 | ifeq ($(ARCH),i386) | 7 | obj-perf := $(OUTPUT) |
13 | override ARCH := x86 | ||
14 | NO_PERF_REGS := 0 | ||
15 | LIBUNWIND_LIBS = -lunwind -lunwind-x86 | ||
16 | endif | 8 | endif |
17 | 9 | ||
18 | ifeq ($(ARCH),x86_64) | 10 | ifneq ($(obj-perf),) |
19 | override ARCH := x86 | 11 | obj-perf := $(abspath $(obj-perf))/ |
20 | IS_X86_64 := 0 | 12 | endif |
21 | ifeq (, $(findstring m32,$(CFLAGS))) | 13 | |
22 | IS_X86_64 := $(shell echo __x86_64__ | ${CC} -E -x c - | tail -n 1) | 14 | LIB_INCLUDE := $(srctree)/tools/lib/ |
23 | endif | 15 | CFLAGS := $(EXTRA_CFLAGS) $(EXTRA_WARNINGS) |
16 | |||
17 | include $(src-perf)/config/Makefile.arch | ||
18 | |||
19 | NO_PERF_REGS := 1 | ||
20 | |||
21 | # Additional ARCH settings for x86 | ||
22 | ifeq ($(ARCH),x86) | ||
24 | ifeq (${IS_X86_64}, 1) | 23 | ifeq (${IS_X86_64}, 1) |
25 | RAW_ARCH := x86_64 | ||
26 | CFLAGS += -DHAVE_ARCH_X86_64_SUPPORT | 24 | CFLAGS += -DHAVE_ARCH_X86_64_SUPPORT |
27 | ARCH_INCLUDE = ../../arch/x86/lib/memcpy_64.S ../../arch/x86/lib/memset_64.S | 25 | ARCH_INCLUDE = ../../arch/x86/lib/memcpy_64.S ../../arch/x86/lib/memset_64.S |
28 | LIBUNWIND_LIBS = -lunwind -lunwind-x86_64 | 26 | LIBUNWIND_LIBS = -lunwind -lunwind-x86_64 |
@@ -36,24 +34,31 @@ ifeq ($(ARCH),arm) | |||
36 | LIBUNWIND_LIBS = -lunwind -lunwind-arm | 34 | LIBUNWIND_LIBS = -lunwind -lunwind-arm |
37 | endif | 35 | endif |
38 | 36 | ||
39 | ifeq ($(NO_PERF_REGS),0) | 37 | ifeq ($(LIBUNWIND_LIBS),) |
40 | CFLAGS += -DHAVE_PERF_REGS_SUPPORT | 38 | NO_LIBUNWIND := 1 |
41 | endif | 39 | else |
42 | 40 | # | |
43 | ifeq ($(src-perf),) | 41 | # For linking with debug library, run like: |
44 | src-perf := $(srctree)/tools/perf | 42 | # |
45 | endif | 43 | # make DEBUG=1 LIBUNWIND_DIR=/opt/libunwind/ |
44 | # | ||
45 | ifdef LIBUNWIND_DIR | ||
46 | LIBUNWIND_CFLAGS = -I$(LIBUNWIND_DIR)/include | ||
47 | LIBUNWIND_LDFLAGS = -L$(LIBUNWIND_DIR)/lib | ||
48 | endif | ||
49 | LIBUNWIND_LDFLAGS += $(LIBUNWIND_LIBS) | ||
46 | 50 | ||
47 | ifeq ($(obj-perf),) | 51 | # Set per-feature check compilation flags |
48 | obj-perf := $(OUTPUT) | 52 | FEATURE_CHECK_CFLAGS-libunwind = $(LIBUNWIND_CFLAGS) |
53 | FEATURE_CHECK_LDFLAGS-libunwind = $(LIBUNWIND_LDFLAGS) | ||
54 | FEATURE_CHECK_CFLAGS-libunwind-debug-frame = $(LIBUNWIND_CFLAGS) | ||
55 | FEATURE_CHECK_LDFLAGS-libunwind-debug-frame = $(LIBUNWIND_LDFLAGS) | ||
49 | endif | 56 | endif |
50 | 57 | ||
51 | ifneq ($(obj-perf),) | 58 | ifeq ($(NO_PERF_REGS),0) |
52 | obj-perf := $(abspath $(obj-perf))/ | 59 | CFLAGS += -DHAVE_PERF_REGS_SUPPORT |
53 | endif | 60 | endif |
54 | 61 | ||
55 | LIB_INCLUDE := $(srctree)/tools/lib/ | ||
56 | |||
57 | # include ARCH specific config | 62 | # include ARCH specific config |
58 | -include $(src-perf)/arch/$(ARCH)/Makefile | 63 | -include $(src-perf)/arch/$(ARCH)/Makefile |
59 | 64 | ||
@@ -102,7 +107,7 @@ endif | |||
102 | 107 | ||
103 | feature_check = $(eval $(feature_check_code)) | 108 | feature_check = $(eval $(feature_check_code)) |
104 | define feature_check_code | 109 | define feature_check_code |
105 | feature-$(1) := $(shell $(MAKE) OUTPUT=$(OUTPUT_FEATURES) CFLAGS="$(EXTRA_CFLAGS)" LDFLAGS="$(LDFLAGS)" LIBUNWIND_LIBS="$(LIBUNWIND_LIBS)" -C config/feature-checks test-$1 >/dev/null 2>/dev/null && echo 1 || echo 0) | 110 | feature-$(1) := $(shell $(MAKE) OUTPUT=$(OUTPUT_FEATURES) CFLAGS="$(EXTRA_CFLAGS) $(FEATURE_CHECK_CFLAGS-$(1))" LDFLAGS="$(LDFLAGS) $(FEATURE_CHECK_LDFLAGS-$(1))" -C config/feature-checks test-$1.bin >/dev/null 2>/dev/null && echo 1 || echo 0) |
106 | endef | 111 | endef |
107 | 112 | ||
108 | feature_set = $(eval $(feature_set_code)) | 113 | feature_set = $(eval $(feature_set_code)) |
@@ -141,16 +146,26 @@ CORE_FEATURE_TESTS = \ | |||
141 | libslang \ | 146 | libslang \ |
142 | libunwind \ | 147 | libunwind \ |
143 | on-exit \ | 148 | on-exit \ |
144 | stackprotector \ | ||
145 | stackprotector-all \ | 149 | stackprotector-all \ |
146 | timerfd | 150 | timerfd |
147 | 151 | ||
152 | # Set FEATURE_CHECK_(C|LD)FLAGS-all for all CORE_FEATURE_TESTS features. | ||
153 | # If in the future we need per-feature checks/flags for features not | ||
154 | # mentioned in this list we need to refactor this ;-). | ||
155 | set_test_all_flags = $(eval $(set_test_all_flags_code)) | ||
156 | define set_test_all_flags_code | ||
157 | FEATURE_CHECK_CFLAGS-all += $(FEATURE_CHECK_CFLAGS-$(1)) | ||
158 | FEATURE_CHECK_LDFLAGS-all += $(FEATURE_CHECK_LDFLAGS-$(1)) | ||
159 | endef | ||
160 | |||
161 | $(foreach feat,$(CORE_FEATURE_TESTS),$(call set_test_all_flags,$(feat))) | ||
162 | |||
148 | # | 163 | # |
149 | # So here we detect whether test-all was rebuilt, to be able | 164 | # So here we detect whether test-all was rebuilt, to be able |
150 | # to skip the print-out of the long features list if the file | 165 | # to skip the print-out of the long features list if the file |
151 | # existed before and after it was built: | 166 | # existed before and after it was built: |
152 | # | 167 | # |
153 | ifeq ($(wildcard $(OUTPUT)config/feature-checks/test-all),) | 168 | ifeq ($(wildcard $(OUTPUT)config/feature-checks/test-all.bin),) |
154 | test-all-failed := 1 | 169 | test-all-failed := 1 |
155 | else | 170 | else |
156 | test-all-failed := 0 | 171 | test-all-failed := 0 |
@@ -180,7 +195,7 @@ ifeq ($(feature-all), 1) | |||
180 | # | 195 | # |
181 | $(foreach feat,$(CORE_FEATURE_TESTS),$(call feature_set,$(feat))) | 196 | $(foreach feat,$(CORE_FEATURE_TESTS),$(call feature_set,$(feat))) |
182 | else | 197 | else |
183 | $(shell $(MAKE) OUTPUT=$(OUTPUT_FEATURES) CFLAGS="$(EXTRA_CFLAGS)" LDFLAGS=$(LDFLAGS) -i -j -C config/feature-checks $(CORE_FEATURE_TESTS) >/dev/null 2>&1) | 198 | $(shell $(MAKE) OUTPUT=$(OUTPUT_FEATURES) CFLAGS="$(EXTRA_CFLAGS)" LDFLAGS=$(LDFLAGS) -i -j -C config/feature-checks $(addsuffix .bin,$(CORE_FEATURE_TESTS)) >/dev/null 2>&1) |
184 | $(foreach feat,$(CORE_FEATURE_TESTS),$(call feature_check,$(feat))) | 199 | $(foreach feat,$(CORE_FEATURE_TESTS),$(call feature_check,$(feat))) |
185 | endif | 200 | endif |
186 | 201 | ||
@@ -209,10 +224,6 @@ ifeq ($(feature-stackprotector-all), 1) | |||
209 | CFLAGS += -fstack-protector-all | 224 | CFLAGS += -fstack-protector-all |
210 | endif | 225 | endif |
211 | 226 | ||
212 | ifeq ($(feature-stackprotector), 1) | ||
213 | CFLAGS += -Wstack-protector | ||
214 | endif | ||
215 | |||
216 | ifeq ($(DEBUG),0) | 227 | ifeq ($(DEBUG),0) |
217 | ifeq ($(feature-fortify-source), 1) | 228 | ifeq ($(feature-fortify-source), 1) |
218 | CFLAGS += -D_FORTIFY_SOURCE=2 | 229 | CFLAGS += -D_FORTIFY_SOURCE=2 |
@@ -221,6 +232,7 @@ endif | |||
221 | 232 | ||
222 | CFLAGS += -I$(src-perf)/util/include | 233 | CFLAGS += -I$(src-perf)/util/include |
223 | CFLAGS += -I$(src-perf)/arch/$(ARCH)/include | 234 | CFLAGS += -I$(src-perf)/arch/$(ARCH)/include |
235 | CFLAGS += -I$(srctree)/tools/include/ | ||
224 | CFLAGS += -I$(srctree)/arch/$(ARCH)/include/uapi | 236 | CFLAGS += -I$(srctree)/arch/$(ARCH)/include/uapi |
225 | CFLAGS += -I$(srctree)/arch/$(ARCH)/include | 237 | CFLAGS += -I$(srctree)/arch/$(ARCH)/include |
226 | CFLAGS += -I$(srctree)/include/uapi | 238 | CFLAGS += -I$(srctree)/include/uapi |
@@ -310,21 +322,7 @@ ifndef NO_LIBELF | |||
310 | endif # NO_DWARF | 322 | endif # NO_DWARF |
311 | endif # NO_LIBELF | 323 | endif # NO_LIBELF |
312 | 324 | ||
313 | ifeq ($(LIBUNWIND_LIBS),) | ||
314 | NO_LIBUNWIND := 1 | ||
315 | endif | ||
316 | |||
317 | ifndef NO_LIBUNWIND | 325 | ifndef NO_LIBUNWIND |
318 | # | ||
319 | # For linking with debug library, run like: | ||
320 | # | ||
321 | # make DEBUG=1 LIBUNWIND_DIR=/opt/libunwind/ | ||
322 | # | ||
323 | ifdef LIBUNWIND_DIR | ||
324 | LIBUNWIND_CFLAGS := -I$(LIBUNWIND_DIR)/include | ||
325 | LIBUNWIND_LDFLAGS := -L$(LIBUNWIND_DIR)/lib | ||
326 | endif | ||
327 | |||
328 | ifneq ($(feature-libunwind), 1) | 326 | ifneq ($(feature-libunwind), 1) |
329 | msg := $(warning No libunwind found, disabling post unwind support. Please install libunwind-dev[el] >= 1.1); | 327 | msg := $(warning No libunwind found, disabling post unwind support. Please install libunwind-dev[el] >= 1.1); |
330 | NO_LIBUNWIND := 1 | 328 | NO_LIBUNWIND := 1 |
@@ -339,14 +337,12 @@ ifndef NO_LIBUNWIND | |||
339 | # non-ARM has no dwarf_find_debug_frame() function: | 337 | # non-ARM has no dwarf_find_debug_frame() function: |
340 | CFLAGS += -DNO_LIBUNWIND_DEBUG_FRAME | 338 | CFLAGS += -DNO_LIBUNWIND_DEBUG_FRAME |
341 | endif | 339 | endif |
342 | endif | ||
343 | endif | ||
344 | 340 | ||
345 | ifndef NO_LIBUNWIND | 341 | CFLAGS += -DHAVE_LIBUNWIND_SUPPORT |
346 | CFLAGS += -DHAVE_LIBUNWIND_SUPPORT | 342 | EXTLIBS += $(LIBUNWIND_LIBS) |
347 | EXTLIBS += $(LIBUNWIND_LIBS) | 343 | CFLAGS += $(LIBUNWIND_CFLAGS) |
348 | CFLAGS += $(LIBUNWIND_CFLAGS) | 344 | LDFLAGS += $(LIBUNWIND_LDFLAGS) |
349 | LDFLAGS += $(LIBUNWIND_LDFLAGS) | 345 | endif # ifneq ($(feature-libunwind), 1) |
350 | endif | 346 | endif |
351 | 347 | ||
352 | ifndef NO_LIBAUDIT | 348 | ifndef NO_LIBAUDIT |
@@ -376,7 +372,7 @@ ifndef NO_SLANG | |||
376 | endif | 372 | endif |
377 | 373 | ||
378 | ifndef NO_GTK2 | 374 | ifndef NO_GTK2 |
379 | FLAGS_GTK2=$(CFLAGS) $(LDFLAGS) $(EXTLIBS) $(shell pkg-config --libs --cflags gtk+-2.0 2>/dev/null) | 375 | FLAGS_GTK2=$(CFLAGS) $(LDFLAGS) $(EXTLIBS) $(shell $(PKG_CONFIG) --libs --cflags gtk+-2.0 2>/dev/null) |
380 | ifneq ($(feature-gtk2), 1) | 376 | ifneq ($(feature-gtk2), 1) |
381 | msg := $(warning GTK2 not found, disables GTK2 support. Please install gtk2-devel or libgtk2.0-dev); | 377 | msg := $(warning GTK2 not found, disables GTK2 support. Please install gtk2-devel or libgtk2.0-dev); |
382 | NO_GTK2 := 1 | 378 | NO_GTK2 := 1 |
@@ -385,8 +381,8 @@ ifndef NO_GTK2 | |||
385 | GTK_CFLAGS := -DHAVE_GTK_INFO_BAR_SUPPORT | 381 | GTK_CFLAGS := -DHAVE_GTK_INFO_BAR_SUPPORT |
386 | endif | 382 | endif |
387 | CFLAGS += -DHAVE_GTK2_SUPPORT | 383 | CFLAGS += -DHAVE_GTK2_SUPPORT |
388 | GTK_CFLAGS += $(shell pkg-config --cflags gtk+-2.0 2>/dev/null) | 384 | GTK_CFLAGS += $(shell $(PKG_CONFIG) --cflags gtk+-2.0 2>/dev/null) |
389 | GTK_LIBS := $(shell pkg-config --libs gtk+-2.0 2>/dev/null) | 385 | GTK_LIBS := $(shell $(PKG_CONFIG) --libs gtk+-2.0 2>/dev/null) |
390 | EXTLIBS += -ldl | 386 | EXTLIBS += -ldl |
391 | endif | 387 | endif |
392 | endif | 388 | endif |
@@ -482,7 +478,7 @@ else | |||
482 | endif | 478 | endif |
483 | 479 | ||
484 | ifeq ($(feature-libbfd), 1) | 480 | ifeq ($(feature-libbfd), 1) |
485 | EXTLIBS += -lbfd | 481 | EXTLIBS += -lbfd -lz -liberty |
486 | endif | 482 | endif |
487 | 483 | ||
488 | ifdef NO_DEMANGLE | 484 | ifdef NO_DEMANGLE |
@@ -533,7 +529,7 @@ endif | |||
533 | 529 | ||
534 | ifndef NO_LIBNUMA | 530 | ifndef NO_LIBNUMA |
535 | ifeq ($(feature-libnuma), 0) | 531 | ifeq ($(feature-libnuma), 0) |
536 | msg := $(warning No numa.h found, disables 'perf bench numa mem' benchmark, please install numa-libs-devel or libnuma-dev); | 532 | msg := $(warning No numa.h found, disables 'perf bench numa mem' benchmark, please install numactl-devel/libnuma-devel/libnuma-dev); |
537 | NO_LIBNUMA := 1 | 533 | NO_LIBNUMA := 1 |
538 | else | 534 | else |
539 | CFLAGS += -DHAVE_LIBNUMA_SUPPORT | 535 | CFLAGS += -DHAVE_LIBNUMA_SUPPORT |
@@ -598,3 +594,11 @@ else | |||
598 | perfexec_instdir = $(prefix)/$(perfexecdir) | 594 | perfexec_instdir = $(prefix)/$(perfexecdir) |
599 | endif | 595 | endif |
600 | perfexec_instdir_SQ = $(subst ','\'',$(perfexec_instdir)) | 596 | perfexec_instdir_SQ = $(subst ','\'',$(perfexec_instdir)) |
597 | |||
598 | # If we install to $(HOME) we keep the traceevent default: | ||
599 | # $(HOME)/.traceevent/plugins | ||
600 | # Otherwise we install plugins into the global $(libdir). | ||
601 | ifdef DESTDIR | ||
602 | plugindir=$(libdir)/traceevent/plugins | ||
603 | plugindir_SQ= $(subst ','\'',$(plugindir)) | ||
604 | endif | ||
diff --git a/tools/perf/config/Makefile.arch b/tools/perf/config/Makefile.arch new file mode 100644 index 000000000000..fef8ae922800 --- /dev/null +++ b/tools/perf/config/Makefile.arch | |||
@@ -0,0 +1,22 @@ | |||
1 | |||
2 | uname_M := $(shell uname -m 2>/dev/null || echo not) | ||
3 | |||
4 | ARCH ?= $(shell echo $(uname_M) | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ \ | ||
5 | -e s/arm.*/arm/ -e s/sa110/arm/ \ | ||
6 | -e s/s390x/s390/ -e s/parisc64/parisc/ \ | ||
7 | -e s/ppc.*/powerpc/ -e s/mips.*/mips/ \ | ||
8 | -e s/sh[234].*/sh/ -e s/aarch64.*/arm64/ ) | ||
9 | |||
10 | # Additional ARCH settings for x86 | ||
11 | ifeq ($(ARCH),i386) | ||
12 | override ARCH := x86 | ||
13 | endif | ||
14 | |||
15 | ifeq ($(ARCH),x86_64) | ||
16 | override ARCH := x86 | ||
17 | IS_X86_64 := 0 | ||
18 | ifeq (, $(findstring m32,$(CFLAGS))) | ||
19 | IS_X86_64 := $(shell echo __x86_64__ | ${CC} -E -x c - | tail -n 1) | ||
20 | RAW_ARCH := x86_64 | ||
21 | endif | ||
22 | endif | ||
diff --git a/tools/perf/config/feature-checks/.gitignore b/tools/perf/config/feature-checks/.gitignore new file mode 100644 index 000000000000..80f3da0c3515 --- /dev/null +++ b/tools/perf/config/feature-checks/.gitignore | |||
@@ -0,0 +1,2 @@ | |||
1 | *.d | ||
2 | *.bin | ||
diff --git a/tools/perf/config/feature-checks/Makefile b/tools/perf/config/feature-checks/Makefile index 87e790017c69..523b7bc10553 100644 --- a/tools/perf/config/feature-checks/Makefile +++ b/tools/perf/config/feature-checks/Makefile | |||
@@ -1,95 +1,92 @@ | |||
1 | 1 | ||
2 | FILES= \ | 2 | FILES= \ |
3 | test-all \ | 3 | test-all.bin \ |
4 | test-backtrace \ | 4 | test-backtrace.bin \ |
5 | test-bionic \ | 5 | test-bionic.bin \ |
6 | test-dwarf \ | 6 | test-dwarf.bin \ |
7 | test-fortify-source \ | 7 | test-fortify-source.bin \ |
8 | test-glibc \ | 8 | test-glibc.bin \ |
9 | test-gtk2 \ | 9 | test-gtk2.bin \ |
10 | test-gtk2-infobar \ | 10 | test-gtk2-infobar.bin \ |
11 | test-hello \ | 11 | test-hello.bin \ |
12 | test-libaudit \ | 12 | test-libaudit.bin \ |
13 | test-libbfd \ | 13 | test-libbfd.bin \ |
14 | test-liberty \ | 14 | test-liberty.bin \ |
15 | test-liberty-z \ | 15 | test-liberty-z.bin \ |
16 | test-cplus-demangle \ | 16 | test-cplus-demangle.bin \ |
17 | test-libelf \ | 17 | test-libelf.bin \ |
18 | test-libelf-getphdrnum \ | 18 | test-libelf-getphdrnum.bin \ |
19 | test-libelf-mmap \ | 19 | test-libelf-mmap.bin \ |
20 | test-libnuma \ | 20 | test-libnuma.bin \ |
21 | test-libperl \ | 21 | test-libperl.bin \ |
22 | test-libpython \ | 22 | test-libpython.bin \ |
23 | test-libpython-version \ | 23 | test-libpython-version.bin \ |
24 | test-libslang \ | 24 | test-libslang.bin \ |
25 | test-libunwind \ | 25 | test-libunwind.bin \ |
26 | test-libunwind-debug-frame \ | 26 | test-libunwind-debug-frame.bin \ |
27 | test-on-exit \ | 27 | test-on-exit.bin \ |
28 | test-stackprotector-all \ | 28 | test-stackprotector-all.bin \ |
29 | test-stackprotector \ | 29 | test-timerfd.bin |
30 | test-timerfd | 30 | |
31 | 31 | CC := $(CROSS_COMPILE)gcc -MD | |
32 | CC := $(CC) -MD | 32 | PKG_CONFIG := $(CROSS_COMPILE)pkg-config |
33 | 33 | ||
34 | all: $(FILES) | 34 | all: $(FILES) |
35 | 35 | ||
36 | BUILD = $(CC) $(CFLAGS) $(LDFLAGS) -o $(OUTPUT)$@ $@.c | 36 | BUILD = $(CC) $(CFLAGS) -o $(OUTPUT)$@ $(patsubst %.bin,%.c,$@) $(LDFLAGS) |
37 | 37 | ||
38 | ############################### | 38 | ############################### |
39 | 39 | ||
40 | test-all: | 40 | test-all.bin: |
41 | $(BUILD) -Werror -fstack-protector -fstack-protector-all -O2 -Werror -D_FORTIFY_SOURCE=2 -ldw -lelf -lnuma $(LIBUNWIND_LIBS) -lelf -laudit -I/usr/include/slang -lslang $(shell pkg-config --libs --cflags gtk+-2.0 2>/dev/null) $(FLAGS_PERL_EMBED) $(FLAGS_PYTHON_EMBED) -DPACKAGE='"perf"' -lbfd -ldl | 41 | $(BUILD) -Werror -fstack-protector-all -O2 -Werror -D_FORTIFY_SOURCE=2 -ldw -lelf -lnuma -lelf -laudit -I/usr/include/slang -lslang $(shell $(PKG_CONFIG) --libs --cflags gtk+-2.0 2>/dev/null) $(FLAGS_PERL_EMBED) $(FLAGS_PYTHON_EMBED) -DPACKAGE='"perf"' -lbfd -ldl |
42 | 42 | ||
43 | test-hello: | 43 | test-hello.bin: |
44 | $(BUILD) | 44 | $(BUILD) |
45 | 45 | ||
46 | test-stackprotector-all: | 46 | test-stackprotector-all.bin: |
47 | $(BUILD) -Werror -fstack-protector-all | 47 | $(BUILD) -Werror -fstack-protector-all |
48 | 48 | ||
49 | test-stackprotector: | 49 | test-fortify-source.bin: |
50 | $(BUILD) -Werror -fstack-protector -Wstack-protector | ||
51 | |||
52 | test-fortify-source: | ||
53 | $(BUILD) -O2 -Werror -D_FORTIFY_SOURCE=2 | 50 | $(BUILD) -O2 -Werror -D_FORTIFY_SOURCE=2 |
54 | 51 | ||
55 | test-bionic: | 52 | test-bionic.bin: |
56 | $(BUILD) | 53 | $(BUILD) |
57 | 54 | ||
58 | test-libelf: | 55 | test-libelf.bin: |
59 | $(BUILD) -lelf | 56 | $(BUILD) -lelf |
60 | 57 | ||
61 | test-glibc: | 58 | test-glibc.bin: |
62 | $(BUILD) | 59 | $(BUILD) |
63 | 60 | ||
64 | test-dwarf: | 61 | test-dwarf.bin: |
65 | $(BUILD) -ldw | 62 | $(BUILD) -ldw |
66 | 63 | ||
67 | test-libelf-mmap: | 64 | test-libelf-mmap.bin: |
68 | $(BUILD) -lelf | 65 | $(BUILD) -lelf |
69 | 66 | ||
70 | test-libelf-getphdrnum: | 67 | test-libelf-getphdrnum.bin: |
71 | $(BUILD) -lelf | 68 | $(BUILD) -lelf |
72 | 69 | ||
73 | test-libnuma: | 70 | test-libnuma.bin: |
74 | $(BUILD) -lnuma | 71 | $(BUILD) -lnuma |
75 | 72 | ||
76 | test-libunwind: | 73 | test-libunwind.bin: |
77 | $(BUILD) $(LIBUNWIND_LIBS) -lelf | 74 | $(BUILD) -lelf |
78 | 75 | ||
79 | test-libunwind-debug-frame: | 76 | test-libunwind-debug-frame.bin: |
80 | $(BUILD) $(LIBUNWIND_LIBS) -lelf | 77 | $(BUILD) -lelf |
81 | 78 | ||
82 | test-libaudit: | 79 | test-libaudit.bin: |
83 | $(BUILD) -laudit | 80 | $(BUILD) -laudit |
84 | 81 | ||
85 | test-libslang: | 82 | test-libslang.bin: |
86 | $(BUILD) -I/usr/include/slang -lslang | 83 | $(BUILD) -I/usr/include/slang -lslang |
87 | 84 | ||
88 | test-gtk2: | 85 | test-gtk2.bin: |
89 | $(BUILD) $(shell pkg-config --libs --cflags gtk+-2.0 2>/dev/null) | 86 | $(BUILD) $(shell $(PKG_CONFIG) --libs --cflags gtk+-2.0 2>/dev/null) |
90 | 87 | ||
91 | test-gtk2-infobar: | 88 | test-gtk2-infobar.bin: |
92 | $(BUILD) $(shell pkg-config --libs --cflags gtk+-2.0 2>/dev/null) | 89 | $(BUILD) $(shell $(PKG_CONFIG) --libs --cflags gtk+-2.0 2>/dev/null) |
93 | 90 | ||
94 | grep-libs = $(filter -l%,$(1)) | 91 | grep-libs = $(filter -l%,$(1)) |
95 | strip-libs = $(filter-out -l%,$(1)) | 92 | strip-libs = $(filter-out -l%,$(1)) |
@@ -100,7 +97,7 @@ PERL_EMBED_LIBADD = $(call grep-libs,$(PERL_EMBED_LDOPTS)) | |||
100 | PERL_EMBED_CCOPTS = `perl -MExtUtils::Embed -e ccopts 2>/dev/null` | 97 | PERL_EMBED_CCOPTS = `perl -MExtUtils::Embed -e ccopts 2>/dev/null` |
101 | FLAGS_PERL_EMBED=$(PERL_EMBED_CCOPTS) $(PERL_EMBED_LDOPTS) | 98 | FLAGS_PERL_EMBED=$(PERL_EMBED_CCOPTS) $(PERL_EMBED_LDOPTS) |
102 | 99 | ||
103 | test-libperl: | 100 | test-libperl.bin: |
104 | $(BUILD) $(FLAGS_PERL_EMBED) | 101 | $(BUILD) $(FLAGS_PERL_EMBED) |
105 | 102 | ||
106 | override PYTHON := python | 103 | override PYTHON := python |
@@ -117,31 +114,31 @@ PYTHON_EMBED_LIBADD = $(call grep-libs,$(PYTHON_EMBED_LDOPTS)) | |||
117 | PYTHON_EMBED_CCOPTS = $(shell $(PYTHON_CONFIG_SQ) --cflags 2>/dev/null) | 114 | PYTHON_EMBED_CCOPTS = $(shell $(PYTHON_CONFIG_SQ) --cflags 2>/dev/null) |
118 | FLAGS_PYTHON_EMBED = $(PYTHON_EMBED_CCOPTS) $(PYTHON_EMBED_LDOPTS) | 115 | FLAGS_PYTHON_EMBED = $(PYTHON_EMBED_CCOPTS) $(PYTHON_EMBED_LDOPTS) |
119 | 116 | ||
120 | test-libpython: | 117 | test-libpython.bin: |
121 | $(BUILD) $(FLAGS_PYTHON_EMBED) | 118 | $(BUILD) $(FLAGS_PYTHON_EMBED) |
122 | 119 | ||
123 | test-libpython-version: | 120 | test-libpython-version.bin: |
124 | $(BUILD) $(FLAGS_PYTHON_EMBED) | 121 | $(BUILD) $(FLAGS_PYTHON_EMBED) |
125 | 122 | ||
126 | test-libbfd: | 123 | test-libbfd.bin: |
127 | $(BUILD) -DPACKAGE='"perf"' -lbfd -ldl | 124 | $(BUILD) -DPACKAGE='"perf"' -lbfd -lz -liberty -ldl |
128 | 125 | ||
129 | test-liberty: | 126 | test-liberty.bin: |
130 | $(CC) -o $(OUTPUT)$@ test-libbfd.c -DPACKAGE='"perf"' -lbfd -ldl -liberty | 127 | $(CC) -o $(OUTPUT)$@ test-libbfd.c -DPACKAGE='"perf"' -lbfd -ldl -liberty |
131 | 128 | ||
132 | test-liberty-z: | 129 | test-liberty-z.bin: |
133 | $(CC) -o $(OUTPUT)$@ test-libbfd.c -DPACKAGE='"perf"' -lbfd -ldl -liberty -lz | 130 | $(CC) -o $(OUTPUT)$@ test-libbfd.c -DPACKAGE='"perf"' -lbfd -ldl -liberty -lz |
134 | 131 | ||
135 | test-cplus-demangle: | 132 | test-cplus-demangle.bin: |
136 | $(BUILD) -liberty | 133 | $(BUILD) -liberty |
137 | 134 | ||
138 | test-on-exit: | 135 | test-on-exit.bin: |
139 | $(BUILD) | 136 | $(BUILD) |
140 | 137 | ||
141 | test-backtrace: | 138 | test-backtrace.bin: |
142 | $(BUILD) | 139 | $(BUILD) |
143 | 140 | ||
144 | test-timerfd: | 141 | test-timerfd.bin: |
145 | $(BUILD) | 142 | $(BUILD) |
146 | 143 | ||
147 | -include *.d | 144 | -include *.d |
diff --git a/tools/perf/config/feature-checks/test-all.c b/tools/perf/config/feature-checks/test-all.c index 59e7a705e146..9b8a544155bb 100644 --- a/tools/perf/config/feature-checks/test-all.c +++ b/tools/perf/config/feature-checks/test-all.c | |||
@@ -85,6 +85,10 @@ | |||
85 | # include "test-timerfd.c" | 85 | # include "test-timerfd.c" |
86 | #undef main | 86 | #undef main |
87 | 87 | ||
88 | #define main main_test_stackprotector_all | ||
89 | # include "test-stackprotector-all.c" | ||
90 | #undef main | ||
91 | |||
88 | int main(int argc, char *argv[]) | 92 | int main(int argc, char *argv[]) |
89 | { | 93 | { |
90 | main_test_libpython(); | 94 | main_test_libpython(); |
@@ -106,6 +110,7 @@ int main(int argc, char *argv[]) | |||
106 | main_test_backtrace(); | 110 | main_test_backtrace(); |
107 | main_test_libnuma(); | 111 | main_test_libnuma(); |
108 | main_test_timerfd(); | 112 | main_test_timerfd(); |
113 | main_test_stackprotector_all(); | ||
109 | 114 | ||
110 | return 0; | 115 | return 0; |
111 | } | 116 | } |
diff --git a/tools/perf/config/feature-checks/test-stackprotector.c b/tools/perf/config/feature-checks/test-stackprotector.c deleted file mode 100644 index c9f398d87868..000000000000 --- a/tools/perf/config/feature-checks/test-stackprotector.c +++ /dev/null | |||
@@ -1,6 +0,0 @@ | |||
1 | #include <stdio.h> | ||
2 | |||
3 | int main(void) | ||
4 | { | ||
5 | return puts("hi"); | ||
6 | } | ||
diff --git a/tools/perf/config/feature-checks/test-volatile-register-var.c b/tools/perf/config/feature-checks/test-volatile-register-var.c deleted file mode 100644 index c9f398d87868..000000000000 --- a/tools/perf/config/feature-checks/test-volatile-register-var.c +++ /dev/null | |||
@@ -1,6 +0,0 @@ | |||
1 | #include <stdio.h> | ||
2 | |||
3 | int main(void) | ||
4 | { | ||
5 | return puts("hi"); | ||
6 | } | ||
diff --git a/tools/perf/config/utilities.mak b/tools/perf/config/utilities.mak index f168debc5be2..4d985e0f03f5 100644 --- a/tools/perf/config/utilities.mak +++ b/tools/perf/config/utilities.mak | |||
@@ -178,10 +178,3 @@ endef | |||
178 | _ge_attempt = $(if $(get-executable),$(get-executable),$(_gea_warn)$(call _gea_err,$(2))) | 178 | _ge_attempt = $(if $(get-executable),$(get-executable),$(_gea_warn)$(call _gea_err,$(2))) |
179 | _gea_warn = $(warning The path '$(1)' is not executable.) | 179 | _gea_warn = $(warning The path '$(1)' is not executable.) |
180 | _gea_err = $(if $(1),$(error Please set '$(1)' appropriately)) | 180 | _gea_err = $(if $(1),$(error Please set '$(1)' appropriately)) |
181 | |||
182 | ifneq ($(findstring $(MAKEFLAGS),s),s) | ||
183 | ifneq ($(V),1) | ||
184 | QUIET_CLEAN = @printf ' CLEAN %s\n' $1; | ||
185 | QUIET_INSTALL = @printf ' INSTALL %s\n' $1; | ||
186 | endif | ||
187 | endif | ||
diff --git a/tools/perf/design.txt b/tools/perf/design.txt index 67e5d0cace85..63a0e6f04a01 100644 --- a/tools/perf/design.txt +++ b/tools/perf/design.txt | |||
@@ -454,7 +454,6 @@ So to start with, in order to add HAVE_PERF_EVENTS to your Kconfig, you | |||
454 | will need at least this: | 454 | will need at least this: |
455 | - asm/perf_event.h - a basic stub will suffice at first | 455 | - asm/perf_event.h - a basic stub will suffice at first |
456 | - support for atomic64 types (and associated helper functions) | 456 | - support for atomic64 types (and associated helper functions) |
457 | - set_perf_event_pending() implemented | ||
458 | 457 | ||
459 | If your architecture does have hardware capabilities, you can override the | 458 | If your architecture does have hardware capabilities, you can override the |
460 | weak stub hw_perf_event_init() to register hardware counters. | 459 | weak stub hw_perf_event_init() to register hardware counters. |
diff --git a/tools/perf/bash_completion b/tools/perf/perf-completion.sh index 62e157db2e2b..496e2abb5482 100644 --- a/tools/perf/bash_completion +++ b/tools/perf/perf-completion.sh | |||
@@ -1,4 +1,4 @@ | |||
1 | # perf completion | 1 | # perf bash and zsh completion |
2 | 2 | ||
3 | # Taken from git.git's completion script. | 3 | # Taken from git.git's completion script. |
4 | __my_reassemble_comp_words_by_ref() | 4 | __my_reassemble_comp_words_by_ref() |
@@ -89,37 +89,117 @@ __ltrim_colon_completions() | |||
89 | fi | 89 | fi |
90 | } | 90 | } |
91 | 91 | ||
92 | type perf &>/dev/null && | 92 | __perfcomp () |
93 | _perf() | ||
94 | { | 93 | { |
95 | local cur words cword prev cmd | 94 | COMPREPLY=( $( compgen -W "$1" -- "$2" ) ) |
95 | } | ||
96 | 96 | ||
97 | COMPREPLY=() | 97 | __perfcomp_colon () |
98 | _get_comp_words_by_ref -n =: cur words cword prev | 98 | { |
99 | __perfcomp "$1" "$2" | ||
100 | __ltrim_colon_completions $cur | ||
101 | } | ||
102 | |||
103 | __perf_main () | ||
104 | { | ||
105 | local cmd | ||
99 | 106 | ||
100 | cmd=${words[0]} | 107 | cmd=${words[0]} |
108 | COMPREPLY=() | ||
101 | 109 | ||
102 | # List perf subcommands or long options | 110 | # List perf subcommands or long options |
103 | if [ $cword -eq 1 ]; then | 111 | if [ $cword -eq 1 ]; then |
104 | if [[ $cur == --* ]]; then | 112 | if [[ $cur == --* ]]; then |
105 | COMPREPLY=( $( compgen -W '--help --version \ | 113 | __perfcomp '--help --version \ |
106 | --exec-path --html-path --paginate --no-pager \ | 114 | --exec-path --html-path --paginate --no-pager \ |
107 | --perf-dir --work-tree --debugfs-dir' -- "$cur" ) ) | 115 | --perf-dir --work-tree --debugfs-dir' -- "$cur" |
108 | else | 116 | else |
109 | cmds=$($cmd --list-cmds) | 117 | cmds=$($cmd --list-cmds) |
110 | COMPREPLY=( $( compgen -W '$cmds' -- "$cur" ) ) | 118 | __perfcomp "$cmds" "$cur" |
111 | fi | 119 | fi |
112 | # List possible events for -e option | 120 | # List possible events for -e option |
113 | elif [[ $prev == "-e" && "${words[1]}" == @(record|stat|top) ]]; then | 121 | elif [[ $prev == "-e" && "${words[1]}" == @(record|stat|top) ]]; then |
114 | evts=$($cmd list --raw-dump) | 122 | evts=$($cmd list --raw-dump) |
115 | COMPREPLY=( $( compgen -W '$evts' -- "$cur" ) ) | 123 | __perfcomp_colon "$evts" "$cur" |
116 | __ltrim_colon_completions $cur | 124 | # List subcommands for 'perf kvm' |
125 | elif [[ $prev == "kvm" ]]; then | ||
126 | subcmds="top record report diff buildid-list stat" | ||
127 | __perfcomp_colon "$subcmds" "$cur" | ||
117 | # List long option names | 128 | # List long option names |
118 | elif [[ $cur == --* ]]; then | 129 | elif [[ $cur == --* ]]; then |
119 | subcmd=${words[1]} | 130 | subcmd=${words[1]} |
120 | opts=$($cmd $subcmd --list-opts) | 131 | opts=$($cmd $subcmd --list-opts) |
121 | COMPREPLY=( $( compgen -W '$opts' -- "$cur" ) ) | 132 | __perfcomp "$opts" "$cur" |
122 | fi | 133 | fi |
134 | } | ||
135 | |||
136 | if [[ -n ${ZSH_VERSION-} ]]; then | ||
137 | autoload -U +X compinit && compinit | ||
138 | |||
139 | __perfcomp () | ||
140 | { | ||
141 | emulate -L zsh | ||
142 | |||
143 | local c IFS=$' \t\n' | ||
144 | local -a array | ||
145 | |||
146 | for c in ${=1}; do | ||
147 | case $c in | ||
148 | --*=*|*.) ;; | ||
149 | *) c="$c " ;; | ||
150 | esac | ||
151 | array[${#array[@]}+1]="$c" | ||
152 | done | ||
153 | |||
154 | compset -P '*[=:]' | ||
155 | compadd -Q -S '' -a -- array && _ret=0 | ||
156 | } | ||
157 | |||
158 | __perfcomp_colon () | ||
159 | { | ||
160 | emulate -L zsh | ||
161 | |||
162 | local cur_="${2-$cur}" | ||
163 | local c IFS=$' \t\n' | ||
164 | local -a array | ||
165 | |||
166 | if [[ "$cur_" == *:* ]]; then | ||
167 | local colon_word=${cur_%"${cur_##*:}"} | ||
168 | fi | ||
169 | |||
170 | for c in ${=1}; do | ||
171 | case $c in | ||
172 | --*=*|*.) ;; | ||
173 | *) c="$c " ;; | ||
174 | esac | ||
175 | array[$#array+1]=${c#"$colon_word"} | ||
176 | done | ||
177 | |||
178 | compset -P '*[=:]' | ||
179 | compadd -Q -S '' -a -- array && _ret=0 | ||
180 | } | ||
181 | |||
182 | _perf () | ||
183 | { | ||
184 | local _ret=1 cur cword prev | ||
185 | cur=${words[CURRENT]} | ||
186 | prev=${words[CURRENT-1]} | ||
187 | let cword=CURRENT-1 | ||
188 | emulate ksh -c __perf_main | ||
189 | let _ret && _default && _ret=0 | ||
190 | return _ret | ||
191 | } | ||
192 | |||
193 | compdef _perf perf | ||
194 | return | ||
195 | fi | ||
196 | |||
197 | type perf &>/dev/null && | ||
198 | _perf() | ||
199 | { | ||
200 | local cur words cword prev | ||
201 | _get_comp_words_by_ref -n =: cur words cword prev | ||
202 | __perf_main | ||
123 | } && | 203 | } && |
124 | 204 | ||
125 | complete -o bashdefault -o default -o nospace -F _perf perf 2>/dev/null \ | 205 | complete -o bashdefault -o default -o nospace -F _perf perf 2>/dev/null \ |
diff --git a/tools/perf/perf.c b/tools/perf/perf.c index 8b38b4e80ec2..431798a4110d 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 <lk/debugfs.h> | 16 | #include <api/fs/debugfs.h> |
17 | #include <pthread.h> | 17 | #include <pthread.h> |
18 | 18 | ||
19 | const char perf_usage_string[] = | 19 | const char perf_usage_string[] = |
diff --git a/tools/perf/perf.h b/tools/perf/perf.h index b079304bd53d..e84fa26bc1be 100644 --- a/tools/perf/perf.h +++ b/tools/perf/perf.h | |||
@@ -100,8 +100,8 @@ | |||
100 | 100 | ||
101 | #ifdef __aarch64__ | 101 | #ifdef __aarch64__ |
102 | #define mb() asm volatile("dmb ish" ::: "memory") | 102 | #define mb() asm volatile("dmb ish" ::: "memory") |
103 | #define wmb() asm volatile("dmb ishld" ::: "memory") | 103 | #define wmb() asm volatile("dmb ishst" ::: "memory") |
104 | #define rmb() asm volatile("dmb ishst" ::: "memory") | 104 | #define rmb() asm volatile("dmb ishld" ::: "memory") |
105 | #define cpu_relax() asm volatile("yield" ::: "memory") | 105 | #define cpu_relax() asm volatile("yield" ::: "memory") |
106 | #endif | 106 | #endif |
107 | 107 | ||
@@ -132,6 +132,13 @@ | |||
132 | #define CPUINFO_PROC "CPU" | 132 | #define CPUINFO_PROC "CPU" |
133 | #endif | 133 | #endif |
134 | 134 | ||
135 | #ifdef __xtensa__ | ||
136 | #define mb() asm volatile("memw" ::: "memory") | ||
137 | #define wmb() asm volatile("memw" ::: "memory") | ||
138 | #define rmb() asm volatile("" ::: "memory") | ||
139 | #define CPUINFO_PROC "core ID" | ||
140 | #endif | ||
141 | |||
135 | #define barrier() asm volatile ("" ::: "memory") | 142 | #define barrier() asm volatile ("" ::: "memory") |
136 | 143 | ||
137 | #ifndef cpu_relax | 144 | #ifndef cpu_relax |
@@ -247,13 +254,14 @@ enum perf_call_graph_mode { | |||
247 | CALLCHAIN_DWARF | 254 | CALLCHAIN_DWARF |
248 | }; | 255 | }; |
249 | 256 | ||
250 | struct perf_record_opts { | 257 | struct record_opts { |
251 | struct target target; | 258 | struct target target; |
252 | int call_graph; | 259 | int call_graph; |
253 | bool group; | 260 | bool group; |
254 | bool inherit_stat; | 261 | bool inherit_stat; |
255 | bool no_delay; | 262 | bool no_buffering; |
256 | bool no_inherit; | 263 | bool no_inherit; |
264 | bool no_inherit_set; | ||
257 | bool no_samples; | 265 | bool no_samples; |
258 | bool raw_samples; | 266 | bool raw_samples; |
259 | bool sample_address; | 267 | bool sample_address; |
@@ -268,6 +276,7 @@ struct perf_record_opts { | |||
268 | u64 user_interval; | 276 | u64 user_interval; |
269 | u16 stack_dump_size; | 277 | u16 stack_dump_size; |
270 | bool sample_transaction; | 278 | bool sample_transaction; |
279 | unsigned initial_delay; | ||
271 | }; | 280 | }; |
272 | 281 | ||
273 | #endif | 282 | #endif |
diff --git a/tools/perf/tests/attr/test-record-no-inherit b/tools/perf/tests/attr/test-record-no-inherit index 9079a25cd643..44edcb2edcd5 100644 --- a/tools/perf/tests/attr/test-record-no-inherit +++ b/tools/perf/tests/attr/test-record-no-inherit | |||
@@ -3,5 +3,5 @@ command = record | |||
3 | args = -i kill >/dev/null 2>&1 | 3 | args = -i kill >/dev/null 2>&1 |
4 | 4 | ||
5 | [event:base-record] | 5 | [event:base-record] |
6 | sample_type=259 | 6 | sample_type=263 |
7 | inherit=0 | 7 | inherit=0 |
diff --git a/tools/perf/tests/code-reading.c b/tools/perf/tests/code-reading.c index 85d4919dd623..653a8fe2db95 100644 --- a/tools/perf/tests/code-reading.c +++ b/tools/perf/tests/code-reading.c | |||
@@ -391,7 +391,7 @@ static int do_test_code_reading(bool try_kcore) | |||
391 | struct machines machines; | 391 | struct machines machines; |
392 | struct machine *machine; | 392 | struct machine *machine; |
393 | struct thread *thread; | 393 | struct thread *thread; |
394 | struct perf_record_opts opts = { | 394 | struct record_opts opts = { |
395 | .mmap_pages = UINT_MAX, | 395 | .mmap_pages = UINT_MAX, |
396 | .user_freq = UINT_MAX, | 396 | .user_freq = UINT_MAX, |
397 | .user_interval = ULLONG_MAX, | 397 | .user_interval = ULLONG_MAX, |
@@ -540,14 +540,11 @@ static int do_test_code_reading(bool try_kcore) | |||
540 | err = TEST_CODE_READING_OK; | 540 | err = TEST_CODE_READING_OK; |
541 | out_err: | 541 | out_err: |
542 | if (evlist) { | 542 | if (evlist) { |
543 | perf_evlist__munmap(evlist); | ||
544 | perf_evlist__close(evlist); | ||
545 | perf_evlist__delete(evlist); | 543 | perf_evlist__delete(evlist); |
546 | } | 544 | } else { |
547 | if (cpus) | ||
548 | cpu_map__delete(cpus); | 545 | cpu_map__delete(cpus); |
549 | if (threads) | ||
550 | thread_map__delete(threads); | 546 | thread_map__delete(threads); |
547 | } | ||
551 | machines__destroy_kernel_maps(&machines); | 548 | machines__destroy_kernel_maps(&machines); |
552 | machine__delete_threads(machine); | 549 | machine__delete_threads(machine); |
553 | machines__exit(&machines); | 550 | machines__exit(&machines); |
diff --git a/tools/perf/tests/evsel-roundtrip-name.c b/tools/perf/tests/evsel-roundtrip-name.c index 0197bda9c461..465cdbc345cf 100644 --- a/tools/perf/tests/evsel-roundtrip-name.c +++ b/tools/perf/tests/evsel-roundtrip-name.c | |||
@@ -79,7 +79,7 @@ static int __perf_evsel__name_array_test(const char *names[], int nr_names) | |||
79 | } | 79 | } |
80 | 80 | ||
81 | err = 0; | 81 | err = 0; |
82 | list_for_each_entry(evsel, &evlist->entries, node) { | 82 | evlist__for_each(evlist, evsel) { |
83 | if (strcmp(perf_evsel__name(evsel), names[evsel->idx])) { | 83 | if (strcmp(perf_evsel__name(evsel), names[evsel->idx])) { |
84 | --err; | 84 | --err; |
85 | pr_debug("%s != %s\n", perf_evsel__name(evsel), names[evsel->idx]); | 85 | pr_debug("%s != %s\n", perf_evsel__name(evsel), names[evsel->idx]); |
diff --git a/tools/perf/tests/hists_link.c b/tools/perf/tests/hists_link.c index 173bf42cc03e..2b6519e0e36f 100644 --- a/tools/perf/tests/hists_link.c +++ b/tools/perf/tests/hists_link.c | |||
@@ -208,7 +208,7 @@ static int add_hist_entries(struct perf_evlist *evlist, struct machine *machine) | |||
208 | * However the second evsel also has a collapsed entry for | 208 | * However the second evsel also has a collapsed entry for |
209 | * "bash [libc] malloc" so total 9 entries will be in the tree. | 209 | * "bash [libc] malloc" so total 9 entries will be in the tree. |
210 | */ | 210 | */ |
211 | list_for_each_entry(evsel, &evlist->entries, node) { | 211 | evlist__for_each(evlist, evsel) { |
212 | for (k = 0; k < ARRAY_SIZE(fake_common_samples); k++) { | 212 | for (k = 0; k < ARRAY_SIZE(fake_common_samples); k++) { |
213 | const union perf_event event = { | 213 | const union perf_event event = { |
214 | .header = { | 214 | .header = { |
@@ -466,7 +466,7 @@ int test__hists_link(void) | |||
466 | if (err < 0) | 466 | if (err < 0) |
467 | goto out; | 467 | goto out; |
468 | 468 | ||
469 | list_for_each_entry(evsel, &evlist->entries, node) { | 469 | evlist__for_each(evlist, evsel) { |
470 | hists__collapse_resort(&evsel->hists, NULL); | 470 | hists__collapse_resort(&evsel->hists, NULL); |
471 | 471 | ||
472 | if (verbose > 2) | 472 | if (verbose > 2) |
diff --git a/tools/perf/tests/keep-tracking.c b/tools/perf/tests/keep-tracking.c index 376c35608534..497957f269d8 100644 --- a/tools/perf/tests/keep-tracking.c +++ b/tools/perf/tests/keep-tracking.c | |||
@@ -51,7 +51,7 @@ static int find_comm(struct perf_evlist *evlist, const char *comm) | |||
51 | */ | 51 | */ |
52 | int test__keep_tracking(void) | 52 | int test__keep_tracking(void) |
53 | { | 53 | { |
54 | struct perf_record_opts opts = { | 54 | struct record_opts opts = { |
55 | .mmap_pages = UINT_MAX, | 55 | .mmap_pages = UINT_MAX, |
56 | .user_freq = UINT_MAX, | 56 | .user_freq = UINT_MAX, |
57 | .user_interval = ULLONG_MAX, | 57 | .user_interval = ULLONG_MAX, |
@@ -142,14 +142,11 @@ int test__keep_tracking(void) | |||
142 | out_err: | 142 | out_err: |
143 | if (evlist) { | 143 | if (evlist) { |
144 | perf_evlist__disable(evlist); | 144 | perf_evlist__disable(evlist); |
145 | perf_evlist__munmap(evlist); | ||
146 | perf_evlist__close(evlist); | ||
147 | perf_evlist__delete(evlist); | 145 | perf_evlist__delete(evlist); |
148 | } | 146 | } else { |
149 | if (cpus) | ||
150 | cpu_map__delete(cpus); | 147 | cpu_map__delete(cpus); |
151 | if (threads) | ||
152 | thread_map__delete(threads); | 148 | thread_map__delete(threads); |
149 | } | ||
153 | 150 | ||
154 | return err; | 151 | return err; |
155 | } | 152 | } |
diff --git a/tools/perf/tests/make b/tools/perf/tests/make index 2ca0abf1b2b6..00544b8b644b 100644 --- a/tools/perf/tests/make +++ b/tools/perf/tests/make | |||
@@ -1,6 +1,16 @@ | |||
1 | PERF := . | 1 | PERF := . |
2 | MK := Makefile | 2 | MK := Makefile |
3 | 3 | ||
4 | include config/Makefile.arch | ||
5 | |||
6 | # FIXME looks like x86 is the only arch running tests ;-) | ||
7 | # we need some IS_(32/64) flag to make this generic | ||
8 | ifeq ($(IS_X86_64),1) | ||
9 | lib = lib64 | ||
10 | else | ||
11 | lib = lib | ||
12 | endif | ||
13 | |||
4 | has = $(shell which $1 2>/dev/null) | 14 | has = $(shell which $1 2>/dev/null) |
5 | 15 | ||
6 | # standard single make variable specified | 16 | # standard single make variable specified |
@@ -106,10 +116,36 @@ test_make_python_perf_so := test -f $(PERF)/python/perf.so | |||
106 | test_make_perf_o := test -f $(PERF)/perf.o | 116 | test_make_perf_o := test -f $(PERF)/perf.o |
107 | test_make_util_map_o := test -f $(PERF)/util/map.o | 117 | test_make_util_map_o := test -f $(PERF)/util/map.o |
108 | 118 | ||
109 | test_make_install := test -x $$TMP_DEST/bin/perf | 119 | define test_dest_files |
110 | test_make_install_O := $(test_make_install) | 120 | for file in $(1); do \ |
111 | test_make_install_bin := $(test_make_install) | 121 | if [ ! -x $$TMP_DEST/$$file ]; then \ |
112 | test_make_install_bin_O := $(test_make_install) | 122 | echo " failed to find: $$file"; \ |
123 | fi \ | ||
124 | done | ||
125 | endef | ||
126 | |||
127 | installed_files_bin := bin/perf | ||
128 | installed_files_bin += etc/bash_completion.d/perf | ||
129 | installed_files_bin += libexec/perf-core/perf-archive | ||
130 | |||
131 | installed_files_plugins := $(lib)/traceevent/plugins/plugin_cfg80211.so | ||
132 | installed_files_plugins += $(lib)/traceevent/plugins/plugin_scsi.so | ||
133 | installed_files_plugins += $(lib)/traceevent/plugins/plugin_xen.so | ||
134 | installed_files_plugins += $(lib)/traceevent/plugins/plugin_function.so | ||
135 | installed_files_plugins += $(lib)/traceevent/plugins/plugin_sched_switch.so | ||
136 | installed_files_plugins += $(lib)/traceevent/plugins/plugin_mac80211.so | ||
137 | installed_files_plugins += $(lib)/traceevent/plugins/plugin_kvm.so | ||
138 | installed_files_plugins += $(lib)/traceevent/plugins/plugin_kmem.so | ||
139 | installed_files_plugins += $(lib)/traceevent/plugins/plugin_hrtimer.so | ||
140 | installed_files_plugins += $(lib)/traceevent/plugins/plugin_jbd2.so | ||
141 | |||
142 | installed_files_all := $(installed_files_bin) | ||
143 | installed_files_all += $(installed_files_plugins) | ||
144 | |||
145 | test_make_install := $(call test_dest_files,$(installed_files_all)) | ||
146 | test_make_install_O := $(call test_dest_files,$(installed_files_all)) | ||
147 | test_make_install_bin := $(call test_dest_files,$(installed_files_bin)) | ||
148 | test_make_install_bin_O := $(call test_dest_files,$(installed_files_bin)) | ||
113 | 149 | ||
114 | # FIXME nothing gets installed | 150 | # FIXME nothing gets installed |
115 | test_make_install_man := test -f $$TMP_DEST/share/man/man1/perf.1 | 151 | test_make_install_man := test -f $$TMP_DEST/share/man/man1/perf.1 |
@@ -162,7 +198,7 @@ $(run): | |||
162 | cmd="cd $(PERF) && make -f $(MK) DESTDIR=$$TMP_DEST $($@)"; \ | 198 | cmd="cd $(PERF) && make -f $(MK) DESTDIR=$$TMP_DEST $($@)"; \ |
163 | echo "- $@: $$cmd" && echo $$cmd > $@ && \ | 199 | echo "- $@: $$cmd" && echo $$cmd > $@ && \ |
164 | ( eval $$cmd ) >> $@ 2>&1; \ | 200 | ( eval $$cmd ) >> $@ 2>&1; \ |
165 | echo " test: $(call test,$@)"; \ | 201 | echo " test: $(call test,$@)" >> $@ 2>&1; \ |
166 | $(call test,$@) && \ | 202 | $(call test,$@) && \ |
167 | rm -f $@ \ | 203 | rm -f $@ \ |
168 | rm -rf $$TMP_DEST | 204 | rm -rf $$TMP_DEST |
@@ -174,16 +210,22 @@ $(run_O): | |||
174 | cmd="cd $(PERF) && make -f $(MK) O=$$TMP_O DESTDIR=$$TMP_DEST $($(patsubst %_O,%,$@))"; \ | 210 | cmd="cd $(PERF) && make -f $(MK) O=$$TMP_O DESTDIR=$$TMP_DEST $($(patsubst %_O,%,$@))"; \ |
175 | echo "- $@: $$cmd" && echo $$cmd > $@ && \ | 211 | echo "- $@: $$cmd" && echo $$cmd > $@ && \ |
176 | ( eval $$cmd ) >> $@ 2>&1 && \ | 212 | ( eval $$cmd ) >> $@ 2>&1 && \ |
177 | echo " test: $(call test_O,$@)"; \ | 213 | echo " test: $(call test_O,$@)" >> $@ 2>&1; \ |
178 | $(call test_O,$@) && \ | 214 | $(call test_O,$@) && \ |
179 | rm -f $@ && \ | 215 | rm -f $@ && \ |
180 | rm -rf $$TMP_O \ | 216 | rm -rf $$TMP_O \ |
181 | rm -rf $$TMP_DEST | 217 | rm -rf $$TMP_DEST |
182 | 218 | ||
183 | all: $(run) $(run_O) | 219 | tarpkg: |
220 | @cmd="$(PERF)/tests/perf-targz-src-pkg $(PERF)"; \ | ||
221 | echo "- $@: $$cmd" && echo $$cmd > $@ && \ | ||
222 | ( eval $$cmd ) >> $@ 2>&1 | ||
223 | |||
224 | |||
225 | all: $(run) $(run_O) tarpkg | ||
184 | @echo OK | 226 | @echo OK |
185 | 227 | ||
186 | out: $(run_O) | 228 | out: $(run_O) |
187 | @echo OK | 229 | @echo OK |
188 | 230 | ||
189 | .PHONY: all $(run) $(run_O) clean | 231 | .PHONY: all $(run) $(run_O) tarpkg clean |
diff --git a/tools/perf/tests/mmap-basic.c b/tools/perf/tests/mmap-basic.c index d64ab79c6d35..142263492f6f 100644 --- a/tools/perf/tests/mmap-basic.c +++ b/tools/perf/tests/mmap-basic.c | |||
@@ -68,7 +68,7 @@ int test__basic_mmap(void) | |||
68 | evsels[i] = perf_evsel__newtp("syscalls", name); | 68 | evsels[i] = perf_evsel__newtp("syscalls", name); |
69 | if (evsels[i] == NULL) { | 69 | if (evsels[i] == NULL) { |
70 | pr_debug("perf_evsel__new\n"); | 70 | pr_debug("perf_evsel__new\n"); |
71 | goto out_free_evlist; | 71 | goto out_delete_evlist; |
72 | } | 72 | } |
73 | 73 | ||
74 | evsels[i]->attr.wakeup_events = 1; | 74 | evsels[i]->attr.wakeup_events = 1; |
@@ -80,7 +80,7 @@ int test__basic_mmap(void) | |||
80 | pr_debug("failed to open counter: %s, " | 80 | pr_debug("failed to open counter: %s, " |
81 | "tweak /proc/sys/kernel/perf_event_paranoid?\n", | 81 | "tweak /proc/sys/kernel/perf_event_paranoid?\n", |
82 | strerror(errno)); | 82 | strerror(errno)); |
83 | goto out_close_fd; | 83 | goto out_delete_evlist; |
84 | } | 84 | } |
85 | 85 | ||
86 | nr_events[i] = 0; | 86 | nr_events[i] = 0; |
@@ -90,7 +90,7 @@ int test__basic_mmap(void) | |||
90 | if (perf_evlist__mmap(evlist, 128, true) < 0) { | 90 | if (perf_evlist__mmap(evlist, 128, true) < 0) { |
91 | pr_debug("failed to mmap events: %d (%s)\n", errno, | 91 | pr_debug("failed to mmap events: %d (%s)\n", errno, |
92 | strerror(errno)); | 92 | strerror(errno)); |
93 | goto out_close_fd; | 93 | goto out_delete_evlist; |
94 | } | 94 | } |
95 | 95 | ||
96 | for (i = 0; i < nsyscalls; ++i) | 96 | for (i = 0; i < nsyscalls; ++i) |
@@ -105,13 +105,13 @@ int test__basic_mmap(void) | |||
105 | if (event->header.type != PERF_RECORD_SAMPLE) { | 105 | if (event->header.type != PERF_RECORD_SAMPLE) { |
106 | pr_debug("unexpected %s event\n", | 106 | pr_debug("unexpected %s event\n", |
107 | perf_event__name(event->header.type)); | 107 | perf_event__name(event->header.type)); |
108 | goto out_munmap; | 108 | goto out_delete_evlist; |
109 | } | 109 | } |
110 | 110 | ||
111 | err = perf_evlist__parse_sample(evlist, event, &sample); | 111 | err = perf_evlist__parse_sample(evlist, event, &sample); |
112 | if (err) { | 112 | if (err) { |
113 | pr_err("Can't parse sample, err = %d\n", err); | 113 | pr_err("Can't parse sample, err = %d\n", err); |
114 | goto out_munmap; | 114 | goto out_delete_evlist; |
115 | } | 115 | } |
116 | 116 | ||
117 | err = -1; | 117 | err = -1; |
@@ -119,30 +119,27 @@ int test__basic_mmap(void) | |||
119 | if (evsel == NULL) { | 119 | if (evsel == NULL) { |
120 | pr_debug("event with id %" PRIu64 | 120 | pr_debug("event with id %" PRIu64 |
121 | " doesn't map to an evsel\n", sample.id); | 121 | " doesn't map to an evsel\n", sample.id); |
122 | goto out_munmap; | 122 | goto out_delete_evlist; |
123 | } | 123 | } |
124 | nr_events[evsel->idx]++; | 124 | nr_events[evsel->idx]++; |
125 | perf_evlist__mmap_consume(evlist, 0); | 125 | perf_evlist__mmap_consume(evlist, 0); |
126 | } | 126 | } |
127 | 127 | ||
128 | err = 0; | 128 | err = 0; |
129 | list_for_each_entry(evsel, &evlist->entries, node) { | 129 | evlist__for_each(evlist, evsel) { |
130 | if (nr_events[evsel->idx] != expected_nr_events[evsel->idx]) { | 130 | if (nr_events[evsel->idx] != expected_nr_events[evsel->idx]) { |
131 | pr_debug("expected %d %s events, got %d\n", | 131 | pr_debug("expected %d %s events, got %d\n", |
132 | expected_nr_events[evsel->idx], | 132 | expected_nr_events[evsel->idx], |
133 | perf_evsel__name(evsel), nr_events[evsel->idx]); | 133 | perf_evsel__name(evsel), nr_events[evsel->idx]); |
134 | err = -1; | 134 | err = -1; |
135 | goto out_munmap; | 135 | goto out_delete_evlist; |
136 | } | 136 | } |
137 | } | 137 | } |
138 | 138 | ||
139 | out_munmap: | 139 | out_delete_evlist: |
140 | perf_evlist__munmap(evlist); | ||
141 | out_close_fd: | ||
142 | for (i = 0; i < nsyscalls; ++i) | ||
143 | perf_evsel__close_fd(evsels[i], 1, threads->nr); | ||
144 | out_free_evlist: | ||
145 | perf_evlist__delete(evlist); | 140 | perf_evlist__delete(evlist); |
141 | cpus = NULL; | ||
142 | threads = NULL; | ||
146 | out_free_cpus: | 143 | out_free_cpus: |
147 | cpu_map__delete(cpus); | 144 | cpu_map__delete(cpus); |
148 | out_free_threads: | 145 | out_free_threads: |
diff --git a/tools/perf/tests/open-syscall-tp-fields.c b/tools/perf/tests/open-syscall-tp-fields.c index 41cc0badb74b..c505ef2af245 100644 --- a/tools/perf/tests/open-syscall-tp-fields.c +++ b/tools/perf/tests/open-syscall-tp-fields.c | |||
@@ -6,15 +6,15 @@ | |||
6 | 6 | ||
7 | int test__syscall_open_tp_fields(void) | 7 | int test__syscall_open_tp_fields(void) |
8 | { | 8 | { |
9 | struct perf_record_opts opts = { | 9 | struct record_opts opts = { |
10 | .target = { | 10 | .target = { |
11 | .uid = UINT_MAX, | 11 | .uid = UINT_MAX, |
12 | .uses_mmap = true, | 12 | .uses_mmap = true, |
13 | }, | 13 | }, |
14 | .no_delay = true, | 14 | .no_buffering = true, |
15 | .freq = 1, | 15 | .freq = 1, |
16 | .mmap_pages = 256, | 16 | .mmap_pages = 256, |
17 | .raw_samples = true, | 17 | .raw_samples = true, |
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; |
@@ -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_maps; | 51 | goto out_delete_evlist; |
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_close_evlist; | 57 | goto out_delete_evlist; |
58 | } | 58 | } |
59 | 59 | ||
60 | perf_evlist__enable(evlist); | 60 | perf_evlist__enable(evlist); |
@@ -85,7 +85,7 @@ int test__syscall_open_tp_fields(void) | |||
85 | err = perf_evsel__parse_sample(evsel, event, &sample); | 85 | err = perf_evsel__parse_sample(evsel, event, &sample); |
86 | if (err) { | 86 | if (err) { |
87 | pr_err("Can't parse sample, err = %d\n", err); | 87 | pr_err("Can't parse sample, err = %d\n", err); |
88 | goto out_munmap; | 88 | goto out_delete_evlist; |
89 | } | 89 | } |
90 | 90 | ||
91 | tp_flags = perf_evsel__intval(evsel, &sample, "flags"); | 91 | tp_flags = perf_evsel__intval(evsel, &sample, "flags"); |
@@ -93,7 +93,7 @@ int test__syscall_open_tp_fields(void) | |||
93 | if (flags != tp_flags) { | 93 | if (flags != tp_flags) { |
94 | pr_debug("%s: Expected flags=%#x, got %#x\n", | 94 | pr_debug("%s: Expected flags=%#x, got %#x\n", |
95 | __func__, flags, tp_flags); | 95 | __func__, flags, tp_flags); |
96 | goto out_munmap; | 96 | goto out_delete_evlist; |
97 | } | 97 | } |
98 | 98 | ||
99 | goto out_ok; | 99 | goto out_ok; |
@@ -105,17 +105,11 @@ int test__syscall_open_tp_fields(void) | |||
105 | 105 | ||
106 | if (++nr_polls > 5) { | 106 | if (++nr_polls > 5) { |
107 | pr_debug("%s: no events!\n", __func__); | 107 | pr_debug("%s: no events!\n", __func__); |
108 | goto out_munmap; | 108 | goto out_delete_evlist; |
109 | } | 109 | } |
110 | } | 110 | } |
111 | out_ok: | 111 | out_ok: |
112 | err = 0; | 112 | err = 0; |
113 | out_munmap: | ||
114 | perf_evlist__munmap(evlist); | ||
115 | out_close_evlist: | ||
116 | perf_evlist__close(evlist); | ||
117 | out_delete_maps: | ||
118 | perf_evlist__delete_maps(evlist); | ||
119 | out_delete_evlist: | 113 | out_delete_evlist: |
120 | perf_evlist__delete(evlist); | 114 | perf_evlist__delete(evlist); |
121 | out: | 115 | out: |
diff --git a/tools/perf/tests/parse-events.c b/tools/perf/tests/parse-events.c index 3cbd10496087..4db0ae617d70 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 "fs.h" | 5 | #include "fs.h" |
6 | #include <lk/debugfs.h> | 6 | #include <api/fs/debugfs.h> |
7 | #include "tests.h" | 7 | #include "tests.h" |
8 | #include <linux/hw_breakpoint.h> | 8 | #include <linux/hw_breakpoint.h> |
9 | 9 | ||
@@ -30,7 +30,7 @@ static int test__checkevent_tracepoint_multi(struct perf_evlist *evlist) | |||
30 | TEST_ASSERT_VAL("wrong number of entries", evlist->nr_entries > 1); | 30 | TEST_ASSERT_VAL("wrong number of entries", evlist->nr_entries > 1); |
31 | TEST_ASSERT_VAL("wrong number of groups", 0 == evlist->nr_groups); | 31 | TEST_ASSERT_VAL("wrong number of groups", 0 == evlist->nr_groups); |
32 | 32 | ||
33 | list_for_each_entry(evsel, &evlist->entries, node) { | 33 | evlist__for_each(evlist, evsel) { |
34 | TEST_ASSERT_VAL("wrong type", | 34 | TEST_ASSERT_VAL("wrong type", |
35 | PERF_TYPE_TRACEPOINT == evsel->attr.type); | 35 | PERF_TYPE_TRACEPOINT == evsel->attr.type); |
36 | TEST_ASSERT_VAL("wrong sample_type", | 36 | TEST_ASSERT_VAL("wrong sample_type", |
@@ -201,7 +201,7 @@ test__checkevent_tracepoint_multi_modifier(struct perf_evlist *evlist) | |||
201 | 201 | ||
202 | TEST_ASSERT_VAL("wrong number of entries", evlist->nr_entries > 1); | 202 | TEST_ASSERT_VAL("wrong number of entries", evlist->nr_entries > 1); |
203 | 203 | ||
204 | list_for_each_entry(evsel, &evlist->entries, node) { | 204 | evlist__for_each(evlist, evsel) { |
205 | TEST_ASSERT_VAL("wrong exclude_user", | 205 | TEST_ASSERT_VAL("wrong exclude_user", |
206 | !evsel->attr.exclude_user); | 206 | !evsel->attr.exclude_user); |
207 | TEST_ASSERT_VAL("wrong exclude_kernel", | 207 | TEST_ASSERT_VAL("wrong exclude_kernel", |
@@ -1385,10 +1385,10 @@ static int test_event(struct evlist_test *e) | |||
1385 | if (ret) { | 1385 | if (ret) { |
1386 | pr_debug("failed to parse event '%s', err %d\n", | 1386 | pr_debug("failed to parse event '%s', err %d\n", |
1387 | e->name, ret); | 1387 | e->name, ret); |
1388 | return ret; | 1388 | } else { |
1389 | ret = e->check(evlist); | ||
1389 | } | 1390 | } |
1390 | 1391 | ||
1391 | ret = e->check(evlist); | ||
1392 | perf_evlist__delete(evlist); | 1392 | perf_evlist__delete(evlist); |
1393 | 1393 | ||
1394 | return ret; | 1394 | return ret; |
diff --git a/tools/perf/tests/perf-record.c b/tools/perf/tests/perf-record.c index 93a62b06c3af..aca1a83dd13a 100644 --- a/tools/perf/tests/perf-record.c +++ b/tools/perf/tests/perf-record.c | |||
@@ -34,14 +34,14 @@ realloc: | |||
34 | 34 | ||
35 | int test__PERF_RECORD(void) | 35 | int test__PERF_RECORD(void) |
36 | { | 36 | { |
37 | struct perf_record_opts opts = { | 37 | struct record_opts opts = { |
38 | .target = { | 38 | .target = { |
39 | .uid = UINT_MAX, | 39 | .uid = UINT_MAX, |
40 | .uses_mmap = true, | 40 | .uses_mmap = true, |
41 | }, | 41 | }, |
42 | .no_delay = true, | 42 | .no_buffering = true, |
43 | .freq = 10, | 43 | .freq = 10, |
44 | .mmap_pages = 256, | 44 | .mmap_pages = 256, |
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); |
@@ -83,11 +83,10 @@ int test__PERF_RECORD(void) | |||
83 | * so that we have time to open the evlist (calling sys_perf_event_open | 83 | * so that we have time to open the evlist (calling sys_perf_event_open |
84 | * on all the fds) and then mmap them. | 84 | * on all the fds) and then mmap them. |
85 | */ | 85 | */ |
86 | err = perf_evlist__prepare_workload(evlist, &opts.target, argv, | 86 | err = perf_evlist__prepare_workload(evlist, &opts.target, argv, false, NULL); |
87 | false, false); | ||
88 | if (err < 0) { | 87 | if (err < 0) { |
89 | pr_debug("Couldn't run the workload!\n"); | 88 | pr_debug("Couldn't run the workload!\n"); |
90 | goto out_delete_maps; | 89 | goto out_delete_evlist; |
91 | } | 90 | } |
92 | 91 | ||
93 | /* | 92 | /* |
@@ -102,7 +101,7 @@ int test__PERF_RECORD(void) | |||
102 | err = sched__get_first_possible_cpu(evlist->workload.pid, &cpu_mask); | 101 | err = sched__get_first_possible_cpu(evlist->workload.pid, &cpu_mask); |
103 | if (err < 0) { | 102 | if (err < 0) { |
104 | pr_debug("sched__get_first_possible_cpu: %s\n", strerror(errno)); | 103 | pr_debug("sched__get_first_possible_cpu: %s\n", strerror(errno)); |
105 | goto out_delete_maps; | 104 | goto out_delete_evlist; |
106 | } | 105 | } |
107 | 106 | ||
108 | cpu = err; | 107 | cpu = err; |
@@ -112,7 +111,7 @@ int test__PERF_RECORD(void) | |||
112 | */ | 111 | */ |
113 | if (sched_setaffinity(evlist->workload.pid, cpu_mask_size, &cpu_mask) < 0) { | 112 | if (sched_setaffinity(evlist->workload.pid, cpu_mask_size, &cpu_mask) < 0) { |
114 | pr_debug("sched_setaffinity: %s\n", strerror(errno)); | 113 | pr_debug("sched_setaffinity: %s\n", strerror(errno)); |
115 | goto out_delete_maps; | 114 | goto out_delete_evlist; |
116 | } | 115 | } |
117 | 116 | ||
118 | /* | 117 | /* |
@@ -122,7 +121,7 @@ int test__PERF_RECORD(void) | |||
122 | err = perf_evlist__open(evlist); | 121 | err = perf_evlist__open(evlist); |
123 | if (err < 0) { | 122 | if (err < 0) { |
124 | pr_debug("perf_evlist__open: %s\n", strerror(errno)); | 123 | pr_debug("perf_evlist__open: %s\n", strerror(errno)); |
125 | goto out_delete_maps; | 124 | goto out_delete_evlist; |
126 | } | 125 | } |
127 | 126 | ||
128 | /* | 127 | /* |
@@ -133,7 +132,7 @@ int test__PERF_RECORD(void) | |||
133 | err = perf_evlist__mmap(evlist, opts.mmap_pages, false); | 132 | err = perf_evlist__mmap(evlist, opts.mmap_pages, false); |
134 | if (err < 0) { | 133 | if (err < 0) { |
135 | pr_debug("perf_evlist__mmap: %s\n", strerror(errno)); | 134 | pr_debug("perf_evlist__mmap: %s\n", strerror(errno)); |
136 | goto out_close_evlist; | 135 | goto out_delete_evlist; |
137 | } | 136 | } |
138 | 137 | ||
139 | /* | 138 | /* |
@@ -166,7 +165,7 @@ int test__PERF_RECORD(void) | |||
166 | if (verbose) | 165 | if (verbose) |
167 | perf_event__fprintf(event, stderr); | 166 | perf_event__fprintf(event, stderr); |
168 | pr_debug("Couldn't parse sample\n"); | 167 | pr_debug("Couldn't parse sample\n"); |
169 | goto out_err; | 168 | goto out_delete_evlist; |
170 | } | 169 | } |
171 | 170 | ||
172 | if (verbose) { | 171 | if (verbose) { |
@@ -303,12 +302,6 @@ found_exit: | |||
303 | pr_debug("PERF_RECORD_MMAP for %s missing!\n", "[vdso]"); | 302 | pr_debug("PERF_RECORD_MMAP for %s missing!\n", "[vdso]"); |
304 | ++errs; | 303 | ++errs; |
305 | } | 304 | } |
306 | out_err: | ||
307 | perf_evlist__munmap(evlist); | ||
308 | out_close_evlist: | ||
309 | perf_evlist__close(evlist); | ||
310 | out_delete_maps: | ||
311 | perf_evlist__delete_maps(evlist); | ||
312 | out_delete_evlist: | 305 | out_delete_evlist: |
313 | perf_evlist__delete(evlist); | 306 | perf_evlist__delete(evlist); |
314 | out: | 307 | out: |
diff --git a/tools/perf/tests/perf-targz-src-pkg b/tools/perf/tests/perf-targz-src-pkg new file mode 100755 index 000000000000..238aa3927c71 --- /dev/null +++ b/tools/perf/tests/perf-targz-src-pkg | |||
@@ -0,0 +1,21 @@ | |||
1 | #!/bin/sh | ||
2 | # Test one of the main kernel Makefile targets to generate a perf sources tarball | ||
3 | # suitable for build outside the full kernel sources. | ||
4 | # | ||
5 | # This is to test that the tools/perf/MANIFEST file lists all the files needed to | ||
6 | # be in such tarball, which sometimes gets broken when we move files around, | ||
7 | # like when we made some files that were in tools/perf/ available to other tools/ | ||
8 | # codebases by moving it to tools/include/, etc. | ||
9 | |||
10 | PERF=$1 | ||
11 | cd ${PERF}/../.. | ||
12 | make perf-targz-src-pkg > /dev/null | ||
13 | TARBALL=$(ls -rt perf-*.tar.gz) | ||
14 | TMP_DEST=$(mktemp -d) | ||
15 | tar xf ${TARBALL} -C $TMP_DEST | ||
16 | rm -f ${TARBALL} | ||
17 | cd - > /dev/null | ||
18 | make -C $TMP_DEST/perf*/tools/perf > /dev/null 2>&1 | ||
19 | RC=$? | ||
20 | rm -rf ${TMP_DEST} | ||
21 | exit $RC | ||
diff --git a/tools/perf/tests/perf-time-to-tsc.c b/tools/perf/tests/perf-time-to-tsc.c index 4ca1b938f6a6..47146d388dbf 100644 --- a/tools/perf/tests/perf-time-to-tsc.c +++ b/tools/perf/tests/perf-time-to-tsc.c | |||
@@ -46,7 +46,7 @@ static u64 rdtsc(void) | |||
46 | */ | 46 | */ |
47 | int test__perf_time_to_tsc(void) | 47 | int test__perf_time_to_tsc(void) |
48 | { | 48 | { |
49 | struct perf_record_opts opts = { | 49 | struct record_opts opts = { |
50 | .mmap_pages = UINT_MAX, | 50 | .mmap_pages = UINT_MAX, |
51 | .user_freq = UINT_MAX, | 51 | .user_freq = UINT_MAX, |
52 | .user_interval = ULLONG_MAX, | 52 | .user_interval = ULLONG_MAX, |
@@ -166,14 +166,8 @@ next_event: | |||
166 | out_err: | 166 | out_err: |
167 | if (evlist) { | 167 | if (evlist) { |
168 | perf_evlist__disable(evlist); | 168 | perf_evlist__disable(evlist); |
169 | perf_evlist__munmap(evlist); | ||
170 | perf_evlist__close(evlist); | ||
171 | perf_evlist__delete(evlist); | 169 | perf_evlist__delete(evlist); |
172 | } | 170 | } |
173 | if (cpus) | ||
174 | cpu_map__delete(cpus); | ||
175 | if (threads) | ||
176 | thread_map__delete(threads); | ||
177 | 171 | ||
178 | return err; | 172 | return err; |
179 | } | 173 | } |
diff --git a/tools/perf/tests/sw-clock.c b/tools/perf/tests/sw-clock.c index 6664a7cd828c..983d6b8562a8 100644 --- a/tools/perf/tests/sw-clock.c +++ b/tools/perf/tests/sw-clock.c | |||
@@ -45,7 +45,7 @@ static int __test__sw_clock_freq(enum perf_sw_ids clock_id) | |||
45 | evsel = perf_evsel__new(&attr); | 45 | evsel = perf_evsel__new(&attr); |
46 | if (evsel == NULL) { | 46 | if (evsel == NULL) { |
47 | pr_debug("perf_evsel__new\n"); | 47 | pr_debug("perf_evsel__new\n"); |
48 | goto out_free_evlist; | 48 | goto out_delete_evlist; |
49 | } | 49 | } |
50 | perf_evlist__add(evlist, evsel); | 50 | perf_evlist__add(evlist, evsel); |
51 | 51 | ||
@@ -54,7 +54,7 @@ static int __test__sw_clock_freq(enum perf_sw_ids clock_id) | |||
54 | if (!evlist->cpus || !evlist->threads) { | 54 | if (!evlist->cpus || !evlist->threads) { |
55 | err = -ENOMEM; | 55 | err = -ENOMEM; |
56 | pr_debug("Not enough memory to create thread/cpu maps\n"); | 56 | pr_debug("Not enough memory to create thread/cpu maps\n"); |
57 | goto out_delete_maps; | 57 | goto out_delete_evlist; |
58 | } | 58 | } |
59 | 59 | ||
60 | if (perf_evlist__open(evlist)) { | 60 | if (perf_evlist__open(evlist)) { |
@@ -63,14 +63,14 @@ static int __test__sw_clock_freq(enum perf_sw_ids clock_id) | |||
63 | err = -errno; | 63 | err = -errno; |
64 | pr_debug("Couldn't open evlist: %s\nHint: check %s, using %" PRIu64 " in this test.\n", | 64 | pr_debug("Couldn't open evlist: %s\nHint: check %s, using %" PRIu64 " in this test.\n", |
65 | strerror(errno), knob, (u64)attr.sample_freq); | 65 | strerror(errno), knob, (u64)attr.sample_freq); |
66 | goto out_delete_maps; | 66 | goto out_delete_evlist; |
67 | } | 67 | } |
68 | 68 | ||
69 | err = perf_evlist__mmap(evlist, 128, true); | 69 | err = perf_evlist__mmap(evlist, 128, true); |
70 | if (err < 0) { | 70 | if (err < 0) { |
71 | pr_debug("failed to mmap event: %d (%s)\n", errno, | 71 | pr_debug("failed to mmap event: %d (%s)\n", errno, |
72 | strerror(errno)); | 72 | strerror(errno)); |
73 | goto out_close_evlist; | 73 | goto out_delete_evlist; |
74 | } | 74 | } |
75 | 75 | ||
76 | perf_evlist__enable(evlist); | 76 | perf_evlist__enable(evlist); |
@@ -90,7 +90,7 @@ static int __test__sw_clock_freq(enum perf_sw_ids clock_id) | |||
90 | err = perf_evlist__parse_sample(evlist, event, &sample); | 90 | err = perf_evlist__parse_sample(evlist, event, &sample); |
91 | if (err < 0) { | 91 | if (err < 0) { |
92 | pr_debug("Error during parse sample\n"); | 92 | pr_debug("Error during parse sample\n"); |
93 | goto out_unmap_evlist; | 93 | goto out_delete_evlist; |
94 | } | 94 | } |
95 | 95 | ||
96 | total_periods += sample.period; | 96 | total_periods += sample.period; |
@@ -105,13 +105,7 @@ next_event: | |||
105 | err = -1; | 105 | err = -1; |
106 | } | 106 | } |
107 | 107 | ||
108 | out_unmap_evlist: | 108 | out_delete_evlist: |
109 | perf_evlist__munmap(evlist); | ||
110 | out_close_evlist: | ||
111 | perf_evlist__close(evlist); | ||
112 | out_delete_maps: | ||
113 | perf_evlist__delete_maps(evlist); | ||
114 | out_free_evlist: | ||
115 | perf_evlist__delete(evlist); | 109 | perf_evlist__delete(evlist); |
116 | return err; | 110 | return err; |
117 | } | 111 | } |
diff --git a/tools/perf/tests/task-exit.c b/tools/perf/tests/task-exit.c index d09ab579119e..5ff3db318f12 100644 --- a/tools/perf/tests/task-exit.c +++ b/tools/perf/tests/task-exit.c | |||
@@ -9,12 +9,21 @@ | |||
9 | static int exited; | 9 | static int exited; |
10 | static int nr_exit; | 10 | static int nr_exit; |
11 | 11 | ||
12 | static void sig_handler(int sig) | 12 | static void sig_handler(int sig __maybe_unused) |
13 | { | 13 | { |
14 | exited = 1; | 14 | exited = 1; |
15 | } | ||
15 | 16 | ||
16 | if (sig == SIGUSR1) | 17 | /* |
17 | nr_exit = -1; | 18 | * perf_evlist__prepare_workload will send a SIGUSR1 if the fork fails, since |
19 | * we asked by setting its exec_error to this handler. | ||
20 | */ | ||
21 | static void workload_exec_failed_signal(int signo __maybe_unused, | ||
22 | siginfo_t *info __maybe_unused, | ||
23 | void *ucontext __maybe_unused) | ||
24 | { | ||
25 | exited = 1; | ||
26 | nr_exit = -1; | ||
18 | } | 27 | } |
19 | 28 | ||
20 | /* | 29 | /* |
@@ -35,7 +44,6 @@ int test__task_exit(void) | |||
35 | const char *argv[] = { "true", NULL }; | 44 | const char *argv[] = { "true", NULL }; |
36 | 45 | ||
37 | signal(SIGCHLD, sig_handler); | 46 | signal(SIGCHLD, sig_handler); |
38 | signal(SIGUSR1, sig_handler); | ||
39 | 47 | ||
40 | evlist = perf_evlist__new_default(); | 48 | evlist = perf_evlist__new_default(); |
41 | if (evlist == NULL) { | 49 | if (evlist == NULL) { |
@@ -54,13 +62,14 @@ int test__task_exit(void) | |||
54 | if (!evlist->cpus || !evlist->threads) { | 62 | if (!evlist->cpus || !evlist->threads) { |
55 | err = -ENOMEM; | 63 | err = -ENOMEM; |
56 | pr_debug("Not enough memory to create thread/cpu maps\n"); | 64 | pr_debug("Not enough memory to create thread/cpu maps\n"); |
57 | goto out_delete_maps; | 65 | goto out_delete_evlist; |
58 | } | 66 | } |
59 | 67 | ||
60 | err = perf_evlist__prepare_workload(evlist, &target, argv, false, true); | 68 | err = perf_evlist__prepare_workload(evlist, &target, argv, false, |
69 | workload_exec_failed_signal); | ||
61 | if (err < 0) { | 70 | if (err < 0) { |
62 | pr_debug("Couldn't run the workload!\n"); | 71 | pr_debug("Couldn't run the workload!\n"); |
63 | goto out_delete_maps; | 72 | goto out_delete_evlist; |
64 | } | 73 | } |
65 | 74 | ||
66 | evsel = perf_evlist__first(evlist); | 75 | evsel = perf_evlist__first(evlist); |
@@ -74,13 +83,13 @@ int test__task_exit(void) | |||
74 | err = perf_evlist__open(evlist); | 83 | err = perf_evlist__open(evlist); |
75 | if (err < 0) { | 84 | if (err < 0) { |
76 | pr_debug("Couldn't open the evlist: %s\n", strerror(-err)); | 85 | pr_debug("Couldn't open the evlist: %s\n", strerror(-err)); |
77 | goto out_delete_maps; | 86 | goto out_delete_evlist; |
78 | } | 87 | } |
79 | 88 | ||
80 | if (perf_evlist__mmap(evlist, 128, true) < 0) { | 89 | if (perf_evlist__mmap(evlist, 128, true) < 0) { |
81 | pr_debug("failed to mmap events: %d (%s)\n", errno, | 90 | pr_debug("failed to mmap events: %d (%s)\n", errno, |
82 | strerror(errno)); | 91 | strerror(errno)); |
83 | goto out_close_evlist; | 92 | goto out_delete_evlist; |
84 | } | 93 | } |
85 | 94 | ||
86 | perf_evlist__start_workload(evlist); | 95 | perf_evlist__start_workload(evlist); |
@@ -103,11 +112,7 @@ retry: | |||
103 | err = -1; | 112 | err = -1; |
104 | } | 113 | } |
105 | 114 | ||
106 | perf_evlist__munmap(evlist); | 115 | out_delete_evlist: |
107 | out_close_evlist: | ||
108 | perf_evlist__close(evlist); | ||
109 | out_delete_maps: | ||
110 | perf_evlist__delete_maps(evlist); | ||
111 | perf_evlist__delete(evlist); | 116 | perf_evlist__delete(evlist); |
112 | return err; | 117 | return err; |
113 | } | 118 | } |
diff --git a/tools/perf/tests/vmlinux-kallsyms.c b/tools/perf/tests/vmlinux-kallsyms.c index 2bd13edcbc17..3d9088003a5b 100644 --- a/tools/perf/tests/vmlinux-kallsyms.c +++ b/tools/perf/tests/vmlinux-kallsyms.c | |||
@@ -26,7 +26,6 @@ int test__vmlinux_matches_kallsyms(void) | |||
26 | struct map *kallsyms_map, *vmlinux_map; | 26 | struct map *kallsyms_map, *vmlinux_map; |
27 | struct machine kallsyms, vmlinux; | 27 | struct machine kallsyms, vmlinux; |
28 | enum map_type type = MAP__FUNCTION; | 28 | enum map_type type = MAP__FUNCTION; |
29 | struct ref_reloc_sym ref_reloc_sym = { .name = "_stext", }; | ||
30 | u64 mem_start, mem_end; | 29 | u64 mem_start, mem_end; |
31 | 30 | ||
32 | /* | 31 | /* |
@@ -70,14 +69,6 @@ int test__vmlinux_matches_kallsyms(void) | |||
70 | */ | 69 | */ |
71 | kallsyms_map = machine__kernel_map(&kallsyms, type); | 70 | kallsyms_map = machine__kernel_map(&kallsyms, type); |
72 | 71 | ||
73 | sym = map__find_symbol_by_name(kallsyms_map, ref_reloc_sym.name, NULL); | ||
74 | if (sym == NULL) { | ||
75 | pr_debug("dso__find_symbol_by_name "); | ||
76 | goto out; | ||
77 | } | ||
78 | |||
79 | ref_reloc_sym.addr = UM(sym->start); | ||
80 | |||
81 | /* | 72 | /* |
82 | * Step 5: | 73 | * Step 5: |
83 | * | 74 | * |
@@ -89,7 +80,6 @@ int test__vmlinux_matches_kallsyms(void) | |||
89 | } | 80 | } |
90 | 81 | ||
91 | vmlinux_map = machine__kernel_map(&vmlinux, type); | 82 | vmlinux_map = machine__kernel_map(&vmlinux, type); |
92 | map__kmap(vmlinux_map)->ref_reloc_sym = &ref_reloc_sym; | ||
93 | 83 | ||
94 | /* | 84 | /* |
95 | * Step 6: | 85 | * Step 6: |
diff --git a/tools/perf/ui/browser.c b/tools/perf/ui/browser.c index cbaa7af45513..d11541d4d7d7 100644 --- a/tools/perf/ui/browser.c +++ b/tools/perf/ui/browser.c | |||
@@ -256,8 +256,7 @@ int ui_browser__show(struct ui_browser *browser, const char *title, | |||
256 | __ui_browser__show_title(browser, title); | 256 | __ui_browser__show_title(browser, title); |
257 | 257 | ||
258 | browser->title = title; | 258 | browser->title = title; |
259 | free(browser->helpline); | 259 | zfree(&browser->helpline); |
260 | browser->helpline = NULL; | ||
261 | 260 | ||
262 | va_start(ap, helpline); | 261 | va_start(ap, helpline); |
263 | err = vasprintf(&browser->helpline, helpline, ap); | 262 | err = vasprintf(&browser->helpline, helpline, ap); |
@@ -268,12 +267,11 @@ int ui_browser__show(struct ui_browser *browser, const char *title, | |||
268 | return err ? 0 : -1; | 267 | return err ? 0 : -1; |
269 | } | 268 | } |
270 | 269 | ||
271 | void ui_browser__hide(struct ui_browser *browser __maybe_unused) | 270 | void ui_browser__hide(struct ui_browser *browser) |
272 | { | 271 | { |
273 | pthread_mutex_lock(&ui__lock); | 272 | pthread_mutex_lock(&ui__lock); |
274 | ui_helpline__pop(); | 273 | ui_helpline__pop(); |
275 | free(browser->helpline); | 274 | zfree(&browser->helpline); |
276 | browser->helpline = NULL; | ||
277 | pthread_mutex_unlock(&ui__lock); | 275 | pthread_mutex_unlock(&ui__lock); |
278 | } | 276 | } |
279 | 277 | ||
diff --git a/tools/perf/ui/browser.h b/tools/perf/ui/browser.h index 7d45d2f53601..118cca29dd26 100644 --- a/tools/perf/ui/browser.h +++ b/tools/perf/ui/browser.h | |||
@@ -59,6 +59,8 @@ int ui_browser__help_window(struct ui_browser *browser, const char *text); | |||
59 | bool ui_browser__dialog_yesno(struct ui_browser *browser, const char *text); | 59 | bool ui_browser__dialog_yesno(struct ui_browser *browser, const char *text); |
60 | int ui_browser__input_window(const char *title, const char *text, char *input, | 60 | int ui_browser__input_window(const char *title, const char *text, char *input, |
61 | const char *exit_msg, int delay_sec); | 61 | const char *exit_msg, int delay_sec); |
62 | struct perf_session_env; | ||
63 | int tui__header_window(struct perf_session_env *env); | ||
62 | 64 | ||
63 | void ui_browser__argv_seek(struct ui_browser *browser, off_t offset, int whence); | 65 | void ui_browser__argv_seek(struct ui_browser *browser, off_t offset, int whence); |
64 | unsigned int ui_browser__argv_refresh(struct ui_browser *browser); | 66 | unsigned int ui_browser__argv_refresh(struct ui_browser *browser); |
diff --git a/tools/perf/ui/browsers/header.c b/tools/perf/ui/browsers/header.c new file mode 100644 index 000000000000..89c16b988618 --- /dev/null +++ b/tools/perf/ui/browsers/header.c | |||
@@ -0,0 +1,127 @@ | |||
1 | #include "util/cache.h" | ||
2 | #include "util/debug.h" | ||
3 | #include "ui/browser.h" | ||
4 | #include "ui/ui.h" | ||
5 | #include "ui/util.h" | ||
6 | #include "ui/libslang.h" | ||
7 | #include "util/header.h" | ||
8 | #include "util/session.h" | ||
9 | |||
10 | static void ui_browser__argv_write(struct ui_browser *browser, | ||
11 | void *entry, int row) | ||
12 | { | ||
13 | char **arg = entry; | ||
14 | char *str = *arg; | ||
15 | char empty[] = " "; | ||
16 | bool current_entry = ui_browser__is_current_entry(browser, row); | ||
17 | unsigned long offset = (unsigned long)browser->priv; | ||
18 | |||
19 | if (offset >= strlen(str)) | ||
20 | str = empty; | ||
21 | else | ||
22 | str = str + offset; | ||
23 | |||
24 | ui_browser__set_color(browser, current_entry ? HE_COLORSET_SELECTED : | ||
25 | HE_COLORSET_NORMAL); | ||
26 | |||
27 | slsmg_write_nstring(str, browser->width); | ||
28 | } | ||
29 | |||
30 | static int list_menu__run(struct ui_browser *menu) | ||
31 | { | ||
32 | int key; | ||
33 | unsigned long offset; | ||
34 | const char help[] = | ||
35 | "h/?/F1 Show this window\n" | ||
36 | "UP/DOWN/PGUP\n" | ||
37 | "PGDN/SPACE\n" | ||
38 | "LEFT/RIGHT Navigate\n" | ||
39 | "q/ESC/CTRL+C Exit browser"; | ||
40 | |||
41 | if (ui_browser__show(menu, "Header information", "Press 'q' to exit") < 0) | ||
42 | return -1; | ||
43 | |||
44 | while (1) { | ||
45 | key = ui_browser__run(menu, 0); | ||
46 | |||
47 | switch (key) { | ||
48 | case K_RIGHT: | ||
49 | offset = (unsigned long)menu->priv; | ||
50 | offset += 10; | ||
51 | menu->priv = (void *)offset; | ||
52 | continue; | ||
53 | case K_LEFT: | ||
54 | offset = (unsigned long)menu->priv; | ||
55 | if (offset >= 10) | ||
56 | offset -= 10; | ||
57 | menu->priv = (void *)offset; | ||
58 | continue; | ||
59 | case K_F1: | ||
60 | case 'h': | ||
61 | case '?': | ||
62 | ui_browser__help_window(menu, help); | ||
63 | continue; | ||
64 | case K_ESC: | ||
65 | case 'q': | ||
66 | case CTRL('c'): | ||
67 | key = -1; | ||
68 | break; | ||
69 | default: | ||
70 | continue; | ||
71 | } | ||
72 | |||
73 | break; | ||
74 | } | ||
75 | |||
76 | ui_browser__hide(menu); | ||
77 | return key; | ||
78 | } | ||
79 | |||
80 | static int ui__list_menu(int argc, char * const argv[]) | ||
81 | { | ||
82 | struct ui_browser menu = { | ||
83 | .entries = (void *)argv, | ||
84 | .refresh = ui_browser__argv_refresh, | ||
85 | .seek = ui_browser__argv_seek, | ||
86 | .write = ui_browser__argv_write, | ||
87 | .nr_entries = argc, | ||
88 | }; | ||
89 | |||
90 | return list_menu__run(&menu); | ||
91 | } | ||
92 | |||
93 | int tui__header_window(struct perf_session_env *env) | ||
94 | { | ||
95 | int i, argc = 0; | ||
96 | char **argv; | ||
97 | struct perf_session *session; | ||
98 | char *ptr, *pos; | ||
99 | size_t size; | ||
100 | FILE *fp = open_memstream(&ptr, &size); | ||
101 | |||
102 | session = container_of(env, struct perf_session, header.env); | ||
103 | perf_header__fprintf_info(session, fp, true); | ||
104 | fclose(fp); | ||
105 | |||
106 | for (pos = ptr, argc = 0; (pos = strchr(pos, '\n')) != NULL; pos++) | ||
107 | argc++; | ||
108 | |||
109 | argv = calloc(argc + 1, sizeof(*argv)); | ||
110 | if (argv == NULL) | ||
111 | goto out; | ||
112 | |||
113 | argv[0] = pos = ptr; | ||
114 | for (i = 1; (pos = strchr(pos, '\n')) != NULL; i++) { | ||
115 | *pos++ = '\0'; | ||
116 | argv[i] = pos; | ||
117 | } | ||
118 | |||
119 | BUG_ON(i != argc + 1); | ||
120 | |||
121 | ui__list_menu(argc, argv); | ||
122 | |||
123 | out: | ||
124 | free(argv); | ||
125 | free(ptr); | ||
126 | return 0; | ||
127 | } | ||
diff --git a/tools/perf/ui/browsers/hists.c b/tools/perf/ui/browsers/hists.c index a440e03cd8c2..b720b92eba6e 100644 --- a/tools/perf/ui/browsers/hists.c +++ b/tools/perf/ui/browsers/hists.c | |||
@@ -1267,10 +1267,8 @@ static inline void free_popup_options(char **options, int n) | |||
1267 | { | 1267 | { |
1268 | int i; | 1268 | int i; |
1269 | 1269 | ||
1270 | for (i = 0; i < n; ++i) { | 1270 | for (i = 0; i < n; ++i) |
1271 | free(options[i]); | 1271 | zfree(&options[i]); |
1272 | options[i] = NULL; | ||
1273 | } | ||
1274 | } | 1272 | } |
1275 | 1273 | ||
1276 | /* Check whether the browser is for 'top' or 'report' */ | 1274 | /* Check whether the browser is for 'top' or 'report' */ |
@@ -1329,7 +1327,7 @@ static int switch_data_file(void) | |||
1329 | 1327 | ||
1330 | abs_path[nr_options] = strdup(path); | 1328 | abs_path[nr_options] = strdup(path); |
1331 | if (!abs_path[nr_options]) { | 1329 | if (!abs_path[nr_options]) { |
1332 | free(options[nr_options]); | 1330 | zfree(&options[nr_options]); |
1333 | ui__warning("Can't search all data files due to memory shortage.\n"); | 1331 | ui__warning("Can't search all data files due to memory shortage.\n"); |
1334 | fclose(file); | 1332 | fclose(file); |
1335 | break; | 1333 | break; |
@@ -1400,6 +1398,36 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events, | |||
1400 | char script_opt[64]; | 1398 | char script_opt[64]; |
1401 | int delay_secs = hbt ? hbt->refresh : 0; | 1399 | int delay_secs = hbt ? hbt->refresh : 0; |
1402 | 1400 | ||
1401 | #define HIST_BROWSER_HELP_COMMON \ | ||
1402 | "h/?/F1 Show this window\n" \ | ||
1403 | "UP/DOWN/PGUP\n" \ | ||
1404 | "PGDN/SPACE Navigate\n" \ | ||
1405 | "q/ESC/CTRL+C Exit browser\n\n" \ | ||
1406 | "For multiple event sessions:\n\n" \ | ||
1407 | "TAB/UNTAB Switch events\n\n" \ | ||
1408 | "For symbolic views (--sort has sym):\n\n" \ | ||
1409 | "-> Zoom into DSO/Threads & Annotate current symbol\n" \ | ||
1410 | "<- Zoom out\n" \ | ||
1411 | "a Annotate current symbol\n" \ | ||
1412 | "C Collapse all callchains\n" \ | ||
1413 | "d Zoom into current DSO\n" \ | ||
1414 | "E Expand all callchains\n" \ | ||
1415 | |||
1416 | /* help messages are sorted by lexical order of the hotkey */ | ||
1417 | const char report_help[] = HIST_BROWSER_HELP_COMMON | ||
1418 | "i Show header information\n" | ||
1419 | "P Print histograms to perf.hist.N\n" | ||
1420 | "r Run available scripts\n" | ||
1421 | "s Switch to another data file in PWD\n" | ||
1422 | "t Zoom into current Thread\n" | ||
1423 | "V Verbose (DSO names in callchains, etc)\n" | ||
1424 | "/ Filter symbol by name"; | ||
1425 | const char top_help[] = HIST_BROWSER_HELP_COMMON | ||
1426 | "P Print histograms to perf.hist.N\n" | ||
1427 | "t Zoom into current Thread\n" | ||
1428 | "V Verbose (DSO names in callchains, etc)\n" | ||
1429 | "/ Filter symbol by name"; | ||
1430 | |||
1403 | if (browser == NULL) | 1431 | if (browser == NULL) |
1404 | return -1; | 1432 | return -1; |
1405 | 1433 | ||
@@ -1484,29 +1512,16 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events, | |||
1484 | if (is_report_browser(hbt)) | 1512 | if (is_report_browser(hbt)) |
1485 | goto do_data_switch; | 1513 | goto do_data_switch; |
1486 | continue; | 1514 | continue; |
1515 | case 'i': | ||
1516 | /* env->arch is NULL for live-mode (i.e. perf top) */ | ||
1517 | if (env->arch) | ||
1518 | tui__header_window(env); | ||
1519 | continue; | ||
1487 | case K_F1: | 1520 | case K_F1: |
1488 | case 'h': | 1521 | case 'h': |
1489 | case '?': | 1522 | case '?': |
1490 | ui_browser__help_window(&browser->b, | 1523 | ui_browser__help_window(&browser->b, |
1491 | "h/?/F1 Show this window\n" | 1524 | is_report_browser(hbt) ? report_help : top_help); |
1492 | "UP/DOWN/PGUP\n" | ||
1493 | "PGDN/SPACE Navigate\n" | ||
1494 | "q/ESC/CTRL+C Exit browser\n\n" | ||
1495 | "For multiple event sessions:\n\n" | ||
1496 | "TAB/UNTAB Switch events\n\n" | ||
1497 | "For symbolic views (--sort has sym):\n\n" | ||
1498 | "-> Zoom into DSO/Threads & Annotate current symbol\n" | ||
1499 | "<- Zoom out\n" | ||
1500 | "a Annotate current symbol\n" | ||
1501 | "C Collapse all callchains\n" | ||
1502 | "E Expand all callchains\n" | ||
1503 | "d Zoom into current DSO\n" | ||
1504 | "t Zoom into current Thread\n" | ||
1505 | "r Run available scripts('perf report' only)\n" | ||
1506 | "s Switch to another data file in PWD ('perf report' only)\n" | ||
1507 | "P Print histograms to perf.hist.N\n" | ||
1508 | "V Verbose (DSO names in callchains, etc)\n" | ||
1509 | "/ Filter symbol by name"); | ||
1510 | continue; | 1525 | continue; |
1511 | case K_ENTER: | 1526 | case K_ENTER: |
1512 | case K_RIGHT: | 1527 | case K_RIGHT: |
@@ -1923,7 +1938,7 @@ static int __perf_evlist__tui_browse_hists(struct perf_evlist *evlist, | |||
1923 | 1938 | ||
1924 | ui_helpline__push("Press ESC to exit"); | 1939 | ui_helpline__push("Press ESC to exit"); |
1925 | 1940 | ||
1926 | list_for_each_entry(pos, &evlist->entries, node) { | 1941 | evlist__for_each(evlist, pos) { |
1927 | const char *ev_name = perf_evsel__name(pos); | 1942 | const char *ev_name = perf_evsel__name(pos); |
1928 | size_t line_len = strlen(ev_name) + 7; | 1943 | size_t line_len = strlen(ev_name) + 7; |
1929 | 1944 | ||
@@ -1955,9 +1970,10 @@ single_entry: | |||
1955 | struct perf_evsel *pos; | 1970 | struct perf_evsel *pos; |
1956 | 1971 | ||
1957 | nr_entries = 0; | 1972 | nr_entries = 0; |
1958 | list_for_each_entry(pos, &evlist->entries, node) | 1973 | evlist__for_each(evlist, pos) { |
1959 | if (perf_evsel__is_group_leader(pos)) | 1974 | if (perf_evsel__is_group_leader(pos)) |
1960 | nr_entries++; | 1975 | nr_entries++; |
1976 | } | ||
1961 | 1977 | ||
1962 | if (nr_entries == 1) | 1978 | if (nr_entries == 1) |
1963 | goto single_entry; | 1979 | goto single_entry; |
diff --git a/tools/perf/ui/browsers/scripts.c b/tools/perf/ui/browsers/scripts.c index d63c68ea02a8..402d2bd30b09 100644 --- a/tools/perf/ui/browsers/scripts.c +++ b/tools/perf/ui/browsers/scripts.c | |||
@@ -173,8 +173,7 @@ int script_browse(const char *script_opt) | |||
173 | if (script.b.width > AVERAGE_LINE_LEN) | 173 | if (script.b.width > AVERAGE_LINE_LEN) |
174 | script.b.width = AVERAGE_LINE_LEN; | 174 | script.b.width = AVERAGE_LINE_LEN; |
175 | 175 | ||
176 | if (line) | 176 | free(line); |
177 | free(line); | ||
178 | pclose(fp); | 177 | pclose(fp); |
179 | 178 | ||
180 | script.nr_lines = nr_entries; | 179 | script.nr_lines = nr_entries; |
diff --git a/tools/perf/ui/gtk/hists.c b/tools/perf/ui/gtk/hists.c index 2ca66cc1160f..5b95c44f3435 100644 --- a/tools/perf/ui/gtk/hists.c +++ b/tools/perf/ui/gtk/hists.c | |||
@@ -375,7 +375,7 @@ int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist, | |||
375 | 375 | ||
376 | gtk_container_add(GTK_CONTAINER(window), vbox); | 376 | gtk_container_add(GTK_CONTAINER(window), vbox); |
377 | 377 | ||
378 | list_for_each_entry(pos, &evlist->entries, node) { | 378 | evlist__for_each(evlist, pos) { |
379 | struct hists *hists = &pos->hists; | 379 | struct hists *hists = &pos->hists; |
380 | const char *evname = perf_evsel__name(pos); | 380 | const char *evname = perf_evsel__name(pos); |
381 | GtkWidget *scrolled_window; | 381 | GtkWidget *scrolled_window; |
diff --git a/tools/perf/ui/gtk/util.c b/tools/perf/ui/gtk/util.c index 696c1fbe4248..52e7fc48af9f 100644 --- a/tools/perf/ui/gtk/util.c +++ b/tools/perf/ui/gtk/util.c | |||
@@ -23,8 +23,7 @@ int perf_gtk__deactivate_context(struct perf_gtk_context **ctx) | |||
23 | if (!perf_gtk__is_active_context(*ctx)) | 23 | if (!perf_gtk__is_active_context(*ctx)) |
24 | return -1; | 24 | return -1; |
25 | 25 | ||
26 | free(*ctx); | 26 | zfree(ctx); |
27 | *ctx = NULL; | ||
28 | return 0; | 27 | return 0; |
29 | } | 28 | } |
30 | 29 | ||
diff --git a/tools/perf/ui/stdio/hist.c b/tools/perf/ui/stdio/hist.c index c244cb524ef2..831fbb77d1ff 100644 --- a/tools/perf/ui/stdio/hist.c +++ b/tools/perf/ui/stdio/hist.c | |||
@@ -510,7 +510,7 @@ print_entries: | |||
510 | 510 | ||
511 | free(line); | 511 | free(line); |
512 | out: | 512 | out: |
513 | free(rem_sq_bracket); | 513 | zfree(&rem_sq_bracket); |
514 | 514 | ||
515 | return ret; | 515 | return ret; |
516 | } | 516 | } |
diff --git a/tools/perf/ui/tui/util.c b/tools/perf/ui/tui/util.c index 092902e30cee..bf890f72fe80 100644 --- a/tools/perf/ui/tui/util.c +++ b/tools/perf/ui/tui/util.c | |||
@@ -92,6 +92,8 @@ int ui_browser__input_window(const char *title, const char *text, char *input, | |||
92 | t = sep + 1; | 92 | t = sep + 1; |
93 | } | 93 | } |
94 | 94 | ||
95 | pthread_mutex_lock(&ui__lock); | ||
96 | |||
95 | max_len += 2; | 97 | max_len += 2; |
96 | nr_lines += 8; | 98 | nr_lines += 8; |
97 | y = SLtt_Screen_Rows / 2 - nr_lines / 2; | 99 | y = SLtt_Screen_Rows / 2 - nr_lines / 2; |
@@ -120,13 +122,19 @@ int ui_browser__input_window(const char *title, const char *text, char *input, | |||
120 | SLsmg_write_nstring((char *)exit_msg, max_len); | 122 | SLsmg_write_nstring((char *)exit_msg, max_len); |
121 | SLsmg_refresh(); | 123 | SLsmg_refresh(); |
122 | 124 | ||
125 | pthread_mutex_unlock(&ui__lock); | ||
126 | |||
123 | x += 2; | 127 | x += 2; |
124 | len = 0; | 128 | len = 0; |
125 | key = ui__getch(delay_secs); | 129 | key = ui__getch(delay_secs); |
126 | while (key != K_TIMER && key != K_ENTER && key != K_ESC) { | 130 | while (key != K_TIMER && key != K_ENTER && key != K_ESC) { |
131 | pthread_mutex_lock(&ui__lock); | ||
132 | |||
127 | if (key == K_BKSPC) { | 133 | if (key == K_BKSPC) { |
128 | if (len == 0) | 134 | if (len == 0) { |
135 | pthread_mutex_unlock(&ui__lock); | ||
129 | goto next_key; | 136 | goto next_key; |
137 | } | ||
130 | SLsmg_gotorc(y, x + --len); | 138 | SLsmg_gotorc(y, x + --len); |
131 | SLsmg_write_char(' '); | 139 | SLsmg_write_char(' '); |
132 | } else { | 140 | } else { |
@@ -136,6 +144,8 @@ int ui_browser__input_window(const char *title, const char *text, char *input, | |||
136 | } | 144 | } |
137 | SLsmg_refresh(); | 145 | SLsmg_refresh(); |
138 | 146 | ||
147 | pthread_mutex_unlock(&ui__lock); | ||
148 | |||
139 | /* XXX more graceful overflow handling needed */ | 149 | /* XXX more graceful overflow handling needed */ |
140 | if (len == sizeof(buf) - 1) { | 150 | if (len == sizeof(buf) - 1) { |
141 | ui_helpline__push("maximum size of symbol name reached!"); | 151 | ui_helpline__push("maximum size of symbol name reached!"); |
@@ -174,6 +184,8 @@ int ui__question_window(const char *title, const char *text, | |||
174 | t = sep + 1; | 184 | t = sep + 1; |
175 | } | 185 | } |
176 | 186 | ||
187 | pthread_mutex_lock(&ui__lock); | ||
188 | |||
177 | max_len += 2; | 189 | max_len += 2; |
178 | nr_lines += 4; | 190 | nr_lines += 4; |
179 | y = SLtt_Screen_Rows / 2 - nr_lines / 2, | 191 | y = SLtt_Screen_Rows / 2 - nr_lines / 2, |
@@ -195,6 +207,9 @@ int ui__question_window(const char *title, const char *text, | |||
195 | SLsmg_gotorc(y + nr_lines - 1, x); | 207 | SLsmg_gotorc(y + nr_lines - 1, x); |
196 | SLsmg_write_nstring((char *)exit_msg, max_len); | 208 | SLsmg_write_nstring((char *)exit_msg, max_len); |
197 | SLsmg_refresh(); | 209 | SLsmg_refresh(); |
210 | |||
211 | pthread_mutex_unlock(&ui__lock); | ||
212 | |||
198 | return ui__getch(delay_secs); | 213 | return ui__getch(delay_secs); |
199 | } | 214 | } |
200 | 215 | ||
@@ -215,9 +230,7 @@ static int __ui__warning(const char *title, const char *format, va_list args) | |||
215 | if (vasprintf(&s, format, args) > 0) { | 230 | if (vasprintf(&s, format, args) > 0) { |
216 | int key; | 231 | int key; |
217 | 232 | ||
218 | pthread_mutex_lock(&ui__lock); | ||
219 | key = ui__question_window(title, s, "Press any key...", 0); | 233 | key = ui__question_window(title, s, "Press any key...", 0); |
220 | pthread_mutex_unlock(&ui__lock); | ||
221 | free(s); | 234 | free(s); |
222 | return key; | 235 | return key; |
223 | } | 236 | } |
diff --git a/tools/perf/util/alias.c b/tools/perf/util/alias.c index e6d134773d0a..c0b43ee40d95 100644 --- a/tools/perf/util/alias.c +++ b/tools/perf/util/alias.c | |||
@@ -55,8 +55,7 @@ int split_cmdline(char *cmdline, const char ***argv) | |||
55 | src++; | 55 | src++; |
56 | c = cmdline[src]; | 56 | c = cmdline[src]; |
57 | if (!c) { | 57 | if (!c) { |
58 | free(*argv); | 58 | zfree(argv); |
59 | *argv = NULL; | ||
60 | return error("cmdline ends with \\"); | 59 | return error("cmdline ends with \\"); |
61 | } | 60 | } |
62 | } | 61 | } |
@@ -68,8 +67,7 @@ int split_cmdline(char *cmdline, const char ***argv) | |||
68 | cmdline[dst] = 0; | 67 | cmdline[dst] = 0; |
69 | 68 | ||
70 | if (quoted) { | 69 | if (quoted) { |
71 | free(*argv); | 70 | zfree(argv); |
72 | *argv = NULL; | ||
73 | return error("unclosed quote"); | 71 | return error("unclosed quote"); |
74 | } | 72 | } |
75 | 73 | ||
diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index cf6242c92ee2..3aa555ff9d89 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c | |||
@@ -8,6 +8,8 @@ | |||
8 | */ | 8 | */ |
9 | 9 | ||
10 | #include "util.h" | 10 | #include "util.h" |
11 | #include "ui/ui.h" | ||
12 | #include "sort.h" | ||
11 | #include "build-id.h" | 13 | #include "build-id.h" |
12 | #include "color.h" | 14 | #include "color.h" |
13 | #include "cache.h" | 15 | #include "cache.h" |
@@ -26,10 +28,10 @@ static int disasm_line__parse(char *line, char **namep, char **rawp); | |||
26 | 28 | ||
27 | static void ins__delete(struct ins_operands *ops) | 29 | static void ins__delete(struct ins_operands *ops) |
28 | { | 30 | { |
29 | free(ops->source.raw); | 31 | zfree(&ops->source.raw); |
30 | free(ops->source.name); | 32 | zfree(&ops->source.name); |
31 | free(ops->target.raw); | 33 | zfree(&ops->target.raw); |
32 | free(ops->target.name); | 34 | zfree(&ops->target.name); |
33 | } | 35 | } |
34 | 36 | ||
35 | static int ins__raw_scnprintf(struct ins *ins, char *bf, size_t size, | 37 | static int ins__raw_scnprintf(struct ins *ins, char *bf, size_t size, |
@@ -185,8 +187,7 @@ static int lock__parse(struct ins_operands *ops) | |||
185 | return 0; | 187 | return 0; |
186 | 188 | ||
187 | out_free_ops: | 189 | out_free_ops: |
188 | free(ops->locked.ops); | 190 | zfree(&ops->locked.ops); |
189 | ops->locked.ops = NULL; | ||
190 | return 0; | 191 | return 0; |
191 | } | 192 | } |
192 | 193 | ||
@@ -205,9 +206,9 @@ static int lock__scnprintf(struct ins *ins, char *bf, size_t size, | |||
205 | 206 | ||
206 | static void lock__delete(struct ins_operands *ops) | 207 | static void lock__delete(struct ins_operands *ops) |
207 | { | 208 | { |
208 | free(ops->locked.ops); | 209 | zfree(&ops->locked.ops); |
209 | free(ops->target.raw); | 210 | zfree(&ops->target.raw); |
210 | free(ops->target.name); | 211 | zfree(&ops->target.name); |
211 | } | 212 | } |
212 | 213 | ||
213 | static struct ins_ops lock_ops = { | 214 | static struct ins_ops lock_ops = { |
@@ -256,8 +257,7 @@ static int mov__parse(struct ins_operands *ops) | |||
256 | return 0; | 257 | return 0; |
257 | 258 | ||
258 | out_free_source: | 259 | out_free_source: |
259 | free(ops->source.raw); | 260 | zfree(&ops->source.raw); |
260 | ops->source.raw = NULL; | ||
261 | return -1; | 261 | return -1; |
262 | } | 262 | } |
263 | 263 | ||
@@ -464,17 +464,12 @@ void symbol__annotate_zero_histograms(struct symbol *sym) | |||
464 | pthread_mutex_unlock(¬es->lock); | 464 | pthread_mutex_unlock(¬es->lock); |
465 | } | 465 | } |
466 | 466 | ||
467 | int symbol__inc_addr_samples(struct symbol *sym, struct map *map, | 467 | static int __symbol__inc_addr_samples(struct symbol *sym, struct map *map, |
468 | int evidx, u64 addr) | 468 | struct annotation *notes, int evidx, u64 addr) |
469 | { | 469 | { |
470 | unsigned offset; | 470 | unsigned offset; |
471 | struct annotation *notes; | ||
472 | struct sym_hist *h; | 471 | struct sym_hist *h; |
473 | 472 | ||
474 | notes = symbol__annotation(sym); | ||
475 | if (notes->src == NULL) | ||
476 | return -ENOMEM; | ||
477 | |||
478 | pr_debug3("%s: addr=%#" PRIx64 "\n", __func__, map->unmap_ip(map, addr)); | 473 | pr_debug3("%s: addr=%#" PRIx64 "\n", __func__, map->unmap_ip(map, addr)); |
479 | 474 | ||
480 | if (addr < sym->start || addr > sym->end) | 475 | if (addr < sym->start || addr > sym->end) |
@@ -491,6 +486,33 @@ int symbol__inc_addr_samples(struct symbol *sym, struct map *map, | |||
491 | return 0; | 486 | return 0; |
492 | } | 487 | } |
493 | 488 | ||
489 | static int symbol__inc_addr_samples(struct symbol *sym, struct map *map, | ||
490 | int evidx, u64 addr) | ||
491 | { | ||
492 | struct annotation *notes; | ||
493 | |||
494 | if (sym == NULL) | ||
495 | return 0; | ||
496 | |||
497 | notes = symbol__annotation(sym); | ||
498 | if (notes->src == NULL) { | ||
499 | if (symbol__alloc_hist(sym) < 0) | ||
500 | return -ENOMEM; | ||
501 | } | ||
502 | |||
503 | return __symbol__inc_addr_samples(sym, map, notes, evidx, addr); | ||
504 | } | ||
505 | |||
506 | int addr_map_symbol__inc_samples(struct addr_map_symbol *ams, int evidx) | ||
507 | { | ||
508 | return symbol__inc_addr_samples(ams->sym, ams->map, evidx, ams->al_addr); | ||
509 | } | ||
510 | |||
511 | int hist_entry__inc_addr_samples(struct hist_entry *he, int evidx, u64 ip) | ||
512 | { | ||
513 | return symbol__inc_addr_samples(he->ms.sym, he->ms.map, evidx, ip); | ||
514 | } | ||
515 | |||
494 | static void disasm_line__init_ins(struct disasm_line *dl) | 516 | static void disasm_line__init_ins(struct disasm_line *dl) |
495 | { | 517 | { |
496 | dl->ins = ins__find(dl->name); | 518 | dl->ins = ins__find(dl->name); |
@@ -538,8 +560,7 @@ static int disasm_line__parse(char *line, char **namep, char **rawp) | |||
538 | return 0; | 560 | return 0; |
539 | 561 | ||
540 | out_free_name: | 562 | out_free_name: |
541 | free(*namep); | 563 | zfree(namep); |
542 | *namep = NULL; | ||
543 | return -1; | 564 | return -1; |
544 | } | 565 | } |
545 | 566 | ||
@@ -564,7 +585,7 @@ static struct disasm_line *disasm_line__new(s64 offset, char *line, size_t privs | |||
564 | return dl; | 585 | return dl; |
565 | 586 | ||
566 | out_free_line: | 587 | out_free_line: |
567 | free(dl->line); | 588 | zfree(&dl->line); |
568 | out_delete: | 589 | out_delete: |
569 | free(dl); | 590 | free(dl); |
570 | return NULL; | 591 | return NULL; |
@@ -572,8 +593,8 @@ out_delete: | |||
572 | 593 | ||
573 | void disasm_line__free(struct disasm_line *dl) | 594 | void disasm_line__free(struct disasm_line *dl) |
574 | { | 595 | { |
575 | free(dl->line); | 596 | zfree(&dl->line); |
576 | free(dl->name); | 597 | zfree(&dl->name); |
577 | if (dl->ins && dl->ins->ops->free) | 598 | if (dl->ins && dl->ins->ops->free) |
578 | dl->ins->ops->free(&dl->ops); | 599 | dl->ins->ops->free(&dl->ops); |
579 | else | 600 | else |
@@ -900,7 +921,7 @@ fallback: | |||
900 | * cache, or is just a kallsyms file, well, lets hope that this | 921 | * cache, or is just a kallsyms file, well, lets hope that this |
901 | * DSO is the same as when 'perf record' ran. | 922 | * DSO is the same as when 'perf record' ran. |
902 | */ | 923 | */ |
903 | filename = dso->long_name; | 924 | filename = (char *)dso->long_name; |
904 | snprintf(symfs_filename, sizeof(symfs_filename), "%s%s", | 925 | snprintf(symfs_filename, sizeof(symfs_filename), "%s%s", |
905 | symbol_conf.symfs, filename); | 926 | symbol_conf.symfs, filename); |
906 | free_filename = false; | 927 | free_filename = false; |
@@ -1091,8 +1112,7 @@ static void symbol__free_source_line(struct symbol *sym, int len) | |||
1091 | src_line = (void *)src_line + sizeof_src_line; | 1112 | src_line = (void *)src_line + sizeof_src_line; |
1092 | } | 1113 | } |
1093 | 1114 | ||
1094 | free(notes->src->lines); | 1115 | zfree(¬es->src->lines); |
1095 | notes->src->lines = NULL; | ||
1096 | } | 1116 | } |
1097 | 1117 | ||
1098 | /* Get the filename:line for the colored entries */ | 1118 | /* Get the filename:line for the colored entries */ |
@@ -1376,3 +1396,13 @@ int symbol__tty_annotate(struct symbol *sym, struct map *map, | |||
1376 | 1396 | ||
1377 | return 0; | 1397 | return 0; |
1378 | } | 1398 | } |
1399 | |||
1400 | int hist_entry__annotate(struct hist_entry *he, size_t privsize) | ||
1401 | { | ||
1402 | return symbol__annotate(he->ms.sym, he->ms.map, privsize); | ||
1403 | } | ||
1404 | |||
1405 | bool ui__has_annotation(void) | ||
1406 | { | ||
1407 | return use_browser == 1 && sort__has_sym; | ||
1408 | } | ||
diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h index 834b7b57b788..56ad4f5287de 100644 --- a/tools/perf/util/annotate.h +++ b/tools/perf/util/annotate.h | |||
@@ -132,12 +132,17 @@ static inline struct annotation *symbol__annotation(struct symbol *sym) | |||
132 | return &a->annotation; | 132 | return &a->annotation; |
133 | } | 133 | } |
134 | 134 | ||
135 | int symbol__inc_addr_samples(struct symbol *sym, struct map *map, | 135 | int addr_map_symbol__inc_samples(struct addr_map_symbol *ams, int evidx); |
136 | int evidx, u64 addr); | 136 | |
137 | int hist_entry__inc_addr_samples(struct hist_entry *he, int evidx, u64 addr); | ||
138 | |||
137 | int symbol__alloc_hist(struct symbol *sym); | 139 | int symbol__alloc_hist(struct symbol *sym); |
138 | void symbol__annotate_zero_histograms(struct symbol *sym); | 140 | void symbol__annotate_zero_histograms(struct symbol *sym); |
139 | 141 | ||
140 | int symbol__annotate(struct symbol *sym, struct map *map, size_t privsize); | 142 | int symbol__annotate(struct symbol *sym, struct map *map, size_t privsize); |
143 | |||
144 | int hist_entry__annotate(struct hist_entry *he, size_t privsize); | ||
145 | |||
141 | int symbol__annotate_init(struct map *map __maybe_unused, struct symbol *sym); | 146 | int symbol__annotate_init(struct map *map __maybe_unused, struct symbol *sym); |
142 | int symbol__annotate_printf(struct symbol *sym, struct map *map, | 147 | int symbol__annotate_printf(struct symbol *sym, struct map *map, |
143 | struct perf_evsel *evsel, bool full_paths, | 148 | struct perf_evsel *evsel, bool full_paths, |
@@ -146,6 +151,8 @@ void symbol__annotate_zero_histogram(struct symbol *sym, int evidx); | |||
146 | void symbol__annotate_decay_histogram(struct symbol *sym, int evidx); | 151 | void symbol__annotate_decay_histogram(struct symbol *sym, int evidx); |
147 | void disasm__purge(struct list_head *head); | 152 | void disasm__purge(struct list_head *head); |
148 | 153 | ||
154 | bool ui__has_annotation(void); | ||
155 | |||
149 | int symbol__tty_annotate(struct symbol *sym, struct map *map, | 156 | int symbol__tty_annotate(struct symbol *sym, struct map *map, |
150 | struct perf_evsel *evsel, bool print_lines, | 157 | struct perf_evsel *evsel, bool print_lines, |
151 | bool full_paths, int min_pcnt, int max_lines); | 158 | bool full_paths, int min_pcnt, int max_lines); |
diff --git a/tools/perf/util/build-id.c b/tools/perf/util/build-id.c index a92770c98cc7..6baabe63182b 100644 --- a/tools/perf/util/build-id.c +++ b/tools/perf/util/build-id.c | |||
@@ -89,7 +89,7 @@ int build_id__sprintf(const u8 *build_id, int len, char *bf) | |||
89 | return raw - build_id; | 89 | return raw - build_id; |
90 | } | 90 | } |
91 | 91 | ||
92 | char *dso__build_id_filename(struct dso *dso, char *bf, size_t size) | 92 | char *dso__build_id_filename(const struct dso *dso, char *bf, size_t size) |
93 | { | 93 | { |
94 | char build_id_hex[BUILD_ID_SIZE * 2 + 1]; | 94 | char build_id_hex[BUILD_ID_SIZE * 2 + 1]; |
95 | 95 | ||
diff --git a/tools/perf/util/build-id.h b/tools/perf/util/build-id.h index 929f28a7c14d..845ef865eced 100644 --- a/tools/perf/util/build-id.h +++ b/tools/perf/util/build-id.h | |||
@@ -10,7 +10,7 @@ extern struct perf_tool build_id__mark_dso_hit_ops; | |||
10 | struct dso; | 10 | struct dso; |
11 | 11 | ||
12 | int build_id__sprintf(const u8 *build_id, int len, char *bf); | 12 | int build_id__sprintf(const u8 *build_id, int len, char *bf); |
13 | char *dso__build_id_filename(struct dso *dso, char *bf, size_t size); | 13 | char *dso__build_id_filename(const struct dso *dso, char *bf, size_t size); |
14 | 14 | ||
15 | int build_id__mark_dso_hit(struct perf_tool *tool, union perf_event *event, | 15 | int build_id__mark_dso_hit(struct perf_tool *tool, union perf_event *event, |
16 | struct perf_sample *sample, struct perf_evsel *evsel, | 16 | struct perf_sample *sample, struct perf_evsel *evsel, |
diff --git a/tools/perf/util/callchain.c b/tools/perf/util/callchain.c index e3970e3eaacf..8d9db454f1a9 100644 --- a/tools/perf/util/callchain.c +++ b/tools/perf/util/callchain.c | |||
@@ -15,8 +15,12 @@ | |||
15 | #include <errno.h> | 15 | #include <errno.h> |
16 | #include <math.h> | 16 | #include <math.h> |
17 | 17 | ||
18 | #include "asm/bug.h" | ||
19 | |||
18 | #include "hist.h" | 20 | #include "hist.h" |
19 | #include "util.h" | 21 | #include "util.h" |
22 | #include "sort.h" | ||
23 | #include "machine.h" | ||
20 | #include "callchain.h" | 24 | #include "callchain.h" |
21 | 25 | ||
22 | __thread struct callchain_cursor callchain_cursor; | 26 | __thread struct callchain_cursor callchain_cursor; |
@@ -356,19 +360,14 @@ append_chain_children(struct callchain_node *root, | |||
356 | /* lookup in childrens */ | 360 | /* lookup in childrens */ |
357 | while (*p) { | 361 | while (*p) { |
358 | s64 ret; | 362 | s64 ret; |
359 | struct callchain_list *cnode; | ||
360 | 363 | ||
361 | parent = *p; | 364 | parent = *p; |
362 | rnode = rb_entry(parent, struct callchain_node, rb_node_in); | 365 | rnode = rb_entry(parent, struct callchain_node, rb_node_in); |
363 | cnode = list_first_entry(&rnode->val, struct callchain_list, | ||
364 | list); | ||
365 | 366 | ||
366 | /* just check first entry */ | 367 | /* If at least first entry matches, rely to children */ |
367 | ret = match_chain(node, cnode); | 368 | ret = append_chain(rnode, cursor, period); |
368 | if (ret == 0) { | 369 | if (ret == 0) |
369 | append_chain(rnode, cursor, period); | ||
370 | goto inc_children_hit; | 370 | goto inc_children_hit; |
371 | } | ||
372 | 371 | ||
373 | if (ret < 0) | 372 | if (ret < 0) |
374 | p = &parent->rb_left; | 373 | p = &parent->rb_left; |
@@ -389,11 +388,11 @@ append_chain(struct callchain_node *root, | |||
389 | struct callchain_cursor *cursor, | 388 | struct callchain_cursor *cursor, |
390 | u64 period) | 389 | u64 period) |
391 | { | 390 | { |
392 | struct callchain_cursor_node *curr_snap = cursor->curr; | ||
393 | struct callchain_list *cnode; | 391 | struct callchain_list *cnode; |
394 | u64 start = cursor->pos; | 392 | u64 start = cursor->pos; |
395 | bool found = false; | 393 | bool found = false; |
396 | u64 matches; | 394 | u64 matches; |
395 | int cmp = 0; | ||
397 | 396 | ||
398 | /* | 397 | /* |
399 | * Lookup in the current node | 398 | * Lookup in the current node |
@@ -408,7 +407,8 @@ append_chain(struct callchain_node *root, | |||
408 | if (!node) | 407 | if (!node) |
409 | break; | 408 | break; |
410 | 409 | ||
411 | if (match_chain(node, cnode) != 0) | 410 | cmp = match_chain(node, cnode); |
411 | if (cmp) | ||
412 | break; | 412 | break; |
413 | 413 | ||
414 | found = true; | 414 | found = true; |
@@ -418,9 +418,8 @@ append_chain(struct callchain_node *root, | |||
418 | 418 | ||
419 | /* matches not, relay no the parent */ | 419 | /* matches not, relay no the parent */ |
420 | if (!found) { | 420 | if (!found) { |
421 | cursor->curr = curr_snap; | 421 | WARN_ONCE(!cmp, "Chain comparison error\n"); |
422 | cursor->pos = start; | 422 | return cmp; |
423 | return -1; | ||
424 | } | 423 | } |
425 | 424 | ||
426 | matches = cursor->pos - start; | 425 | matches = cursor->pos - start; |
@@ -531,3 +530,24 @@ int callchain_cursor_append(struct callchain_cursor *cursor, | |||
531 | 530 | ||
532 | return 0; | 531 | return 0; |
533 | } | 532 | } |
533 | |||
534 | int sample__resolve_callchain(struct perf_sample *sample, struct symbol **parent, | ||
535 | struct perf_evsel *evsel, struct addr_location *al, | ||
536 | int max_stack) | ||
537 | { | ||
538 | if (sample->callchain == NULL) | ||
539 | return 0; | ||
540 | |||
541 | if (symbol_conf.use_callchain || sort__has_parent) { | ||
542 | return machine__resolve_callchain(al->machine, evsel, al->thread, | ||
543 | sample, parent, al, max_stack); | ||
544 | } | ||
545 | return 0; | ||
546 | } | ||
547 | |||
548 | int hist_entry__append_callchain(struct hist_entry *he, struct perf_sample *sample) | ||
549 | { | ||
550 | if (!symbol_conf.use_callchain) | ||
551 | return 0; | ||
552 | return callchain_append(he->callchain, &callchain_cursor, sample->period); | ||
553 | } | ||
diff --git a/tools/perf/util/callchain.h b/tools/perf/util/callchain.h index 4f7f989876ec..8ad97e9b119f 100644 --- a/tools/perf/util/callchain.h +++ b/tools/perf/util/callchain.h | |||
@@ -145,10 +145,16 @@ static inline void callchain_cursor_advance(struct callchain_cursor *cursor) | |||
145 | } | 145 | } |
146 | 146 | ||
147 | struct option; | 147 | struct option; |
148 | struct hist_entry; | ||
148 | 149 | ||
149 | int record_parse_callchain(const char *arg, struct perf_record_opts *opts); | 150 | int record_parse_callchain(const char *arg, struct record_opts *opts); |
150 | int record_parse_callchain_opt(const struct option *opt, const char *arg, int unset); | 151 | int record_parse_callchain_opt(const struct option *opt, const char *arg, int unset); |
151 | int record_callchain_opt(const struct option *opt, const char *arg, int unset); | 152 | int record_callchain_opt(const struct option *opt, const char *arg, int unset); |
152 | 153 | ||
154 | int sample__resolve_callchain(struct perf_sample *sample, struct symbol **parent, | ||
155 | struct perf_evsel *evsel, struct addr_location *al, | ||
156 | int max_stack); | ||
157 | int hist_entry__append_callchain(struct hist_entry *he, struct perf_sample *sample); | ||
158 | |||
153 | extern const char record_callchain_help[]; | 159 | extern const char record_callchain_help[]; |
154 | #endif /* __PERF_CALLCHAIN_H */ | 160 | #endif /* __PERF_CALLCHAIN_H */ |
diff --git a/tools/perf/util/cgroup.c b/tools/perf/util/cgroup.c index 96bbda1ddb83..88f7be399432 100644 --- a/tools/perf/util/cgroup.c +++ b/tools/perf/util/cgroup.c | |||
@@ -81,7 +81,7 @@ static int add_cgroup(struct perf_evlist *evlist, char *str) | |||
81 | /* | 81 | /* |
82 | * check if cgrp is already defined, if so we reuse it | 82 | * check if cgrp is already defined, if so we reuse it |
83 | */ | 83 | */ |
84 | list_for_each_entry(counter, &evlist->entries, node) { | 84 | evlist__for_each(evlist, counter) { |
85 | cgrp = counter->cgrp; | 85 | cgrp = counter->cgrp; |
86 | if (!cgrp) | 86 | if (!cgrp) |
87 | continue; | 87 | continue; |
@@ -110,7 +110,7 @@ static int add_cgroup(struct perf_evlist *evlist, char *str) | |||
110 | * if add cgroup N, then need to find event N | 110 | * if add cgroup N, then need to find event N |
111 | */ | 111 | */ |
112 | n = 0; | 112 | n = 0; |
113 | list_for_each_entry(counter, &evlist->entries, node) { | 113 | evlist__for_each(evlist, counter) { |
114 | if (n == nr_cgroups) | 114 | if (n == nr_cgroups) |
115 | goto found; | 115 | goto found; |
116 | n++; | 116 | n++; |
@@ -133,7 +133,7 @@ void close_cgroup(struct cgroup_sel *cgrp) | |||
133 | /* XXX: not reentrant */ | 133 | /* XXX: not reentrant */ |
134 | if (--cgrp->refcnt == 0) { | 134 | if (--cgrp->refcnt == 0) { |
135 | close(cgrp->fd); | 135 | close(cgrp->fd); |
136 | free(cgrp->name); | 136 | zfree(&cgrp->name); |
137 | free(cgrp); | 137 | free(cgrp); |
138 | } | 138 | } |
139 | } | 139 | } |
diff --git a/tools/perf/util/color.c b/tools/perf/util/color.c index 66e44a5019d5..87b8672eb413 100644 --- a/tools/perf/util/color.c +++ b/tools/perf/util/color.c | |||
@@ -1,6 +1,7 @@ | |||
1 | #include <linux/kernel.h> | 1 | #include <linux/kernel.h> |
2 | #include "cache.h" | 2 | #include "cache.h" |
3 | #include "color.h" | 3 | #include "color.h" |
4 | #include <math.h> | ||
4 | 5 | ||
5 | int perf_use_color_default = -1; | 6 | int perf_use_color_default = -1; |
6 | 7 | ||
@@ -298,10 +299,10 @@ const char *get_percent_color(double percent) | |||
298 | * entries in green - and keep the low overhead places | 299 | * entries in green - and keep the low overhead places |
299 | * normal: | 300 | * normal: |
300 | */ | 301 | */ |
301 | if (percent >= MIN_RED) | 302 | if (fabs(percent) >= MIN_RED) |
302 | color = PERF_COLOR_RED; | 303 | color = PERF_COLOR_RED; |
303 | else { | 304 | else { |
304 | if (percent > MIN_GREEN) | 305 | if (fabs(percent) > MIN_GREEN) |
305 | color = PERF_COLOR_GREEN; | 306 | color = PERF_COLOR_GREEN; |
306 | } | 307 | } |
307 | return color; | 308 | return color; |
@@ -318,15 +319,19 @@ int percent_color_fprintf(FILE *fp, const char *fmt, double percent) | |||
318 | return r; | 319 | return r; |
319 | } | 320 | } |
320 | 321 | ||
322 | int value_color_snprintf(char *bf, size_t size, const char *fmt, double value) | ||
323 | { | ||
324 | const char *color = get_percent_color(value); | ||
325 | return color_snprintf(bf, size, color, fmt, value); | ||
326 | } | ||
327 | |||
321 | int percent_color_snprintf(char *bf, size_t size, const char *fmt, ...) | 328 | int percent_color_snprintf(char *bf, size_t size, const char *fmt, ...) |
322 | { | 329 | { |
323 | va_list args; | 330 | va_list args; |
324 | double percent; | 331 | double percent; |
325 | const char *color; | ||
326 | 332 | ||
327 | va_start(args, fmt); | 333 | va_start(args, fmt); |
328 | percent = va_arg(args, double); | 334 | percent = va_arg(args, double); |
329 | va_end(args); | 335 | va_end(args); |
330 | color = get_percent_color(percent); | 336 | return value_color_snprintf(bf, size, fmt, percent); |
331 | return color_snprintf(bf, size, color, fmt, percent); | ||
332 | } | 337 | } |
diff --git a/tools/perf/util/color.h b/tools/perf/util/color.h index fced3840e99c..7ff30a62a132 100644 --- a/tools/perf/util/color.h +++ b/tools/perf/util/color.h | |||
@@ -39,6 +39,7 @@ int color_fprintf(FILE *fp, const char *color, const char *fmt, ...); | |||
39 | int color_snprintf(char *bf, size_t size, const char *color, const char *fmt, ...); | 39 | int color_snprintf(char *bf, size_t size, const char *color, const char *fmt, ...); |
40 | int color_fprintf_ln(FILE *fp, const char *color, const char *fmt, ...); | 40 | int color_fprintf_ln(FILE *fp, const char *color, const char *fmt, ...); |
41 | int color_fwrite_lines(FILE *fp, const char *color, size_t count, const char *buf); | 41 | int color_fwrite_lines(FILE *fp, const char *color, size_t count, const char *buf); |
42 | int value_color_snprintf(char *bf, size_t size, const char *fmt, double value); | ||
42 | int percent_color_snprintf(char *bf, size_t size, const char *fmt, ...); | 43 | int percent_color_snprintf(char *bf, size_t size, const char *fmt, ...); |
43 | int percent_color_fprintf(FILE *fp, const char *fmt, double percent); | 44 | int percent_color_fprintf(FILE *fp, const char *fmt, double percent); |
44 | const char *get_percent_color(double percent); | 45 | const char *get_percent_color(double percent); |
diff --git a/tools/perf/util/comm.c b/tools/perf/util/comm.c index ee0df0e24cdb..f9e777629e21 100644 --- a/tools/perf/util/comm.c +++ b/tools/perf/util/comm.c | |||
@@ -21,7 +21,7 @@ static void comm_str__put(struct comm_str *cs) | |||
21 | { | 21 | { |
22 | if (!--cs->ref) { | 22 | if (!--cs->ref) { |
23 | rb_erase(&cs->rb_node, &comm_str_root); | 23 | rb_erase(&cs->rb_node, &comm_str_root); |
24 | free(cs->str); | 24 | zfree(&cs->str); |
25 | free(cs); | 25 | free(cs); |
26 | } | 26 | } |
27 | } | 27 | } |
@@ -94,19 +94,20 @@ struct comm *comm__new(const char *str, u64 timestamp) | |||
94 | return comm; | 94 | return comm; |
95 | } | 95 | } |
96 | 96 | ||
97 | void comm__override(struct comm *comm, const char *str, u64 timestamp) | 97 | int comm__override(struct comm *comm, const char *str, u64 timestamp) |
98 | { | 98 | { |
99 | struct comm_str *old = comm->comm_str; | 99 | struct comm_str *new, *old = comm->comm_str; |
100 | 100 | ||
101 | comm->comm_str = comm_str__findnew(str, &comm_str_root); | 101 | new = comm_str__findnew(str, &comm_str_root); |
102 | if (!comm->comm_str) { | 102 | if (!new) |
103 | comm->comm_str = old; | 103 | return -ENOMEM; |
104 | return; | ||
105 | } | ||
106 | 104 | ||
107 | comm->start = timestamp; | 105 | comm_str__get(new); |
108 | comm_str__get(comm->comm_str); | ||
109 | comm_str__put(old); | 106 | comm_str__put(old); |
107 | comm->comm_str = new; | ||
108 | comm->start = timestamp; | ||
109 | |||
110 | return 0; | ||
110 | } | 111 | } |
111 | 112 | ||
112 | void comm__free(struct comm *comm) | 113 | void comm__free(struct comm *comm) |
diff --git a/tools/perf/util/comm.h b/tools/perf/util/comm.h index 7a86e5656710..fac5bd51befc 100644 --- a/tools/perf/util/comm.h +++ b/tools/perf/util/comm.h | |||
@@ -16,6 +16,6 @@ struct comm { | |||
16 | void comm__free(struct comm *comm); | 16 | void comm__free(struct comm *comm); |
17 | struct comm *comm__new(const char *str, u64 timestamp); | 17 | struct comm *comm__new(const char *str, u64 timestamp); |
18 | const char *comm__str(const struct comm *comm); | 18 | const char *comm__str(const struct comm *comm); |
19 | void comm__override(struct comm *comm, const char *str, u64 timestamp); | 19 | int comm__override(struct comm *comm, const char *str, u64 timestamp); |
20 | 20 | ||
21 | #endif /* __PERF_COMM_H */ | 21 | #endif /* __PERF_COMM_H */ |
diff --git a/tools/perf/util/data.c b/tools/perf/util/data.c index 7d09faf85cf1..1fbcd8bdc11b 100644 --- a/tools/perf/util/data.c +++ b/tools/perf/util/data.c | |||
@@ -118,3 +118,9 @@ void perf_data_file__close(struct perf_data_file *file) | |||
118 | { | 118 | { |
119 | close(file->fd); | 119 | close(file->fd); |
120 | } | 120 | } |
121 | |||
122 | ssize_t perf_data_file__write(struct perf_data_file *file, | ||
123 | void *buf, size_t size) | ||
124 | { | ||
125 | return writen(file->fd, buf, size); | ||
126 | } | ||
diff --git a/tools/perf/util/data.h b/tools/perf/util/data.h index 8c2df80152a5..2b15d0c95c7f 100644 --- a/tools/perf/util/data.h +++ b/tools/perf/util/data.h | |||
@@ -9,12 +9,12 @@ enum perf_data_mode { | |||
9 | }; | 9 | }; |
10 | 10 | ||
11 | struct perf_data_file { | 11 | struct perf_data_file { |
12 | const char *path; | 12 | const char *path; |
13 | int fd; | 13 | int fd; |
14 | bool is_pipe; | 14 | bool is_pipe; |
15 | bool force; | 15 | bool force; |
16 | unsigned long size; | 16 | unsigned long size; |
17 | enum perf_data_mode mode; | 17 | enum perf_data_mode mode; |
18 | }; | 18 | }; |
19 | 19 | ||
20 | static inline bool perf_data_file__is_read(struct perf_data_file *file) | 20 | static inline bool perf_data_file__is_read(struct perf_data_file *file) |
@@ -44,5 +44,7 @@ static inline unsigned long perf_data_file__size(struct perf_data_file *file) | |||
44 | 44 | ||
45 | int perf_data_file__open(struct perf_data_file *file); | 45 | int perf_data_file__open(struct perf_data_file *file); |
46 | void perf_data_file__close(struct perf_data_file *file); | 46 | void perf_data_file__close(struct perf_data_file *file); |
47 | ssize_t perf_data_file__write(struct perf_data_file *file, | ||
48 | void *buf, size_t size); | ||
47 | 49 | ||
48 | #endif /* __PERF_DATA_H */ | 50 | #endif /* __PERF_DATA_H */ |
diff --git a/tools/perf/util/debug.c b/tools/perf/util/debug.c index 399e74c34c1a..299b55586502 100644 --- a/tools/perf/util/debug.c +++ b/tools/perf/util/debug.c | |||
@@ -16,23 +16,46 @@ | |||
16 | int verbose; | 16 | int verbose; |
17 | bool dump_trace = false, quiet = false; | 17 | bool dump_trace = false, quiet = false; |
18 | 18 | ||
19 | int eprintf(int level, const char *fmt, ...) | 19 | static int _eprintf(int level, const char *fmt, va_list args) |
20 | { | 20 | { |
21 | va_list args; | ||
22 | int ret = 0; | 21 | int ret = 0; |
23 | 22 | ||
24 | if (verbose >= level) { | 23 | if (verbose >= level) { |
25 | va_start(args, fmt); | ||
26 | if (use_browser >= 1) | 24 | if (use_browser >= 1) |
27 | ui_helpline__vshow(fmt, args); | 25 | ui_helpline__vshow(fmt, args); |
28 | else | 26 | else |
29 | ret = vfprintf(stderr, fmt, args); | 27 | ret = vfprintf(stderr, fmt, args); |
30 | va_end(args); | ||
31 | } | 28 | } |
32 | 29 | ||
33 | return ret; | 30 | return ret; |
34 | } | 31 | } |
35 | 32 | ||
33 | int eprintf(int level, const char *fmt, ...) | ||
34 | { | ||
35 | va_list args; | ||
36 | int ret; | ||
37 | |||
38 | va_start(args, fmt); | ||
39 | ret = _eprintf(level, fmt, args); | ||
40 | va_end(args); | ||
41 | |||
42 | return ret; | ||
43 | } | ||
44 | |||
45 | /* | ||
46 | * Overloading libtraceevent standard info print | ||
47 | * function, display with -v in perf. | ||
48 | */ | ||
49 | void pr_stat(const char *fmt, ...) | ||
50 | { | ||
51 | va_list args; | ||
52 | |||
53 | va_start(args, fmt); | ||
54 | _eprintf(1, fmt, args); | ||
55 | va_end(args); | ||
56 | eprintf(1, "\n"); | ||
57 | } | ||
58 | |||
36 | int dump_printf(const char *fmt, ...) | 59 | int dump_printf(const char *fmt, ...) |
37 | { | 60 | { |
38 | va_list args; | 61 | va_list args; |
diff --git a/tools/perf/util/debug.h b/tools/perf/util/debug.h index efbd98805ad0..443694c36b03 100644 --- a/tools/perf/util/debug.h +++ b/tools/perf/util/debug.h | |||
@@ -17,4 +17,6 @@ void trace_event(union perf_event *event); | |||
17 | int ui__error(const char *format, ...) __attribute__((format(printf, 1, 2))); | 17 | int ui__error(const char *format, ...) __attribute__((format(printf, 1, 2))); |
18 | int ui__warning(const char *format, ...) __attribute__((format(printf, 1, 2))); | 18 | int ui__warning(const char *format, ...) __attribute__((format(printf, 1, 2))); |
19 | 19 | ||
20 | void pr_stat(const char *fmt, ...); | ||
21 | |||
20 | #endif /* __PERF_DEBUG_H */ | 22 | #endif /* __PERF_DEBUG_H */ |
diff --git a/tools/perf/util/dso.c b/tools/perf/util/dso.c index af4c687cc49b..4045d086d9d9 100644 --- a/tools/perf/util/dso.c +++ b/tools/perf/util/dso.c | |||
@@ -28,8 +28,9 @@ char dso__symtab_origin(const struct dso *dso) | |||
28 | return origin[dso->symtab_type]; | 28 | return origin[dso->symtab_type]; |
29 | } | 29 | } |
30 | 30 | ||
31 | int dso__binary_type_file(struct dso *dso, enum dso_binary_type type, | 31 | int dso__read_binary_type_filename(const struct dso *dso, |
32 | char *root_dir, char *file, size_t size) | 32 | enum dso_binary_type type, |
33 | char *root_dir, char *filename, size_t size) | ||
33 | { | 34 | { |
34 | char build_id_hex[BUILD_ID_SIZE * 2 + 1]; | 35 | char build_id_hex[BUILD_ID_SIZE * 2 + 1]; |
35 | int ret = 0; | 36 | int ret = 0; |
@@ -38,36 +39,36 @@ int dso__binary_type_file(struct dso *dso, enum dso_binary_type type, | |||
38 | case DSO_BINARY_TYPE__DEBUGLINK: { | 39 | case DSO_BINARY_TYPE__DEBUGLINK: { |
39 | char *debuglink; | 40 | char *debuglink; |
40 | 41 | ||
41 | strncpy(file, dso->long_name, size); | 42 | strncpy(filename, dso->long_name, size); |
42 | debuglink = file + dso->long_name_len; | 43 | debuglink = filename + dso->long_name_len; |
43 | while (debuglink != file && *debuglink != '/') | 44 | while (debuglink != filename && *debuglink != '/') |
44 | debuglink--; | 45 | debuglink--; |
45 | if (*debuglink == '/') | 46 | if (*debuglink == '/') |
46 | debuglink++; | 47 | debuglink++; |
47 | filename__read_debuglink(dso->long_name, debuglink, | 48 | filename__read_debuglink(dso->long_name, debuglink, |
48 | size - (debuglink - file)); | 49 | size - (debuglink - filename)); |
49 | } | 50 | } |
50 | break; | 51 | break; |
51 | case DSO_BINARY_TYPE__BUILD_ID_CACHE: | 52 | case DSO_BINARY_TYPE__BUILD_ID_CACHE: |
52 | /* skip the locally configured cache if a symfs is given */ | 53 | /* skip the locally configured cache if a symfs is given */ |
53 | if (symbol_conf.symfs[0] || | 54 | if (symbol_conf.symfs[0] || |
54 | (dso__build_id_filename(dso, file, size) == NULL)) | 55 | (dso__build_id_filename(dso, filename, size) == NULL)) |
55 | ret = -1; | 56 | ret = -1; |
56 | break; | 57 | break; |
57 | 58 | ||
58 | case DSO_BINARY_TYPE__FEDORA_DEBUGINFO: | 59 | case DSO_BINARY_TYPE__FEDORA_DEBUGINFO: |
59 | snprintf(file, size, "%s/usr/lib/debug%s.debug", | 60 | snprintf(filename, size, "%s/usr/lib/debug%s.debug", |
60 | symbol_conf.symfs, dso->long_name); | 61 | symbol_conf.symfs, dso->long_name); |
61 | break; | 62 | break; |
62 | 63 | ||
63 | case DSO_BINARY_TYPE__UBUNTU_DEBUGINFO: | 64 | case DSO_BINARY_TYPE__UBUNTU_DEBUGINFO: |
64 | snprintf(file, size, "%s/usr/lib/debug%s", | 65 | snprintf(filename, size, "%s/usr/lib/debug%s", |
65 | symbol_conf.symfs, dso->long_name); | 66 | symbol_conf.symfs, dso->long_name); |
66 | break; | 67 | break; |
67 | 68 | ||
68 | case DSO_BINARY_TYPE__OPENEMBEDDED_DEBUGINFO: | 69 | case DSO_BINARY_TYPE__OPENEMBEDDED_DEBUGINFO: |
69 | { | 70 | { |
70 | char *last_slash; | 71 | const char *last_slash; |
71 | size_t len; | 72 | size_t len; |
72 | size_t dir_size; | 73 | size_t dir_size; |
73 | 74 | ||
@@ -75,14 +76,14 @@ int dso__binary_type_file(struct dso *dso, enum dso_binary_type type, | |||
75 | while (last_slash != dso->long_name && *last_slash != '/') | 76 | while (last_slash != dso->long_name && *last_slash != '/') |
76 | last_slash--; | 77 | last_slash--; |
77 | 78 | ||
78 | len = scnprintf(file, size, "%s", symbol_conf.symfs); | 79 | len = scnprintf(filename, size, "%s", symbol_conf.symfs); |
79 | dir_size = last_slash - dso->long_name + 2; | 80 | dir_size = last_slash - dso->long_name + 2; |
80 | if (dir_size > (size - len)) { | 81 | if (dir_size > (size - len)) { |
81 | ret = -1; | 82 | ret = -1; |
82 | break; | 83 | break; |
83 | } | 84 | } |
84 | len += scnprintf(file + len, dir_size, "%s", dso->long_name); | 85 | len += scnprintf(filename + len, dir_size, "%s", dso->long_name); |
85 | len += scnprintf(file + len , size - len, ".debug%s", | 86 | len += scnprintf(filename + len , size - len, ".debug%s", |
86 | last_slash); | 87 | last_slash); |
87 | break; | 88 | break; |
88 | } | 89 | } |
@@ -96,7 +97,7 @@ int dso__binary_type_file(struct dso *dso, enum dso_binary_type type, | |||
96 | build_id__sprintf(dso->build_id, | 97 | build_id__sprintf(dso->build_id, |
97 | sizeof(dso->build_id), | 98 | sizeof(dso->build_id), |
98 | build_id_hex); | 99 | build_id_hex); |
99 | snprintf(file, size, | 100 | snprintf(filename, size, |
100 | "%s/usr/lib/debug/.build-id/%.2s/%s.debug", | 101 | "%s/usr/lib/debug/.build-id/%.2s/%s.debug", |
101 | symbol_conf.symfs, build_id_hex, build_id_hex + 2); | 102 | symbol_conf.symfs, build_id_hex, build_id_hex + 2); |
102 | break; | 103 | break; |
@@ -104,23 +105,23 @@ int dso__binary_type_file(struct dso *dso, enum dso_binary_type type, | |||
104 | case DSO_BINARY_TYPE__VMLINUX: | 105 | case DSO_BINARY_TYPE__VMLINUX: |
105 | case DSO_BINARY_TYPE__GUEST_VMLINUX: | 106 | case DSO_BINARY_TYPE__GUEST_VMLINUX: |
106 | case DSO_BINARY_TYPE__SYSTEM_PATH_DSO: | 107 | case DSO_BINARY_TYPE__SYSTEM_PATH_DSO: |
107 | snprintf(file, size, "%s%s", | 108 | snprintf(filename, size, "%s%s", |
108 | symbol_conf.symfs, dso->long_name); | 109 | symbol_conf.symfs, dso->long_name); |
109 | break; | 110 | break; |
110 | 111 | ||
111 | case DSO_BINARY_TYPE__GUEST_KMODULE: | 112 | case DSO_BINARY_TYPE__GUEST_KMODULE: |
112 | snprintf(file, size, "%s%s%s", symbol_conf.symfs, | 113 | snprintf(filename, size, "%s%s%s", symbol_conf.symfs, |
113 | root_dir, dso->long_name); | 114 | root_dir, dso->long_name); |
114 | break; | 115 | break; |
115 | 116 | ||
116 | case DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE: | 117 | case DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE: |
117 | snprintf(file, size, "%s%s", symbol_conf.symfs, | 118 | snprintf(filename, size, "%s%s", symbol_conf.symfs, |
118 | dso->long_name); | 119 | dso->long_name); |
119 | break; | 120 | break; |
120 | 121 | ||
121 | case DSO_BINARY_TYPE__KCORE: | 122 | case DSO_BINARY_TYPE__KCORE: |
122 | case DSO_BINARY_TYPE__GUEST_KCORE: | 123 | case DSO_BINARY_TYPE__GUEST_KCORE: |
123 | snprintf(file, size, "%s", dso->long_name); | 124 | snprintf(filename, size, "%s", dso->long_name); |
124 | break; | 125 | break; |
125 | 126 | ||
126 | default: | 127 | default: |
@@ -137,19 +138,18 @@ int dso__binary_type_file(struct dso *dso, enum dso_binary_type type, | |||
137 | 138 | ||
138 | static int open_dso(struct dso *dso, struct machine *machine) | 139 | static int open_dso(struct dso *dso, struct machine *machine) |
139 | { | 140 | { |
140 | char *root_dir = (char *) ""; | ||
141 | char *name; | ||
142 | int fd; | 141 | int fd; |
142 | char *root_dir = (char *)""; | ||
143 | char *name = malloc(PATH_MAX); | ||
143 | 144 | ||
144 | name = malloc(PATH_MAX); | ||
145 | if (!name) | 145 | if (!name) |
146 | return -ENOMEM; | 146 | return -ENOMEM; |
147 | 147 | ||
148 | if (machine) | 148 | if (machine) |
149 | root_dir = machine->root_dir; | 149 | root_dir = machine->root_dir; |
150 | 150 | ||
151 | if (dso__binary_type_file(dso, dso->data_type, | 151 | if (dso__read_binary_type_filename(dso, dso->binary_type, |
152 | root_dir, name, PATH_MAX)) { | 152 | root_dir, name, PATH_MAX)) { |
153 | free(name); | 153 | free(name); |
154 | return -EINVAL; | 154 | return -EINVAL; |
155 | } | 155 | } |
@@ -161,26 +161,26 @@ static int open_dso(struct dso *dso, struct machine *machine) | |||
161 | 161 | ||
162 | int dso__data_fd(struct dso *dso, struct machine *machine) | 162 | int dso__data_fd(struct dso *dso, struct machine *machine) |
163 | { | 163 | { |
164 | static enum dso_binary_type binary_type_data[] = { | 164 | enum dso_binary_type binary_type_data[] = { |
165 | DSO_BINARY_TYPE__BUILD_ID_CACHE, | 165 | DSO_BINARY_TYPE__BUILD_ID_CACHE, |
166 | DSO_BINARY_TYPE__SYSTEM_PATH_DSO, | 166 | DSO_BINARY_TYPE__SYSTEM_PATH_DSO, |
167 | DSO_BINARY_TYPE__NOT_FOUND, | 167 | DSO_BINARY_TYPE__NOT_FOUND, |
168 | }; | 168 | }; |
169 | int i = 0; | 169 | int i = 0; |
170 | 170 | ||
171 | if (dso->data_type != DSO_BINARY_TYPE__NOT_FOUND) | 171 | if (dso->binary_type != DSO_BINARY_TYPE__NOT_FOUND) |
172 | return open_dso(dso, machine); | 172 | return open_dso(dso, machine); |
173 | 173 | ||
174 | do { | 174 | do { |
175 | int fd; | 175 | int fd; |
176 | 176 | ||
177 | dso->data_type = binary_type_data[i++]; | 177 | dso->binary_type = binary_type_data[i++]; |
178 | 178 | ||
179 | fd = open_dso(dso, machine); | 179 | fd = open_dso(dso, machine); |
180 | if (fd >= 0) | 180 | if (fd >= 0) |
181 | return fd; | 181 | return fd; |
182 | 182 | ||
183 | } while (dso->data_type != DSO_BINARY_TYPE__NOT_FOUND); | 183 | } while (dso->binary_type != DSO_BINARY_TYPE__NOT_FOUND); |
184 | 184 | ||
185 | return -EINVAL; | 185 | return -EINVAL; |
186 | } | 186 | } |
@@ -200,11 +200,10 @@ dso_cache__free(struct rb_root *root) | |||
200 | } | 200 | } |
201 | } | 201 | } |
202 | 202 | ||
203 | static struct dso_cache* | 203 | static struct dso_cache *dso_cache__find(const struct rb_root *root, u64 offset) |
204 | dso_cache__find(struct rb_root *root, u64 offset) | ||
205 | { | 204 | { |
206 | struct rb_node **p = &root->rb_node; | 205 | struct rb_node * const *p = &root->rb_node; |
207 | struct rb_node *parent = NULL; | 206 | const struct rb_node *parent = NULL; |
208 | struct dso_cache *cache; | 207 | struct dso_cache *cache; |
209 | 208 | ||
210 | while (*p != NULL) { | 209 | while (*p != NULL) { |
@@ -379,32 +378,63 @@ struct dso *dso__kernel_findnew(struct machine *machine, const char *name, | |||
379 | * processing we had no idea this was the kernel dso. | 378 | * processing we had no idea this was the kernel dso. |
380 | */ | 379 | */ |
381 | if (dso != NULL) { | 380 | if (dso != NULL) { |
382 | dso__set_short_name(dso, short_name); | 381 | dso__set_short_name(dso, short_name, false); |
383 | dso->kernel = dso_type; | 382 | dso->kernel = dso_type; |
384 | } | 383 | } |
385 | 384 | ||
386 | return dso; | 385 | return dso; |
387 | } | 386 | } |
388 | 387 | ||
389 | void dso__set_long_name(struct dso *dso, char *name) | 388 | void dso__set_long_name(struct dso *dso, const char *name, bool name_allocated) |
390 | { | 389 | { |
391 | if (name == NULL) | 390 | if (name == NULL) |
392 | return; | 391 | return; |
393 | dso->long_name = name; | 392 | |
394 | dso->long_name_len = strlen(name); | 393 | if (dso->long_name_allocated) |
394 | free((char *)dso->long_name); | ||
395 | |||
396 | dso->long_name = name; | ||
397 | dso->long_name_len = strlen(name); | ||
398 | dso->long_name_allocated = name_allocated; | ||
395 | } | 399 | } |
396 | 400 | ||
397 | void dso__set_short_name(struct dso *dso, const char *name) | 401 | void dso__set_short_name(struct dso *dso, const char *name, bool name_allocated) |
398 | { | 402 | { |
399 | if (name == NULL) | 403 | if (name == NULL) |
400 | return; | 404 | return; |
401 | dso->short_name = name; | 405 | |
402 | dso->short_name_len = strlen(name); | 406 | if (dso->short_name_allocated) |
407 | free((char *)dso->short_name); | ||
408 | |||
409 | dso->short_name = name; | ||
410 | dso->short_name_len = strlen(name); | ||
411 | dso->short_name_allocated = name_allocated; | ||
403 | } | 412 | } |
404 | 413 | ||
405 | static void dso__set_basename(struct dso *dso) | 414 | static void dso__set_basename(struct dso *dso) |
406 | { | 415 | { |
407 | dso__set_short_name(dso, basename(dso->long_name)); | 416 | /* |
417 | * basename() may modify path buffer, so we must pass | ||
418 | * a copy. | ||
419 | */ | ||
420 | char *base, *lname = strdup(dso->long_name); | ||
421 | |||
422 | if (!lname) | ||
423 | return; | ||
424 | |||
425 | /* | ||
426 | * basename() may return a pointer to internal | ||
427 | * storage which is reused in subsequent calls | ||
428 | * so copy the result. | ||
429 | */ | ||
430 | base = strdup(basename(lname)); | ||
431 | |||
432 | free(lname); | ||
433 | |||
434 | if (!base) | ||
435 | return; | ||
436 | |||
437 | dso__set_short_name(dso, base, true); | ||
408 | } | 438 | } |
409 | 439 | ||
410 | int dso__name_len(const struct dso *dso) | 440 | int dso__name_len(const struct dso *dso) |
@@ -439,18 +469,19 @@ struct dso *dso__new(const char *name) | |||
439 | if (dso != NULL) { | 469 | if (dso != NULL) { |
440 | int i; | 470 | int i; |
441 | strcpy(dso->name, name); | 471 | strcpy(dso->name, name); |
442 | dso__set_long_name(dso, dso->name); | 472 | dso__set_long_name(dso, dso->name, false); |
443 | dso__set_short_name(dso, dso->name); | 473 | dso__set_short_name(dso, dso->name, false); |
444 | for (i = 0; i < MAP__NR_TYPES; ++i) | 474 | for (i = 0; i < MAP__NR_TYPES; ++i) |
445 | dso->symbols[i] = dso->symbol_names[i] = RB_ROOT; | 475 | dso->symbols[i] = dso->symbol_names[i] = RB_ROOT; |
446 | dso->cache = RB_ROOT; | 476 | dso->cache = RB_ROOT; |
447 | dso->symtab_type = DSO_BINARY_TYPE__NOT_FOUND; | 477 | dso->symtab_type = DSO_BINARY_TYPE__NOT_FOUND; |
448 | dso->data_type = DSO_BINARY_TYPE__NOT_FOUND; | 478 | dso->binary_type = DSO_BINARY_TYPE__NOT_FOUND; |
449 | dso->loaded = 0; | 479 | dso->loaded = 0; |
450 | dso->rel = 0; | 480 | dso->rel = 0; |
451 | dso->sorted_by_name = 0; | 481 | dso->sorted_by_name = 0; |
452 | dso->has_build_id = 0; | 482 | dso->has_build_id = 0; |
453 | dso->has_srcline = 1; | 483 | dso->has_srcline = 1; |
484 | dso->a2l_fails = 1; | ||
454 | dso->kernel = DSO_TYPE_USER; | 485 | dso->kernel = DSO_TYPE_USER; |
455 | dso->needs_swap = DSO_SWAP__UNSET; | 486 | dso->needs_swap = DSO_SWAP__UNSET; |
456 | INIT_LIST_HEAD(&dso->node); | 487 | INIT_LIST_HEAD(&dso->node); |
@@ -464,11 +495,20 @@ void dso__delete(struct dso *dso) | |||
464 | int i; | 495 | int i; |
465 | for (i = 0; i < MAP__NR_TYPES; ++i) | 496 | for (i = 0; i < MAP__NR_TYPES; ++i) |
466 | symbols__delete(&dso->symbols[i]); | 497 | symbols__delete(&dso->symbols[i]); |
467 | if (dso->sname_alloc) | 498 | |
468 | free((char *)dso->short_name); | 499 | if (dso->short_name_allocated) { |
469 | if (dso->lname_alloc) | 500 | zfree((char **)&dso->short_name); |
470 | free(dso->long_name); | 501 | dso->short_name_allocated = false; |
502 | } | ||
503 | |||
504 | if (dso->long_name_allocated) { | ||
505 | zfree((char **)&dso->long_name); | ||
506 | dso->long_name_allocated = false; | ||
507 | } | ||
508 | |||
471 | dso_cache__free(&dso->cache); | 509 | dso_cache__free(&dso->cache); |
510 | dso__free_a2l(dso); | ||
511 | zfree(&dso->symsrc_filename); | ||
472 | free(dso); | 512 | free(dso); |
473 | } | 513 | } |
474 | 514 | ||
@@ -543,7 +583,7 @@ void dsos__add(struct list_head *head, struct dso *dso) | |||
543 | list_add_tail(&dso->node, head); | 583 | list_add_tail(&dso->node, head); |
544 | } | 584 | } |
545 | 585 | ||
546 | struct dso *dsos__find(struct list_head *head, const char *name, bool cmp_short) | 586 | struct dso *dsos__find(const struct list_head *head, const char *name, bool cmp_short) |
547 | { | 587 | { |
548 | struct dso *pos; | 588 | struct dso *pos; |
549 | 589 | ||
diff --git a/tools/perf/util/dso.h b/tools/perf/util/dso.h index 9ac666abbe7e..cd7d6f078cdd 100644 --- a/tools/perf/util/dso.h +++ b/tools/perf/util/dso.h | |||
@@ -77,23 +77,26 @@ struct dso { | |||
77 | struct rb_root symbols[MAP__NR_TYPES]; | 77 | struct rb_root symbols[MAP__NR_TYPES]; |
78 | struct rb_root symbol_names[MAP__NR_TYPES]; | 78 | struct rb_root symbol_names[MAP__NR_TYPES]; |
79 | struct rb_root cache; | 79 | struct rb_root cache; |
80 | void *a2l; | ||
81 | char *symsrc_filename; | ||
82 | unsigned int a2l_fails; | ||
80 | enum dso_kernel_type kernel; | 83 | enum dso_kernel_type kernel; |
81 | enum dso_swap_type needs_swap; | 84 | enum dso_swap_type needs_swap; |
82 | enum dso_binary_type symtab_type; | 85 | enum dso_binary_type symtab_type; |
83 | enum dso_binary_type data_type; | 86 | enum dso_binary_type binary_type; |
84 | u8 adjust_symbols:1; | 87 | u8 adjust_symbols:1; |
85 | u8 has_build_id:1; | 88 | u8 has_build_id:1; |
86 | u8 has_srcline:1; | 89 | u8 has_srcline:1; |
87 | u8 hit:1; | 90 | u8 hit:1; |
88 | u8 annotate_warned:1; | 91 | u8 annotate_warned:1; |
89 | u8 sname_alloc:1; | 92 | u8 short_name_allocated:1; |
90 | u8 lname_alloc:1; | 93 | u8 long_name_allocated:1; |
91 | u8 sorted_by_name; | 94 | u8 sorted_by_name; |
92 | u8 loaded; | 95 | u8 loaded; |
93 | u8 rel; | 96 | u8 rel; |
94 | u8 build_id[BUILD_ID_SIZE]; | 97 | u8 build_id[BUILD_ID_SIZE]; |
95 | const char *short_name; | 98 | const char *short_name; |
96 | char *long_name; | 99 | const char *long_name; |
97 | u16 long_name_len; | 100 | u16 long_name_len; |
98 | u16 short_name_len; | 101 | u16 short_name_len; |
99 | char name[0]; | 102 | char name[0]; |
@@ -107,8 +110,8 @@ static inline void dso__set_loaded(struct dso *dso, enum map_type type) | |||
107 | struct dso *dso__new(const char *name); | 110 | struct dso *dso__new(const char *name); |
108 | void dso__delete(struct dso *dso); | 111 | void dso__delete(struct dso *dso); |
109 | 112 | ||
110 | void dso__set_short_name(struct dso *dso, const char *name); | 113 | void dso__set_short_name(struct dso *dso, const char *name, bool name_allocated); |
111 | void dso__set_long_name(struct dso *dso, char *name); | 114 | void dso__set_long_name(struct dso *dso, const char *name, bool name_allocated); |
112 | 115 | ||
113 | int dso__name_len(const struct dso *dso); | 116 | int dso__name_len(const struct dso *dso); |
114 | 117 | ||
@@ -125,8 +128,8 @@ void dso__read_running_kernel_build_id(struct dso *dso, | |||
125 | int dso__kernel_module_get_build_id(struct dso *dso, const char *root_dir); | 128 | int dso__kernel_module_get_build_id(struct dso *dso, const char *root_dir); |
126 | 129 | ||
127 | char dso__symtab_origin(const struct dso *dso); | 130 | char dso__symtab_origin(const struct dso *dso); |
128 | int dso__binary_type_file(struct dso *dso, enum dso_binary_type type, | 131 | int dso__read_binary_type_filename(const struct dso *dso, enum dso_binary_type type, |
129 | char *root_dir, char *file, size_t size); | 132 | char *root_dir, char *filename, size_t size); |
130 | 133 | ||
131 | int dso__data_fd(struct dso *dso, struct machine *machine); | 134 | int dso__data_fd(struct dso *dso, struct machine *machine); |
132 | ssize_t dso__data_read_offset(struct dso *dso, struct machine *machine, | 135 | ssize_t dso__data_read_offset(struct dso *dso, struct machine *machine, |
@@ -140,7 +143,7 @@ struct dso *dso__kernel_findnew(struct machine *machine, const char *name, | |||
140 | const char *short_name, int dso_type); | 143 | const char *short_name, int dso_type); |
141 | 144 | ||
142 | void dsos__add(struct list_head *head, struct dso *dso); | 145 | void dsos__add(struct list_head *head, struct dso *dso); |
143 | struct dso *dsos__find(struct list_head *head, const char *name, | 146 | struct dso *dsos__find(const struct list_head *head, const char *name, |
144 | bool cmp_short); | 147 | bool cmp_short); |
145 | struct dso *__dsos__findnew(struct list_head *head, const char *name); | 148 | struct dso *__dsos__findnew(struct list_head *head, const char *name); |
146 | bool __dsos__read_build_ids(struct list_head *head, bool with_hits); | 149 | bool __dsos__read_build_ids(struct list_head *head, bool with_hits); |
@@ -156,14 +159,16 @@ size_t dso__fprintf(struct dso *dso, enum map_type type, FILE *fp); | |||
156 | 159 | ||
157 | static inline bool dso__is_vmlinux(struct dso *dso) | 160 | static inline bool dso__is_vmlinux(struct dso *dso) |
158 | { | 161 | { |
159 | return dso->data_type == DSO_BINARY_TYPE__VMLINUX || | 162 | return dso->binary_type == DSO_BINARY_TYPE__VMLINUX || |
160 | dso->data_type == DSO_BINARY_TYPE__GUEST_VMLINUX; | 163 | dso->binary_type == DSO_BINARY_TYPE__GUEST_VMLINUX; |
161 | } | 164 | } |
162 | 165 | ||
163 | static inline bool dso__is_kcore(struct dso *dso) | 166 | static inline bool dso__is_kcore(struct dso *dso) |
164 | { | 167 | { |
165 | return dso->data_type == DSO_BINARY_TYPE__KCORE || | 168 | return dso->binary_type == DSO_BINARY_TYPE__KCORE || |
166 | dso->data_type == DSO_BINARY_TYPE__GUEST_KCORE; | 169 | dso->binary_type == DSO_BINARY_TYPE__GUEST_KCORE; |
167 | } | 170 | } |
168 | 171 | ||
172 | void dso__free_a2l(struct dso *dso); | ||
173 | |||
169 | #endif /* __PERF_DSO */ | 174 | #endif /* __PERF_DSO */ |
diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c index bb788c109fe6..b0f3ca850e9e 100644 --- a/tools/perf/util/event.c +++ b/tools/perf/util/event.c | |||
@@ -7,6 +7,7 @@ | |||
7 | #include "strlist.h" | 7 | #include "strlist.h" |
8 | #include "thread.h" | 8 | #include "thread.h" |
9 | #include "thread_map.h" | 9 | #include "thread_map.h" |
10 | #include "symbol/kallsyms.h" | ||
10 | 11 | ||
11 | static const char *perf_event__names[] = { | 12 | static const char *perf_event__names[] = { |
12 | [0] = "TOTAL", | 13 | [0] = "TOTAL", |
@@ -105,8 +106,12 @@ static pid_t perf_event__synthesize_comm(struct perf_tool *tool, | |||
105 | 106 | ||
106 | memset(&event->comm, 0, sizeof(event->comm)); | 107 | memset(&event->comm, 0, sizeof(event->comm)); |
107 | 108 | ||
108 | tgid = perf_event__get_comm_tgid(pid, event->comm.comm, | 109 | if (machine__is_host(machine)) |
109 | sizeof(event->comm.comm)); | 110 | tgid = perf_event__get_comm_tgid(pid, event->comm.comm, |
111 | sizeof(event->comm.comm)); | ||
112 | else | ||
113 | tgid = machine->pid; | ||
114 | |||
110 | if (tgid < 0) | 115 | if (tgid < 0) |
111 | goto out; | 116 | goto out; |
112 | 117 | ||
@@ -128,7 +133,11 @@ static pid_t perf_event__synthesize_comm(struct perf_tool *tool, | |||
128 | goto out; | 133 | goto out; |
129 | } | 134 | } |
130 | 135 | ||
131 | snprintf(filename, sizeof(filename), "/proc/%d/task", pid); | 136 | if (machine__is_default_guest(machine)) |
137 | return 0; | ||
138 | |||
139 | snprintf(filename, sizeof(filename), "%s/proc/%d/task", | ||
140 | machine->root_dir, pid); | ||
132 | 141 | ||
133 | tasks = opendir(filename); | 142 | tasks = opendir(filename); |
134 | if (tasks == NULL) { | 143 | if (tasks == NULL) { |
@@ -166,18 +175,22 @@ out: | |||
166 | return tgid; | 175 | return tgid; |
167 | } | 176 | } |
168 | 177 | ||
169 | static int perf_event__synthesize_mmap_events(struct perf_tool *tool, | 178 | int perf_event__synthesize_mmap_events(struct perf_tool *tool, |
170 | union perf_event *event, | 179 | union perf_event *event, |
171 | pid_t pid, pid_t tgid, | 180 | pid_t pid, pid_t tgid, |
172 | perf_event__handler_t process, | 181 | perf_event__handler_t process, |
173 | struct machine *machine, | 182 | struct machine *machine, |
174 | bool mmap_data) | 183 | bool mmap_data) |
175 | { | 184 | { |
176 | char filename[PATH_MAX]; | 185 | char filename[PATH_MAX]; |
177 | FILE *fp; | 186 | FILE *fp; |
178 | int rc = 0; | 187 | int rc = 0; |
179 | 188 | ||
180 | snprintf(filename, sizeof(filename), "/proc/%d/maps", pid); | 189 | if (machine__is_default_guest(machine)) |
190 | return 0; | ||
191 | |||
192 | snprintf(filename, sizeof(filename), "%s/proc/%d/maps", | ||
193 | machine->root_dir, pid); | ||
181 | 194 | ||
182 | fp = fopen(filename, "r"); | 195 | fp = fopen(filename, "r"); |
183 | if (fp == NULL) { | 196 | if (fp == NULL) { |
@@ -217,7 +230,10 @@ static int perf_event__synthesize_mmap_events(struct perf_tool *tool, | |||
217 | /* | 230 | /* |
218 | * Just like the kernel, see __perf_event_mmap in kernel/perf_event.c | 231 | * Just like the kernel, see __perf_event_mmap in kernel/perf_event.c |
219 | */ | 232 | */ |
220 | event->header.misc = PERF_RECORD_MISC_USER; | 233 | if (machine__is_host(machine)) |
234 | event->header.misc = PERF_RECORD_MISC_USER; | ||
235 | else | ||
236 | event->header.misc = PERF_RECORD_MISC_GUEST_USER; | ||
221 | 237 | ||
222 | if (prot[2] != 'x') { | 238 | if (prot[2] != 'x') { |
223 | if (!mmap_data || prot[0] != 'r') | 239 | if (!mmap_data || prot[0] != 'r') |
@@ -386,6 +402,7 @@ int perf_event__synthesize_threads(struct perf_tool *tool, | |||
386 | struct machine *machine, bool mmap_data) | 402 | struct machine *machine, bool mmap_data) |
387 | { | 403 | { |
388 | DIR *proc; | 404 | DIR *proc; |
405 | char proc_path[PATH_MAX]; | ||
389 | struct dirent dirent, *next; | 406 | struct dirent dirent, *next; |
390 | union perf_event *comm_event, *mmap_event; | 407 | union perf_event *comm_event, *mmap_event; |
391 | int err = -1; | 408 | int err = -1; |
@@ -398,7 +415,12 @@ int perf_event__synthesize_threads(struct perf_tool *tool, | |||
398 | if (mmap_event == NULL) | 415 | if (mmap_event == NULL) |
399 | goto out_free_comm; | 416 | goto out_free_comm; |
400 | 417 | ||
401 | proc = opendir("/proc"); | 418 | if (machine__is_default_guest(machine)) |
419 | return 0; | ||
420 | |||
421 | snprintf(proc_path, sizeof(proc_path), "%s/proc", machine->root_dir); | ||
422 | proc = opendir(proc_path); | ||
423 | |||
402 | if (proc == NULL) | 424 | if (proc == NULL) |
403 | goto out_free_mmap; | 425 | goto out_free_mmap; |
404 | 426 | ||
@@ -448,23 +470,32 @@ static int find_symbol_cb(void *arg, const char *name, char type, | |||
448 | return 1; | 470 | return 1; |
449 | } | 471 | } |
450 | 472 | ||
473 | u64 kallsyms__get_function_start(const char *kallsyms_filename, | ||
474 | const char *symbol_name) | ||
475 | { | ||
476 | struct process_symbol_args args = { .name = symbol_name, }; | ||
477 | |||
478 | if (kallsyms__parse(kallsyms_filename, &args, find_symbol_cb) <= 0) | ||
479 | return 0; | ||
480 | |||
481 | return args.start; | ||
482 | } | ||
483 | |||
451 | int perf_event__synthesize_kernel_mmap(struct perf_tool *tool, | 484 | int perf_event__synthesize_kernel_mmap(struct perf_tool *tool, |
452 | perf_event__handler_t process, | 485 | perf_event__handler_t process, |
453 | struct machine *machine, | 486 | struct machine *machine) |
454 | const char *symbol_name) | ||
455 | { | 487 | { |
456 | size_t size; | 488 | size_t size; |
457 | const char *filename, *mmap_name; | 489 | const char *mmap_name; |
458 | char path[PATH_MAX]; | ||
459 | char name_buff[PATH_MAX]; | 490 | char name_buff[PATH_MAX]; |
460 | struct map *map; | 491 | struct map *map; |
492 | struct kmap *kmap; | ||
461 | int err; | 493 | int err; |
462 | /* | 494 | /* |
463 | * We should get this from /sys/kernel/sections/.text, but till that is | 495 | * We should get this from /sys/kernel/sections/.text, but till that is |
464 | * available use this, and after it is use this as a fallback for older | 496 | * available use this, and after it is use this as a fallback for older |
465 | * kernels. | 497 | * kernels. |
466 | */ | 498 | */ |
467 | struct process_symbol_args args = { .name = symbol_name, }; | ||
468 | union perf_event *event = zalloc((sizeof(event->mmap) + | 499 | union perf_event *event = zalloc((sizeof(event->mmap) + |
469 | machine->id_hdr_size)); | 500 | machine->id_hdr_size)); |
470 | if (event == NULL) { | 501 | if (event == NULL) { |
@@ -480,30 +511,19 @@ int perf_event__synthesize_kernel_mmap(struct perf_tool *tool, | |||
480 | * see kernel/perf_event.c __perf_event_mmap | 511 | * see kernel/perf_event.c __perf_event_mmap |
481 | */ | 512 | */ |
482 | event->header.misc = PERF_RECORD_MISC_KERNEL; | 513 | event->header.misc = PERF_RECORD_MISC_KERNEL; |
483 | filename = "/proc/kallsyms"; | ||
484 | } else { | 514 | } else { |
485 | event->header.misc = PERF_RECORD_MISC_GUEST_KERNEL; | 515 | event->header.misc = PERF_RECORD_MISC_GUEST_KERNEL; |
486 | if (machine__is_default_guest(machine)) | ||
487 | filename = (char *) symbol_conf.default_guest_kallsyms; | ||
488 | else { | ||
489 | sprintf(path, "%s/proc/kallsyms", machine->root_dir); | ||
490 | filename = path; | ||
491 | } | ||
492 | } | ||
493 | |||
494 | if (kallsyms__parse(filename, &args, find_symbol_cb) <= 0) { | ||
495 | free(event); | ||
496 | return -ENOENT; | ||
497 | } | 516 | } |
498 | 517 | ||
499 | map = machine->vmlinux_maps[MAP__FUNCTION]; | 518 | map = machine->vmlinux_maps[MAP__FUNCTION]; |
519 | kmap = map__kmap(map); | ||
500 | size = snprintf(event->mmap.filename, sizeof(event->mmap.filename), | 520 | size = snprintf(event->mmap.filename, sizeof(event->mmap.filename), |
501 | "%s%s", mmap_name, symbol_name) + 1; | 521 | "%s%s", mmap_name, kmap->ref_reloc_sym->name) + 1; |
502 | size = PERF_ALIGN(size, sizeof(u64)); | 522 | size = PERF_ALIGN(size, sizeof(u64)); |
503 | event->mmap.header.type = PERF_RECORD_MMAP; | 523 | event->mmap.header.type = PERF_RECORD_MMAP; |
504 | event->mmap.header.size = (sizeof(event->mmap) - | 524 | event->mmap.header.size = (sizeof(event->mmap) - |
505 | (sizeof(event->mmap.filename) - size) + machine->id_hdr_size); | 525 | (sizeof(event->mmap.filename) - size) + machine->id_hdr_size); |
506 | event->mmap.pgoff = args.start; | 526 | event->mmap.pgoff = kmap->ref_reloc_sym->addr; |
507 | event->mmap.start = map->start; | 527 | event->mmap.start = map->start; |
508 | event->mmap.len = map->end - event->mmap.start; | 528 | event->mmap.len = map->end - event->mmap.start; |
509 | event->mmap.pid = machine->pid; | 529 | event->mmap.pid = machine->pid; |
@@ -637,6 +657,7 @@ void thread__find_addr_map(struct thread *thread, | |||
637 | struct map_groups *mg = &thread->mg; | 657 | struct map_groups *mg = &thread->mg; |
638 | bool load_map = false; | 658 | bool load_map = false; |
639 | 659 | ||
660 | al->machine = machine; | ||
640 | al->thread = thread; | 661 | al->thread = thread; |
641 | al->addr = addr; | 662 | al->addr = addr; |
642 | al->cpumode = cpumode; | 663 | al->cpumode = cpumode; |
@@ -657,15 +678,10 @@ void thread__find_addr_map(struct thread *thread, | |||
657 | al->level = 'g'; | 678 | al->level = 'g'; |
658 | mg = &machine->kmaps; | 679 | mg = &machine->kmaps; |
659 | load_map = true; | 680 | load_map = true; |
681 | } else if (cpumode == PERF_RECORD_MISC_GUEST_USER && perf_guest) { | ||
682 | al->level = 'u'; | ||
660 | } else { | 683 | } else { |
661 | /* | 684 | al->level = 'H'; |
662 | * 'u' means guest os user space. | ||
663 | * TODO: We don't support guest user space. Might support late. | ||
664 | */ | ||
665 | if (cpumode == PERF_RECORD_MISC_GUEST_USER && perf_guest) | ||
666 | al->level = 'u'; | ||
667 | else | ||
668 | al->level = 'H'; | ||
669 | al->map = NULL; | 685 | al->map = NULL; |
670 | 686 | ||
671 | if ((cpumode == PERF_RECORD_MISC_GUEST_USER || | 687 | if ((cpumode == PERF_RECORD_MISC_GUEST_USER || |
@@ -732,8 +748,7 @@ int perf_event__preprocess_sample(const union perf_event *event, | |||
732 | if (thread == NULL) | 748 | if (thread == NULL) |
733 | return -1; | 749 | return -1; |
734 | 750 | ||
735 | if (symbol_conf.comm_list && | 751 | if (thread__is_filtered(thread)) |
736 | !strlist__has_entry(symbol_conf.comm_list, thread__comm_str(thread))) | ||
737 | goto out_filtered; | 752 | goto out_filtered; |
738 | 753 | ||
739 | dump_printf(" ... thread: %s:%d\n", thread__comm_str(thread), thread->tid); | 754 | dump_printf(" ... thread: %s:%d\n", thread__comm_str(thread), thread->tid); |
diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h index 30fec9901e44..851fa06f4a42 100644 --- a/tools/perf/util/event.h +++ b/tools/perf/util/event.h | |||
@@ -214,8 +214,7 @@ int perf_event__synthesize_threads(struct perf_tool *tool, | |||
214 | struct machine *machine, bool mmap_data); | 214 | struct machine *machine, bool mmap_data); |
215 | int perf_event__synthesize_kernel_mmap(struct perf_tool *tool, | 215 | int perf_event__synthesize_kernel_mmap(struct perf_tool *tool, |
216 | perf_event__handler_t process, | 216 | perf_event__handler_t process, |
217 | struct machine *machine, | 217 | struct machine *machine); |
218 | const char *symbol_name); | ||
219 | 218 | ||
220 | int perf_event__synthesize_modules(struct perf_tool *tool, | 219 | int perf_event__synthesize_modules(struct perf_tool *tool, |
221 | perf_event__handler_t process, | 220 | perf_event__handler_t process, |
@@ -266,10 +265,20 @@ int perf_event__synthesize_sample(union perf_event *event, u64 type, | |||
266 | const struct perf_sample *sample, | 265 | const struct perf_sample *sample, |
267 | bool swapped); | 266 | bool swapped); |
268 | 267 | ||
268 | int perf_event__synthesize_mmap_events(struct perf_tool *tool, | ||
269 | union perf_event *event, | ||
270 | pid_t pid, pid_t tgid, | ||
271 | perf_event__handler_t process, | ||
272 | struct machine *machine, | ||
273 | bool mmap_data); | ||
274 | |||
269 | size_t perf_event__fprintf_comm(union perf_event *event, FILE *fp); | 275 | size_t perf_event__fprintf_comm(union perf_event *event, FILE *fp); |
270 | size_t perf_event__fprintf_mmap(union perf_event *event, FILE *fp); | 276 | size_t perf_event__fprintf_mmap(union perf_event *event, FILE *fp); |
271 | size_t perf_event__fprintf_mmap2(union perf_event *event, FILE *fp); | 277 | size_t perf_event__fprintf_mmap2(union perf_event *event, FILE *fp); |
272 | size_t perf_event__fprintf_task(union perf_event *event, FILE *fp); | 278 | size_t perf_event__fprintf_task(union perf_event *event, FILE *fp); |
273 | size_t perf_event__fprintf(union perf_event *event, FILE *fp); | 279 | size_t perf_event__fprintf(union perf_event *event, FILE *fp); |
274 | 280 | ||
281 | u64 kallsyms__get_function_start(const char *kallsyms_filename, | ||
282 | const char *symbol_name); | ||
283 | |||
275 | #endif /* __PERF_RECORD_H */ | 284 | #endif /* __PERF_RECORD_H */ |
diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c index bbc746aa5716..59ef2802fcf6 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 <lk/debugfs.h> | 10 | #include <api/fs/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" |
@@ -81,7 +81,7 @@ static void perf_evlist__update_id_pos(struct perf_evlist *evlist) | |||
81 | { | 81 | { |
82 | struct perf_evsel *evsel; | 82 | struct perf_evsel *evsel; |
83 | 83 | ||
84 | list_for_each_entry(evsel, &evlist->entries, node) | 84 | evlist__for_each(evlist, evsel) |
85 | perf_evsel__calc_id_pos(evsel); | 85 | perf_evsel__calc_id_pos(evsel); |
86 | 86 | ||
87 | perf_evlist__set_id_pos(evlist); | 87 | perf_evlist__set_id_pos(evlist); |
@@ -91,7 +91,7 @@ static void perf_evlist__purge(struct perf_evlist *evlist) | |||
91 | { | 91 | { |
92 | struct perf_evsel *pos, *n; | 92 | struct perf_evsel *pos, *n; |
93 | 93 | ||
94 | list_for_each_entry_safe(pos, n, &evlist->entries, node) { | 94 | evlist__for_each_safe(evlist, n, pos) { |
95 | list_del_init(&pos->node); | 95 | list_del_init(&pos->node); |
96 | perf_evsel__delete(pos); | 96 | perf_evsel__delete(pos); |
97 | } | 97 | } |
@@ -101,14 +101,18 @@ static void perf_evlist__purge(struct perf_evlist *evlist) | |||
101 | 101 | ||
102 | void perf_evlist__exit(struct perf_evlist *evlist) | 102 | void perf_evlist__exit(struct perf_evlist *evlist) |
103 | { | 103 | { |
104 | free(evlist->mmap); | 104 | zfree(&evlist->mmap); |
105 | free(evlist->pollfd); | 105 | zfree(&evlist->pollfd); |
106 | evlist->mmap = NULL; | ||
107 | evlist->pollfd = NULL; | ||
108 | } | 106 | } |
109 | 107 | ||
110 | void perf_evlist__delete(struct perf_evlist *evlist) | 108 | void perf_evlist__delete(struct perf_evlist *evlist) |
111 | { | 109 | { |
110 | perf_evlist__munmap(evlist); | ||
111 | perf_evlist__close(evlist); | ||
112 | cpu_map__delete(evlist->cpus); | ||
113 | thread_map__delete(evlist->threads); | ||
114 | evlist->cpus = NULL; | ||
115 | evlist->threads = NULL; | ||
112 | perf_evlist__purge(evlist); | 116 | perf_evlist__purge(evlist); |
113 | perf_evlist__exit(evlist); | 117 | perf_evlist__exit(evlist); |
114 | free(evlist); | 118 | free(evlist); |
@@ -144,7 +148,7 @@ void __perf_evlist__set_leader(struct list_head *list) | |||
144 | 148 | ||
145 | leader->nr_members = evsel->idx - leader->idx + 1; | 149 | leader->nr_members = evsel->idx - leader->idx + 1; |
146 | 150 | ||
147 | list_for_each_entry(evsel, list, node) { | 151 | __evlist__for_each(list, evsel) { |
148 | evsel->leader = leader; | 152 | evsel->leader = leader; |
149 | } | 153 | } |
150 | } | 154 | } |
@@ -203,7 +207,7 @@ static int perf_evlist__add_attrs(struct perf_evlist *evlist, | |||
203 | return 0; | 207 | return 0; |
204 | 208 | ||
205 | out_delete_partial_list: | 209 | out_delete_partial_list: |
206 | list_for_each_entry_safe(evsel, n, &head, node) | 210 | __evlist__for_each_safe(&head, n, evsel) |
207 | perf_evsel__delete(evsel); | 211 | perf_evsel__delete(evsel); |
208 | return -1; | 212 | return -1; |
209 | } | 213 | } |
@@ -224,7 +228,7 @@ perf_evlist__find_tracepoint_by_id(struct perf_evlist *evlist, int id) | |||
224 | { | 228 | { |
225 | struct perf_evsel *evsel; | 229 | struct perf_evsel *evsel; |
226 | 230 | ||
227 | list_for_each_entry(evsel, &evlist->entries, node) { | 231 | evlist__for_each(evlist, evsel) { |
228 | if (evsel->attr.type == PERF_TYPE_TRACEPOINT && | 232 | if (evsel->attr.type == PERF_TYPE_TRACEPOINT && |
229 | (int)evsel->attr.config == id) | 233 | (int)evsel->attr.config == id) |
230 | return evsel; | 234 | return evsel; |
@@ -239,7 +243,7 @@ perf_evlist__find_tracepoint_by_name(struct perf_evlist *evlist, | |||
239 | { | 243 | { |
240 | struct perf_evsel *evsel; | 244 | struct perf_evsel *evsel; |
241 | 245 | ||
242 | list_for_each_entry(evsel, &evlist->entries, node) { | 246 | evlist__for_each(evlist, evsel) { |
243 | if ((evsel->attr.type == PERF_TYPE_TRACEPOINT) && | 247 | if ((evsel->attr.type == PERF_TYPE_TRACEPOINT) && |
244 | (strcmp(evsel->name, name) == 0)) | 248 | (strcmp(evsel->name, name) == 0)) |
245 | return evsel; | 249 | return evsel; |
@@ -269,7 +273,7 @@ void perf_evlist__disable(struct perf_evlist *evlist) | |||
269 | int nr_threads = thread_map__nr(evlist->threads); | 273 | int nr_threads = thread_map__nr(evlist->threads); |
270 | 274 | ||
271 | for (cpu = 0; cpu < nr_cpus; cpu++) { | 275 | for (cpu = 0; cpu < nr_cpus; cpu++) { |
272 | list_for_each_entry(pos, &evlist->entries, node) { | 276 | evlist__for_each(evlist, pos) { |
273 | if (!perf_evsel__is_group_leader(pos) || !pos->fd) | 277 | if (!perf_evsel__is_group_leader(pos) || !pos->fd) |
274 | continue; | 278 | continue; |
275 | for (thread = 0; thread < nr_threads; thread++) | 279 | for (thread = 0; thread < nr_threads; thread++) |
@@ -287,7 +291,7 @@ void perf_evlist__enable(struct perf_evlist *evlist) | |||
287 | int nr_threads = thread_map__nr(evlist->threads); | 291 | int nr_threads = thread_map__nr(evlist->threads); |
288 | 292 | ||
289 | for (cpu = 0; cpu < nr_cpus; cpu++) { | 293 | for (cpu = 0; cpu < nr_cpus; cpu++) { |
290 | list_for_each_entry(pos, &evlist->entries, node) { | 294 | evlist__for_each(evlist, pos) { |
291 | if (!perf_evsel__is_group_leader(pos) || !pos->fd) | 295 | if (!perf_evsel__is_group_leader(pos) || !pos->fd) |
292 | continue; | 296 | continue; |
293 | for (thread = 0; thread < nr_threads; thread++) | 297 | for (thread = 0; thread < nr_threads; thread++) |
@@ -584,11 +588,13 @@ void perf_evlist__munmap(struct perf_evlist *evlist) | |||
584 | { | 588 | { |
585 | int i; | 589 | int i; |
586 | 590 | ||
591 | if (evlist->mmap == NULL) | ||
592 | return; | ||
593 | |||
587 | for (i = 0; i < evlist->nr_mmaps; i++) | 594 | for (i = 0; i < evlist->nr_mmaps; i++) |
588 | __perf_evlist__munmap(evlist, i); | 595 | __perf_evlist__munmap(evlist, i); |
589 | 596 | ||
590 | free(evlist->mmap); | 597 | zfree(&evlist->mmap); |
591 | evlist->mmap = NULL; | ||
592 | } | 598 | } |
593 | 599 | ||
594 | static int perf_evlist__alloc_mmap(struct perf_evlist *evlist) | 600 | static int perf_evlist__alloc_mmap(struct perf_evlist *evlist) |
@@ -624,7 +630,7 @@ static int perf_evlist__mmap_per_evsel(struct perf_evlist *evlist, int idx, | |||
624 | { | 630 | { |
625 | struct perf_evsel *evsel; | 631 | struct perf_evsel *evsel; |
626 | 632 | ||
627 | list_for_each_entry(evsel, &evlist->entries, node) { | 633 | evlist__for_each(evlist, evsel) { |
628 | int fd = FD(evsel, cpu, thread); | 634 | int fd = FD(evsel, cpu, thread); |
629 | 635 | ||
630 | if (*output == -1) { | 636 | if (*output == -1) { |
@@ -732,11 +738,13 @@ static long parse_pages_arg(const char *str, unsigned long min, | |||
732 | return -EINVAL; | 738 | return -EINVAL; |
733 | } | 739 | } |
734 | 740 | ||
735 | if ((pages == 0) && (min == 0)) { | 741 | if (pages == 0 && min == 0) { |
736 | /* leave number of pages at 0 */ | 742 | /* leave number of pages at 0 */ |
737 | } else if (pages < (1UL << 31) && !is_power_of_2(pages)) { | 743 | } else if (!is_power_of_2(pages)) { |
738 | /* round pages up to next power of 2 */ | 744 | /* round pages up to next power of 2 */ |
739 | pages = next_pow2(pages); | 745 | pages = next_pow2_l(pages); |
746 | if (!pages) | ||
747 | return -EINVAL; | ||
740 | pr_info("rounding mmap pages size to %lu bytes (%lu pages)\n", | 748 | pr_info("rounding mmap pages size to %lu bytes (%lu pages)\n", |
741 | pages * page_size, pages); | 749 | pages * page_size, pages); |
742 | } | 750 | } |
@@ -754,7 +762,7 @@ int perf_evlist__parse_mmap_pages(const struct option *opt, const char *str, | |||
754 | unsigned long max = UINT_MAX; | 762 | unsigned long max = UINT_MAX; |
755 | long pages; | 763 | long pages; |
756 | 764 | ||
757 | if (max < SIZE_MAX / page_size) | 765 | if (max > SIZE_MAX / page_size) |
758 | max = SIZE_MAX / page_size; | 766 | max = SIZE_MAX / page_size; |
759 | 767 | ||
760 | pages = parse_pages_arg(str, 1, max); | 768 | pages = parse_pages_arg(str, 1, max); |
@@ -798,7 +806,7 @@ int perf_evlist__mmap(struct perf_evlist *evlist, unsigned int pages, | |||
798 | pr_debug("mmap size %zuB\n", evlist->mmap_len); | 806 | pr_debug("mmap size %zuB\n", evlist->mmap_len); |
799 | mask = evlist->mmap_len - page_size - 1; | 807 | mask = evlist->mmap_len - page_size - 1; |
800 | 808 | ||
801 | list_for_each_entry(evsel, &evlist->entries, node) { | 809 | evlist__for_each(evlist, evsel) { |
802 | if ((evsel->attr.read_format & PERF_FORMAT_ID) && | 810 | if ((evsel->attr.read_format & PERF_FORMAT_ID) && |
803 | evsel->sample_id == NULL && | 811 | evsel->sample_id == NULL && |
804 | perf_evsel__alloc_id(evsel, cpu_map__nr(cpus), threads->nr) < 0) | 812 | perf_evsel__alloc_id(evsel, cpu_map__nr(cpus), threads->nr) < 0) |
@@ -819,11 +827,7 @@ int perf_evlist__create_maps(struct perf_evlist *evlist, struct target *target) | |||
819 | if (evlist->threads == NULL) | 827 | if (evlist->threads == NULL) |
820 | return -1; | 828 | return -1; |
821 | 829 | ||
822 | if (target->force_per_cpu) | 830 | if (target__uses_dummy_map(target)) |
823 | evlist->cpus = cpu_map__new(target->cpu_list); | ||
824 | else if (target__has_task(target)) | ||
825 | evlist->cpus = cpu_map__dummy_new(); | ||
826 | else if (!target__has_cpu(target) && !target->uses_mmap) | ||
827 | evlist->cpus = cpu_map__dummy_new(); | 831 | evlist->cpus = cpu_map__dummy_new(); |
828 | else | 832 | else |
829 | evlist->cpus = cpu_map__new(target->cpu_list); | 833 | evlist->cpus = cpu_map__new(target->cpu_list); |
@@ -838,14 +842,6 @@ out_delete_threads: | |||
838 | return -1; | 842 | return -1; |
839 | } | 843 | } |
840 | 844 | ||
841 | void perf_evlist__delete_maps(struct perf_evlist *evlist) | ||
842 | { | ||
843 | cpu_map__delete(evlist->cpus); | ||
844 | thread_map__delete(evlist->threads); | ||
845 | evlist->cpus = NULL; | ||
846 | evlist->threads = NULL; | ||
847 | } | ||
848 | |||
849 | int perf_evlist__apply_filters(struct perf_evlist *evlist) | 845 | int perf_evlist__apply_filters(struct perf_evlist *evlist) |
850 | { | 846 | { |
851 | struct perf_evsel *evsel; | 847 | struct perf_evsel *evsel; |
@@ -853,7 +849,7 @@ int perf_evlist__apply_filters(struct perf_evlist *evlist) | |||
853 | const int ncpus = cpu_map__nr(evlist->cpus), | 849 | const int ncpus = cpu_map__nr(evlist->cpus), |
854 | nthreads = thread_map__nr(evlist->threads); | 850 | nthreads = thread_map__nr(evlist->threads); |
855 | 851 | ||
856 | list_for_each_entry(evsel, &evlist->entries, node) { | 852 | evlist__for_each(evlist, evsel) { |
857 | if (evsel->filter == NULL) | 853 | if (evsel->filter == NULL) |
858 | continue; | 854 | continue; |
859 | 855 | ||
@@ -872,7 +868,7 @@ int perf_evlist__set_filter(struct perf_evlist *evlist, const char *filter) | |||
872 | const int ncpus = cpu_map__nr(evlist->cpus), | 868 | const int ncpus = cpu_map__nr(evlist->cpus), |
873 | nthreads = thread_map__nr(evlist->threads); | 869 | nthreads = thread_map__nr(evlist->threads); |
874 | 870 | ||
875 | list_for_each_entry(evsel, &evlist->entries, node) { | 871 | evlist__for_each(evlist, evsel) { |
876 | err = perf_evsel__set_filter(evsel, ncpus, nthreads, filter); | 872 | err = perf_evsel__set_filter(evsel, ncpus, nthreads, filter); |
877 | if (err) | 873 | if (err) |
878 | break; | 874 | break; |
@@ -891,7 +887,7 @@ bool perf_evlist__valid_sample_type(struct perf_evlist *evlist) | |||
891 | if (evlist->id_pos < 0 || evlist->is_pos < 0) | 887 | if (evlist->id_pos < 0 || evlist->is_pos < 0) |
892 | return false; | 888 | return false; |
893 | 889 | ||
894 | list_for_each_entry(pos, &evlist->entries, node) { | 890 | evlist__for_each(evlist, pos) { |
895 | if (pos->id_pos != evlist->id_pos || | 891 | if (pos->id_pos != evlist->id_pos || |
896 | pos->is_pos != evlist->is_pos) | 892 | pos->is_pos != evlist->is_pos) |
897 | return false; | 893 | return false; |
@@ -907,7 +903,7 @@ u64 __perf_evlist__combined_sample_type(struct perf_evlist *evlist) | |||
907 | if (evlist->combined_sample_type) | 903 | if (evlist->combined_sample_type) |
908 | return evlist->combined_sample_type; | 904 | return evlist->combined_sample_type; |
909 | 905 | ||
910 | list_for_each_entry(evsel, &evlist->entries, node) | 906 | evlist__for_each(evlist, evsel) |
911 | evlist->combined_sample_type |= evsel->attr.sample_type; | 907 | evlist->combined_sample_type |= evsel->attr.sample_type; |
912 | 908 | ||
913 | return evlist->combined_sample_type; | 909 | return evlist->combined_sample_type; |
@@ -925,7 +921,7 @@ bool perf_evlist__valid_read_format(struct perf_evlist *evlist) | |||
925 | u64 read_format = first->attr.read_format; | 921 | u64 read_format = first->attr.read_format; |
926 | u64 sample_type = first->attr.sample_type; | 922 | u64 sample_type = first->attr.sample_type; |
927 | 923 | ||
928 | list_for_each_entry_continue(pos, &evlist->entries, node) { | 924 | evlist__for_each(evlist, pos) { |
929 | if (read_format != pos->attr.read_format) | 925 | if (read_format != pos->attr.read_format) |
930 | return false; | 926 | return false; |
931 | } | 927 | } |
@@ -982,7 +978,7 @@ bool perf_evlist__valid_sample_id_all(struct perf_evlist *evlist) | |||
982 | { | 978 | { |
983 | struct perf_evsel *first = perf_evlist__first(evlist), *pos = first; | 979 | struct perf_evsel *first = perf_evlist__first(evlist), *pos = first; |
984 | 980 | ||
985 | list_for_each_entry_continue(pos, &evlist->entries, node) { | 981 | evlist__for_each_continue(evlist, pos) { |
986 | if (first->attr.sample_id_all != pos->attr.sample_id_all) | 982 | if (first->attr.sample_id_all != pos->attr.sample_id_all) |
987 | return false; | 983 | return false; |
988 | } | 984 | } |
@@ -1007,9 +1003,12 @@ void perf_evlist__close(struct perf_evlist *evlist) | |||
1007 | struct perf_evsel *evsel; | 1003 | struct perf_evsel *evsel; |
1008 | int ncpus = cpu_map__nr(evlist->cpus); | 1004 | int ncpus = cpu_map__nr(evlist->cpus); |
1009 | int nthreads = thread_map__nr(evlist->threads); | 1005 | int nthreads = thread_map__nr(evlist->threads); |
1006 | int n; | ||
1010 | 1007 | ||
1011 | list_for_each_entry_reverse(evsel, &evlist->entries, node) | 1008 | evlist__for_each_reverse(evlist, evsel) { |
1012 | perf_evsel__close(evsel, ncpus, nthreads); | 1009 | n = evsel->cpus ? evsel->cpus->nr : ncpus; |
1010 | perf_evsel__close(evsel, n, nthreads); | ||
1011 | } | ||
1013 | } | 1012 | } |
1014 | 1013 | ||
1015 | int perf_evlist__open(struct perf_evlist *evlist) | 1014 | int perf_evlist__open(struct perf_evlist *evlist) |
@@ -1019,7 +1018,7 @@ int perf_evlist__open(struct perf_evlist *evlist) | |||
1019 | 1018 | ||
1020 | perf_evlist__update_id_pos(evlist); | 1019 | perf_evlist__update_id_pos(evlist); |
1021 | 1020 | ||
1022 | list_for_each_entry(evsel, &evlist->entries, node) { | 1021 | evlist__for_each(evlist, evsel) { |
1023 | err = perf_evsel__open(evsel, evlist->cpus, evlist->threads); | 1022 | err = perf_evsel__open(evsel, evlist->cpus, evlist->threads); |
1024 | if (err < 0) | 1023 | if (err < 0) |
1025 | goto out_err; | 1024 | goto out_err; |
@@ -1034,7 +1033,7 @@ out_err: | |||
1034 | 1033 | ||
1035 | int perf_evlist__prepare_workload(struct perf_evlist *evlist, struct target *target, | 1034 | int perf_evlist__prepare_workload(struct perf_evlist *evlist, struct target *target, |
1036 | const char *argv[], bool pipe_output, | 1035 | const char *argv[], bool pipe_output, |
1037 | bool want_signal) | 1036 | void (*exec_error)(int signo, siginfo_t *info, void *ucontext)) |
1038 | { | 1037 | { |
1039 | int child_ready_pipe[2], go_pipe[2]; | 1038 | int child_ready_pipe[2], go_pipe[2]; |
1040 | char bf; | 1039 | char bf; |
@@ -1078,12 +1077,25 @@ int perf_evlist__prepare_workload(struct perf_evlist *evlist, struct target *tar | |||
1078 | 1077 | ||
1079 | execvp(argv[0], (char **)argv); | 1078 | execvp(argv[0], (char **)argv); |
1080 | 1079 | ||
1081 | perror(argv[0]); | 1080 | if (exec_error) { |
1082 | if (want_signal) | 1081 | union sigval val; |
1083 | kill(getppid(), SIGUSR1); | 1082 | |
1083 | val.sival_int = errno; | ||
1084 | if (sigqueue(getppid(), SIGUSR1, val)) | ||
1085 | perror(argv[0]); | ||
1086 | } else | ||
1087 | perror(argv[0]); | ||
1084 | exit(-1); | 1088 | exit(-1); |
1085 | } | 1089 | } |
1086 | 1090 | ||
1091 | if (exec_error) { | ||
1092 | struct sigaction act = { | ||
1093 | .sa_flags = SA_SIGINFO, | ||
1094 | .sa_sigaction = exec_error, | ||
1095 | }; | ||
1096 | sigaction(SIGUSR1, &act, NULL); | ||
1097 | } | ||
1098 | |||
1087 | if (target__none(target)) | 1099 | if (target__none(target)) |
1088 | evlist->threads->map[0] = evlist->workload.pid; | 1100 | evlist->threads->map[0] = evlist->workload.pid; |
1089 | 1101 | ||
@@ -1145,7 +1157,7 @@ size_t perf_evlist__fprintf(struct perf_evlist *evlist, FILE *fp) | |||
1145 | struct perf_evsel *evsel; | 1157 | struct perf_evsel *evsel; |
1146 | size_t printed = 0; | 1158 | size_t printed = 0; |
1147 | 1159 | ||
1148 | list_for_each_entry(evsel, &evlist->entries, node) { | 1160 | evlist__for_each(evlist, evsel) { |
1149 | printed += fprintf(fp, "%s%s", evsel->idx ? ", " : "", | 1161 | printed += fprintf(fp, "%s%s", evsel->idx ? ", " : "", |
1150 | perf_evsel__name(evsel)); | 1162 | perf_evsel__name(evsel)); |
1151 | } | 1163 | } |
@@ -1193,8 +1205,7 @@ int perf_evlist__strerror_open(struct perf_evlist *evlist __maybe_unused, | |||
1193 | "Error:\t%s.\n" | 1205 | "Error:\t%s.\n" |
1194 | "Hint:\tCheck /proc/sys/kernel/perf_event_paranoid setting.", emsg); | 1206 | "Hint:\tCheck /proc/sys/kernel/perf_event_paranoid setting.", emsg); |
1195 | 1207 | ||
1196 | if (filename__read_int("/proc/sys/kernel/perf_event_paranoid", &value)) | 1208 | value = perf_event_paranoid(); |
1197 | break; | ||
1198 | 1209 | ||
1199 | printed += scnprintf(buf + printed, size - printed, "\nHint:\t"); | 1210 | printed += scnprintf(buf + printed, size - printed, "\nHint:\t"); |
1200 | 1211 | ||
@@ -1215,3 +1226,20 @@ int perf_evlist__strerror_open(struct perf_evlist *evlist __maybe_unused, | |||
1215 | 1226 | ||
1216 | return 0; | 1227 | return 0; |
1217 | } | 1228 | } |
1229 | |||
1230 | void perf_evlist__to_front(struct perf_evlist *evlist, | ||
1231 | struct perf_evsel *move_evsel) | ||
1232 | { | ||
1233 | struct perf_evsel *evsel, *n; | ||
1234 | LIST_HEAD(move); | ||
1235 | |||
1236 | if (move_evsel == perf_evlist__first(evlist)) | ||
1237 | return; | ||
1238 | |||
1239 | evlist__for_each_safe(evlist, n, evsel) { | ||
1240 | if (evsel->leader == move_evsel->leader) | ||
1241 | list_move_tail(&evsel->node, &move); | ||
1242 | } | ||
1243 | |||
1244 | list_splice(&move, &evlist->entries); | ||
1245 | } | ||
diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h index 649d6ea98a84..f5173cd63693 100644 --- a/tools/perf/util/evlist.h +++ b/tools/perf/util/evlist.h | |||
@@ -12,7 +12,7 @@ | |||
12 | struct pollfd; | 12 | struct pollfd; |
13 | struct thread_map; | 13 | struct thread_map; |
14 | struct cpu_map; | 14 | struct cpu_map; |
15 | struct perf_record_opts; | 15 | struct record_opts; |
16 | 16 | ||
17 | #define PERF_EVLIST__HLIST_BITS 8 | 17 | #define PERF_EVLIST__HLIST_BITS 8 |
18 | #define PERF_EVLIST__HLIST_SIZE (1 << PERF_EVLIST__HLIST_BITS) | 18 | #define PERF_EVLIST__HLIST_SIZE (1 << PERF_EVLIST__HLIST_BITS) |
@@ -97,14 +97,14 @@ void perf_evlist__close(struct perf_evlist *evlist); | |||
97 | 97 | ||
98 | void perf_evlist__set_id_pos(struct perf_evlist *evlist); | 98 | void perf_evlist__set_id_pos(struct perf_evlist *evlist); |
99 | bool perf_can_sample_identifier(void); | 99 | bool perf_can_sample_identifier(void); |
100 | void perf_evlist__config(struct perf_evlist *evlist, | 100 | void perf_evlist__config(struct perf_evlist *evlist, struct record_opts *opts); |
101 | struct perf_record_opts *opts); | 101 | int record_opts__config(struct record_opts *opts); |
102 | int perf_record_opts__config(struct perf_record_opts *opts); | ||
103 | 102 | ||
104 | int perf_evlist__prepare_workload(struct perf_evlist *evlist, | 103 | int perf_evlist__prepare_workload(struct perf_evlist *evlist, |
105 | struct target *target, | 104 | struct target *target, |
106 | const char *argv[], bool pipe_output, | 105 | const char *argv[], bool pipe_output, |
107 | bool want_signal); | 106 | void (*exec_error)(int signo, siginfo_t *info, |
107 | void *ucontext)); | ||
108 | int perf_evlist__start_workload(struct perf_evlist *evlist); | 108 | int perf_evlist__start_workload(struct perf_evlist *evlist); |
109 | 109 | ||
110 | int perf_evlist__parse_mmap_pages(const struct option *opt, | 110 | int perf_evlist__parse_mmap_pages(const struct option *opt, |
@@ -135,7 +135,6 @@ static inline void perf_evlist__set_maps(struct perf_evlist *evlist, | |||
135 | } | 135 | } |
136 | 136 | ||
137 | int perf_evlist__create_maps(struct perf_evlist *evlist, struct target *target); | 137 | int perf_evlist__create_maps(struct perf_evlist *evlist, struct target *target); |
138 | void perf_evlist__delete_maps(struct perf_evlist *evlist); | ||
139 | int perf_evlist__apply_filters(struct perf_evlist *evlist); | 138 | int perf_evlist__apply_filters(struct perf_evlist *evlist); |
140 | 139 | ||
141 | void __perf_evlist__set_leader(struct list_head *list); | 140 | void __perf_evlist__set_leader(struct list_head *list); |
@@ -193,4 +192,74 @@ static inline void perf_mmap__write_tail(struct perf_mmap *md, | |||
193 | pc->data_tail = tail; | 192 | pc->data_tail = tail; |
194 | } | 193 | } |
195 | 194 | ||
195 | bool perf_evlist__can_select_event(struct perf_evlist *evlist, const char *str); | ||
196 | void perf_evlist__to_front(struct perf_evlist *evlist, | ||
197 | struct perf_evsel *move_evsel); | ||
198 | |||
199 | /** | ||
200 | * __evlist__for_each - iterate thru all the evsels | ||
201 | * @list: list_head instance to iterate | ||
202 | * @evsel: struct evsel iterator | ||
203 | */ | ||
204 | #define __evlist__for_each(list, evsel) \ | ||
205 | list_for_each_entry(evsel, list, node) | ||
206 | |||
207 | /** | ||
208 | * evlist__for_each - iterate thru all the evsels | ||
209 | * @evlist: evlist instance to iterate | ||
210 | * @evsel: struct evsel iterator | ||
211 | */ | ||
212 | #define evlist__for_each(evlist, evsel) \ | ||
213 | __evlist__for_each(&(evlist)->entries, evsel) | ||
214 | |||
215 | /** | ||
216 | * __evlist__for_each_continue - continue iteration thru all the evsels | ||
217 | * @list: list_head instance to iterate | ||
218 | * @evsel: struct evsel iterator | ||
219 | */ | ||
220 | #define __evlist__for_each_continue(list, evsel) \ | ||
221 | list_for_each_entry_continue(evsel, list, node) | ||
222 | |||
223 | /** | ||
224 | * evlist__for_each_continue - continue iteration thru all the evsels | ||
225 | * @evlist: evlist instance to iterate | ||
226 | * @evsel: struct evsel iterator | ||
227 | */ | ||
228 | #define evlist__for_each_continue(evlist, evsel) \ | ||
229 | __evlist__for_each_continue(&(evlist)->entries, evsel) | ||
230 | |||
231 | /** | ||
232 | * __evlist__for_each_reverse - iterate thru all the evsels in reverse order | ||
233 | * @list: list_head instance to iterate | ||
234 | * @evsel: struct evsel iterator | ||
235 | */ | ||
236 | #define __evlist__for_each_reverse(list, evsel) \ | ||
237 | list_for_each_entry_reverse(evsel, list, node) | ||
238 | |||
239 | /** | ||
240 | * evlist__for_each_reverse - iterate thru all the evsels in reverse order | ||
241 | * @evlist: evlist instance to iterate | ||
242 | * @evsel: struct evsel iterator | ||
243 | */ | ||
244 | #define evlist__for_each_reverse(evlist, evsel) \ | ||
245 | __evlist__for_each_reverse(&(evlist)->entries, evsel) | ||
246 | |||
247 | /** | ||
248 | * __evlist__for_each_safe - safely iterate thru all the evsels | ||
249 | * @list: list_head instance to iterate | ||
250 | * @tmp: struct evsel temp iterator | ||
251 | * @evsel: struct evsel iterator | ||
252 | */ | ||
253 | #define __evlist__for_each_safe(list, tmp, evsel) \ | ||
254 | list_for_each_entry_safe(evsel, tmp, list, node) | ||
255 | |||
256 | /** | ||
257 | * evlist__for_each_safe - safely iterate thru all the evsels | ||
258 | * @evlist: evlist instance to iterate | ||
259 | * @evsel: struct evsel iterator | ||
260 | * @tmp: struct evsel temp iterator | ||
261 | */ | ||
262 | #define evlist__for_each_safe(evlist, tmp, evsel) \ | ||
263 | __evlist__for_each_safe(&(evlist)->entries, tmp, evsel) | ||
264 | |||
196 | #endif /* __PERF_EVLIST_H */ | 265 | #endif /* __PERF_EVLIST_H */ |
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index 46dd4c2a41ce..55407c594b87 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c | |||
@@ -9,7 +9,7 @@ | |||
9 | 9 | ||
10 | #include <byteswap.h> | 10 | #include <byteswap.h> |
11 | #include <linux/bitops.h> | 11 | #include <linux/bitops.h> |
12 | #include <lk/debugfs.h> | 12 | #include <api/fs/debugfs.h> |
13 | #include <traceevent/event-parse.h> | 13 | #include <traceevent/event-parse.h> |
14 | #include <linux/hw_breakpoint.h> | 14 | #include <linux/hw_breakpoint.h> |
15 | #include <linux/perf_event.h> | 15 | #include <linux/perf_event.h> |
@@ -23,6 +23,7 @@ | |||
23 | #include "target.h" | 23 | #include "target.h" |
24 | #include "perf_regs.h" | 24 | #include "perf_regs.h" |
25 | #include "debug.h" | 25 | #include "debug.h" |
26 | #include "trace-event.h" | ||
26 | 27 | ||
27 | static struct { | 28 | static struct { |
28 | bool sample_id_all; | 29 | bool sample_id_all; |
@@ -162,6 +163,8 @@ void perf_evsel__init(struct perf_evsel *evsel, | |||
162 | evsel->idx = idx; | 163 | evsel->idx = idx; |
163 | evsel->attr = *attr; | 164 | evsel->attr = *attr; |
164 | evsel->leader = evsel; | 165 | evsel->leader = evsel; |
166 | evsel->unit = ""; | ||
167 | evsel->scale = 1.0; | ||
165 | INIT_LIST_HEAD(&evsel->node); | 168 | INIT_LIST_HEAD(&evsel->node); |
166 | hists__init(&evsel->hists); | 169 | hists__init(&evsel->hists); |
167 | evsel->sample_size = __perf_evsel__sample_size(attr->sample_type); | 170 | evsel->sample_size = __perf_evsel__sample_size(attr->sample_type); |
@@ -178,47 +181,6 @@ struct perf_evsel *perf_evsel__new_idx(struct perf_event_attr *attr, int idx) | |||
178 | return evsel; | 181 | return evsel; |
179 | } | 182 | } |
180 | 183 | ||
181 | struct event_format *event_format__new(const char *sys, const char *name) | ||
182 | { | ||
183 | int fd, n; | ||
184 | char *filename; | ||
185 | void *bf = NULL, *nbf; | ||
186 | size_t size = 0, alloc_size = 0; | ||
187 | struct event_format *format = NULL; | ||
188 | |||
189 | if (asprintf(&filename, "%s/%s/%s/format", tracing_events_path, sys, name) < 0) | ||
190 | goto out; | ||
191 | |||
192 | fd = open(filename, O_RDONLY); | ||
193 | if (fd < 0) | ||
194 | goto out_free_filename; | ||
195 | |||
196 | do { | ||
197 | if (size == alloc_size) { | ||
198 | alloc_size += BUFSIZ; | ||
199 | nbf = realloc(bf, alloc_size); | ||
200 | if (nbf == NULL) | ||
201 | goto out_free_bf; | ||
202 | bf = nbf; | ||
203 | } | ||
204 | |||
205 | n = read(fd, bf + size, alloc_size - size); | ||
206 | if (n < 0) | ||
207 | goto out_free_bf; | ||
208 | size += n; | ||
209 | } while (n > 0); | ||
210 | |||
211 | pevent_parse_format(&format, bf, size, sys); | ||
212 | |||
213 | out_free_bf: | ||
214 | free(bf); | ||
215 | close(fd); | ||
216 | out_free_filename: | ||
217 | free(filename); | ||
218 | out: | ||
219 | return format; | ||
220 | } | ||
221 | |||
222 | struct perf_evsel *perf_evsel__newtp_idx(const char *sys, const char *name, int idx) | 184 | struct perf_evsel *perf_evsel__newtp_idx(const char *sys, const char *name, int idx) |
223 | { | 185 | { |
224 | struct perf_evsel *evsel = zalloc(sizeof(*evsel)); | 186 | struct perf_evsel *evsel = zalloc(sizeof(*evsel)); |
@@ -233,7 +195,7 @@ struct perf_evsel *perf_evsel__newtp_idx(const char *sys, const char *name, int | |||
233 | if (asprintf(&evsel->name, "%s:%s", sys, name) < 0) | 195 | if (asprintf(&evsel->name, "%s:%s", sys, name) < 0) |
234 | goto out_free; | 196 | goto out_free; |
235 | 197 | ||
236 | evsel->tp_format = event_format__new(sys, name); | 198 | evsel->tp_format = trace_event__tp_format(sys, name); |
237 | if (evsel->tp_format == NULL) | 199 | if (evsel->tp_format == NULL) |
238 | goto out_free; | 200 | goto out_free; |
239 | 201 | ||
@@ -246,7 +208,7 @@ struct perf_evsel *perf_evsel__newtp_idx(const char *sys, const char *name, int | |||
246 | return evsel; | 208 | return evsel; |
247 | 209 | ||
248 | out_free: | 210 | out_free: |
249 | free(evsel->name); | 211 | zfree(&evsel->name); |
250 | free(evsel); | 212 | free(evsel); |
251 | return NULL; | 213 | return NULL; |
252 | } | 214 | } |
@@ -566,12 +528,12 @@ int perf_evsel__group_desc(struct perf_evsel *evsel, char *buf, size_t size) | |||
566 | * enable/disable events specifically, as there's no | 528 | * enable/disable events specifically, as there's no |
567 | * initial traced exec call. | 529 | * initial traced exec call. |
568 | */ | 530 | */ |
569 | void perf_evsel__config(struct perf_evsel *evsel, | 531 | void perf_evsel__config(struct perf_evsel *evsel, struct record_opts *opts) |
570 | struct perf_record_opts *opts) | ||
571 | { | 532 | { |
572 | struct perf_evsel *leader = evsel->leader; | 533 | struct perf_evsel *leader = evsel->leader; |
573 | struct perf_event_attr *attr = &evsel->attr; | 534 | struct perf_event_attr *attr = &evsel->attr; |
574 | int track = !evsel->idx; /* only the first counter needs these */ | 535 | int track = !evsel->idx; /* only the first counter needs these */ |
536 | bool per_cpu = opts->target.default_per_cpu && !opts->target.per_thread; | ||
575 | 537 | ||
576 | attr->sample_id_all = perf_missing_features.sample_id_all ? 0 : 1; | 538 | attr->sample_id_all = perf_missing_features.sample_id_all ? 0 : 1; |
577 | attr->inherit = !opts->no_inherit; | 539 | attr->inherit = !opts->no_inherit; |
@@ -645,7 +607,7 @@ void perf_evsel__config(struct perf_evsel *evsel, | |||
645 | } | 607 | } |
646 | } | 608 | } |
647 | 609 | ||
648 | if (target__has_cpu(&opts->target) || opts->target.force_per_cpu) | 610 | if (target__has_cpu(&opts->target)) |
649 | perf_evsel__set_sample_bit(evsel, CPU); | 611 | perf_evsel__set_sample_bit(evsel, CPU); |
650 | 612 | ||
651 | if (opts->period) | 613 | if (opts->period) |
@@ -653,7 +615,7 @@ void perf_evsel__config(struct perf_evsel *evsel, | |||
653 | 615 | ||
654 | if (!perf_missing_features.sample_id_all && | 616 | if (!perf_missing_features.sample_id_all && |
655 | (opts->sample_time || !opts->no_inherit || | 617 | (opts->sample_time || !opts->no_inherit || |
656 | target__has_cpu(&opts->target) || opts->target.force_per_cpu)) | 618 | target__has_cpu(&opts->target) || per_cpu)) |
657 | perf_evsel__set_sample_bit(evsel, TIME); | 619 | perf_evsel__set_sample_bit(evsel, TIME); |
658 | 620 | ||
659 | if (opts->raw_samples) { | 621 | if (opts->raw_samples) { |
@@ -665,7 +627,7 @@ void perf_evsel__config(struct perf_evsel *evsel, | |||
665 | if (opts->sample_address) | 627 | if (opts->sample_address) |
666 | perf_evsel__set_sample_bit(evsel, DATA_SRC); | 628 | perf_evsel__set_sample_bit(evsel, DATA_SRC); |
667 | 629 | ||
668 | if (opts->no_delay) { | 630 | if (opts->no_buffering) { |
669 | attr->watermark = 0; | 631 | attr->watermark = 0; |
670 | attr->wakeup_events = 1; | 632 | attr->wakeup_events = 1; |
671 | } | 633 | } |
@@ -696,7 +658,8 @@ void perf_evsel__config(struct perf_evsel *evsel, | |||
696 | * Setting enable_on_exec for independent events and | 658 | * Setting enable_on_exec for independent events and |
697 | * group leaders for traced executed by perf. | 659 | * group leaders for traced executed by perf. |
698 | */ | 660 | */ |
699 | if (target__none(&opts->target) && perf_evsel__is_group_leader(evsel)) | 661 | if (target__none(&opts->target) && perf_evsel__is_group_leader(evsel) && |
662 | !opts->initial_delay) | ||
700 | attr->enable_on_exec = 1; | 663 | attr->enable_on_exec = 1; |
701 | } | 664 | } |
702 | 665 | ||
@@ -788,8 +751,7 @@ void perf_evsel__free_id(struct perf_evsel *evsel) | |||
788 | { | 751 | { |
789 | xyarray__delete(evsel->sample_id); | 752 | xyarray__delete(evsel->sample_id); |
790 | evsel->sample_id = NULL; | 753 | evsel->sample_id = NULL; |
791 | free(evsel->id); | 754 | zfree(&evsel->id); |
792 | evsel->id = NULL; | ||
793 | } | 755 | } |
794 | 756 | ||
795 | void perf_evsel__close_fd(struct perf_evsel *evsel, int ncpus, int nthreads) | 757 | void perf_evsel__close_fd(struct perf_evsel *evsel, int ncpus, int nthreads) |
@@ -805,7 +767,7 @@ void perf_evsel__close_fd(struct perf_evsel *evsel, int ncpus, int nthreads) | |||
805 | 767 | ||
806 | void perf_evsel__free_counts(struct perf_evsel *evsel) | 768 | void perf_evsel__free_counts(struct perf_evsel *evsel) |
807 | { | 769 | { |
808 | free(evsel->counts); | 770 | zfree(&evsel->counts); |
809 | } | 771 | } |
810 | 772 | ||
811 | void perf_evsel__exit(struct perf_evsel *evsel) | 773 | void perf_evsel__exit(struct perf_evsel *evsel) |
@@ -819,10 +781,10 @@ void perf_evsel__delete(struct perf_evsel *evsel) | |||
819 | { | 781 | { |
820 | perf_evsel__exit(evsel); | 782 | perf_evsel__exit(evsel); |
821 | close_cgroup(evsel->cgrp); | 783 | close_cgroup(evsel->cgrp); |
822 | free(evsel->group_name); | 784 | zfree(&evsel->group_name); |
823 | if (evsel->tp_format) | 785 | if (evsel->tp_format) |
824 | pevent_free_format(evsel->tp_format); | 786 | pevent_free_format(evsel->tp_format); |
825 | free(evsel->name); | 787 | zfree(&evsel->name); |
826 | free(evsel); | 788 | free(evsel); |
827 | } | 789 | } |
828 | 790 | ||
@@ -1119,7 +1081,6 @@ void perf_evsel__close(struct perf_evsel *evsel, int ncpus, int nthreads) | |||
1119 | 1081 | ||
1120 | perf_evsel__close_fd(evsel, ncpus, nthreads); | 1082 | perf_evsel__close_fd(evsel, ncpus, nthreads); |
1121 | perf_evsel__free_fd(evsel); | 1083 | perf_evsel__free_fd(evsel); |
1122 | evsel->fd = NULL; | ||
1123 | } | 1084 | } |
1124 | 1085 | ||
1125 | static struct { | 1086 | static struct { |
@@ -1998,8 +1959,7 @@ bool perf_evsel__fallback(struct perf_evsel *evsel, int err, | |||
1998 | evsel->attr.type = PERF_TYPE_SOFTWARE; | 1959 | evsel->attr.type = PERF_TYPE_SOFTWARE; |
1999 | evsel->attr.config = PERF_COUNT_SW_CPU_CLOCK; | 1960 | evsel->attr.config = PERF_COUNT_SW_CPU_CLOCK; |
2000 | 1961 | ||
2001 | free(evsel->name); | 1962 | zfree(&evsel->name); |
2002 | evsel->name = NULL; | ||
2003 | return true; | 1963 | return true; |
2004 | } | 1964 | } |
2005 | 1965 | ||
diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h index 1ea7c92e6e33..f1b325665aae 100644 --- a/tools/perf/util/evsel.h +++ b/tools/perf/util/evsel.h | |||
@@ -68,6 +68,8 @@ struct perf_evsel { | |||
68 | u32 ids; | 68 | u32 ids; |
69 | struct hists hists; | 69 | struct hists hists; |
70 | char *name; | 70 | char *name; |
71 | double scale; | ||
72 | const char *unit; | ||
71 | struct event_format *tp_format; | 73 | struct event_format *tp_format; |
72 | union { | 74 | union { |
73 | void *priv; | 75 | void *priv; |
@@ -94,7 +96,7 @@ struct perf_evsel { | |||
94 | struct cpu_map; | 96 | struct cpu_map; |
95 | struct thread_map; | 97 | struct thread_map; |
96 | struct perf_evlist; | 98 | struct perf_evlist; |
97 | struct perf_record_opts; | 99 | struct record_opts; |
98 | 100 | ||
99 | struct perf_evsel *perf_evsel__new_idx(struct perf_event_attr *attr, int idx); | 101 | struct perf_evsel *perf_evsel__new_idx(struct perf_event_attr *attr, int idx); |
100 | 102 | ||
@@ -118,7 +120,7 @@ void perf_evsel__exit(struct perf_evsel *evsel); | |||
118 | void perf_evsel__delete(struct perf_evsel *evsel); | 120 | void perf_evsel__delete(struct perf_evsel *evsel); |
119 | 121 | ||
120 | void perf_evsel__config(struct perf_evsel *evsel, | 122 | void perf_evsel__config(struct perf_evsel *evsel, |
121 | struct perf_record_opts *opts); | 123 | struct record_opts *opts); |
122 | 124 | ||
123 | int __perf_evsel__sample_size(u64 sample_type); | 125 | int __perf_evsel__sample_size(u64 sample_type); |
124 | void perf_evsel__calc_id_pos(struct perf_evsel *evsel); | 126 | void perf_evsel__calc_id_pos(struct perf_evsel *evsel); |
@@ -138,6 +140,7 @@ extern const char *perf_evsel__sw_names[PERF_COUNT_SW_MAX]; | |||
138 | int __perf_evsel__hw_cache_type_op_res_name(u8 type, u8 op, u8 result, | 140 | int __perf_evsel__hw_cache_type_op_res_name(u8 type, u8 op, u8 result, |
139 | char *bf, size_t size); | 141 | char *bf, size_t size); |
140 | const char *perf_evsel__name(struct perf_evsel *evsel); | 142 | const char *perf_evsel__name(struct perf_evsel *evsel); |
143 | |||
141 | const char *perf_evsel__group_name(struct perf_evsel *evsel); | 144 | const char *perf_evsel__group_name(struct perf_evsel *evsel); |
142 | int perf_evsel__group_desc(struct perf_evsel *evsel, char *buf, size_t size); | 145 | int perf_evsel__group_desc(struct perf_evsel *evsel, char *buf, size_t size); |
143 | 146 | ||
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index 1cd035708931..893f8e2df928 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c | |||
@@ -177,7 +177,7 @@ perf_header__set_cmdline(int argc, const char **argv) | |||
177 | continue; \ | 177 | continue; \ |
178 | else | 178 | else |
179 | 179 | ||
180 | static int write_buildid(char *name, size_t name_len, u8 *build_id, | 180 | static int write_buildid(const char *name, size_t name_len, u8 *build_id, |
181 | pid_t pid, u16 misc, int fd) | 181 | pid_t pid, u16 misc, int fd) |
182 | { | 182 | { |
183 | int err; | 183 | int err; |
@@ -209,7 +209,7 @@ static int __dsos__write_buildid_table(struct list_head *head, | |||
209 | 209 | ||
210 | dsos__for_each_with_build_id(pos, head) { | 210 | dsos__for_each_with_build_id(pos, head) { |
211 | int err; | 211 | int err; |
212 | char *name; | 212 | const char *name; |
213 | size_t name_len; | 213 | size_t name_len; |
214 | 214 | ||
215 | if (!pos->hit) | 215 | if (!pos->hit) |
@@ -387,7 +387,7 @@ static int dso__cache_build_id(struct dso *dso, struct machine *machine, | |||
387 | { | 387 | { |
388 | bool is_kallsyms = dso->kernel && dso->long_name[0] != '/'; | 388 | bool is_kallsyms = dso->kernel && dso->long_name[0] != '/'; |
389 | bool is_vdso = is_vdso_map(dso->short_name); | 389 | bool is_vdso = is_vdso_map(dso->short_name); |
390 | char *name = dso->long_name; | 390 | const char *name = dso->long_name; |
391 | char nm[PATH_MAX]; | 391 | char nm[PATH_MAX]; |
392 | 392 | ||
393 | if (dso__is_kcore(dso)) { | 393 | if (dso__is_kcore(dso)) { |
@@ -643,8 +643,7 @@ static int write_event_desc(int fd, struct perf_header *h __maybe_unused, | |||
643 | if (ret < 0) | 643 | if (ret < 0) |
644 | return ret; | 644 | return ret; |
645 | 645 | ||
646 | list_for_each_entry(evsel, &evlist->entries, node) { | 646 | evlist__for_each(evlist, evsel) { |
647 | |||
648 | ret = do_write(fd, &evsel->attr, sz); | 647 | ret = do_write(fd, &evsel->attr, sz); |
649 | if (ret < 0) | 648 | if (ret < 0) |
650 | return ret; | 649 | return ret; |
@@ -800,10 +799,10 @@ static void free_cpu_topo(struct cpu_topo *tp) | |||
800 | return; | 799 | return; |
801 | 800 | ||
802 | for (i = 0 ; i < tp->core_sib; i++) | 801 | for (i = 0 ; i < tp->core_sib; i++) |
803 | free(tp->core_siblings[i]); | 802 | zfree(&tp->core_siblings[i]); |
804 | 803 | ||
805 | for (i = 0 ; i < tp->thread_sib; i++) | 804 | for (i = 0 ; i < tp->thread_sib; i++) |
806 | free(tp->thread_siblings[i]); | 805 | zfree(&tp->thread_siblings[i]); |
807 | 806 | ||
808 | free(tp); | 807 | free(tp); |
809 | } | 808 | } |
@@ -931,7 +930,7 @@ static int write_topo_node(int fd, int node) | |||
931 | /* skip over invalid lines */ | 930 | /* skip over invalid lines */ |
932 | if (!strchr(buf, ':')) | 931 | if (!strchr(buf, ':')) |
933 | continue; | 932 | continue; |
934 | if (sscanf(buf, "%*s %*d %s %"PRIu64, field, &mem) != 2) | 933 | if (sscanf(buf, "%*s %*d %31s %"PRIu64, field, &mem) != 2) |
935 | goto done; | 934 | goto done; |
936 | if (!strcmp(field, "MemTotal:")) | 935 | if (!strcmp(field, "MemTotal:")) |
937 | mem_total = mem; | 936 | mem_total = mem; |
@@ -1092,7 +1091,7 @@ static int write_group_desc(int fd, struct perf_header *h __maybe_unused, | |||
1092 | if (ret < 0) | 1091 | if (ret < 0) |
1093 | return ret; | 1092 | return ret; |
1094 | 1093 | ||
1095 | list_for_each_entry(evsel, &evlist->entries, node) { | 1094 | evlist__for_each(evlist, evsel) { |
1096 | if (perf_evsel__is_group_leader(evsel) && | 1095 | if (perf_evsel__is_group_leader(evsel) && |
1097 | evsel->nr_members > 1) { | 1096 | evsel->nr_members > 1) { |
1098 | const char *name = evsel->group_name ?: "{anon_group}"; | 1097 | const char *name = evsel->group_name ?: "{anon_group}"; |
@@ -1232,10 +1231,8 @@ static void free_event_desc(struct perf_evsel *events) | |||
1232 | return; | 1231 | return; |
1233 | 1232 | ||
1234 | for (evsel = events; evsel->attr.size; evsel++) { | 1233 | for (evsel = events; evsel->attr.size; evsel++) { |
1235 | if (evsel->name) | 1234 | zfree(&evsel->name); |
1236 | free(evsel->name); | 1235 | zfree(&evsel->id); |
1237 | if (evsel->id) | ||
1238 | free(evsel->id); | ||
1239 | } | 1236 | } |
1240 | 1237 | ||
1241 | free(events); | 1238 | free(events); |
@@ -1326,8 +1323,7 @@ read_event_desc(struct perf_header *ph, int fd) | |||
1326 | } | 1323 | } |
1327 | } | 1324 | } |
1328 | out: | 1325 | out: |
1329 | if (buf) | 1326 | free(buf); |
1330 | free(buf); | ||
1331 | return events; | 1327 | return events; |
1332 | error: | 1328 | error: |
1333 | if (events) | 1329 | if (events) |
@@ -1490,7 +1486,7 @@ static void print_group_desc(struct perf_header *ph, int fd __maybe_unused, | |||
1490 | 1486 | ||
1491 | session = container_of(ph, struct perf_session, header); | 1487 | session = container_of(ph, struct perf_session, header); |
1492 | 1488 | ||
1493 | list_for_each_entry(evsel, &session->evlist->entries, node) { | 1489 | evlist__for_each(session->evlist, evsel) { |
1494 | if (perf_evsel__is_group_leader(evsel) && | 1490 | if (perf_evsel__is_group_leader(evsel) && |
1495 | evsel->nr_members > 1) { | 1491 | evsel->nr_members > 1) { |
1496 | fprintf(fp, "# group: %s{%s", evsel->group_name ?: "", | 1492 | fprintf(fp, "# group: %s{%s", evsel->group_name ?: "", |
@@ -1709,7 +1705,7 @@ static int process_nrcpus(struct perf_file_section *section __maybe_unused, | |||
1709 | struct perf_header *ph, int fd, | 1705 | struct perf_header *ph, int fd, |
1710 | void *data __maybe_unused) | 1706 | void *data __maybe_unused) |
1711 | { | 1707 | { |
1712 | size_t ret; | 1708 | ssize_t ret; |
1713 | u32 nr; | 1709 | u32 nr; |
1714 | 1710 | ||
1715 | ret = readn(fd, &nr, sizeof(nr)); | 1711 | ret = readn(fd, &nr, sizeof(nr)); |
@@ -1753,7 +1749,7 @@ static int process_total_mem(struct perf_file_section *section __maybe_unused, | |||
1753 | void *data __maybe_unused) | 1749 | void *data __maybe_unused) |
1754 | { | 1750 | { |
1755 | uint64_t mem; | 1751 | uint64_t mem; |
1756 | size_t ret; | 1752 | ssize_t ret; |
1757 | 1753 | ||
1758 | ret = readn(fd, &mem, sizeof(mem)); | 1754 | ret = readn(fd, &mem, sizeof(mem)); |
1759 | if (ret != sizeof(mem)) | 1755 | if (ret != sizeof(mem)) |
@@ -1771,7 +1767,7 @@ perf_evlist__find_by_index(struct perf_evlist *evlist, int idx) | |||
1771 | { | 1767 | { |
1772 | struct perf_evsel *evsel; | 1768 | struct perf_evsel *evsel; |
1773 | 1769 | ||
1774 | list_for_each_entry(evsel, &evlist->entries, node) { | 1770 | evlist__for_each(evlist, evsel) { |
1775 | if (evsel->idx == idx) | 1771 | if (evsel->idx == idx) |
1776 | return evsel; | 1772 | return evsel; |
1777 | } | 1773 | } |
@@ -1822,7 +1818,7 @@ static int process_cmdline(struct perf_file_section *section __maybe_unused, | |||
1822 | struct perf_header *ph, int fd, | 1818 | struct perf_header *ph, int fd, |
1823 | void *data __maybe_unused) | 1819 | void *data __maybe_unused) |
1824 | { | 1820 | { |
1825 | size_t ret; | 1821 | ssize_t ret; |
1826 | char *str; | 1822 | char *str; |
1827 | u32 nr, i; | 1823 | u32 nr, i; |
1828 | struct strbuf sb; | 1824 | struct strbuf sb; |
@@ -1858,7 +1854,7 @@ static int process_cpu_topology(struct perf_file_section *section __maybe_unused | |||
1858 | struct perf_header *ph, int fd, | 1854 | struct perf_header *ph, int fd, |
1859 | void *data __maybe_unused) | 1855 | void *data __maybe_unused) |
1860 | { | 1856 | { |
1861 | size_t ret; | 1857 | ssize_t ret; |
1862 | u32 nr, i; | 1858 | u32 nr, i; |
1863 | char *str; | 1859 | char *str; |
1864 | struct strbuf sb; | 1860 | struct strbuf sb; |
@@ -1914,7 +1910,7 @@ static int process_numa_topology(struct perf_file_section *section __maybe_unuse | |||
1914 | struct perf_header *ph, int fd, | 1910 | struct perf_header *ph, int fd, |
1915 | void *data __maybe_unused) | 1911 | void *data __maybe_unused) |
1916 | { | 1912 | { |
1917 | size_t ret; | 1913 | ssize_t ret; |
1918 | u32 nr, node, i; | 1914 | u32 nr, node, i; |
1919 | char *str; | 1915 | char *str; |
1920 | uint64_t mem_total, mem_free; | 1916 | uint64_t mem_total, mem_free; |
@@ -1974,7 +1970,7 @@ static int process_pmu_mappings(struct perf_file_section *section __maybe_unused | |||
1974 | struct perf_header *ph, int fd, | 1970 | struct perf_header *ph, int fd, |
1975 | void *data __maybe_unused) | 1971 | void *data __maybe_unused) |
1976 | { | 1972 | { |
1977 | size_t ret; | 1973 | ssize_t ret; |
1978 | char *name; | 1974 | char *name; |
1979 | u32 pmu_num; | 1975 | u32 pmu_num; |
1980 | u32 type; | 1976 | u32 type; |
@@ -2074,7 +2070,7 @@ static int process_group_desc(struct perf_file_section *section __maybe_unused, | |||
2074 | session->evlist->nr_groups = nr_groups; | 2070 | session->evlist->nr_groups = nr_groups; |
2075 | 2071 | ||
2076 | i = nr = 0; | 2072 | i = nr = 0; |
2077 | list_for_each_entry(evsel, &session->evlist->entries, node) { | 2073 | evlist__for_each(session->evlist, evsel) { |
2078 | if (evsel->idx == (int) desc[i].leader_idx) { | 2074 | if (evsel->idx == (int) desc[i].leader_idx) { |
2079 | evsel->leader = evsel; | 2075 | evsel->leader = evsel; |
2080 | /* {anon_group} is a dummy name */ | 2076 | /* {anon_group} is a dummy name */ |
@@ -2108,7 +2104,7 @@ static int process_group_desc(struct perf_file_section *section __maybe_unused, | |||
2108 | ret = 0; | 2104 | ret = 0; |
2109 | out_free: | 2105 | out_free: |
2110 | for (i = 0; i < nr_groups; i++) | 2106 | for (i = 0; i < nr_groups; i++) |
2111 | free(desc[i].name); | 2107 | zfree(&desc[i].name); |
2112 | free(desc); | 2108 | free(desc); |
2113 | 2109 | ||
2114 | return ret; | 2110 | return ret; |
@@ -2301,7 +2297,7 @@ int perf_session__write_header(struct perf_session *session, | |||
2301 | 2297 | ||
2302 | lseek(fd, sizeof(f_header), SEEK_SET); | 2298 | lseek(fd, sizeof(f_header), SEEK_SET); |
2303 | 2299 | ||
2304 | list_for_each_entry(evsel, &evlist->entries, node) { | 2300 | evlist__for_each(session->evlist, evsel) { |
2305 | evsel->id_offset = lseek(fd, 0, SEEK_CUR); | 2301 | evsel->id_offset = lseek(fd, 0, SEEK_CUR); |
2306 | err = do_write(fd, evsel->id, evsel->ids * sizeof(u64)); | 2302 | err = do_write(fd, evsel->id, evsel->ids * sizeof(u64)); |
2307 | if (err < 0) { | 2303 | if (err < 0) { |
@@ -2312,7 +2308,7 @@ int perf_session__write_header(struct perf_session *session, | |||
2312 | 2308 | ||
2313 | attr_offset = lseek(fd, 0, SEEK_CUR); | 2309 | attr_offset = lseek(fd, 0, SEEK_CUR); |
2314 | 2310 | ||
2315 | list_for_each_entry(evsel, &evlist->entries, node) { | 2311 | evlist__for_each(evlist, evsel) { |
2316 | f_attr = (struct perf_file_attr){ | 2312 | f_attr = (struct perf_file_attr){ |
2317 | .attr = evsel->attr, | 2313 | .attr = evsel->attr, |
2318 | .ids = { | 2314 | .ids = { |
@@ -2327,7 +2323,8 @@ int perf_session__write_header(struct perf_session *session, | |||
2327 | } | 2323 | } |
2328 | } | 2324 | } |
2329 | 2325 | ||
2330 | header->data_offset = lseek(fd, 0, SEEK_CUR); | 2326 | if (!header->data_offset) |
2327 | header->data_offset = lseek(fd, 0, SEEK_CUR); | ||
2331 | header->feat_offset = header->data_offset + header->data_size; | 2328 | header->feat_offset = header->data_offset + header->data_size; |
2332 | 2329 | ||
2333 | if (at_exit) { | 2330 | if (at_exit) { |
@@ -2534,7 +2531,7 @@ static int check_magic_endian(u64 magic, uint64_t hdr_sz, | |||
2534 | int perf_file_header__read(struct perf_file_header *header, | 2531 | int perf_file_header__read(struct perf_file_header *header, |
2535 | struct perf_header *ph, int fd) | 2532 | struct perf_header *ph, int fd) |
2536 | { | 2533 | { |
2537 | int ret; | 2534 | ssize_t ret; |
2538 | 2535 | ||
2539 | lseek(fd, 0, SEEK_SET); | 2536 | lseek(fd, 0, SEEK_SET); |
2540 | 2537 | ||
@@ -2628,7 +2625,7 @@ static int perf_file_header__read_pipe(struct perf_pipe_file_header *header, | |||
2628 | struct perf_header *ph, int fd, | 2625 | struct perf_header *ph, int fd, |
2629 | bool repipe) | 2626 | bool repipe) |
2630 | { | 2627 | { |
2631 | int ret; | 2628 | ssize_t ret; |
2632 | 2629 | ||
2633 | ret = readn(fd, header, sizeof(*header)); | 2630 | ret = readn(fd, header, sizeof(*header)); |
2634 | if (ret <= 0) | 2631 | if (ret <= 0) |
@@ -2669,7 +2666,7 @@ static int read_attr(int fd, struct perf_header *ph, | |||
2669 | struct perf_event_attr *attr = &f_attr->attr; | 2666 | struct perf_event_attr *attr = &f_attr->attr; |
2670 | size_t sz, left; | 2667 | size_t sz, left; |
2671 | size_t our_sz = sizeof(f_attr->attr); | 2668 | size_t our_sz = sizeof(f_attr->attr); |
2672 | int ret; | 2669 | ssize_t ret; |
2673 | 2670 | ||
2674 | memset(f_attr, 0, sizeof(*f_attr)); | 2671 | memset(f_attr, 0, sizeof(*f_attr)); |
2675 | 2672 | ||
@@ -2744,7 +2741,7 @@ static int perf_evlist__prepare_tracepoint_events(struct perf_evlist *evlist, | |||
2744 | { | 2741 | { |
2745 | struct perf_evsel *pos; | 2742 | struct perf_evsel *pos; |
2746 | 2743 | ||
2747 | list_for_each_entry(pos, &evlist->entries, node) { | 2744 | evlist__for_each(evlist, pos) { |
2748 | if (pos->attr.type == PERF_TYPE_TRACEPOINT && | 2745 | if (pos->attr.type == PERF_TYPE_TRACEPOINT && |
2749 | perf_evsel__prepare_tracepoint_event(pos, pevent)) | 2746 | perf_evsel__prepare_tracepoint_event(pos, pevent)) |
2750 | return -1; | 2747 | return -1; |
@@ -2834,11 +2831,11 @@ int perf_session__read_header(struct perf_session *session) | |||
2834 | 2831 | ||
2835 | symbol_conf.nr_events = nr_attrs; | 2832 | symbol_conf.nr_events = nr_attrs; |
2836 | 2833 | ||
2837 | perf_header__process_sections(header, fd, &session->pevent, | 2834 | perf_header__process_sections(header, fd, &session->tevent, |
2838 | perf_file_section__process); | 2835 | perf_file_section__process); |
2839 | 2836 | ||
2840 | if (perf_evlist__prepare_tracepoint_events(session->evlist, | 2837 | if (perf_evlist__prepare_tracepoint_events(session->evlist, |
2841 | session->pevent)) | 2838 | session->tevent.pevent)) |
2842 | goto out_delete_evlist; | 2839 | goto out_delete_evlist; |
2843 | 2840 | ||
2844 | return 0; | 2841 | return 0; |
@@ -2892,7 +2889,7 @@ int perf_event__synthesize_attrs(struct perf_tool *tool, | |||
2892 | struct perf_evsel *evsel; | 2889 | struct perf_evsel *evsel; |
2893 | int err = 0; | 2890 | int err = 0; |
2894 | 2891 | ||
2895 | list_for_each_entry(evsel, &session->evlist->entries, node) { | 2892 | evlist__for_each(session->evlist, evsel) { |
2896 | err = perf_event__synthesize_attr(tool, &evsel->attr, evsel->ids, | 2893 | err = perf_event__synthesize_attr(tool, &evsel->attr, evsel->ids, |
2897 | evsel->id, process); | 2894 | evsel->id, process); |
2898 | if (err) { | 2895 | if (err) { |
@@ -3003,7 +3000,7 @@ int perf_event__process_tracing_data(struct perf_tool *tool __maybe_unused, | |||
3003 | lseek(fd, offset + sizeof(struct tracing_data_event), | 3000 | lseek(fd, offset + sizeof(struct tracing_data_event), |
3004 | SEEK_SET); | 3001 | SEEK_SET); |
3005 | 3002 | ||
3006 | size_read = trace_report(fd, &session->pevent, | 3003 | size_read = trace_report(fd, &session->tevent, |
3007 | session->repipe); | 3004 | session->repipe); |
3008 | padding = PERF_ALIGN(size_read, sizeof(u64)) - size_read; | 3005 | padding = PERF_ALIGN(size_read, sizeof(u64)) - size_read; |
3009 | 3006 | ||
@@ -3025,7 +3022,7 @@ int perf_event__process_tracing_data(struct perf_tool *tool __maybe_unused, | |||
3025 | } | 3022 | } |
3026 | 3023 | ||
3027 | perf_evlist__prepare_tracepoint_events(session->evlist, | 3024 | perf_evlist__prepare_tracepoint_events(session->evlist, |
3028 | session->pevent); | 3025 | session->tevent.pevent); |
3029 | 3026 | ||
3030 | return size_read + padding; | 3027 | return size_read + padding; |
3031 | } | 3028 | } |
diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h index 307c9aed972e..a2d047bdf4ef 100644 --- a/tools/perf/util/header.h +++ b/tools/perf/util/header.h | |||
@@ -77,16 +77,16 @@ struct perf_session_env { | |||
77 | unsigned long long total_mem; | 77 | unsigned long long total_mem; |
78 | 78 | ||
79 | int nr_cmdline; | 79 | int nr_cmdline; |
80 | char *cmdline; | ||
81 | int nr_sibling_cores; | 80 | int nr_sibling_cores; |
82 | char *sibling_cores; | ||
83 | int nr_sibling_threads; | 81 | int nr_sibling_threads; |
84 | char *sibling_threads; | ||
85 | int nr_numa_nodes; | 82 | int nr_numa_nodes; |
86 | char *numa_nodes; | ||
87 | int nr_pmu_mappings; | 83 | int nr_pmu_mappings; |
88 | char *pmu_mappings; | ||
89 | int nr_groups; | 84 | int nr_groups; |
85 | char *cmdline; | ||
86 | char *sibling_cores; | ||
87 | char *sibling_threads; | ||
88 | char *numa_nodes; | ||
89 | char *pmu_mappings; | ||
90 | }; | 90 | }; |
91 | 91 | ||
92 | struct perf_header { | 92 | struct perf_header { |
diff --git a/tools/perf/util/help.c b/tools/perf/util/help.c index 8b1f6e891b8a..86c37c472263 100644 --- a/tools/perf/util/help.c +++ b/tools/perf/util/help.c | |||
@@ -22,8 +22,8 @@ static void clean_cmdnames(struct cmdnames *cmds) | |||
22 | unsigned int i; | 22 | unsigned int i; |
23 | 23 | ||
24 | for (i = 0; i < cmds->cnt; ++i) | 24 | for (i = 0; i < cmds->cnt; ++i) |
25 | free(cmds->names[i]); | 25 | zfree(&cmds->names[i]); |
26 | free(cmds->names); | 26 | zfree(&cmds->names); |
27 | cmds->cnt = 0; | 27 | cmds->cnt = 0; |
28 | cmds->alloc = 0; | 28 | cmds->alloc = 0; |
29 | } | 29 | } |
@@ -263,9 +263,8 @@ static void add_cmd_list(struct cmdnames *cmds, struct cmdnames *old) | |||
263 | 263 | ||
264 | for (i = 0; i < old->cnt; i++) | 264 | for (i = 0; i < old->cnt; i++) |
265 | cmds->names[cmds->cnt++] = old->names[i]; | 265 | cmds->names[cmds->cnt++] = old->names[i]; |
266 | free(old->names); | 266 | zfree(&old->names); |
267 | old->cnt = 0; | 267 | old->cnt = 0; |
268 | old->names = NULL; | ||
269 | } | 268 | } |
270 | 269 | ||
271 | const char *help_unknown_cmd(const char *cmd) | 270 | const char *help_unknown_cmd(const char *cmd) |
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c index 822903eaa201..e4e6249b87d4 100644 --- a/tools/perf/util/hist.c +++ b/tools/perf/util/hist.c | |||
@@ -1,4 +1,3 @@ | |||
1 | #include "annotate.h" | ||
2 | #include "util.h" | 1 | #include "util.h" |
3 | #include "build-id.h" | 2 | #include "build-id.h" |
4 | #include "hist.h" | 3 | #include "hist.h" |
@@ -182,21 +181,21 @@ void hists__output_recalc_col_len(struct hists *hists, int max_rows) | |||
182 | } | 181 | } |
183 | } | 182 | } |
184 | 183 | ||
185 | static void hist_entry__add_cpumode_period(struct hist_entry *he, | 184 | static void he_stat__add_cpumode_period(struct he_stat *he_stat, |
186 | unsigned int cpumode, u64 period) | 185 | unsigned int cpumode, u64 period) |
187 | { | 186 | { |
188 | switch (cpumode) { | 187 | switch (cpumode) { |
189 | case PERF_RECORD_MISC_KERNEL: | 188 | case PERF_RECORD_MISC_KERNEL: |
190 | he->stat.period_sys += period; | 189 | he_stat->period_sys += period; |
191 | break; | 190 | break; |
192 | case PERF_RECORD_MISC_USER: | 191 | case PERF_RECORD_MISC_USER: |
193 | he->stat.period_us += period; | 192 | he_stat->period_us += period; |
194 | break; | 193 | break; |
195 | case PERF_RECORD_MISC_GUEST_KERNEL: | 194 | case PERF_RECORD_MISC_GUEST_KERNEL: |
196 | he->stat.period_guest_sys += period; | 195 | he_stat->period_guest_sys += period; |
197 | break; | 196 | break; |
198 | case PERF_RECORD_MISC_GUEST_USER: | 197 | case PERF_RECORD_MISC_GUEST_USER: |
199 | he->stat.period_guest_us += period; | 198 | he_stat->period_guest_us += period; |
200 | break; | 199 | break; |
201 | default: | 200 | default: |
202 | break; | 201 | break; |
@@ -223,10 +222,10 @@ static void he_stat__add_stat(struct he_stat *dest, struct he_stat *src) | |||
223 | dest->weight += src->weight; | 222 | dest->weight += src->weight; |
224 | } | 223 | } |
225 | 224 | ||
226 | static void hist_entry__decay(struct hist_entry *he) | 225 | static void he_stat__decay(struct he_stat *he_stat) |
227 | { | 226 | { |
228 | he->stat.period = (he->stat.period * 7) / 8; | 227 | he_stat->period = (he_stat->period * 7) / 8; |
229 | he->stat.nr_events = (he->stat.nr_events * 7) / 8; | 228 | he_stat->nr_events = (he_stat->nr_events * 7) / 8; |
230 | /* XXX need decay for weight too? */ | 229 | /* XXX need decay for weight too? */ |
231 | } | 230 | } |
232 | 231 | ||
@@ -237,7 +236,7 @@ static bool hists__decay_entry(struct hists *hists, struct hist_entry *he) | |||
237 | if (prev_period == 0) | 236 | if (prev_period == 0) |
238 | return true; | 237 | return true; |
239 | 238 | ||
240 | hist_entry__decay(he); | 239 | he_stat__decay(&he->stat); |
241 | 240 | ||
242 | if (!he->filtered) | 241 | if (!he->filtered) |
243 | hists->stats.total_period -= prev_period - he->stat.period; | 242 | hists->stats.total_period -= prev_period - he->stat.period; |
@@ -342,15 +341,15 @@ static u8 symbol__parent_filter(const struct symbol *parent) | |||
342 | } | 341 | } |
343 | 342 | ||
344 | static struct hist_entry *add_hist_entry(struct hists *hists, | 343 | static struct hist_entry *add_hist_entry(struct hists *hists, |
345 | struct hist_entry *entry, | 344 | struct hist_entry *entry, |
346 | struct addr_location *al, | 345 | struct addr_location *al) |
347 | u64 period, | ||
348 | u64 weight) | ||
349 | { | 346 | { |
350 | struct rb_node **p; | 347 | struct rb_node **p; |
351 | struct rb_node *parent = NULL; | 348 | struct rb_node *parent = NULL; |
352 | struct hist_entry *he; | 349 | struct hist_entry *he; |
353 | int64_t cmp; | 350 | int64_t cmp; |
351 | u64 period = entry->stat.period; | ||
352 | u64 weight = entry->stat.weight; | ||
354 | 353 | ||
355 | p = &hists->entries_in->rb_node; | 354 | p = &hists->entries_in->rb_node; |
356 | 355 | ||
@@ -373,7 +372,7 @@ static struct hist_entry *add_hist_entry(struct hists *hists, | |||
373 | * This mem info was allocated from machine__resolve_mem | 372 | * This mem info was allocated from machine__resolve_mem |
374 | * and will not be used anymore. | 373 | * and will not be used anymore. |
375 | */ | 374 | */ |
376 | free(entry->mem_info); | 375 | zfree(&entry->mem_info); |
377 | 376 | ||
378 | /* If the map of an existing hist_entry has | 377 | /* If the map of an existing hist_entry has |
379 | * become out-of-date due to an exec() or | 378 | * become out-of-date due to an exec() or |
@@ -403,7 +402,7 @@ static struct hist_entry *add_hist_entry(struct hists *hists, | |||
403 | rb_link_node(&he->rb_node_in, parent, p); | 402 | rb_link_node(&he->rb_node_in, parent, p); |
404 | rb_insert_color(&he->rb_node_in, hists->entries_in); | 403 | rb_insert_color(&he->rb_node_in, hists->entries_in); |
405 | out: | 404 | out: |
406 | hist_entry__add_cpumode_period(he, al->cpumode, period); | 405 | he_stat__add_cpumode_period(&he->stat, al->cpumode, period); |
407 | return he; | 406 | return he; |
408 | } | 407 | } |
409 | 408 | ||
@@ -437,7 +436,7 @@ struct hist_entry *__hists__add_entry(struct hists *hists, | |||
437 | .transaction = transaction, | 436 | .transaction = transaction, |
438 | }; | 437 | }; |
439 | 438 | ||
440 | return add_hist_entry(hists, &entry, al, period, weight); | 439 | return add_hist_entry(hists, &entry, al); |
441 | } | 440 | } |
442 | 441 | ||
443 | int64_t | 442 | int64_t |
@@ -476,8 +475,8 @@ hist_entry__collapse(struct hist_entry *left, struct hist_entry *right) | |||
476 | 475 | ||
477 | void hist_entry__free(struct hist_entry *he) | 476 | void hist_entry__free(struct hist_entry *he) |
478 | { | 477 | { |
479 | free(he->branch_info); | 478 | zfree(&he->branch_info); |
480 | free(he->mem_info); | 479 | zfree(&he->mem_info); |
481 | free_srcline(he->srcline); | 480 | free_srcline(he->srcline); |
482 | free(he); | 481 | free(he); |
483 | } | 482 | } |
@@ -807,16 +806,6 @@ void hists__filter_by_symbol(struct hists *hists) | |||
807 | } | 806 | } |
808 | } | 807 | } |
809 | 808 | ||
810 | int hist_entry__inc_addr_samples(struct hist_entry *he, int evidx, u64 ip) | ||
811 | { | ||
812 | return symbol__inc_addr_samples(he->ms.sym, he->ms.map, evidx, ip); | ||
813 | } | ||
814 | |||
815 | int hist_entry__annotate(struct hist_entry *he, size_t privsize) | ||
816 | { | ||
817 | return symbol__annotate(he->ms.sym, he->ms.map, privsize); | ||
818 | } | ||
819 | |||
820 | void events_stats__inc(struct events_stats *stats, u32 type) | 809 | void events_stats__inc(struct events_stats *stats, u32 type) |
821 | { | 810 | { |
822 | ++stats->nr_events[0]; | 811 | ++stats->nr_events[0]; |
diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h index b621347a1585..a59743fa3ef7 100644 --- a/tools/perf/util/hist.h +++ b/tools/perf/util/hist.h | |||
@@ -111,9 +111,6 @@ size_t events_stats__fprintf(struct events_stats *stats, FILE *fp); | |||
111 | size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows, | 111 | size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows, |
112 | int max_cols, float min_pcnt, FILE *fp); | 112 | int max_cols, float min_pcnt, FILE *fp); |
113 | 113 | ||
114 | int hist_entry__inc_addr_samples(struct hist_entry *he, int evidx, u64 addr); | ||
115 | int hist_entry__annotate(struct hist_entry *he, size_t privsize); | ||
116 | |||
117 | void hists__filter_by_dso(struct hists *hists); | 114 | void hists__filter_by_dso(struct hists *hists); |
118 | void hists__filter_by_thread(struct hists *hists); | 115 | void hists__filter_by_thread(struct hists *hists); |
119 | void hists__filter_by_symbol(struct hists *hists); | 116 | void hists__filter_by_symbol(struct hists *hists); |
diff --git a/tools/perf/util/include/asm/hash.h b/tools/perf/util/include/asm/hash.h new file mode 100644 index 000000000000..d82b170bb216 --- /dev/null +++ b/tools/perf/util/include/asm/hash.h | |||
@@ -0,0 +1,6 @@ | |||
1 | #ifndef __ASM_GENERIC_HASH_H | ||
2 | #define __ASM_GENERIC_HASH_H | ||
3 | |||
4 | /* Stub */ | ||
5 | |||
6 | #endif /* __ASM_GENERIC_HASH_H */ | ||
diff --git a/tools/perf/util/include/linux/bitops.h b/tools/perf/util/include/linux/bitops.h index 45cf10a562bd..dadfa7e54287 100644 --- a/tools/perf/util/include/linux/bitops.h +++ b/tools/perf/util/include/linux/bitops.h | |||
@@ -87,13 +87,15 @@ static __always_inline unsigned long __ffs(unsigned long word) | |||
87 | return num; | 87 | return num; |
88 | } | 88 | } |
89 | 89 | ||
90 | typedef const unsigned long __attribute__((__may_alias__)) long_alias_t; | ||
91 | |||
90 | /* | 92 | /* |
91 | * Find the first set bit in a memory region. | 93 | * Find the first set bit in a memory region. |
92 | */ | 94 | */ |
93 | static inline unsigned long | 95 | static inline unsigned long |
94 | find_first_bit(const unsigned long *addr, unsigned long size) | 96 | find_first_bit(const unsigned long *addr, unsigned long size) |
95 | { | 97 | { |
96 | const unsigned long *p = addr; | 98 | long_alias_t *p = (long_alias_t *) addr; |
97 | unsigned long result = 0; | 99 | unsigned long result = 0; |
98 | unsigned long tmp; | 100 | unsigned long tmp; |
99 | 101 | ||
diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c index 84cdb072ac83..620a1983b76b 100644 --- a/tools/perf/util/machine.c +++ b/tools/perf/util/machine.c | |||
@@ -9,6 +9,7 @@ | |||
9 | #include "strlist.h" | 9 | #include "strlist.h" |
10 | #include "thread.h" | 10 | #include "thread.h" |
11 | #include <stdbool.h> | 11 | #include <stdbool.h> |
12 | #include <symbol/kallsyms.h> | ||
12 | #include "unwind.h" | 13 | #include "unwind.h" |
13 | 14 | ||
14 | int machine__init(struct machine *machine, const char *root_dir, pid_t pid) | 15 | int machine__init(struct machine *machine, const char *root_dir, pid_t pid) |
@@ -26,6 +27,7 @@ int machine__init(struct machine *machine, const char *root_dir, pid_t pid) | |||
26 | machine->pid = pid; | 27 | machine->pid = pid; |
27 | 28 | ||
28 | machine->symbol_filter = NULL; | 29 | machine->symbol_filter = NULL; |
30 | machine->id_hdr_size = 0; | ||
29 | 31 | ||
30 | machine->root_dir = strdup(root_dir); | 32 | machine->root_dir = strdup(root_dir); |
31 | if (machine->root_dir == NULL) | 33 | if (machine->root_dir == NULL) |
@@ -101,8 +103,7 @@ void machine__exit(struct machine *machine) | |||
101 | map_groups__exit(&machine->kmaps); | 103 | map_groups__exit(&machine->kmaps); |
102 | dsos__delete(&machine->user_dsos); | 104 | dsos__delete(&machine->user_dsos); |
103 | dsos__delete(&machine->kernel_dsos); | 105 | dsos__delete(&machine->kernel_dsos); |
104 | free(machine->root_dir); | 106 | zfree(&machine->root_dir); |
105 | machine->root_dir = NULL; | ||
106 | } | 107 | } |
107 | 108 | ||
108 | void machine__delete(struct machine *machine) | 109 | void machine__delete(struct machine *machine) |
@@ -495,23 +496,22 @@ static int symbol__in_kernel(void *arg, const char *name, | |||
495 | return 1; | 496 | return 1; |
496 | } | 497 | } |
497 | 498 | ||
499 | static void machine__get_kallsyms_filename(struct machine *machine, char *buf, | ||
500 | size_t bufsz) | ||
501 | { | ||
502 | if (machine__is_default_guest(machine)) | ||
503 | scnprintf(buf, bufsz, "%s", symbol_conf.default_guest_kallsyms); | ||
504 | else | ||
505 | scnprintf(buf, bufsz, "%s/proc/kallsyms", machine->root_dir); | ||
506 | } | ||
507 | |||
498 | /* Figure out the start address of kernel map from /proc/kallsyms */ | 508 | /* Figure out the start address of kernel map from /proc/kallsyms */ |
499 | static u64 machine__get_kernel_start_addr(struct machine *machine) | 509 | static u64 machine__get_kernel_start_addr(struct machine *machine) |
500 | { | 510 | { |
501 | const char *filename; | 511 | char filename[PATH_MAX]; |
502 | char path[PATH_MAX]; | ||
503 | struct process_args args; | 512 | struct process_args args; |
504 | 513 | ||
505 | if (machine__is_host(machine)) { | 514 | machine__get_kallsyms_filename(machine, filename, PATH_MAX); |
506 | filename = "/proc/kallsyms"; | ||
507 | } else { | ||
508 | if (machine__is_default_guest(machine)) | ||
509 | filename = (char *)symbol_conf.default_guest_kallsyms; | ||
510 | else { | ||
511 | sprintf(path, "%s/proc/kallsyms", machine->root_dir); | ||
512 | filename = path; | ||
513 | } | ||
514 | } | ||
515 | 515 | ||
516 | if (symbol__restricted_filename(filename, "/proc/kallsyms")) | 516 | if (symbol__restricted_filename(filename, "/proc/kallsyms")) |
517 | return 0; | 517 | return 0; |
@@ -565,11 +565,10 @@ void machine__destroy_kernel_maps(struct machine *machine) | |||
565 | * on one of them. | 565 | * on one of them. |
566 | */ | 566 | */ |
567 | if (type == MAP__FUNCTION) { | 567 | if (type == MAP__FUNCTION) { |
568 | free((char *)kmap->ref_reloc_sym->name); | 568 | zfree((char **)&kmap->ref_reloc_sym->name); |
569 | kmap->ref_reloc_sym->name = NULL; | 569 | zfree(&kmap->ref_reloc_sym); |
570 | free(kmap->ref_reloc_sym); | 570 | } else |
571 | } | 571 | kmap->ref_reloc_sym = NULL; |
572 | kmap->ref_reloc_sym = NULL; | ||
573 | } | 572 | } |
574 | 573 | ||
575 | map__delete(machine->vmlinux_maps[type]); | 574 | map__delete(machine->vmlinux_maps[type]); |
@@ -767,8 +766,7 @@ static int map_groups__set_modules_path_dir(struct map_groups *mg, | |||
767 | ret = -1; | 766 | ret = -1; |
768 | goto out; | 767 | goto out; |
769 | } | 768 | } |
770 | dso__set_long_name(map->dso, long_name); | 769 | dso__set_long_name(map->dso, long_name, true); |
771 | map->dso->lname_alloc = 1; | ||
772 | dso__kernel_module_get_build_id(map->dso, ""); | 770 | dso__kernel_module_get_build_id(map->dso, ""); |
773 | } | 771 | } |
774 | } | 772 | } |
@@ -834,9 +832,25 @@ static int machine__create_modules(struct machine *machine) | |||
834 | return 0; | 832 | return 0; |
835 | } | 833 | } |
836 | 834 | ||
835 | const char *ref_reloc_sym_names[] = {"_text", "_stext", NULL}; | ||
836 | |||
837 | int machine__create_kernel_maps(struct machine *machine) | 837 | int machine__create_kernel_maps(struct machine *machine) |
838 | { | 838 | { |
839 | struct dso *kernel = machine__get_kernel(machine); | 839 | struct dso *kernel = machine__get_kernel(machine); |
840 | char filename[PATH_MAX]; | ||
841 | const char *name; | ||
842 | u64 addr = 0; | ||
843 | int i; | ||
844 | |||
845 | machine__get_kallsyms_filename(machine, filename, PATH_MAX); | ||
846 | |||
847 | for (i = 0; (name = ref_reloc_sym_names[i]) != NULL; i++) { | ||
848 | addr = kallsyms__get_function_start(filename, name); | ||
849 | if (addr) | ||
850 | break; | ||
851 | } | ||
852 | if (!addr) | ||
853 | return -1; | ||
840 | 854 | ||
841 | if (kernel == NULL || | 855 | if (kernel == NULL || |
842 | __machine__create_kernel_maps(machine, kernel) < 0) | 856 | __machine__create_kernel_maps(machine, kernel) < 0) |
@@ -855,6 +869,13 @@ int machine__create_kernel_maps(struct machine *machine) | |||
855 | * Now that we have all the maps created, just set the ->end of them: | 869 | * Now that we have all the maps created, just set the ->end of them: |
856 | */ | 870 | */ |
857 | map_groups__fixup_end(&machine->kmaps); | 871 | map_groups__fixup_end(&machine->kmaps); |
872 | |||
873 | if (maps__set_kallsyms_ref_reloc_sym(machine->vmlinux_maps, name, | ||
874 | addr)) { | ||
875 | machine__destroy_kernel_maps(machine); | ||
876 | return -1; | ||
877 | } | ||
878 | |||
858 | return 0; | 879 | return 0; |
859 | } | 880 | } |
860 | 881 | ||
@@ -939,8 +960,7 @@ static int machine__process_kernel_mmap_event(struct machine *machine, | |||
939 | if (name == NULL) | 960 | if (name == NULL) |
940 | goto out_problem; | 961 | goto out_problem; |
941 | 962 | ||
942 | map->dso->short_name = name; | 963 | dso__set_short_name(map->dso, name, true); |
943 | map->dso->sname_alloc = 1; | ||
944 | map->end = map->start + event->mmap.len; | 964 | map->end = map->start + event->mmap.len; |
945 | } else if (is_kernel_mmap) { | 965 | } else if (is_kernel_mmap) { |
946 | const char *symbol_name = (event->mmap.filename + | 966 | const char *symbol_name = (event->mmap.filename + |
@@ -1193,7 +1213,7 @@ static void ip__resolve_ams(struct machine *machine, struct thread *thread, | |||
1193 | */ | 1213 | */ |
1194 | thread__find_addr_location(thread, machine, m, MAP__FUNCTION, | 1214 | thread__find_addr_location(thread, machine, m, MAP__FUNCTION, |
1195 | ip, &al); | 1215 | ip, &al); |
1196 | if (al.sym) | 1216 | if (al.map) |
1197 | goto found; | 1217 | goto found; |
1198 | } | 1218 | } |
1199 | found: | 1219 | found: |
@@ -1320,8 +1340,6 @@ static int machine__resolve_callchain_sample(struct machine *machine, | |||
1320 | *root_al = al; | 1340 | *root_al = al; |
1321 | callchain_cursor_reset(&callchain_cursor); | 1341 | callchain_cursor_reset(&callchain_cursor); |
1322 | } | 1342 | } |
1323 | if (!symbol_conf.use_callchain) | ||
1324 | break; | ||
1325 | } | 1343 | } |
1326 | 1344 | ||
1327 | err = callchain_cursor_append(&callchain_cursor, | 1345 | err = callchain_cursor_append(&callchain_cursor, |
diff --git a/tools/perf/util/machine.h b/tools/perf/util/machine.h index 477133015440..f77e91e483dc 100644 --- a/tools/perf/util/machine.h +++ b/tools/perf/util/machine.h | |||
@@ -18,6 +18,8 @@ union perf_event; | |||
18 | #define HOST_KERNEL_ID (-1) | 18 | #define HOST_KERNEL_ID (-1) |
19 | #define DEFAULT_GUEST_KERNEL_ID (0) | 19 | #define DEFAULT_GUEST_KERNEL_ID (0) |
20 | 20 | ||
21 | extern const char *ref_reloc_sym_names[]; | ||
22 | |||
21 | struct machine { | 23 | struct machine { |
22 | struct rb_node rb_node; | 24 | struct rb_node rb_node; |
23 | pid_t pid; | 25 | pid_t pid; |
diff --git a/tools/perf/util/map.c b/tools/perf/util/map.c index ef5bc913ca7a..39cd2d0faff6 100644 --- a/tools/perf/util/map.c +++ b/tools/perf/util/map.c | |||
@@ -11,6 +11,7 @@ | |||
11 | #include "strlist.h" | 11 | #include "strlist.h" |
12 | #include "vdso.h" | 12 | #include "vdso.h" |
13 | #include "build-id.h" | 13 | #include "build-id.h" |
14 | #include "util.h" | ||
14 | #include <linux/string.h> | 15 | #include <linux/string.h> |
15 | 16 | ||
16 | const char *map_type__name[MAP__NR_TYPES] = { | 17 | const char *map_type__name[MAP__NR_TYPES] = { |
@@ -38,6 +39,7 @@ void map__init(struct map *map, enum map_type type, | |||
38 | map->start = start; | 39 | map->start = start; |
39 | map->end = end; | 40 | map->end = end; |
40 | map->pgoff = pgoff; | 41 | map->pgoff = pgoff; |
42 | map->reloc = 0; | ||
41 | map->dso = dso; | 43 | map->dso = dso; |
42 | map->map_ip = map__map_ip; | 44 | map->map_ip = map__map_ip; |
43 | map->unmap_ip = map__unmap_ip; | 45 | map->unmap_ip = map__unmap_ip; |
@@ -68,7 +70,7 @@ struct map *map__new(struct list_head *dsos__list, u64 start, u64 len, | |||
68 | map->ino = ino; | 70 | map->ino = ino; |
69 | map->ino_generation = ino_gen; | 71 | map->ino_generation = ino_gen; |
70 | 72 | ||
71 | if (anon) { | 73 | if ((anon || no_dso) && type == MAP__FUNCTION) { |
72 | snprintf(newfilename, sizeof(newfilename), "/tmp/perf-%d.map", pid); | 74 | snprintf(newfilename, sizeof(newfilename), "/tmp/perf-%d.map", pid); |
73 | filename = newfilename; | 75 | filename = newfilename; |
74 | } | 76 | } |
@@ -92,7 +94,7 @@ struct map *map__new(struct list_head *dsos__list, u64 start, u64 len, | |||
92 | * functions still return NULL, and we avoid the | 94 | * functions still return NULL, and we avoid the |
93 | * unnecessary map__load warning. | 95 | * unnecessary map__load warning. |
94 | */ | 96 | */ |
95 | if (no_dso) | 97 | if (type != MAP__FUNCTION) |
96 | dso__set_loaded(dso, map->type); | 98 | dso__set_loaded(dso, map->type); |
97 | } | 99 | } |
98 | } | 100 | } |
@@ -252,6 +254,22 @@ size_t map__fprintf_dsoname(struct map *map, FILE *fp) | |||
252 | return fprintf(fp, "%s", dsoname); | 254 | return fprintf(fp, "%s", dsoname); |
253 | } | 255 | } |
254 | 256 | ||
257 | int map__fprintf_srcline(struct map *map, u64 addr, const char *prefix, | ||
258 | FILE *fp) | ||
259 | { | ||
260 | char *srcline; | ||
261 | int ret = 0; | ||
262 | |||
263 | if (map && map->dso) { | ||
264 | srcline = get_srcline(map->dso, | ||
265 | map__rip_2objdump(map, addr)); | ||
266 | if (srcline != SRCLINE_UNKNOWN) | ||
267 | ret = fprintf(fp, "%s%s", prefix, srcline); | ||
268 | free_srcline(srcline); | ||
269 | } | ||
270 | return ret; | ||
271 | } | ||
272 | |||
255 | /** | 273 | /** |
256 | * map__rip_2objdump - convert symbol start address to objdump address. | 274 | * map__rip_2objdump - convert symbol start address to objdump address. |
257 | * @map: memory map | 275 | * @map: memory map |
@@ -271,7 +289,7 @@ u64 map__rip_2objdump(struct map *map, u64 rip) | |||
271 | if (map->dso->rel) | 289 | if (map->dso->rel) |
272 | return rip - map->pgoff; | 290 | return rip - map->pgoff; |
273 | 291 | ||
274 | return map->unmap_ip(map, rip); | 292 | return map->unmap_ip(map, rip) - map->reloc; |
275 | } | 293 | } |
276 | 294 | ||
277 | /** | 295 | /** |
@@ -294,7 +312,7 @@ u64 map__objdump_2mem(struct map *map, u64 ip) | |||
294 | if (map->dso->rel) | 312 | if (map->dso->rel) |
295 | return map->unmap_ip(map, ip + map->pgoff); | 313 | return map->unmap_ip(map, ip + map->pgoff); |
296 | 314 | ||
297 | return ip; | 315 | return ip + map->reloc; |
298 | } | 316 | } |
299 | 317 | ||
300 | void map_groups__init(struct map_groups *mg) | 318 | void map_groups__init(struct map_groups *mg) |
@@ -369,7 +387,8 @@ struct symbol *map_groups__find_symbol(struct map_groups *mg, | |||
369 | { | 387 | { |
370 | struct map *map = map_groups__find(mg, type, addr); | 388 | struct map *map = map_groups__find(mg, type, addr); |
371 | 389 | ||
372 | if (map != NULL) { | 390 | /* Ensure map is loaded before using map->map_ip */ |
391 | if (map != NULL && map__load(map, filter) >= 0) { | ||
373 | if (mapp != NULL) | 392 | if (mapp != NULL) |
374 | *mapp = map; | 393 | *mapp = map; |
375 | return map__find_symbol(map, map->map_ip(map, addr), filter); | 394 | return map__find_symbol(map, map->map_ip(map, addr), filter); |
diff --git a/tools/perf/util/map.h b/tools/perf/util/map.h index e4e259c3ba16..257e513205ce 100644 --- a/tools/perf/util/map.h +++ b/tools/perf/util/map.h | |||
@@ -36,6 +36,7 @@ struct map { | |||
36 | bool erange_warned; | 36 | bool erange_warned; |
37 | u32 priv; | 37 | u32 priv; |
38 | u64 pgoff; | 38 | u64 pgoff; |
39 | u64 reloc; | ||
39 | u32 maj, min; /* only valid for MMAP2 record */ | 40 | u32 maj, min; /* only valid for MMAP2 record */ |
40 | u64 ino; /* only valid for MMAP2 record */ | 41 | u64 ino; /* only valid for MMAP2 record */ |
41 | u64 ino_generation;/* only valid for MMAP2 record */ | 42 | u64 ino_generation;/* only valid for MMAP2 record */ |
@@ -103,6 +104,8 @@ struct map *map__clone(struct map *map); | |||
103 | int map__overlap(struct map *l, struct map *r); | 104 | int map__overlap(struct map *l, struct map *r); |
104 | size_t map__fprintf(struct map *map, FILE *fp); | 105 | size_t map__fprintf(struct map *map, FILE *fp); |
105 | size_t map__fprintf_dsoname(struct map *map, FILE *fp); | 106 | size_t map__fprintf_dsoname(struct map *map, FILE *fp); |
107 | int map__fprintf_srcline(struct map *map, u64 addr, const char *prefix, | ||
108 | FILE *fp); | ||
106 | 109 | ||
107 | int map__load(struct map *map, symbol_filter_t filter); | 110 | int map__load(struct map *map, symbol_filter_t filter); |
108 | struct symbol *map__find_symbol(struct map *map, | 111 | struct symbol *map__find_symbol(struct map *map, |
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index 6de6f89c2a61..1e15df10a88c 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 <lk/debugfs.h> | 13 | #include <api/fs/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" |
@@ -204,7 +204,7 @@ struct tracepoint_path *tracepoint_id_to_path(u64 config) | |||
204 | } | 204 | } |
205 | path->name = malloc(MAX_EVENT_LENGTH); | 205 | path->name = malloc(MAX_EVENT_LENGTH); |
206 | if (!path->name) { | 206 | if (!path->name) { |
207 | free(path->system); | 207 | zfree(&path->system); |
208 | free(path); | 208 | free(path); |
209 | return NULL; | 209 | return NULL; |
210 | } | 210 | } |
@@ -236,8 +236,8 @@ struct tracepoint_path *tracepoint_name_to_path(const char *name) | |||
236 | path->name = strdup(str+1); | 236 | path->name = strdup(str+1); |
237 | 237 | ||
238 | if (path->system == NULL || path->name == NULL) { | 238 | if (path->system == NULL || path->name == NULL) { |
239 | free(path->system); | 239 | zfree(&path->system); |
240 | free(path->name); | 240 | zfree(&path->name); |
241 | free(path); | 241 | free(path); |
242 | path = NULL; | 242 | path = NULL; |
243 | } | 243 | } |
@@ -269,9 +269,10 @@ const char *event_type(int type) | |||
269 | 269 | ||
270 | 270 | ||
271 | 271 | ||
272 | static int __add_event(struct list_head *list, int *idx, | 272 | static struct perf_evsel * |
273 | struct perf_event_attr *attr, | 273 | __add_event(struct list_head *list, int *idx, |
274 | char *name, struct cpu_map *cpus) | 274 | struct perf_event_attr *attr, |
275 | char *name, struct cpu_map *cpus) | ||
275 | { | 276 | { |
276 | struct perf_evsel *evsel; | 277 | struct perf_evsel *evsel; |
277 | 278 | ||
@@ -279,19 +280,19 @@ static int __add_event(struct list_head *list, int *idx, | |||
279 | 280 | ||
280 | evsel = perf_evsel__new_idx(attr, (*idx)++); | 281 | evsel = perf_evsel__new_idx(attr, (*idx)++); |
281 | if (!evsel) | 282 | if (!evsel) |
282 | return -ENOMEM; | 283 | return NULL; |
283 | 284 | ||
284 | evsel->cpus = cpus; | 285 | evsel->cpus = cpus; |
285 | if (name) | 286 | if (name) |
286 | evsel->name = strdup(name); | 287 | evsel->name = strdup(name); |
287 | list_add_tail(&evsel->node, list); | 288 | list_add_tail(&evsel->node, list); |
288 | return 0; | 289 | return evsel; |
289 | } | 290 | } |
290 | 291 | ||
291 | static int add_event(struct list_head *list, int *idx, | 292 | static int add_event(struct list_head *list, int *idx, |
292 | struct perf_event_attr *attr, char *name) | 293 | struct perf_event_attr *attr, char *name) |
293 | { | 294 | { |
294 | return __add_event(list, idx, attr, name, NULL); | 295 | return __add_event(list, idx, attr, name, NULL) ? 0 : -ENOMEM; |
295 | } | 296 | } |
296 | 297 | ||
297 | static int parse_aliases(char *str, const char *names[][PERF_EVSEL__MAX_ALIASES], int size) | 298 | static int parse_aliases(char *str, const char *names[][PERF_EVSEL__MAX_ALIASES], int size) |
@@ -633,6 +634,9 @@ int parse_events_add_pmu(struct list_head *list, int *idx, | |||
633 | { | 634 | { |
634 | struct perf_event_attr attr; | 635 | struct perf_event_attr attr; |
635 | struct perf_pmu *pmu; | 636 | struct perf_pmu *pmu; |
637 | struct perf_evsel *evsel; | ||
638 | const char *unit; | ||
639 | double scale; | ||
636 | 640 | ||
637 | pmu = perf_pmu__find(name); | 641 | pmu = perf_pmu__find(name); |
638 | if (!pmu) | 642 | if (!pmu) |
@@ -640,7 +644,7 @@ int parse_events_add_pmu(struct list_head *list, int *idx, | |||
640 | 644 | ||
641 | memset(&attr, 0, sizeof(attr)); | 645 | memset(&attr, 0, sizeof(attr)); |
642 | 646 | ||
643 | if (perf_pmu__check_alias(pmu, head_config)) | 647 | if (perf_pmu__check_alias(pmu, head_config, &unit, &scale)) |
644 | return -EINVAL; | 648 | return -EINVAL; |
645 | 649 | ||
646 | /* | 650 | /* |
@@ -652,8 +656,14 @@ int parse_events_add_pmu(struct list_head *list, int *idx, | |||
652 | if (perf_pmu__config(pmu, &attr, head_config)) | 656 | if (perf_pmu__config(pmu, &attr, head_config)) |
653 | return -EINVAL; | 657 | return -EINVAL; |
654 | 658 | ||
655 | return __add_event(list, idx, &attr, pmu_event_name(head_config), | 659 | evsel = __add_event(list, idx, &attr, pmu_event_name(head_config), |
656 | pmu->cpus); | 660 | pmu->cpus); |
661 | if (evsel) { | ||
662 | evsel->unit = unit; | ||
663 | evsel->scale = scale; | ||
664 | } | ||
665 | |||
666 | return evsel ? 0 : -ENOMEM; | ||
657 | } | 667 | } |
658 | 668 | ||
659 | int parse_events__modifier_group(struct list_head *list, | 669 | int parse_events__modifier_group(struct list_head *list, |
@@ -810,8 +820,7 @@ int parse_events__modifier_event(struct list_head *list, char *str, bool add) | |||
810 | if (!add && get_event_modifier(&mod, str, NULL)) | 820 | if (!add && get_event_modifier(&mod, str, NULL)) |
811 | return -EINVAL; | 821 | return -EINVAL; |
812 | 822 | ||
813 | list_for_each_entry(evsel, list, node) { | 823 | __evlist__for_each(list, evsel) { |
814 | |||
815 | if (add && get_event_modifier(&mod, str, evsel)) | 824 | if (add && get_event_modifier(&mod, str, evsel)) |
816 | return -EINVAL; | 825 | return -EINVAL; |
817 | 826 | ||
@@ -835,7 +844,7 @@ int parse_events_name(struct list_head *list, char *name) | |||
835 | { | 844 | { |
836 | struct perf_evsel *evsel; | 845 | struct perf_evsel *evsel; |
837 | 846 | ||
838 | list_for_each_entry(evsel, list, node) { | 847 | __evlist__for_each(list, evsel) { |
839 | if (!evsel->name) | 848 | if (!evsel->name) |
840 | evsel->name = strdup(name); | 849 | evsel->name = strdup(name); |
841 | } | 850 | } |
@@ -907,7 +916,7 @@ int parse_events_terms(struct list_head *terms, const char *str) | |||
907 | ret = parse_events__scanner(str, &data, PE_START_TERMS); | 916 | ret = parse_events__scanner(str, &data, PE_START_TERMS); |
908 | if (!ret) { | 917 | if (!ret) { |
909 | list_splice(data.terms, terms); | 918 | list_splice(data.terms, terms); |
910 | free(data.terms); | 919 | zfree(&data.terms); |
911 | return 0; | 920 | return 0; |
912 | } | 921 | } |
913 | 922 | ||
@@ -1082,12 +1091,12 @@ int is_valid_tracepoint(const char *event_string) | |||
1082 | static bool is_event_supported(u8 type, unsigned config) | 1091 | static bool is_event_supported(u8 type, unsigned config) |
1083 | { | 1092 | { |
1084 | bool ret = true; | 1093 | bool ret = true; |
1094 | int open_return; | ||
1085 | struct perf_evsel *evsel; | 1095 | struct perf_evsel *evsel; |
1086 | struct perf_event_attr attr = { | 1096 | struct perf_event_attr attr = { |
1087 | .type = type, | 1097 | .type = type, |
1088 | .config = config, | 1098 | .config = config, |
1089 | .disabled = 1, | 1099 | .disabled = 1, |
1090 | .exclude_kernel = 1, | ||
1091 | }; | 1100 | }; |
1092 | struct { | 1101 | struct { |
1093 | struct thread_map map; | 1102 | struct thread_map map; |
@@ -1099,7 +1108,20 @@ static bool is_event_supported(u8 type, unsigned config) | |||
1099 | 1108 | ||
1100 | evsel = perf_evsel__new(&attr); | 1109 | evsel = perf_evsel__new(&attr); |
1101 | if (evsel) { | 1110 | if (evsel) { |
1102 | ret = perf_evsel__open(evsel, NULL, &tmap.map) >= 0; | 1111 | open_return = perf_evsel__open(evsel, NULL, &tmap.map); |
1112 | ret = open_return >= 0; | ||
1113 | |||
1114 | if (open_return == -EACCES) { | ||
1115 | /* | ||
1116 | * This happens if the paranoid value | ||
1117 | * /proc/sys/kernel/perf_event_paranoid is set to 2 | ||
1118 | * Re-run with exclude_kernel set; we don't do that | ||
1119 | * by default as some ARM machines do not support it. | ||
1120 | * | ||
1121 | */ | ||
1122 | evsel->attr.exclude_kernel = 1; | ||
1123 | ret = perf_evsel__open(evsel, NULL, &tmap.map) >= 0; | ||
1124 | } | ||
1103 | perf_evsel__delete(evsel); | 1125 | perf_evsel__delete(evsel); |
1104 | } | 1126 | } |
1105 | 1127 | ||
diff --git a/tools/perf/util/parse-options.c b/tools/perf/util/parse-options.c index 31f404a032a9..d22e3f8017dc 100644 --- a/tools/perf/util/parse-options.c +++ b/tools/perf/util/parse-options.c | |||
@@ -78,6 +78,8 @@ static int get_value(struct parse_opt_ctx_t *p, | |||
78 | 78 | ||
79 | case OPTION_BOOLEAN: | 79 | case OPTION_BOOLEAN: |
80 | *(bool *)opt->value = unset ? false : true; | 80 | *(bool *)opt->value = unset ? false : true; |
81 | if (opt->set) | ||
82 | *(bool *)opt->set = true; | ||
81 | return 0; | 83 | return 0; |
82 | 84 | ||
83 | case OPTION_INCR: | 85 | case OPTION_INCR: |
@@ -224,6 +226,24 @@ static int parse_long_opt(struct parse_opt_ctx_t *p, const char *arg, | |||
224 | return 0; | 226 | return 0; |
225 | } | 227 | } |
226 | if (!rest) { | 228 | if (!rest) { |
229 | if (!prefixcmp(options->long_name, "no-")) { | ||
230 | /* | ||
231 | * The long name itself starts with "no-", so | ||
232 | * accept the option without "no-" so that users | ||
233 | * do not have to enter "no-no-" to get the | ||
234 | * negation. | ||
235 | */ | ||
236 | rest = skip_prefix(arg, options->long_name + 3); | ||
237 | if (rest) { | ||
238 | flags |= OPT_UNSET; | ||
239 | goto match; | ||
240 | } | ||
241 | /* Abbreviated case */ | ||
242 | if (!prefixcmp(options->long_name + 3, arg)) { | ||
243 | flags |= OPT_UNSET; | ||
244 | goto is_abbreviated; | ||
245 | } | ||
246 | } | ||
227 | /* abbreviated? */ | 247 | /* abbreviated? */ |
228 | if (!strncmp(options->long_name, arg, arg_end - arg)) { | 248 | if (!strncmp(options->long_name, arg, arg_end - arg)) { |
229 | is_abbreviated: | 249 | is_abbreviated: |
@@ -259,6 +279,7 @@ is_abbreviated: | |||
259 | if (!rest) | 279 | if (!rest) |
260 | continue; | 280 | continue; |
261 | } | 281 | } |
282 | match: | ||
262 | if (*rest) { | 283 | if (*rest) { |
263 | if (*rest != '=') | 284 | if (*rest != '=') |
264 | continue; | 285 | continue; |
diff --git a/tools/perf/util/parse-options.h b/tools/perf/util/parse-options.h index b0241e28eaf7..cbf0149cf221 100644 --- a/tools/perf/util/parse-options.h +++ b/tools/perf/util/parse-options.h | |||
@@ -82,6 +82,9 @@ typedef int parse_opt_cb(const struct option *, const char *arg, int unset); | |||
82 | * OPTION_{BIT,SET_UINT,SET_PTR} store the {mask,integer,pointer} to put in | 82 | * OPTION_{BIT,SET_UINT,SET_PTR} store the {mask,integer,pointer} to put in |
83 | * the value when met. | 83 | * the value when met. |
84 | * CALLBACKS can use it like they want. | 84 | * CALLBACKS can use it like they want. |
85 | * | ||
86 | * `set`:: | ||
87 | * whether an option was set by the user | ||
85 | */ | 88 | */ |
86 | struct option { | 89 | struct option { |
87 | enum parse_opt_type type; | 90 | enum parse_opt_type type; |
@@ -94,6 +97,7 @@ struct option { | |||
94 | int flags; | 97 | int flags; |
95 | parse_opt_cb *callback; | 98 | parse_opt_cb *callback; |
96 | intptr_t defval; | 99 | intptr_t defval; |
100 | bool *set; | ||
97 | }; | 101 | }; |
98 | 102 | ||
99 | #define check_vtype(v, type) ( BUILD_BUG_ON_ZERO(!__builtin_types_compatible_p(typeof(v), type)) + v ) | 103 | #define check_vtype(v, type) ( BUILD_BUG_ON_ZERO(!__builtin_types_compatible_p(typeof(v), type)) + v ) |
@@ -103,6 +107,10 @@ struct option { | |||
103 | #define OPT_GROUP(h) { .type = OPTION_GROUP, .help = (h) } | 107 | #define OPT_GROUP(h) { .type = OPTION_GROUP, .help = (h) } |
104 | #define OPT_BIT(s, l, v, h, b) { .type = OPTION_BIT, .short_name = (s), .long_name = (l), .value = check_vtype(v, int *), .help = (h), .defval = (b) } | 108 | #define OPT_BIT(s, l, v, h, b) { .type = OPTION_BIT, .short_name = (s), .long_name = (l), .value = check_vtype(v, int *), .help = (h), .defval = (b) } |
105 | #define OPT_BOOLEAN(s, l, v, h) { .type = OPTION_BOOLEAN, .short_name = (s), .long_name = (l), .value = check_vtype(v, bool *), .help = (h) } | 109 | #define OPT_BOOLEAN(s, l, v, h) { .type = OPTION_BOOLEAN, .short_name = (s), .long_name = (l), .value = check_vtype(v, bool *), .help = (h) } |
110 | #define OPT_BOOLEAN_SET(s, l, v, os, h) \ | ||
111 | { .type = OPTION_BOOLEAN, .short_name = (s), .long_name = (l), \ | ||
112 | .value = check_vtype(v, bool *), .help = (h), \ | ||
113 | .set = check_vtype(os, bool *)} | ||
106 | #define OPT_INCR(s, l, v, h) { .type = OPTION_INCR, .short_name = (s), .long_name = (l), .value = check_vtype(v, int *), .help = (h) } | 114 | #define OPT_INCR(s, l, v, h) { .type = OPTION_INCR, .short_name = (s), .long_name = (l), .value = check_vtype(v, int *), .help = (h) } |
107 | #define OPT_SET_UINT(s, l, v, h, i) { .type = OPTION_SET_UINT, .short_name = (s), .long_name = (l), .value = check_vtype(v, unsigned int *), .help = (h), .defval = (i) } | 115 | #define OPT_SET_UINT(s, l, v, h, i) { .type = OPTION_SET_UINT, .short_name = (s), .long_name = (l), .value = check_vtype(v, unsigned int *), .help = (h), .defval = (i) } |
108 | #define OPT_SET_PTR(s, l, v, h, p) { .type = OPTION_SET_PTR, .short_name = (s), .long_name = (l), .value = (v), .help = (h), .defval = (p) } | 116 | #define OPT_SET_PTR(s, l, v, h, p) { .type = OPTION_SET_PTR, .short_name = (s), .long_name = (l), .value = (v), .help = (h), .defval = (p) } |
diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c index c232d8dd410b..b752ecb40d86 100644 --- a/tools/perf/util/pmu.c +++ b/tools/perf/util/pmu.c | |||
@@ -1,19 +1,23 @@ | |||
1 | #include <linux/list.h> | 1 | #include <linux/list.h> |
2 | #include <sys/types.h> | 2 | #include <sys/types.h> |
3 | #include <sys/stat.h> | ||
4 | #include <unistd.h> | 3 | #include <unistd.h> |
5 | #include <stdio.h> | 4 | #include <stdio.h> |
6 | #include <dirent.h> | 5 | #include <dirent.h> |
7 | #include "fs.h" | 6 | #include "fs.h" |
7 | #include <locale.h> | ||
8 | #include "util.h" | 8 | #include "util.h" |
9 | #include "pmu.h" | 9 | #include "pmu.h" |
10 | #include "parse-events.h" | 10 | #include "parse-events.h" |
11 | #include "cpumap.h" | 11 | #include "cpumap.h" |
12 | 12 | ||
13 | #define UNIT_MAX_LEN 31 /* max length for event unit name */ | ||
14 | |||
13 | struct perf_pmu_alias { | 15 | struct perf_pmu_alias { |
14 | char *name; | 16 | char *name; |
15 | struct list_head terms; | 17 | struct list_head terms; |
16 | struct list_head list; | 18 | struct list_head list; |
19 | char unit[UNIT_MAX_LEN+1]; | ||
20 | double scale; | ||
17 | }; | 21 | }; |
18 | 22 | ||
19 | struct perf_pmu_format { | 23 | struct perf_pmu_format { |
@@ -94,7 +98,80 @@ static int pmu_format(const char *name, struct list_head *format) | |||
94 | return 0; | 98 | return 0; |
95 | } | 99 | } |
96 | 100 | ||
97 | static int perf_pmu__new_alias(struct list_head *list, char *name, FILE *file) | 101 | static int perf_pmu__parse_scale(struct perf_pmu_alias *alias, char *dir, char *name) |
102 | { | ||
103 | struct stat st; | ||
104 | ssize_t sret; | ||
105 | char scale[128]; | ||
106 | int fd, ret = -1; | ||
107 | char path[PATH_MAX]; | ||
108 | const char *lc; | ||
109 | |||
110 | snprintf(path, PATH_MAX, "%s/%s.scale", dir, name); | ||
111 | |||
112 | fd = open(path, O_RDONLY); | ||
113 | if (fd == -1) | ||
114 | return -1; | ||
115 | |||
116 | if (fstat(fd, &st) < 0) | ||
117 | goto error; | ||
118 | |||
119 | sret = read(fd, scale, sizeof(scale)-1); | ||
120 | if (sret < 0) | ||
121 | goto error; | ||
122 | |||
123 | scale[sret] = '\0'; | ||
124 | /* | ||
125 | * save current locale | ||
126 | */ | ||
127 | lc = setlocale(LC_NUMERIC, NULL); | ||
128 | |||
129 | /* | ||
130 | * force to C locale to ensure kernel | ||
131 | * scale string is converted correctly. | ||
132 | * kernel uses default C locale. | ||
133 | */ | ||
134 | setlocale(LC_NUMERIC, "C"); | ||
135 | |||
136 | alias->scale = strtod(scale, NULL); | ||
137 | |||
138 | /* restore locale */ | ||
139 | setlocale(LC_NUMERIC, lc); | ||
140 | |||
141 | ret = 0; | ||
142 | error: | ||
143 | close(fd); | ||
144 | return ret; | ||
145 | } | ||
146 | |||
147 | static int perf_pmu__parse_unit(struct perf_pmu_alias *alias, char *dir, char *name) | ||
148 | { | ||
149 | char path[PATH_MAX]; | ||
150 | ssize_t sret; | ||
151 | int fd; | ||
152 | |||
153 | snprintf(path, PATH_MAX, "%s/%s.unit", dir, name); | ||
154 | |||
155 | fd = open(path, O_RDONLY); | ||
156 | if (fd == -1) | ||
157 | return -1; | ||
158 | |||
159 | sret = read(fd, alias->unit, UNIT_MAX_LEN); | ||
160 | if (sret < 0) | ||
161 | goto error; | ||
162 | |||
163 | close(fd); | ||
164 | |||
165 | alias->unit[sret] = '\0'; | ||
166 | |||
167 | return 0; | ||
168 | error: | ||
169 | close(fd); | ||
170 | alias->unit[0] = '\0'; | ||
171 | return -1; | ||
172 | } | ||
173 | |||
174 | static int perf_pmu__new_alias(struct list_head *list, char *dir, char *name, FILE *file) | ||
98 | { | 175 | { |
99 | struct perf_pmu_alias *alias; | 176 | struct perf_pmu_alias *alias; |
100 | char buf[256]; | 177 | char buf[256]; |
@@ -110,6 +187,9 @@ static int perf_pmu__new_alias(struct list_head *list, char *name, FILE *file) | |||
110 | return -ENOMEM; | 187 | return -ENOMEM; |
111 | 188 | ||
112 | INIT_LIST_HEAD(&alias->terms); | 189 | INIT_LIST_HEAD(&alias->terms); |
190 | alias->scale = 1.0; | ||
191 | alias->unit[0] = '\0'; | ||
192 | |||
113 | ret = parse_events_terms(&alias->terms, buf); | 193 | ret = parse_events_terms(&alias->terms, buf); |
114 | if (ret) { | 194 | if (ret) { |
115 | free(alias); | 195 | free(alias); |
@@ -117,7 +197,14 @@ static int perf_pmu__new_alias(struct list_head *list, char *name, FILE *file) | |||
117 | } | 197 | } |
118 | 198 | ||
119 | alias->name = strdup(name); | 199 | alias->name = strdup(name); |
200 | /* | ||
201 | * load unit name and scale if available | ||
202 | */ | ||
203 | perf_pmu__parse_unit(alias, dir, name); | ||
204 | perf_pmu__parse_scale(alias, dir, name); | ||
205 | |||
120 | list_add_tail(&alias->list, list); | 206 | list_add_tail(&alias->list, list); |
207 | |||
121 | return 0; | 208 | return 0; |
122 | } | 209 | } |
123 | 210 | ||
@@ -129,6 +216,7 @@ static int pmu_aliases_parse(char *dir, struct list_head *head) | |||
129 | { | 216 | { |
130 | struct dirent *evt_ent; | 217 | struct dirent *evt_ent; |
131 | DIR *event_dir; | 218 | DIR *event_dir; |
219 | size_t len; | ||
132 | int ret = 0; | 220 | int ret = 0; |
133 | 221 | ||
134 | event_dir = opendir(dir); | 222 | event_dir = opendir(dir); |
@@ -143,13 +231,24 @@ static int pmu_aliases_parse(char *dir, struct list_head *head) | |||
143 | if (!strcmp(name, ".") || !strcmp(name, "..")) | 231 | if (!strcmp(name, ".") || !strcmp(name, "..")) |
144 | continue; | 232 | continue; |
145 | 233 | ||
234 | /* | ||
235 | * skip .unit and .scale info files | ||
236 | * parsed in perf_pmu__new_alias() | ||
237 | */ | ||
238 | len = strlen(name); | ||
239 | if (len > 5 && !strcmp(name + len - 5, ".unit")) | ||
240 | continue; | ||
241 | if (len > 6 && !strcmp(name + len - 6, ".scale")) | ||
242 | continue; | ||
243 | |||
146 | snprintf(path, PATH_MAX, "%s/%s", dir, name); | 244 | snprintf(path, PATH_MAX, "%s/%s", dir, name); |
147 | 245 | ||
148 | ret = -EINVAL; | 246 | ret = -EINVAL; |
149 | file = fopen(path, "r"); | 247 | file = fopen(path, "r"); |
150 | if (!file) | 248 | if (!file) |
151 | break; | 249 | break; |
152 | ret = perf_pmu__new_alias(head, name, file); | 250 | |
251 | ret = perf_pmu__new_alias(head, dir, name, file); | ||
153 | fclose(file); | 252 | fclose(file); |
154 | } | 253 | } |
155 | 254 | ||
@@ -406,7 +505,7 @@ static __u64 pmu_format_value(unsigned long *format, __u64 value) | |||
406 | 505 | ||
407 | /* | 506 | /* |
408 | * Setup one of config[12] attr members based on the | 507 | * Setup one of config[12] attr members based on the |
409 | * user input data - temr parameter. | 508 | * user input data - term parameter. |
410 | */ | 509 | */ |
411 | static int pmu_config_term(struct list_head *formats, | 510 | static int pmu_config_term(struct list_head *formats, |
412 | struct perf_event_attr *attr, | 511 | struct perf_event_attr *attr, |
@@ -508,16 +607,46 @@ static struct perf_pmu_alias *pmu_find_alias(struct perf_pmu *pmu, | |||
508 | return NULL; | 607 | return NULL; |
509 | } | 608 | } |
510 | 609 | ||
610 | |||
611 | static int check_unit_scale(struct perf_pmu_alias *alias, | ||
612 | const char **unit, double *scale) | ||
613 | { | ||
614 | /* | ||
615 | * Only one term in event definition can | ||
616 | * define unit and scale, fail if there's | ||
617 | * more than one. | ||
618 | */ | ||
619 | if ((*unit && alias->unit) || | ||
620 | (*scale && alias->scale)) | ||
621 | return -EINVAL; | ||
622 | |||
623 | if (alias->unit) | ||
624 | *unit = alias->unit; | ||
625 | |||
626 | if (alias->scale) | ||
627 | *scale = alias->scale; | ||
628 | |||
629 | return 0; | ||
630 | } | ||
631 | |||
511 | /* | 632 | /* |
512 | * Find alias in the terms list and replace it with the terms | 633 | * Find alias in the terms list and replace it with the terms |
513 | * defined for the alias | 634 | * defined for the alias |
514 | */ | 635 | */ |
515 | int perf_pmu__check_alias(struct perf_pmu *pmu, struct list_head *head_terms) | 636 | int perf_pmu__check_alias(struct perf_pmu *pmu, struct list_head *head_terms, |
637 | const char **unit, double *scale) | ||
516 | { | 638 | { |
517 | struct parse_events_term *term, *h; | 639 | struct parse_events_term *term, *h; |
518 | struct perf_pmu_alias *alias; | 640 | struct perf_pmu_alias *alias; |
519 | int ret; | 641 | int ret; |
520 | 642 | ||
643 | /* | ||
644 | * Mark unit and scale as not set | ||
645 | * (different from default values, see below) | ||
646 | */ | ||
647 | *unit = NULL; | ||
648 | *scale = 0.0; | ||
649 | |||
521 | list_for_each_entry_safe(term, h, head_terms, list) { | 650 | list_for_each_entry_safe(term, h, head_terms, list) { |
522 | alias = pmu_find_alias(pmu, term); | 651 | alias = pmu_find_alias(pmu, term); |
523 | if (!alias) | 652 | if (!alias) |
@@ -525,9 +654,26 @@ int perf_pmu__check_alias(struct perf_pmu *pmu, struct list_head *head_terms) | |||
525 | ret = pmu_alias_terms(alias, &term->list); | 654 | ret = pmu_alias_terms(alias, &term->list); |
526 | if (ret) | 655 | if (ret) |
527 | return ret; | 656 | return ret; |
657 | |||
658 | ret = check_unit_scale(alias, unit, scale); | ||
659 | if (ret) | ||
660 | return ret; | ||
661 | |||
528 | list_del(&term->list); | 662 | list_del(&term->list); |
529 | free(term); | 663 | free(term); |
530 | } | 664 | } |
665 | |||
666 | /* | ||
667 | * if no unit or scale foundin aliases, then | ||
668 | * set defaults as for evsel | ||
669 | * unit cannot left to NULL | ||
670 | */ | ||
671 | if (*unit == NULL) | ||
672 | *unit = ""; | ||
673 | |||
674 | if (*scale == 0.0) | ||
675 | *scale = 1.0; | ||
676 | |||
531 | return 0; | 677 | return 0; |
532 | } | 678 | } |
533 | 679 | ||
@@ -625,7 +771,7 @@ void print_pmu_events(const char *event_glob, bool name_only) | |||
625 | continue; | 771 | continue; |
626 | } | 772 | } |
627 | printf(" %-50s [Kernel PMU event]\n", aliases[j]); | 773 | printf(" %-50s [Kernel PMU event]\n", aliases[j]); |
628 | free(aliases[j]); | 774 | zfree(&aliases[j]); |
629 | printed++; | 775 | printed++; |
630 | } | 776 | } |
631 | if (printed) | 777 | if (printed) |
diff --git a/tools/perf/util/pmu.h b/tools/perf/util/pmu.h index 1179b26f244a..8b64125a9281 100644 --- a/tools/perf/util/pmu.h +++ b/tools/perf/util/pmu.h | |||
@@ -28,7 +28,8 @@ int perf_pmu__config(struct perf_pmu *pmu, struct perf_event_attr *attr, | |||
28 | int perf_pmu__config_terms(struct list_head *formats, | 28 | int perf_pmu__config_terms(struct list_head *formats, |
29 | struct perf_event_attr *attr, | 29 | struct perf_event_attr *attr, |
30 | struct list_head *head_terms); | 30 | struct list_head *head_terms); |
31 | int perf_pmu__check_alias(struct perf_pmu *pmu, struct list_head *head_terms); | 31 | int perf_pmu__check_alias(struct perf_pmu *pmu, struct list_head *head_terms, |
32 | const char **unit, double *scale); | ||
32 | struct list_head *perf_pmu__alias(struct perf_pmu *pmu, | 33 | struct list_head *perf_pmu__alias(struct perf_pmu *pmu, |
33 | struct list_head *head_terms); | 34 | struct list_head *head_terms); |
34 | int perf_pmu_wrap(void); | 35 | int perf_pmu_wrap(void); |
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c index 9c6989ca2bea..d8b048c20cde 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 <lk/debugfs.h> | 43 | #include <api/fs/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" |
@@ -72,6 +72,7 @@ static int e_snprintf(char *str, size_t size, const char *format, ...) | |||
72 | static char *synthesize_perf_probe_point(struct perf_probe_point *pp); | 72 | static char *synthesize_perf_probe_point(struct perf_probe_point *pp); |
73 | static int convert_name_to_addr(struct perf_probe_event *pev, | 73 | static int convert_name_to_addr(struct perf_probe_event *pev, |
74 | const char *exec); | 74 | const char *exec); |
75 | static void clear_probe_trace_event(struct probe_trace_event *tev); | ||
75 | static struct machine machine; | 76 | static struct machine machine; |
76 | 77 | ||
77 | /* Initialize symbol maps and path of vmlinux/modules */ | 78 | /* Initialize symbol maps and path of vmlinux/modules */ |
@@ -154,7 +155,7 @@ static struct dso *kernel_get_module_dso(const char *module) | |||
154 | 155 | ||
155 | vmlinux_name = symbol_conf.vmlinux_name; | 156 | vmlinux_name = symbol_conf.vmlinux_name; |
156 | if (vmlinux_name) { | 157 | if (vmlinux_name) { |
157 | if (dso__load_vmlinux(dso, map, vmlinux_name, NULL) <= 0) | 158 | if (dso__load_vmlinux(dso, map, vmlinux_name, false, NULL) <= 0) |
158 | return NULL; | 159 | return NULL; |
159 | } else { | 160 | } else { |
160 | if (dso__load_vmlinux_path(dso, map, NULL) <= 0) { | 161 | if (dso__load_vmlinux_path(dso, map, NULL) <= 0) { |
@@ -186,6 +187,37 @@ static int init_user_exec(void) | |||
186 | return ret; | 187 | return ret; |
187 | } | 188 | } |
188 | 189 | ||
190 | static int convert_exec_to_group(const char *exec, char **result) | ||
191 | { | ||
192 | char *ptr1, *ptr2, *exec_copy; | ||
193 | char buf[64]; | ||
194 | int ret; | ||
195 | |||
196 | exec_copy = strdup(exec); | ||
197 | if (!exec_copy) | ||
198 | return -ENOMEM; | ||
199 | |||
200 | ptr1 = basename(exec_copy); | ||
201 | if (!ptr1) { | ||
202 | ret = -EINVAL; | ||
203 | goto out; | ||
204 | } | ||
205 | |||
206 | ptr2 = strpbrk(ptr1, "-._"); | ||
207 | if (ptr2) | ||
208 | *ptr2 = '\0'; | ||
209 | ret = e_snprintf(buf, 64, "%s_%s", PERFPROBE_GROUP, ptr1); | ||
210 | if (ret < 0) | ||
211 | goto out; | ||
212 | |||
213 | *result = strdup(buf); | ||
214 | ret = *result ? 0 : -ENOMEM; | ||
215 | |||
216 | out: | ||
217 | free(exec_copy); | ||
218 | return ret; | ||
219 | } | ||
220 | |||
189 | static int convert_to_perf_probe_point(struct probe_trace_point *tp, | 221 | static int convert_to_perf_probe_point(struct probe_trace_point *tp, |
190 | struct perf_probe_point *pp) | 222 | struct perf_probe_point *pp) |
191 | { | 223 | { |
@@ -261,6 +293,68 @@ static int kprobe_convert_to_perf_probe(struct probe_trace_point *tp, | |||
261 | return 0; | 293 | return 0; |
262 | } | 294 | } |
263 | 295 | ||
296 | static int get_text_start_address(const char *exec, unsigned long *address) | ||
297 | { | ||
298 | Elf *elf; | ||
299 | GElf_Ehdr ehdr; | ||
300 | GElf_Shdr shdr; | ||
301 | int fd, ret = -ENOENT; | ||
302 | |||
303 | fd = open(exec, O_RDONLY); | ||
304 | if (fd < 0) | ||
305 | return -errno; | ||
306 | |||
307 | elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL); | ||
308 | if (elf == NULL) | ||
309 | return -EINVAL; | ||
310 | |||
311 | if (gelf_getehdr(elf, &ehdr) == NULL) | ||
312 | goto out; | ||
313 | |||
314 | if (!elf_section_by_name(elf, &ehdr, &shdr, ".text", NULL)) | ||
315 | goto out; | ||
316 | |||
317 | *address = shdr.sh_addr - shdr.sh_offset; | ||
318 | ret = 0; | ||
319 | out: | ||
320 | elf_end(elf); | ||
321 | return ret; | ||
322 | } | ||
323 | |||
324 | static int add_exec_to_probe_trace_events(struct probe_trace_event *tevs, | ||
325 | int ntevs, const char *exec) | ||
326 | { | ||
327 | int i, ret = 0; | ||
328 | unsigned long offset, stext = 0; | ||
329 | char buf[32]; | ||
330 | |||
331 | if (!exec) | ||
332 | return 0; | ||
333 | |||
334 | ret = get_text_start_address(exec, &stext); | ||
335 | if (ret < 0) | ||
336 | return ret; | ||
337 | |||
338 | for (i = 0; i < ntevs && ret >= 0; i++) { | ||
339 | /* point.address is the addres of point.symbol + point.offset */ | ||
340 | offset = tevs[i].point.address - stext; | ||
341 | tevs[i].point.offset = 0; | ||
342 | zfree(&tevs[i].point.symbol); | ||
343 | ret = e_snprintf(buf, 32, "0x%lx", offset); | ||
344 | if (ret < 0) | ||
345 | break; | ||
346 | tevs[i].point.module = strdup(exec); | ||
347 | tevs[i].point.symbol = strdup(buf); | ||
348 | if (!tevs[i].point.symbol || !tevs[i].point.module) { | ||
349 | ret = -ENOMEM; | ||
350 | break; | ||
351 | } | ||
352 | tevs[i].uprobes = true; | ||
353 | } | ||
354 | |||
355 | return ret; | ||
356 | } | ||
357 | |||
264 | static int add_module_to_probe_trace_events(struct probe_trace_event *tevs, | 358 | static int add_module_to_probe_trace_events(struct probe_trace_event *tevs, |
265 | int ntevs, const char *module) | 359 | int ntevs, const char *module) |
266 | { | 360 | { |
@@ -290,12 +384,18 @@ static int add_module_to_probe_trace_events(struct probe_trace_event *tevs, | |||
290 | } | 384 | } |
291 | } | 385 | } |
292 | 386 | ||
293 | if (tmp) | 387 | free(tmp); |
294 | free(tmp); | ||
295 | |||
296 | return ret; | 388 | return ret; |
297 | } | 389 | } |
298 | 390 | ||
391 | static void clear_probe_trace_events(struct probe_trace_event *tevs, int ntevs) | ||
392 | { | ||
393 | int i; | ||
394 | |||
395 | for (i = 0; i < ntevs; i++) | ||
396 | clear_probe_trace_event(tevs + i); | ||
397 | } | ||
398 | |||
299 | /* Try to find perf_probe_event with debuginfo */ | 399 | /* Try to find perf_probe_event with debuginfo */ |
300 | static int try_to_find_probe_trace_events(struct perf_probe_event *pev, | 400 | static int try_to_find_probe_trace_events(struct perf_probe_event *pev, |
301 | struct probe_trace_event **tevs, | 401 | struct probe_trace_event **tevs, |
@@ -305,15 +405,6 @@ static int try_to_find_probe_trace_events(struct perf_probe_event *pev, | |||
305 | struct debuginfo *dinfo; | 405 | struct debuginfo *dinfo; |
306 | int ntevs, ret = 0; | 406 | int ntevs, ret = 0; |
307 | 407 | ||
308 | if (pev->uprobes) { | ||
309 | if (need_dwarf) { | ||
310 | pr_warning("Debuginfo-analysis is not yet supported" | ||
311 | " with -x/--exec option.\n"); | ||
312 | return -ENOSYS; | ||
313 | } | ||
314 | return convert_name_to_addr(pev, target); | ||
315 | } | ||
316 | |||
317 | dinfo = open_debuginfo(target); | 408 | dinfo = open_debuginfo(target); |
318 | 409 | ||
319 | if (!dinfo) { | 410 | if (!dinfo) { |
@@ -332,9 +423,18 @@ static int try_to_find_probe_trace_events(struct perf_probe_event *pev, | |||
332 | 423 | ||
333 | if (ntevs > 0) { /* Succeeded to find trace events */ | 424 | if (ntevs > 0) { /* Succeeded to find trace events */ |
334 | pr_debug("find %d probe_trace_events.\n", ntevs); | 425 | pr_debug("find %d probe_trace_events.\n", ntevs); |
335 | if (target) | 426 | if (target) { |
336 | ret = add_module_to_probe_trace_events(*tevs, ntevs, | 427 | if (pev->uprobes) |
337 | target); | 428 | ret = add_exec_to_probe_trace_events(*tevs, |
429 | ntevs, target); | ||
430 | else | ||
431 | ret = add_module_to_probe_trace_events(*tevs, | ||
432 | ntevs, target); | ||
433 | } | ||
434 | if (ret < 0) { | ||
435 | clear_probe_trace_events(*tevs, ntevs); | ||
436 | zfree(tevs); | ||
437 | } | ||
338 | return ret < 0 ? ret : ntevs; | 438 | return ret < 0 ? ret : ntevs; |
339 | } | 439 | } |
340 | 440 | ||
@@ -401,15 +501,13 @@ static int get_real_path(const char *raw_path, const char *comp_dir, | |||
401 | case EFAULT: | 501 | case EFAULT: |
402 | raw_path = strchr(++raw_path, '/'); | 502 | raw_path = strchr(++raw_path, '/'); |
403 | if (!raw_path) { | 503 | if (!raw_path) { |
404 | free(*new_path); | 504 | zfree(new_path); |
405 | *new_path = NULL; | ||
406 | return -ENOENT; | 505 | return -ENOENT; |
407 | } | 506 | } |
408 | continue; | 507 | continue; |
409 | 508 | ||
410 | default: | 509 | default: |
411 | free(*new_path); | 510 | zfree(new_path); |
412 | *new_path = NULL; | ||
413 | return -errno; | 511 | return -errno; |
414 | } | 512 | } |
415 | } | 513 | } |
@@ -580,7 +678,7 @@ static int show_available_vars_at(struct debuginfo *dinfo, | |||
580 | */ | 678 | */ |
581 | fprintf(stdout, "\t@<%s+%lu>\n", vl->point.symbol, | 679 | fprintf(stdout, "\t@<%s+%lu>\n", vl->point.symbol, |
582 | vl->point.offset); | 680 | vl->point.offset); |
583 | free(vl->point.symbol); | 681 | zfree(&vl->point.symbol); |
584 | nvars = 0; | 682 | nvars = 0; |
585 | if (vl->vars) { | 683 | if (vl->vars) { |
586 | strlist__for_each(node, vl->vars) { | 684 | strlist__for_each(node, vl->vars) { |
@@ -647,16 +745,14 @@ static int kprobe_convert_to_perf_probe(struct probe_trace_point *tp, | |||
647 | 745 | ||
648 | static int try_to_find_probe_trace_events(struct perf_probe_event *pev, | 746 | static int try_to_find_probe_trace_events(struct perf_probe_event *pev, |
649 | struct probe_trace_event **tevs __maybe_unused, | 747 | struct probe_trace_event **tevs __maybe_unused, |
650 | int max_tevs __maybe_unused, const char *target) | 748 | int max_tevs __maybe_unused, |
749 | const char *target __maybe_unused) | ||
651 | { | 750 | { |
652 | if (perf_probe_event_need_dwarf(pev)) { | 751 | if (perf_probe_event_need_dwarf(pev)) { |
653 | pr_warning("Debuginfo-analysis is not supported.\n"); | 752 | pr_warning("Debuginfo-analysis is not supported.\n"); |
654 | return -ENOSYS; | 753 | return -ENOSYS; |
655 | } | 754 | } |
656 | 755 | ||
657 | if (pev->uprobes) | ||
658 | return convert_name_to_addr(pev, target); | ||
659 | |||
660 | return 0; | 756 | return 0; |
661 | } | 757 | } |
662 | 758 | ||
@@ -678,6 +774,28 @@ int show_available_vars(struct perf_probe_event *pevs __maybe_unused, | |||
678 | } | 774 | } |
679 | #endif | 775 | #endif |
680 | 776 | ||
777 | void line_range__clear(struct line_range *lr) | ||
778 | { | ||
779 | struct line_node *ln; | ||
780 | |||
781 | free(lr->function); | ||
782 | free(lr->file); | ||
783 | free(lr->path); | ||
784 | free(lr->comp_dir); | ||
785 | while (!list_empty(&lr->line_list)) { | ||
786 | ln = list_first_entry(&lr->line_list, struct line_node, list); | ||
787 | list_del(&ln->list); | ||
788 | free(ln); | ||
789 | } | ||
790 | memset(lr, 0, sizeof(*lr)); | ||
791 | } | ||
792 | |||
793 | void line_range__init(struct line_range *lr) | ||
794 | { | ||
795 | memset(lr, 0, sizeof(*lr)); | ||
796 | INIT_LIST_HEAD(&lr->line_list); | ||
797 | } | ||
798 | |||
681 | static int parse_line_num(char **ptr, int *val, const char *what) | 799 | static int parse_line_num(char **ptr, int *val, const char *what) |
682 | { | 800 | { |
683 | const char *start = *ptr; | 801 | const char *start = *ptr; |
@@ -1278,8 +1396,7 @@ static char *synthesize_perf_probe_point(struct perf_probe_point *pp) | |||
1278 | error: | 1396 | error: |
1279 | pr_debug("Failed to synthesize perf probe point: %s\n", | 1397 | pr_debug("Failed to synthesize perf probe point: %s\n", |
1280 | strerror(-ret)); | 1398 | strerror(-ret)); |
1281 | if (buf) | 1399 | free(buf); |
1282 | free(buf); | ||
1283 | return NULL; | 1400 | return NULL; |
1284 | } | 1401 | } |
1285 | 1402 | ||
@@ -1480,34 +1597,25 @@ void clear_perf_probe_event(struct perf_probe_event *pev) | |||
1480 | struct perf_probe_arg_field *field, *next; | 1597 | struct perf_probe_arg_field *field, *next; |
1481 | int i; | 1598 | int i; |
1482 | 1599 | ||
1483 | if (pev->event) | 1600 | free(pev->event); |
1484 | free(pev->event); | 1601 | free(pev->group); |
1485 | if (pev->group) | 1602 | free(pp->file); |
1486 | free(pev->group); | 1603 | free(pp->function); |
1487 | if (pp->file) | 1604 | free(pp->lazy_line); |
1488 | free(pp->file); | 1605 | |
1489 | if (pp->function) | ||
1490 | free(pp->function); | ||
1491 | if (pp->lazy_line) | ||
1492 | free(pp->lazy_line); | ||
1493 | for (i = 0; i < pev->nargs; i++) { | 1606 | for (i = 0; i < pev->nargs; i++) { |
1494 | if (pev->args[i].name) | 1607 | free(pev->args[i].name); |
1495 | free(pev->args[i].name); | 1608 | free(pev->args[i].var); |
1496 | if (pev->args[i].var) | 1609 | free(pev->args[i].type); |
1497 | free(pev->args[i].var); | ||
1498 | if (pev->args[i].type) | ||
1499 | free(pev->args[i].type); | ||
1500 | field = pev->args[i].field; | 1610 | field = pev->args[i].field; |
1501 | while (field) { | 1611 | while (field) { |
1502 | next = field->next; | 1612 | next = field->next; |
1503 | if (field->name) | 1613 | zfree(&field->name); |
1504 | free(field->name); | ||
1505 | free(field); | 1614 | free(field); |
1506 | field = next; | 1615 | field = next; |
1507 | } | 1616 | } |
1508 | } | 1617 | } |
1509 | if (pev->args) | 1618 | free(pev->args); |
1510 | free(pev->args); | ||
1511 | memset(pev, 0, sizeof(*pev)); | 1619 | memset(pev, 0, sizeof(*pev)); |
1512 | } | 1620 | } |
1513 | 1621 | ||
@@ -1516,21 +1624,14 @@ static void clear_probe_trace_event(struct probe_trace_event *tev) | |||
1516 | struct probe_trace_arg_ref *ref, *next; | 1624 | struct probe_trace_arg_ref *ref, *next; |
1517 | int i; | 1625 | int i; |
1518 | 1626 | ||
1519 | if (tev->event) | 1627 | free(tev->event); |
1520 | free(tev->event); | 1628 | free(tev->group); |
1521 | if (tev->group) | 1629 | free(tev->point.symbol); |
1522 | free(tev->group); | 1630 | free(tev->point.module); |
1523 | if (tev->point.symbol) | ||
1524 | free(tev->point.symbol); | ||
1525 | if (tev->point.module) | ||
1526 | free(tev->point.module); | ||
1527 | for (i = 0; i < tev->nargs; i++) { | 1631 | for (i = 0; i < tev->nargs; i++) { |
1528 | if (tev->args[i].name) | 1632 | free(tev->args[i].name); |
1529 | free(tev->args[i].name); | 1633 | free(tev->args[i].value); |
1530 | if (tev->args[i].value) | 1634 | free(tev->args[i].type); |
1531 | free(tev->args[i].value); | ||
1532 | if (tev->args[i].type) | ||
1533 | free(tev->args[i].type); | ||
1534 | ref = tev->args[i].ref; | 1635 | ref = tev->args[i].ref; |
1535 | while (ref) { | 1636 | while (ref) { |
1536 | next = ref->next; | 1637 | next = ref->next; |
@@ -1538,8 +1639,7 @@ static void clear_probe_trace_event(struct probe_trace_event *tev) | |||
1538 | ref = next; | 1639 | ref = next; |
1539 | } | 1640 | } |
1540 | } | 1641 | } |
1541 | if (tev->args) | 1642 | free(tev->args); |
1542 | free(tev->args); | ||
1543 | memset(tev, 0, sizeof(*tev)); | 1643 | memset(tev, 0, sizeof(*tev)); |
1544 | } | 1644 | } |
1545 | 1645 | ||
@@ -1913,14 +2013,29 @@ static int convert_to_probe_trace_events(struct perf_probe_event *pev, | |||
1913 | int max_tevs, const char *target) | 2013 | int max_tevs, const char *target) |
1914 | { | 2014 | { |
1915 | struct symbol *sym; | 2015 | struct symbol *sym; |
1916 | int ret = 0, i; | 2016 | int ret, i; |
1917 | struct probe_trace_event *tev; | 2017 | struct probe_trace_event *tev; |
1918 | 2018 | ||
2019 | if (pev->uprobes && !pev->group) { | ||
2020 | /* Replace group name if not given */ | ||
2021 | ret = convert_exec_to_group(target, &pev->group); | ||
2022 | if (ret != 0) { | ||
2023 | pr_warning("Failed to make a group name.\n"); | ||
2024 | return ret; | ||
2025 | } | ||
2026 | } | ||
2027 | |||
1919 | /* Convert perf_probe_event with debuginfo */ | 2028 | /* Convert perf_probe_event with debuginfo */ |
1920 | ret = try_to_find_probe_trace_events(pev, tevs, max_tevs, target); | 2029 | ret = try_to_find_probe_trace_events(pev, tevs, max_tevs, target); |
1921 | if (ret != 0) | 2030 | if (ret != 0) |
1922 | return ret; /* Found in debuginfo or got an error */ | 2031 | return ret; /* Found in debuginfo or got an error */ |
1923 | 2032 | ||
2033 | if (pev->uprobes) { | ||
2034 | ret = convert_name_to_addr(pev, target); | ||
2035 | if (ret < 0) | ||
2036 | return ret; | ||
2037 | } | ||
2038 | |||
1924 | /* Allocate trace event buffer */ | 2039 | /* Allocate trace event buffer */ |
1925 | tev = *tevs = zalloc(sizeof(struct probe_trace_event)); | 2040 | tev = *tevs = zalloc(sizeof(struct probe_trace_event)); |
1926 | if (tev == NULL) | 2041 | if (tev == NULL) |
@@ -2056,7 +2171,7 @@ end: | |||
2056 | for (i = 0; i < npevs; i++) { | 2171 | for (i = 0; i < npevs; i++) { |
2057 | for (j = 0; j < pkgs[i].ntevs; j++) | 2172 | for (j = 0; j < pkgs[i].ntevs; j++) |
2058 | clear_probe_trace_event(&pkgs[i].tevs[j]); | 2173 | clear_probe_trace_event(&pkgs[i].tevs[j]); |
2059 | free(pkgs[i].tevs); | 2174 | zfree(&pkgs[i].tevs); |
2060 | } | 2175 | } |
2061 | free(pkgs); | 2176 | free(pkgs); |
2062 | 2177 | ||
@@ -2281,7 +2396,7 @@ static int convert_name_to_addr(struct perf_probe_event *pev, const char *exec) | |||
2281 | struct perf_probe_point *pp = &pev->point; | 2396 | struct perf_probe_point *pp = &pev->point; |
2282 | struct symbol *sym; | 2397 | struct symbol *sym; |
2283 | struct map *map = NULL; | 2398 | struct map *map = NULL; |
2284 | char *function = NULL, *name = NULL; | 2399 | char *function = NULL; |
2285 | int ret = -EINVAL; | 2400 | int ret = -EINVAL; |
2286 | unsigned long long vaddr = 0; | 2401 | unsigned long long vaddr = 0; |
2287 | 2402 | ||
@@ -2297,12 +2412,7 @@ static int convert_name_to_addr(struct perf_probe_event *pev, const char *exec) | |||
2297 | goto out; | 2412 | goto out; |
2298 | } | 2413 | } |
2299 | 2414 | ||
2300 | name = realpath(exec, NULL); | 2415 | map = dso__new_map(exec); |
2301 | if (!name) { | ||
2302 | pr_warning("Cannot find realpath for %s.\n", exec); | ||
2303 | goto out; | ||
2304 | } | ||
2305 | map = dso__new_map(name); | ||
2306 | if (!map) { | 2416 | if (!map) { |
2307 | pr_warning("Cannot find appropriate DSO for %s.\n", exec); | 2417 | pr_warning("Cannot find appropriate DSO for %s.\n", exec); |
2308 | goto out; | 2418 | goto out; |
@@ -2367,7 +2477,5 @@ out: | |||
2367 | } | 2477 | } |
2368 | if (function) | 2478 | if (function) |
2369 | free(function); | 2479 | free(function); |
2370 | if (name) | ||
2371 | free(name); | ||
2372 | return ret; | 2480 | return ret; |
2373 | } | 2481 | } |
diff --git a/tools/perf/util/probe-event.h b/tools/perf/util/probe-event.h index f9f3de8b4220..fcaf7273e85a 100644 --- a/tools/perf/util/probe-event.h +++ b/tools/perf/util/probe-event.h | |||
@@ -12,6 +12,7 @@ struct probe_trace_point { | |||
12 | char *symbol; /* Base symbol */ | 12 | char *symbol; /* Base symbol */ |
13 | char *module; /* Module name */ | 13 | char *module; /* Module name */ |
14 | unsigned long offset; /* Offset from symbol */ | 14 | unsigned long offset; /* Offset from symbol */ |
15 | unsigned long address; /* Actual address of the trace point */ | ||
15 | bool retprobe; /* Return probe flag */ | 16 | bool retprobe; /* Return probe flag */ |
16 | }; | 17 | }; |
17 | 18 | ||
@@ -119,6 +120,12 @@ extern void clear_perf_probe_event(struct perf_probe_event *pev); | |||
119 | /* Command string to line-range */ | 120 | /* Command string to line-range */ |
120 | extern int parse_line_range_desc(const char *cmd, struct line_range *lr); | 121 | extern int parse_line_range_desc(const char *cmd, struct line_range *lr); |
121 | 122 | ||
123 | /* Release line range members */ | ||
124 | extern void line_range__clear(struct line_range *lr); | ||
125 | |||
126 | /* Initialize line range */ | ||
127 | extern void line_range__init(struct line_range *lr); | ||
128 | |||
122 | /* Internal use: Return kernel/module path */ | 129 | /* Internal use: Return kernel/module path */ |
123 | extern const char *kernel_get_module_path(const char *module); | 130 | extern const char *kernel_get_module_path(const char *module); |
124 | 131 | ||
diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c index ffb657ffd327..061edb162b5b 100644 --- a/tools/perf/util/probe-finder.c +++ b/tools/perf/util/probe-finder.c | |||
@@ -226,10 +226,8 @@ struct debuginfo *debuginfo__new(const char *path) | |||
226 | if (!dbg) | 226 | if (!dbg) |
227 | return NULL; | 227 | return NULL; |
228 | 228 | ||
229 | if (debuginfo__init_offline_dwarf(dbg, path) < 0) { | 229 | if (debuginfo__init_offline_dwarf(dbg, path) < 0) |
230 | free(dbg); | 230 | zfree(&dbg); |
231 | dbg = NULL; | ||
232 | } | ||
233 | 231 | ||
234 | return dbg; | 232 | return dbg; |
235 | } | 233 | } |
@@ -241,10 +239,8 @@ struct debuginfo *debuginfo__new_online_kernel(unsigned long addr) | |||
241 | if (!dbg) | 239 | if (!dbg) |
242 | return NULL; | 240 | return NULL; |
243 | 241 | ||
244 | if (debuginfo__init_online_kernel_dwarf(dbg, (Dwarf_Addr)addr) < 0) { | 242 | if (debuginfo__init_online_kernel_dwarf(dbg, (Dwarf_Addr)addr) < 0) |
245 | free(dbg); | 243 | zfree(&dbg); |
246 | dbg = NULL; | ||
247 | } | ||
248 | 244 | ||
249 | return dbg; | 245 | return dbg; |
250 | } | 246 | } |
@@ -729,6 +725,7 @@ static int convert_to_trace_point(Dwarf_Die *sp_die, Dwfl_Module *mod, | |||
729 | return -ENOENT; | 725 | return -ENOENT; |
730 | } | 726 | } |
731 | tp->offset = (unsigned long)(paddr - sym.st_value); | 727 | tp->offset = (unsigned long)(paddr - sym.st_value); |
728 | tp->address = (unsigned long)paddr; | ||
732 | tp->symbol = strdup(symbol); | 729 | tp->symbol = strdup(symbol); |
733 | if (!tp->symbol) | 730 | if (!tp->symbol) |
734 | return -ENOMEM; | 731 | return -ENOMEM; |
@@ -1301,8 +1298,7 @@ int debuginfo__find_trace_events(struct debuginfo *dbg, | |||
1301 | 1298 | ||
1302 | ret = debuginfo__find_probes(dbg, &tf.pf); | 1299 | ret = debuginfo__find_probes(dbg, &tf.pf); |
1303 | if (ret < 0) { | 1300 | if (ret < 0) { |
1304 | free(*tevs); | 1301 | zfree(tevs); |
1305 | *tevs = NULL; | ||
1306 | return ret; | 1302 | return ret; |
1307 | } | 1303 | } |
1308 | 1304 | ||
@@ -1413,13 +1409,10 @@ int debuginfo__find_available_vars_at(struct debuginfo *dbg, | |||
1413 | if (ret < 0) { | 1409 | if (ret < 0) { |
1414 | /* Free vlist for error */ | 1410 | /* Free vlist for error */ |
1415 | while (af.nvls--) { | 1411 | while (af.nvls--) { |
1416 | if (af.vls[af.nvls].point.symbol) | 1412 | zfree(&af.vls[af.nvls].point.symbol); |
1417 | free(af.vls[af.nvls].point.symbol); | 1413 | strlist__delete(af.vls[af.nvls].vars); |
1418 | if (af.vls[af.nvls].vars) | ||
1419 | strlist__delete(af.vls[af.nvls].vars); | ||
1420 | } | 1414 | } |
1421 | free(af.vls); | 1415 | zfree(vls); |
1422 | *vls = NULL; | ||
1423 | return ret; | 1416 | return ret; |
1424 | } | 1417 | } |
1425 | 1418 | ||
@@ -1523,10 +1516,7 @@ post: | |||
1523 | if (fname) { | 1516 | if (fname) { |
1524 | ppt->file = strdup(fname); | 1517 | ppt->file = strdup(fname); |
1525 | if (ppt->file == NULL) { | 1518 | if (ppt->file == NULL) { |
1526 | if (ppt->function) { | 1519 | zfree(&ppt->function); |
1527 | free(ppt->function); | ||
1528 | ppt->function = NULL; | ||
1529 | } | ||
1530 | ret = -ENOMEM; | 1520 | ret = -ENOMEM; |
1531 | goto end; | 1521 | goto end; |
1532 | } | 1522 | } |
@@ -1580,8 +1570,7 @@ static int find_line_range_by_line(Dwarf_Die *sp_die, struct line_finder *lf) | |||
1580 | else | 1570 | else |
1581 | ret = 0; /* Lines are not found */ | 1571 | ret = 0; /* Lines are not found */ |
1582 | else { | 1572 | else { |
1583 | free(lf->lr->path); | 1573 | zfree(&lf->lr->path); |
1584 | lf->lr->path = NULL; | ||
1585 | } | 1574 | } |
1586 | return ret; | 1575 | return ret; |
1587 | } | 1576 | } |
diff --git a/tools/perf/util/python-ext-sources b/tools/perf/util/python-ext-sources index 239036fb2b2c..595bfc73d2ed 100644 --- a/tools/perf/util/python-ext-sources +++ b/tools/perf/util/python-ext-sources | |||
@@ -18,4 +18,5 @@ util/cgroup.c | |||
18 | util/rblist.c | 18 | util/rblist.c |
19 | util/strlist.c | 19 | util/strlist.c |
20 | util/fs.c | 20 | util/fs.c |
21 | util/trace-event.c | ||
21 | ../../lib/rbtree.c | 22 | ../../lib/rbtree.c |
diff --git a/tools/perf/util/python.c b/tools/perf/util/python.c index 4bf8ace7f511..122669c18ff4 100644 --- a/tools/perf/util/python.c +++ b/tools/perf/util/python.c | |||
@@ -908,9 +908,10 @@ static PyObject *pyrf_evlist__item(PyObject *obj, Py_ssize_t i) | |||
908 | if (i >= pevlist->evlist.nr_entries) | 908 | if (i >= pevlist->evlist.nr_entries) |
909 | return NULL; | 909 | return NULL; |
910 | 910 | ||
911 | list_for_each_entry(pos, &pevlist->evlist.entries, node) | 911 | evlist__for_each(&pevlist->evlist, pos) { |
912 | if (i-- == 0) | 912 | if (i-- == 0) |
913 | break; | 913 | break; |
914 | } | ||
914 | 915 | ||
915 | return Py_BuildValue("O", container_of(pos, struct pyrf_evsel, evsel)); | 916 | return Py_BuildValue("O", container_of(pos, struct pyrf_evsel, evsel)); |
916 | } | 917 | } |
diff --git a/tools/perf/util/record.c b/tools/perf/util/record.c index c8845b107f60..373762501dad 100644 --- a/tools/perf/util/record.c +++ b/tools/perf/util/record.c | |||
@@ -74,8 +74,7 @@ bool perf_can_sample_identifier(void) | |||
74 | return perf_probe_api(perf_probe_sample_identifier); | 74 | return perf_probe_api(perf_probe_sample_identifier); |
75 | } | 75 | } |
76 | 76 | ||
77 | void perf_evlist__config(struct perf_evlist *evlist, | 77 | void perf_evlist__config(struct perf_evlist *evlist, struct record_opts *opts) |
78 | struct perf_record_opts *opts) | ||
79 | { | 78 | { |
80 | struct perf_evsel *evsel; | 79 | struct perf_evsel *evsel; |
81 | bool use_sample_identifier = false; | 80 | bool use_sample_identifier = false; |
@@ -90,19 +89,19 @@ void perf_evlist__config(struct perf_evlist *evlist, | |||
90 | if (evlist->cpus->map[0] < 0) | 89 | if (evlist->cpus->map[0] < 0) |
91 | opts->no_inherit = true; | 90 | opts->no_inherit = true; |
92 | 91 | ||
93 | list_for_each_entry(evsel, &evlist->entries, node) | 92 | evlist__for_each(evlist, evsel) |
94 | perf_evsel__config(evsel, opts); | 93 | perf_evsel__config(evsel, opts); |
95 | 94 | ||
96 | if (evlist->nr_entries > 1) { | 95 | if (evlist->nr_entries > 1) { |
97 | struct perf_evsel *first = perf_evlist__first(evlist); | 96 | struct perf_evsel *first = perf_evlist__first(evlist); |
98 | 97 | ||
99 | list_for_each_entry(evsel, &evlist->entries, node) { | 98 | evlist__for_each(evlist, evsel) { |
100 | if (evsel->attr.sample_type == first->attr.sample_type) | 99 | if (evsel->attr.sample_type == first->attr.sample_type) |
101 | continue; | 100 | continue; |
102 | use_sample_identifier = perf_can_sample_identifier(); | 101 | use_sample_identifier = perf_can_sample_identifier(); |
103 | break; | 102 | break; |
104 | } | 103 | } |
105 | list_for_each_entry(evsel, &evlist->entries, node) | 104 | evlist__for_each(evlist, evsel) |
106 | perf_evsel__set_sample_id(evsel, use_sample_identifier); | 105 | perf_evsel__set_sample_id(evsel, use_sample_identifier); |
107 | } | 106 | } |
108 | 107 | ||
@@ -123,7 +122,7 @@ static int get_max_rate(unsigned int *rate) | |||
123 | return filename__read_int(path, (int *) rate); | 122 | return filename__read_int(path, (int *) rate); |
124 | } | 123 | } |
125 | 124 | ||
126 | static int perf_record_opts__config_freq(struct perf_record_opts *opts) | 125 | static int record_opts__config_freq(struct record_opts *opts) |
127 | { | 126 | { |
128 | bool user_freq = opts->user_freq != UINT_MAX; | 127 | bool user_freq = opts->user_freq != UINT_MAX; |
129 | unsigned int max_rate; | 128 | unsigned int max_rate; |
@@ -173,7 +172,44 @@ static int perf_record_opts__config_freq(struct perf_record_opts *opts) | |||
173 | return 0; | 172 | return 0; |
174 | } | 173 | } |
175 | 174 | ||
176 | int perf_record_opts__config(struct perf_record_opts *opts) | 175 | int record_opts__config(struct record_opts *opts) |
177 | { | 176 | { |
178 | return perf_record_opts__config_freq(opts); | 177 | return record_opts__config_freq(opts); |
178 | } | ||
179 | |||
180 | bool perf_evlist__can_select_event(struct perf_evlist *evlist, const char *str) | ||
181 | { | ||
182 | struct perf_evlist *temp_evlist; | ||
183 | struct perf_evsel *evsel; | ||
184 | int err, fd, cpu; | ||
185 | bool ret = false; | ||
186 | |||
187 | temp_evlist = perf_evlist__new(); | ||
188 | if (!temp_evlist) | ||
189 | return false; | ||
190 | |||
191 | err = parse_events(temp_evlist, str); | ||
192 | if (err) | ||
193 | goto out_delete; | ||
194 | |||
195 | evsel = perf_evlist__last(temp_evlist); | ||
196 | |||
197 | if (!evlist || cpu_map__empty(evlist->cpus)) { | ||
198 | struct cpu_map *cpus = cpu_map__new(NULL); | ||
199 | |||
200 | cpu = cpus ? cpus->map[0] : 0; | ||
201 | cpu_map__delete(cpus); | ||
202 | } else { | ||
203 | cpu = evlist->cpus->map[0]; | ||
204 | } | ||
205 | |||
206 | fd = sys_perf_event_open(&evsel->attr, -1, cpu, -1, 0); | ||
207 | if (fd >= 0) { | ||
208 | close(fd); | ||
209 | ret = true; | ||
210 | } | ||
211 | |||
212 | out_delete: | ||
213 | perf_evlist__delete(temp_evlist); | ||
214 | return ret; | ||
179 | } | 215 | } |
diff --git a/tools/perf/util/scripting-engines/trace-event-perl.c b/tools/perf/util/scripting-engines/trace-event-perl.c index d5e5969f6fea..e108207c5de0 100644 --- a/tools/perf/util/scripting-engines/trace-event-perl.c +++ b/tools/perf/util/scripting-engines/trace-event-perl.c | |||
@@ -194,8 +194,7 @@ static void define_event_symbols(struct event_format *event, | |||
194 | zero_flag_atom = 0; | 194 | zero_flag_atom = 0; |
195 | break; | 195 | break; |
196 | case PRINT_FIELD: | 196 | case PRINT_FIELD: |
197 | if (cur_field_name) | 197 | free(cur_field_name); |
198 | free(cur_field_name); | ||
199 | cur_field_name = strdup(args->field.name); | 198 | cur_field_name = strdup(args->field.name); |
200 | break; | 199 | break; |
201 | case PRINT_FLAGS: | 200 | case PRINT_FLAGS: |
@@ -257,12 +256,9 @@ static inline struct event_format *find_cache_event(struct perf_evsel *evsel) | |||
257 | return event; | 256 | return event; |
258 | } | 257 | } |
259 | 258 | ||
260 | static void perl_process_tracepoint(union perf_event *perf_event __maybe_unused, | 259 | static void perl_process_tracepoint(struct perf_sample *sample, |
261 | struct perf_sample *sample, | ||
262 | struct perf_evsel *evsel, | 260 | struct perf_evsel *evsel, |
263 | struct machine *machine __maybe_unused, | 261 | struct thread *thread) |
264 | struct thread *thread, | ||
265 | struct addr_location *al) | ||
266 | { | 262 | { |
267 | struct format_field *field; | 263 | struct format_field *field; |
268 | static char handler[256]; | 264 | static char handler[256]; |
@@ -349,10 +345,7 @@ static void perl_process_tracepoint(union perf_event *perf_event __maybe_unused, | |||
349 | 345 | ||
350 | static void perl_process_event_generic(union perf_event *event, | 346 | static void perl_process_event_generic(union perf_event *event, |
351 | struct perf_sample *sample, | 347 | struct perf_sample *sample, |
352 | struct perf_evsel *evsel, | 348 | struct perf_evsel *evsel) |
353 | struct machine *machine __maybe_unused, | ||
354 | struct thread *thread __maybe_unused, | ||
355 | struct addr_location *al __maybe_unused) | ||
356 | { | 349 | { |
357 | dSP; | 350 | dSP; |
358 | 351 | ||
@@ -377,12 +370,11 @@ static void perl_process_event_generic(union perf_event *event, | |||
377 | static void perl_process_event(union perf_event *event, | 370 | static void perl_process_event(union perf_event *event, |
378 | struct perf_sample *sample, | 371 | struct perf_sample *sample, |
379 | struct perf_evsel *evsel, | 372 | struct perf_evsel *evsel, |
380 | struct machine *machine, | ||
381 | struct thread *thread, | 373 | struct thread *thread, |
382 | struct addr_location *al) | 374 | struct addr_location *al __maybe_unused) |
383 | { | 375 | { |
384 | perl_process_tracepoint(event, sample, evsel, machine, thread, al); | 376 | perl_process_tracepoint(sample, evsel, thread); |
385 | perl_process_event_generic(event, sample, evsel, machine, thread, al); | 377 | perl_process_event_generic(event, sample, evsel); |
386 | } | 378 | } |
387 | 379 | ||
388 | static void run_start_sub(void) | 380 | static void run_start_sub(void) |
diff --git a/tools/perf/util/scripting-engines/trace-event-python.c b/tools/perf/util/scripting-engines/trace-event-python.c index 53c20e7fd900..cd9774df3750 100644 --- a/tools/perf/util/scripting-engines/trace-event-python.c +++ b/tools/perf/util/scripting-engines/trace-event-python.c | |||
@@ -161,8 +161,7 @@ static void define_event_symbols(struct event_format *event, | |||
161 | zero_flag_atom = 0; | 161 | zero_flag_atom = 0; |
162 | break; | 162 | break; |
163 | case PRINT_FIELD: | 163 | case PRINT_FIELD: |
164 | if (cur_field_name) | 164 | free(cur_field_name); |
165 | free(cur_field_name); | ||
166 | cur_field_name = strdup(args->field.name); | 165 | cur_field_name = strdup(args->field.name); |
167 | break; | 166 | break; |
168 | case PRINT_FLAGS: | 167 | case PRINT_FLAGS: |
@@ -231,13 +230,10 @@ static inline struct event_format *find_cache_event(struct perf_evsel *evsel) | |||
231 | return event; | 230 | return event; |
232 | } | 231 | } |
233 | 232 | ||
234 | static void python_process_tracepoint(union perf_event *perf_event | 233 | static void python_process_tracepoint(struct perf_sample *sample, |
235 | __maybe_unused, | 234 | struct perf_evsel *evsel, |
236 | struct perf_sample *sample, | 235 | struct thread *thread, |
237 | struct perf_evsel *evsel, | 236 | struct addr_location *al) |
238 | struct machine *machine __maybe_unused, | ||
239 | struct thread *thread, | ||
240 | struct addr_location *al) | ||
241 | { | 237 | { |
242 | PyObject *handler, *retval, *context, *t, *obj, *dict = NULL; | 238 | PyObject *handler, *retval, *context, *t, *obj, *dict = NULL; |
243 | static char handler_name[256]; | 239 | static char handler_name[256]; |
@@ -351,11 +347,8 @@ static void python_process_tracepoint(union perf_event *perf_event | |||
351 | Py_DECREF(t); | 347 | Py_DECREF(t); |
352 | } | 348 | } |
353 | 349 | ||
354 | static void python_process_general_event(union perf_event *perf_event | 350 | static void python_process_general_event(struct perf_sample *sample, |
355 | __maybe_unused, | ||
356 | struct perf_sample *sample, | ||
357 | struct perf_evsel *evsel, | 351 | struct perf_evsel *evsel, |
358 | struct machine *machine __maybe_unused, | ||
359 | struct thread *thread, | 352 | struct thread *thread, |
360 | struct addr_location *al) | 353 | struct addr_location *al) |
361 | { | 354 | { |
@@ -411,22 +404,19 @@ exit: | |||
411 | Py_DECREF(t); | 404 | Py_DECREF(t); |
412 | } | 405 | } |
413 | 406 | ||
414 | static void python_process_event(union perf_event *perf_event, | 407 | static void python_process_event(union perf_event *event __maybe_unused, |
415 | struct perf_sample *sample, | 408 | struct perf_sample *sample, |
416 | struct perf_evsel *evsel, | 409 | struct perf_evsel *evsel, |
417 | struct machine *machine, | ||
418 | struct thread *thread, | 410 | struct thread *thread, |
419 | struct addr_location *al) | 411 | struct addr_location *al) |
420 | { | 412 | { |
421 | switch (evsel->attr.type) { | 413 | switch (evsel->attr.type) { |
422 | case PERF_TYPE_TRACEPOINT: | 414 | case PERF_TYPE_TRACEPOINT: |
423 | python_process_tracepoint(perf_event, sample, evsel, | 415 | python_process_tracepoint(sample, evsel, thread, al); |
424 | machine, thread, al); | ||
425 | break; | 416 | break; |
426 | /* Reserve for future process_hw/sw/raw APIs */ | 417 | /* Reserve for future process_hw/sw/raw APIs */ |
427 | default: | 418 | default: |
428 | python_process_general_event(perf_event, sample, evsel, | 419 | python_process_general_event(sample, evsel, thread, al); |
429 | machine, thread, al); | ||
430 | } | 420 | } |
431 | } | 421 | } |
432 | 422 | ||
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index f36d24a02445..5da6ce74c676 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c | |||
@@ -132,18 +132,18 @@ static void perf_session__delete_threads(struct perf_session *session) | |||
132 | 132 | ||
133 | static void perf_session_env__delete(struct perf_session_env *env) | 133 | static void perf_session_env__delete(struct perf_session_env *env) |
134 | { | 134 | { |
135 | free(env->hostname); | 135 | zfree(&env->hostname); |
136 | free(env->os_release); | 136 | zfree(&env->os_release); |
137 | free(env->version); | 137 | zfree(&env->version); |
138 | free(env->arch); | 138 | zfree(&env->arch); |
139 | free(env->cpu_desc); | 139 | zfree(&env->cpu_desc); |
140 | free(env->cpuid); | 140 | zfree(&env->cpuid); |
141 | 141 | ||
142 | free(env->cmdline); | 142 | zfree(&env->cmdline); |
143 | free(env->sibling_cores); | 143 | zfree(&env->sibling_cores); |
144 | free(env->sibling_threads); | 144 | zfree(&env->sibling_threads); |
145 | free(env->numa_nodes); | 145 | zfree(&env->numa_nodes); |
146 | free(env->pmu_mappings); | 146 | zfree(&env->pmu_mappings); |
147 | } | 147 | } |
148 | 148 | ||
149 | void perf_session__delete(struct perf_session *session) | 149 | void perf_session__delete(struct perf_session *session) |
@@ -247,27 +247,6 @@ void perf_tool__fill_defaults(struct perf_tool *tool) | |||
247 | } | 247 | } |
248 | } | 248 | } |
249 | 249 | ||
250 | void mem_bswap_32(void *src, int byte_size) | ||
251 | { | ||
252 | u32 *m = src; | ||
253 | while (byte_size > 0) { | ||
254 | *m = bswap_32(*m); | ||
255 | byte_size -= sizeof(u32); | ||
256 | ++m; | ||
257 | } | ||
258 | } | ||
259 | |||
260 | void mem_bswap_64(void *src, int byte_size) | ||
261 | { | ||
262 | u64 *m = src; | ||
263 | |||
264 | while (byte_size > 0) { | ||
265 | *m = bswap_64(*m); | ||
266 | byte_size -= sizeof(u64); | ||
267 | ++m; | ||
268 | } | ||
269 | } | ||
270 | |||
271 | static void swap_sample_id_all(union perf_event *event, void *data) | 250 | static void swap_sample_id_all(union perf_event *event, void *data) |
272 | { | 251 | { |
273 | void *end = (void *) event + event->header.size; | 252 | void *end = (void *) event + event->header.size; |
@@ -851,6 +830,7 @@ static struct machine * | |||
851 | struct perf_sample *sample) | 830 | struct perf_sample *sample) |
852 | { | 831 | { |
853 | const u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; | 832 | const u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; |
833 | struct machine *machine; | ||
854 | 834 | ||
855 | if (perf_guest && | 835 | if (perf_guest && |
856 | ((cpumode == PERF_RECORD_MISC_GUEST_KERNEL) || | 836 | ((cpumode == PERF_RECORD_MISC_GUEST_KERNEL) || |
@@ -863,7 +843,11 @@ static struct machine * | |||
863 | else | 843 | else |
864 | pid = sample->pid; | 844 | pid = sample->pid; |
865 | 845 | ||
866 | return perf_session__findnew_machine(session, pid); | 846 | machine = perf_session__find_machine(session, pid); |
847 | if (!machine) | ||
848 | machine = perf_session__findnew_machine(session, | ||
849 | DEFAULT_GUEST_KERNEL_ID); | ||
850 | return machine; | ||
867 | } | 851 | } |
868 | 852 | ||
869 | return &session->machines.host; | 853 | return &session->machines.host; |
@@ -1024,6 +1008,12 @@ static int perf_session__process_user_event(struct perf_session *session, union | |||
1024 | if (err == 0) | 1008 | if (err == 0) |
1025 | perf_session__set_id_hdr_size(session); | 1009 | perf_session__set_id_hdr_size(session); |
1026 | return err; | 1010 | return err; |
1011 | case PERF_RECORD_HEADER_EVENT_TYPE: | ||
1012 | /* | ||
1013 | * Depreceated, but we need to handle it for sake | ||
1014 | * of old data files create in pipe mode. | ||
1015 | */ | ||
1016 | return 0; | ||
1027 | case PERF_RECORD_HEADER_TRACING_DATA: | 1017 | case PERF_RECORD_HEADER_TRACING_DATA: |
1028 | /* setup for reading amidst mmap */ | 1018 | /* setup for reading amidst mmap */ |
1029 | lseek(fd, file_offset, SEEK_SET); | 1019 | lseek(fd, file_offset, SEEK_SET); |
@@ -1158,7 +1148,7 @@ static int __perf_session__process_pipe_events(struct perf_session *session, | |||
1158 | void *buf = NULL; | 1148 | void *buf = NULL; |
1159 | int skip = 0; | 1149 | int skip = 0; |
1160 | u64 head; | 1150 | u64 head; |
1161 | int err; | 1151 | ssize_t err; |
1162 | void *p; | 1152 | void *p; |
1163 | 1153 | ||
1164 | perf_tool__fill_defaults(tool); | 1154 | perf_tool__fill_defaults(tool); |
@@ -1400,7 +1390,7 @@ bool perf_session__has_traces(struct perf_session *session, const char *msg) | |||
1400 | { | 1390 | { |
1401 | struct perf_evsel *evsel; | 1391 | struct perf_evsel *evsel; |
1402 | 1392 | ||
1403 | list_for_each_entry(evsel, &session->evlist->entries, node) { | 1393 | evlist__for_each(session->evlist, evsel) { |
1404 | if (evsel->attr.type == PERF_TYPE_TRACEPOINT) | 1394 | if (evsel->attr.type == PERF_TYPE_TRACEPOINT) |
1405 | return true; | 1395 | return true; |
1406 | } | 1396 | } |
@@ -1458,7 +1448,7 @@ size_t perf_session__fprintf_nr_events(struct perf_session *session, FILE *fp) | |||
1458 | 1448 | ||
1459 | ret += events_stats__fprintf(&session->stats, fp); | 1449 | ret += events_stats__fprintf(&session->stats, fp); |
1460 | 1450 | ||
1461 | list_for_each_entry(pos, &session->evlist->entries, node) { | 1451 | evlist__for_each(session->evlist, pos) { |
1462 | ret += fprintf(fp, "%s stats:\n", perf_evsel__name(pos)); | 1452 | ret += fprintf(fp, "%s stats:\n", perf_evsel__name(pos)); |
1463 | ret += events_stats__fprintf(&pos->hists.stats, fp); | 1453 | ret += events_stats__fprintf(&pos->hists.stats, fp); |
1464 | } | 1454 | } |
@@ -1480,35 +1470,30 @@ struct perf_evsel *perf_session__find_first_evtype(struct perf_session *session, | |||
1480 | { | 1470 | { |
1481 | struct perf_evsel *pos; | 1471 | struct perf_evsel *pos; |
1482 | 1472 | ||
1483 | list_for_each_entry(pos, &session->evlist->entries, node) { | 1473 | evlist__for_each(session->evlist, pos) { |
1484 | if (pos->attr.type == type) | 1474 | if (pos->attr.type == type) |
1485 | return pos; | 1475 | return pos; |
1486 | } | 1476 | } |
1487 | return NULL; | 1477 | return NULL; |
1488 | } | 1478 | } |
1489 | 1479 | ||
1490 | void perf_evsel__print_ip(struct perf_evsel *evsel, union perf_event *event, | 1480 | void perf_evsel__print_ip(struct perf_evsel *evsel, struct perf_sample *sample, |
1491 | struct perf_sample *sample, struct machine *machine, | 1481 | struct addr_location *al, |
1492 | unsigned int print_opts, unsigned int stack_depth) | 1482 | unsigned int print_opts, unsigned int stack_depth) |
1493 | { | 1483 | { |
1494 | struct addr_location al; | ||
1495 | struct callchain_cursor_node *node; | 1484 | struct callchain_cursor_node *node; |
1496 | int print_ip = print_opts & PRINT_IP_OPT_IP; | 1485 | int print_ip = print_opts & PRINT_IP_OPT_IP; |
1497 | int print_sym = print_opts & PRINT_IP_OPT_SYM; | 1486 | int print_sym = print_opts & PRINT_IP_OPT_SYM; |
1498 | int print_dso = print_opts & PRINT_IP_OPT_DSO; | 1487 | int print_dso = print_opts & PRINT_IP_OPT_DSO; |
1499 | int print_symoffset = print_opts & PRINT_IP_OPT_SYMOFFSET; | 1488 | int print_symoffset = print_opts & PRINT_IP_OPT_SYMOFFSET; |
1500 | int print_oneline = print_opts & PRINT_IP_OPT_ONELINE; | 1489 | int print_oneline = print_opts & PRINT_IP_OPT_ONELINE; |
1490 | int print_srcline = print_opts & PRINT_IP_OPT_SRCLINE; | ||
1501 | char s = print_oneline ? ' ' : '\t'; | 1491 | char s = print_oneline ? ' ' : '\t'; |
1502 | 1492 | ||
1503 | if (perf_event__preprocess_sample(event, machine, &al, sample) < 0) { | ||
1504 | error("problem processing %d event, skipping it.\n", | ||
1505 | event->header.type); | ||
1506 | return; | ||
1507 | } | ||
1508 | |||
1509 | if (symbol_conf.use_callchain && sample->callchain) { | 1493 | if (symbol_conf.use_callchain && sample->callchain) { |
1494 | struct addr_location node_al; | ||
1510 | 1495 | ||
1511 | if (machine__resolve_callchain(machine, evsel, al.thread, | 1496 | if (machine__resolve_callchain(al->machine, evsel, al->thread, |
1512 | sample, NULL, NULL, | 1497 | sample, NULL, NULL, |
1513 | PERF_MAX_STACK_DEPTH) != 0) { | 1498 | PERF_MAX_STACK_DEPTH) != 0) { |
1514 | if (verbose) | 1499 | if (verbose) |
@@ -1517,20 +1502,31 @@ void perf_evsel__print_ip(struct perf_evsel *evsel, union perf_event *event, | |||
1517 | } | 1502 | } |
1518 | callchain_cursor_commit(&callchain_cursor); | 1503 | callchain_cursor_commit(&callchain_cursor); |
1519 | 1504 | ||
1505 | if (print_symoffset) | ||
1506 | node_al = *al; | ||
1507 | |||
1520 | while (stack_depth) { | 1508 | while (stack_depth) { |
1509 | u64 addr = 0; | ||
1510 | |||
1521 | node = callchain_cursor_current(&callchain_cursor); | 1511 | node = callchain_cursor_current(&callchain_cursor); |
1522 | if (!node) | 1512 | if (!node) |
1523 | break; | 1513 | break; |
1524 | 1514 | ||
1515 | if (node->sym && node->sym->ignore) | ||
1516 | goto next; | ||
1517 | |||
1525 | if (print_ip) | 1518 | if (print_ip) |
1526 | printf("%c%16" PRIx64, s, node->ip); | 1519 | printf("%c%16" PRIx64, s, node->ip); |
1527 | 1520 | ||
1521 | if (node->map) | ||
1522 | addr = node->map->map_ip(node->map, node->ip); | ||
1523 | |||
1528 | if (print_sym) { | 1524 | if (print_sym) { |
1529 | printf(" "); | 1525 | printf(" "); |
1530 | if (print_symoffset) { | 1526 | if (print_symoffset) { |
1531 | al.addr = node->ip; | 1527 | node_al.addr = addr; |
1532 | al.map = node->map; | 1528 | node_al.map = node->map; |
1533 | symbol__fprintf_symname_offs(node->sym, &al, stdout); | 1529 | symbol__fprintf_symname_offs(node->sym, &node_al, stdout); |
1534 | } else | 1530 | } else |
1535 | symbol__fprintf_symname(node->sym, stdout); | 1531 | symbol__fprintf_symname(node->sym, stdout); |
1536 | } | 1532 | } |
@@ -1541,39 +1537,49 @@ void perf_evsel__print_ip(struct perf_evsel *evsel, union perf_event *event, | |||
1541 | printf(")"); | 1537 | printf(")"); |
1542 | } | 1538 | } |
1543 | 1539 | ||
1540 | if (print_srcline) | ||
1541 | map__fprintf_srcline(node->map, addr, "\n ", | ||
1542 | stdout); | ||
1543 | |||
1544 | if (!print_oneline) | 1544 | if (!print_oneline) |
1545 | printf("\n"); | 1545 | printf("\n"); |
1546 | 1546 | ||
1547 | callchain_cursor_advance(&callchain_cursor); | ||
1548 | |||
1549 | stack_depth--; | 1547 | stack_depth--; |
1548 | next: | ||
1549 | callchain_cursor_advance(&callchain_cursor); | ||
1550 | } | 1550 | } |
1551 | 1551 | ||
1552 | } else { | 1552 | } else { |
1553 | if (al->sym && al->sym->ignore) | ||
1554 | return; | ||
1555 | |||
1553 | if (print_ip) | 1556 | if (print_ip) |
1554 | printf("%16" PRIx64, sample->ip); | 1557 | printf("%16" PRIx64, sample->ip); |
1555 | 1558 | ||
1556 | if (print_sym) { | 1559 | if (print_sym) { |
1557 | printf(" "); | 1560 | printf(" "); |
1558 | if (print_symoffset) | 1561 | if (print_symoffset) |
1559 | symbol__fprintf_symname_offs(al.sym, &al, | 1562 | symbol__fprintf_symname_offs(al->sym, al, |
1560 | stdout); | 1563 | stdout); |
1561 | else | 1564 | else |
1562 | symbol__fprintf_symname(al.sym, stdout); | 1565 | symbol__fprintf_symname(al->sym, stdout); |
1563 | } | 1566 | } |
1564 | 1567 | ||
1565 | if (print_dso) { | 1568 | if (print_dso) { |
1566 | printf(" ("); | 1569 | printf(" ("); |
1567 | map__fprintf_dsoname(al.map, stdout); | 1570 | map__fprintf_dsoname(al->map, stdout); |
1568 | printf(")"); | 1571 | printf(")"); |
1569 | } | 1572 | } |
1573 | |||
1574 | if (print_srcline) | ||
1575 | map__fprintf_srcline(al->map, al->addr, "\n ", stdout); | ||
1570 | } | 1576 | } |
1571 | } | 1577 | } |
1572 | 1578 | ||
1573 | int perf_session__cpu_bitmap(struct perf_session *session, | 1579 | int perf_session__cpu_bitmap(struct perf_session *session, |
1574 | const char *cpu_list, unsigned long *cpu_bitmap) | 1580 | const char *cpu_list, unsigned long *cpu_bitmap) |
1575 | { | 1581 | { |
1576 | int i; | 1582 | int i, err = -1; |
1577 | struct cpu_map *map; | 1583 | struct cpu_map *map; |
1578 | 1584 | ||
1579 | for (i = 0; i < PERF_TYPE_MAX; ++i) { | 1585 | for (i = 0; i < PERF_TYPE_MAX; ++i) { |
@@ -1602,13 +1608,17 @@ int perf_session__cpu_bitmap(struct perf_session *session, | |||
1602 | if (cpu >= MAX_NR_CPUS) { | 1608 | if (cpu >= MAX_NR_CPUS) { |
1603 | pr_err("Requested CPU %d too large. " | 1609 | pr_err("Requested CPU %d too large. " |
1604 | "Consider raising MAX_NR_CPUS\n", cpu); | 1610 | "Consider raising MAX_NR_CPUS\n", cpu); |
1605 | return -1; | 1611 | goto out_delete_map; |
1606 | } | 1612 | } |
1607 | 1613 | ||
1608 | set_bit(cpu, cpu_bitmap); | 1614 | set_bit(cpu, cpu_bitmap); |
1609 | } | 1615 | } |
1610 | 1616 | ||
1611 | return 0; | 1617 | err = 0; |
1618 | |||
1619 | out_delete_map: | ||
1620 | cpu_map__delete(map); | ||
1621 | return err; | ||
1612 | } | 1622 | } |
1613 | 1623 | ||
1614 | void perf_session__fprintf_info(struct perf_session *session, FILE *fp, | 1624 | void perf_session__fprintf_info(struct perf_session *session, FILE *fp, |
diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h index 50f640958f0f..3140f8ae6148 100644 --- a/tools/perf/util/session.h +++ b/tools/perf/util/session.h | |||
@@ -1,6 +1,7 @@ | |||
1 | #ifndef __PERF_SESSION_H | 1 | #ifndef __PERF_SESSION_H |
2 | #define __PERF_SESSION_H | 2 | #define __PERF_SESSION_H |
3 | 3 | ||
4 | #include "trace-event.h" | ||
4 | #include "hist.h" | 5 | #include "hist.h" |
5 | #include "event.h" | 6 | #include "event.h" |
6 | #include "header.h" | 7 | #include "header.h" |
@@ -32,7 +33,7 @@ struct perf_session { | |||
32 | struct perf_header header; | 33 | struct perf_header header; |
33 | struct machines machines; | 34 | struct machines machines; |
34 | struct perf_evlist *evlist; | 35 | struct perf_evlist *evlist; |
35 | struct pevent *pevent; | 36 | struct trace_event tevent; |
36 | struct events_stats stats; | 37 | struct events_stats stats; |
37 | bool repipe; | 38 | bool repipe; |
38 | struct ordered_samples ordered_samples; | 39 | struct ordered_samples ordered_samples; |
@@ -44,6 +45,7 @@ struct perf_session { | |||
44 | #define PRINT_IP_OPT_DSO (1<<2) | 45 | #define PRINT_IP_OPT_DSO (1<<2) |
45 | #define PRINT_IP_OPT_SYMOFFSET (1<<3) | 46 | #define PRINT_IP_OPT_SYMOFFSET (1<<3) |
46 | #define PRINT_IP_OPT_ONELINE (1<<4) | 47 | #define PRINT_IP_OPT_ONELINE (1<<4) |
48 | #define PRINT_IP_OPT_SRCLINE (1<<5) | ||
47 | 49 | ||
48 | struct perf_tool; | 50 | struct perf_tool; |
49 | 51 | ||
@@ -72,8 +74,6 @@ int perf_session__resolve_callchain(struct perf_session *session, | |||
72 | 74 | ||
73 | bool perf_session__has_traces(struct perf_session *session, const char *msg); | 75 | bool perf_session__has_traces(struct perf_session *session, const char *msg); |
74 | 76 | ||
75 | void mem_bswap_64(void *src, int byte_size); | ||
76 | void mem_bswap_32(void *src, int byte_size); | ||
77 | void perf_event__attr_swap(struct perf_event_attr *attr); | 77 | void perf_event__attr_swap(struct perf_event_attr *attr); |
78 | 78 | ||
79 | int perf_session__create_kernel_maps(struct perf_session *session); | 79 | int perf_session__create_kernel_maps(struct perf_session *session); |
@@ -105,8 +105,8 @@ size_t perf_session__fprintf_nr_events(struct perf_session *session, FILE *fp); | |||
105 | struct perf_evsel *perf_session__find_first_evtype(struct perf_session *session, | 105 | struct perf_evsel *perf_session__find_first_evtype(struct perf_session *session, |
106 | unsigned int type); | 106 | unsigned int type); |
107 | 107 | ||
108 | void perf_evsel__print_ip(struct perf_evsel *evsel, union perf_event *event, | 108 | void perf_evsel__print_ip(struct perf_evsel *evsel, struct perf_sample *sample, |
109 | struct perf_sample *sample, struct machine *machine, | 109 | struct addr_location *al, |
110 | unsigned int print_opts, unsigned int stack_depth); | 110 | unsigned int print_opts, unsigned int stack_depth); |
111 | 111 | ||
112 | int perf_session__cpu_bitmap(struct perf_session *session, | 112 | int perf_session__cpu_bitmap(struct perf_session *session, |
diff --git a/tools/perf/util/setup.py b/tools/perf/util/setup.py index 58ea5ca6c255..d0aee4b9dfd4 100644 --- a/tools/perf/util/setup.py +++ b/tools/perf/util/setup.py | |||
@@ -25,7 +25,7 @@ cflags += ['-fno-strict-aliasing', '-Wno-write-strings', '-Wno-unused-parameter' | |||
25 | build_lib = getenv('PYTHON_EXTBUILD_LIB') | 25 | build_lib = getenv('PYTHON_EXTBUILD_LIB') |
26 | build_tmp = getenv('PYTHON_EXTBUILD_TMP') | 26 | build_tmp = getenv('PYTHON_EXTBUILD_TMP') |
27 | libtraceevent = getenv('LIBTRACEEVENT') | 27 | libtraceevent = getenv('LIBTRACEEVENT') |
28 | liblk = getenv('LIBLK') | 28 | libapikfs = getenv('LIBAPIKFS') |
29 | 29 | ||
30 | ext_sources = [f.strip() for f in file('util/python-ext-sources') | 30 | ext_sources = [f.strip() for f in file('util/python-ext-sources') |
31 | if len(f.strip()) > 0 and f[0] != '#'] | 31 | if len(f.strip()) > 0 and f[0] != '#'] |
@@ -34,7 +34,7 @@ perf = Extension('perf', | |||
34 | sources = ext_sources, | 34 | sources = ext_sources, |
35 | include_dirs = ['util/include'], | 35 | include_dirs = ['util/include'], |
36 | extra_compile_args = cflags, | 36 | extra_compile_args = cflags, |
37 | extra_objects = [libtraceevent, liblk], | 37 | extra_objects = [libtraceevent, libapikfs], |
38 | ) | 38 | ) |
39 | 39 | ||
40 | setup(name='perf', | 40 | setup(name='perf', |
diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c index 8b0bb1f4494a..635cd8f8b22e 100644 --- a/tools/perf/util/sort.c +++ b/tools/perf/util/sort.c | |||
@@ -13,6 +13,7 @@ int have_ignore_callees = 0; | |||
13 | int sort__need_collapse = 0; | 13 | int sort__need_collapse = 0; |
14 | int sort__has_parent = 0; | 14 | int sort__has_parent = 0; |
15 | int sort__has_sym = 0; | 15 | int sort__has_sym = 0; |
16 | int sort__has_dso = 0; | ||
16 | enum sort_mode sort__mode = SORT_MODE__NORMAL; | 17 | enum sort_mode sort__mode = SORT_MODE__NORMAL; |
17 | 18 | ||
18 | enum sort_type sort__first_dimension; | 19 | enum sort_type sort__first_dimension; |
@@ -161,6 +162,11 @@ struct sort_entry sort_dso = { | |||
161 | 162 | ||
162 | /* --sort symbol */ | 163 | /* --sort symbol */ |
163 | 164 | ||
165 | static int64_t _sort__addr_cmp(u64 left_ip, u64 right_ip) | ||
166 | { | ||
167 | return (int64_t)(right_ip - left_ip); | ||
168 | } | ||
169 | |||
164 | static int64_t _sort__sym_cmp(struct symbol *sym_l, struct symbol *sym_r) | 170 | static int64_t _sort__sym_cmp(struct symbol *sym_l, struct symbol *sym_r) |
165 | { | 171 | { |
166 | u64 ip_l, ip_r; | 172 | u64 ip_l, ip_r; |
@@ -183,15 +189,17 @@ sort__sym_cmp(struct hist_entry *left, struct hist_entry *right) | |||
183 | int64_t ret; | 189 | int64_t ret; |
184 | 190 | ||
185 | if (!left->ms.sym && !right->ms.sym) | 191 | if (!left->ms.sym && !right->ms.sym) |
186 | return right->level - left->level; | 192 | return _sort__addr_cmp(left->ip, right->ip); |
187 | 193 | ||
188 | /* | 194 | /* |
189 | * comparing symbol address alone is not enough since it's a | 195 | * comparing symbol address alone is not enough since it's a |
190 | * relative address within a dso. | 196 | * relative address within a dso. |
191 | */ | 197 | */ |
192 | ret = sort__dso_cmp(left, right); | 198 | if (!sort__has_dso) { |
193 | if (ret != 0) | 199 | ret = sort__dso_cmp(left, right); |
194 | return ret; | 200 | if (ret != 0) |
201 | return ret; | ||
202 | } | ||
195 | 203 | ||
196 | return _sort__sym_cmp(left->ms.sym, right->ms.sym); | 204 | return _sort__sym_cmp(left->ms.sym, right->ms.sym); |
197 | } | 205 | } |
@@ -372,7 +380,7 @@ sort__sym_from_cmp(struct hist_entry *left, struct hist_entry *right) | |||
372 | struct addr_map_symbol *from_r = &right->branch_info->from; | 380 | struct addr_map_symbol *from_r = &right->branch_info->from; |
373 | 381 | ||
374 | if (!from_l->sym && !from_r->sym) | 382 | if (!from_l->sym && !from_r->sym) |
375 | return right->level - left->level; | 383 | return _sort__addr_cmp(from_l->addr, from_r->addr); |
376 | 384 | ||
377 | return _sort__sym_cmp(from_l->sym, from_r->sym); | 385 | return _sort__sym_cmp(from_l->sym, from_r->sym); |
378 | } | 386 | } |
@@ -384,7 +392,7 @@ sort__sym_to_cmp(struct hist_entry *left, struct hist_entry *right) | |||
384 | struct addr_map_symbol *to_r = &right->branch_info->to; | 392 | struct addr_map_symbol *to_r = &right->branch_info->to; |
385 | 393 | ||
386 | if (!to_l->sym && !to_r->sym) | 394 | if (!to_l->sym && !to_r->sym) |
387 | return right->level - left->level; | 395 | return _sort__addr_cmp(to_l->addr, to_r->addr); |
388 | 396 | ||
389 | return _sort__sym_cmp(to_l->sym, to_r->sym); | 397 | return _sort__sym_cmp(to_l->sym, to_r->sym); |
390 | } | 398 | } |
@@ -1056,6 +1064,8 @@ int sort_dimension__add(const char *tok) | |||
1056 | sort__has_parent = 1; | 1064 | sort__has_parent = 1; |
1057 | } else if (sd->entry == &sort_sym) { | 1065 | } else if (sd->entry == &sort_sym) { |
1058 | sort__has_sym = 1; | 1066 | sort__has_sym = 1; |
1067 | } else if (sd->entry == &sort_dso) { | ||
1068 | sort__has_dso = 1; | ||
1059 | } | 1069 | } |
1060 | 1070 | ||
1061 | __sort_dimension__add(sd, i); | 1071 | __sort_dimension__add(sd, i); |
diff --git a/tools/perf/util/srcline.c b/tools/perf/util/srcline.c index d11aefbc4b8d..f3e4bc5fe5d2 100644 --- a/tools/perf/util/srcline.c +++ b/tools/perf/util/srcline.c | |||
@@ -129,7 +129,7 @@ static struct a2l_data *addr2line_init(const char *path) | |||
129 | 129 | ||
130 | out: | 130 | out: |
131 | if (a2l) { | 131 | if (a2l) { |
132 | free((void *)a2l->input); | 132 | zfree((char **)&a2l->input); |
133 | free(a2l); | 133 | free(a2l); |
134 | } | 134 | } |
135 | bfd_close(abfd); | 135 | bfd_close(abfd); |
@@ -140,24 +140,30 @@ static void addr2line_cleanup(struct a2l_data *a2l) | |||
140 | { | 140 | { |
141 | if (a2l->abfd) | 141 | if (a2l->abfd) |
142 | bfd_close(a2l->abfd); | 142 | bfd_close(a2l->abfd); |
143 | free((void *)a2l->input); | 143 | zfree((char **)&a2l->input); |
144 | free(a2l->syms); | 144 | zfree(&a2l->syms); |
145 | free(a2l); | 145 | free(a2l); |
146 | } | 146 | } |
147 | 147 | ||
148 | static int addr2line(const char *dso_name, unsigned long addr, | 148 | static int addr2line(const char *dso_name, unsigned long addr, |
149 | char **file, unsigned int *line) | 149 | char **file, unsigned int *line, struct dso *dso) |
150 | { | 150 | { |
151 | int ret = 0; | 151 | int ret = 0; |
152 | struct a2l_data *a2l; | 152 | struct a2l_data *a2l = dso->a2l; |
153 | |||
154 | if (!a2l) { | ||
155 | dso->a2l = addr2line_init(dso_name); | ||
156 | a2l = dso->a2l; | ||
157 | } | ||
153 | 158 | ||
154 | a2l = addr2line_init(dso_name); | ||
155 | if (a2l == NULL) { | 159 | if (a2l == NULL) { |
156 | pr_warning("addr2line_init failed for %s\n", dso_name); | 160 | pr_warning("addr2line_init failed for %s\n", dso_name); |
157 | return 0; | 161 | return 0; |
158 | } | 162 | } |
159 | 163 | ||
160 | a2l->addr = addr; | 164 | a2l->addr = addr; |
165 | a2l->found = false; | ||
166 | |||
161 | bfd_map_over_sections(a2l->abfd, find_address_in_section, a2l); | 167 | bfd_map_over_sections(a2l->abfd, find_address_in_section, a2l); |
162 | 168 | ||
163 | if (a2l->found && a2l->filename) { | 169 | if (a2l->found && a2l->filename) { |
@@ -168,14 +174,26 @@ static int addr2line(const char *dso_name, unsigned long addr, | |||
168 | ret = 1; | 174 | ret = 1; |
169 | } | 175 | } |
170 | 176 | ||
171 | addr2line_cleanup(a2l); | ||
172 | return ret; | 177 | return ret; |
173 | } | 178 | } |
174 | 179 | ||
180 | void dso__free_a2l(struct dso *dso) | ||
181 | { | ||
182 | struct a2l_data *a2l = dso->a2l; | ||
183 | |||
184 | if (!a2l) | ||
185 | return; | ||
186 | |||
187 | addr2line_cleanup(a2l); | ||
188 | |||
189 | dso->a2l = NULL; | ||
190 | } | ||
191 | |||
175 | #else /* HAVE_LIBBFD_SUPPORT */ | 192 | #else /* HAVE_LIBBFD_SUPPORT */ |
176 | 193 | ||
177 | static int addr2line(const char *dso_name, unsigned long addr, | 194 | static int addr2line(const char *dso_name, unsigned long addr, |
178 | char **file, unsigned int *line_nr) | 195 | char **file, unsigned int *line_nr, |
196 | struct dso *dso __maybe_unused) | ||
179 | { | 197 | { |
180 | FILE *fp; | 198 | FILE *fp; |
181 | char cmd[PATH_MAX]; | 199 | char cmd[PATH_MAX]; |
@@ -219,42 +237,58 @@ out: | |||
219 | pclose(fp); | 237 | pclose(fp); |
220 | return ret; | 238 | return ret; |
221 | } | 239 | } |
240 | |||
241 | void dso__free_a2l(struct dso *dso __maybe_unused) | ||
242 | { | ||
243 | } | ||
244 | |||
222 | #endif /* HAVE_LIBBFD_SUPPORT */ | 245 | #endif /* HAVE_LIBBFD_SUPPORT */ |
223 | 246 | ||
247 | /* | ||
248 | * Number of addr2line failures (without success) before disabling it for that | ||
249 | * dso. | ||
250 | */ | ||
251 | #define A2L_FAIL_LIMIT 123 | ||
252 | |||
224 | char *get_srcline(struct dso *dso, unsigned long addr) | 253 | char *get_srcline(struct dso *dso, unsigned long addr) |
225 | { | 254 | { |
226 | char *file = NULL; | 255 | char *file = NULL; |
227 | unsigned line = 0; | 256 | unsigned line = 0; |
228 | char *srcline; | 257 | char *srcline; |
229 | char *dso_name = dso->long_name; | 258 | const char *dso_name; |
230 | size_t size; | ||
231 | 259 | ||
232 | if (!dso->has_srcline) | 260 | if (!dso->has_srcline) |
233 | return SRCLINE_UNKNOWN; | 261 | return SRCLINE_UNKNOWN; |
234 | 262 | ||
263 | if (dso->symsrc_filename) | ||
264 | dso_name = dso->symsrc_filename; | ||
265 | else | ||
266 | dso_name = dso->long_name; | ||
267 | |||
235 | if (dso_name[0] == '[') | 268 | if (dso_name[0] == '[') |
236 | goto out; | 269 | goto out; |
237 | 270 | ||
238 | if (!strncmp(dso_name, "/tmp/perf-", 10)) | 271 | if (!strncmp(dso_name, "/tmp/perf-", 10)) |
239 | goto out; | 272 | goto out; |
240 | 273 | ||
241 | if (!addr2line(dso_name, addr, &file, &line)) | 274 | if (!addr2line(dso_name, addr, &file, &line, dso)) |
242 | goto out; | 275 | goto out; |
243 | 276 | ||
244 | /* just calculate actual length */ | 277 | if (asprintf(&srcline, "%s:%u", file, line) < 0) { |
245 | size = snprintf(NULL, 0, "%s:%u", file, line) + 1; | 278 | free(file); |
279 | goto out; | ||
280 | } | ||
246 | 281 | ||
247 | srcline = malloc(size); | 282 | dso->a2l_fails = 0; |
248 | if (srcline) | ||
249 | snprintf(srcline, size, "%s:%u", file, line); | ||
250 | else | ||
251 | srcline = SRCLINE_UNKNOWN; | ||
252 | 283 | ||
253 | free(file); | 284 | free(file); |
254 | return srcline; | 285 | return srcline; |
255 | 286 | ||
256 | out: | 287 | out: |
257 | dso->has_srcline = 0; | 288 | if (dso->a2l_fails && ++dso->a2l_fails > A2L_FAIL_LIMIT) { |
289 | dso->has_srcline = 0; | ||
290 | dso__free_a2l(dso); | ||
291 | } | ||
258 | return SRCLINE_UNKNOWN; | 292 | return SRCLINE_UNKNOWN; |
259 | } | 293 | } |
260 | 294 | ||
diff --git a/tools/perf/util/strbuf.c b/tools/perf/util/strbuf.c index cfa906882e2c..4abe23550c73 100644 --- a/tools/perf/util/strbuf.c +++ b/tools/perf/util/strbuf.c | |||
@@ -28,7 +28,7 @@ void strbuf_init(struct strbuf *sb, ssize_t hint) | |||
28 | void strbuf_release(struct strbuf *sb) | 28 | void strbuf_release(struct strbuf *sb) |
29 | { | 29 | { |
30 | if (sb->alloc) { | 30 | if (sb->alloc) { |
31 | free(sb->buf); | 31 | zfree(&sb->buf); |
32 | strbuf_init(sb, 0); | 32 | strbuf_init(sb, 0); |
33 | } | 33 | } |
34 | } | 34 | } |
diff --git a/tools/perf/util/strfilter.c b/tools/perf/util/strfilter.c index 3edd0538161f..79a757a2a15c 100644 --- a/tools/perf/util/strfilter.c +++ b/tools/perf/util/strfilter.c | |||
@@ -14,7 +14,7 @@ static void strfilter_node__delete(struct strfilter_node *node) | |||
14 | { | 14 | { |
15 | if (node) { | 15 | if (node) { |
16 | if (node->p && !is_operator(*node->p)) | 16 | if (node->p && !is_operator(*node->p)) |
17 | free((char *)node->p); | 17 | zfree((char **)&node->p); |
18 | strfilter_node__delete(node->l); | 18 | strfilter_node__delete(node->l); |
19 | strfilter_node__delete(node->r); | 19 | strfilter_node__delete(node->r); |
20 | free(node); | 20 | free(node); |
diff --git a/tools/perf/util/string.c b/tools/perf/util/string.c index f0b0c008c507..2553e5b55b89 100644 --- a/tools/perf/util/string.c +++ b/tools/perf/util/string.c | |||
@@ -128,7 +128,7 @@ void argv_free(char **argv) | |||
128 | { | 128 | { |
129 | char **p; | 129 | char **p; |
130 | for (p = argv; *p; p++) | 130 | for (p = argv; *p; p++) |
131 | free(*p); | 131 | zfree(p); |
132 | 132 | ||
133 | free(argv); | 133 | free(argv); |
134 | } | 134 | } |
diff --git a/tools/perf/util/strlist.c b/tools/perf/util/strlist.c index eabdce0a2daa..71f9d102b96f 100644 --- a/tools/perf/util/strlist.c +++ b/tools/perf/util/strlist.c | |||
@@ -5,6 +5,7 @@ | |||
5 | */ | 5 | */ |
6 | 6 | ||
7 | #include "strlist.h" | 7 | #include "strlist.h" |
8 | #include "util.h" | ||
8 | #include <errno.h> | 9 | #include <errno.h> |
9 | #include <stdio.h> | 10 | #include <stdio.h> |
10 | #include <stdlib.h> | 11 | #include <stdlib.h> |
@@ -38,7 +39,7 @@ out_delete: | |||
38 | static void str_node__delete(struct str_node *snode, bool dupstr) | 39 | static void str_node__delete(struct str_node *snode, bool dupstr) |
39 | { | 40 | { |
40 | if (dupstr) | 41 | if (dupstr) |
41 | free((void *)snode->s); | 42 | zfree((char **)&snode->s); |
42 | free(snode); | 43 | free(snode); |
43 | } | 44 | } |
44 | 45 | ||
diff --git a/tools/perf/util/svghelper.c b/tools/perf/util/svghelper.c index 96c866045d60..43262b83c541 100644 --- a/tools/perf/util/svghelper.c +++ b/tools/perf/util/svghelper.c | |||
@@ -17,8 +17,12 @@ | |||
17 | #include <stdlib.h> | 17 | #include <stdlib.h> |
18 | #include <unistd.h> | 18 | #include <unistd.h> |
19 | #include <string.h> | 19 | #include <string.h> |
20 | #include <linux/bitops.h> | ||
20 | 21 | ||
22 | #include "perf.h" | ||
21 | #include "svghelper.h" | 23 | #include "svghelper.h" |
24 | #include "util.h" | ||
25 | #include "cpumap.h" | ||
22 | 26 | ||
23 | static u64 first_time, last_time; | 27 | static u64 first_time, last_time; |
24 | static u64 turbo_frequency, max_freq; | 28 | static u64 turbo_frequency, max_freq; |
@@ -28,6 +32,8 @@ static u64 turbo_frequency, max_freq; | |||
28 | #define SLOT_HEIGHT 25.0 | 32 | #define SLOT_HEIGHT 25.0 |
29 | 33 | ||
30 | int svg_page_width = 1000; | 34 | int svg_page_width = 1000; |
35 | u64 svg_highlight; | ||
36 | const char *svg_highlight_name; | ||
31 | 37 | ||
32 | #define MIN_TEXT_SIZE 0.01 | 38 | #define MIN_TEXT_SIZE 0.01 |
33 | 39 | ||
@@ -39,9 +45,14 @@ static double cpu2slot(int cpu) | |||
39 | return 2 * cpu + 1; | 45 | return 2 * cpu + 1; |
40 | } | 46 | } |
41 | 47 | ||
48 | static int *topology_map; | ||
49 | |||
42 | static double cpu2y(int cpu) | 50 | static double cpu2y(int cpu) |
43 | { | 51 | { |
44 | return cpu2slot(cpu) * SLOT_MULT; | 52 | if (topology_map) |
53 | return cpu2slot(topology_map[cpu]) * SLOT_MULT; | ||
54 | else | ||
55 | return cpu2slot(cpu) * SLOT_MULT; | ||
45 | } | 56 | } |
46 | 57 | ||
47 | static double time2pixels(u64 __time) | 58 | static double time2pixels(u64 __time) |
@@ -95,6 +106,7 @@ void open_svg(const char *filename, int cpus, int rows, u64 start, u64 end) | |||
95 | 106 | ||
96 | total_height = (1 + rows + cpu2slot(cpus)) * SLOT_MULT; | 107 | total_height = (1 + rows + cpu2slot(cpus)) * SLOT_MULT; |
97 | fprintf(svgfile, "<?xml version=\"1.0\" standalone=\"no\"?> \n"); | 108 | fprintf(svgfile, "<?xml version=\"1.0\" standalone=\"no\"?> \n"); |
109 | fprintf(svgfile, "<!DOCTYPE svg SYSTEM \"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">\n"); | ||
98 | fprintf(svgfile, "<svg width=\"%i\" height=\"%" PRIu64 "\" version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\">\n", svg_page_width, total_height); | 110 | fprintf(svgfile, "<svg width=\"%i\" height=\"%" PRIu64 "\" version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\">\n", svg_page_width, total_height); |
99 | 111 | ||
100 | fprintf(svgfile, "<defs>\n <style type=\"text/css\">\n <![CDATA[\n"); | 112 | fprintf(svgfile, "<defs>\n <style type=\"text/css\">\n <![CDATA[\n"); |
@@ -103,6 +115,7 @@ void open_svg(const char *filename, int cpus, int rows, u64 start, u64 end) | |||
103 | fprintf(svgfile, " rect.process { fill:rgb(180,180,180); fill-opacity:0.9; stroke-width:1; stroke:rgb( 0, 0, 0); } \n"); | 115 | fprintf(svgfile, " rect.process { fill:rgb(180,180,180); fill-opacity:0.9; stroke-width:1; stroke:rgb( 0, 0, 0); } \n"); |
104 | fprintf(svgfile, " rect.process2 { fill:rgb(180,180,180); fill-opacity:0.9; stroke-width:0; stroke:rgb( 0, 0, 0); } \n"); | 116 | fprintf(svgfile, " rect.process2 { fill:rgb(180,180,180); fill-opacity:0.9; stroke-width:0; stroke:rgb( 0, 0, 0); } \n"); |
105 | fprintf(svgfile, " rect.sample { fill:rgb( 0, 0,255); fill-opacity:0.8; stroke-width:0; stroke:rgb( 0, 0, 0); } \n"); | 117 | fprintf(svgfile, " rect.sample { fill:rgb( 0, 0,255); fill-opacity:0.8; stroke-width:0; stroke:rgb( 0, 0, 0); } \n"); |
118 | fprintf(svgfile, " rect.sample_hi{ fill:rgb(255,128, 0); fill-opacity:0.8; stroke-width:0; stroke:rgb( 0, 0, 0); } \n"); | ||
106 | fprintf(svgfile, " rect.blocked { fill:rgb(255, 0, 0); fill-opacity:0.5; stroke-width:0; stroke:rgb( 0, 0, 0); } \n"); | 119 | fprintf(svgfile, " rect.blocked { fill:rgb(255, 0, 0); fill-opacity:0.5; stroke-width:0; stroke:rgb( 0, 0, 0); } \n"); |
107 | fprintf(svgfile, " rect.waiting { fill:rgb(224,214, 0); fill-opacity:0.8; stroke-width:0; stroke:rgb( 0, 0, 0); } \n"); | 120 | fprintf(svgfile, " rect.waiting { fill:rgb(224,214, 0); fill-opacity:0.8; stroke-width:0; stroke:rgb( 0, 0, 0); } \n"); |
108 | fprintf(svgfile, " rect.WAITING { fill:rgb(255,214, 48); fill-opacity:0.6; stroke-width:0; stroke:rgb( 0, 0, 0); } \n"); | 121 | fprintf(svgfile, " rect.WAITING { fill:rgb(255,214, 48); fill-opacity:0.6; stroke-width:0; stroke:rgb( 0, 0, 0); } \n"); |
@@ -128,14 +141,42 @@ void svg_box(int Yslot, u64 start, u64 end, const char *type) | |||
128 | time2pixels(start), time2pixels(end)-time2pixels(start), Yslot * SLOT_MULT, SLOT_HEIGHT, type); | 141 | time2pixels(start), time2pixels(end)-time2pixels(start), Yslot * SLOT_MULT, SLOT_HEIGHT, type); |
129 | } | 142 | } |
130 | 143 | ||
131 | void svg_sample(int Yslot, int cpu, u64 start, u64 end) | 144 | static char *time_to_string(u64 duration); |
145 | void svg_blocked(int Yslot, int cpu, u64 start, u64 end, const char *backtrace) | ||
146 | { | ||
147 | if (!svgfile) | ||
148 | return; | ||
149 | |||
150 | fprintf(svgfile, "<g>\n"); | ||
151 | fprintf(svgfile, "<title>#%d blocked %s</title>\n", cpu, | ||
152 | time_to_string(end - start)); | ||
153 | if (backtrace) | ||
154 | fprintf(svgfile, "<desc>Blocked on:\n%s</desc>\n", backtrace); | ||
155 | svg_box(Yslot, start, end, "blocked"); | ||
156 | fprintf(svgfile, "</g>\n"); | ||
157 | } | ||
158 | |||
159 | void svg_running(int Yslot, int cpu, u64 start, u64 end, const char *backtrace) | ||
132 | { | 160 | { |
133 | double text_size; | 161 | double text_size; |
162 | const char *type; | ||
163 | |||
134 | if (!svgfile) | 164 | if (!svgfile) |
135 | return; | 165 | return; |
136 | 166 | ||
137 | fprintf(svgfile, "<rect x=\"%4.8f\" width=\"%4.8f\" y=\"%4.1f\" height=\"%4.1f\" class=\"sample\"/>\n", | 167 | if (svg_highlight && end - start > svg_highlight) |
138 | time2pixels(start), time2pixels(end)-time2pixels(start), Yslot * SLOT_MULT, SLOT_HEIGHT); | 168 | type = "sample_hi"; |
169 | else | ||
170 | type = "sample"; | ||
171 | fprintf(svgfile, "<g>\n"); | ||
172 | |||
173 | fprintf(svgfile, "<title>#%d running %s</title>\n", | ||
174 | cpu, time_to_string(end - start)); | ||
175 | if (backtrace) | ||
176 | fprintf(svgfile, "<desc>Switched because:\n%s</desc>\n", backtrace); | ||
177 | fprintf(svgfile, "<rect x=\"%4.8f\" width=\"%4.8f\" y=\"%4.1f\" height=\"%4.1f\" class=\"%s\"/>\n", | ||
178 | time2pixels(start), time2pixels(end)-time2pixels(start), Yslot * SLOT_MULT, SLOT_HEIGHT, | ||
179 | type); | ||
139 | 180 | ||
140 | text_size = (time2pixels(end)-time2pixels(start)); | 181 | text_size = (time2pixels(end)-time2pixels(start)); |
141 | if (cpu > 9) | 182 | if (cpu > 9) |
@@ -148,6 +189,7 @@ void svg_sample(int Yslot, int cpu, u64 start, u64 end) | |||
148 | fprintf(svgfile, "<text x=\"%1.8f\" y=\"%1.8f\" font-size=\"%1.8fpt\">%i</text>\n", | 189 | fprintf(svgfile, "<text x=\"%1.8f\" y=\"%1.8f\" font-size=\"%1.8fpt\">%i</text>\n", |
149 | time2pixels(start), Yslot * SLOT_MULT + SLOT_HEIGHT - 1, text_size, cpu + 1); | 190 | time2pixels(start), Yslot * SLOT_MULT + SLOT_HEIGHT - 1, text_size, cpu + 1); |
150 | 191 | ||
192 | fprintf(svgfile, "</g>\n"); | ||
151 | } | 193 | } |
152 | 194 | ||
153 | static char *time_to_string(u64 duration) | 195 | static char *time_to_string(u64 duration) |
@@ -168,7 +210,7 @@ static char *time_to_string(u64 duration) | |||
168 | return text; | 210 | return text; |
169 | } | 211 | } |
170 | 212 | ||
171 | void svg_waiting(int Yslot, u64 start, u64 end) | 213 | void svg_waiting(int Yslot, int cpu, u64 start, u64 end, const char *backtrace) |
172 | { | 214 | { |
173 | char *text; | 215 | char *text; |
174 | const char *style; | 216 | const char *style; |
@@ -192,6 +234,9 @@ void svg_waiting(int Yslot, u64 start, u64 end) | |||
192 | font_size = round_text_size(font_size); | 234 | font_size = round_text_size(font_size); |
193 | 235 | ||
194 | fprintf(svgfile, "<g transform=\"translate(%4.8f,%4.8f)\">\n", time2pixels(start), Yslot * SLOT_MULT); | 236 | fprintf(svgfile, "<g transform=\"translate(%4.8f,%4.8f)\">\n", time2pixels(start), Yslot * SLOT_MULT); |
237 | fprintf(svgfile, "<title>#%d waiting %s</title>\n", cpu, time_to_string(end - start)); | ||
238 | if (backtrace) | ||
239 | fprintf(svgfile, "<desc>Waiting on:\n%s</desc>\n", backtrace); | ||
195 | fprintf(svgfile, "<rect x=\"0\" width=\"%4.8f\" y=\"0\" height=\"%4.1f\" class=\"%s\"/>\n", | 240 | fprintf(svgfile, "<rect x=\"0\" width=\"%4.8f\" y=\"0\" height=\"%4.1f\" class=\"%s\"/>\n", |
196 | time2pixels(end)-time2pixels(start), SLOT_HEIGHT, style); | 241 | time2pixels(end)-time2pixels(start), SLOT_HEIGHT, style); |
197 | if (font_size > MIN_TEXT_SIZE) | 242 | if (font_size > MIN_TEXT_SIZE) |
@@ -242,28 +287,42 @@ void svg_cpu_box(int cpu, u64 __max_freq, u64 __turbo_freq) | |||
242 | max_freq = __max_freq; | 287 | max_freq = __max_freq; |
243 | turbo_frequency = __turbo_freq; | 288 | turbo_frequency = __turbo_freq; |
244 | 289 | ||
290 | fprintf(svgfile, "<g>\n"); | ||
291 | |||
245 | fprintf(svgfile, "<rect x=\"%4.8f\" width=\"%4.8f\" y=\"%4.1f\" height=\"%4.1f\" class=\"cpu\"/>\n", | 292 | fprintf(svgfile, "<rect x=\"%4.8f\" width=\"%4.8f\" y=\"%4.1f\" height=\"%4.1f\" class=\"cpu\"/>\n", |
246 | time2pixels(first_time), | 293 | time2pixels(first_time), |
247 | time2pixels(last_time)-time2pixels(first_time), | 294 | time2pixels(last_time)-time2pixels(first_time), |
248 | cpu2y(cpu), SLOT_MULT+SLOT_HEIGHT); | 295 | cpu2y(cpu), SLOT_MULT+SLOT_HEIGHT); |
249 | 296 | ||
250 | sprintf(cpu_string, "CPU %i", (int)cpu+1); | 297 | sprintf(cpu_string, "CPU %i", (int)cpu); |
251 | fprintf(svgfile, "<text x=\"%4.8f\" y=\"%4.8f\">%s</text>\n", | 298 | fprintf(svgfile, "<text x=\"%4.8f\" y=\"%4.8f\">%s</text>\n", |
252 | 10+time2pixels(first_time), cpu2y(cpu) + SLOT_HEIGHT/2, cpu_string); | 299 | 10+time2pixels(first_time), cpu2y(cpu) + SLOT_HEIGHT/2, cpu_string); |
253 | 300 | ||
254 | fprintf(svgfile, "<text transform=\"translate(%4.8f,%4.8f)\" font-size=\"1.25pt\">%s</text>\n", | 301 | fprintf(svgfile, "<text transform=\"translate(%4.8f,%4.8f)\" font-size=\"1.25pt\">%s</text>\n", |
255 | 10+time2pixels(first_time), cpu2y(cpu) + SLOT_MULT + SLOT_HEIGHT - 4, cpu_model()); | 302 | 10+time2pixels(first_time), cpu2y(cpu) + SLOT_MULT + SLOT_HEIGHT - 4, cpu_model()); |
303 | |||
304 | fprintf(svgfile, "</g>\n"); | ||
256 | } | 305 | } |
257 | 306 | ||
258 | void svg_process(int cpu, u64 start, u64 end, const char *type, const char *name) | 307 | void svg_process(int cpu, u64 start, u64 end, int pid, const char *name, const char *backtrace) |
259 | { | 308 | { |
260 | double width; | 309 | double width; |
310 | const char *type; | ||
261 | 311 | ||
262 | if (!svgfile) | 312 | if (!svgfile) |
263 | return; | 313 | return; |
264 | 314 | ||
315 | if (svg_highlight && end - start >= svg_highlight) | ||
316 | type = "sample_hi"; | ||
317 | else if (svg_highlight_name && strstr(name, svg_highlight_name)) | ||
318 | type = "sample_hi"; | ||
319 | else | ||
320 | type = "sample"; | ||
265 | 321 | ||
266 | fprintf(svgfile, "<g transform=\"translate(%4.8f,%4.8f)\">\n", time2pixels(start), cpu2y(cpu)); | 322 | fprintf(svgfile, "<g transform=\"translate(%4.8f,%4.8f)\">\n", time2pixels(start), cpu2y(cpu)); |
323 | fprintf(svgfile, "<title>%d %s running %s</title>\n", pid, name, time_to_string(end - start)); | ||
324 | if (backtrace) | ||
325 | fprintf(svgfile, "<desc>Switched because:\n%s</desc>\n", backtrace); | ||
267 | fprintf(svgfile, "<rect x=\"0\" width=\"%4.8f\" y=\"0\" height=\"%4.1f\" class=\"%s\"/>\n", | 326 | fprintf(svgfile, "<rect x=\"0\" width=\"%4.8f\" y=\"0\" height=\"%4.1f\" class=\"%s\"/>\n", |
268 | time2pixels(end)-time2pixels(start), SLOT_MULT+SLOT_HEIGHT, type); | 327 | time2pixels(end)-time2pixels(start), SLOT_MULT+SLOT_HEIGHT, type); |
269 | width = time2pixels(end)-time2pixels(start); | 328 | width = time2pixels(end)-time2pixels(start); |
@@ -288,6 +347,8 @@ void svg_cstate(int cpu, u64 start, u64 end, int type) | |||
288 | return; | 347 | return; |
289 | 348 | ||
290 | 349 | ||
350 | fprintf(svgfile, "<g>\n"); | ||
351 | |||
291 | if (type > 6) | 352 | if (type > 6) |
292 | type = 6; | 353 | type = 6; |
293 | sprintf(style, "c%i", type); | 354 | sprintf(style, "c%i", type); |
@@ -306,6 +367,8 @@ void svg_cstate(int cpu, u64 start, u64 end, int type) | |||
306 | if (width > MIN_TEXT_SIZE) | 367 | if (width > MIN_TEXT_SIZE) |
307 | fprintf(svgfile, "<text x=\"%4.8f\" y=\"%4.8f\" font-size=\"%3.8fpt\">C%i</text>\n", | 368 | fprintf(svgfile, "<text x=\"%4.8f\" y=\"%4.8f\" font-size=\"%3.8fpt\">C%i</text>\n", |
308 | time2pixels(start), cpu2y(cpu)+width, width, type); | 369 | time2pixels(start), cpu2y(cpu)+width, width, type); |
370 | |||
371 | fprintf(svgfile, "</g>\n"); | ||
309 | } | 372 | } |
310 | 373 | ||
311 | static char *HzToHuman(unsigned long hz) | 374 | static char *HzToHuman(unsigned long hz) |
@@ -339,6 +402,8 @@ void svg_pstate(int cpu, u64 start, u64 end, u64 freq) | |||
339 | if (!svgfile) | 402 | if (!svgfile) |
340 | return; | 403 | return; |
341 | 404 | ||
405 | fprintf(svgfile, "<g>\n"); | ||
406 | |||
342 | if (max_freq) | 407 | if (max_freq) |
343 | height = freq * 1.0 / max_freq * (SLOT_HEIGHT + SLOT_MULT); | 408 | height = freq * 1.0 / max_freq * (SLOT_HEIGHT + SLOT_MULT); |
344 | height = 1 + cpu2y(cpu) + SLOT_MULT + SLOT_HEIGHT - height; | 409 | height = 1 + cpu2y(cpu) + SLOT_MULT + SLOT_HEIGHT - height; |
@@ -347,10 +412,11 @@ void svg_pstate(int cpu, u64 start, u64 end, u64 freq) | |||
347 | fprintf(svgfile, "<text x=\"%4.8f\" y=\"%4.8f\" font-size=\"0.25pt\">%s</text>\n", | 412 | fprintf(svgfile, "<text x=\"%4.8f\" y=\"%4.8f\" font-size=\"0.25pt\">%s</text>\n", |
348 | time2pixels(start), height+0.9, HzToHuman(freq)); | 413 | time2pixels(start), height+0.9, HzToHuman(freq)); |
349 | 414 | ||
415 | fprintf(svgfile, "</g>\n"); | ||
350 | } | 416 | } |
351 | 417 | ||
352 | 418 | ||
353 | void svg_partial_wakeline(u64 start, int row1, char *desc1, int row2, char *desc2) | 419 | void svg_partial_wakeline(u64 start, int row1, char *desc1, int row2, char *desc2, const char *backtrace) |
354 | { | 420 | { |
355 | double height; | 421 | double height; |
356 | 422 | ||
@@ -358,6 +424,15 @@ void svg_partial_wakeline(u64 start, int row1, char *desc1, int row2, char *desc | |||
358 | return; | 424 | return; |
359 | 425 | ||
360 | 426 | ||
427 | fprintf(svgfile, "<g>\n"); | ||
428 | |||
429 | fprintf(svgfile, "<title>%s wakes up %s</title>\n", | ||
430 | desc1 ? desc1 : "?", | ||
431 | desc2 ? desc2 : "?"); | ||
432 | |||
433 | if (backtrace) | ||
434 | fprintf(svgfile, "<desc>%s</desc>\n", backtrace); | ||
435 | |||
361 | if (row1 < row2) { | 436 | if (row1 < row2) { |
362 | if (row1) { | 437 | if (row1) { |
363 | fprintf(svgfile, "<line x1=\"%4.8f\" y1=\"%4.2f\" x2=\"%4.8f\" y2=\"%4.2f\" style=\"stroke:rgb(32,255,32);stroke-width:0.009\"/>\n", | 438 | fprintf(svgfile, "<line x1=\"%4.8f\" y1=\"%4.2f\" x2=\"%4.8f\" y2=\"%4.2f\" style=\"stroke:rgb(32,255,32);stroke-width:0.009\"/>\n", |
@@ -395,9 +470,11 @@ void svg_partial_wakeline(u64 start, int row1, char *desc1, int row2, char *desc | |||
395 | if (row1) | 470 | if (row1) |
396 | fprintf(svgfile, "<circle cx=\"%4.8f\" cy=\"%4.2f\" r = \"0.01\" style=\"fill:rgb(32,255,32)\"/>\n", | 471 | fprintf(svgfile, "<circle cx=\"%4.8f\" cy=\"%4.2f\" r = \"0.01\" style=\"fill:rgb(32,255,32)\"/>\n", |
397 | time2pixels(start), height); | 472 | time2pixels(start), height); |
473 | |||
474 | fprintf(svgfile, "</g>\n"); | ||
398 | } | 475 | } |
399 | 476 | ||
400 | void svg_wakeline(u64 start, int row1, int row2) | 477 | void svg_wakeline(u64 start, int row1, int row2, const char *backtrace) |
401 | { | 478 | { |
402 | double height; | 479 | double height; |
403 | 480 | ||
@@ -405,6 +482,11 @@ void svg_wakeline(u64 start, int row1, int row2) | |||
405 | return; | 482 | return; |
406 | 483 | ||
407 | 484 | ||
485 | fprintf(svgfile, "<g>\n"); | ||
486 | |||
487 | if (backtrace) | ||
488 | fprintf(svgfile, "<desc>%s</desc>\n", backtrace); | ||
489 | |||
408 | if (row1 < row2) | 490 | if (row1 < row2) |
409 | fprintf(svgfile, "<line x1=\"%4.8f\" y1=\"%4.2f\" x2=\"%4.8f\" y2=\"%4.2f\" style=\"stroke:rgb(32,255,32);stroke-width:0.009\"/>\n", | 491 | fprintf(svgfile, "<line x1=\"%4.8f\" y1=\"%4.2f\" x2=\"%4.8f\" y2=\"%4.2f\" style=\"stroke:rgb(32,255,32);stroke-width:0.009\"/>\n", |
410 | time2pixels(start), row1 * SLOT_MULT + SLOT_HEIGHT, time2pixels(start), row2 * SLOT_MULT); | 492 | time2pixels(start), row1 * SLOT_MULT + SLOT_HEIGHT, time2pixels(start), row2 * SLOT_MULT); |
@@ -417,17 +499,28 @@ void svg_wakeline(u64 start, int row1, int row2) | |||
417 | height += SLOT_HEIGHT; | 499 | height += SLOT_HEIGHT; |
418 | fprintf(svgfile, "<circle cx=\"%4.8f\" cy=\"%4.2f\" r = \"0.01\" style=\"fill:rgb(32,255,32)\"/>\n", | 500 | fprintf(svgfile, "<circle cx=\"%4.8f\" cy=\"%4.2f\" r = \"0.01\" style=\"fill:rgb(32,255,32)\"/>\n", |
419 | time2pixels(start), height); | 501 | time2pixels(start), height); |
502 | |||
503 | fprintf(svgfile, "</g>\n"); | ||
420 | } | 504 | } |
421 | 505 | ||
422 | void svg_interrupt(u64 start, int row) | 506 | void svg_interrupt(u64 start, int row, const char *backtrace) |
423 | { | 507 | { |
424 | if (!svgfile) | 508 | if (!svgfile) |
425 | return; | 509 | return; |
426 | 510 | ||
511 | fprintf(svgfile, "<g>\n"); | ||
512 | |||
513 | fprintf(svgfile, "<title>Wakeup from interrupt</title>\n"); | ||
514 | |||
515 | if (backtrace) | ||
516 | fprintf(svgfile, "<desc>%s</desc>\n", backtrace); | ||
517 | |||
427 | fprintf(svgfile, "<circle cx=\"%4.8f\" cy=\"%4.2f\" r = \"0.01\" style=\"fill:rgb(255,128,128)\"/>\n", | 518 | fprintf(svgfile, "<circle cx=\"%4.8f\" cy=\"%4.2f\" r = \"0.01\" style=\"fill:rgb(255,128,128)\"/>\n", |
428 | time2pixels(start), row * SLOT_MULT); | 519 | time2pixels(start), row * SLOT_MULT); |
429 | fprintf(svgfile, "<circle cx=\"%4.8f\" cy=\"%4.2f\" r = \"0.01\" style=\"fill:rgb(255,128,128)\"/>\n", | 520 | fprintf(svgfile, "<circle cx=\"%4.8f\" cy=\"%4.2f\" r = \"0.01\" style=\"fill:rgb(255,128,128)\"/>\n", |
430 | time2pixels(start), row * SLOT_MULT + SLOT_HEIGHT); | 521 | time2pixels(start), row * SLOT_MULT + SLOT_HEIGHT); |
522 | |||
523 | fprintf(svgfile, "</g>\n"); | ||
431 | } | 524 | } |
432 | 525 | ||
433 | void svg_text(int Yslot, u64 start, const char *text) | 526 | void svg_text(int Yslot, u64 start, const char *text) |
@@ -455,6 +548,7 @@ void svg_legenda(void) | |||
455 | if (!svgfile) | 548 | if (!svgfile) |
456 | return; | 549 | return; |
457 | 550 | ||
551 | fprintf(svgfile, "<g>\n"); | ||
458 | svg_legenda_box(0, "Running", "sample"); | 552 | svg_legenda_box(0, "Running", "sample"); |
459 | svg_legenda_box(100, "Idle","c1"); | 553 | svg_legenda_box(100, "Idle","c1"); |
460 | svg_legenda_box(200, "Deeper Idle", "c3"); | 554 | svg_legenda_box(200, "Deeper Idle", "c3"); |
@@ -462,6 +556,7 @@ void svg_legenda(void) | |||
462 | svg_legenda_box(550, "Sleeping", "process2"); | 556 | svg_legenda_box(550, "Sleeping", "process2"); |
463 | svg_legenda_box(650, "Waiting for cpu", "waiting"); | 557 | svg_legenda_box(650, "Waiting for cpu", "waiting"); |
464 | svg_legenda_box(800, "Blocked on IO", "blocked"); | 558 | svg_legenda_box(800, "Blocked on IO", "blocked"); |
559 | fprintf(svgfile, "</g>\n"); | ||
465 | } | 560 | } |
466 | 561 | ||
467 | void svg_time_grid(void) | 562 | void svg_time_grid(void) |
@@ -499,3 +594,123 @@ void svg_close(void) | |||
499 | svgfile = NULL; | 594 | svgfile = NULL; |
500 | } | 595 | } |
501 | } | 596 | } |
597 | |||
598 | #define cpumask_bits(maskp) ((maskp)->bits) | ||
599 | typedef struct { DECLARE_BITMAP(bits, MAX_NR_CPUS); } cpumask_t; | ||
600 | |||
601 | struct topology { | ||
602 | cpumask_t *sib_core; | ||
603 | int sib_core_nr; | ||
604 | cpumask_t *sib_thr; | ||
605 | int sib_thr_nr; | ||
606 | }; | ||
607 | |||
608 | static void scan_thread_topology(int *map, struct topology *t, int cpu, int *pos) | ||
609 | { | ||
610 | int i; | ||
611 | int thr; | ||
612 | |||
613 | for (i = 0; i < t->sib_thr_nr; i++) { | ||
614 | if (!test_bit(cpu, cpumask_bits(&t->sib_thr[i]))) | ||
615 | continue; | ||
616 | |||
617 | for_each_set_bit(thr, | ||
618 | cpumask_bits(&t->sib_thr[i]), | ||
619 | MAX_NR_CPUS) | ||
620 | if (map[thr] == -1) | ||
621 | map[thr] = (*pos)++; | ||
622 | } | ||
623 | } | ||
624 | |||
625 | static void scan_core_topology(int *map, struct topology *t) | ||
626 | { | ||
627 | int pos = 0; | ||
628 | int i; | ||
629 | int cpu; | ||
630 | |||
631 | for (i = 0; i < t->sib_core_nr; i++) | ||
632 | for_each_set_bit(cpu, | ||
633 | cpumask_bits(&t->sib_core[i]), | ||
634 | MAX_NR_CPUS) | ||
635 | scan_thread_topology(map, t, cpu, &pos); | ||
636 | } | ||
637 | |||
638 | static int str_to_bitmap(char *s, cpumask_t *b) | ||
639 | { | ||
640 | int i; | ||
641 | int ret = 0; | ||
642 | struct cpu_map *m; | ||
643 | int c; | ||
644 | |||
645 | m = cpu_map__new(s); | ||
646 | if (!m) | ||
647 | return -1; | ||
648 | |||
649 | for (i = 0; i < m->nr; i++) { | ||
650 | c = m->map[i]; | ||
651 | if (c >= MAX_NR_CPUS) { | ||
652 | ret = -1; | ||
653 | break; | ||
654 | } | ||
655 | |||
656 | set_bit(c, cpumask_bits(b)); | ||
657 | } | ||
658 | |||
659 | cpu_map__delete(m); | ||
660 | |||
661 | return ret; | ||
662 | } | ||
663 | |||
664 | int svg_build_topology_map(char *sib_core, int sib_core_nr, | ||
665 | char *sib_thr, int sib_thr_nr) | ||
666 | { | ||
667 | int i; | ||
668 | struct topology t; | ||
669 | |||
670 | t.sib_core_nr = sib_core_nr; | ||
671 | t.sib_thr_nr = sib_thr_nr; | ||
672 | t.sib_core = calloc(sib_core_nr, sizeof(cpumask_t)); | ||
673 | t.sib_thr = calloc(sib_thr_nr, sizeof(cpumask_t)); | ||
674 | |||
675 | if (!t.sib_core || !t.sib_thr) { | ||
676 | fprintf(stderr, "topology: no memory\n"); | ||
677 | goto exit; | ||
678 | } | ||
679 | |||
680 | for (i = 0; i < sib_core_nr; i++) { | ||
681 | if (str_to_bitmap(sib_core, &t.sib_core[i])) { | ||
682 | fprintf(stderr, "topology: can't parse siblings map\n"); | ||
683 | goto exit; | ||
684 | } | ||
685 | |||
686 | sib_core += strlen(sib_core) + 1; | ||
687 | } | ||
688 | |||
689 | for (i = 0; i < sib_thr_nr; i++) { | ||
690 | if (str_to_bitmap(sib_thr, &t.sib_thr[i])) { | ||
691 | fprintf(stderr, "topology: can't parse siblings map\n"); | ||
692 | goto exit; | ||
693 | } | ||
694 | |||
695 | sib_thr += strlen(sib_thr) + 1; | ||
696 | } | ||
697 | |||
698 | topology_map = malloc(sizeof(int) * MAX_NR_CPUS); | ||
699 | if (!topology_map) { | ||
700 | fprintf(stderr, "topology: no memory\n"); | ||
701 | goto exit; | ||
702 | } | ||
703 | |||
704 | for (i = 0; i < MAX_NR_CPUS; i++) | ||
705 | topology_map[i] = -1; | ||
706 | |||
707 | scan_core_topology(topology_map, &t); | ||
708 | |||
709 | return 0; | ||
710 | |||
711 | exit: | ||
712 | zfree(&t.sib_core); | ||
713 | zfree(&t.sib_thr); | ||
714 | |||
715 | return -1; | ||
716 | } | ||
diff --git a/tools/perf/util/svghelper.h b/tools/perf/util/svghelper.h index e0781989cc31..f7b4d6e699ea 100644 --- a/tools/perf/util/svghelper.h +++ b/tools/perf/util/svghelper.h | |||
@@ -5,24 +5,29 @@ | |||
5 | 5 | ||
6 | extern void open_svg(const char *filename, int cpus, int rows, u64 start, u64 end); | 6 | extern void open_svg(const char *filename, int cpus, int rows, u64 start, u64 end); |
7 | extern void svg_box(int Yslot, u64 start, u64 end, const char *type); | 7 | extern void svg_box(int Yslot, u64 start, u64 end, const char *type); |
8 | extern void svg_sample(int Yslot, int cpu, u64 start, u64 end); | 8 | extern void svg_blocked(int Yslot, int cpu, u64 start, u64 end, const char *backtrace); |
9 | extern void svg_waiting(int Yslot, u64 start, u64 end); | 9 | extern void svg_running(int Yslot, int cpu, u64 start, u64 end, const char *backtrace); |
10 | extern void svg_waiting(int Yslot, int cpu, u64 start, u64 end, const char *backtrace); | ||
10 | extern void svg_cpu_box(int cpu, u64 max_frequency, u64 turbo_frequency); | 11 | extern void svg_cpu_box(int cpu, u64 max_frequency, u64 turbo_frequency); |
11 | 12 | ||
12 | 13 | ||
13 | extern void svg_process(int cpu, u64 start, u64 end, const char *type, const char *name); | 14 | extern void svg_process(int cpu, u64 start, u64 end, int pid, const char *name, const char *backtrace); |
14 | extern void svg_cstate(int cpu, u64 start, u64 end, int type); | 15 | extern void svg_cstate(int cpu, u64 start, u64 end, int type); |
15 | extern void svg_pstate(int cpu, u64 start, u64 end, u64 freq); | 16 | extern void svg_pstate(int cpu, u64 start, u64 end, u64 freq); |
16 | 17 | ||
17 | 18 | ||
18 | extern void svg_time_grid(void); | 19 | extern void svg_time_grid(void); |
19 | extern void svg_legenda(void); | 20 | extern void svg_legenda(void); |
20 | extern void svg_wakeline(u64 start, int row1, int row2); | 21 | extern void svg_wakeline(u64 start, int row1, int row2, const char *backtrace); |
21 | extern void svg_partial_wakeline(u64 start, int row1, char *desc1, int row2, char *desc2); | 22 | extern void svg_partial_wakeline(u64 start, int row1, char *desc1, int row2, char *desc2, const char *backtrace); |
22 | extern void svg_interrupt(u64 start, int row); | 23 | extern void svg_interrupt(u64 start, int row, const char *backtrace); |
23 | extern void svg_text(int Yslot, u64 start, const char *text); | 24 | extern void svg_text(int Yslot, u64 start, const char *text); |
24 | extern void svg_close(void); | 25 | extern void svg_close(void); |
26 | extern int svg_build_topology_map(char *sib_core, int sib_core_nr, | ||
27 | char *sib_thr, int sib_thr_nr); | ||
25 | 28 | ||
26 | extern int svg_page_width; | 29 | extern int svg_page_width; |
30 | extern u64 svg_highlight; | ||
31 | extern const char *svg_highlight_name; | ||
27 | 32 | ||
28 | #endif /* __PERF_SVGHELPER_H */ | 33 | #endif /* __PERF_SVGHELPER_H */ |
diff --git a/tools/perf/util/symbol-elf.c b/tools/perf/util/symbol-elf.c index eed0b96302af..516d19fb999b 100644 --- a/tools/perf/util/symbol-elf.c +++ b/tools/perf/util/symbol-elf.c | |||
@@ -6,6 +6,7 @@ | |||
6 | #include <inttypes.h> | 6 | #include <inttypes.h> |
7 | 7 | ||
8 | #include "symbol.h" | 8 | #include "symbol.h" |
9 | #include <symbol/kallsyms.h> | ||
9 | #include "debug.h" | 10 | #include "debug.h" |
10 | 11 | ||
11 | #ifndef HAVE_ELF_GETPHDRNUM_SUPPORT | 12 | #ifndef HAVE_ELF_GETPHDRNUM_SUPPORT |
@@ -135,9 +136,8 @@ static size_t elf_addr_to_index(Elf *elf, GElf_Addr addr) | |||
135 | return -1; | 136 | return -1; |
136 | } | 137 | } |
137 | 138 | ||
138 | static Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep, | 139 | Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep, |
139 | GElf_Shdr *shp, const char *name, | 140 | GElf_Shdr *shp, const char *name, size_t *idx) |
140 | size_t *idx) | ||
141 | { | 141 | { |
142 | Elf_Scn *sec = NULL; | 142 | Elf_Scn *sec = NULL; |
143 | size_t cnt = 1; | 143 | size_t cnt = 1; |
@@ -151,15 +151,15 @@ static Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep, | |||
151 | 151 | ||
152 | gelf_getshdr(sec, shp); | 152 | gelf_getshdr(sec, shp); |
153 | str = elf_strptr(elf, ep->e_shstrndx, shp->sh_name); | 153 | str = elf_strptr(elf, ep->e_shstrndx, shp->sh_name); |
154 | if (!strcmp(name, str)) { | 154 | if (str && !strcmp(name, str)) { |
155 | if (idx) | 155 | if (idx) |
156 | *idx = cnt; | 156 | *idx = cnt; |
157 | break; | 157 | return sec; |
158 | } | 158 | } |
159 | ++cnt; | 159 | ++cnt; |
160 | } | 160 | } |
161 | 161 | ||
162 | return sec; | 162 | return NULL; |
163 | } | 163 | } |
164 | 164 | ||
165 | #define elf_section__for_each_rel(reldata, pos, pos_mem, idx, nr_entries) \ | 165 | #define elf_section__for_each_rel(reldata, pos, pos_mem, idx, nr_entries) \ |
@@ -553,7 +553,7 @@ bool symsrc__has_symtab(struct symsrc *ss) | |||
553 | 553 | ||
554 | void symsrc__destroy(struct symsrc *ss) | 554 | void symsrc__destroy(struct symsrc *ss) |
555 | { | 555 | { |
556 | free(ss->name); | 556 | zfree(&ss->name); |
557 | elf_end(ss->elf); | 557 | elf_end(ss->elf); |
558 | close(ss->fd); | 558 | close(ss->fd); |
559 | } | 559 | } |
@@ -751,6 +751,8 @@ int dso__load_sym(struct dso *dso, struct map *map, | |||
751 | if (strcmp(elf_name, kmap->ref_reloc_sym->name)) | 751 | if (strcmp(elf_name, kmap->ref_reloc_sym->name)) |
752 | continue; | 752 | continue; |
753 | kmap->ref_reloc_sym->unrelocated_addr = sym.st_value; | 753 | kmap->ref_reloc_sym->unrelocated_addr = sym.st_value; |
754 | map->reloc = kmap->ref_reloc_sym->addr - | ||
755 | kmap->ref_reloc_sym->unrelocated_addr; | ||
754 | break; | 756 | break; |
755 | } | 757 | } |
756 | } | 758 | } |
@@ -922,6 +924,7 @@ int dso__load_sym(struct dso *dso, struct map *map, | |||
922 | (u64)shdr.sh_offset); | 924 | (u64)shdr.sh_offset); |
923 | sym.st_value -= shdr.sh_addr - shdr.sh_offset; | 925 | sym.st_value -= shdr.sh_addr - shdr.sh_offset; |
924 | } | 926 | } |
927 | new_symbol: | ||
925 | /* | 928 | /* |
926 | * We need to figure out if the object was created from C++ sources | 929 | * We need to figure out if the object was created from C++ sources |
927 | * DWARF DW_compile_unit has this, but we don't always have access | 930 | * DWARF DW_compile_unit has this, but we don't always have access |
@@ -933,7 +936,6 @@ int dso__load_sym(struct dso *dso, struct map *map, | |||
933 | if (demangled != NULL) | 936 | if (demangled != NULL) |
934 | elf_name = demangled; | 937 | elf_name = demangled; |
935 | } | 938 | } |
936 | new_symbol: | ||
937 | f = symbol__new(sym.st_value, sym.st_size, | 939 | f = symbol__new(sym.st_value, sym.st_size, |
938 | GELF_ST_BIND(sym.st_info), elf_name); | 940 | GELF_ST_BIND(sym.st_info), elf_name); |
939 | free(demangled); | 941 | free(demangled); |
diff --git a/tools/perf/util/symbol-minimal.c b/tools/perf/util/symbol-minimal.c index 2d2dd0532b5a..bd15f490d04f 100644 --- a/tools/perf/util/symbol-minimal.c +++ b/tools/perf/util/symbol-minimal.c | |||
@@ -1,4 +1,5 @@ | |||
1 | #include "symbol.h" | 1 | #include "symbol.h" |
2 | #include "util.h" | ||
2 | 3 | ||
3 | #include <stdio.h> | 4 | #include <stdio.h> |
4 | #include <fcntl.h> | 5 | #include <fcntl.h> |
@@ -253,6 +254,7 @@ int symsrc__init(struct symsrc *ss, struct dso *dso __maybe_unused, | |||
253 | if (!ss->name) | 254 | if (!ss->name) |
254 | goto out_close; | 255 | goto out_close; |
255 | 256 | ||
257 | ss->fd = fd; | ||
256 | ss->type = type; | 258 | ss->type = type; |
257 | 259 | ||
258 | return 0; | 260 | return 0; |
@@ -274,7 +276,7 @@ bool symsrc__has_symtab(struct symsrc *ss __maybe_unused) | |||
274 | 276 | ||
275 | void symsrc__destroy(struct symsrc *ss) | 277 | void symsrc__destroy(struct symsrc *ss) |
276 | { | 278 | { |
277 | free(ss->name); | 279 | zfree(&ss->name); |
278 | close(ss->fd); | 280 | close(ss->fd); |
279 | } | 281 | } |
280 | 282 | ||
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index c0c36965fff0..e89afc097d8a 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c | |||
@@ -18,12 +18,9 @@ | |||
18 | 18 | ||
19 | #include <elf.h> | 19 | #include <elf.h> |
20 | #include <limits.h> | 20 | #include <limits.h> |
21 | #include <symbol/kallsyms.h> | ||
21 | #include <sys/utsname.h> | 22 | #include <sys/utsname.h> |
22 | 23 | ||
23 | #ifndef KSYM_NAME_LEN | ||
24 | #define KSYM_NAME_LEN 256 | ||
25 | #endif | ||
26 | |||
27 | static int dso__load_kernel_sym(struct dso *dso, struct map *map, | 24 | static int dso__load_kernel_sym(struct dso *dso, struct map *map, |
28 | symbol_filter_t filter); | 25 | symbol_filter_t filter); |
29 | static int dso__load_guest_kernel_sym(struct dso *dso, struct map *map, | 26 | static int dso__load_guest_kernel_sym(struct dso *dso, struct map *map, |
@@ -446,62 +443,6 @@ size_t dso__fprintf_symbols_by_name(struct dso *dso, | |||
446 | return ret; | 443 | return ret; |
447 | } | 444 | } |
448 | 445 | ||
449 | int kallsyms__parse(const char *filename, void *arg, | ||
450 | int (*process_symbol)(void *arg, const char *name, | ||
451 | char type, u64 start)) | ||
452 | { | ||
453 | char *line = NULL; | ||
454 | size_t n; | ||
455 | int err = -1; | ||
456 | FILE *file = fopen(filename, "r"); | ||
457 | |||
458 | if (file == NULL) | ||
459 | goto out_failure; | ||
460 | |||
461 | err = 0; | ||
462 | |||
463 | while (!feof(file)) { | ||
464 | u64 start; | ||
465 | int line_len, len; | ||
466 | char symbol_type; | ||
467 | char *symbol_name; | ||
468 | |||
469 | line_len = getline(&line, &n, file); | ||
470 | if (line_len < 0 || !line) | ||
471 | break; | ||
472 | |||
473 | line[--line_len] = '\0'; /* \n */ | ||
474 | |||
475 | len = hex2u64(line, &start); | ||
476 | |||
477 | len++; | ||
478 | if (len + 2 >= line_len) | ||
479 | continue; | ||
480 | |||
481 | symbol_type = line[len]; | ||
482 | len += 2; | ||
483 | symbol_name = line + len; | ||
484 | len = line_len - len; | ||
485 | |||
486 | if (len >= KSYM_NAME_LEN) { | ||
487 | err = -1; | ||
488 | break; | ||
489 | } | ||
490 | |||
491 | err = process_symbol(arg, symbol_name, | ||
492 | symbol_type, start); | ||
493 | if (err) | ||
494 | break; | ||
495 | } | ||
496 | |||
497 | free(line); | ||
498 | fclose(file); | ||
499 | return err; | ||
500 | |||
501 | out_failure: | ||
502 | return -1; | ||
503 | } | ||
504 | |||
505 | int modules__parse(const char *filename, void *arg, | 446 | int modules__parse(const char *filename, void *arg, |
506 | int (*process_module)(void *arg, const char *name, | 447 | int (*process_module)(void *arg, const char *name, |
507 | u64 start)) | 448 | u64 start)) |
@@ -565,12 +506,34 @@ struct process_kallsyms_args { | |||
565 | struct dso *dso; | 506 | struct dso *dso; |
566 | }; | 507 | }; |
567 | 508 | ||
568 | static u8 kallsyms2elf_type(char type) | 509 | bool symbol__is_idle(struct symbol *sym) |
569 | { | 510 | { |
570 | if (type == 'W') | 511 | const char * const idle_symbols[] = { |
571 | return STB_WEAK; | 512 | "cpu_idle", |
513 | "intel_idle", | ||
514 | "default_idle", | ||
515 | "native_safe_halt", | ||
516 | "enter_idle", | ||
517 | "exit_idle", | ||
518 | "mwait_idle", | ||
519 | "mwait_idle_with_hints", | ||
520 | "poll_idle", | ||
521 | "ppc64_runlatch_off", | ||
522 | "pseries_dedicated_idle_sleep", | ||
523 | NULL | ||
524 | }; | ||
525 | |||
526 | int i; | ||
527 | |||
528 | if (!sym) | ||
529 | return false; | ||
572 | 530 | ||
573 | return isupper(type) ? STB_GLOBAL : STB_LOCAL; | 531 | for (i = 0; idle_symbols[i]; i++) { |
532 | if (!strcmp(idle_symbols[i], sym->name)) | ||
533 | return true; | ||
534 | } | ||
535 | |||
536 | return false; | ||
574 | } | 537 | } |
575 | 538 | ||
576 | static int map__process_kallsym_symbol(void *arg, const char *name, | 539 | static int map__process_kallsym_symbol(void *arg, const char *name, |
@@ -664,7 +627,7 @@ static int dso__split_kallsyms_for_kcore(struct dso *dso, struct map *map, | |||
664 | * kernel range is broken in several maps, named [kernel].N, as we don't have | 627 | * kernel range is broken in several maps, named [kernel].N, as we don't have |
665 | * the original ELF section names vmlinux have. | 628 | * the original ELF section names vmlinux have. |
666 | */ | 629 | */ |
667 | static int dso__split_kallsyms(struct dso *dso, struct map *map, | 630 | static int dso__split_kallsyms(struct dso *dso, struct map *map, u64 delta, |
668 | symbol_filter_t filter) | 631 | symbol_filter_t filter) |
669 | { | 632 | { |
670 | struct map_groups *kmaps = map__kmap(map)->kmaps; | 633 | struct map_groups *kmaps = map__kmap(map)->kmaps; |
@@ -729,6 +692,12 @@ static int dso__split_kallsyms(struct dso *dso, struct map *map, | |||
729 | char dso_name[PATH_MAX]; | 692 | char dso_name[PATH_MAX]; |
730 | struct dso *ndso; | 693 | struct dso *ndso; |
731 | 694 | ||
695 | if (delta) { | ||
696 | /* Kernel was relocated at boot time */ | ||
697 | pos->start -= delta; | ||
698 | pos->end -= delta; | ||
699 | } | ||
700 | |||
732 | if (count == 0) { | 701 | if (count == 0) { |
733 | curr_map = map; | 702 | curr_map = map; |
734 | goto filter_symbol; | 703 | goto filter_symbol; |
@@ -758,6 +727,10 @@ static int dso__split_kallsyms(struct dso *dso, struct map *map, | |||
758 | curr_map->map_ip = curr_map->unmap_ip = identity__map_ip; | 727 | curr_map->map_ip = curr_map->unmap_ip = identity__map_ip; |
759 | map_groups__insert(kmaps, curr_map); | 728 | map_groups__insert(kmaps, curr_map); |
760 | ++kernel_range; | 729 | ++kernel_range; |
730 | } else if (delta) { | ||
731 | /* Kernel was relocated at boot time */ | ||
732 | pos->start -= delta; | ||
733 | pos->end -= delta; | ||
761 | } | 734 | } |
762 | filter_symbol: | 735 | filter_symbol: |
763 | if (filter && filter(curr_map, pos)) { | 736 | if (filter && filter(curr_map, pos)) { |
@@ -833,7 +806,7 @@ static void delete_modules(struct rb_root *modules) | |||
833 | mi = rb_entry(next, struct module_info, rb_node); | 806 | mi = rb_entry(next, struct module_info, rb_node); |
834 | next = rb_next(&mi->rb_node); | 807 | next = rb_next(&mi->rb_node); |
835 | rb_erase(&mi->rb_node, modules); | 808 | rb_erase(&mi->rb_node, modules); |
836 | free(mi->name); | 809 | zfree(&mi->name); |
837 | free(mi); | 810 | free(mi); |
838 | } | 811 | } |
839 | } | 812 | } |
@@ -1013,6 +986,23 @@ static int validate_kcore_modules(const char *kallsyms_filename, | |||
1013 | return 0; | 986 | return 0; |
1014 | } | 987 | } |
1015 | 988 | ||
989 | static int validate_kcore_addresses(const char *kallsyms_filename, | ||
990 | struct map *map) | ||
991 | { | ||
992 | struct kmap *kmap = map__kmap(map); | ||
993 | |||
994 | if (kmap->ref_reloc_sym && kmap->ref_reloc_sym->name) { | ||
995 | u64 start; | ||
996 | |||
997 | start = kallsyms__get_function_start(kallsyms_filename, | ||
998 | kmap->ref_reloc_sym->name); | ||
999 | if (start != kmap->ref_reloc_sym->addr) | ||
1000 | return -EINVAL; | ||
1001 | } | ||
1002 | |||
1003 | return validate_kcore_modules(kallsyms_filename, map); | ||
1004 | } | ||
1005 | |||
1016 | struct kcore_mapfn_data { | 1006 | struct kcore_mapfn_data { |
1017 | struct dso *dso; | 1007 | struct dso *dso; |
1018 | enum map_type type; | 1008 | enum map_type type; |
@@ -1056,8 +1046,8 @@ static int dso__load_kcore(struct dso *dso, struct map *map, | |||
1056 | kallsyms_filename)) | 1046 | kallsyms_filename)) |
1057 | return -EINVAL; | 1047 | return -EINVAL; |
1058 | 1048 | ||
1059 | /* All modules must be present at their original addresses */ | 1049 | /* Modules and kernel must be present at their original addresses */ |
1060 | if (validate_kcore_modules(kallsyms_filename, map)) | 1050 | if (validate_kcore_addresses(kallsyms_filename, map)) |
1061 | return -EINVAL; | 1051 | return -EINVAL; |
1062 | 1052 | ||
1063 | md.dso = dso; | 1053 | md.dso = dso; |
@@ -1126,10 +1116,10 @@ static int dso__load_kcore(struct dso *dso, struct map *map, | |||
1126 | * dso__data_read_addr(). | 1116 | * dso__data_read_addr(). |
1127 | */ | 1117 | */ |
1128 | if (dso->kernel == DSO_TYPE_GUEST_KERNEL) | 1118 | if (dso->kernel == DSO_TYPE_GUEST_KERNEL) |
1129 | dso->data_type = DSO_BINARY_TYPE__GUEST_KCORE; | 1119 | dso->binary_type = DSO_BINARY_TYPE__GUEST_KCORE; |
1130 | else | 1120 | else |
1131 | dso->data_type = DSO_BINARY_TYPE__KCORE; | 1121 | dso->binary_type = DSO_BINARY_TYPE__KCORE; |
1132 | dso__set_long_name(dso, strdup(kcore_filename)); | 1122 | dso__set_long_name(dso, strdup(kcore_filename), true); |
1133 | 1123 | ||
1134 | close(fd); | 1124 | close(fd); |
1135 | 1125 | ||
@@ -1150,15 +1140,41 @@ out_err: | |||
1150 | return -EINVAL; | 1140 | return -EINVAL; |
1151 | } | 1141 | } |
1152 | 1142 | ||
1143 | /* | ||
1144 | * If the kernel is relocated at boot time, kallsyms won't match. Compute the | ||
1145 | * delta based on the relocation reference symbol. | ||
1146 | */ | ||
1147 | static int kallsyms__delta(struct map *map, const char *filename, u64 *delta) | ||
1148 | { | ||
1149 | struct kmap *kmap = map__kmap(map); | ||
1150 | u64 addr; | ||
1151 | |||
1152 | if (!kmap->ref_reloc_sym || !kmap->ref_reloc_sym->name) | ||
1153 | return 0; | ||
1154 | |||
1155 | addr = kallsyms__get_function_start(filename, | ||
1156 | kmap->ref_reloc_sym->name); | ||
1157 | if (!addr) | ||
1158 | return -1; | ||
1159 | |||
1160 | *delta = addr - kmap->ref_reloc_sym->addr; | ||
1161 | return 0; | ||
1162 | } | ||
1163 | |||
1153 | int dso__load_kallsyms(struct dso *dso, const char *filename, | 1164 | int dso__load_kallsyms(struct dso *dso, const char *filename, |
1154 | struct map *map, symbol_filter_t filter) | 1165 | struct map *map, symbol_filter_t filter) |
1155 | { | 1166 | { |
1167 | u64 delta = 0; | ||
1168 | |||
1156 | if (symbol__restricted_filename(filename, "/proc/kallsyms")) | 1169 | if (symbol__restricted_filename(filename, "/proc/kallsyms")) |
1157 | return -1; | 1170 | return -1; |
1158 | 1171 | ||
1159 | if (dso__load_all_kallsyms(dso, filename, map) < 0) | 1172 | if (dso__load_all_kallsyms(dso, filename, map) < 0) |
1160 | return -1; | 1173 | return -1; |
1161 | 1174 | ||
1175 | if (kallsyms__delta(map, filename, &delta)) | ||
1176 | return -1; | ||
1177 | |||
1162 | symbols__fixup_duplicate(&dso->symbols[map->type]); | 1178 | symbols__fixup_duplicate(&dso->symbols[map->type]); |
1163 | symbols__fixup_end(&dso->symbols[map->type]); | 1179 | symbols__fixup_end(&dso->symbols[map->type]); |
1164 | 1180 | ||
@@ -1170,7 +1186,7 @@ int dso__load_kallsyms(struct dso *dso, const char *filename, | |||
1170 | if (!dso__load_kcore(dso, map, filename)) | 1186 | if (!dso__load_kcore(dso, map, filename)) |
1171 | return dso__split_kallsyms_for_kcore(dso, map, filter); | 1187 | return dso__split_kallsyms_for_kcore(dso, map, filter); |
1172 | else | 1188 | else |
1173 | return dso__split_kallsyms(dso, map, filter); | 1189 | return dso__split_kallsyms(dso, map, delta, filter); |
1174 | } | 1190 | } |
1175 | 1191 | ||
1176 | static int dso__load_perf_map(struct dso *dso, struct map *map, | 1192 | static int dso__load_perf_map(struct dso *dso, struct map *map, |
@@ -1295,8 +1311,8 @@ int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter) | |||
1295 | 1311 | ||
1296 | enum dso_binary_type symtab_type = binary_type_symtab[i]; | 1312 | enum dso_binary_type symtab_type = binary_type_symtab[i]; |
1297 | 1313 | ||
1298 | if (dso__binary_type_file(dso, symtab_type, | 1314 | if (dso__read_binary_type_filename(dso, symtab_type, |
1299 | root_dir, name, PATH_MAX)) | 1315 | root_dir, name, PATH_MAX)) |
1300 | continue; | 1316 | continue; |
1301 | 1317 | ||
1302 | /* Name is now the name of the next image to try */ | 1318 | /* Name is now the name of the next image to try */ |
@@ -1306,6 +1322,8 @@ int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter) | |||
1306 | if (!syms_ss && symsrc__has_symtab(ss)) { | 1322 | if (!syms_ss && symsrc__has_symtab(ss)) { |
1307 | syms_ss = ss; | 1323 | syms_ss = ss; |
1308 | next_slot = true; | 1324 | next_slot = true; |
1325 | if (!dso->symsrc_filename) | ||
1326 | dso->symsrc_filename = strdup(name); | ||
1309 | } | 1327 | } |
1310 | 1328 | ||
1311 | if (!runtime_ss && symsrc__possibly_runtime(ss)) { | 1329 | if (!runtime_ss && symsrc__possibly_runtime(ss)) { |
@@ -1318,6 +1336,8 @@ int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter) | |||
1318 | 1336 | ||
1319 | if (syms_ss && runtime_ss) | 1337 | if (syms_ss && runtime_ss) |
1320 | break; | 1338 | break; |
1339 | } else { | ||
1340 | symsrc__destroy(ss); | ||
1321 | } | 1341 | } |
1322 | 1342 | ||
1323 | } | 1343 | } |
@@ -1376,7 +1396,8 @@ struct map *map_groups__find_by_name(struct map_groups *mg, | |||
1376 | } | 1396 | } |
1377 | 1397 | ||
1378 | int dso__load_vmlinux(struct dso *dso, struct map *map, | 1398 | int dso__load_vmlinux(struct dso *dso, struct map *map, |
1379 | const char *vmlinux, symbol_filter_t filter) | 1399 | const char *vmlinux, bool vmlinux_allocated, |
1400 | symbol_filter_t filter) | ||
1380 | { | 1401 | { |
1381 | int err = -1; | 1402 | int err = -1; |
1382 | struct symsrc ss; | 1403 | struct symsrc ss; |
@@ -1402,10 +1423,10 @@ int dso__load_vmlinux(struct dso *dso, struct map *map, | |||
1402 | 1423 | ||
1403 | if (err > 0) { | 1424 | if (err > 0) { |
1404 | if (dso->kernel == DSO_TYPE_GUEST_KERNEL) | 1425 | if (dso->kernel == DSO_TYPE_GUEST_KERNEL) |
1405 | dso->data_type = DSO_BINARY_TYPE__GUEST_VMLINUX; | 1426 | dso->binary_type = DSO_BINARY_TYPE__GUEST_VMLINUX; |
1406 | else | 1427 | else |
1407 | dso->data_type = DSO_BINARY_TYPE__VMLINUX; | 1428 | dso->binary_type = DSO_BINARY_TYPE__VMLINUX; |
1408 | dso__set_long_name(dso, (char *)vmlinux); | 1429 | dso__set_long_name(dso, vmlinux, vmlinux_allocated); |
1409 | dso__set_loaded(dso, map->type); | 1430 | dso__set_loaded(dso, map->type); |
1410 | pr_debug("Using %s for symbols\n", symfs_vmlinux); | 1431 | pr_debug("Using %s for symbols\n", symfs_vmlinux); |
1411 | } | 1432 | } |
@@ -1424,21 +1445,16 @@ int dso__load_vmlinux_path(struct dso *dso, struct map *map, | |||
1424 | 1445 | ||
1425 | filename = dso__build_id_filename(dso, NULL, 0); | 1446 | filename = dso__build_id_filename(dso, NULL, 0); |
1426 | if (filename != NULL) { | 1447 | if (filename != NULL) { |
1427 | err = dso__load_vmlinux(dso, map, filename, filter); | 1448 | err = dso__load_vmlinux(dso, map, filename, true, filter); |
1428 | if (err > 0) { | 1449 | if (err > 0) |
1429 | dso->lname_alloc = 1; | ||
1430 | goto out; | 1450 | goto out; |
1431 | } | ||
1432 | free(filename); | 1451 | free(filename); |
1433 | } | 1452 | } |
1434 | 1453 | ||
1435 | for (i = 0; i < vmlinux_path__nr_entries; ++i) { | 1454 | for (i = 0; i < vmlinux_path__nr_entries; ++i) { |
1436 | err = dso__load_vmlinux(dso, map, vmlinux_path[i], filter); | 1455 | err = dso__load_vmlinux(dso, map, vmlinux_path[i], false, filter); |
1437 | if (err > 0) { | 1456 | if (err > 0) |
1438 | dso__set_long_name(dso, strdup(vmlinux_path[i])); | ||
1439 | dso->lname_alloc = 1; | ||
1440 | break; | 1457 | break; |
1441 | } | ||
1442 | } | 1458 | } |
1443 | out: | 1459 | out: |
1444 | return err; | 1460 | return err; |
@@ -1463,7 +1479,7 @@ static int find_matching_kcore(struct map *map, char *dir, size_t dir_sz) | |||
1463 | continue; | 1479 | continue; |
1464 | scnprintf(kallsyms_filename, sizeof(kallsyms_filename), | 1480 | scnprintf(kallsyms_filename, sizeof(kallsyms_filename), |
1465 | "%s/%s/kallsyms", dir, dent->d_name); | 1481 | "%s/%s/kallsyms", dir, dent->d_name); |
1466 | if (!validate_kcore_modules(kallsyms_filename, map)) { | 1482 | if (!validate_kcore_addresses(kallsyms_filename, map)) { |
1467 | strlcpy(dir, kallsyms_filename, dir_sz); | 1483 | strlcpy(dir, kallsyms_filename, dir_sz); |
1468 | ret = 0; | 1484 | ret = 0; |
1469 | break; | 1485 | break; |
@@ -1496,14 +1512,15 @@ static char *dso__find_kallsyms(struct dso *dso, struct map *map) | |||
1496 | 1512 | ||
1497 | build_id__sprintf(dso->build_id, sizeof(dso->build_id), sbuild_id); | 1513 | build_id__sprintf(dso->build_id, sizeof(dso->build_id), sbuild_id); |
1498 | 1514 | ||
1515 | scnprintf(path, sizeof(path), "%s/[kernel.kcore]/%s", buildid_dir, | ||
1516 | sbuild_id); | ||
1517 | |||
1499 | /* Use /proc/kallsyms if possible */ | 1518 | /* Use /proc/kallsyms if possible */ |
1500 | if (is_host) { | 1519 | if (is_host) { |
1501 | DIR *d; | 1520 | DIR *d; |
1502 | int fd; | 1521 | int fd; |
1503 | 1522 | ||
1504 | /* If no cached kcore go with /proc/kallsyms */ | 1523 | /* If no cached kcore go with /proc/kallsyms */ |
1505 | scnprintf(path, sizeof(path), "%s/[kernel.kcore]/%s", | ||
1506 | buildid_dir, sbuild_id); | ||
1507 | d = opendir(path); | 1524 | d = opendir(path); |
1508 | if (!d) | 1525 | if (!d) |
1509 | goto proc_kallsyms; | 1526 | goto proc_kallsyms; |
@@ -1517,7 +1534,7 @@ static char *dso__find_kallsyms(struct dso *dso, struct map *map) | |||
1517 | if (fd != -1) { | 1534 | if (fd != -1) { |
1518 | close(fd); | 1535 | close(fd); |
1519 | /* If module maps match go with /proc/kallsyms */ | 1536 | /* If module maps match go with /proc/kallsyms */ |
1520 | if (!validate_kcore_modules("/proc/kallsyms", map)) | 1537 | if (!validate_kcore_addresses("/proc/kallsyms", map)) |
1521 | goto proc_kallsyms; | 1538 | goto proc_kallsyms; |
1522 | } | 1539 | } |
1523 | 1540 | ||
@@ -1528,6 +1545,10 @@ static char *dso__find_kallsyms(struct dso *dso, struct map *map) | |||
1528 | goto proc_kallsyms; | 1545 | goto proc_kallsyms; |
1529 | } | 1546 | } |
1530 | 1547 | ||
1548 | /* Find kallsyms in build-id cache with kcore */ | ||
1549 | if (!find_matching_kcore(map, path, sizeof(path))) | ||
1550 | return strdup(path); | ||
1551 | |||
1531 | scnprintf(path, sizeof(path), "%s/[kernel.kallsyms]/%s", | 1552 | scnprintf(path, sizeof(path), "%s/[kernel.kallsyms]/%s", |
1532 | buildid_dir, sbuild_id); | 1553 | buildid_dir, sbuild_id); |
1533 | 1554 | ||
@@ -1570,15 +1591,8 @@ static int dso__load_kernel_sym(struct dso *dso, struct map *map, | |||
1570 | } | 1591 | } |
1571 | 1592 | ||
1572 | if (!symbol_conf.ignore_vmlinux && symbol_conf.vmlinux_name != NULL) { | 1593 | if (!symbol_conf.ignore_vmlinux && symbol_conf.vmlinux_name != NULL) { |
1573 | err = dso__load_vmlinux(dso, map, | 1594 | return dso__load_vmlinux(dso, map, symbol_conf.vmlinux_name, |
1574 | symbol_conf.vmlinux_name, filter); | 1595 | false, filter); |
1575 | if (err > 0) { | ||
1576 | dso__set_long_name(dso, | ||
1577 | strdup(symbol_conf.vmlinux_name)); | ||
1578 | dso->lname_alloc = 1; | ||
1579 | return err; | ||
1580 | } | ||
1581 | return err; | ||
1582 | } | 1596 | } |
1583 | 1597 | ||
1584 | if (!symbol_conf.ignore_vmlinux && vmlinux_path != NULL) { | 1598 | if (!symbol_conf.ignore_vmlinux && vmlinux_path != NULL) { |
@@ -1604,7 +1618,7 @@ do_kallsyms: | |||
1604 | free(kallsyms_allocated_filename); | 1618 | free(kallsyms_allocated_filename); |
1605 | 1619 | ||
1606 | if (err > 0 && !dso__is_kcore(dso)) { | 1620 | if (err > 0 && !dso__is_kcore(dso)) { |
1607 | dso__set_long_name(dso, strdup("[kernel.kallsyms]")); | 1621 | dso__set_long_name(dso, "[kernel.kallsyms]", false); |
1608 | map__fixup_start(map); | 1622 | map__fixup_start(map); |
1609 | map__fixup_end(map); | 1623 | map__fixup_end(map); |
1610 | } | 1624 | } |
@@ -1634,7 +1648,8 @@ static int dso__load_guest_kernel_sym(struct dso *dso, struct map *map, | |||
1634 | */ | 1648 | */ |
1635 | if (symbol_conf.default_guest_vmlinux_name != NULL) { | 1649 | if (symbol_conf.default_guest_vmlinux_name != NULL) { |
1636 | err = dso__load_vmlinux(dso, map, | 1650 | err = dso__load_vmlinux(dso, map, |
1637 | symbol_conf.default_guest_vmlinux_name, filter); | 1651 | symbol_conf.default_guest_vmlinux_name, |
1652 | false, filter); | ||
1638 | return err; | 1653 | return err; |
1639 | } | 1654 | } |
1640 | 1655 | ||
@@ -1651,7 +1666,7 @@ static int dso__load_guest_kernel_sym(struct dso *dso, struct map *map, | |||
1651 | pr_debug("Using %s for symbols\n", kallsyms_filename); | 1666 | pr_debug("Using %s for symbols\n", kallsyms_filename); |
1652 | if (err > 0 && !dso__is_kcore(dso)) { | 1667 | if (err > 0 && !dso__is_kcore(dso)) { |
1653 | machine__mmap_name(machine, path, sizeof(path)); | 1668 | machine__mmap_name(machine, path, sizeof(path)); |
1654 | dso__set_long_name(dso, strdup(path)); | 1669 | dso__set_long_name(dso, strdup(path), true); |
1655 | map__fixup_start(map); | 1670 | map__fixup_start(map); |
1656 | map__fixup_end(map); | 1671 | map__fixup_end(map); |
1657 | } | 1672 | } |
@@ -1661,13 +1676,10 @@ static int dso__load_guest_kernel_sym(struct dso *dso, struct map *map, | |||
1661 | 1676 | ||
1662 | static void vmlinux_path__exit(void) | 1677 | static void vmlinux_path__exit(void) |
1663 | { | 1678 | { |
1664 | while (--vmlinux_path__nr_entries >= 0) { | 1679 | while (--vmlinux_path__nr_entries >= 0) |
1665 | free(vmlinux_path[vmlinux_path__nr_entries]); | 1680 | zfree(&vmlinux_path[vmlinux_path__nr_entries]); |
1666 | vmlinux_path[vmlinux_path__nr_entries] = NULL; | ||
1667 | } | ||
1668 | 1681 | ||
1669 | free(vmlinux_path); | 1682 | zfree(&vmlinux_path); |
1670 | vmlinux_path = NULL; | ||
1671 | } | 1683 | } |
1672 | 1684 | ||
1673 | static int vmlinux_path__init(void) | 1685 | static int vmlinux_path__init(void) |
@@ -1719,7 +1731,7 @@ out_fail: | |||
1719 | return -1; | 1731 | return -1; |
1720 | } | 1732 | } |
1721 | 1733 | ||
1722 | static int setup_list(struct strlist **list, const char *list_str, | 1734 | int setup_list(struct strlist **list, const char *list_str, |
1723 | const char *list_name) | 1735 | const char *list_name) |
1724 | { | 1736 | { |
1725 | if (list_str == NULL) | 1737 | if (list_str == NULL) |
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h index 07de8fea2f48..fffe2888a1c7 100644 --- a/tools/perf/util/symbol.h +++ b/tools/perf/util/symbol.h | |||
@@ -52,6 +52,11 @@ static inline char *bfd_demangle(void __maybe_unused *v, | |||
52 | # define PERF_ELF_C_READ_MMAP ELF_C_READ | 52 | # define PERF_ELF_C_READ_MMAP ELF_C_READ |
53 | #endif | 53 | #endif |
54 | 54 | ||
55 | #ifdef HAVE_LIBELF_SUPPORT | ||
56 | extern Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep, | ||
57 | GElf_Shdr *shp, const char *name, size_t *idx); | ||
58 | #endif | ||
59 | |||
55 | #ifndef DMGL_PARAMS | 60 | #ifndef DMGL_PARAMS |
56 | #define DMGL_PARAMS (1 << 0) /* Include function args */ | 61 | #define DMGL_PARAMS (1 << 0) /* Include function args */ |
57 | #define DMGL_ANSI (1 << 1) /* Include const, volatile, etc */ | 62 | #define DMGL_ANSI (1 << 1) /* Include const, volatile, etc */ |
@@ -164,6 +169,7 @@ struct mem_info { | |||
164 | }; | 169 | }; |
165 | 170 | ||
166 | struct addr_location { | 171 | struct addr_location { |
172 | struct machine *machine; | ||
167 | struct thread *thread; | 173 | struct thread *thread; |
168 | struct map *map; | 174 | struct map *map; |
169 | struct symbol *sym; | 175 | struct symbol *sym; |
@@ -206,7 +212,8 @@ bool symsrc__possibly_runtime(struct symsrc *ss); | |||
206 | 212 | ||
207 | int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter); | 213 | int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter); |
208 | int dso__load_vmlinux(struct dso *dso, struct map *map, | 214 | int dso__load_vmlinux(struct dso *dso, struct map *map, |
209 | const char *vmlinux, symbol_filter_t filter); | 215 | const char *vmlinux, bool vmlinux_allocated, |
216 | symbol_filter_t filter); | ||
210 | int dso__load_vmlinux_path(struct dso *dso, struct map *map, | 217 | int dso__load_vmlinux_path(struct dso *dso, struct map *map, |
211 | symbol_filter_t filter); | 218 | symbol_filter_t filter); |
212 | int dso__load_kallsyms(struct dso *dso, const char *filename, struct map *map, | 219 | int dso__load_kallsyms(struct dso *dso, const char *filename, struct map *map, |
@@ -220,9 +227,6 @@ struct symbol *dso__first_symbol(struct dso *dso, enum map_type type); | |||
220 | 227 | ||
221 | int filename__read_build_id(const char *filename, void *bf, size_t size); | 228 | int filename__read_build_id(const char *filename, void *bf, size_t size); |
222 | int sysfs__read_build_id(const char *filename, void *bf, size_t size); | 229 | int sysfs__read_build_id(const char *filename, void *bf, size_t size); |
223 | int kallsyms__parse(const char *filename, void *arg, | ||
224 | int (*process_symbol)(void *arg, const char *name, | ||
225 | char type, u64 start)); | ||
226 | int modules__parse(const char *filename, void *arg, | 230 | int modules__parse(const char *filename, void *arg, |
227 | int (*process_module)(void *arg, const char *name, | 231 | int (*process_module)(void *arg, const char *name, |
228 | u64 start)); | 232 | u64 start)); |
@@ -240,6 +244,7 @@ size_t symbol__fprintf(struct symbol *sym, FILE *fp); | |||
240 | bool symbol_type__is_a(char symbol_type, enum map_type map_type); | 244 | bool symbol_type__is_a(char symbol_type, enum map_type map_type); |
241 | bool symbol__restricted_filename(const char *filename, | 245 | bool symbol__restricted_filename(const char *filename, |
242 | const char *restricted_filename); | 246 | const char *restricted_filename); |
247 | bool symbol__is_idle(struct symbol *sym); | ||
243 | 248 | ||
244 | int dso__load_sym(struct dso *dso, struct map *map, struct symsrc *syms_ss, | 249 | int dso__load_sym(struct dso *dso, struct map *map, struct symsrc *syms_ss, |
245 | struct symsrc *runtime_ss, symbol_filter_t filter, | 250 | struct symsrc *runtime_ss, symbol_filter_t filter, |
@@ -273,4 +278,7 @@ void kcore_extract__delete(struct kcore_extract *kce); | |||
273 | int kcore_copy(const char *from_dir, const char *to_dir); | 278 | int kcore_copy(const char *from_dir, const char *to_dir); |
274 | int compare_proc_modules(const char *from, const char *to); | 279 | int compare_proc_modules(const char *from, const char *to); |
275 | 280 | ||
281 | int setup_list(struct strlist **list, const char *list_str, | ||
282 | const char *list_name); | ||
283 | |||
276 | #endif /* __PERF_SYMBOL */ | 284 | #endif /* __PERF_SYMBOL */ |
diff --git a/tools/perf/util/target.c b/tools/perf/util/target.c index 3c778a07b7cc..e74c5963dc7a 100644 --- a/tools/perf/util/target.c +++ b/tools/perf/util/target.c | |||
@@ -55,6 +55,13 @@ enum target_errno target__validate(struct target *target) | |||
55 | ret = TARGET_ERRNO__UID_OVERRIDE_SYSTEM; | 55 | ret = TARGET_ERRNO__UID_OVERRIDE_SYSTEM; |
56 | } | 56 | } |
57 | 57 | ||
58 | /* THREAD and SYSTEM/CPU are mutually exclusive */ | ||
59 | if (target->per_thread && (target->system_wide || target->cpu_list)) { | ||
60 | target->per_thread = false; | ||
61 | if (ret == TARGET_ERRNO__SUCCESS) | ||
62 | ret = TARGET_ERRNO__SYSTEM_OVERRIDE_THREAD; | ||
63 | } | ||
64 | |||
58 | return ret; | 65 | return ret; |
59 | } | 66 | } |
60 | 67 | ||
@@ -100,6 +107,7 @@ static const char *target__error_str[] = { | |||
100 | "UID switch overriding CPU", | 107 | "UID switch overriding CPU", |
101 | "PID/TID switch overriding SYSTEM", | 108 | "PID/TID switch overriding SYSTEM", |
102 | "UID switch overriding SYSTEM", | 109 | "UID switch overriding SYSTEM", |
110 | "SYSTEM/CPU switch overriding PER-THREAD", | ||
103 | "Invalid User: %s", | 111 | "Invalid User: %s", |
104 | "Problems obtaining information for user %s", | 112 | "Problems obtaining information for user %s", |
105 | }; | 113 | }; |
@@ -131,7 +139,8 @@ int target__strerror(struct target *target, int errnum, | |||
131 | msg = target__error_str[idx]; | 139 | msg = target__error_str[idx]; |
132 | 140 | ||
133 | switch (errnum) { | 141 | switch (errnum) { |
134 | case TARGET_ERRNO__PID_OVERRIDE_CPU ... TARGET_ERRNO__UID_OVERRIDE_SYSTEM: | 142 | case TARGET_ERRNO__PID_OVERRIDE_CPU ... |
143 | TARGET_ERRNO__SYSTEM_OVERRIDE_THREAD: | ||
135 | snprintf(buf, buflen, "%s", msg); | 144 | snprintf(buf, buflen, "%s", msg); |
136 | break; | 145 | break; |
137 | 146 | ||
diff --git a/tools/perf/util/target.h b/tools/perf/util/target.h index 2d0c50690892..7381b1ca4041 100644 --- a/tools/perf/util/target.h +++ b/tools/perf/util/target.h | |||
@@ -12,7 +12,8 @@ struct target { | |||
12 | uid_t uid; | 12 | uid_t uid; |
13 | bool system_wide; | 13 | bool system_wide; |
14 | bool uses_mmap; | 14 | bool uses_mmap; |
15 | bool force_per_cpu; | 15 | bool default_per_cpu; |
16 | bool per_thread; | ||
16 | }; | 17 | }; |
17 | 18 | ||
18 | enum target_errno { | 19 | enum target_errno { |
@@ -33,6 +34,7 @@ enum target_errno { | |||
33 | TARGET_ERRNO__UID_OVERRIDE_CPU, | 34 | TARGET_ERRNO__UID_OVERRIDE_CPU, |
34 | TARGET_ERRNO__PID_OVERRIDE_SYSTEM, | 35 | TARGET_ERRNO__PID_OVERRIDE_SYSTEM, |
35 | TARGET_ERRNO__UID_OVERRIDE_SYSTEM, | 36 | TARGET_ERRNO__UID_OVERRIDE_SYSTEM, |
37 | TARGET_ERRNO__SYSTEM_OVERRIDE_THREAD, | ||
36 | 38 | ||
37 | /* for target__parse_uid() */ | 39 | /* for target__parse_uid() */ |
38 | TARGET_ERRNO__INVALID_UID, | 40 | TARGET_ERRNO__INVALID_UID, |
@@ -61,4 +63,17 @@ static inline bool target__none(struct target *target) | |||
61 | return !target__has_task(target) && !target__has_cpu(target); | 63 | return !target__has_task(target) && !target__has_cpu(target); |
62 | } | 64 | } |
63 | 65 | ||
66 | static inline bool target__uses_dummy_map(struct target *target) | ||
67 | { | ||
68 | bool use_dummy = false; | ||
69 | |||
70 | if (target->default_per_cpu) | ||
71 | use_dummy = target->per_thread ? true : false; | ||
72 | else if (target__has_task(target) || | ||
73 | (!target__has_cpu(target) && !target->uses_mmap)) | ||
74 | use_dummy = true; | ||
75 | |||
76 | return use_dummy; | ||
77 | } | ||
78 | |||
64 | #endif /* _PERF_TARGET_H */ | 79 | #endif /* _PERF_TARGET_H */ |
diff --git a/tools/perf/util/thread.c b/tools/perf/util/thread.c index 49eaf1d7d89d..0358882c8910 100644 --- a/tools/perf/util/thread.c +++ b/tools/perf/util/thread.c | |||
@@ -66,10 +66,13 @@ struct comm *thread__comm(const struct thread *thread) | |||
66 | int thread__set_comm(struct thread *thread, const char *str, u64 timestamp) | 66 | int thread__set_comm(struct thread *thread, const char *str, u64 timestamp) |
67 | { | 67 | { |
68 | struct comm *new, *curr = thread__comm(thread); | 68 | struct comm *new, *curr = thread__comm(thread); |
69 | int err; | ||
69 | 70 | ||
70 | /* Override latest entry if it had no specific time coverage */ | 71 | /* Override latest entry if it had no specific time coverage */ |
71 | if (!curr->start) { | 72 | if (!curr->start) { |
72 | comm__override(curr, str, timestamp); | 73 | err = comm__override(curr, str, timestamp); |
74 | if (err) | ||
75 | return err; | ||
73 | } else { | 76 | } else { |
74 | new = comm__new(str, timestamp); | 77 | new = comm__new(str, timestamp); |
75 | if (!new) | 78 | if (!new) |
@@ -126,7 +129,7 @@ int thread__fork(struct thread *thread, struct thread *parent, u64 timestamp) | |||
126 | if (!comm) | 129 | if (!comm) |
127 | return -ENOMEM; | 130 | return -ENOMEM; |
128 | err = thread__set_comm(thread, comm, timestamp); | 131 | err = thread__set_comm(thread, comm, timestamp); |
129 | if (!err) | 132 | if (err) |
130 | return err; | 133 | return err; |
131 | thread->comm_set = true; | 134 | thread->comm_set = true; |
132 | } | 135 | } |
diff --git a/tools/perf/util/thread.h b/tools/perf/util/thread.h index 897c1b2a750a..5b856bf942e1 100644 --- a/tools/perf/util/thread.h +++ b/tools/perf/util/thread.h | |||
@@ -6,6 +6,7 @@ | |||
6 | #include <unistd.h> | 6 | #include <unistd.h> |
7 | #include <sys/types.h> | 7 | #include <sys/types.h> |
8 | #include "symbol.h" | 8 | #include "symbol.h" |
9 | #include <strlist.h> | ||
9 | 10 | ||
10 | struct thread { | 11 | struct thread { |
11 | union { | 12 | union { |
@@ -66,4 +67,15 @@ static inline void thread__set_priv(struct thread *thread, void *p) | |||
66 | { | 67 | { |
67 | thread->priv = p; | 68 | thread->priv = p; |
68 | } | 69 | } |
70 | |||
71 | static inline bool thread__is_filtered(struct thread *thread) | ||
72 | { | ||
73 | if (symbol_conf.comm_list && | ||
74 | !strlist__has_entry(symbol_conf.comm_list, thread__comm_str(thread))) { | ||
75 | return true; | ||
76 | } | ||
77 | |||
78 | return false; | ||
79 | } | ||
80 | |||
69 | #endif /* __PERF_THREAD_H */ | 81 | #endif /* __PERF_THREAD_H */ |
diff --git a/tools/perf/util/thread_map.c b/tools/perf/util/thread_map.c index 9b5f856cc280..5d3215912105 100644 --- a/tools/perf/util/thread_map.c +++ b/tools/perf/util/thread_map.c | |||
@@ -9,6 +9,7 @@ | |||
9 | #include "strlist.h" | 9 | #include "strlist.h" |
10 | #include <string.h> | 10 | #include <string.h> |
11 | #include "thread_map.h" | 11 | #include "thread_map.h" |
12 | #include "util.h" | ||
12 | 13 | ||
13 | /* Skip "." and ".." directories */ | 14 | /* Skip "." and ".." directories */ |
14 | static int filter(const struct dirent *dir) | 15 | static int filter(const struct dirent *dir) |
@@ -40,7 +41,7 @@ struct thread_map *thread_map__new_by_pid(pid_t pid) | |||
40 | } | 41 | } |
41 | 42 | ||
42 | for (i=0; i<items; i++) | 43 | for (i=0; i<items; i++) |
43 | free(namelist[i]); | 44 | zfree(&namelist[i]); |
44 | free(namelist); | 45 | free(namelist); |
45 | 46 | ||
46 | return threads; | 47 | return threads; |
@@ -117,7 +118,7 @@ struct thread_map *thread_map__new_by_uid(uid_t uid) | |||
117 | threads->map[threads->nr + i] = atoi(namelist[i]->d_name); | 118 | threads->map[threads->nr + i] = atoi(namelist[i]->d_name); |
118 | 119 | ||
119 | for (i = 0; i < items; i++) | 120 | for (i = 0; i < items; i++) |
120 | free(namelist[i]); | 121 | zfree(&namelist[i]); |
121 | free(namelist); | 122 | free(namelist); |
122 | 123 | ||
123 | threads->nr += items; | 124 | threads->nr += items; |
@@ -134,12 +135,11 @@ out_free_threads: | |||
134 | 135 | ||
135 | out_free_namelist: | 136 | out_free_namelist: |
136 | for (i = 0; i < items; i++) | 137 | for (i = 0; i < items; i++) |
137 | free(namelist[i]); | 138 | zfree(&namelist[i]); |
138 | free(namelist); | 139 | free(namelist); |
139 | 140 | ||
140 | out_free_closedir: | 141 | out_free_closedir: |
141 | free(threads); | 142 | zfree(&threads); |
142 | threads = NULL; | ||
143 | goto out_closedir; | 143 | goto out_closedir; |
144 | } | 144 | } |
145 | 145 | ||
@@ -194,7 +194,7 @@ static struct thread_map *thread_map__new_by_pid_str(const char *pid_str) | |||
194 | 194 | ||
195 | for (i = 0; i < items; i++) { | 195 | for (i = 0; i < items; i++) { |
196 | threads->map[j++] = atoi(namelist[i]->d_name); | 196 | threads->map[j++] = atoi(namelist[i]->d_name); |
197 | free(namelist[i]); | 197 | zfree(&namelist[i]); |
198 | } | 198 | } |
199 | threads->nr = total_tasks; | 199 | threads->nr = total_tasks; |
200 | free(namelist); | 200 | free(namelist); |
@@ -206,12 +206,11 @@ out: | |||
206 | 206 | ||
207 | out_free_namelist: | 207 | out_free_namelist: |
208 | for (i = 0; i < items; i++) | 208 | for (i = 0; i < items; i++) |
209 | free(namelist[i]); | 209 | zfree(&namelist[i]); |
210 | free(namelist); | 210 | free(namelist); |
211 | 211 | ||
212 | out_free_threads: | 212 | out_free_threads: |
213 | free(threads); | 213 | zfree(&threads); |
214 | threads = NULL; | ||
215 | goto out; | 214 | goto out; |
216 | } | 215 | } |
217 | 216 | ||
@@ -262,8 +261,7 @@ out: | |||
262 | return threads; | 261 | return threads; |
263 | 262 | ||
264 | out_free_threads: | 263 | out_free_threads: |
265 | free(threads); | 264 | zfree(&threads); |
266 | threads = NULL; | ||
267 | goto out; | 265 | goto out; |
268 | } | 266 | } |
269 | 267 | ||
diff --git a/tools/perf/util/top.c b/tools/perf/util/top.c index ce793c7dd23c..8e517def925b 100644 --- a/tools/perf/util/top.c +++ b/tools/perf/util/top.c | |||
@@ -26,7 +26,7 @@ size_t perf_top__header_snprintf(struct perf_top *top, char *bf, size_t size) | |||
26 | float samples_per_sec; | 26 | float samples_per_sec; |
27 | float ksamples_per_sec; | 27 | float ksamples_per_sec; |
28 | float esamples_percent; | 28 | float esamples_percent; |
29 | struct perf_record_opts *opts = &top->record_opts; | 29 | struct record_opts *opts = &top->record_opts; |
30 | struct target *target = &opts->target; | 30 | struct target *target = &opts->target; |
31 | size_t ret = 0; | 31 | size_t ret = 0; |
32 | 32 | ||
diff --git a/tools/perf/util/top.h b/tools/perf/util/top.h index 88cfeaff600b..dab14d0ad3d0 100644 --- a/tools/perf/util/top.h +++ b/tools/perf/util/top.h | |||
@@ -14,7 +14,7 @@ struct perf_session; | |||
14 | struct perf_top { | 14 | struct perf_top { |
15 | struct perf_tool tool; | 15 | struct perf_tool tool; |
16 | struct perf_evlist *evlist; | 16 | struct perf_evlist *evlist; |
17 | struct perf_record_opts record_opts; | 17 | struct record_opts record_opts; |
18 | /* | 18 | /* |
19 | * Symbols will be added here in perf_event__process_sample and will | 19 | * Symbols will be added here in perf_event__process_sample and will |
20 | * get out after decayed. | 20 | * get out after decayed. |
diff --git a/tools/perf/util/trace-event-info.c b/tools/perf/util/trace-event-info.c index f3c9e551bd35..7e6fcfe8b438 100644 --- a/tools/perf/util/trace-event-info.c +++ b/tools/perf/util/trace-event-info.c | |||
@@ -38,7 +38,7 @@ | |||
38 | 38 | ||
39 | #include "../perf.h" | 39 | #include "../perf.h" |
40 | #include "trace-event.h" | 40 | #include "trace-event.h" |
41 | #include <lk/debugfs.h> | 41 | #include <api/fs/debugfs.h> |
42 | #include "evsel.h" | 42 | #include "evsel.h" |
43 | 43 | ||
44 | #define VERSION "0.5" | 44 | #define VERSION "0.5" |
@@ -397,8 +397,8 @@ put_tracepoints_path(struct tracepoint_path *tps) | |||
397 | struct tracepoint_path *t = tps; | 397 | struct tracepoint_path *t = tps; |
398 | 398 | ||
399 | tps = tps->next; | 399 | tps = tps->next; |
400 | free(t->name); | 400 | zfree(&t->name); |
401 | free(t->system); | 401 | zfree(&t->system); |
402 | free(t); | 402 | free(t); |
403 | } | 403 | } |
404 | } | 404 | } |
@@ -562,10 +562,8 @@ out: | |||
562 | output_fd = fd; | 562 | output_fd = fd; |
563 | } | 563 | } |
564 | 564 | ||
565 | if (err) { | 565 | if (err) |
566 | free(tdata); | 566 | zfree(&tdata); |
567 | tdata = NULL; | ||
568 | } | ||
569 | 567 | ||
570 | put_tracepoints_path(tps); | 568 | put_tracepoints_path(tps); |
571 | return tdata; | 569 | return tdata; |
diff --git a/tools/perf/util/trace-event-parse.c b/tools/perf/util/trace-event-parse.c index 6681f71f2f95..e0d6d07f6848 100644 --- a/tools/perf/util/trace-event-parse.c +++ b/tools/perf/util/trace-event-parse.c | |||
@@ -28,19 +28,6 @@ | |||
28 | #include "util.h" | 28 | #include "util.h" |
29 | #include "trace-event.h" | 29 | #include "trace-event.h" |
30 | 30 | ||
31 | struct pevent *read_trace_init(int file_bigendian, int host_bigendian) | ||
32 | { | ||
33 | struct pevent *pevent = pevent_alloc(); | ||
34 | |||
35 | if (pevent != NULL) { | ||
36 | pevent_set_flag(pevent, PEVENT_NSEC_OUTPUT); | ||
37 | pevent_set_file_bigendian(pevent, file_bigendian); | ||
38 | pevent_set_host_bigendian(pevent, host_bigendian); | ||
39 | } | ||
40 | |||
41 | return pevent; | ||
42 | } | ||
43 | |||
44 | static int get_common_field(struct scripting_context *context, | 31 | static int get_common_field(struct scripting_context *context, |
45 | int *offset, int *size, const char *type) | 32 | int *offset, int *size, const char *type) |
46 | { | 33 | { |
diff --git a/tools/perf/util/trace-event-read.c b/tools/perf/util/trace-event-read.c index f2112270c663..e113e180c48f 100644 --- a/tools/perf/util/trace-event-read.c +++ b/tools/perf/util/trace-event-read.c | |||
@@ -343,7 +343,7 @@ static int read_event_files(struct pevent *pevent) | |||
343 | return 0; | 343 | return 0; |
344 | } | 344 | } |
345 | 345 | ||
346 | ssize_t trace_report(int fd, struct pevent **ppevent, bool __repipe) | 346 | ssize_t trace_report(int fd, struct trace_event *tevent, bool __repipe) |
347 | { | 347 | { |
348 | char buf[BUFSIZ]; | 348 | char buf[BUFSIZ]; |
349 | char test[] = { 23, 8, 68 }; | 349 | char test[] = { 23, 8, 68 }; |
@@ -356,11 +356,9 @@ ssize_t trace_report(int fd, struct pevent **ppevent, bool __repipe) | |||
356 | int host_bigendian; | 356 | int host_bigendian; |
357 | int file_long_size; | 357 | int file_long_size; |
358 | int file_page_size; | 358 | int file_page_size; |
359 | struct pevent *pevent; | 359 | struct pevent *pevent = NULL; |
360 | int err; | 360 | int err; |
361 | 361 | ||
362 | *ppevent = NULL; | ||
363 | |||
364 | repipe = __repipe; | 362 | repipe = __repipe; |
365 | input_fd = fd; | 363 | input_fd = fd; |
366 | 364 | ||
@@ -390,12 +388,17 @@ ssize_t trace_report(int fd, struct pevent **ppevent, bool __repipe) | |||
390 | file_bigendian = buf[0]; | 388 | file_bigendian = buf[0]; |
391 | host_bigendian = bigendian(); | 389 | host_bigendian = bigendian(); |
392 | 390 | ||
393 | pevent = read_trace_init(file_bigendian, host_bigendian); | 391 | if (trace_event__init(tevent)) { |
394 | if (pevent == NULL) { | 392 | pr_debug("trace_event__init failed"); |
395 | pr_debug("read_trace_init failed"); | ||
396 | goto out; | 393 | goto out; |
397 | } | 394 | } |
398 | 395 | ||
396 | pevent = tevent->pevent; | ||
397 | |||
398 | pevent_set_flag(pevent, PEVENT_NSEC_OUTPUT); | ||
399 | pevent_set_file_bigendian(pevent, file_bigendian); | ||
400 | pevent_set_host_bigendian(pevent, host_bigendian); | ||
401 | |||
399 | if (do_read(buf, 1) < 0) | 402 | if (do_read(buf, 1) < 0) |
400 | goto out; | 403 | goto out; |
401 | file_long_size = buf[0]; | 404 | file_long_size = buf[0]; |
@@ -432,11 +435,10 @@ ssize_t trace_report(int fd, struct pevent **ppevent, bool __repipe) | |||
432 | pevent_print_printk(pevent); | 435 | pevent_print_printk(pevent); |
433 | } | 436 | } |
434 | 437 | ||
435 | *ppevent = pevent; | ||
436 | pevent = NULL; | 438 | pevent = NULL; |
437 | 439 | ||
438 | out: | 440 | out: |
439 | if (pevent) | 441 | if (pevent) |
440 | pevent_free(pevent); | 442 | trace_event__cleanup(tevent); |
441 | return size; | 443 | return size; |
442 | } | 444 | } |
diff --git a/tools/perf/util/trace-event-scripting.c b/tools/perf/util/trace-event-scripting.c index 95199e4eea97..57aaccc1692e 100644 --- a/tools/perf/util/trace-event-scripting.c +++ b/tools/perf/util/trace-event-scripting.c | |||
@@ -38,9 +38,8 @@ static int stop_script_unsupported(void) | |||
38 | static void process_event_unsupported(union perf_event *event __maybe_unused, | 38 | static void process_event_unsupported(union perf_event *event __maybe_unused, |
39 | struct perf_sample *sample __maybe_unused, | 39 | struct perf_sample *sample __maybe_unused, |
40 | struct perf_evsel *evsel __maybe_unused, | 40 | struct perf_evsel *evsel __maybe_unused, |
41 | struct machine *machine __maybe_unused, | ||
42 | struct thread *thread __maybe_unused, | 41 | struct thread *thread __maybe_unused, |
43 | struct addr_location *al __maybe_unused) | 42 | struct addr_location *al __maybe_unused) |
44 | { | 43 | { |
45 | } | 44 | } |
46 | 45 | ||
diff --git a/tools/perf/util/trace-event.c b/tools/perf/util/trace-event.c new file mode 100644 index 000000000000..6322d37164c5 --- /dev/null +++ b/tools/perf/util/trace-event.c | |||
@@ -0,0 +1,82 @@ | |||
1 | |||
2 | #include <stdio.h> | ||
3 | #include <unistd.h> | ||
4 | #include <stdlib.h> | ||
5 | #include <errno.h> | ||
6 | #include <sys/types.h> | ||
7 | #include <sys/stat.h> | ||
8 | #include <fcntl.h> | ||
9 | #include <linux/kernel.h> | ||
10 | #include <traceevent/event-parse.h> | ||
11 | #include "trace-event.h" | ||
12 | #include "util.h" | ||
13 | |||
14 | /* | ||
15 | * global trace_event object used by trace_event__tp_format | ||
16 | * | ||
17 | * TODO There's no cleanup call for this. Add some sort of | ||
18 | * __exit function support and call trace_event__cleanup | ||
19 | * there. | ||
20 | */ | ||
21 | static struct trace_event tevent; | ||
22 | |||
23 | int trace_event__init(struct trace_event *t) | ||
24 | { | ||
25 | struct pevent *pevent = pevent_alloc(); | ||
26 | |||
27 | if (pevent) { | ||
28 | t->plugin_list = traceevent_load_plugins(pevent); | ||
29 | t->pevent = pevent; | ||
30 | } | ||
31 | |||
32 | return pevent ? 0 : -1; | ||
33 | } | ||
34 | |||
35 | void trace_event__cleanup(struct trace_event *t) | ||
36 | { | ||
37 | traceevent_unload_plugins(t->plugin_list, t->pevent); | ||
38 | pevent_free(t->pevent); | ||
39 | } | ||
40 | |||
41 | static struct event_format* | ||
42 | tp_format(const char *sys, const char *name) | ||
43 | { | ||
44 | struct pevent *pevent = tevent.pevent; | ||
45 | struct event_format *event = NULL; | ||
46 | char path[PATH_MAX]; | ||
47 | size_t size; | ||
48 | char *data; | ||
49 | |||
50 | scnprintf(path, PATH_MAX, "%s/%s/%s/format", | ||
51 | tracing_events_path, sys, name); | ||
52 | |||
53 | if (filename__read_str(path, &data, &size)) | ||
54 | return NULL; | ||
55 | |||
56 | pevent_parse_format(pevent, &event, data, size, sys); | ||
57 | |||
58 | free(data); | ||
59 | return event; | ||
60 | } | ||
61 | |||
62 | struct event_format* | ||
63 | trace_event__tp_format(const char *sys, const char *name) | ||
64 | { | ||
65 | static bool initialized; | ||
66 | |||
67 | if (!initialized) { | ||
68 | int be = traceevent_host_bigendian(); | ||
69 | struct pevent *pevent; | ||
70 | |||
71 | if (trace_event__init(&tevent)) | ||
72 | return NULL; | ||
73 | |||
74 | pevent = tevent.pevent; | ||
75 | pevent_set_flag(pevent, PEVENT_NSEC_OUTPUT); | ||
76 | pevent_set_file_bigendian(pevent, be); | ||
77 | pevent_set_host_bigendian(pevent, be); | ||
78 | initialized = true; | ||
79 | } | ||
80 | |||
81 | return tp_format(sys, name); | ||
82 | } | ||
diff --git a/tools/perf/util/trace-event.h b/tools/perf/util/trace-event.h index 04df63114109..7b6d68688327 100644 --- a/tools/perf/util/trace-event.h +++ b/tools/perf/util/trace-event.h | |||
@@ -3,17 +3,26 @@ | |||
3 | 3 | ||
4 | #include <traceevent/event-parse.h> | 4 | #include <traceevent/event-parse.h> |
5 | #include "parse-events.h" | 5 | #include "parse-events.h" |
6 | #include "session.h" | ||
7 | 6 | ||
8 | struct machine; | 7 | struct machine; |
9 | struct perf_sample; | 8 | struct perf_sample; |
10 | union perf_event; | 9 | union perf_event; |
11 | struct perf_tool; | 10 | struct perf_tool; |
12 | struct thread; | 11 | struct thread; |
12 | struct plugin_list; | ||
13 | |||
14 | struct trace_event { | ||
15 | struct pevent *pevent; | ||
16 | struct plugin_list *plugin_list; | ||
17 | }; | ||
18 | |||
19 | int trace_event__init(struct trace_event *t); | ||
20 | void trace_event__cleanup(struct trace_event *t); | ||
21 | struct event_format* | ||
22 | trace_event__tp_format(const char *sys, const char *name); | ||
13 | 23 | ||
14 | int bigendian(void); | 24 | int bigendian(void); |
15 | 25 | ||
16 | struct pevent *read_trace_init(int file_bigendian, int host_bigendian); | ||
17 | void event_format__print(struct event_format *event, | 26 | void event_format__print(struct event_format *event, |
18 | int cpu, void *data, int size); | 27 | int cpu, void *data, int size); |
19 | 28 | ||
@@ -27,7 +36,7 @@ raw_field_value(struct event_format *event, const char *name, void *data); | |||
27 | void parse_proc_kallsyms(struct pevent *pevent, char *file, unsigned int size); | 36 | void parse_proc_kallsyms(struct pevent *pevent, char *file, unsigned int size); |
28 | void parse_ftrace_printk(struct pevent *pevent, char *file, unsigned int size); | 37 | void parse_ftrace_printk(struct pevent *pevent, char *file, unsigned int size); |
29 | 38 | ||
30 | ssize_t trace_report(int fd, struct pevent **pevent, bool repipe); | 39 | ssize_t trace_report(int fd, struct trace_event *tevent, bool repipe); |
31 | 40 | ||
32 | struct event_format *trace_find_next_event(struct pevent *pevent, | 41 | struct event_format *trace_find_next_event(struct pevent *pevent, |
33 | struct event_format *event); | 42 | struct event_format *event); |
@@ -59,7 +68,6 @@ struct scripting_ops { | |||
59 | void (*process_event) (union perf_event *event, | 68 | void (*process_event) (union perf_event *event, |
60 | struct perf_sample *sample, | 69 | struct perf_sample *sample, |
61 | struct perf_evsel *evsel, | 70 | struct perf_evsel *evsel, |
62 | struct machine *machine, | ||
63 | struct thread *thread, | 71 | struct thread *thread, |
64 | struct addr_location *al); | 72 | struct addr_location *al); |
65 | int (*generate_script) (struct pevent *pevent, const char *outfile); | 73 | int (*generate_script) (struct pevent *pevent, const char *outfile); |
diff --git a/tools/perf/util/unwind.c b/tools/perf/util/unwind.c index 0efd5393de85..742f23bf35ff 100644 --- a/tools/perf/util/unwind.c +++ b/tools/perf/util/unwind.c | |||
@@ -28,6 +28,7 @@ | |||
28 | #include "session.h" | 28 | #include "session.h" |
29 | #include "perf_regs.h" | 29 | #include "perf_regs.h" |
30 | #include "unwind.h" | 30 | #include "unwind.h" |
31 | #include "symbol.h" | ||
31 | #include "util.h" | 32 | #include "util.h" |
32 | 33 | ||
33 | extern int | 34 | extern int |
@@ -158,23 +159,6 @@ static int __dw_read_encoded_value(u8 **p, u8 *end, u64 *val, | |||
158 | __v; \ | 159 | __v; \ |
159 | }) | 160 | }) |
160 | 161 | ||
161 | static Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep, | ||
162 | GElf_Shdr *shp, const char *name) | ||
163 | { | ||
164 | Elf_Scn *sec = NULL; | ||
165 | |||
166 | while ((sec = elf_nextscn(elf, sec)) != NULL) { | ||
167 | char *str; | ||
168 | |||
169 | gelf_getshdr(sec, shp); | ||
170 | str = elf_strptr(elf, ep->e_shstrndx, shp->sh_name); | ||
171 | if (!strcmp(name, str)) | ||
172 | break; | ||
173 | } | ||
174 | |||
175 | return sec; | ||
176 | } | ||
177 | |||
178 | static u64 elf_section_offset(int fd, const char *name) | 162 | static u64 elf_section_offset(int fd, const char *name) |
179 | { | 163 | { |
180 | Elf *elf; | 164 | Elf *elf; |
@@ -190,7 +174,7 @@ static u64 elf_section_offset(int fd, const char *name) | |||
190 | if (gelf_getehdr(elf, &ehdr) == NULL) | 174 | if (gelf_getehdr(elf, &ehdr) == NULL) |
191 | break; | 175 | break; |
192 | 176 | ||
193 | if (!elf_section_by_name(elf, &ehdr, &shdr, name)) | 177 | if (!elf_section_by_name(elf, &ehdr, &shdr, name, NULL)) |
194 | break; | 178 | break; |
195 | 179 | ||
196 | offset = shdr.sh_offset; | 180 | offset = shdr.sh_offset; |
@@ -340,10 +324,10 @@ find_proc_info(unw_addr_space_t as, unw_word_t ip, unw_proc_info_t *pi, | |||
340 | /* Check the .debug_frame section for unwinding info */ | 324 | /* Check the .debug_frame section for unwinding info */ |
341 | if (!read_unwind_spec_debug_frame(map->dso, ui->machine, &segbase)) { | 325 | if (!read_unwind_spec_debug_frame(map->dso, ui->machine, &segbase)) { |
342 | memset(&di, 0, sizeof(di)); | 326 | memset(&di, 0, sizeof(di)); |
343 | dwarf_find_debug_frame(0, &di, ip, 0, map->dso->name, | 327 | if (dwarf_find_debug_frame(0, &di, ip, 0, map->dso->name, |
344 | map->start, map->end); | 328 | map->start, map->end)) |
345 | return dwarf_search_unwind_table(as, ip, &di, pi, | 329 | return dwarf_search_unwind_table(as, ip, &di, pi, |
346 | need_unwind_info, arg); | 330 | need_unwind_info, arg); |
347 | } | 331 | } |
348 | #endif | 332 | #endif |
349 | 333 | ||
diff --git a/tools/perf/util/util.c b/tools/perf/util/util.c index 28a0a89c1f73..42ad667bb317 100644 --- a/tools/perf/util/util.c +++ b/tools/perf/util/util.c | |||
@@ -1,11 +1,17 @@ | |||
1 | #include "../perf.h" | 1 | #include "../perf.h" |
2 | #include "util.h" | 2 | #include "util.h" |
3 | #include "fs.h" | ||
3 | #include <sys/mman.h> | 4 | #include <sys/mman.h> |
4 | #ifdef HAVE_BACKTRACE_SUPPORT | 5 | #ifdef HAVE_BACKTRACE_SUPPORT |
5 | #include <execinfo.h> | 6 | #include <execinfo.h> |
6 | #endif | 7 | #endif |
7 | #include <stdio.h> | 8 | #include <stdio.h> |
8 | #include <stdlib.h> | 9 | #include <stdlib.h> |
10 | #include <string.h> | ||
11 | #include <errno.h> | ||
12 | #include <limits.h> | ||
13 | #include <byteswap.h> | ||
14 | #include <linux/kernel.h> | ||
9 | 15 | ||
10 | /* | 16 | /* |
11 | * XXX We need to find a better place for these things... | 17 | * XXX We need to find a better place for these things... |
@@ -151,21 +157,40 @@ unsigned long convert_unit(unsigned long value, char *unit) | |||
151 | return value; | 157 | return value; |
152 | } | 158 | } |
153 | 159 | ||
154 | int readn(int fd, void *buf, size_t n) | 160 | static ssize_t ion(bool is_read, int fd, void *buf, size_t n) |
155 | { | 161 | { |
156 | void *buf_start = buf; | 162 | void *buf_start = buf; |
163 | size_t left = n; | ||
157 | 164 | ||
158 | while (n) { | 165 | while (left) { |
159 | int ret = read(fd, buf, n); | 166 | ssize_t ret = is_read ? read(fd, buf, left) : |
167 | write(fd, buf, left); | ||
160 | 168 | ||
161 | if (ret <= 0) | 169 | if (ret <= 0) |
162 | return ret; | 170 | return ret; |
163 | 171 | ||
164 | n -= ret; | 172 | left -= ret; |
165 | buf += ret; | 173 | buf += ret; |
166 | } | 174 | } |
167 | 175 | ||
168 | return buf - buf_start; | 176 | BUG_ON((size_t)(buf - buf_start) != n); |
177 | return n; | ||
178 | } | ||
179 | |||
180 | /* | ||
181 | * Read exactly 'n' bytes or return an error. | ||
182 | */ | ||
183 | ssize_t readn(int fd, void *buf, size_t n) | ||
184 | { | ||
185 | return ion(true, fd, buf, n); | ||
186 | } | ||
187 | |||
188 | /* | ||
189 | * Write exactly 'n' bytes or return an error. | ||
190 | */ | ||
191 | ssize_t writen(int fd, void *buf, size_t n) | ||
192 | { | ||
193 | return ion(false, fd, buf, n); | ||
169 | } | 194 | } |
170 | 195 | ||
171 | size_t hex_width(u64 v) | 196 | size_t hex_width(u64 v) |
@@ -413,3 +438,102 @@ int filename__read_int(const char *filename, int *value) | |||
413 | close(fd); | 438 | close(fd); |
414 | return err; | 439 | return err; |
415 | } | 440 | } |
441 | |||
442 | int filename__read_str(const char *filename, char **buf, size_t *sizep) | ||
443 | { | ||
444 | size_t size = 0, alloc_size = 0; | ||
445 | void *bf = NULL, *nbf; | ||
446 | int fd, n, err = 0; | ||
447 | |||
448 | fd = open(filename, O_RDONLY); | ||
449 | if (fd < 0) | ||
450 | return -errno; | ||
451 | |||
452 | do { | ||
453 | if (size == alloc_size) { | ||
454 | alloc_size += BUFSIZ; | ||
455 | nbf = realloc(bf, alloc_size); | ||
456 | if (!nbf) { | ||
457 | err = -ENOMEM; | ||
458 | break; | ||
459 | } | ||
460 | |||
461 | bf = nbf; | ||
462 | } | ||
463 | |||
464 | n = read(fd, bf + size, alloc_size - size); | ||
465 | if (n < 0) { | ||
466 | if (size) { | ||
467 | pr_warning("read failed %d: %s\n", | ||
468 | errno, strerror(errno)); | ||
469 | err = 0; | ||
470 | } else | ||
471 | err = -errno; | ||
472 | |||
473 | break; | ||
474 | } | ||
475 | |||
476 | size += n; | ||
477 | } while (n > 0); | ||
478 | |||
479 | if (!err) { | ||
480 | *sizep = size; | ||
481 | *buf = bf; | ||
482 | } else | ||
483 | free(bf); | ||
484 | |||
485 | close(fd); | ||
486 | return err; | ||
487 | } | ||
488 | |||
489 | const char *get_filename_for_perf_kvm(void) | ||
490 | { | ||
491 | const char *filename; | ||
492 | |||
493 | if (perf_host && !perf_guest) | ||
494 | filename = strdup("perf.data.host"); | ||
495 | else if (!perf_host && perf_guest) | ||
496 | filename = strdup("perf.data.guest"); | ||
497 | else | ||
498 | filename = strdup("perf.data.kvm"); | ||
499 | |||
500 | return filename; | ||
501 | } | ||
502 | |||
503 | int perf_event_paranoid(void) | ||
504 | { | ||
505 | char path[PATH_MAX]; | ||
506 | const char *procfs = procfs__mountpoint(); | ||
507 | int value; | ||
508 | |||
509 | if (!procfs) | ||
510 | return INT_MAX; | ||
511 | |||
512 | scnprintf(path, PATH_MAX, "%s/sys/kernel/perf_event_paranoid", procfs); | ||
513 | |||
514 | if (filename__read_int(path, &value)) | ||
515 | return INT_MAX; | ||
516 | |||
517 | return value; | ||
518 | } | ||
519 | |||
520 | void mem_bswap_32(void *src, int byte_size) | ||
521 | { | ||
522 | u32 *m = src; | ||
523 | while (byte_size > 0) { | ||
524 | *m = bswap_32(*m); | ||
525 | byte_size -= sizeof(u32); | ||
526 | ++m; | ||
527 | } | ||
528 | } | ||
529 | |||
530 | void mem_bswap_64(void *src, int byte_size) | ||
531 | { | ||
532 | u64 *m = src; | ||
533 | |||
534 | while (byte_size > 0) { | ||
535 | *m = bswap_64(*m); | ||
536 | byte_size -= sizeof(u64); | ||
537 | ++m; | ||
538 | } | ||
539 | } | ||
diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h index c8f362daba87..6995d66f225c 100644 --- a/tools/perf/util/util.h +++ b/tools/perf/util/util.h | |||
@@ -71,8 +71,9 @@ | |||
71 | #include <linux/magic.h> | 71 | #include <linux/magic.h> |
72 | #include "types.h" | 72 | #include "types.h" |
73 | #include <sys/ttydefaults.h> | 73 | #include <sys/ttydefaults.h> |
74 | #include <lk/debugfs.h> | 74 | #include <api/fs/debugfs.h> |
75 | #include <termios.h> | 75 | #include <termios.h> |
76 | #include <linux/bitops.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; |
@@ -185,6 +186,8 @@ static inline void *zalloc(size_t size) | |||
185 | return calloc(1, size); | 186 | return calloc(1, size); |
186 | } | 187 | } |
187 | 188 | ||
189 | #define zfree(ptr) ({ free(*ptr); *ptr = NULL; }) | ||
190 | |||
188 | static inline int has_extension(const char *filename, const char *ext) | 191 | static inline int has_extension(const char *filename, const char *ext) |
189 | { | 192 | { |
190 | size_t len = strlen(filename); | 193 | size_t len = strlen(filename); |
@@ -253,7 +256,8 @@ bool strlazymatch(const char *str, const char *pat); | |||
253 | int strtailcmp(const char *s1, const char *s2); | 256 | int strtailcmp(const char *s1, const char *s2); |
254 | char *strxfrchar(char *s, char from, char to); | 257 | char *strxfrchar(char *s, char from, char to); |
255 | unsigned long convert_unit(unsigned long value, char *unit); | 258 | unsigned long convert_unit(unsigned long value, char *unit); |
256 | int readn(int fd, void *buf, size_t size); | 259 | ssize_t readn(int fd, void *buf, size_t n); |
260 | ssize_t writen(int fd, void *buf, size_t n); | ||
257 | 261 | ||
258 | struct perf_event_attr; | 262 | struct perf_event_attr; |
259 | 263 | ||
@@ -280,6 +284,17 @@ static inline unsigned next_pow2(unsigned x) | |||
280 | return 1ULL << (32 - __builtin_clz(x - 1)); | 284 | return 1ULL << (32 - __builtin_clz(x - 1)); |
281 | } | 285 | } |
282 | 286 | ||
287 | static inline unsigned long next_pow2_l(unsigned long x) | ||
288 | { | ||
289 | #if BITS_PER_LONG == 64 | ||
290 | if (x <= (1UL << 31)) | ||
291 | return next_pow2(x); | ||
292 | return (unsigned long)next_pow2(x >> 32) << 32; | ||
293 | #else | ||
294 | return next_pow2(x); | ||
295 | #endif | ||
296 | } | ||
297 | |||
283 | size_t hex_width(u64 v); | 298 | size_t hex_width(u64 v); |
284 | int hex2u64(const char *ptr, u64 *val); | 299 | int hex2u64(const char *ptr, u64 *val); |
285 | 300 | ||
@@ -307,4 +322,11 @@ char *get_srcline(struct dso *dso, unsigned long addr); | |||
307 | void free_srcline(char *srcline); | 322 | void free_srcline(char *srcline); |
308 | 323 | ||
309 | int filename__read_int(const char *filename, int *value); | 324 | int filename__read_int(const char *filename, int *value); |
325 | int filename__read_str(const char *filename, char **buf, size_t *sizep); | ||
326 | int perf_event_paranoid(void); | ||
327 | |||
328 | void mem_bswap_64(void *src, int byte_size); | ||
329 | void mem_bswap_32(void *src, int byte_size); | ||
330 | |||
331 | const char *get_filename_for_perf_kvm(void); | ||
310 | #endif /* GIT_COMPAT_UTIL_H */ | 332 | #endif /* GIT_COMPAT_UTIL_H */ |
diff --git a/tools/perf/util/values.c b/tools/perf/util/values.c index 697c8b4e59cc..0fb3c1fcd3e6 100644 --- a/tools/perf/util/values.c +++ b/tools/perf/util/values.c | |||
@@ -31,14 +31,14 @@ void perf_read_values_destroy(struct perf_read_values *values) | |||
31 | return; | 31 | return; |
32 | 32 | ||
33 | for (i = 0; i < values->threads; i++) | 33 | for (i = 0; i < values->threads; i++) |
34 | free(values->value[i]); | 34 | zfree(&values->value[i]); |
35 | free(values->value); | 35 | zfree(&values->value); |
36 | free(values->pid); | 36 | zfree(&values->pid); |
37 | free(values->tid); | 37 | zfree(&values->tid); |
38 | free(values->counterrawid); | 38 | zfree(&values->counterrawid); |
39 | for (i = 0; i < values->counters; i++) | 39 | for (i = 0; i < values->counters; i++) |
40 | free(values->countername[i]); | 40 | zfree(&values->countername[i]); |
41 | free(values->countername); | 41 | zfree(&values->countername); |
42 | } | 42 | } |
43 | 43 | ||
44 | static void perf_read_values__enlarge_threads(struct perf_read_values *values) | 44 | static void perf_read_values__enlarge_threads(struct perf_read_values *values) |
diff --git a/tools/perf/util/vdso.c b/tools/perf/util/vdso.c index 39159822d58f..0ddb3b8a89ec 100644 --- a/tools/perf/util/vdso.c +++ b/tools/perf/util/vdso.c | |||
@@ -103,7 +103,7 @@ struct dso *vdso__dso_findnew(struct list_head *head) | |||
103 | dso = dso__new(VDSO__MAP_NAME); | 103 | dso = dso__new(VDSO__MAP_NAME); |
104 | if (dso != NULL) { | 104 | if (dso != NULL) { |
105 | dsos__add(head, dso); | 105 | dsos__add(head, dso); |
106 | dso__set_long_name(dso, file); | 106 | dso__set_long_name(dso, file, false); |
107 | } | 107 | } |
108 | } | 108 | } |
109 | 109 | ||
diff --git a/tools/power/acpi/Makefile b/tools/power/acpi/Makefile index bafeb8d662a3..d9186a2fdf06 100644 --- a/tools/power/acpi/Makefile +++ b/tools/power/acpi/Makefile | |||
@@ -1,18 +1,143 @@ | |||
1 | PROG= acpidump | 1 | # tools/power/acpi/Makefile - ACPI tool Makefile |
2 | SRCS= acpidump.c | 2 | # |
3 | # Copyright (c) 2013, Intel Corporation | ||
4 | # Author: Lv Zheng <lv.zheng@intel.com> | ||
5 | # | ||
6 | # This program is free software; you can redistribute it and/or | ||
7 | # modify it under the terms of the GNU General Public License | ||
8 | # as published by the Free Software Foundation; version 2 | ||
9 | # of the License. | ||
10 | |||
11 | OUTPUT=./ | ||
12 | ifeq ("$(origin O)", "command line") | ||
13 | OUTPUT := $(O)/ | ||
14 | endif | ||
15 | |||
16 | ifneq ($(OUTPUT),) | ||
17 | # check that the output directory actually exists | ||
18 | OUTDIR := $(shell cd $(OUTPUT) && /bin/pwd) | ||
19 | $(if $(OUTDIR),, $(error output directory "$(OUTPUT)" does not exist)) | ||
20 | endif | ||
21 | |||
22 | # --- CONFIGURATION BEGIN --- | ||
23 | |||
24 | # Set the following to `true' to make a unstripped, unoptimized | ||
25 | # binary. Leave this set to `false' for production use. | ||
26 | DEBUG ?= true | ||
27 | |||
28 | # make the build silent. Set this to something else to make it noisy again. | ||
29 | V ?= false | ||
30 | |||
31 | # Prefix to the directories we're installing to | ||
32 | DESTDIR ?= | ||
33 | |||
34 | # --- CONFIGURATION END --- | ||
35 | |||
36 | # Directory definitions. These are default and most probably | ||
37 | # do not need to be changed. Please note that DESTDIR is | ||
38 | # added in front of any of them | ||
39 | |||
40 | bindir ?= /usr/bin | ||
41 | sbindir ?= /usr/sbin | ||
42 | mandir ?= /usr/man | ||
43 | |||
44 | # Toolchain: what tools do we use, and what options do they need: | ||
45 | |||
46 | INSTALL = /usr/bin/install -c | ||
47 | INSTALL_PROGRAM = ${INSTALL} | ||
48 | INSTALL_DATA = ${INSTALL} -m 644 | ||
49 | INSTALL_SCRIPT = ${INSTALL_PROGRAM} | ||
50 | |||
51 | # If you are running a cross compiler, you may want to set this | ||
52 | # to something more interesting, like "arm-linux-". If you want | ||
53 | # to compile vs uClibc, that can be done here as well. | ||
54 | CROSS = #/usr/i386-linux-uclibc/usr/bin/i386-uclibc- | ||
55 | CC = $(CROSS)gcc | ||
56 | LD = $(CROSS)gcc | ||
57 | STRIP = $(CROSS)strip | ||
58 | HOSTCC = gcc | ||
59 | |||
60 | # check if compiler option is supported | ||
61 | cc-supports = ${shell if $(CC) ${1} -S -o /dev/null -x c /dev/null > /dev/null 2>&1; then echo "$(1)"; fi;} | ||
62 | |||
63 | # use '-Os' optimization if available, else use -O2 | ||
64 | OPTIMIZATION := $(call cc-supports,-Os,-O2) | ||
65 | |||
66 | WARNINGS := -Wall | ||
67 | WARNINGS += $(call cc-supports,-Wstrict-prototypes) | ||
68 | WARNINGS += $(call cc-supports,-Wdeclaration-after-statement) | ||
69 | |||
3 | KERNEL_INCLUDE := ../../../include | 70 | KERNEL_INCLUDE := ../../../include |
4 | CFLAGS += -Wall -Wstrict-prototypes -Wdeclaration-after-statement -Os -s -D_LINUX -DDEFINE_ALTERNATE_TYPES -I$(KERNEL_INCLUDE) | 71 | CFLAGS += -D_LINUX -DDEFINE_ALTERNATE_TYPES -I$(KERNEL_INCLUDE) |
72 | CFLAGS += $(WARNINGS) | ||
73 | |||
74 | ifeq ($(strip $(V)),false) | ||
75 | QUIET=@ | ||
76 | ECHO=@echo | ||
77 | else | ||
78 | QUIET= | ||
79 | ECHO=@\# | ||
80 | endif | ||
81 | export QUIET ECHO | ||
82 | |||
83 | # if DEBUG is enabled, then we do not strip or optimize | ||
84 | ifeq ($(strip $(DEBUG)),true) | ||
85 | CFLAGS += -O1 -g -DDEBUG | ||
86 | STRIPCMD = /bin/true -Since_we_are_debugging | ||
87 | else | ||
88 | CFLAGS += $(OPTIMIZATION) -fomit-frame-pointer | ||
89 | STRIPCMD = $(STRIP) -s --remove-section=.note --remove-section=.comment | ||
90 | endif | ||
91 | |||
92 | # if DEBUG is enabled, then we do not strip or optimize | ||
93 | ifeq ($(strip $(DEBUG)),true) | ||
94 | CFLAGS += -O1 -g -DDEBUG | ||
95 | STRIPCMD = /bin/true -Since_we_are_debugging | ||
96 | else | ||
97 | CFLAGS += $(OPTIMIZATION) -fomit-frame-pointer | ||
98 | STRIPCMD = $(STRIP) -s --remove-section=.note --remove-section=.comment | ||
99 | endif | ||
100 | |||
101 | # --- ACPIDUMP BEGIN --- | ||
102 | |||
103 | vpath %.c \ | ||
104 | tools/acpidump | ||
105 | |||
106 | DUMP_OBJS = \ | ||
107 | acpidump.o | ||
108 | |||
109 | DUMP_OBJS := $(addprefix $(OUTPUT)tools/acpidump/,$(DUMP_OBJS)) | ||
110 | |||
111 | $(OUTPUT)acpidump: $(DUMP_OBJS) | ||
112 | $(ECHO) " LD " $@ | ||
113 | $(QUIET) $(LD) $(CFLAGS) $(LDFLAGS) $(DUMP_OBJS) -L$(OUTPUT) -o $@ | ||
114 | $(QUIET) $(STRIPCMD) $@ | ||
115 | |||
116 | $(OUTPUT)tools/acpidump/%.o: %.c | ||
117 | $(ECHO) " CC " $@ | ||
118 | $(QUIET) $(CC) -c $(CFLAGS) -o $@ $< | ||
119 | |||
120 | # --- ACPIDUMP END --- | ||
121 | |||
122 | all: $(OUTPUT)acpidump | ||
123 | echo $(OUTPUT) | ||
124 | |||
125 | clean: | ||
126 | -find $(OUTPUT) \( -not -type d \) -and \( -name '*~' -o -name '*.[oas]' \) -type f -print \ | ||
127 | | xargs rm -f | ||
128 | -rm -f $(OUTPUT)acpidump | ||
5 | 129 | ||
6 | all: acpidump | 130 | install-tools: |
7 | $(PROG) : $(SRCS) | 131 | $(INSTALL) -d $(DESTDIR)${bindir} |
8 | $(CC) $(CFLAGS) $(SRCS) -o $(PROG) | 132 | $(INSTALL_PROGRAM) $(OUTPUT)acpidump $(DESTDIR)${sbindir} |
9 | 133 | ||
10 | CLEANFILES= $(PROG) | 134 | install-man: |
135 | $(INSTALL_DATA) -D man/acpidump.8 $(DESTDIR)${mandir}/man8/acpidump.8 | ||
11 | 136 | ||
12 | clean : | 137 | install: all install-tools install-man |
13 | rm -f $(CLEANFILES) $(patsubst %.c,%.o, $(SRCS)) *~ | ||
14 | 138 | ||
15 | install : | 139 | uninstall: |
16 | install acpidump /usr/sbin/acpidump | 140 | - rm -f $(DESTDIR)${sbindir}/acpidump |
17 | install acpidump.8 /usr/share/man/man8 | 141 | - rm -f $(DESTDIR)${mandir}/man8/acpidump.8 |
18 | 142 | ||
143 | .PHONY: all utils install-tools install-man install uninstall clean | ||
diff --git a/tools/power/acpi/acpidump.8 b/tools/power/acpi/man/acpidump.8 index adfa99166e5e..adfa99166e5e 100644 --- a/tools/power/acpi/acpidump.8 +++ b/tools/power/acpi/man/acpidump.8 | |||
diff --git a/tools/power/acpi/acpidump.c b/tools/power/acpi/tools/acpidump/acpidump.c index a84553a0e0df..a84553a0e0df 100644 --- a/tools/power/acpi/acpidump.c +++ b/tools/power/acpi/tools/acpidump/acpidump.c | |||
diff --git a/tools/power/cpupower/debug/kernel/cpufreq-test_tsc.c b/tools/power/cpupower/debug/kernel/cpufreq-test_tsc.c index 66cace601e57..0f10b81e3322 100644 --- a/tools/power/cpupower/debug/kernel/cpufreq-test_tsc.c +++ b/tools/power/cpupower/debug/kernel/cpufreq-test_tsc.c | |||
@@ -25,12 +25,9 @@ | |||
25 | #include <linux/module.h> | 25 | #include <linux/module.h> |
26 | #include <linux/init.h> | 26 | #include <linux/init.h> |
27 | #include <linux/delay.h> | 27 | #include <linux/delay.h> |
28 | 28 | #include <linux/acpi.h> | |
29 | #include <asm/io.h> | 29 | #include <asm/io.h> |
30 | 30 | ||
31 | #include <acpi/acpi_bus.h> | ||
32 | #include <acpi/acpi_drivers.h> | ||
33 | |||
34 | static int pm_tmr_ioport = 0; | 31 | static int pm_tmr_ioport = 0; |
35 | 32 | ||
36 | /*helper function to safely read acpi pm timesource*/ | 33 | /*helper function to safely read acpi pm timesource*/ |
diff --git a/tools/power/cpupower/utils/cpufreq-set.c b/tools/power/cpupower/utils/cpufreq-set.c index dd1539eb8c63..a416de80c55e 100644 --- a/tools/power/cpupower/utils/cpufreq-set.c +++ b/tools/power/cpupower/utils/cpufreq-set.c | |||
@@ -257,7 +257,7 @@ int cmd_freq_set(int argc, char **argv) | |||
257 | print_unknown_arg(); | 257 | print_unknown_arg(); |
258 | return -EINVAL; | 258 | return -EINVAL; |
259 | } | 259 | } |
260 | if ((sscanf(optarg, "%s", gov)) != 1) { | 260 | if ((sscanf(optarg, "%19s", gov)) != 1) { |
261 | print_unknown_arg(); | 261 | print_unknown_arg(); |
262 | return -EINVAL; | 262 | return -EINVAL; |
263 | } | 263 | } |
diff --git a/tools/power/x86/turbostat/.gitignore b/tools/power/x86/turbostat/.gitignore new file mode 100644 index 000000000000..7521370d3568 --- /dev/null +++ b/tools/power/x86/turbostat/.gitignore | |||
@@ -0,0 +1 @@ | |||
turbostat | |||
diff --git a/tools/power/x86/turbostat/Makefile b/tools/power/x86/turbostat/Makefile index f09641da40d4..d1b3a361e526 100644 --- a/tools/power/x86/turbostat/Makefile +++ b/tools/power/x86/turbostat/Makefile | |||
@@ -5,7 +5,7 @@ DESTDIR := | |||
5 | 5 | ||
6 | turbostat : turbostat.c | 6 | turbostat : turbostat.c |
7 | CFLAGS += -Wall | 7 | CFLAGS += -Wall |
8 | CFLAGS += -I../../../../arch/x86/include/uapi/ | 8 | CFLAGS += -DMSRHEADER='"../../../../arch/x86/include/uapi/asm/msr-index.h"' |
9 | 9 | ||
10 | %: %.c | 10 | %: %.c |
11 | @mkdir -p $(BUILD_OUTPUT) | 11 | @mkdir -p $(BUILD_OUTPUT) |
diff --git a/tools/power/x86/turbostat/turbostat.c b/tools/power/x86/turbostat/turbostat.c index 9d77f13c2d25..77eb130168da 100644 --- a/tools/power/x86/turbostat/turbostat.c +++ b/tools/power/x86/turbostat/turbostat.c | |||
@@ -20,8 +20,10 @@ | |||
20 | */ | 20 | */ |
21 | 21 | ||
22 | #define _GNU_SOURCE | 22 | #define _GNU_SOURCE |
23 | #include <asm/msr.h> | 23 | #include MSRHEADER |
24 | #include <stdarg.h> | ||
24 | #include <stdio.h> | 25 | #include <stdio.h> |
26 | #include <err.h> | ||
25 | #include <unistd.h> | 27 | #include <unistd.h> |
26 | #include <sys/types.h> | 28 | #include <sys/types.h> |
27 | #include <sys/wait.h> | 29 | #include <sys/wait.h> |
@@ -35,13 +37,16 @@ | |||
35 | #include <string.h> | 37 | #include <string.h> |
36 | #include <ctype.h> | 38 | #include <ctype.h> |
37 | #include <sched.h> | 39 | #include <sched.h> |
40 | #include <cpuid.h> | ||
38 | 41 | ||
39 | char *proc_stat = "/proc/stat"; | 42 | char *proc_stat = "/proc/stat"; |
40 | unsigned int interval_sec = 5; /* set with -i interval_sec */ | 43 | unsigned int interval_sec = 5; /* set with -i interval_sec */ |
41 | unsigned int verbose; /* set with -v */ | 44 | unsigned int verbose; /* set with -v */ |
42 | unsigned int rapl_verbose; /* set with -R */ | 45 | unsigned int rapl_verbose; /* set with -R */ |
46 | unsigned int rapl_joules; /* set with -J */ | ||
43 | unsigned int thermal_verbose; /* set with -T */ | 47 | unsigned int thermal_verbose; /* set with -T */ |
44 | unsigned int summary_only; /* set with -s */ | 48 | unsigned int summary_only; /* set with -S */ |
49 | unsigned int dump_only; /* set with -s */ | ||
45 | unsigned int skip_c0; | 50 | unsigned int skip_c0; |
46 | unsigned int skip_c1; | 51 | unsigned int skip_c1; |
47 | unsigned int do_nhm_cstates; | 52 | unsigned int do_nhm_cstates; |
@@ -77,14 +82,32 @@ unsigned int tcc_activation_temp_override; | |||
77 | double rapl_power_units, rapl_energy_units, rapl_time_units; | 82 | double rapl_power_units, rapl_energy_units, rapl_time_units; |
78 | double rapl_joule_counter_range; | 83 | double rapl_joule_counter_range; |
79 | 84 | ||
80 | #define RAPL_PKG (1 << 0) | 85 | #define RAPL_PKG (1 << 0) |
81 | #define RAPL_CORES (1 << 1) | 86 | /* 0x610 MSR_PKG_POWER_LIMIT */ |
82 | #define RAPL_GFX (1 << 2) | 87 | /* 0x611 MSR_PKG_ENERGY_STATUS */ |
83 | #define RAPL_DRAM (1 << 3) | 88 | #define RAPL_PKG_PERF_STATUS (1 << 1) |
84 | #define RAPL_PKG_PERF_STATUS (1 << 4) | 89 | /* 0x613 MSR_PKG_PERF_STATUS */ |
85 | #define RAPL_DRAM_PERF_STATUS (1 << 5) | 90 | #define RAPL_PKG_POWER_INFO (1 << 2) |
86 | #define RAPL_PKG_POWER_INFO (1 << 6) | 91 | /* 0x614 MSR_PKG_POWER_INFO */ |
87 | #define RAPL_CORE_POLICY (1 << 7) | 92 | |
93 | #define RAPL_DRAM (1 << 3) | ||
94 | /* 0x618 MSR_DRAM_POWER_LIMIT */ | ||
95 | /* 0x619 MSR_DRAM_ENERGY_STATUS */ | ||
96 | /* 0x61c MSR_DRAM_POWER_INFO */ | ||
97 | #define RAPL_DRAM_PERF_STATUS (1 << 4) | ||
98 | /* 0x61b MSR_DRAM_PERF_STATUS */ | ||
99 | |||
100 | #define RAPL_CORES (1 << 5) | ||
101 | /* 0x638 MSR_PP0_POWER_LIMIT */ | ||
102 | /* 0x639 MSR_PP0_ENERGY_STATUS */ | ||
103 | #define RAPL_CORE_POLICY (1 << 6) | ||
104 | /* 0x63a MSR_PP0_POLICY */ | ||
105 | |||
106 | |||
107 | #define RAPL_GFX (1 << 7) | ||
108 | /* 0x640 MSR_PP1_POWER_LIMIT */ | ||
109 | /* 0x641 MSR_PP1_ENERGY_STATUS */ | ||
110 | /* 0x642 MSR_PP1_POLICY */ | ||
88 | #define TJMAX_DEFAULT 100 | 111 | #define TJMAX_DEFAULT 100 |
89 | 112 | ||
90 | #define MAX(a, b) ((a) > (b) ? (a) : (b)) | 113 | #define MAX(a, b) ((a) > (b) ? (a) : (b)) |
@@ -234,7 +257,7 @@ int get_msr(int cpu, off_t offset, unsigned long long *msr) | |||
234 | close(fd); | 257 | close(fd); |
235 | 258 | ||
236 | if (retval != sizeof *msr) { | 259 | if (retval != sizeof *msr) { |
237 | fprintf(stderr, "%s offset 0x%zx read failed\n", pathname, offset); | 260 | fprintf(stderr, "%s offset 0x%llx read failed\n", pathname, (unsigned long long)offset); |
238 | return -1; | 261 | return -1; |
239 | } | 262 | } |
240 | 263 | ||
@@ -296,70 +319,92 @@ void print_header(void) | |||
296 | outp += sprintf(outp, " %%pc10"); | 319 | outp += sprintf(outp, " %%pc10"); |
297 | } | 320 | } |
298 | 321 | ||
299 | if (do_rapl & RAPL_PKG) | 322 | if (do_rapl && !rapl_joules) { |
300 | outp += sprintf(outp, " Pkg_W"); | 323 | if (do_rapl & RAPL_PKG) |
301 | if (do_rapl & RAPL_CORES) | 324 | outp += sprintf(outp, " Pkg_W"); |
302 | outp += sprintf(outp, " Cor_W"); | 325 | if (do_rapl & RAPL_CORES) |
303 | if (do_rapl & RAPL_GFX) | 326 | outp += sprintf(outp, " Cor_W"); |
304 | outp += sprintf(outp, " GFX_W"); | 327 | if (do_rapl & RAPL_GFX) |
305 | if (do_rapl & RAPL_DRAM) | 328 | outp += sprintf(outp, " GFX_W"); |
306 | outp += sprintf(outp, " RAM_W"); | 329 | if (do_rapl & RAPL_DRAM) |
307 | if (do_rapl & RAPL_PKG_PERF_STATUS) | 330 | outp += sprintf(outp, " RAM_W"); |
308 | outp += sprintf(outp, " PKG_%%"); | 331 | if (do_rapl & RAPL_PKG_PERF_STATUS) |
309 | if (do_rapl & RAPL_DRAM_PERF_STATUS) | 332 | outp += sprintf(outp, " PKG_%%"); |
310 | outp += sprintf(outp, " RAM_%%"); | 333 | if (do_rapl & RAPL_DRAM_PERF_STATUS) |
334 | outp += sprintf(outp, " RAM_%%"); | ||
335 | } else { | ||
336 | if (do_rapl & RAPL_PKG) | ||
337 | outp += sprintf(outp, " Pkg_J"); | ||
338 | if (do_rapl & RAPL_CORES) | ||
339 | outp += sprintf(outp, " Cor_J"); | ||
340 | if (do_rapl & RAPL_GFX) | ||
341 | outp += sprintf(outp, " GFX_J"); | ||
342 | if (do_rapl & RAPL_DRAM) | ||
343 | outp += sprintf(outp, " RAM_W"); | ||
344 | if (do_rapl & RAPL_PKG_PERF_STATUS) | ||
345 | outp += sprintf(outp, " PKG_%%"); | ||
346 | if (do_rapl & RAPL_DRAM_PERF_STATUS) | ||
347 | outp += sprintf(outp, " RAM_%%"); | ||
348 | outp += sprintf(outp, " time"); | ||
311 | 349 | ||
350 | } | ||
312 | outp += sprintf(outp, "\n"); | 351 | outp += sprintf(outp, "\n"); |
313 | } | 352 | } |
314 | 353 | ||
315 | int dump_counters(struct thread_data *t, struct core_data *c, | 354 | int dump_counters(struct thread_data *t, struct core_data *c, |
316 | struct pkg_data *p) | 355 | struct pkg_data *p) |
317 | { | 356 | { |
318 | fprintf(stderr, "t %p, c %p, p %p\n", t, c, p); | 357 | outp += sprintf(outp, "t %p, c %p, p %p\n", t, c, p); |
319 | 358 | ||
320 | if (t) { | 359 | if (t) { |
321 | fprintf(stderr, "CPU: %d flags 0x%x\n", t->cpu_id, t->flags); | 360 | outp += sprintf(outp, "CPU: %d flags 0x%x\n", |
322 | fprintf(stderr, "TSC: %016llX\n", t->tsc); | 361 | t->cpu_id, t->flags); |
323 | fprintf(stderr, "aperf: %016llX\n", t->aperf); | 362 | outp += sprintf(outp, "TSC: %016llX\n", t->tsc); |
324 | fprintf(stderr, "mperf: %016llX\n", t->mperf); | 363 | outp += sprintf(outp, "aperf: %016llX\n", t->aperf); |
325 | fprintf(stderr, "c1: %016llX\n", t->c1); | 364 | outp += sprintf(outp, "mperf: %016llX\n", t->mperf); |
326 | fprintf(stderr, "msr0x%x: %08llX\n", | 365 | outp += sprintf(outp, "c1: %016llX\n", t->c1); |
366 | outp += sprintf(outp, "msr0x%x: %08llX\n", | ||
327 | extra_delta_offset32, t->extra_delta32); | 367 | extra_delta_offset32, t->extra_delta32); |
328 | fprintf(stderr, "msr0x%x: %016llX\n", | 368 | outp += sprintf(outp, "msr0x%x: %016llX\n", |
329 | extra_delta_offset64, t->extra_delta64); | 369 | extra_delta_offset64, t->extra_delta64); |
330 | fprintf(stderr, "msr0x%x: %08llX\n", | 370 | outp += sprintf(outp, "msr0x%x: %08llX\n", |
331 | extra_msr_offset32, t->extra_msr32); | 371 | extra_msr_offset32, t->extra_msr32); |
332 | fprintf(stderr, "msr0x%x: %016llX\n", | 372 | outp += sprintf(outp, "msr0x%x: %016llX\n", |
333 | extra_msr_offset64, t->extra_msr64); | 373 | extra_msr_offset64, t->extra_msr64); |
334 | if (do_smi) | 374 | if (do_smi) |
335 | fprintf(stderr, "SMI: %08X\n", t->smi_count); | 375 | outp += sprintf(outp, "SMI: %08X\n", t->smi_count); |
336 | } | 376 | } |
337 | 377 | ||
338 | if (c) { | 378 | if (c) { |
339 | fprintf(stderr, "core: %d\n", c->core_id); | 379 | outp += sprintf(outp, "core: %d\n", c->core_id); |
340 | fprintf(stderr, "c3: %016llX\n", c->c3); | 380 | outp += sprintf(outp, "c3: %016llX\n", c->c3); |
341 | fprintf(stderr, "c6: %016llX\n", c->c6); | 381 | outp += sprintf(outp, "c6: %016llX\n", c->c6); |
342 | fprintf(stderr, "c7: %016llX\n", c->c7); | 382 | outp += sprintf(outp, "c7: %016llX\n", c->c7); |
343 | fprintf(stderr, "DTS: %dC\n", c->core_temp_c); | 383 | outp += sprintf(outp, "DTS: %dC\n", c->core_temp_c); |
344 | } | 384 | } |
345 | 385 | ||
346 | if (p) { | 386 | if (p) { |
347 | fprintf(stderr, "package: %d\n", p->package_id); | 387 | outp += sprintf(outp, "package: %d\n", p->package_id); |
348 | fprintf(stderr, "pc2: %016llX\n", p->pc2); | 388 | outp += sprintf(outp, "pc2: %016llX\n", p->pc2); |
349 | fprintf(stderr, "pc3: %016llX\n", p->pc3); | 389 | outp += sprintf(outp, "pc3: %016llX\n", p->pc3); |
350 | fprintf(stderr, "pc6: %016llX\n", p->pc6); | 390 | outp += sprintf(outp, "pc6: %016llX\n", p->pc6); |
351 | fprintf(stderr, "pc7: %016llX\n", p->pc7); | 391 | outp += sprintf(outp, "pc7: %016llX\n", p->pc7); |
352 | fprintf(stderr, "pc8: %016llX\n", p->pc8); | 392 | outp += sprintf(outp, "pc8: %016llX\n", p->pc8); |
353 | fprintf(stderr, "pc9: %016llX\n", p->pc9); | 393 | outp += sprintf(outp, "pc9: %016llX\n", p->pc9); |
354 | fprintf(stderr, "pc10: %016llX\n", p->pc10); | 394 | outp += sprintf(outp, "pc10: %016llX\n", p->pc10); |
355 | fprintf(stderr, "Joules PKG: %0X\n", p->energy_pkg); | 395 | outp += sprintf(outp, "Joules PKG: %0X\n", p->energy_pkg); |
356 | fprintf(stderr, "Joules COR: %0X\n", p->energy_cores); | 396 | outp += sprintf(outp, "Joules COR: %0X\n", p->energy_cores); |
357 | fprintf(stderr, "Joules GFX: %0X\n", p->energy_gfx); | 397 | outp += sprintf(outp, "Joules GFX: %0X\n", p->energy_gfx); |
358 | fprintf(stderr, "Joules RAM: %0X\n", p->energy_dram); | 398 | outp += sprintf(outp, "Joules RAM: %0X\n", p->energy_dram); |
359 | fprintf(stderr, "Throttle PKG: %0X\n", p->rapl_pkg_perf_status); | 399 | outp += sprintf(outp, "Throttle PKG: %0X\n", |
360 | fprintf(stderr, "Throttle RAM: %0X\n", p->rapl_dram_perf_status); | 400 | p->rapl_pkg_perf_status); |
361 | fprintf(stderr, "PTM: %dC\n", p->pkg_temp_c); | 401 | outp += sprintf(outp, "Throttle RAM: %0X\n", |
402 | p->rapl_dram_perf_status); | ||
403 | outp += sprintf(outp, "PTM: %dC\n", p->pkg_temp_c); | ||
362 | } | 404 | } |
405 | |||
406 | outp += sprintf(outp, "\n"); | ||
407 | |||
363 | return 0; | 408 | return 0; |
364 | } | 409 | } |
365 | 410 | ||
@@ -527,19 +572,39 @@ int format_counters(struct thread_data *t, struct core_data *c, | |||
527 | fmt6 = " %4.0f**"; | 572 | fmt6 = " %4.0f**"; |
528 | } | 573 | } |
529 | 574 | ||
530 | if (do_rapl & RAPL_PKG) | 575 | if (do_rapl && !rapl_joules) { |
531 | outp += sprintf(outp, fmt6, p->energy_pkg * rapl_energy_units / interval_float); | 576 | if (do_rapl & RAPL_PKG) |
532 | if (do_rapl & RAPL_CORES) | 577 | outp += sprintf(outp, fmt6, p->energy_pkg * rapl_energy_units / interval_float); |
533 | outp += sprintf(outp, fmt6, p->energy_cores * rapl_energy_units / interval_float); | 578 | if (do_rapl & RAPL_CORES) |
534 | if (do_rapl & RAPL_GFX) | 579 | outp += sprintf(outp, fmt6, p->energy_cores * rapl_energy_units / interval_float); |
535 | outp += sprintf(outp, fmt5, p->energy_gfx * rapl_energy_units / interval_float); | 580 | if (do_rapl & RAPL_GFX) |
536 | if (do_rapl & RAPL_DRAM) | 581 | outp += sprintf(outp, fmt5, p->energy_gfx * rapl_energy_units / interval_float); |
537 | outp += sprintf(outp, fmt5, p->energy_dram * rapl_energy_units / interval_float); | 582 | if (do_rapl & RAPL_DRAM) |
538 | if (do_rapl & RAPL_PKG_PERF_STATUS ) | 583 | outp += sprintf(outp, fmt5, p->energy_dram * rapl_energy_units / interval_float); |
539 | outp += sprintf(outp, fmt5, 100.0 * p->rapl_pkg_perf_status * rapl_time_units / interval_float); | 584 | if (do_rapl & RAPL_PKG_PERF_STATUS) |
540 | if (do_rapl & RAPL_DRAM_PERF_STATUS ) | 585 | outp += sprintf(outp, fmt5, 100.0 * p->rapl_pkg_perf_status * rapl_time_units / interval_float); |
541 | outp += sprintf(outp, fmt5, 100.0 * p->rapl_dram_perf_status * rapl_time_units / interval_float); | 586 | if (do_rapl & RAPL_DRAM_PERF_STATUS) |
587 | outp += sprintf(outp, fmt5, 100.0 * p->rapl_dram_perf_status * rapl_time_units / interval_float); | ||
588 | } else { | ||
589 | if (do_rapl & RAPL_PKG) | ||
590 | outp += sprintf(outp, fmt6, | ||
591 | p->energy_pkg * rapl_energy_units); | ||
592 | if (do_rapl & RAPL_CORES) | ||
593 | outp += sprintf(outp, fmt6, | ||
594 | p->energy_cores * rapl_energy_units); | ||
595 | if (do_rapl & RAPL_GFX) | ||
596 | outp += sprintf(outp, fmt5, | ||
597 | p->energy_gfx * rapl_energy_units); | ||
598 | if (do_rapl & RAPL_DRAM) | ||
599 | outp += sprintf(outp, fmt5, | ||
600 | p->energy_dram * rapl_energy_units); | ||
601 | if (do_rapl & RAPL_PKG_PERF_STATUS) | ||
602 | outp += sprintf(outp, fmt5, 100.0 * p->rapl_pkg_perf_status * rapl_time_units / interval_float); | ||
603 | if (do_rapl & RAPL_DRAM_PERF_STATUS) | ||
604 | outp += sprintf(outp, fmt5, 100.0 * p->rapl_dram_perf_status * rapl_time_units / interval_float); | ||
605 | outp += sprintf(outp, fmt5, interval_float); | ||
542 | 606 | ||
607 | } | ||
543 | done: | 608 | done: |
544 | outp += sprintf(outp, "\n"); | 609 | outp += sprintf(outp, "\n"); |
545 | 610 | ||
@@ -622,12 +687,10 @@ delta_thread(struct thread_data *new, struct thread_data *old, | |||
622 | old->tsc = new->tsc - old->tsc; | 687 | old->tsc = new->tsc - old->tsc; |
623 | 688 | ||
624 | /* check for TSC < 1 Mcycles over interval */ | 689 | /* check for TSC < 1 Mcycles over interval */ |
625 | if (old->tsc < (1000 * 1000)) { | 690 | if (old->tsc < (1000 * 1000)) |
626 | fprintf(stderr, "Insanely slow TSC rate, TSC stops in idle?\n"); | 691 | errx(-3, "Insanely slow TSC rate, TSC stops in idle?\n" |
627 | fprintf(stderr, "You can disable all c-states by booting with \"idle=poll\"\n"); | 692 | "You can disable all c-states by booting with \"idle=poll\"\n" |
628 | fprintf(stderr, "or just the deep ones with \"processor.max_cstate=1\"\n"); | 693 | "or just the deep ones with \"processor.max_cstate=1\""); |
629 | exit(-3); | ||
630 | } | ||
631 | 694 | ||
632 | old->c1 = new->c1 - old->c1; | 695 | old->c1 = new->c1 - old->c1; |
633 | 696 | ||
@@ -1173,24 +1236,43 @@ void free_all_buffers(void) | |||
1173 | } | 1236 | } |
1174 | 1237 | ||
1175 | /* | 1238 | /* |
1239 | * Open a file, and exit on failure | ||
1240 | */ | ||
1241 | FILE *fopen_or_die(const char *path, const char *mode) | ||
1242 | { | ||
1243 | FILE *filep = fopen(path, "r"); | ||
1244 | if (!filep) | ||
1245 | err(1, "%s: open failed", path); | ||
1246 | return filep; | ||
1247 | } | ||
1248 | |||
1249 | /* | ||
1250 | * Parse a file containing a single int. | ||
1251 | */ | ||
1252 | int parse_int_file(const char *fmt, ...) | ||
1253 | { | ||
1254 | va_list args; | ||
1255 | char path[PATH_MAX]; | ||
1256 | FILE *filep; | ||
1257 | int value; | ||
1258 | |||
1259 | va_start(args, fmt); | ||
1260 | vsnprintf(path, sizeof(path), fmt, args); | ||
1261 | va_end(args); | ||
1262 | filep = fopen_or_die(path, "r"); | ||
1263 | if (fscanf(filep, "%d", &value) != 1) | ||
1264 | err(1, "%s: failed to parse number from file", path); | ||
1265 | fclose(filep); | ||
1266 | return value; | ||
1267 | } | ||
1268 | |||
1269 | /* | ||
1176 | * cpu_is_first_sibling_in_core(cpu) | 1270 | * cpu_is_first_sibling_in_core(cpu) |
1177 | * return 1 if given CPU is 1st HT sibling in the core | 1271 | * return 1 if given CPU is 1st HT sibling in the core |
1178 | */ | 1272 | */ |
1179 | int cpu_is_first_sibling_in_core(int cpu) | 1273 | int cpu_is_first_sibling_in_core(int cpu) |
1180 | { | 1274 | { |
1181 | char path[64]; | 1275 | return cpu == parse_int_file("/sys/devices/system/cpu/cpu%d/topology/thread_siblings_list", cpu); |
1182 | FILE *filep; | ||
1183 | int first_cpu; | ||
1184 | |||
1185 | sprintf(path, "/sys/devices/system/cpu/cpu%d/topology/thread_siblings_list", cpu); | ||
1186 | filep = fopen(path, "r"); | ||
1187 | if (filep == NULL) { | ||
1188 | perror(path); | ||
1189 | exit(1); | ||
1190 | } | ||
1191 | fscanf(filep, "%d", &first_cpu); | ||
1192 | fclose(filep); | ||
1193 | return (cpu == first_cpu); | ||
1194 | } | 1276 | } |
1195 | 1277 | ||
1196 | /* | 1278 | /* |
@@ -1199,53 +1281,17 @@ int cpu_is_first_sibling_in_core(int cpu) | |||
1199 | */ | 1281 | */ |
1200 | int cpu_is_first_core_in_package(int cpu) | 1282 | int cpu_is_first_core_in_package(int cpu) |
1201 | { | 1283 | { |
1202 | char path[64]; | 1284 | return cpu == parse_int_file("/sys/devices/system/cpu/cpu%d/topology/core_siblings_list", cpu); |
1203 | FILE *filep; | ||
1204 | int first_cpu; | ||
1205 | |||
1206 | sprintf(path, "/sys/devices/system/cpu/cpu%d/topology/core_siblings_list", cpu); | ||
1207 | filep = fopen(path, "r"); | ||
1208 | if (filep == NULL) { | ||
1209 | perror(path); | ||
1210 | exit(1); | ||
1211 | } | ||
1212 | fscanf(filep, "%d", &first_cpu); | ||
1213 | fclose(filep); | ||
1214 | return (cpu == first_cpu); | ||
1215 | } | 1285 | } |
1216 | 1286 | ||
1217 | int get_physical_package_id(int cpu) | 1287 | int get_physical_package_id(int cpu) |
1218 | { | 1288 | { |
1219 | char path[80]; | 1289 | return parse_int_file("/sys/devices/system/cpu/cpu%d/topology/physical_package_id", cpu); |
1220 | FILE *filep; | ||
1221 | int pkg; | ||
1222 | |||
1223 | sprintf(path, "/sys/devices/system/cpu/cpu%d/topology/physical_package_id", cpu); | ||
1224 | filep = fopen(path, "r"); | ||
1225 | if (filep == NULL) { | ||
1226 | perror(path); | ||
1227 | exit(1); | ||
1228 | } | ||
1229 | fscanf(filep, "%d", &pkg); | ||
1230 | fclose(filep); | ||
1231 | return pkg; | ||
1232 | } | 1290 | } |
1233 | 1291 | ||
1234 | int get_core_id(int cpu) | 1292 | int get_core_id(int cpu) |
1235 | { | 1293 | { |
1236 | char path[80]; | 1294 | return parse_int_file("/sys/devices/system/cpu/cpu%d/topology/core_id", cpu); |
1237 | FILE *filep; | ||
1238 | int core; | ||
1239 | |||
1240 | sprintf(path, "/sys/devices/system/cpu/cpu%d/topology/core_id", cpu); | ||
1241 | filep = fopen(path, "r"); | ||
1242 | if (filep == NULL) { | ||
1243 | perror(path); | ||
1244 | exit(1); | ||
1245 | } | ||
1246 | fscanf(filep, "%d", &core); | ||
1247 | fclose(filep); | ||
1248 | return core; | ||
1249 | } | 1295 | } |
1250 | 1296 | ||
1251 | int get_num_ht_siblings(int cpu) | 1297 | int get_num_ht_siblings(int cpu) |
@@ -1257,11 +1303,7 @@ int get_num_ht_siblings(int cpu) | |||
1257 | char character; | 1303 | char character; |
1258 | 1304 | ||
1259 | sprintf(path, "/sys/devices/system/cpu/cpu%d/topology/thread_siblings_list", cpu); | 1305 | sprintf(path, "/sys/devices/system/cpu/cpu%d/topology/thread_siblings_list", cpu); |
1260 | filep = fopen(path, "r"); | 1306 | filep = fopen_or_die(path, "r"); |
1261 | if (filep == NULL) { | ||
1262 | perror(path); | ||
1263 | exit(1); | ||
1264 | } | ||
1265 | /* | 1307 | /* |
1266 | * file format: | 1308 | * file format: |
1267 | * if a pair of number with a character between: 2 siblings (eg. 1-2, or 1,4) | 1309 | * if a pair of number with a character between: 2 siblings (eg. 1-2, or 1,4) |
@@ -1331,17 +1373,11 @@ int for_all_proc_cpus(int (func)(int)) | |||
1331 | int cpu_num; | 1373 | int cpu_num; |
1332 | int retval; | 1374 | int retval; |
1333 | 1375 | ||
1334 | fp = fopen(proc_stat, "r"); | 1376 | fp = fopen_or_die(proc_stat, "r"); |
1335 | if (fp == NULL) { | ||
1336 | perror(proc_stat); | ||
1337 | exit(1); | ||
1338 | } | ||
1339 | 1377 | ||
1340 | retval = fscanf(fp, "cpu %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d\n"); | 1378 | retval = fscanf(fp, "cpu %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d\n"); |
1341 | if (retval != 0) { | 1379 | if (retval != 0) |
1342 | perror("/proc/stat format"); | 1380 | err(1, "%s: failed to parse format", proc_stat); |
1343 | exit(1); | ||
1344 | } | ||
1345 | 1381 | ||
1346 | while (1) { | 1382 | while (1) { |
1347 | retval = fscanf(fp, "cpu%u %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d\n", &cpu_num); | 1383 | retval = fscanf(fp, "cpu%u %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d\n", &cpu_num); |
@@ -1445,19 +1481,15 @@ void check_dev_msr() | |||
1445 | { | 1481 | { |
1446 | struct stat sb; | 1482 | struct stat sb; |
1447 | 1483 | ||
1448 | if (stat("/dev/cpu/0/msr", &sb)) { | 1484 | if (stat("/dev/cpu/0/msr", &sb)) |
1449 | fprintf(stderr, "no /dev/cpu/0/msr\n"); | 1485 | err(-5, "no /dev/cpu/0/msr\n" |
1450 | fprintf(stderr, "Try \"# modprobe msr\"\n"); | 1486 | "Try \"# modprobe msr\""); |
1451 | exit(-5); | ||
1452 | } | ||
1453 | } | 1487 | } |
1454 | 1488 | ||
1455 | void check_super_user() | 1489 | void check_super_user() |
1456 | { | 1490 | { |
1457 | if (getuid() != 0) { | 1491 | if (getuid() != 0) |
1458 | fprintf(stderr, "must be root\n"); | 1492 | errx(-6, "must be root"); |
1459 | exit(-6); | ||
1460 | } | ||
1461 | } | 1493 | } |
1462 | 1494 | ||
1463 | int has_nehalem_turbo_ratio_limit(unsigned int family, unsigned int model) | 1495 | int has_nehalem_turbo_ratio_limit(unsigned int family, unsigned int model) |
@@ -1479,7 +1511,7 @@ int has_nehalem_turbo_ratio_limit(unsigned int family, unsigned int model) | |||
1479 | case 0x3A: /* IVB */ | 1511 | case 0x3A: /* IVB */ |
1480 | case 0x3E: /* IVB Xeon */ | 1512 | case 0x3E: /* IVB Xeon */ |
1481 | case 0x3C: /* HSW */ | 1513 | case 0x3C: /* HSW */ |
1482 | case 0x3F: /* HSW */ | 1514 | case 0x3F: /* HSX */ |
1483 | case 0x45: /* HSW */ | 1515 | case 0x45: /* HSW */ |
1484 | case 0x46: /* HSW */ | 1516 | case 0x46: /* HSW */ |
1485 | case 0x37: /* BYT */ | 1517 | case 0x37: /* BYT */ |
@@ -1595,11 +1627,13 @@ void rapl_probe(unsigned int family, unsigned int model) | |||
1595 | case 0x2A: | 1627 | case 0x2A: |
1596 | case 0x3A: | 1628 | case 0x3A: |
1597 | case 0x3C: /* HSW */ | 1629 | case 0x3C: /* HSW */ |
1598 | case 0x3F: /* HSW */ | ||
1599 | case 0x45: /* HSW */ | 1630 | case 0x45: /* HSW */ |
1600 | case 0x46: /* HSW */ | 1631 | case 0x46: /* HSW */ |
1601 | do_rapl = RAPL_PKG | RAPL_CORES | RAPL_CORE_POLICY | RAPL_GFX | RAPL_PKG_POWER_INFO; | 1632 | do_rapl = RAPL_PKG | RAPL_CORES | RAPL_CORE_POLICY | RAPL_GFX | RAPL_PKG_POWER_INFO; |
1602 | break; | 1633 | break; |
1634 | case 0x3F: /* HSX */ | ||
1635 | do_rapl = RAPL_PKG | RAPL_DRAM | RAPL_DRAM_PERF_STATUS | RAPL_PKG_PERF_STATUS | RAPL_PKG_POWER_INFO; | ||
1636 | break; | ||
1603 | case 0x2D: | 1637 | case 0x2D: |
1604 | case 0x3E: | 1638 | case 0x3E: |
1605 | do_rapl = RAPL_PKG | RAPL_CORES | RAPL_CORE_POLICY | RAPL_DRAM | RAPL_PKG_PERF_STATUS | RAPL_DRAM_PERF_STATUS | RAPL_PKG_POWER_INFO; | 1639 | do_rapl = RAPL_PKG | RAPL_CORES | RAPL_CORE_POLICY | RAPL_DRAM | RAPL_PKG_PERF_STATUS | RAPL_DRAM_PERF_STATUS | RAPL_PKG_POWER_INFO; |
@@ -1978,7 +2012,7 @@ void check_cpuid() | |||
1978 | 2012 | ||
1979 | eax = ebx = ecx = edx = 0; | 2013 | eax = ebx = ecx = edx = 0; |
1980 | 2014 | ||
1981 | asm("cpuid" : "=a" (max_level), "=b" (ebx), "=c" (ecx), "=d" (edx) : "a" (0)); | 2015 | __get_cpuid(0, &max_level, &ebx, &ecx, &edx); |
1982 | 2016 | ||
1983 | if (ebx == 0x756e6547 && edx == 0x49656e69 && ecx == 0x6c65746e) | 2017 | if (ebx == 0x756e6547 && edx == 0x49656e69 && ecx == 0x6c65746e) |
1984 | genuine_intel = 1; | 2018 | genuine_intel = 1; |
@@ -1987,7 +2021,7 @@ void check_cpuid() | |||
1987 | fprintf(stderr, "CPUID(0): %.4s%.4s%.4s ", | 2021 | fprintf(stderr, "CPUID(0): %.4s%.4s%.4s ", |
1988 | (char *)&ebx, (char *)&edx, (char *)&ecx); | 2022 | (char *)&ebx, (char *)&edx, (char *)&ecx); |
1989 | 2023 | ||
1990 | asm("cpuid" : "=a" (fms), "=c" (ecx), "=d" (edx) : "a" (1) : "ebx"); | 2024 | __get_cpuid(1, &fms, &ebx, &ecx, &edx); |
1991 | family = (fms >> 8) & 0xf; | 2025 | family = (fms >> 8) & 0xf; |
1992 | model = (fms >> 4) & 0xf; | 2026 | model = (fms >> 4) & 0xf; |
1993 | stepping = fms & 0xf; | 2027 | stepping = fms & 0xf; |
@@ -1998,10 +2032,8 @@ void check_cpuid() | |||
1998 | fprintf(stderr, "%d CPUID levels; family:model:stepping 0x%x:%x:%x (%d:%d:%d)\n", | 2032 | fprintf(stderr, "%d CPUID levels; family:model:stepping 0x%x:%x:%x (%d:%d:%d)\n", |
1999 | max_level, family, model, stepping, family, model, stepping); | 2033 | max_level, family, model, stepping, family, model, stepping); |
2000 | 2034 | ||
2001 | if (!(edx & (1 << 5))) { | 2035 | if (!(edx & (1 << 5))) |
2002 | fprintf(stderr, "CPUID: no MSR\n"); | 2036 | errx(1, "CPUID: no MSR"); |
2003 | exit(1); | ||
2004 | } | ||
2005 | 2037 | ||
2006 | /* | 2038 | /* |
2007 | * check max extended function levels of CPUID. | 2039 | * check max extended function levels of CPUID. |
@@ -2009,31 +2041,27 @@ void check_cpuid() | |||
2009 | * This check is valid for both Intel and AMD. | 2041 | * This check is valid for both Intel and AMD. |
2010 | */ | 2042 | */ |
2011 | ebx = ecx = edx = 0; | 2043 | ebx = ecx = edx = 0; |
2012 | asm("cpuid" : "=a" (max_level), "=b" (ebx), "=c" (ecx), "=d" (edx) : "a" (0x80000000)); | 2044 | __get_cpuid(0x80000000, &max_level, &ebx, &ecx, &edx); |
2013 | 2045 | ||
2014 | if (max_level < 0x80000007) { | 2046 | if (max_level < 0x80000007) |
2015 | fprintf(stderr, "CPUID: no invariant TSC (max_level 0x%x)\n", max_level); | 2047 | errx(1, "CPUID: no invariant TSC (max_level 0x%x)", max_level); |
2016 | exit(1); | ||
2017 | } | ||
2018 | 2048 | ||
2019 | /* | 2049 | /* |
2020 | * Non-Stop TSC is advertised by CPUID.EAX=0x80000007: EDX.bit8 | 2050 | * Non-Stop TSC is advertised by CPUID.EAX=0x80000007: EDX.bit8 |
2021 | * this check is valid for both Intel and AMD | 2051 | * this check is valid for both Intel and AMD |
2022 | */ | 2052 | */ |
2023 | asm("cpuid" : "=a" (eax), "=b" (ebx), "=c" (ecx), "=d" (edx) : "a" (0x80000007)); | 2053 | __get_cpuid(0x80000007, &eax, &ebx, &ecx, &edx); |
2024 | has_invariant_tsc = edx & (1 << 8); | 2054 | has_invariant_tsc = edx & (1 << 8); |
2025 | 2055 | ||
2026 | if (!has_invariant_tsc) { | 2056 | if (!has_invariant_tsc) |
2027 | fprintf(stderr, "No invariant TSC\n"); | 2057 | errx(1, "No invariant TSC"); |
2028 | exit(1); | ||
2029 | } | ||
2030 | 2058 | ||
2031 | /* | 2059 | /* |
2032 | * APERF/MPERF is advertised by CPUID.EAX=0x6: ECX.bit0 | 2060 | * APERF/MPERF is advertised by CPUID.EAX=0x6: ECX.bit0 |
2033 | * this check is valid for both Intel and AMD | 2061 | * this check is valid for both Intel and AMD |
2034 | */ | 2062 | */ |
2035 | 2063 | ||
2036 | asm("cpuid" : "=a" (eax), "=b" (ebx), "=c" (ecx), "=d" (edx) : "a" (0x6)); | 2064 | __get_cpuid(0x6, &eax, &ebx, &ecx, &edx); |
2037 | has_aperf = ecx & (1 << 0); | 2065 | has_aperf = ecx & (1 << 0); |
2038 | do_dts = eax & (1 << 0); | 2066 | do_dts = eax & (1 << 0); |
2039 | do_ptm = eax & (1 << 6); | 2067 | do_ptm = eax & (1 << 6); |
@@ -2047,7 +2075,7 @@ void check_cpuid() | |||
2047 | has_epb ? ", EPB": ""); | 2075 | has_epb ? ", EPB": ""); |
2048 | 2076 | ||
2049 | if (!has_aperf) | 2077 | if (!has_aperf) |
2050 | exit(-1); | 2078 | errx(-1, "No APERF"); |
2051 | 2079 | ||
2052 | do_nehalem_platform_info = genuine_intel && has_invariant_tsc; | 2080 | do_nehalem_platform_info = genuine_intel && has_invariant_tsc; |
2053 | do_nhm_cstates = genuine_intel; /* all Intel w/ non-stop TSC have NHM counters */ | 2081 | do_nhm_cstates = genuine_intel; /* all Intel w/ non-stop TSC have NHM counters */ |
@@ -2067,9 +2095,8 @@ void check_cpuid() | |||
2067 | 2095 | ||
2068 | void usage() | 2096 | void usage() |
2069 | { | 2097 | { |
2070 | fprintf(stderr, "%s: [-v][-R][-T][-p|-P|-S][-c MSR# | -s]][-C MSR#][-m MSR#][-M MSR#][-i interval_sec | command ...]\n", | 2098 | errx(1, "%s: [-v][-R][-T][-p|-P|-S][-c MSR#][-C MSR#][-m MSR#][-M MSR#][-i interval_sec | command ...]\n", |
2071 | progname); | 2099 | progname); |
2072 | exit(1); | ||
2073 | } | 2100 | } |
2074 | 2101 | ||
2075 | 2102 | ||
@@ -2112,19 +2139,15 @@ void topology_probe() | |||
2112 | fprintf(stderr, "num_cpus %d max_cpu_num %d\n", topo.num_cpus, topo.max_cpu_num); | 2139 | fprintf(stderr, "num_cpus %d max_cpu_num %d\n", topo.num_cpus, topo.max_cpu_num); |
2113 | 2140 | ||
2114 | cpus = calloc(1, (topo.max_cpu_num + 1) * sizeof(struct cpu_topology)); | 2141 | cpus = calloc(1, (topo.max_cpu_num + 1) * sizeof(struct cpu_topology)); |
2115 | if (cpus == NULL) { | 2142 | if (cpus == NULL) |
2116 | perror("calloc cpus"); | 2143 | err(1, "calloc cpus"); |
2117 | exit(1); | ||
2118 | } | ||
2119 | 2144 | ||
2120 | /* | 2145 | /* |
2121 | * Allocate and initialize cpu_present_set | 2146 | * Allocate and initialize cpu_present_set |
2122 | */ | 2147 | */ |
2123 | cpu_present_set = CPU_ALLOC((topo.max_cpu_num + 1)); | 2148 | cpu_present_set = CPU_ALLOC((topo.max_cpu_num + 1)); |
2124 | if (cpu_present_set == NULL) { | 2149 | if (cpu_present_set == NULL) |
2125 | perror("CPU_ALLOC"); | 2150 | err(3, "CPU_ALLOC"); |
2126 | exit(3); | ||
2127 | } | ||
2128 | cpu_present_setsize = CPU_ALLOC_SIZE((topo.max_cpu_num + 1)); | 2151 | cpu_present_setsize = CPU_ALLOC_SIZE((topo.max_cpu_num + 1)); |
2129 | CPU_ZERO_S(cpu_present_setsize, cpu_present_set); | 2152 | CPU_ZERO_S(cpu_present_setsize, cpu_present_set); |
2130 | for_all_proc_cpus(mark_cpu_present); | 2153 | for_all_proc_cpus(mark_cpu_present); |
@@ -2133,10 +2156,8 @@ void topology_probe() | |||
2133 | * Allocate and initialize cpu_affinity_set | 2156 | * Allocate and initialize cpu_affinity_set |
2134 | */ | 2157 | */ |
2135 | cpu_affinity_set = CPU_ALLOC((topo.max_cpu_num + 1)); | 2158 | cpu_affinity_set = CPU_ALLOC((topo.max_cpu_num + 1)); |
2136 | if (cpu_affinity_set == NULL) { | 2159 | if (cpu_affinity_set == NULL) |
2137 | perror("CPU_ALLOC"); | 2160 | err(3, "CPU_ALLOC"); |
2138 | exit(3); | ||
2139 | } | ||
2140 | cpu_affinity_setsize = CPU_ALLOC_SIZE((topo.max_cpu_num + 1)); | 2161 | cpu_affinity_setsize = CPU_ALLOC_SIZE((topo.max_cpu_num + 1)); |
2141 | CPU_ZERO_S(cpu_affinity_setsize, cpu_affinity_set); | 2162 | CPU_ZERO_S(cpu_affinity_setsize, cpu_affinity_set); |
2142 | 2163 | ||
@@ -2220,8 +2241,7 @@ allocate_counters(struct thread_data **t, struct core_data **c, struct pkg_data | |||
2220 | 2241 | ||
2221 | return; | 2242 | return; |
2222 | error: | 2243 | error: |
2223 | perror("calloc counters"); | 2244 | err(1, "calloc counters"); |
2224 | exit(1); | ||
2225 | } | 2245 | } |
2226 | /* | 2246 | /* |
2227 | * init_counter() | 2247 | * init_counter() |
@@ -2276,12 +2296,10 @@ int initialize_counters(int cpu_id) | |||
2276 | 2296 | ||
2277 | void allocate_output_buffer() | 2297 | void allocate_output_buffer() |
2278 | { | 2298 | { |
2279 | output_buffer = calloc(1, (1 + topo.num_cpus) * 256); | 2299 | output_buffer = calloc(1, (1 + topo.num_cpus) * 1024); |
2280 | outp = output_buffer; | 2300 | outp = output_buffer; |
2281 | if (outp == NULL) { | 2301 | if (outp == NULL) |
2282 | perror("calloc"); | 2302 | err(-1, "calloc output buffer"); |
2283 | exit(-1); | ||
2284 | } | ||
2285 | } | 2303 | } |
2286 | 2304 | ||
2287 | void setup_all_buffers(void) | 2305 | void setup_all_buffers(void) |
@@ -2292,6 +2310,7 @@ void setup_all_buffers(void) | |||
2292 | allocate_output_buffer(); | 2310 | allocate_output_buffer(); |
2293 | for_all_proc_cpus(initialize_counters); | 2311 | for_all_proc_cpus(initialize_counters); |
2294 | } | 2312 | } |
2313 | |||
2295 | void turbostat_init() | 2314 | void turbostat_init() |
2296 | { | 2315 | { |
2297 | check_cpuid(); | 2316 | check_cpuid(); |
@@ -2335,17 +2354,13 @@ int fork_it(char **argv) | |||
2335 | } else { | 2354 | } else { |
2336 | 2355 | ||
2337 | /* parent */ | 2356 | /* parent */ |
2338 | if (child_pid == -1) { | 2357 | if (child_pid == -1) |
2339 | perror("fork"); | 2358 | err(1, "fork"); |
2340 | exit(1); | ||
2341 | } | ||
2342 | 2359 | ||
2343 | signal(SIGINT, SIG_IGN); | 2360 | signal(SIGINT, SIG_IGN); |
2344 | signal(SIGQUIT, SIG_IGN); | 2361 | signal(SIGQUIT, SIG_IGN); |
2345 | if (waitpid(child_pid, &status, 0) == -1) { | 2362 | if (waitpid(child_pid, &status, 0) == -1) |
2346 | perror("wait"); | 2363 | err(status, "waitpid"); |
2347 | exit(status); | ||
2348 | } | ||
2349 | } | 2364 | } |
2350 | /* | 2365 | /* |
2351 | * n.b. fork_it() does not check for errors from for_all_cpus() | 2366 | * n.b. fork_it() does not check for errors from for_all_cpus() |
@@ -2364,13 +2379,30 @@ int fork_it(char **argv) | |||
2364 | return status; | 2379 | return status; |
2365 | } | 2380 | } |
2366 | 2381 | ||
2382 | int get_and_dump_counters(void) | ||
2383 | { | ||
2384 | int status; | ||
2385 | |||
2386 | status = for_all_cpus(get_counters, ODD_COUNTERS); | ||
2387 | if (status) | ||
2388 | return status; | ||
2389 | |||
2390 | status = for_all_cpus(dump_counters, ODD_COUNTERS); | ||
2391 | if (status) | ||
2392 | return status; | ||
2393 | |||
2394 | flush_stdout(); | ||
2395 | |||
2396 | return status; | ||
2397 | } | ||
2398 | |||
2367 | void cmdline(int argc, char **argv) | 2399 | void cmdline(int argc, char **argv) |
2368 | { | 2400 | { |
2369 | int opt; | 2401 | int opt; |
2370 | 2402 | ||
2371 | progname = argv[0]; | 2403 | progname = argv[0]; |
2372 | 2404 | ||
2373 | while ((opt = getopt(argc, argv, "+pPSvi:sc:sC:m:M:RT:")) != -1) { | 2405 | while ((opt = getopt(argc, argv, "+pPsSvi:c:C:m:M:RJT:")) != -1) { |
2374 | switch (opt) { | 2406 | switch (opt) { |
2375 | case 'p': | 2407 | case 'p': |
2376 | show_core_only++; | 2408 | show_core_only++; |
@@ -2378,6 +2410,9 @@ void cmdline(int argc, char **argv) | |||
2378 | case 'P': | 2410 | case 'P': |
2379 | show_pkg_only++; | 2411 | show_pkg_only++; |
2380 | break; | 2412 | break; |
2413 | case 's': | ||
2414 | dump_only++; | ||
2415 | break; | ||
2381 | case 'S': | 2416 | case 'S': |
2382 | summary_only++; | 2417 | summary_only++; |
2383 | break; | 2418 | break; |
@@ -2405,6 +2440,10 @@ void cmdline(int argc, char **argv) | |||
2405 | case 'T': | 2440 | case 'T': |
2406 | tcc_activation_temp_override = atoi(optarg); | 2441 | tcc_activation_temp_override = atoi(optarg); |
2407 | break; | 2442 | break; |
2443 | case 'J': | ||
2444 | rapl_joules++; | ||
2445 | break; | ||
2446 | |||
2408 | default: | 2447 | default: |
2409 | usage(); | 2448 | usage(); |
2410 | } | 2449 | } |
@@ -2416,11 +2455,15 @@ int main(int argc, char **argv) | |||
2416 | cmdline(argc, argv); | 2455 | cmdline(argc, argv); |
2417 | 2456 | ||
2418 | if (verbose) | 2457 | if (verbose) |
2419 | fprintf(stderr, "turbostat v3.5 April 26, 2013" | 2458 | fprintf(stderr, "turbostat v3.6 Dec 2, 2013" |
2420 | " - Len Brown <lenb@kernel.org>\n"); | 2459 | " - Len Brown <lenb@kernel.org>\n"); |
2421 | 2460 | ||
2422 | turbostat_init(); | 2461 | turbostat_init(); |
2423 | 2462 | ||
2463 | /* dump counters and exit */ | ||
2464 | if (dump_only) | ||
2465 | return get_and_dump_counters(); | ||
2466 | |||
2424 | /* | 2467 | /* |
2425 | * if any params left, it must be a command to fork | 2468 | * if any params left, it must be a command to fork |
2426 | */ | 2469 | */ |
diff --git a/tools/scripts/Makefile.include b/tools/scripts/Makefile.include index ee76544deecb..8abbef164b4e 100644 --- a/tools/scripts/Makefile.include +++ b/tools/scripts/Makefile.include | |||
@@ -61,6 +61,7 @@ QUIET_SUBDIR1 = | |||
61 | ifneq ($(findstring $(MAKEFLAGS),s),s) | 61 | ifneq ($(findstring $(MAKEFLAGS),s),s) |
62 | ifneq ($(V),1) | 62 | ifneq ($(V),1) |
63 | QUIET_CC = @echo ' CC '$@; | 63 | QUIET_CC = @echo ' CC '$@; |
64 | QUIET_CC_FPIC = @echo ' CC FPIC '$@; | ||
64 | QUIET_AR = @echo ' AR '$@; | 65 | QUIET_AR = @echo ' AR '$@; |
65 | QUIET_LINK = @echo ' LINK '$@; | 66 | QUIET_LINK = @echo ' LINK '$@; |
66 | QUIET_MKDIR = @echo ' MKDIR '$@; | 67 | QUIET_MKDIR = @echo ' MKDIR '$@; |
@@ -76,5 +77,8 @@ ifneq ($(findstring $(MAKEFLAGS),s),s) | |||
76 | +@echo ' DESCEND '$(1); \ | 77 | +@echo ' DESCEND '$(1); \ |
77 | mkdir -p $(OUTPUT)$(1) && \ | 78 | mkdir -p $(OUTPUT)$(1) && \ |
78 | $(MAKE) $(COMMAND_O) subdir=$(if $(subdir),$(subdir)/$(1),$(1)) $(PRINT_DIR) -C $(1) $(2) | 79 | $(MAKE) $(COMMAND_O) subdir=$(if $(subdir),$(subdir)/$(1),$(1)) $(PRINT_DIR) -C $(1) $(2) |
80 | |||
81 | QUIET_CLEAN = @printf ' CLEAN %s\n' $1; | ||
82 | QUIET_INSTALL = @printf ' INSTALL %s\n' $1; | ||
79 | endif | 83 | endif |
80 | endif | 84 | endif |
diff --git a/tools/testing/ktest/ktest.pl b/tools/testing/ktest/ktest.pl index 999eab1bc64f..40631569a0fd 100755 --- a/tools/testing/ktest/ktest.pl +++ b/tools/testing/ktest/ktest.pl | |||
@@ -18,6 +18,7 @@ $| = 1; | |||
18 | my %opt; | 18 | my %opt; |
19 | my %repeat_tests; | 19 | my %repeat_tests; |
20 | my %repeats; | 20 | my %repeats; |
21 | my %evals; | ||
21 | 22 | ||
22 | #default opts | 23 | #default opts |
23 | my %default = ( | 24 | my %default = ( |
@@ -25,6 +26,7 @@ my %default = ( | |||
25 | "TEST_TYPE" => "build", | 26 | "TEST_TYPE" => "build", |
26 | "BUILD_TYPE" => "randconfig", | 27 | "BUILD_TYPE" => "randconfig", |
27 | "MAKE_CMD" => "make", | 28 | "MAKE_CMD" => "make", |
29 | "CLOSE_CONSOLE_SIGNAL" => "INT", | ||
28 | "TIMEOUT" => 120, | 30 | "TIMEOUT" => 120, |
29 | "TMP_DIR" => "/tmp/ktest/\${MACHINE}", | 31 | "TMP_DIR" => "/tmp/ktest/\${MACHINE}", |
30 | "SLEEP_TIME" => 60, # sleep time between tests | 32 | "SLEEP_TIME" => 60, # sleep time between tests |
@@ -39,6 +41,7 @@ my %default = ( | |||
39 | "CLEAR_LOG" => 0, | 41 | "CLEAR_LOG" => 0, |
40 | "BISECT_MANUAL" => 0, | 42 | "BISECT_MANUAL" => 0, |
41 | "BISECT_SKIP" => 1, | 43 | "BISECT_SKIP" => 1, |
44 | "BISECT_TRIES" => 1, | ||
42 | "MIN_CONFIG_TYPE" => "boot", | 45 | "MIN_CONFIG_TYPE" => "boot", |
43 | "SUCCESS_LINE" => "login:", | 46 | "SUCCESS_LINE" => "login:", |
44 | "DETECT_TRIPLE_FAULT" => 1, | 47 | "DETECT_TRIPLE_FAULT" => 1, |
@@ -137,6 +140,7 @@ my $bisect_bad_commit = ""; | |||
137 | my $reverse_bisect; | 140 | my $reverse_bisect; |
138 | my $bisect_manual; | 141 | my $bisect_manual; |
139 | my $bisect_skip; | 142 | my $bisect_skip; |
143 | my $bisect_tries; | ||
140 | my $config_bisect_good; | 144 | my $config_bisect_good; |
141 | my $bisect_ret_good; | 145 | my $bisect_ret_good; |
142 | my $bisect_ret_bad; | 146 | my $bisect_ret_bad; |
@@ -163,6 +167,7 @@ my $timeout; | |||
163 | my $booted_timeout; | 167 | my $booted_timeout; |
164 | my $detect_triplefault; | 168 | my $detect_triplefault; |
165 | my $console; | 169 | my $console; |
170 | my $close_console_signal; | ||
166 | my $reboot_success_line; | 171 | my $reboot_success_line; |
167 | my $success_line; | 172 | my $success_line; |
168 | my $stop_after_success; | 173 | my $stop_after_success; |
@@ -273,6 +278,7 @@ my %option_map = ( | |||
273 | "IGNORE_ERRORS" => \$ignore_errors, | 278 | "IGNORE_ERRORS" => \$ignore_errors, |
274 | "BISECT_MANUAL" => \$bisect_manual, | 279 | "BISECT_MANUAL" => \$bisect_manual, |
275 | "BISECT_SKIP" => \$bisect_skip, | 280 | "BISECT_SKIP" => \$bisect_skip, |
281 | "BISECT_TRIES" => \$bisect_tries, | ||
276 | "CONFIG_BISECT_GOOD" => \$config_bisect_good, | 282 | "CONFIG_BISECT_GOOD" => \$config_bisect_good, |
277 | "BISECT_RET_GOOD" => \$bisect_ret_good, | 283 | "BISECT_RET_GOOD" => \$bisect_ret_good, |
278 | "BISECT_RET_BAD" => \$bisect_ret_bad, | 284 | "BISECT_RET_BAD" => \$bisect_ret_bad, |
@@ -285,6 +291,7 @@ my %option_map = ( | |||
285 | "TIMEOUT" => \$timeout, | 291 | "TIMEOUT" => \$timeout, |
286 | "BOOTED_TIMEOUT" => \$booted_timeout, | 292 | "BOOTED_TIMEOUT" => \$booted_timeout, |
287 | "CONSOLE" => \$console, | 293 | "CONSOLE" => \$console, |
294 | "CLOSE_CONSOLE_SIGNAL" => \$close_console_signal, | ||
288 | "DETECT_TRIPLE_FAULT" => \$detect_triplefault, | 295 | "DETECT_TRIPLE_FAULT" => \$detect_triplefault, |
289 | "SUCCESS_LINE" => \$success_line, | 296 | "SUCCESS_LINE" => \$success_line, |
290 | "REBOOT_SUCCESS_LINE" => \$reboot_success_line, | 297 | "REBOOT_SUCCESS_LINE" => \$reboot_success_line, |
@@ -445,6 +452,27 @@ $config_help{"REBOOT_SCRIPT"} = << "EOF" | |||
445 | EOF | 452 | EOF |
446 | ; | 453 | ; |
447 | 454 | ||
455 | sub _logit { | ||
456 | if (defined($opt{"LOG_FILE"})) { | ||
457 | open(OUT, ">> $opt{LOG_FILE}") or die "Can't write to $opt{LOG_FILE}"; | ||
458 | print OUT @_; | ||
459 | close(OUT); | ||
460 | } | ||
461 | } | ||
462 | |||
463 | sub logit { | ||
464 | if (defined($opt{"LOG_FILE"})) { | ||
465 | _logit @_; | ||
466 | } else { | ||
467 | print @_; | ||
468 | } | ||
469 | } | ||
470 | |||
471 | sub doprint { | ||
472 | print @_; | ||
473 | _logit @_; | ||
474 | } | ||
475 | |||
448 | sub read_prompt { | 476 | sub read_prompt { |
449 | my ($cancel, $prompt) = @_; | 477 | my ($cancel, $prompt) = @_; |
450 | 478 | ||
@@ -662,6 +690,22 @@ sub set_value { | |||
662 | } | 690 | } |
663 | } | 691 | } |
664 | 692 | ||
693 | sub set_eval { | ||
694 | my ($lvalue, $rvalue, $name) = @_; | ||
695 | |||
696 | my $prvalue = process_variables($rvalue); | ||
697 | my $arr; | ||
698 | |||
699 | if (defined($evals{$lvalue})) { | ||
700 | $arr = $evals{$lvalue}; | ||
701 | } else { | ||
702 | $arr = []; | ||
703 | $evals{$lvalue} = $arr; | ||
704 | } | ||
705 | |||
706 | push @{$arr}, $rvalue; | ||
707 | } | ||
708 | |||
665 | sub set_variable { | 709 | sub set_variable { |
666 | my ($lvalue, $rvalue) = @_; | 710 | my ($lvalue, $rvalue) = @_; |
667 | 711 | ||
@@ -947,6 +991,20 @@ sub __read_config { | |||
947 | $test_case = 1; | 991 | $test_case = 1; |
948 | } | 992 | } |
949 | 993 | ||
994 | } elsif (/^\s*([A-Z_\[\]\d]+)\s*=~\s*(.*?)\s*$/) { | ||
995 | |||
996 | next if ($skip); | ||
997 | |||
998 | my $lvalue = $1; | ||
999 | my $rvalue = $2; | ||
1000 | |||
1001 | if ($default || $lvalue =~ /\[\d+\]$/) { | ||
1002 | set_eval($lvalue, $rvalue, $name); | ||
1003 | } else { | ||
1004 | my $val = "$lvalue\[$test_num\]"; | ||
1005 | set_eval($val, $rvalue, $name); | ||
1006 | } | ||
1007 | |||
950 | } elsif (/^\s*([A-Z_\[\]\d]+)\s*=\s*(.*?)\s*$/) { | 1008 | } elsif (/^\s*([A-Z_\[\]\d]+)\s*=\s*(.*?)\s*$/) { |
951 | 1009 | ||
952 | next if ($skip); | 1010 | next if ($skip); |
@@ -1126,6 +1184,10 @@ sub __eval_option { | |||
1126 | } elsif (defined($opt{$var})) { | 1184 | } elsif (defined($opt{$var})) { |
1127 | $o = $opt{$var}; | 1185 | $o = $opt{$var}; |
1128 | $retval = "$retval$o"; | 1186 | $retval = "$retval$o"; |
1187 | } elsif ($var eq "KERNEL_VERSION" && defined($make)) { | ||
1188 | # special option KERNEL_VERSION uses kernel version | ||
1189 | get_version(); | ||
1190 | $retval = "$retval$version"; | ||
1129 | } else { | 1191 | } else { |
1130 | $retval = "$retval\$\{$var\}"; | 1192 | $retval = "$retval\$\{$var\}"; |
1131 | } | 1193 | } |
@@ -1140,6 +1202,33 @@ sub __eval_option { | |||
1140 | return $retval; | 1202 | return $retval; |
1141 | } | 1203 | } |
1142 | 1204 | ||
1205 | sub process_evals { | ||
1206 | my ($name, $option, $i) = @_; | ||
1207 | |||
1208 | my $option_name = "$name\[$i\]"; | ||
1209 | my $ev; | ||
1210 | |||
1211 | my $old_option = $option; | ||
1212 | |||
1213 | if (defined($evals{$option_name})) { | ||
1214 | $ev = $evals{$option_name}; | ||
1215 | } elsif (defined($evals{$name})) { | ||
1216 | $ev = $evals{$name}; | ||
1217 | } else { | ||
1218 | return $option; | ||
1219 | } | ||
1220 | |||
1221 | for my $e (@{$ev}) { | ||
1222 | eval "\$option =~ $e"; | ||
1223 | } | ||
1224 | |||
1225 | if ($option ne $old_option) { | ||
1226 | doprint("$name changed from '$old_option' to '$option'\n"); | ||
1227 | } | ||
1228 | |||
1229 | return $option; | ||
1230 | } | ||
1231 | |||
1143 | sub eval_option { | 1232 | sub eval_option { |
1144 | my ($name, $option, $i) = @_; | 1233 | my ($name, $option, $i) = @_; |
1145 | 1234 | ||
@@ -1160,28 +1249,9 @@ sub eval_option { | |||
1160 | $option = __eval_option($name, $option, $i); | 1249 | $option = __eval_option($name, $option, $i); |
1161 | } | 1250 | } |
1162 | 1251 | ||
1163 | return $option; | 1252 | $option = process_evals($name, $option, $i); |
1164 | } | ||
1165 | 1253 | ||
1166 | sub _logit { | 1254 | return $option; |
1167 | if (defined($opt{"LOG_FILE"})) { | ||
1168 | open(OUT, ">> $opt{LOG_FILE}") or die "Can't write to $opt{LOG_FILE}"; | ||
1169 | print OUT @_; | ||
1170 | close(OUT); | ||
1171 | } | ||
1172 | } | ||
1173 | |||
1174 | sub logit { | ||
1175 | if (defined($opt{"LOG_FILE"})) { | ||
1176 | _logit @_; | ||
1177 | } else { | ||
1178 | print @_; | ||
1179 | } | ||
1180 | } | ||
1181 | |||
1182 | sub doprint { | ||
1183 | print @_; | ||
1184 | _logit @_; | ||
1185 | } | 1255 | } |
1186 | 1256 | ||
1187 | sub run_command; | 1257 | sub run_command; |
@@ -1296,7 +1366,7 @@ sub close_console { | |||
1296 | my ($fp, $pid) = @_; | 1366 | my ($fp, $pid) = @_; |
1297 | 1367 | ||
1298 | doprint "kill child process $pid\n"; | 1368 | doprint "kill child process $pid\n"; |
1299 | kill 2, $pid; | 1369 | kill $close_console_signal, $pid; |
1300 | 1370 | ||
1301 | print "closing!\n"; | 1371 | print "closing!\n"; |
1302 | close($fp); | 1372 | close($fp); |
@@ -2517,12 +2587,29 @@ sub run_bisect { | |||
2517 | $buildtype = "useconfig:$minconfig"; | 2587 | $buildtype = "useconfig:$minconfig"; |
2518 | } | 2588 | } |
2519 | 2589 | ||
2520 | my $ret = run_bisect_test $type, $buildtype; | 2590 | # If the user sets bisect_tries to less than 1, then no tries |
2591 | # is a success. | ||
2592 | my $ret = 1; | ||
2521 | 2593 | ||
2522 | if ($bisect_manual) { | 2594 | # Still let the user manually decide that though. |
2595 | if ($bisect_tries < 1 && $bisect_manual) { | ||
2523 | $ret = answer_bisect; | 2596 | $ret = answer_bisect; |
2524 | } | 2597 | } |
2525 | 2598 | ||
2599 | for (my $i = 0; $i < $bisect_tries; $i++) { | ||
2600 | if ($bisect_tries > 1) { | ||
2601 | my $t = $i + 1; | ||
2602 | doprint("Running bisect trial $t of $bisect_tries:\n"); | ||
2603 | } | ||
2604 | $ret = run_bisect_test $type, $buildtype; | ||
2605 | |||
2606 | if ($bisect_manual) { | ||
2607 | $ret = answer_bisect; | ||
2608 | } | ||
2609 | |||
2610 | last if (!$ret); | ||
2611 | } | ||
2612 | |||
2526 | # Are we looking for where it worked, not failed? | 2613 | # Are we looking for where it worked, not failed? |
2527 | if ($reverse_bisect && $ret >= 0) { | 2614 | if ($reverse_bisect && $ret >= 0) { |
2528 | $ret = !$ret; | 2615 | $ret = !$ret; |
@@ -3916,6 +4003,18 @@ for (my $i = 1; $i <= $opt{"NUM_TESTS"}; $i++) { | |||
3916 | 4003 | ||
3917 | my $makecmd = set_test_option("MAKE_CMD", $i); | 4004 | my $makecmd = set_test_option("MAKE_CMD", $i); |
3918 | 4005 | ||
4006 | $outputdir = set_test_option("OUTPUT_DIR", $i); | ||
4007 | $builddir = set_test_option("BUILD_DIR", $i); | ||
4008 | |||
4009 | chdir $builddir || die "can't change directory to $builddir"; | ||
4010 | |||
4011 | if (!-d $outputdir) { | ||
4012 | mkpath($outputdir) or | ||
4013 | die "can't create $outputdir"; | ||
4014 | } | ||
4015 | |||
4016 | $make = "$makecmd O=$outputdir"; | ||
4017 | |||
3919 | # Load all the options into their mapped variable names | 4018 | # Load all the options into their mapped variable names |
3920 | foreach my $opt (keys %option_map) { | 4019 | foreach my $opt (keys %option_map) { |
3921 | ${$option_map{$opt}} = set_test_option($opt, $i); | 4020 | ${$option_map{$opt}} = set_test_option($opt, $i); |
@@ -3940,13 +4039,9 @@ for (my $i = 1; $i <= $opt{"NUM_TESTS"}; $i++) { | |||
3940 | $start_minconfig = $minconfig; | 4039 | $start_minconfig = $minconfig; |
3941 | } | 4040 | } |
3942 | 4041 | ||
3943 | chdir $builddir || die "can't change directory to $builddir"; | 4042 | if (!-d $tmpdir) { |
3944 | 4043 | mkpath($tmpdir) or | |
3945 | foreach my $dir ($tmpdir, $outputdir) { | 4044 | die "can't create $tmpdir"; |
3946 | if (!-d $dir) { | ||
3947 | mkpath($dir) or | ||
3948 | die "can't create $dir"; | ||
3949 | } | ||
3950 | } | 4045 | } |
3951 | 4046 | ||
3952 | $ENV{"SSH_USER"} = $ssh_user; | 4047 | $ENV{"SSH_USER"} = $ssh_user; |
@@ -3955,7 +4050,6 @@ for (my $i = 1; $i <= $opt{"NUM_TESTS"}; $i++) { | |||
3955 | $buildlog = "$tmpdir/buildlog-$machine"; | 4050 | $buildlog = "$tmpdir/buildlog-$machine"; |
3956 | $testlog = "$tmpdir/testlog-$machine"; | 4051 | $testlog = "$tmpdir/testlog-$machine"; |
3957 | $dmesg = "$tmpdir/dmesg-$machine"; | 4052 | $dmesg = "$tmpdir/dmesg-$machine"; |
3958 | $make = "$makecmd O=$outputdir"; | ||
3959 | $output_config = "$outputdir/.config"; | 4053 | $output_config = "$outputdir/.config"; |
3960 | 4054 | ||
3961 | if (!$buildonly) { | 4055 | if (!$buildonly) { |
diff --git a/tools/testing/ktest/sample.conf b/tools/testing/ktest/sample.conf index 0a290fb4cd5e..172eec4517fb 100644 --- a/tools/testing/ktest/sample.conf +++ b/tools/testing/ktest/sample.conf | |||
@@ -328,6 +328,13 @@ | |||
328 | # For a virtual machine with guest name "Guest". | 328 | # For a virtual machine with guest name "Guest". |
329 | #CONSOLE = virsh console Guest | 329 | #CONSOLE = virsh console Guest |
330 | 330 | ||
331 | # Signal to send to kill console. | ||
332 | # ktest.pl will create a child process to monitor the console. | ||
333 | # When the console is finished, ktest will kill the child process | ||
334 | # with this signal. | ||
335 | # (default INT) | ||
336 | #CLOSE_CONSOLE_SIGNAL = HUP | ||
337 | |||
331 | # Required version ending to differentiate the test | 338 | # Required version ending to differentiate the test |
332 | # from other linux builds on the system. | 339 | # from other linux builds on the system. |
333 | #LOCALVERSION = -test | 340 | #LOCALVERSION = -test |
@@ -1021,6 +1028,20 @@ | |||
1021 | # BISECT_BAD with BISECT_CHECK = good or | 1028 | # BISECT_BAD with BISECT_CHECK = good or |
1022 | # BISECT_CHECK = bad, respectively. | 1029 | # BISECT_CHECK = bad, respectively. |
1023 | # | 1030 | # |
1031 | # BISECT_TRIES = 5 (optional, default 1) | ||
1032 | # | ||
1033 | # For those cases that it takes several tries to hit a bug, | ||
1034 | # the BISECT_TRIES is useful. It is the number of times the | ||
1035 | # test is ran before it says the kernel is good. The first failure | ||
1036 | # will stop trying and mark the current SHA1 as bad. | ||
1037 | # | ||
1038 | # Note, as with all race bugs, there's no guarantee that if | ||
1039 | # it succeeds, it is really a good bisect. But it helps in case | ||
1040 | # the bug is some what reliable. | ||
1041 | # | ||
1042 | # You can set BISECT_TRIES to zero, and all tests will be considered | ||
1043 | # good, unless you also set BISECT_MANUAL. | ||
1044 | # | ||
1024 | # BISECT_RET_GOOD = 0 (optional, default undefined) | 1045 | # BISECT_RET_GOOD = 0 (optional, default undefined) |
1025 | # | 1046 | # |
1026 | # In case the specificed test returns something other than just | 1047 | # In case the specificed test returns something other than just |
diff --git a/tools/testing/selftests/Makefile b/tools/testing/selftests/Makefile index 9f3eae290900..32487ed18354 100644 --- a/tools/testing/selftests/Makefile +++ b/tools/testing/selftests/Makefile | |||
@@ -9,6 +9,7 @@ TARGETS += ptrace | |||
9 | TARGETS += timers | 9 | TARGETS += timers |
10 | TARGETS += vm | 10 | TARGETS += vm |
11 | TARGETS += powerpc | 11 | TARGETS += powerpc |
12 | TARGETS += user | ||
12 | 13 | ||
13 | all: | 14 | all: |
14 | for TARGET in $(TARGETS); do \ | 15 | for TARGET in $(TARGETS); do \ |
diff --git a/tools/testing/selftests/ipc/msgque.c b/tools/testing/selftests/ipc/msgque.c index d66418237d21..aa290c0de6f5 100644 --- a/tools/testing/selftests/ipc/msgque.c +++ b/tools/testing/selftests/ipc/msgque.c | |||
@@ -201,6 +201,7 @@ int main(int argc, char **argv) | |||
201 | 201 | ||
202 | msgque.msq_id = msgget(msgque.key, IPC_CREAT | IPC_EXCL | 0666); | 202 | msgque.msq_id = msgget(msgque.key, IPC_CREAT | IPC_EXCL | 0666); |
203 | if (msgque.msq_id == -1) { | 203 | if (msgque.msq_id == -1) { |
204 | err = -errno; | ||
204 | printf("Can't create queue\n"); | 205 | printf("Can't create queue\n"); |
205 | goto err_out; | 206 | goto err_out; |
206 | } | 207 | } |
diff --git a/tools/testing/selftests/rcutorture/.gitignore b/tools/testing/selftests/rcutorture/.gitignore new file mode 100644 index 000000000000..05838f6f2ebe --- /dev/null +++ b/tools/testing/selftests/rcutorture/.gitignore | |||
@@ -0,0 +1,6 @@ | |||
1 | initrd | ||
2 | linux-2.6 | ||
3 | b[0-9]* | ||
4 | rcu-test-image | ||
5 | res | ||
6 | *.swp | ||
diff --git a/tools/testing/selftests/rcutorture/bin/config2frag.sh b/tools/testing/selftests/rcutorture/bin/config2frag.sh new file mode 100644 index 000000000000..9f9ffcd427d3 --- /dev/null +++ b/tools/testing/selftests/rcutorture/bin/config2frag.sh | |||
@@ -0,0 +1,25 @@ | |||
1 | #!/bin/sh | ||
2 | # Usage: sh config2frag.sh < .config > configfrag | ||
3 | # | ||
4 | # Converts the "# CONFIG_XXX is not set" to "CONFIG_XXX=n" so that the | ||
5 | # resulting file becomes a legitimate Kconfig fragment. | ||
6 | # | ||
7 | # This program is free software; you can redistribute it and/or modify | ||
8 | # it under the terms of the GNU General Public License as published by | ||
9 | # the Free Software Foundation; either version 2 of the License, or | ||
10 | # (at your option) any later version. | ||
11 | # | ||
12 | # This program is distributed in the hope that it will be useful, | ||
13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | # GNU General Public License for more details. | ||
16 | # | ||
17 | # You should have received a copy of the GNU General Public License | ||
18 | # along with this program; if not, you can access it online at | ||
19 | # http://www.gnu.org/licenses/gpl-2.0.html. | ||
20 | # | ||
21 | # Copyright (C) IBM Corporation, 2013 | ||
22 | # | ||
23 | # Authors: Paul E. McKenney <paulmck@linux.vnet.ibm.com> | ||
24 | |||
25 | LANG=C sed -e 's/^# CONFIG_\([a-zA-Z0-9_]*\) is not set$/CONFIG_\1=n/' | ||
diff --git a/tools/testing/selftests/rcutorture/bin/configNR_CPUS.sh b/tools/testing/selftests/rcutorture/bin/configNR_CPUS.sh new file mode 100755 index 000000000000..43540f1828cc --- /dev/null +++ b/tools/testing/selftests/rcutorture/bin/configNR_CPUS.sh | |||
@@ -0,0 +1,45 @@ | |||
1 | #!/bin/bash | ||
2 | # | ||
3 | # Extract the number of CPUs expected from the specified Kconfig-file | ||
4 | # fragment by checking CONFIG_SMP and CONFIG_NR_CPUS. If the specified | ||
5 | # file gives no clue, base the number on the number of idle CPUs on | ||
6 | # the system. | ||
7 | # | ||
8 | # Usage: configNR_CPUS.sh config-frag | ||
9 | # | ||
10 | # This program is free software; you can redistribute it and/or modify | ||
11 | # it under the terms of the GNU General Public License as published by | ||
12 | # the Free Software Foundation; either version 2 of the License, or | ||
13 | # (at your option) any later version. | ||
14 | # | ||
15 | # This program is distributed in the hope that it will be useful, | ||
16 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
17 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
18 | # GNU General Public License for more details. | ||
19 | # | ||
20 | # You should have received a copy of the GNU General Public License | ||
21 | # along with this program; if not, you can access it online at | ||
22 | # http://www.gnu.org/licenses/gpl-2.0.html. | ||
23 | # | ||
24 | # Copyright (C) IBM Corporation, 2013 | ||
25 | # | ||
26 | # Authors: Paul E. McKenney <paulmck@linux.vnet.ibm.com> | ||
27 | |||
28 | cf=$1 | ||
29 | if test ! -r $cf | ||
30 | then | ||
31 | echo Unreadable config fragment $cf 1>&2 | ||
32 | exit -1 | ||
33 | fi | ||
34 | if grep -q '^CONFIG_SMP=n$' $cf | ||
35 | then | ||
36 | echo 1 | ||
37 | exit 0 | ||
38 | fi | ||
39 | if grep -q '^CONFIG_NR_CPUS=' $cf | ||
40 | then | ||
41 | grep '^CONFIG_NR_CPUS=' $cf | | ||
42 | sed -e 's/^CONFIG_NR_CPUS=\([0-9]*\).*$/\1/' | ||
43 | exit 0 | ||
44 | fi | ||
45 | cpus2use.sh | ||
diff --git a/tools/testing/selftests/rcutorture/bin/configcheck.sh b/tools/testing/selftests/rcutorture/bin/configcheck.sh new file mode 100755 index 000000000000..d686537dd55c --- /dev/null +++ b/tools/testing/selftests/rcutorture/bin/configcheck.sh | |||
@@ -0,0 +1,54 @@ | |||
1 | #!/bin/sh | ||
2 | # Usage: sh configcheck.sh .config .config-template | ||
3 | # | ||
4 | # This program is free software; you can redistribute it and/or modify | ||
5 | # it under the terms of the GNU General Public License as published by | ||
6 | # the Free Software Foundation; either version 2 of the License, or | ||
7 | # (at your option) any later version. | ||
8 | # | ||
9 | # This program is distributed in the hope that it will be useful, | ||
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | # GNU General Public License for more details. | ||
13 | # | ||
14 | # You should have received a copy of the GNU General Public License | ||
15 | # along with this program; if not, you can access it online at | ||
16 | # http://www.gnu.org/licenses/gpl-2.0.html. | ||
17 | # | ||
18 | # Copyright (C) IBM Corporation, 2011 | ||
19 | # | ||
20 | # Authors: Paul E. McKenney <paulmck@linux.vnet.ibm.com> | ||
21 | |||
22 | T=/tmp/abat-chk-config.sh.$$ | ||
23 | trap 'rm -rf $T' 0 | ||
24 | mkdir $T | ||
25 | |||
26 | cat $1 > $T/.config | ||
27 | |||
28 | cat $2 | sed -e 's/\(.*\)=n/# \1 is not set/' -e 's/^#CHECK#//' | | ||
29 | awk ' | ||
30 | BEGIN { | ||
31 | print "if grep -q \"" $0 "\" < '"$T/.config"'"; | ||
32 | print "then"; | ||
33 | print "\t:"; | ||
34 | print "else"; | ||
35 | if ($1 == "#") { | ||
36 | print "\tif grep -q \"" $2 "\" < '"$T/.config"'"; | ||
37 | print "\tthen"; | ||
38 | print "\t\tif test \"$firsttime\" = \"\"" | ||
39 | print "\t\tthen" | ||
40 | print "\t\t\tfirsttime=1" | ||
41 | print "\t\tfi" | ||
42 | print "\t\techo \":" $2 ": improperly set\""; | ||
43 | print "\telse"; | ||
44 | print "\t\t:"; | ||
45 | print "\tfi"; | ||
46 | } else { | ||
47 | print "\tif test \"$firsttime\" = \"\"" | ||
48 | print "\tthen" | ||
49 | print "\t\tfirsttime=1" | ||
50 | print "\tfi" | ||
51 | print "\techo \":" $0 ": improperly set\""; | ||
52 | } | ||
53 | print "fi"; | ||
54 | }' | sh | ||
diff --git a/tools/testing/selftests/rcutorture/bin/configinit.sh b/tools/testing/selftests/rcutorture/bin/configinit.sh new file mode 100755 index 000000000000..a1be6e62add1 --- /dev/null +++ b/tools/testing/selftests/rcutorture/bin/configinit.sh | |||
@@ -0,0 +1,74 @@ | |||
1 | #!/bin/sh | ||
2 | # | ||
3 | # sh configinit.sh config-spec-file [ build output dir ] | ||
4 | # | ||
5 | # Create a .config file from the spec file. Run from the kernel source tree. | ||
6 | # Exits with 0 if all went well, with 1 if all went well but the config | ||
7 | # did not match, and some other number for other failures. | ||
8 | # | ||
9 | # The first argument is the .config specification file, which contains | ||
10 | # desired settings, for example, "CONFIG_NO_HZ=y". For best results, | ||
11 | # this should be a full pathname. | ||
12 | # | ||
13 | # The second argument is a optional path to a build output directory, | ||
14 | # for example, "O=/tmp/foo". If this argument is omitted, the .config | ||
15 | # file will be generated directly in the current directory. | ||
16 | # | ||
17 | # This program is free software; you can redistribute it and/or modify | ||
18 | # it under the terms of the GNU General Public License as published by | ||
19 | # the Free Software Foundation; either version 2 of the License, or | ||
20 | # (at your option) any later version. | ||
21 | # | ||
22 | # This program is distributed in the hope that it will be useful, | ||
23 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
24 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
25 | # GNU General Public License for more details. | ||
26 | # | ||
27 | # You should have received a copy of the GNU General Public License | ||
28 | # along with this program; if not, you can access it online at | ||
29 | # http://www.gnu.org/licenses/gpl-2.0.html. | ||
30 | # | ||
31 | # Copyright (C) IBM Corporation, 2013 | ||
32 | # | ||
33 | # Authors: Paul E. McKenney <paulmck@linux.vnet.ibm.com> | ||
34 | |||
35 | T=/tmp/configinit.sh.$$ | ||
36 | trap 'rm -rf $T' 0 | ||
37 | mkdir $T | ||
38 | |||
39 | # Capture config spec file. | ||
40 | |||
41 | c=$1 | ||
42 | buildloc=$2 | ||
43 | builddir= | ||
44 | if test -n $buildloc | ||
45 | then | ||
46 | if echo $buildloc | grep -q '^O=' | ||
47 | then | ||
48 | builddir=`echo $buildloc | sed -e 's/^O=//'` | ||
49 | if test ! -d $builddir | ||
50 | then | ||
51 | mkdir $builddir | ||
52 | fi | ||
53 | else | ||
54 | echo Bad build directory: \"$builddir\" | ||
55 | exit 2 | ||
56 | fi | ||
57 | fi | ||
58 | |||
59 | sed -e 's/^\(CONFIG[0-9A-Z_]*\)=.*$/grep -v "^# \1" |/' < $c > $T/u.sh | ||
60 | sed -e 's/^\(CONFIG[0-9A-Z_]*=\).*$/grep -v \1 |/' < $c >> $T/u.sh | ||
61 | grep '^grep' < $T/u.sh > $T/upd.sh | ||
62 | echo "cat - $c" >> $T/upd.sh | ||
63 | make mrproper | ||
64 | make $buildloc distclean > $builddir/Make.distclean 2>&1 | ||
65 | make $buildloc defconfig > $builddir/Make.defconfig.out 2>&1 | ||
66 | mv $builddir/.config $builddir/.config.sav | ||
67 | sh $T/upd.sh < $builddir/.config.sav > $builddir/.config | ||
68 | cp $builddir/.config $builddir/.config.new | ||
69 | yes '' | make $buildloc oldconfig > $builddir/Make.modconfig.out 2>&1 | ||
70 | |||
71 | # verify new config matches specification. | ||
72 | configcheck.sh $builddir/.config $c | ||
73 | |||
74 | exit 0 | ||
diff --git a/tools/testing/selftests/rcutorture/bin/cpus2use.sh b/tools/testing/selftests/rcutorture/bin/cpus2use.sh new file mode 100755 index 000000000000..abe14b7f36e9 --- /dev/null +++ b/tools/testing/selftests/rcutorture/bin/cpus2use.sh | |||
@@ -0,0 +1,41 @@ | |||
1 | #!/bin/bash | ||
2 | # | ||
3 | # Get an estimate of how CPU-hoggy to be. | ||
4 | # | ||
5 | # Usage: cpus2use.sh | ||
6 | # | ||
7 | # This program is free software; you can redistribute it and/or modify | ||
8 | # it under the terms of the GNU General Public License as published by | ||
9 | # the Free Software Foundation; either version 2 of the License, or | ||
10 | # (at your option) any later version. | ||
11 | # | ||
12 | # This program is distributed in the hope that it will be useful, | ||
13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | # GNU General Public License for more details. | ||
16 | # | ||
17 | # You should have received a copy of the GNU General Public License | ||
18 | # along with this program; if not, you can access it online at | ||
19 | # http://www.gnu.org/licenses/gpl-2.0.html. | ||
20 | # | ||
21 | # Copyright (C) IBM Corporation, 2013 | ||
22 | # | ||
23 | # Authors: Paul E. McKenney <paulmck@linux.vnet.ibm.com> | ||
24 | |||
25 | ncpus=`grep '^processor' /proc/cpuinfo | wc -l` | ||
26 | idlecpus=`mpstat | tail -1 | \ | ||
27 | awk -v ncpus=$ncpus '{ print ncpus * ($7 + $12) / 100 }'` | ||
28 | awk -v ncpus=$ncpus -v idlecpus=$idlecpus < /dev/null ' | ||
29 | BEGIN { | ||
30 | cpus2use = idlecpus; | ||
31 | if (cpus2use < 1) | ||
32 | cpus2use = 1; | ||
33 | if (cpus2use < ncpus / 10) | ||
34 | cpus2use = ncpus / 10; | ||
35 | if (cpus2use == int(cpus2use)) | ||
36 | cpus2use = int(cpus2use) | ||
37 | else | ||
38 | cpus2use = int(cpus2use) + 1 | ||
39 | print cpus2use; | ||
40 | }' | ||
41 | |||
diff --git a/tools/testing/selftests/rcutorture/bin/functions.sh b/tools/testing/selftests/rcutorture/bin/functions.sh new file mode 100644 index 000000000000..587561d7c035 --- /dev/null +++ b/tools/testing/selftests/rcutorture/bin/functions.sh | |||
@@ -0,0 +1,198 @@ | |||
1 | #!/bin/bash | ||
2 | # | ||
3 | # Shell functions for the rest of the scripts. | ||
4 | # | ||
5 | # This program is free software; you can redistribute it and/or modify | ||
6 | # it under the terms of the GNU General Public License as published by | ||
7 | # the Free Software Foundation; either version 2 of the License, or | ||
8 | # (at your option) any later version. | ||
9 | # | ||
10 | # This program is distributed in the hope that it will be useful, | ||
11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | # GNU General Public License for more details. | ||
14 | # | ||
15 | # You should have received a copy of the GNU General Public License | ||
16 | # along with this program; if not, you can access it online at | ||
17 | # http://www.gnu.org/licenses/gpl-2.0.html. | ||
18 | # | ||
19 | # Copyright (C) IBM Corporation, 2013 | ||
20 | # | ||
21 | # Authors: Paul E. McKenney <paulmck@linux.vnet.ibm.com> | ||
22 | |||
23 | # bootparam_hotplug_cpu bootparam-string | ||
24 | # | ||
25 | # Returns 1 if the specified boot-parameter string tells rcutorture to | ||
26 | # test CPU-hotplug operations. | ||
27 | bootparam_hotplug_cpu () { | ||
28 | echo "$1" | grep -q "rcutorture\.onoff_" | ||
29 | } | ||
30 | |||
31 | # checkarg --argname argtype $# arg mustmatch cannotmatch | ||
32 | # | ||
33 | # Checks the specified argument "arg" against the mustmatch and cannotmatch | ||
34 | # patterns. | ||
35 | checkarg () { | ||
36 | if test $3 -le 1 | ||
37 | then | ||
38 | echo $1 needs argument $2 matching \"$5\" | ||
39 | usage | ||
40 | fi | ||
41 | if echo "$4" | grep -q -e "$5" | ||
42 | then | ||
43 | : | ||
44 | else | ||
45 | echo $1 $2 \"$4\" must match \"$5\" | ||
46 | usage | ||
47 | fi | ||
48 | if echo "$4" | grep -q -e "$6" | ||
49 | then | ||
50 | echo $1 $2 \"$4\" must not match \"$6\" | ||
51 | usage | ||
52 | fi | ||
53 | } | ||
54 | |||
55 | # configfrag_boot_params bootparam-string config-fragment-file | ||
56 | # | ||
57 | # Adds boot parameters from the .boot file, if any. | ||
58 | configfrag_boot_params () { | ||
59 | if test -r "$2.boot" | ||
60 | then | ||
61 | echo $1 `grep -v '^#' "$2.boot" | tr '\012' ' '` | ||
62 | else | ||
63 | echo $1 | ||
64 | fi | ||
65 | } | ||
66 | |||
67 | # configfrag_hotplug_cpu config-fragment-file | ||
68 | # | ||
69 | # Returns 1 if the config fragment specifies hotplug CPU. | ||
70 | configfrag_hotplug_cpu () { | ||
71 | if test ! -r "$1" | ||
72 | then | ||
73 | echo Unreadable config fragment "$1" 1>&2 | ||
74 | exit -1 | ||
75 | fi | ||
76 | grep -q '^CONFIG_HOTPLUG_CPU=y$' "$1" | ||
77 | } | ||
78 | |||
79 | # identify_qemu builddir | ||
80 | # | ||
81 | # Returns our best guess as to which qemu command is appropriate for | ||
82 | # the kernel at hand. Override with the RCU_QEMU_CMD environment variable. | ||
83 | identify_qemu () { | ||
84 | local u="`file "$1"`" | ||
85 | if test -n "$RCU_QEMU_CMD" | ||
86 | then | ||
87 | echo $RCU_QEMU_CMD | ||
88 | elif echo $u | grep -q x86-64 | ||
89 | then | ||
90 | echo qemu-system-x86_64 | ||
91 | elif echo $u | grep -q "Intel 80386" | ||
92 | then | ||
93 | echo qemu-system-i386 | ||
94 | elif uname -a | grep -q ppc64 | ||
95 | then | ||
96 | echo qemu-system-ppc64 | ||
97 | else | ||
98 | echo Cannot figure out what qemu command to use! 1>&2 | ||
99 | # Usually this will be one of /usr/bin/qemu-system-* | ||
100 | # Use RCU_QEMU_CMD environment variable or appropriate | ||
101 | # argument to top-level script. | ||
102 | exit 1 | ||
103 | fi | ||
104 | } | ||
105 | |||
106 | # identify_qemu_append qemu-cmd | ||
107 | # | ||
108 | # Output arguments for the qemu "-append" string based on CPU type | ||
109 | # and the RCU_QEMU_INTERACTIVE environment variable. | ||
110 | identify_qemu_append () { | ||
111 | case "$1" in | ||
112 | qemu-system-x86_64|qemu-system-i386) | ||
113 | echo noapic selinux=0 initcall_debug debug | ||
114 | ;; | ||
115 | esac | ||
116 | if test -n "$RCU_QEMU_INTERACTIVE" | ||
117 | then | ||
118 | echo root=/dev/sda | ||
119 | else | ||
120 | echo console=ttyS0 | ||
121 | fi | ||
122 | } | ||
123 | |||
124 | # identify_qemu_args qemu-cmd serial-file | ||
125 | # | ||
126 | # Output arguments for qemu arguments based on the RCU_QEMU_MAC | ||
127 | # and RCU_QEMU_INTERACTIVE environment variables. | ||
128 | identify_qemu_args () { | ||
129 | case "$1" in | ||
130 | qemu-system-x86_64|qemu-system-i386) | ||
131 | ;; | ||
132 | qemu-system-ppc64) | ||
133 | echo -enable-kvm -M pseries -cpu POWER7 -nodefaults | ||
134 | echo -device spapr-vscsi | ||
135 | if test -n "$RCU_QEMU_INTERACTIVE" -a -n "$RCU_QEMU_MAC" | ||
136 | then | ||
137 | echo -device spapr-vlan,netdev=net0,mac=$RCU_QEMU_MAC | ||
138 | echo -netdev bridge,br=br0,id=net0 | ||
139 | elif test -n "$RCU_QEMU_INTERACTIVE" | ||
140 | then | ||
141 | echo -net nic -net user | ||
142 | fi | ||
143 | ;; | ||
144 | esac | ||
145 | if test -n "$RCU_QEMU_INTERACTIVE" | ||
146 | then | ||
147 | echo -monitor stdio -serial pty -S | ||
148 | else | ||
149 | echo -serial file:$2 | ||
150 | fi | ||
151 | } | ||
152 | |||
153 | # identify_qemu_vcpus | ||
154 | # | ||
155 | # Returns the number of virtual CPUs available to the aggregate of the | ||
156 | # guest OSes. | ||
157 | identify_qemu_vcpus () { | ||
158 | lscpu | grep '^CPU(s):' | sed -e 's/CPU(s)://' | ||
159 | } | ||
160 | |||
161 | # print_bug | ||
162 | # | ||
163 | # Prints "BUG: " in red followed by remaining arguments | ||
164 | print_bug () { | ||
165 | printf '\033[031mBUG: \033[m' | ||
166 | echo $* | ||
167 | } | ||
168 | |||
169 | # print_warning | ||
170 | # | ||
171 | # Prints "WARNING: " in yellow followed by remaining arguments | ||
172 | print_warning () { | ||
173 | printf '\033[033mWARNING: \033[m' | ||
174 | echo $* | ||
175 | } | ||
176 | |||
177 | # specify_qemu_cpus qemu-cmd qemu-args #cpus | ||
178 | # | ||
179 | # Appends a string containing "-smp XXX" to qemu-args, unless the incoming | ||
180 | # qemu-args already contains "-smp". | ||
181 | specify_qemu_cpus () { | ||
182 | local nt; | ||
183 | |||
184 | if echo $2 | grep -q -e -smp | ||
185 | then | ||
186 | echo $2 | ||
187 | else | ||
188 | case "$1" in | ||
189 | qemu-system-x86_64|qemu-system-i386) | ||
190 | echo $2 -smp $3 | ||
191 | ;; | ||
192 | qemu-system-ppc64) | ||
193 | nt="`lscpu | grep '^NUMA node0' | sed -e 's/^[^,]*,\([0-9]*\),.*$/\1/'`" | ||
194 | echo $2 -smp cores=`expr \( $3 + $nt - 1 \) / $nt`,threads=$nt | ||
195 | ;; | ||
196 | esac | ||
197 | fi | ||
198 | } | ||
diff --git a/tools/testing/selftests/rcutorture/bin/kvm-build.sh b/tools/testing/selftests/rcutorture/bin/kvm-build.sh new file mode 100755 index 000000000000..197901ec10bf --- /dev/null +++ b/tools/testing/selftests/rcutorture/bin/kvm-build.sh | |||
@@ -0,0 +1,71 @@ | |||
1 | #!/bin/bash | ||
2 | # | ||
3 | # Build a kvm-ready Linux kernel from the tree in the current directory. | ||
4 | # | ||
5 | # Usage: sh kvm-build.sh config-template build-dir more-configs | ||
6 | # | ||
7 | # This program is free software; you can redistribute it and/or modify | ||
8 | # it under the terms of the GNU General Public License as published by | ||
9 | # the Free Software Foundation; either version 2 of the License, or | ||
10 | # (at your option) any later version. | ||
11 | # | ||
12 | # This program is distributed in the hope that it will be useful, | ||
13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | # GNU General Public License for more details. | ||
16 | # | ||
17 | # You should have received a copy of the GNU General Public License | ||
18 | # along with this program; if not, you can access it online at | ||
19 | # http://www.gnu.org/licenses/gpl-2.0.html. | ||
20 | # | ||
21 | # Copyright (C) IBM Corporation, 2011 | ||
22 | # | ||
23 | # Authors: Paul E. McKenney <paulmck@linux.vnet.ibm.com> | ||
24 | |||
25 | config_template=${1} | ||
26 | if test -z "$config_template" -o ! -f "$config_template" -o ! -r "$config_template" | ||
27 | then | ||
28 | echo "kvm-build.sh :$config_template: Not a readable file" | ||
29 | exit 1 | ||
30 | fi | ||
31 | builddir=${2} | ||
32 | if test -z "$builddir" -o ! -d "$builddir" -o ! -w "$builddir" | ||
33 | then | ||
34 | echo "kvm-build.sh :$builddir: Not a writable directory, cannot build into it" | ||
35 | exit 1 | ||
36 | fi | ||
37 | moreconfigs=${3} | ||
38 | if test -z "$moreconfigs" -o ! -r "$moreconfigs" | ||
39 | then | ||
40 | echo "kvm-build.sh :$moreconfigs: Not a readable file" | ||
41 | exit 1 | ||
42 | fi | ||
43 | |||
44 | T=/tmp/test-linux.sh.$$ | ||
45 | trap 'rm -rf $T' 0 | ||
46 | mkdir $T | ||
47 | |||
48 | cat ${config_template} | grep -v CONFIG_RCU_TORTURE_TEST > $T/config | ||
49 | cat << ___EOF___ >> $T/config | ||
50 | CONFIG_INITRAMFS_SOURCE="$RCU_INITRD" | ||
51 | CONFIG_VIRTIO_PCI=y | ||
52 | CONFIG_VIRTIO_CONSOLE=y | ||
53 | ___EOF___ | ||
54 | cat $moreconfigs >> $T/config | ||
55 | |||
56 | configinit.sh $T/config O=$builddir | ||
57 | retval=$? | ||
58 | if test $retval -gt 1 | ||
59 | then | ||
60 | exit 2 | ||
61 | fi | ||
62 | ncpus=`cpus2use.sh` | ||
63 | make O=$builddir -j$ncpus $RCU_KMAKE_ARG > $builddir/Make.out 2>&1 | ||
64 | retval=$? | ||
65 | if test $retval -ne 0 || grep "rcu[^/]*": < $builddir/Make.out | egrep -q "Stop|Error|error:|warning:" || egrep -q "Stop|Error|error:" < $builddir/Make.out | ||
66 | then | ||
67 | echo Kernel build error | ||
68 | egrep "Stop|Error|error:|warning:" < $builddir/Make.out | ||
69 | echo Run aborted. | ||
70 | exit 3 | ||
71 | fi | ||
diff --git a/tools/testing/selftests/rcutorture/bin/kvm-recheck.sh b/tools/testing/selftests/rcutorture/bin/kvm-recheck.sh new file mode 100755 index 000000000000..baef09f3469b --- /dev/null +++ b/tools/testing/selftests/rcutorture/bin/kvm-recheck.sh | |||
@@ -0,0 +1,44 @@ | |||
1 | #!/bin/bash | ||
2 | # | ||
3 | # Given the results directories for previous KVM runs of rcutorture, | ||
4 | # check the build and console output for errors. Given a directory | ||
5 | # containing results directories, this recursively checks them all. | ||
6 | # | ||
7 | # Usage: sh kvm-recheck.sh resdir ... | ||
8 | # | ||
9 | # This program is free software; you can redistribute it and/or modify | ||
10 | # it under the terms of the GNU General Public License as published by | ||
11 | # the Free Software Foundation; either version 2 of the License, or | ||
12 | # (at your option) any later version. | ||
13 | # | ||
14 | # This program is distributed in the hope that it will be useful, | ||
15 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
17 | # GNU General Public License for more details. | ||
18 | # | ||
19 | # You should have received a copy of the GNU General Public License | ||
20 | # along with this program; if not, you can access it online at | ||
21 | # http://www.gnu.org/licenses/gpl-2.0.html. | ||
22 | # | ||
23 | # Copyright (C) IBM Corporation, 2011 | ||
24 | # | ||
25 | # Authors: Paul E. McKenney <paulmck@linux.vnet.ibm.com> | ||
26 | |||
27 | PATH=`pwd`/tools/testing/selftests/rcutorture/bin:$PATH; export PATH | ||
28 | for rd in "$@" | ||
29 | do | ||
30 | dirs=`find $rd -name Make.defconfig.out -print | sort | sed -e 's,/[^/]*$,,' | sort -u` | ||
31 | for i in $dirs | ||
32 | do | ||
33 | configfile=`echo $i | sed -e 's/^.*\///'` | ||
34 | echo $configfile | ||
35 | configcheck.sh $i/.config $i/ConfigFragment | ||
36 | parse-build.sh $i/Make.out $configfile | ||
37 | parse-rcutorture.sh $i/console.log $configfile | ||
38 | parse-console.sh $i/console.log $configfile | ||
39 | if test -r $i/Warnings | ||
40 | then | ||
41 | cat $i/Warnings | ||
42 | fi | ||
43 | done | ||
44 | done | ||
diff --git a/tools/testing/selftests/rcutorture/bin/kvm-test-1-rcu.sh b/tools/testing/selftests/rcutorture/bin/kvm-test-1-rcu.sh new file mode 100755 index 000000000000..151b23788935 --- /dev/null +++ b/tools/testing/selftests/rcutorture/bin/kvm-test-1-rcu.sh | |||
@@ -0,0 +1,192 @@ | |||
1 | #!/bin/bash | ||
2 | # | ||
3 | # Run a kvm-based test of the specified tree on the specified configs. | ||
4 | # Fully automated run and error checking, no graphics console. | ||
5 | # | ||
6 | # Execute this in the source tree. Do not run it as a background task | ||
7 | # because qemu does not seem to like that much. | ||
8 | # | ||
9 | # Usage: sh kvm-test-1-rcu.sh config builddir resdir minutes qemu-args bootargs | ||
10 | # | ||
11 | # qemu-args defaults to "" -- you will want "-nographic" if running headless. | ||
12 | # bootargs defaults to "root=/dev/sda noapic selinux=0 console=ttyS0" | ||
13 | # "initcall_debug debug rcutorture.stat_interval=15" | ||
14 | # "rcutorture.shutdown_secs=$((minutes * 60))" | ||
15 | # "rcutorture.rcutorture_runnable=1" | ||
16 | # | ||
17 | # Anything you specify for either qemu-args or bootargs is appended to | ||
18 | # the default values. The "-smp" value is deduced from the contents of | ||
19 | # the config fragment. | ||
20 | # | ||
21 | # More sophisticated argument parsing is clearly needed. | ||
22 | # | ||
23 | # This program is free software; you can redistribute it and/or modify | ||
24 | # it under the terms of the GNU General Public License as published by | ||
25 | # the Free Software Foundation; either version 2 of the License, or | ||
26 | # (at your option) any later version. | ||
27 | # | ||
28 | # This program is distributed in the hope that it will be useful, | ||
29 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
30 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
31 | # GNU General Public License for more details. | ||
32 | # | ||
33 | # You should have received a copy of the GNU General Public License | ||
34 | # along with this program; if not, you can access it online at | ||
35 | # http://www.gnu.org/licenses/gpl-2.0.html. | ||
36 | # | ||
37 | # Copyright (C) IBM Corporation, 2011 | ||
38 | # | ||
39 | # Authors: Paul E. McKenney <paulmck@linux.vnet.ibm.com> | ||
40 | |||
41 | grace=120 | ||
42 | |||
43 | T=/tmp/kvm-test-1-rcu.sh.$$ | ||
44 | trap 'rm -rf $T' 0 | ||
45 | |||
46 | . $KVM/bin/functions.sh | ||
47 | . $KVPATH/ver_functions.sh | ||
48 | |||
49 | config_template=${1} | ||
50 | title=`echo $config_template | sed -e 's/^.*\///'` | ||
51 | builddir=${2} | ||
52 | if test -z "$builddir" -o ! -d "$builddir" -o ! -w "$builddir" | ||
53 | then | ||
54 | echo "kvm-test-1-rcu.sh :$builddir: Not a writable directory, cannot build into it" | ||
55 | exit 1 | ||
56 | fi | ||
57 | resdir=${3} | ||
58 | if test -z "$resdir" -o ! -d "$resdir" -o ! -w "$resdir" | ||
59 | then | ||
60 | echo "kvm-test-1-rcu.sh :$resdir: Not a writable directory, cannot build into it" | ||
61 | exit 1 | ||
62 | fi | ||
63 | cp $config_template $resdir/ConfigFragment | ||
64 | echo ' ---' `date`: Starting build | ||
65 | echo ' ---' Kconfig fragment at: $config_template >> $resdir/log | ||
66 | cat << '___EOF___' >> $T | ||
67 | CONFIG_RCU_TORTURE_TEST=y | ||
68 | ___EOF___ | ||
69 | # Optimizations below this point | ||
70 | # CONFIG_USB=n | ||
71 | # CONFIG_SECURITY=n | ||
72 | # CONFIG_NFS_FS=n | ||
73 | # CONFIG_SOUND=n | ||
74 | # CONFIG_INPUT_JOYSTICK=n | ||
75 | # CONFIG_INPUT_TABLET=n | ||
76 | # CONFIG_INPUT_TOUCHSCREEN=n | ||
77 | # CONFIG_INPUT_MISC=n | ||
78 | # CONFIG_INPUT_MOUSE=n | ||
79 | # # CONFIG_NET=n # disables console access, so accept the slower build. | ||
80 | # CONFIG_SCSI=n | ||
81 | # CONFIG_ATA=n | ||
82 | # CONFIG_FAT_FS=n | ||
83 | # CONFIG_MSDOS_FS=n | ||
84 | # CONFIG_VFAT_FS=n | ||
85 | # CONFIG_ISO9660_FS=n | ||
86 | # CONFIG_QUOTA=n | ||
87 | # CONFIG_HID=n | ||
88 | # CONFIG_CRYPTO=n | ||
89 | # CONFIG_PCCARD=n | ||
90 | # CONFIG_PCMCIA=n | ||
91 | # CONFIG_CARDBUS=n | ||
92 | # CONFIG_YENTA=n | ||
93 | if kvm-build.sh $config_template $builddir $T | ||
94 | then | ||
95 | cp $builddir/Make*.out $resdir | ||
96 | cp $builddir/.config $resdir | ||
97 | cp $builddir/arch/x86/boot/bzImage $resdir | ||
98 | parse-build.sh $resdir/Make.out $title | ||
99 | else | ||
100 | cp $builddir/Make*.out $resdir | ||
101 | echo Build failed, not running KVM, see $resdir. | ||
102 | exit 1 | ||
103 | fi | ||
104 | minutes=$4 | ||
105 | seconds=$(($minutes * 60)) | ||
106 | qemu_args=$5 | ||
107 | boot_args=$6 | ||
108 | |||
109 | cd $KVM | ||
110 | kstarttime=`awk 'BEGIN { print systime() }' < /dev/null` | ||
111 | echo ' ---' `date`: Starting kernel | ||
112 | |||
113 | # Determine the appropriate flavor of qemu command. | ||
114 | QEMU="`identify_qemu $builddir/vmlinux.o`" | ||
115 | |||
116 | # Generate -smp qemu argument. | ||
117 | cpu_count=`configNR_CPUS.sh $config_template` | ||
118 | vcpus=`identify_qemu_vcpus` | ||
119 | if test $cpu_count -gt $vcpus | ||
120 | then | ||
121 | echo CPU count limited from $cpu_count to $vcpus | ||
122 | touch $resdir/Warnings | ||
123 | echo CPU count limited from $cpu_count to $vcpus >> $resdir/Warnings | ||
124 | cpu_count=$vcpus | ||
125 | fi | ||
126 | qemu_args="`specify_qemu_cpus "$QEMU" "$qemu_args" "$cpu_count"`" | ||
127 | |||
128 | # Generate architecture-specific and interaction-specific qemu arguments | ||
129 | qemu_args="$qemu_args `identify_qemu_args "$QEMU" "$builddir/console.log"`" | ||
130 | |||
131 | # Generate qemu -append arguments | ||
132 | qemu_append="`identify_qemu_append "$QEMU"`" | ||
133 | |||
134 | # Pull in Kconfig-fragment boot parameters | ||
135 | boot_args="`configfrag_boot_params "$boot_args" "$config_template"`" | ||
136 | # Generate CPU-hotplug boot parameters | ||
137 | boot_args="`rcutorture_param_onoff "$boot_args" $builddir/.config`" | ||
138 | # Generate rcu_barrier() boot parameter | ||
139 | boot_args="`rcutorture_param_n_barrier_cbs "$boot_args"`" | ||
140 | # Pull in standard rcutorture boot arguments | ||
141 | boot_args="$boot_args rcutorture.stat_interval=15 rcutorture.shutdown_secs=$seconds rcutorture.rcutorture_runnable=1" | ||
142 | |||
143 | echo $QEMU $qemu_args -m 512 -kernel $builddir/arch/x86/boot/bzImage -append \"$qemu_append $boot_args\" > $resdir/qemu-cmd | ||
144 | if test -n "$RCU_BUILDONLY" | ||
145 | then | ||
146 | echo Build-only run specified, boot/test omitted. | ||
147 | exit 0 | ||
148 | fi | ||
149 | $QEMU $qemu_args -m 512 -kernel $builddir/arch/x86/boot/bzImage -append "$qemu_append $boot_args" & | ||
150 | qemu_pid=$! | ||
151 | commandcompleted=0 | ||
152 | echo Monitoring qemu job at pid $qemu_pid | ||
153 | for ((i=0;i<$seconds;i++)) | ||
154 | do | ||
155 | if kill -0 $qemu_pid > /dev/null 2>&1 | ||
156 | then | ||
157 | sleep 1 | ||
158 | else | ||
159 | commandcompleted=1 | ||
160 | kruntime=`awk 'BEGIN { print systime() - '"$kstarttime"' }' < /dev/null` | ||
161 | if test $kruntime -lt $seconds | ||
162 | then | ||
163 | echo Completed in $kruntime vs. $seconds >> $resdir/Warnings 2>&1 | ||
164 | else | ||
165 | echo ' ---' `date`: Kernel done | ||
166 | fi | ||
167 | break | ||
168 | fi | ||
169 | done | ||
170 | if test $commandcompleted -eq 0 | ||
171 | then | ||
172 | echo Grace period for qemu job at pid $qemu_pid | ||
173 | for ((i=0;i<=$grace;i++)) | ||
174 | do | ||
175 | if kill -0 $qemu_pid > /dev/null 2>&1 | ||
176 | then | ||
177 | sleep 1 | ||
178 | else | ||
179 | break | ||
180 | fi | ||
181 | if test $i -eq $grace | ||
182 | then | ||
183 | kruntime=`awk 'BEGIN { print systime() - '"$kstarttime"' }'` | ||
184 | echo "!!! Hang at $kruntime vs. $seconds seconds" >> $resdir/Warnings 2>&1 | ||
185 | kill -KILL $qemu_pid | ||
186 | fi | ||
187 | done | ||
188 | fi | ||
189 | |||
190 | cp $builddir/console.log $resdir | ||
191 | parse-rcutorture.sh $resdir/console.log $title | ||
192 | parse-console.sh $resdir/console.log $title | ||
diff --git a/tools/testing/selftests/rcutorture/bin/kvm.sh b/tools/testing/selftests/rcutorture/bin/kvm.sh new file mode 100644 index 000000000000..1b7923bf6a70 --- /dev/null +++ b/tools/testing/selftests/rcutorture/bin/kvm.sh | |||
@@ -0,0 +1,210 @@ | |||
1 | #!/bin/bash | ||
2 | # | ||
3 | # Run a series of 14 tests under KVM. These are not particularly | ||
4 | # well-selected or well-tuned, but are the current set. Run from the | ||
5 | # top level of the source tree. | ||
6 | # | ||
7 | # Edit the definitions below to set the locations of the various directories, | ||
8 | # as well as the test duration. | ||
9 | # | ||
10 | # Usage: sh kvm.sh [ options ] | ||
11 | # | ||
12 | # This program is free software; you can redistribute it and/or modify | ||
13 | # it under the terms of the GNU General Public License as published by | ||
14 | # the Free Software Foundation; either version 2 of the License, or | ||
15 | # (at your option) any later version. | ||
16 | # | ||
17 | # This program is distributed in the hope that it will be useful, | ||
18 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
19 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
20 | # GNU General Public License for more details. | ||
21 | # | ||
22 | # You should have received a copy of the GNU General Public License | ||
23 | # along with this program; if not, you can access it online at | ||
24 | # http://www.gnu.org/licenses/gpl-2.0.html. | ||
25 | # | ||
26 | # Copyright (C) IBM Corporation, 2011 | ||
27 | # | ||
28 | # Authors: Paul E. McKenney <paulmck@linux.vnet.ibm.com> | ||
29 | |||
30 | scriptname=$0 | ||
31 | args="$*" | ||
32 | |||
33 | dur=30 | ||
34 | KVM="`pwd`/tools/testing/selftests/rcutorture"; export KVM | ||
35 | PATH=${KVM}/bin:$PATH; export PATH | ||
36 | builddir="${KVM}/b1" | ||
37 | RCU_INITRD="$KVM/initrd"; export RCU_INITRD | ||
38 | RCU_KMAKE_ARG=""; export RCU_KMAKE_ARG | ||
39 | resdir="" | ||
40 | configs="" | ||
41 | ds=`date +%Y.%m.%d-%H:%M:%S` | ||
42 | kversion="" | ||
43 | |||
44 | . functions.sh | ||
45 | |||
46 | usage () { | ||
47 | echo "Usage: $scriptname optional arguments:" | ||
48 | echo " --bootargs kernel-boot-arguments" | ||
49 | echo " --builddir absolute-pathname" | ||
50 | echo " --buildonly" | ||
51 | echo " --configs \"config-file list\"" | ||
52 | echo " --datestamp string" | ||
53 | echo " --duration minutes" | ||
54 | echo " --interactive" | ||
55 | echo " --kmake-arg kernel-make-arguments" | ||
56 | echo " --kversion vN.NN" | ||
57 | echo " --mac nn:nn:nn:nn:nn:nn" | ||
58 | echo " --no-initrd" | ||
59 | echo " --qemu-args qemu-system-..." | ||
60 | echo " --qemu-cmd qemu-system-..." | ||
61 | echo " --results absolute-pathname" | ||
62 | echo " --relbuilddir relative-pathname" | ||
63 | exit 1 | ||
64 | } | ||
65 | |||
66 | while test $# -gt 0 | ||
67 | do | ||
68 | case "$1" in | ||
69 | --bootargs) | ||
70 | checkarg --bootargs "(list of kernel boot arguments)" "$#" "$2" '.*' '^--' | ||
71 | RCU_BOOTARGS="$2" | ||
72 | shift | ||
73 | ;; | ||
74 | --builddir) | ||
75 | checkarg --builddir "(absolute pathname)" "$#" "$2" '^/' '^error' | ||
76 | builddir=$2 | ||
77 | gotbuilddir=1 | ||
78 | shift | ||
79 | ;; | ||
80 | --buildonly) | ||
81 | RCU_BUILDONLY=1; export RCU_BUILDONLY | ||
82 | ;; | ||
83 | --configs) | ||
84 | checkarg --configs "(list of config files)" "$#" "$2" '^[^/]*$' '^--' | ||
85 | configs="$2" | ||
86 | shift | ||
87 | ;; | ||
88 | --datestamp) | ||
89 | checkarg --datestamp "(relative pathname)" "$#" "$2" '^[^/]*$' '^--' | ||
90 | ds=$2 | ||
91 | shift | ||
92 | ;; | ||
93 | --duration) | ||
94 | checkarg --duration "(minutes)" $# "$2" '^[0-9]*$' '^error' | ||
95 | dur=$2 | ||
96 | shift | ||
97 | ;; | ||
98 | --interactive) | ||
99 | RCU_QEMU_INTERACTIVE=1; export RCU_QEMU_INTERACTIVE | ||
100 | ;; | ||
101 | --kmake-arg) | ||
102 | checkarg --kmake-arg "(kernel make arguments)" $# "$2" '.*' '^error$' | ||
103 | RCU_KMAKE_ARG="$2"; export RCU_KMAKE_ARG | ||
104 | shift | ||
105 | ;; | ||
106 | --kversion) | ||
107 | checkarg --kversion "(kernel version)" $# "$2" '^v[0-9.]*$' '^error' | ||
108 | kversion=$2 | ||
109 | shift | ||
110 | ;; | ||
111 | --mac) | ||
112 | checkarg --mac "(MAC address)" $# "$2" '^\([0-9a-fA-F]\{2\}:\)\{5\}[0-9a-fA-F]\{2\}$' error | ||
113 | RCU_QEMU_MAC=$2; export RCU_QEMU_MAC | ||
114 | shift | ||
115 | ;; | ||
116 | --no-initrd) | ||
117 | RCU_INITRD=""; export RCU_INITRD | ||
118 | ;; | ||
119 | --qemu-args) | ||
120 | checkarg --qemu-args "-qemu args" $# "$2" '^-' '^error' | ||
121 | RCU_QEMU_ARG="$2" | ||
122 | shift | ||
123 | ;; | ||
124 | --qemu-cmd) | ||
125 | checkarg --qemu-cmd "(qemu-system-...)" $# "$2" 'qemu-system-' '^--' | ||
126 | RCU_QEMU_CMD="$2"; export RCU_QEMU_CMD | ||
127 | shift | ||
128 | ;; | ||
129 | --relbuilddir) | ||
130 | checkarg --relbuilddir "(relative pathname)" "$#" "$2" '^[^/]*$' '^--' | ||
131 | relbuilddir=$2 | ||
132 | gotrelbuilddir=1 | ||
133 | builddir=${KVM}/${relbuilddir} | ||
134 | shift | ||
135 | ;; | ||
136 | --results) | ||
137 | checkarg --results "(absolute pathname)" "$#" "$2" '^/' '^error' | ||
138 | resdir=$2 | ||
139 | shift | ||
140 | ;; | ||
141 | *) | ||
142 | echo Unknown argument $1 | ||
143 | usage | ||
144 | ;; | ||
145 | esac | ||
146 | shift | ||
147 | done | ||
148 | |||
149 | CONFIGFRAG=${KVM}/configs; export CONFIGFRAG | ||
150 | KVPATH=${CONFIGFRAG}/$kversion; export KVPATH | ||
151 | |||
152 | if test -z "$configs" | ||
153 | then | ||
154 | configs="`cat $CONFIGFRAG/$kversion/CFLIST`" | ||
155 | fi | ||
156 | |||
157 | if test -z "$resdir" | ||
158 | then | ||
159 | resdir=$KVM/res | ||
160 | if ! test -e $resdir | ||
161 | then | ||
162 | mkdir $resdir || : | ||
163 | fi | ||
164 | else | ||
165 | if ! test -e $resdir | ||
166 | then | ||
167 | mkdir -p "$resdir" || : | ||
168 | fi | ||
169 | fi | ||
170 | mkdir $resdir/$ds | ||
171 | touch $resdir/$ds/log | ||
172 | echo $scriptname $args >> $resdir/$ds/log | ||
173 | |||
174 | pwd > $resdir/$ds/testid.txt | ||
175 | if test -d .git | ||
176 | then | ||
177 | git status >> $resdir/$ds/testid.txt | ||
178 | git rev-parse HEAD >> $resdir/$ds/testid.txt | ||
179 | fi | ||
180 | builddir=$KVM/b1 | ||
181 | if ! test -e $builddir | ||
182 | then | ||
183 | mkdir $builddir || : | ||
184 | fi | ||
185 | |||
186 | for CF in $configs | ||
187 | do | ||
188 | # Running TREE01 multiple times creates TREE01, TREE01.2, TREE01.3, ... | ||
189 | rd=$resdir/$ds/$CF | ||
190 | if test -d "${rd}" | ||
191 | then | ||
192 | n="`ls -d "${rd}"* | grep '\.[0-9]\+$' | | ||
193 | sed -e 's/^.*\.\([0-9]\+\)/\1/' | | ||
194 | sort -k1n | tail -1`" | ||
195 | if test -z "$n" | ||
196 | then | ||
197 | rd="${rd}.2" | ||
198 | else | ||
199 | n="`expr $n + 1`" | ||
200 | rd="${rd}.${n}" | ||
201 | fi | ||
202 | fi | ||
203 | mkdir "${rd}" | ||
204 | echo Results directory: $rd | ||
205 | kvm-test-1-rcu.sh $CONFIGFRAG/$kversion/$CF $builddir $rd $dur "-nographic $RCU_QEMU_ARG" "rcutorture.test_no_idle_hz=1 rcutorture.verbose=1 $RCU_BOOTARGS" | ||
206 | done | ||
207 | # Tracing: trace_event=rcu:rcu_grace_period,rcu:rcu_future_grace_period,rcu:rcu_grace_period_init,rcu:rcu_nocb_wake,rcu:rcu_preempt_task,rcu:rcu_unlock_preempted_task,rcu:rcu_quiescent_state_report,rcu:rcu_fqs,rcu:rcu_callback,rcu:rcu_kfree_callback,rcu:rcu_batch_start,rcu:rcu_invoke_callback,rcu:rcu_invoke_kfree_callback,rcu:rcu_batch_end,rcu:rcu_torture_read,rcu:rcu_barrier | ||
208 | |||
209 | echo " --- `date` Test summary:" | ||
210 | kvm-recheck.sh $resdir/$ds | ||
diff --git a/tools/testing/selftests/rcutorture/bin/parse-build.sh b/tools/testing/selftests/rcutorture/bin/parse-build.sh new file mode 100755 index 000000000000..543230951c38 --- /dev/null +++ b/tools/testing/selftests/rcutorture/bin/parse-build.sh | |||
@@ -0,0 +1,57 @@ | |||
1 | #!/bin/sh | ||
2 | # | ||
3 | # Check the build output from an rcutorture run for goodness. | ||
4 | # The "file" is a pathname on the local system, and "title" is | ||
5 | # a text string for error-message purposes. | ||
6 | # | ||
7 | # The file must contain kernel build output. | ||
8 | # | ||
9 | # Usage: | ||
10 | # sh parse-build.sh file title | ||
11 | # | ||
12 | # This program is free software; you can redistribute it and/or modify | ||
13 | # it under the terms of the GNU General Public License as published by | ||
14 | # the Free Software Foundation; either version 2 of the License, or | ||
15 | # (at your option) any later version. | ||
16 | # | ||
17 | # This program is distributed in the hope that it will be useful, | ||
18 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
19 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
20 | # GNU General Public License for more details. | ||
21 | # | ||
22 | # You should have received a copy of the GNU General Public License | ||
23 | # along with this program; if not, you can access it online at | ||
24 | # http://www.gnu.org/licenses/gpl-2.0.html. | ||
25 | # | ||
26 | # Copyright (C) IBM Corporation, 2011 | ||
27 | # | ||
28 | # Authors: Paul E. McKenney <paulmck@linux.vnet.ibm.com> | ||
29 | |||
30 | T=$1 | ||
31 | title=$2 | ||
32 | |||
33 | . functions.sh | ||
34 | |||
35 | if grep -q CC < $T | ||
36 | then | ||
37 | : | ||
38 | else | ||
39 | print_bug $title no build | ||
40 | exit 1 | ||
41 | fi | ||
42 | |||
43 | if grep -q "error:" < $T | ||
44 | then | ||
45 | print_bug $title build errors: | ||
46 | grep "error:" < $T | ||
47 | exit 2 | ||
48 | fi | ||
49 | exit 0 | ||
50 | |||
51 | if egrep -q "rcu[^/]*\.c.*warning:|rcu.*\.h.*warning:" < $T | ||
52 | then | ||
53 | print_warning $title build errors: | ||
54 | egrep "rcu[^/]*\.c.*warning:|rcu.*\.h.*warning:" < $T | ||
55 | exit 2 | ||
56 | fi | ||
57 | exit 0 | ||
diff --git a/tools/testing/selftests/rcutorture/bin/parse-console.sh b/tools/testing/selftests/rcutorture/bin/parse-console.sh new file mode 100755 index 000000000000..4185d4cab32e --- /dev/null +++ b/tools/testing/selftests/rcutorture/bin/parse-console.sh | |||
@@ -0,0 +1,41 @@ | |||
1 | #!/bin/sh | ||
2 | # | ||
3 | # Check the console output from an rcutorture run for oopses. | ||
4 | # The "file" is a pathname on the local system, and "title" is | ||
5 | # a text string for error-message purposes. | ||
6 | # | ||
7 | # Usage: | ||
8 | # sh parse-console.sh file title | ||
9 | # | ||
10 | # This program is free software; you can redistribute it and/or modify | ||
11 | # it under the terms of the GNU General Public License as published by | ||
12 | # the Free Software Foundation; either version 2 of the License, or | ||
13 | # (at your option) any later version. | ||
14 | # | ||
15 | # This program is distributed in the hope that it will be useful, | ||
16 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
17 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
18 | # GNU General Public License for more details. | ||
19 | # | ||
20 | # You should have received a copy of the GNU General Public License | ||
21 | # along with this program; if not, you can access it online at | ||
22 | # http://www.gnu.org/licenses/gpl-2.0.html. | ||
23 | # | ||
24 | # Copyright (C) IBM Corporation, 2011 | ||
25 | # | ||
26 | # Authors: Paul E. McKenney <paulmck@linux.vnet.ibm.com> | ||
27 | |||
28 | T=/tmp/abat-chk-badness.sh.$$ | ||
29 | trap 'rm -f $T' 0 | ||
30 | |||
31 | file="$1" | ||
32 | title="$2" | ||
33 | |||
34 | . functions.sh | ||
35 | |||
36 | egrep 'Badness|WARNING:|Warn|BUG|===========|Call Trace:|Oops:' < $file | grep -v 'ODEBUG: ' | grep -v 'Warning: unable to open an initial console' > $T | ||
37 | if test -s $T | ||
38 | then | ||
39 | print_warning Assertion failure in $file $title | ||
40 | cat $T | ||
41 | fi | ||
diff --git a/tools/testing/selftests/rcutorture/bin/parse-rcutorture.sh b/tools/testing/selftests/rcutorture/bin/parse-rcutorture.sh new file mode 100755 index 000000000000..dd0a275d9796 --- /dev/null +++ b/tools/testing/selftests/rcutorture/bin/parse-rcutorture.sh | |||
@@ -0,0 +1,106 @@ | |||
1 | #!/bin/sh | ||
2 | # | ||
3 | # Check the console output from an rcutorture run for goodness. | ||
4 | # The "file" is a pathname on the local system, and "title" is | ||
5 | # a text string for error-message purposes. | ||
6 | # | ||
7 | # The file must contain rcutorture output, but can be interspersed | ||
8 | # with other dmesg text. | ||
9 | # | ||
10 | # Usage: | ||
11 | # sh parse-rcutorture.sh file title | ||
12 | # | ||
13 | # This program is free software; you can redistribute it and/or modify | ||
14 | # it under the terms of the GNU General Public License as published by | ||
15 | # the Free Software Foundation; either version 2 of the License, or | ||
16 | # (at your option) any later version. | ||
17 | # | ||
18 | # This program is distributed in the hope that it will be useful, | ||
19 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
20 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
21 | # GNU General Public License for more details. | ||
22 | # | ||
23 | # You should have received a copy of the GNU General Public License | ||
24 | # along with this program; if not, you can access it online at | ||
25 | # http://www.gnu.org/licenses/gpl-2.0.html. | ||
26 | # | ||
27 | # Copyright (C) IBM Corporation, 2011 | ||
28 | # | ||
29 | # Authors: Paul E. McKenney <paulmck@linux.vnet.ibm.com> | ||
30 | |||
31 | T=/tmp/parse-rcutorture.sh.$$ | ||
32 | file="$1" | ||
33 | title="$2" | ||
34 | |||
35 | trap 'rm -f $T.seq' 0 | ||
36 | |||
37 | . functions.sh | ||
38 | |||
39 | # check for presence of rcutorture.txt file | ||
40 | |||
41 | if test -f "$file" -a -r "$file" | ||
42 | then | ||
43 | : | ||
44 | else | ||
45 | echo $title unreadable rcutorture.txt file: $file | ||
46 | exit 1 | ||
47 | fi | ||
48 | |||
49 | # check for abject failure | ||
50 | |||
51 | if grep -q FAILURE $file || grep -q -e '-torture.*!!!' $file | ||
52 | then | ||
53 | nerrs=`grep --binary-files=text '!!!' $file | tail -1 | awk '{for (i=NF-8;i<=NF;i++) sum+=$i; } END {print sum}'` | ||
54 | print_bug $title FAILURE, $nerrs instances | ||
55 | echo " " $url | ||
56 | exit | ||
57 | fi | ||
58 | |||
59 | grep --binary-files=text 'torture:.*ver:' $file | grep --binary-files=text -v '(null)' | sed -e 's/^(initramfs)[^]]*] //' -e 's/^\[[^]]*] //' | | ||
60 | awk ' | ||
61 | BEGIN { | ||
62 | ver = 0; | ||
63 | badseq = 0; | ||
64 | } | ||
65 | |||
66 | { | ||
67 | if (!badseq && ($5 + 0 != $5 || $5 <= ver)) { | ||
68 | badseqno1 = ver; | ||
69 | badseqno2 = $5; | ||
70 | badseqnr = NR; | ||
71 | badseq = 1; | ||
72 | } | ||
73 | ver = $5 | ||
74 | } | ||
75 | |||
76 | END { | ||
77 | if (badseq) { | ||
78 | if (badseqno1 == badseqno2 && badseqno2 == ver) | ||
79 | print "RCU GP HANG at " ver " rcutorture stat " badseqnr; | ||
80 | else | ||
81 | print "BAD SEQ " badseqno1 ":" badseqno2 " last:" ver " RCU version " badseqnr; | ||
82 | } | ||
83 | }' > $T.seq | ||
84 | |||
85 | if grep -q SUCCESS $file | ||
86 | then | ||
87 | if test -s $T.seq | ||
88 | then | ||
89 | print_warning $title $title `cat $T.seq` | ||
90 | echo " " $file | ||
91 | exit 2 | ||
92 | fi | ||
93 | else | ||
94 | if grep -q RCU_HOTPLUG $file | ||
95 | then | ||
96 | print_warning HOTPLUG FAILURES $title `cat $T.seq` | ||
97 | echo " " $file | ||
98 | exit 3 | ||
99 | fi | ||
100 | echo $title no success message, `grep --binary-files=text 'ver:' $file | wc -l` successful RCU version messages | ||
101 | if test -s $T.seq | ||
102 | then | ||
103 | print_warning $title `cat $T.seq` | ||
104 | fi | ||
105 | exit 2 | ||
106 | fi | ||
diff --git a/tools/testing/selftests/rcutorture/configs/CFLIST b/tools/testing/selftests/rcutorture/configs/CFLIST new file mode 100644 index 000000000000..cd3d29cb0a47 --- /dev/null +++ b/tools/testing/selftests/rcutorture/configs/CFLIST | |||
@@ -0,0 +1,13 @@ | |||
1 | TREE01 | ||
2 | TREE02 | ||
3 | TREE03 | ||
4 | TREE04 | ||
5 | TREE05 | ||
6 | TREE06 | ||
7 | TREE07 | ||
8 | TREE08 | ||
9 | TREE09 | ||
10 | SRCU-N | ||
11 | SRCU-P | ||
12 | TINY01 | ||
13 | TINY02 | ||
diff --git a/tools/testing/selftests/rcutorture/configs/SRCU-N b/tools/testing/selftests/rcutorture/configs/SRCU-N new file mode 100644 index 000000000000..10a0e27f4c75 --- /dev/null +++ b/tools/testing/selftests/rcutorture/configs/SRCU-N | |||
@@ -0,0 +1,8 @@ | |||
1 | CONFIG_RCU_TRACE=n | ||
2 | CONFIG_SMP=y | ||
3 | CONFIG_NR_CPUS=8 | ||
4 | CONFIG_HOTPLUG_CPU=y | ||
5 | CONFIG_PREEMPT_NONE=y | ||
6 | CONFIG_PREEMPT_VOLUNTARY=n | ||
7 | CONFIG_PREEMPT=n | ||
8 | CONFIG_PRINTK_TIME=y | ||
diff --git a/tools/testing/selftests/rcutorture/configs/SRCU-N.boot b/tools/testing/selftests/rcutorture/configs/SRCU-N.boot new file mode 100644 index 000000000000..238bfe3bd0cc --- /dev/null +++ b/tools/testing/selftests/rcutorture/configs/SRCU-N.boot | |||
@@ -0,0 +1 @@ | |||
rcutorture.torture_type=srcu | |||
diff --git a/tools/testing/selftests/rcutorture/configs/SRCU-P b/tools/testing/selftests/rcutorture/configs/SRCU-P new file mode 100644 index 000000000000..6650e00c6d91 --- /dev/null +++ b/tools/testing/selftests/rcutorture/configs/SRCU-P | |||
@@ -0,0 +1,8 @@ | |||
1 | CONFIG_RCU_TRACE=n | ||
2 | CONFIG_SMP=y | ||
3 | CONFIG_NR_CPUS=8 | ||
4 | CONFIG_HOTPLUG_CPU=y | ||
5 | CONFIG_PREEMPT_NONE=n | ||
6 | CONFIG_PREEMPT_VOLUNTARY=n | ||
7 | CONFIG_PREEMPT=y | ||
8 | CONFIG_PRINTK_TIME=y | ||
diff --git a/tools/testing/selftests/rcutorture/configs/SRCU-P.boot b/tools/testing/selftests/rcutorture/configs/SRCU-P.boot new file mode 100644 index 000000000000..238bfe3bd0cc --- /dev/null +++ b/tools/testing/selftests/rcutorture/configs/SRCU-P.boot | |||
@@ -0,0 +1 @@ | |||
rcutorture.torture_type=srcu | |||
diff --git a/tools/testing/selftests/rcutorture/configs/TINY01 b/tools/testing/selftests/rcutorture/configs/TINY01 new file mode 100644 index 000000000000..0c2823f21712 --- /dev/null +++ b/tools/testing/selftests/rcutorture/configs/TINY01 | |||
@@ -0,0 +1,13 @@ | |||
1 | CONFIG_SMP=n | ||
2 | CONFIG_PREEMPT_NONE=y | ||
3 | CONFIG_PREEMPT_VOLUNTARY=n | ||
4 | CONFIG_PREEMPT=n | ||
5 | #CHECK#CONFIG_TINY_RCU=y | ||
6 | CONFIG_HZ_PERIODIC=n | ||
7 | CONFIG_NO_HZ_IDLE=y | ||
8 | CONFIG_NO_HZ_FULL=n | ||
9 | CONFIG_RCU_TRACE=n | ||
10 | CONFIG_DEBUG_LOCK_ALLOC=n | ||
11 | CONFIG_DEBUG_OBJECTS_RCU_HEAD=n | ||
12 | CONFIG_PREEMPT_COUNT=n | ||
13 | CONFIG_PRINTK_TIME=y | ||
diff --git a/tools/testing/selftests/rcutorture/configs/TINY02 b/tools/testing/selftests/rcutorture/configs/TINY02 new file mode 100644 index 000000000000..e5072d7528b6 --- /dev/null +++ b/tools/testing/selftests/rcutorture/configs/TINY02 | |||
@@ -0,0 +1,13 @@ | |||
1 | CONFIG_SMP=n | ||
2 | CONFIG_PREEMPT_NONE=y | ||
3 | CONFIG_PREEMPT_VOLUNTARY=n | ||
4 | CONFIG_PREEMPT=n | ||
5 | #CHECK#CONFIG_TINY_RCU=y | ||
6 | CONFIG_HZ_PERIODIC=y | ||
7 | CONFIG_NO_HZ_IDLE=n | ||
8 | CONFIG_NO_HZ_FULL=n | ||
9 | CONFIG_RCU_TRACE=y | ||
10 | CONFIG_DEBUG_LOCK_ALLOC=y | ||
11 | CONFIG_DEBUG_OBJECTS_RCU_HEAD=n | ||
12 | CONFIG_PREEMPT_COUNT=y | ||
13 | CONFIG_PRINTK_TIME=y | ||
diff --git a/tools/testing/selftests/rcutorture/configs/TREE01 b/tools/testing/selftests/rcutorture/configs/TREE01 new file mode 100644 index 000000000000..141119a00044 --- /dev/null +++ b/tools/testing/selftests/rcutorture/configs/TREE01 | |||
@@ -0,0 +1,23 @@ | |||
1 | CONFIG_SMP=y | ||
2 | CONFIG_NR_CPUS=8 | ||
3 | CONFIG_PREEMPT_NONE=n | ||
4 | CONFIG_PREEMPT_VOLUNTARY=n | ||
5 | CONFIG_PREEMPT=y | ||
6 | #CHECK#CONFIG_TREE_PREEMPT_RCU=y | ||
7 | CONFIG_HZ_PERIODIC=n | ||
8 | CONFIG_NO_HZ_IDLE=y | ||
9 | CONFIG_NO_HZ_FULL=n | ||
10 | CONFIG_RCU_FAST_NO_HZ=y | ||
11 | CONFIG_RCU_TRACE=y | ||
12 | CONFIG_HOTPLUG_CPU=y | ||
13 | CONFIG_RCU_FANOUT=8 | ||
14 | CONFIG_RCU_FANOUT_EXACT=n | ||
15 | CONFIG_RCU_NOCB_CPU=y | ||
16 | CONFIG_RCU_NOCB_CPU_ZERO=y | ||
17 | CONFIG_DEBUG_LOCK_ALLOC=n | ||
18 | CONFIG_PROVE_RCU_DELAY=n | ||
19 | CONFIG_RCU_CPU_STALL_INFO=n | ||
20 | CONFIG_RCU_CPU_STALL_VERBOSE=n | ||
21 | CONFIG_RCU_BOOST=n | ||
22 | CONFIG_DEBUG_OBJECTS_RCU_HEAD=n | ||
23 | CONFIG_PRINTK_TIME=y | ||
diff --git a/tools/testing/selftests/rcutorture/configs/TREE01.boot b/tools/testing/selftests/rcutorture/configs/TREE01.boot new file mode 100644 index 000000000000..0fc8a3428938 --- /dev/null +++ b/tools/testing/selftests/rcutorture/configs/TREE01.boot | |||
@@ -0,0 +1 @@ | |||
rcutorture.torture_type=rcu_bh | |||
diff --git a/tools/testing/selftests/rcutorture/configs/TREE02 b/tools/testing/selftests/rcutorture/configs/TREE02 new file mode 100644 index 000000000000..2d4d09608528 --- /dev/null +++ b/tools/testing/selftests/rcutorture/configs/TREE02 | |||
@@ -0,0 +1,26 @@ | |||
1 | CONFIG_SMP=y | ||
2 | CONFIG_NR_CPUS=8 | ||
3 | CONFIG_PREEMPT_NONE=n | ||
4 | CONFIG_PREEMPT_VOLUNTARY=n | ||
5 | CONFIG_PREEMPT=y | ||
6 | #CHECK#CONFIG_TREE_PREEMPT_RCU=y | ||
7 | CONFIG_HZ_PERIODIC=n | ||
8 | CONFIG_NO_HZ_IDLE=y | ||
9 | CONFIG_NO_HZ_FULL=n | ||
10 | CONFIG_RCU_FAST_NO_HZ=n | ||
11 | CONFIG_RCU_TRACE=n | ||
12 | CONFIG_HOTPLUG_CPU=n | ||
13 | CONFIG_SUSPEND=n | ||
14 | CONFIG_HIBERNATION=n | ||
15 | CONFIG_RCU_FANOUT=3 | ||
16 | CONFIG_RCU_FANOUT_LEAF=3 | ||
17 | CONFIG_RCU_FANOUT_EXACT=n | ||
18 | CONFIG_RCU_NOCB_CPU=n | ||
19 | CONFIG_DEBUG_LOCK_ALLOC=y | ||
20 | CONFIG_PROVE_LOCKING=n | ||
21 | CONFIG_PROVE_RCU_DELAY=n | ||
22 | CONFIG_RCU_CPU_STALL_INFO=n | ||
23 | CONFIG_RCU_CPU_STALL_VERBOSE=y | ||
24 | CONFIG_RCU_BOOST=n | ||
25 | CONFIG_DEBUG_OBJECTS_RCU_HEAD=n | ||
26 | CONFIG_PRINTK_TIME=y | ||
diff --git a/tools/testing/selftests/rcutorture/configs/TREE03 b/tools/testing/selftests/rcutorture/configs/TREE03 new file mode 100644 index 000000000000..a47de5be8a04 --- /dev/null +++ b/tools/testing/selftests/rcutorture/configs/TREE03 | |||
@@ -0,0 +1,23 @@ | |||
1 | CONFIG_SMP=y | ||
2 | CONFIG_NR_CPUS=8 | ||
3 | CONFIG_PREEMPT_NONE=n | ||
4 | CONFIG_PREEMPT_VOLUNTARY=n | ||
5 | CONFIG_PREEMPT=y | ||
6 | #CHECK#CONFIG_TREE_PREEMPT_RCU=y | ||
7 | CONFIG_HZ_PERIODIC=y | ||
8 | CONFIG_NO_HZ_IDLE=n | ||
9 | CONFIG_NO_HZ_FULL=n | ||
10 | CONFIG_RCU_TRACE=y | ||
11 | CONFIG_HOTPLUG_CPU=y | ||
12 | CONFIG_RCU_FANOUT=4 | ||
13 | CONFIG_RCU_FANOUT_LEAF=4 | ||
14 | CONFIG_RCU_FANOUT_EXACT=n | ||
15 | CONFIG_RCU_NOCB_CPU=n | ||
16 | CONFIG_DEBUG_LOCK_ALLOC=n | ||
17 | CONFIG_PROVE_RCU_DELAY=n | ||
18 | CONFIG_RCU_CPU_STALL_INFO=n | ||
19 | CONFIG_RCU_CPU_STALL_VERBOSE=n | ||
20 | CONFIG_RCU_BOOST=y | ||
21 | CONFIG_RCU_BOOST_PRIO=2 | ||
22 | CONFIG_DEBUG_OBJECTS_RCU_HEAD=n | ||
23 | CONFIG_PRINTK_TIME=y | ||
diff --git a/tools/testing/selftests/rcutorture/configs/TREE04 b/tools/testing/selftests/rcutorture/configs/TREE04 new file mode 100644 index 000000000000..8d839b86a1d5 --- /dev/null +++ b/tools/testing/selftests/rcutorture/configs/TREE04 | |||
@@ -0,0 +1,25 @@ | |||
1 | CONFIG_SMP=y | ||
2 | CONFIG_NR_CPUS=8 | ||
3 | CONFIG_PREEMPT_NONE=y | ||
4 | CONFIG_PREEMPT_VOLUNTARY=n | ||
5 | CONFIG_PREEMPT=n | ||
6 | #CHECK#CONFIG_TREE_RCU=y | ||
7 | CONFIG_HZ_PERIODIC=n | ||
8 | CONFIG_NO_HZ_IDLE=n | ||
9 | CONFIG_NO_HZ_FULL=y | ||
10 | CONFIG_NO_HZ_FULL_ALL=y | ||
11 | CONFIG_RCU_FAST_NO_HZ=y | ||
12 | CONFIG_RCU_TRACE=y | ||
13 | CONFIG_HOTPLUG_CPU=n | ||
14 | CONFIG_SUSPEND=n | ||
15 | CONFIG_HIBERNATION=n | ||
16 | CONFIG_RCU_FANOUT=2 | ||
17 | CONFIG_RCU_FANOUT_LEAF=2 | ||
18 | CONFIG_RCU_FANOUT_EXACT=n | ||
19 | CONFIG_RCU_NOCB_CPU=n | ||
20 | CONFIG_DEBUG_LOCK_ALLOC=n | ||
21 | CONFIG_PROVE_RCU_DELAY=n | ||
22 | CONFIG_RCU_CPU_STALL_INFO=y | ||
23 | CONFIG_RCU_CPU_STALL_VERBOSE=y | ||
24 | CONFIG_DEBUG_OBJECTS_RCU_HEAD=n | ||
25 | CONFIG_PRINTK_TIME=y | ||
diff --git a/tools/testing/selftests/rcutorture/configs/TREE04.boot b/tools/testing/selftests/rcutorture/configs/TREE04.boot new file mode 100644 index 000000000000..0fc8a3428938 --- /dev/null +++ b/tools/testing/selftests/rcutorture/configs/TREE04.boot | |||
@@ -0,0 +1 @@ | |||
rcutorture.torture_type=rcu_bh | |||
diff --git a/tools/testing/selftests/rcutorture/configs/TREE05 b/tools/testing/selftests/rcutorture/configs/TREE05 new file mode 100644 index 000000000000..b5ba72ea25cb --- /dev/null +++ b/tools/testing/selftests/rcutorture/configs/TREE05 | |||
@@ -0,0 +1,25 @@ | |||
1 | CONFIG_SMP=y | ||
2 | CONFIG_NR_CPUS=8 | ||
3 | CONFIG_PREEMPT_NONE=y | ||
4 | CONFIG_PREEMPT_VOLUNTARY=n | ||
5 | CONFIG_PREEMPT=n | ||
6 | #CHECK#CONFIG_TREE_RCU=y | ||
7 | CONFIG_HZ_PERIODIC=n | ||
8 | CONFIG_NO_HZ_IDLE=y | ||
9 | CONFIG_NO_HZ_FULL=n | ||
10 | CONFIG_RCU_FAST_NO_HZ=n | ||
11 | CONFIG_RCU_TRACE=n | ||
12 | CONFIG_HOTPLUG_CPU=y | ||
13 | CONFIG_RCU_FANOUT=6 | ||
14 | CONFIG_RCU_FANOUT_LEAF=6 | ||
15 | CONFIG_RCU_FANOUT_EXACT=n | ||
16 | CONFIG_RCU_NOCB_CPU=y | ||
17 | CONFIG_RCU_NOCB_CPU_NONE=y | ||
18 | CONFIG_DEBUG_LOCK_ALLOC=y | ||
19 | CONFIG_PROVE_LOCKING=y | ||
20 | CONFIG_PROVE_RCU=y | ||
21 | CONFIG_PROVE_RCU_DELAY=y | ||
22 | CONFIG_RCU_CPU_STALL_INFO=n | ||
23 | CONFIG_RCU_CPU_STALL_VERBOSE=n | ||
24 | CONFIG_DEBUG_OBJECTS_RCU_HEAD=n | ||
25 | CONFIG_PRINTK_TIME=y | ||
diff --git a/tools/testing/selftests/rcutorture/configs/TREE05.boot b/tools/testing/selftests/rcutorture/configs/TREE05.boot new file mode 100644 index 000000000000..3b42b8b033cd --- /dev/null +++ b/tools/testing/selftests/rcutorture/configs/TREE05.boot | |||
@@ -0,0 +1 @@ | |||
rcutorture.torture_type=sched | |||
diff --git a/tools/testing/selftests/rcutorture/configs/TREE06 b/tools/testing/selftests/rcutorture/configs/TREE06 new file mode 100644 index 000000000000..7c95ab48d29f --- /dev/null +++ b/tools/testing/selftests/rcutorture/configs/TREE06 | |||
@@ -0,0 +1,26 @@ | |||
1 | CONFIG_SMP=y | ||
2 | CONFIG_NR_CPUS=8 | ||
3 | CONFIG_PREEMPT_NONE=y | ||
4 | CONFIG_PREEMPT_VOLUNTARY=n | ||
5 | CONFIG_PREEMPT=n | ||
6 | #CHECK#CONFIG_TREE_RCU=y | ||
7 | CONFIG_HZ_PERIODIC=n | ||
8 | CONFIG_NO_HZ_IDLE=y | ||
9 | CONFIG_NO_HZ_FULL=n | ||
10 | CONFIG_RCU_FAST_NO_HZ=n | ||
11 | CONFIG_RCU_TRACE=n | ||
12 | CONFIG_HOTPLUG_CPU=n | ||
13 | CONFIG_SUSPEND=n | ||
14 | CONFIG_HIBERNATION=n | ||
15 | CONFIG_RCU_FANOUT=6 | ||
16 | CONFIG_RCU_FANOUT_LEAF=6 | ||
17 | CONFIG_RCU_FANOUT_EXACT=y | ||
18 | CONFIG_RCU_NOCB_CPU=n | ||
19 | CONFIG_DEBUG_LOCK_ALLOC=y | ||
20 | CONFIG_PROVE_LOCKING=y | ||
21 | CONFIG_PROVE_RCU=y | ||
22 | CONFIG_PROVE_RCU_DELAY=n | ||
23 | CONFIG_RCU_CPU_STALL_INFO=n | ||
24 | CONFIG_RCU_CPU_STALL_VERBOSE=n | ||
25 | CONFIG_DEBUG_OBJECTS_RCU_HEAD=y | ||
26 | CONFIG_PRINTK_TIME=y | ||
diff --git a/tools/testing/selftests/rcutorture/configs/TREE07 b/tools/testing/selftests/rcutorture/configs/TREE07 new file mode 100644 index 000000000000..1467404bdec1 --- /dev/null +++ b/tools/testing/selftests/rcutorture/configs/TREE07 | |||
@@ -0,0 +1,24 @@ | |||
1 | CONFIG_SMP=y | ||
2 | CONFIG_NR_CPUS=16 | ||
3 | CONFIG_PREEMPT_NONE=y | ||
4 | CONFIG_PREEMPT_VOLUNTARY=n | ||
5 | CONFIG_PREEMPT=n | ||
6 | #CHECK#CONFIG_TREE_RCU=y | ||
7 | CONFIG_HZ_PERIODIC=n | ||
8 | CONFIG_NO_HZ_IDLE=n | ||
9 | CONFIG_NO_HZ_FULL=y | ||
10 | CONFIG_NO_HZ_FULL_ALL=y | ||
11 | CONFIG_NO_HZ_FULL_SYSIDLE=y | ||
12 | CONFIG_RCU_FAST_NO_HZ=n | ||
13 | CONFIG_RCU_TRACE=y | ||
14 | CONFIG_HOTPLUG_CPU=y | ||
15 | CONFIG_RCU_FANOUT=2 | ||
16 | CONFIG_RCU_FANOUT_LEAF=2 | ||
17 | CONFIG_RCU_FANOUT_EXACT=n | ||
18 | CONFIG_RCU_NOCB_CPU=n | ||
19 | CONFIG_DEBUG_LOCK_ALLOC=n | ||
20 | CONFIG_PROVE_RCU_DELAY=n | ||
21 | CONFIG_RCU_CPU_STALL_INFO=y | ||
22 | CONFIG_RCU_CPU_STALL_VERBOSE=n | ||
23 | CONFIG_DEBUG_OBJECTS_RCU_HEAD=n | ||
24 | CONFIG_PRINTK_TIME=y | ||
diff --git a/tools/testing/selftests/rcutorture/configs/TREE08 b/tools/testing/selftests/rcutorture/configs/TREE08 new file mode 100644 index 000000000000..7d097a61ac2a --- /dev/null +++ b/tools/testing/selftests/rcutorture/configs/TREE08 | |||
@@ -0,0 +1,26 @@ | |||
1 | CONFIG_SMP=y | ||
2 | CONFIG_NR_CPUS=16 | ||
3 | CONFIG_PREEMPT_NONE=n | ||
4 | CONFIG_PREEMPT_VOLUNTARY=n | ||
5 | CONFIG_PREEMPT=y | ||
6 | #CHECK#CONFIG_TREE_PREEMPT_RCU=y | ||
7 | CONFIG_HZ_PERIODIC=n | ||
8 | CONFIG_NO_HZ_IDLE=y | ||
9 | CONFIG_NO_HZ_FULL=n | ||
10 | CONFIG_RCU_FAST_NO_HZ=n | ||
11 | CONFIG_RCU_TRACE=n | ||
12 | CONFIG_HOTPLUG_CPU=n | ||
13 | CONFIG_SUSPEND=n | ||
14 | CONFIG_HIBERNATION=n | ||
15 | CONFIG_RCU_FANOUT=3 | ||
16 | CONFIG_RCU_FANOUT_EXACT=y | ||
17 | CONFIG_RCU_FANOUT_LEAF=2 | ||
18 | CONFIG_RCU_NOCB_CPU=y | ||
19 | CONFIG_RCU_NOCB_CPU_ALL=y | ||
20 | CONFIG_DEBUG_LOCK_ALLOC=n | ||
21 | CONFIG_PROVE_RCU_DELAY=n | ||
22 | CONFIG_RCU_CPU_STALL_INFO=n | ||
23 | CONFIG_RCU_CPU_STALL_VERBOSE=n | ||
24 | CONFIG_RCU_BOOST=n | ||
25 | CONFIG_DEBUG_OBJECTS_RCU_HEAD=n | ||
26 | CONFIG_PRINTK_TIME=y | ||
diff --git a/tools/testing/selftests/rcutorture/configs/TREE08-T b/tools/testing/selftests/rcutorture/configs/TREE08-T new file mode 100644 index 000000000000..442c4e450ab3 --- /dev/null +++ b/tools/testing/selftests/rcutorture/configs/TREE08-T | |||
@@ -0,0 +1,26 @@ | |||
1 | CONFIG_SMP=y | ||
2 | CONFIG_NR_CPUS=16 | ||
3 | CONFIG_PREEMPT_NONE=n | ||
4 | CONFIG_PREEMPT_VOLUNTARY=n | ||
5 | CONFIG_PREEMPT=y | ||
6 | #CHECK#CONFIG_TREE_PREEMPT_RCU=y | ||
7 | CONFIG_HZ_PERIODIC=n | ||
8 | CONFIG_NO_HZ_IDLE=y | ||
9 | CONFIG_NO_HZ_FULL=n | ||
10 | CONFIG_RCU_FAST_NO_HZ=n | ||
11 | CONFIG_RCU_TRACE=y | ||
12 | CONFIG_HOTPLUG_CPU=n | ||
13 | CONFIG_SUSPEND=n | ||
14 | CONFIG_HIBERNATION=n | ||
15 | CONFIG_RCU_FANOUT=3 | ||
16 | CONFIG_RCU_FANOUT_EXACT=y | ||
17 | CONFIG_RCU_FANOUT_LEAF=2 | ||
18 | CONFIG_RCU_NOCB_CPU=y | ||
19 | CONFIG_RCU_NOCB_CPU_ALL=y | ||
20 | CONFIG_DEBUG_LOCK_ALLOC=n | ||
21 | CONFIG_PROVE_RCU_DELAY=n | ||
22 | CONFIG_RCU_CPU_STALL_INFO=n | ||
23 | CONFIG_RCU_CPU_STALL_VERBOSE=n | ||
24 | CONFIG_RCU_BOOST=n | ||
25 | CONFIG_DEBUG_OBJECTS_RCU_HEAD=n | ||
26 | CONFIG_PRINTK_TIME=y | ||
diff --git a/tools/testing/selftests/rcutorture/configs/TREE09 b/tools/testing/selftests/rcutorture/configs/TREE09 new file mode 100644 index 000000000000..0d1ec0d3dfee --- /dev/null +++ b/tools/testing/selftests/rcutorture/configs/TREE09 | |||
@@ -0,0 +1,21 @@ | |||
1 | CONFIG_SMP=n | ||
2 | CONFIG_NR_CPUS=1 | ||
3 | CONFIG_PREEMPT_NONE=n | ||
4 | CONFIG_PREEMPT_VOLUNTARY=n | ||
5 | CONFIG_PREEMPT=y | ||
6 | #CHECK#CONFIG_TREE_PREEMPT_RCU=y | ||
7 | CONFIG_HZ_PERIODIC=n | ||
8 | CONFIG_NO_HZ_IDLE=y | ||
9 | CONFIG_NO_HZ_FULL=n | ||
10 | CONFIG_RCU_TRACE=n | ||
11 | CONFIG_HOTPLUG_CPU=n | ||
12 | CONFIG_SUSPEND=n | ||
13 | CONFIG_HIBERNATION=n | ||
14 | CONFIG_RCU_NOCB_CPU=n | ||
15 | CONFIG_DEBUG_LOCK_ALLOC=n | ||
16 | CONFIG_PROVE_RCU_DELAY=n | ||
17 | CONFIG_RCU_CPU_STALL_INFO=n | ||
18 | CONFIG_RCU_CPU_STALL_VERBOSE=n | ||
19 | CONFIG_RCU_BOOST=n | ||
20 | CONFIG_DEBUG_OBJECTS_RCU_HEAD=n | ||
21 | CONFIG_PRINTK_TIME=y | ||
diff --git a/tools/testing/selftests/rcutorture/configs/v0.0/CFLIST b/tools/testing/selftests/rcutorture/configs/v0.0/CFLIST new file mode 100644 index 000000000000..18223947bbcb --- /dev/null +++ b/tools/testing/selftests/rcutorture/configs/v0.0/CFLIST | |||
@@ -0,0 +1,14 @@ | |||
1 | P1-S-T-NH-SD-SMP-HP | ||
2 | P2-2-t-nh-sd-SMP-hp | ||
3 | P3-3-T-nh-SD-SMP-hp | ||
4 | P4-A-t-NH-sd-SMP-HP | ||
5 | P5-U-T-NH-sd-SMP-hp | ||
6 | N1-S-T-NH-SD-SMP-HP | ||
7 | N2-2-t-nh-sd-SMP-hp | ||
8 | N3-3-T-nh-SD-SMP-hp | ||
9 | N4-A-t-NH-sd-SMP-HP | ||
10 | N5-U-T-NH-sd-SMP-hp | ||
11 | PT1-nh | ||
12 | PT2-NH | ||
13 | NT1-nh | ||
14 | NT3-NH | ||
diff --git a/tools/testing/selftests/rcutorture/configs/v0.0/N1-S-T-NH-SD-SMP-HP b/tools/testing/selftests/rcutorture/configs/v0.0/N1-S-T-NH-SD-SMP-HP new file mode 100644 index 000000000000..d3ef873eb6e7 --- /dev/null +++ b/tools/testing/selftests/rcutorture/configs/v0.0/N1-S-T-NH-SD-SMP-HP | |||
@@ -0,0 +1,18 @@ | |||
1 | CONFIG_RCU_TRACE=y | ||
2 | CONFIG_NO_HZ=y | ||
3 | CONFIG_SMP=y | ||
4 | CONFIG_RCU_FANOUT=8 | ||
5 | CONFIG_NR_CPUS=8 | ||
6 | CONFIG_RCU_FANOUT_EXACT=n | ||
7 | CONFIG_HOTPLUG_CPU=y | ||
8 | CONFIG_PREEMPT_NONE=y | ||
9 | CONFIG_PREEMPT_VOLUNTARY=n | ||
10 | CONFIG_PREEMPT=n | ||
11 | #CHECK#CONFIG_TREE_RCU=y | ||
12 | CONFIG_RCU_TORTURE_TEST=m | ||
13 | CONFIG_MODULE_UNLOAD=y | ||
14 | CONFIG_SYSFS_DEPRECATED_V2=y | ||
15 | CONFIG_IKCONFIG=y | ||
16 | CONFIG_IKCONFIG_PROC=y | ||
17 | CONFIG_PRINTK_TIME=y | ||
18 | |||
diff --git a/tools/testing/selftests/rcutorture/configs/v0.0/N2-2-t-nh-sd-SMP-hp b/tools/testing/selftests/rcutorture/configs/v0.0/N2-2-t-nh-sd-SMP-hp new file mode 100644 index 000000000000..02e418572b1b --- /dev/null +++ b/tools/testing/selftests/rcutorture/configs/v0.0/N2-2-t-nh-sd-SMP-hp | |||
@@ -0,0 +1,20 @@ | |||
1 | CONFIG_RCU_TRACE=n | ||
2 | CONFIG_NO_HZ=n | ||
3 | CONFIG_SMP=y | ||
4 | CONFIG_RCU_FANOUT=4 | ||
5 | CONFIG_NR_CPUS=8 | ||
6 | CONFIG_RCU_FANOUT_EXACT=n | ||
7 | CONFIG_HOTPLUG_CPU=n | ||
8 | CONFIG_SUSPEND=n | ||
9 | CONFIG_HIBERNATION=n | ||
10 | CONFIG_PREEMPT_NONE=y | ||
11 | CONFIG_PREEMPT_VOLUNTARY=n | ||
12 | CONFIG_PREEMPT=n | ||
13 | #CHECK#CONFIG_TREE_RCU=y | ||
14 | CONFIG_RCU_TORTURE_TEST=m | ||
15 | CONFIG_MODULE_UNLOAD=y | ||
16 | CONFIG_SYSFS_DEPRECATED_V2=y | ||
17 | CONFIG_IKCONFIG=y | ||
18 | CONFIG_IKCONFIG_PROC=y | ||
19 | CONFIG_PRINTK_TIME=y | ||
20 | |||
diff --git a/tools/testing/selftests/rcutorture/configs/v0.0/N3-3-T-nh-SD-SMP-hp b/tools/testing/selftests/rcutorture/configs/v0.0/N3-3-T-nh-SD-SMP-hp new file mode 100644 index 000000000000..b3100f69c8cf --- /dev/null +++ b/tools/testing/selftests/rcutorture/configs/v0.0/N3-3-T-nh-SD-SMP-hp | |||
@@ -0,0 +1,22 @@ | |||
1 | CONFIG_RCU_TRACE=y | ||
2 | CONFIG_NO_HZ=n | ||
3 | CONFIG_SMP=y | ||
4 | CONFIG_RCU_FANOUT=2 | ||
5 | CONFIG_NR_CPUS=8 | ||
6 | CONFIG_RCU_FANOUT_EXACT=n | ||
7 | CONFIG_HOTPLUG_CPU=n | ||
8 | CONFIG_SUSPEND=n | ||
9 | CONFIG_HIBERNATION=n | ||
10 | CONFIG_PREEMPT_NONE=y | ||
11 | CONFIG_PREEMPT_VOLUNTARY=n | ||
12 | CONFIG_PREEMPT=n | ||
13 | #CHECK#CONFIG_TREE_RCU=y | ||
14 | CONFIG_RCU_TORTURE_TEST=m | ||
15 | CONFIG_MODULE_UNLOAD=y | ||
16 | CONFIG_PROVE_LOCKING=y | ||
17 | CONFIG_PROVE_RCU=y | ||
18 | CONFIG_SYSFS_DEPRECATED_V2=y | ||
19 | CONFIG_IKCONFIG=y | ||
20 | CONFIG_IKCONFIG_PROC=y | ||
21 | CONFIG_PRINTK_TIME=y | ||
22 | |||
diff --git a/tools/testing/selftests/rcutorture/configs/v0.0/N4-A-t-NH-sd-SMP-HP b/tools/testing/selftests/rcutorture/configs/v0.0/N4-A-t-NH-sd-SMP-HP new file mode 100644 index 000000000000..c56b44530725 --- /dev/null +++ b/tools/testing/selftests/rcutorture/configs/v0.0/N4-A-t-NH-sd-SMP-HP | |||
@@ -0,0 +1,18 @@ | |||
1 | CONFIG_RCU_TRACE=n | ||
2 | CONFIG_NO_HZ=y | ||
3 | CONFIG_SMP=y | ||
4 | CONFIG_RCU_FANOUT=6 | ||
5 | CONFIG_NR_CPUS=8 | ||
6 | CONFIG_RCU_FANOUT_EXACT=n | ||
7 | CONFIG_HOTPLUG_CPU=y | ||
8 | CONFIG_PREEMPT_NONE=y | ||
9 | CONFIG_PREEMPT_VOLUNTARY=n | ||
10 | CONFIG_PREEMPT=n | ||
11 | #CHECK#CONFIG_TREE_RCU=y | ||
12 | CONFIG_RCU_TORTURE_TEST=m | ||
13 | CONFIG_MODULE_UNLOAD=y | ||
14 | CONFIG_SYSFS_DEPRECATED_V2=y | ||
15 | CONFIG_IKCONFIG=y | ||
16 | CONFIG_IKCONFIG_PROC=y | ||
17 | CONFIG_PRINTK_TIME=y | ||
18 | |||
diff --git a/tools/testing/selftests/rcutorture/configs/v0.0/N5-U-T-NH-sd-SMP-hp b/tools/testing/selftests/rcutorture/configs/v0.0/N5-U-T-NH-sd-SMP-hp new file mode 100644 index 000000000000..90d924fea9e9 --- /dev/null +++ b/tools/testing/selftests/rcutorture/configs/v0.0/N5-U-T-NH-sd-SMP-hp | |||
@@ -0,0 +1,22 @@ | |||
1 | CONFIG_RCU_TRACE=y | ||
2 | CONFIG_DEBUG_KERNEL=y | ||
3 | CONFIG_RCU_CPU_STALL_INFO=y | ||
4 | CONFIG_NO_HZ=y | ||
5 | CONFIG_SMP=y | ||
6 | CONFIG_RCU_FANOUT=6 | ||
7 | CONFIG_NR_CPUS=8 | ||
8 | CONFIG_RCU_FANOUT_EXACT=y | ||
9 | CONFIG_HOTPLUG_CPU=n | ||
10 | CONFIG_SUSPEND=n | ||
11 | CONFIG_HIBERNATION=n | ||
12 | CONFIG_PREEMPT_NONE=y | ||
13 | CONFIG_PREEMPT_VOLUNTARY=n | ||
14 | CONFIG_PREEMPT=n | ||
15 | #CHECK#CONFIG_TREE_RCU=y | ||
16 | CONFIG_RCU_TORTURE_TEST=m | ||
17 | CONFIG_MODULE_UNLOAD=y | ||
18 | CONFIG_SYSFS_DEPRECATED_V2=y | ||
19 | CONFIG_IKCONFIG=y | ||
20 | CONFIG_IKCONFIG_PROC=y | ||
21 | CONFIG_PRINTK_TIME=y | ||
22 | |||
diff --git a/tools/testing/selftests/rcutorture/configs/v0.0/NT1-nh b/tools/testing/selftests/rcutorture/configs/v0.0/NT1-nh new file mode 100644 index 000000000000..023f312a931c --- /dev/null +++ b/tools/testing/selftests/rcutorture/configs/v0.0/NT1-nh | |||
@@ -0,0 +1,23 @@ | |||
1 | #CHECK#CONFIG_TINY_RCU=y | ||
2 | CONFIG_RCU_TRACE=y | ||
3 | CONFIG_RCU_TORTURE_TEST=m | ||
4 | CONFIG_MODULE_UNLOAD=y | ||
5 | CONFIG_SUSPEND=n | ||
6 | CONFIG_HIBERNATION=n | ||
7 | # | ||
8 | CONFIG_SMP=n | ||
9 | # | ||
10 | CONFIG_HOTPLUG_CPU=n | ||
11 | # | ||
12 | CONFIG_NO_HZ=n | ||
13 | # | ||
14 | CONFIG_PREEMPT_NONE=y | ||
15 | CONFIG_PREEMPT_VOLUNTARY=n | ||
16 | CONFIG_PREEMPT=n | ||
17 | CONFIG_PROVE_LOCKING=y | ||
18 | CONFIG_PROVE_RCU=y | ||
19 | CONFIG_SYSFS_DEPRECATED_V2=y | ||
20 | CONFIG_IKCONFIG=y | ||
21 | CONFIG_IKCONFIG_PROC=y | ||
22 | CONFIG_PRINTK_TIME=y | ||
23 | |||
diff --git a/tools/testing/selftests/rcutorture/configs/v0.0/NT3-NH b/tools/testing/selftests/rcutorture/configs/v0.0/NT3-NH new file mode 100644 index 000000000000..6fd0235dae73 --- /dev/null +++ b/tools/testing/selftests/rcutorture/configs/v0.0/NT3-NH | |||
@@ -0,0 +1,20 @@ | |||
1 | #CHECK#CONFIG_TINY_RCU=y | ||
2 | CONFIG_RCU_TORTURE_TEST=m | ||
3 | CONFIG_MODULE_UNLOAD=y | ||
4 | CONFIG_SUSPEND=n | ||
5 | CONFIG_HIBERNATION=n | ||
6 | # | ||
7 | CONFIG_SMP=n | ||
8 | # | ||
9 | CONFIG_HOTPLUG_CPU=n | ||
10 | # | ||
11 | CONFIG_NO_HZ=y | ||
12 | # | ||
13 | CONFIG_PREEMPT_NONE=y | ||
14 | CONFIG_PREEMPT_VOLUNTARY=n | ||
15 | CONFIG_PREEMPT=n | ||
16 | CONFIG_SYSFS_DEPRECATED_V2=y | ||
17 | CONFIG_IKCONFIG=y | ||
18 | CONFIG_IKCONFIG_PROC=y | ||
19 | CONFIG_PRINTK_TIME=y | ||
20 | |||
diff --git a/tools/testing/selftests/rcutorture/configs/v0.0/P1-S-T-NH-SD-SMP-HP b/tools/testing/selftests/rcutorture/configs/v0.0/P1-S-T-NH-SD-SMP-HP new file mode 100644 index 000000000000..f72402d7c13d --- /dev/null +++ b/tools/testing/selftests/rcutorture/configs/v0.0/P1-S-T-NH-SD-SMP-HP | |||
@@ -0,0 +1,19 @@ | |||
1 | CONFIG_RCU_TRACE=y | ||
2 | CONFIG_RCU_CPU_STALL_INFO=y | ||
3 | CONFIG_NO_HZ=y | ||
4 | CONFIG_SMP=y | ||
5 | CONFIG_RCU_FANOUT=8 | ||
6 | CONFIG_NR_CPUS=8 | ||
7 | CONFIG_RCU_FANOUT_EXACT=n | ||
8 | CONFIG_HOTPLUG_CPU=y | ||
9 | CONFIG_PREEMPT_NONE=n | ||
10 | CONFIG_PREEMPT_VOLUNTARY=n | ||
11 | CONFIG_PREEMPT=y | ||
12 | #CHECK#CONFIG_TREE_PREEMPT_RCU=y | ||
13 | CONFIG_RCU_TORTURE_TEST=m | ||
14 | CONFIG_MODULE_UNLOAD=y | ||
15 | CONFIG_SYSFS_DEPRECATED_V2=y | ||
16 | CONFIG_IKCONFIG=y | ||
17 | CONFIG_IKCONFIG_PROC=y | ||
18 | CONFIG_PRINTK_TIME=y | ||
19 | |||
diff --git a/tools/testing/selftests/rcutorture/configs/v0.0/P2-2-t-nh-sd-SMP-hp b/tools/testing/selftests/rcutorture/configs/v0.0/P2-2-t-nh-sd-SMP-hp new file mode 100644 index 000000000000..0f3b667d2a9f --- /dev/null +++ b/tools/testing/selftests/rcutorture/configs/v0.0/P2-2-t-nh-sd-SMP-hp | |||
@@ -0,0 +1,20 @@ | |||
1 | CONFIG_RCU_TRACE=n | ||
2 | CONFIG_NO_HZ=n | ||
3 | CONFIG_SMP=y | ||
4 | CONFIG_RCU_FANOUT=4 | ||
5 | CONFIG_NR_CPUS=8 | ||
6 | CONFIG_RCU_FANOUT_EXACT=n | ||
7 | CONFIG_HOTPLUG_CPU=n | ||
8 | CONFIG_SUSPEND=n | ||
9 | CONFIG_HIBERNATION=n | ||
10 | CONFIG_PREEMPT_NONE=n | ||
11 | CONFIG_PREEMPT_VOLUNTARY=n | ||
12 | CONFIG_PREEMPT=y | ||
13 | #CHECK#CONFIG_TREE_PREEMPT_RCU=y | ||
14 | CONFIG_RCU_TORTURE_TEST=m | ||
15 | CONFIG_MODULE_UNLOAD=y | ||
16 | CONFIG_SYSFS_DEPRECATED_V2=y | ||
17 | CONFIG_IKCONFIG=y | ||
18 | CONFIG_IKCONFIG_PROC=y | ||
19 | CONFIG_PRINTK_TIME=y | ||
20 | |||
diff --git a/tools/testing/selftests/rcutorture/configs/v0.0/P3-3-T-nh-SD-SMP-hp b/tools/testing/selftests/rcutorture/configs/v0.0/P3-3-T-nh-SD-SMP-hp new file mode 100644 index 000000000000..b035e141bf2a --- /dev/null +++ b/tools/testing/selftests/rcutorture/configs/v0.0/P3-3-T-nh-SD-SMP-hp | |||
@@ -0,0 +1,20 @@ | |||
1 | CONFIG_RCU_TRACE=y | ||
2 | CONFIG_NO_HZ=n | ||
3 | CONFIG_SMP=y | ||
4 | CONFIG_RCU_FANOUT=2 | ||
5 | CONFIG_NR_CPUS=8 | ||
6 | CONFIG_RCU_FANOUT_EXACT=n | ||
7 | CONFIG_HOTPLUG_CPU=n | ||
8 | CONFIG_SUSPEND=n | ||
9 | CONFIG_HIBERNATION=n | ||
10 | CONFIG_PREEMPT_NONE=n | ||
11 | CONFIG_PREEMPT_VOLUNTARY=n | ||
12 | CONFIG_PREEMPT=y | ||
13 | #CHECK#CONFIG_TREE_PREEMPT_RCU=y | ||
14 | CONFIG_RCU_TORTURE_TEST=m | ||
15 | CONFIG_MODULE_UNLOAD=y | ||
16 | CONFIG_SYSFS_DEPRECATED_V2=y | ||
17 | CONFIG_IKCONFIG=y | ||
18 | CONFIG_IKCONFIG_PROC=y | ||
19 | CONFIG_PRINTK_TIME=y | ||
20 | |||
diff --git a/tools/testing/selftests/rcutorture/configs/v0.0/P4-A-t-NH-sd-SMP-HP b/tools/testing/selftests/rcutorture/configs/v0.0/P4-A-t-NH-sd-SMP-HP new file mode 100644 index 000000000000..3ccf6a9447f5 --- /dev/null +++ b/tools/testing/selftests/rcutorture/configs/v0.0/P4-A-t-NH-sd-SMP-HP | |||
@@ -0,0 +1,22 @@ | |||
1 | CONFIG_RCU_TRACE=n | ||
2 | CONFIG_NO_HZ=y | ||
3 | CONFIG_SMP=y | ||
4 | CONFIG_RCU_FANOUT=6 | ||
5 | CONFIG_NR_CPUS=8 | ||
6 | CONFIG_RCU_FANOUT_EXACT=n | ||
7 | CONFIG_HOTPLUG_CPU=y | ||
8 | CONFIG_PREEMPT_NONE=n | ||
9 | CONFIG_PREEMPT_VOLUNTARY=n | ||
10 | CONFIG_PREEMPT=y | ||
11 | #CHECK#CONFIG_TREE_PREEMPT_RCU=y | ||
12 | CONFIG_RCU_TORTURE_TEST=m | ||
13 | CONFIG_MODULE_UNLOAD=y | ||
14 | CONFIG_RT_MUTEXES=y | ||
15 | CONFIG_RCU_BOOST=y | ||
16 | CONFIG_RCU_BOOST_PRIO=2 | ||
17 | CONFIG_PROVE_LOCKING=y | ||
18 | CONFIG_PROVE_RCU=y | ||
19 | CONFIG_IKCONFIG=y | ||
20 | CONFIG_IKCONFIG_PROC=y | ||
21 | CONFIG_PRINTK_TIME=y | ||
22 | |||
diff --git a/tools/testing/selftests/rcutorture/configs/v0.0/P5-U-T-NH-sd-SMP-hp b/tools/testing/selftests/rcutorture/configs/v0.0/P5-U-T-NH-sd-SMP-hp new file mode 100644 index 000000000000..ef624ce73d8e --- /dev/null +++ b/tools/testing/selftests/rcutorture/configs/v0.0/P5-U-T-NH-sd-SMP-hp | |||
@@ -0,0 +1,28 @@ | |||
1 | CONFIG_RCU_TRACE=y | ||
2 | CONFIG_RCU_CPU_STALL_INFO=y | ||
3 | CONFIG_NO_HZ=y | ||
4 | CONFIG_SMP=y | ||
5 | CONFIG_RCU_FANOUT=6 | ||
6 | CONFIG_NR_CPUS=8 | ||
7 | CONFIG_RCU_FANOUT_EXACT=y | ||
8 | CONFIG_HOTPLUG_CPU=n | ||
9 | CONFIG_SUSPEND=n | ||
10 | CONFIG_HIBERNATION=n | ||
11 | CONFIG_PREEMPT_NONE=n | ||
12 | CONFIG_PREEMPT_VOLUNTARY=n | ||
13 | CONFIG_PREEMPT=y | ||
14 | #CHECK#CONFIG_TREE_PREEMPT_RCU=y | ||
15 | CONFIG_DEBUG_KERNEL=y | ||
16 | CONFIG_PROVE_RCU_DELAY=y | ||
17 | CONFIG_DEBUG_OBJECTS=y | ||
18 | CONFIG_DEBUG_OBJECTS_RCU_HEAD=y | ||
19 | CONFIG_RT_MUTEXES=y | ||
20 | CONFIG_RCU_BOOST=y | ||
21 | CONFIG_RCU_BOOST_PRIO=2 | ||
22 | CONFIG_RCU_TORTURE_TEST=m | ||
23 | CONFIG_MODULE_UNLOAD=y | ||
24 | CONFIG_SYSFS_DEPRECATED_V2=y | ||
25 | CONFIG_IKCONFIG=y | ||
26 | CONFIG_IKCONFIG_PROC=y | ||
27 | CONFIG_PRINTK_TIME=y | ||
28 | |||
diff --git a/tools/testing/selftests/rcutorture/configs/v0.0/PT1-nh b/tools/testing/selftests/rcutorture/configs/v0.0/PT1-nh new file mode 100644 index 000000000000..e3361c3894a1 --- /dev/null +++ b/tools/testing/selftests/rcutorture/configs/v0.0/PT1-nh | |||
@@ -0,0 +1,23 @@ | |||
1 | CONFIG_TINY_PREEMPT_RCU=y | ||
2 | CONFIG_RCU_BOOST=y | ||
3 | CONFIG_RCU_BOOST_PRIO=2 | ||
4 | CONFIG_RCU_TRACE=y | ||
5 | CONFIG_RCU_TORTURE_TEST=m | ||
6 | CONFIG_MODULE_UNLOAD=y | ||
7 | CONFIG_SUSPEND=n | ||
8 | CONFIG_HIBERNATION=n | ||
9 | # | ||
10 | CONFIG_SMP=n | ||
11 | # | ||
12 | CONFIG_HOTPLUG_CPU=n | ||
13 | # | ||
14 | CONFIG_NO_HZ=n | ||
15 | # | ||
16 | CONFIG_PREEMPT_NONE=n | ||
17 | CONFIG_PREEMPT_VOLUNTARY=n | ||
18 | CONFIG_PREEMPT=y | ||
19 | CONFIG_SYSFS_DEPRECATED_V2=y | ||
20 | CONFIG_IKCONFIG=y | ||
21 | CONFIG_IKCONFIG_PROC=y | ||
22 | CONFIG_PRINTK_TIME=y | ||
23 | |||
diff --git a/tools/testing/selftests/rcutorture/configs/v0.0/PT2-NH b/tools/testing/selftests/rcutorture/configs/v0.0/PT2-NH new file mode 100644 index 000000000000..64abfc3b4d94 --- /dev/null +++ b/tools/testing/selftests/rcutorture/configs/v0.0/PT2-NH | |||
@@ -0,0 +1,22 @@ | |||
1 | CONFIG_TINY_PREEMPT_RCU=y | ||
2 | CONFIG_RCU_TORTURE_TEST=m | ||
3 | CONFIG_MODULE_UNLOAD=y | ||
4 | CONFIG_SUSPEND=n | ||
5 | CONFIG_HIBERNATION=n | ||
6 | # | ||
7 | CONFIG_SMP=n | ||
8 | # | ||
9 | CONFIG_HOTPLUG_CPU=n | ||
10 | # | ||
11 | CONFIG_NO_HZ=y | ||
12 | # | ||
13 | CONFIG_PREEMPT_NONE=n | ||
14 | CONFIG_PREEMPT_VOLUNTARY=n | ||
15 | CONFIG_PREEMPT=y | ||
16 | CONFIG_PROVE_LOCKING=y | ||
17 | CONFIG_PROVE_RCU=y | ||
18 | CONFIG_SYSFS_DEPRECATED_V2=y | ||
19 | CONFIG_IKCONFIG=y | ||
20 | CONFIG_IKCONFIG_PROC=y | ||
21 | CONFIG_PRINTK_TIME=y | ||
22 | |||
diff --git a/tools/testing/selftests/rcutorture/configs/v0.0/ver_functions.sh b/tools/testing/selftests/rcutorture/configs/v0.0/ver_functions.sh new file mode 100644 index 000000000000..e8052539af54 --- /dev/null +++ b/tools/testing/selftests/rcutorture/configs/v0.0/ver_functions.sh | |||
@@ -0,0 +1,35 @@ | |||
1 | #!/bin/bash | ||
2 | # | ||
3 | # Kernel-version-dependent shell functions for the rest of the scripts. | ||
4 | # | ||
5 | # This program is free software; you can redistribute it and/or modify | ||
6 | # it under the terms of the GNU General Public License as published by | ||
7 | # the Free Software Foundation; either version 2 of the License, or | ||
8 | # (at your option) any later version. | ||
9 | # | ||
10 | # This program is distributed in the hope that it will be useful, | ||
11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | # GNU General Public License for more details. | ||
14 | # | ||
15 | # You should have received a copy of the GNU General Public License | ||
16 | # along with this program; if not, you can access it online at | ||
17 | # http://www.gnu.org/licenses/gpl-2.0.html. | ||
18 | # | ||
19 | # Copyright (C) IBM Corporation, 2013 | ||
20 | # | ||
21 | # Authors: Paul E. McKenney <paulmck@linux.vnet.ibm.com> | ||
22 | |||
23 | # rcutorture_param_n_barrier_cbs bootparam-string | ||
24 | # | ||
25 | # Adds n_barrier_cbs rcutorture module parameter to kernels having it. | ||
26 | rcutorture_param_n_barrier_cbs () { | ||
27 | echo $1 | ||
28 | } | ||
29 | |||
30 | # rcutorture_param_onoff bootparam-string config-file | ||
31 | # | ||
32 | # Adds onoff rcutorture module parameters to kernels having it. | ||
33 | rcutorture_param_onoff () { | ||
34 | echo $1 | ||
35 | } | ||
diff --git a/tools/testing/selftests/rcutorture/configs/v3.12/CFLIST b/tools/testing/selftests/rcutorture/configs/v3.12/CFLIST new file mode 100644 index 000000000000..da4cbc668f2a --- /dev/null +++ b/tools/testing/selftests/rcutorture/configs/v3.12/CFLIST | |||
@@ -0,0 +1,17 @@ | |||
1 | sysidleY.2013.06.19a | ||
2 | sysidleN.2013.06.19a | ||
3 | P1-S-T-NH-SD-SMP-HP | ||
4 | P2-2-t-nh-sd-SMP-hp | ||
5 | P3-3-T-nh-SD-SMP-hp | ||
6 | P4-A-t-NH-sd-SMP-HP | ||
7 | P5-U-T-NH-sd-SMP-hp | ||
8 | P6---t-nh-SD-smp-hp | ||
9 | N1-S-T-NH-SD-SMP-HP | ||
10 | N2-2-t-nh-sd-SMP-hp | ||
11 | N3-3-T-nh-SD-SMP-hp | ||
12 | N4-A-t-NH-sd-SMP-HP | ||
13 | N5-U-T-NH-sd-SMP-hp | ||
14 | PT1-nh | ||
15 | PT2-NH | ||
16 | NT1-nh | ||
17 | NT3-NH | ||
diff --git a/tools/testing/selftests/rcutorture/configs/v3.12/N1-S-T-NH-SD-SMP-HP b/tools/testing/selftests/rcutorture/configs/v3.12/N1-S-T-NH-SD-SMP-HP new file mode 100644 index 000000000000..d81e11d280aa --- /dev/null +++ b/tools/testing/selftests/rcutorture/configs/v3.12/N1-S-T-NH-SD-SMP-HP | |||
@@ -0,0 +1,19 @@ | |||
1 | CONFIG_RCU_TRACE=y | ||
2 | CONFIG_RCU_FAST_NO_HZ=y | ||
3 | CONFIG_NO_HZ=y | ||
4 | CONFIG_SMP=y | ||
5 | CONFIG_RCU_FANOUT=8 | ||
6 | CONFIG_NR_CPUS=8 | ||
7 | CONFIG_RCU_FANOUT_EXACT=n | ||
8 | CONFIG_HOTPLUG_CPU=y | ||
9 | CONFIG_PREEMPT_NONE=y | ||
10 | CONFIG_PREEMPT_VOLUNTARY=n | ||
11 | CONFIG_PREEMPT=n | ||
12 | #CHECK#CONFIG_TREE_RCU=y | ||
13 | CONFIG_RCU_TORTURE_TEST=m | ||
14 | CONFIG_MODULE_UNLOAD=y | ||
15 | CONFIG_SYSFS_DEPRECATED_V2=y | ||
16 | CONFIG_IKCONFIG=y | ||
17 | CONFIG_IKCONFIG_PROC=y | ||
18 | CONFIG_PRINTK_TIME=y | ||
19 | |||
diff --git a/tools/testing/selftests/rcutorture/configs/v3.12/N2-2-t-nh-sd-SMP-hp b/tools/testing/selftests/rcutorture/configs/v3.12/N2-2-t-nh-sd-SMP-hp new file mode 100644 index 000000000000..02e418572b1b --- /dev/null +++ b/tools/testing/selftests/rcutorture/configs/v3.12/N2-2-t-nh-sd-SMP-hp | |||
@@ -0,0 +1,20 @@ | |||
1 | CONFIG_RCU_TRACE=n | ||
2 | CONFIG_NO_HZ=n | ||
3 | CONFIG_SMP=y | ||
4 | CONFIG_RCU_FANOUT=4 | ||
5 | CONFIG_NR_CPUS=8 | ||
6 | CONFIG_RCU_FANOUT_EXACT=n | ||
7 | CONFIG_HOTPLUG_CPU=n | ||
8 | CONFIG_SUSPEND=n | ||
9 | CONFIG_HIBERNATION=n | ||
10 | CONFIG_PREEMPT_NONE=y | ||
11 | CONFIG_PREEMPT_VOLUNTARY=n | ||
12 | CONFIG_PREEMPT=n | ||
13 | #CHECK#CONFIG_TREE_RCU=y | ||
14 | CONFIG_RCU_TORTURE_TEST=m | ||
15 | CONFIG_MODULE_UNLOAD=y | ||
16 | CONFIG_SYSFS_DEPRECATED_V2=y | ||
17 | CONFIG_IKCONFIG=y | ||
18 | CONFIG_IKCONFIG_PROC=y | ||
19 | CONFIG_PRINTK_TIME=y | ||
20 | |||
diff --git a/tools/testing/selftests/rcutorture/configs/v3.12/N3-3-T-nh-SD-SMP-hp b/tools/testing/selftests/rcutorture/configs/v3.12/N3-3-T-nh-SD-SMP-hp new file mode 100644 index 000000000000..b3100f69c8cf --- /dev/null +++ b/tools/testing/selftests/rcutorture/configs/v3.12/N3-3-T-nh-SD-SMP-hp | |||
@@ -0,0 +1,22 @@ | |||
1 | CONFIG_RCU_TRACE=y | ||
2 | CONFIG_NO_HZ=n | ||
3 | CONFIG_SMP=y | ||
4 | CONFIG_RCU_FANOUT=2 | ||
5 | CONFIG_NR_CPUS=8 | ||
6 | CONFIG_RCU_FANOUT_EXACT=n | ||
7 | CONFIG_HOTPLUG_CPU=n | ||
8 | CONFIG_SUSPEND=n | ||
9 | CONFIG_HIBERNATION=n | ||
10 | CONFIG_PREEMPT_NONE=y | ||
11 | CONFIG_PREEMPT_VOLUNTARY=n | ||
12 | CONFIG_PREEMPT=n | ||
13 | #CHECK#CONFIG_TREE_RCU=y | ||
14 | CONFIG_RCU_TORTURE_TEST=m | ||
15 | CONFIG_MODULE_UNLOAD=y | ||
16 | CONFIG_PROVE_LOCKING=y | ||
17 | CONFIG_PROVE_RCU=y | ||
18 | CONFIG_SYSFS_DEPRECATED_V2=y | ||
19 | CONFIG_IKCONFIG=y | ||
20 | CONFIG_IKCONFIG_PROC=y | ||
21 | CONFIG_PRINTK_TIME=y | ||
22 | |||
diff --git a/tools/testing/selftests/rcutorture/configs/v3.12/N4-A-t-NH-sd-SMP-HP b/tools/testing/selftests/rcutorture/configs/v3.12/N4-A-t-NH-sd-SMP-HP new file mode 100644 index 000000000000..c56b44530725 --- /dev/null +++ b/tools/testing/selftests/rcutorture/configs/v3.12/N4-A-t-NH-sd-SMP-HP | |||
@@ -0,0 +1,18 @@ | |||
1 | CONFIG_RCU_TRACE=n | ||
2 | CONFIG_NO_HZ=y | ||
3 | CONFIG_SMP=y | ||
4 | CONFIG_RCU_FANOUT=6 | ||
5 | CONFIG_NR_CPUS=8 | ||
6 | CONFIG_RCU_FANOUT_EXACT=n | ||
7 | CONFIG_HOTPLUG_CPU=y | ||
8 | CONFIG_PREEMPT_NONE=y | ||
9 | CONFIG_PREEMPT_VOLUNTARY=n | ||
10 | CONFIG_PREEMPT=n | ||
11 | #CHECK#CONFIG_TREE_RCU=y | ||
12 | CONFIG_RCU_TORTURE_TEST=m | ||
13 | CONFIG_MODULE_UNLOAD=y | ||
14 | CONFIG_SYSFS_DEPRECATED_V2=y | ||
15 | CONFIG_IKCONFIG=y | ||
16 | CONFIG_IKCONFIG_PROC=y | ||
17 | CONFIG_PRINTK_TIME=y | ||
18 | |||
diff --git a/tools/testing/selftests/rcutorture/configs/v3.12/N5-U-T-NH-sd-SMP-hp b/tools/testing/selftests/rcutorture/configs/v3.12/N5-U-T-NH-sd-SMP-hp new file mode 100644 index 000000000000..90d924fea9e9 --- /dev/null +++ b/tools/testing/selftests/rcutorture/configs/v3.12/N5-U-T-NH-sd-SMP-hp | |||
@@ -0,0 +1,22 @@ | |||
1 | CONFIG_RCU_TRACE=y | ||
2 | CONFIG_DEBUG_KERNEL=y | ||
3 | CONFIG_RCU_CPU_STALL_INFO=y | ||
4 | CONFIG_NO_HZ=y | ||
5 | CONFIG_SMP=y | ||
6 | CONFIG_RCU_FANOUT=6 | ||
7 | CONFIG_NR_CPUS=8 | ||
8 | CONFIG_RCU_FANOUT_EXACT=y | ||
9 | CONFIG_HOTPLUG_CPU=n | ||
10 | CONFIG_SUSPEND=n | ||
11 | CONFIG_HIBERNATION=n | ||
12 | CONFIG_PREEMPT_NONE=y | ||
13 | CONFIG_PREEMPT_VOLUNTARY=n | ||
14 | CONFIG_PREEMPT=n | ||
15 | #CHECK#CONFIG_TREE_RCU=y | ||
16 | CONFIG_RCU_TORTURE_TEST=m | ||
17 | CONFIG_MODULE_UNLOAD=y | ||
18 | CONFIG_SYSFS_DEPRECATED_V2=y | ||
19 | CONFIG_IKCONFIG=y | ||
20 | CONFIG_IKCONFIG_PROC=y | ||
21 | CONFIG_PRINTK_TIME=y | ||
22 | |||
diff --git a/tools/testing/selftests/rcutorture/configs/v3.12/N6---t-nh-SD-smp-hp b/tools/testing/selftests/rcutorture/configs/v3.12/N6---t-nh-SD-smp-hp new file mode 100644 index 000000000000..0ccc36d72738 --- /dev/null +++ b/tools/testing/selftests/rcutorture/configs/v3.12/N6---t-nh-SD-smp-hp | |||
@@ -0,0 +1,19 @@ | |||
1 | CONFIG_RCU_TRACE=n | ||
2 | CONFIG_NO_HZ=n | ||
3 | CONFIG_SMP=y | ||
4 | CONFIG_NR_CPUS=1 | ||
5 | CONFIG_RCU_FANOUT_EXACT=n | ||
6 | CONFIG_HOTPLUG_CPU=n | ||
7 | CONFIG_SUSPEND=n | ||
8 | CONFIG_HIBERNATION=n | ||
9 | CONFIG_PREEMPT_NONE=y | ||
10 | CONFIG_PREEMPT_VOLUNTARY=n | ||
11 | CONFIG_PREEMPT=n | ||
12 | #CHECK#CONFIG_TREE_RCU=y | ||
13 | CONFIG_RCU_TORTURE_TEST=m | ||
14 | CONFIG_MODULE_UNLOAD=y | ||
15 | CONFIG_SYSFS_DEPRECATED_V2=y | ||
16 | CONFIG_IKCONFIG=y | ||
17 | CONFIG_IKCONFIG_PROC=y | ||
18 | CONFIG_PRINTK_TIME=y | ||
19 | |||
diff --git a/tools/testing/selftests/rcutorture/configs/v3.12/N7-4-T-NH-SD-SMP-HP b/tools/testing/selftests/rcutorture/configs/v3.12/N7-4-T-NH-SD-SMP-HP new file mode 100644 index 000000000000..3f640cf84973 --- /dev/null +++ b/tools/testing/selftests/rcutorture/configs/v3.12/N7-4-T-NH-SD-SMP-HP | |||
@@ -0,0 +1,26 @@ | |||
1 | CONFIG_RCU_TRACE=y | ||
2 | CONFIG_DEBUG_KERNEL=y | ||
3 | CONFIG_RCU_CPU_STALL_INFO=y | ||
4 | CONFIG_NO_HZ=y | ||
5 | CONFIG_SMP=y | ||
6 | CONFIG_RCU_FANOUT=2 | ||
7 | CONFIG_NR_CPUS=16 | ||
8 | CONFIG_RCU_FANOUT_EXACT=n | ||
9 | CONFIG_HOTPLUG_CPU=y | ||
10 | CONFIG_RCU_NOCB_CPU=y | ||
11 | CONFIG_RCU_NOCB_CPU_NONE=y | ||
12 | CONFIG_RCU_NOCB_CPU_ZERO=n | ||
13 | CONFIG_RCU_NOCB_CPU_ALL=n | ||
14 | CONFIG_SUSPEND=n | ||
15 | CONFIG_HIBERNATION=n | ||
16 | CONFIG_PREEMPT_NONE=y | ||
17 | CONFIG_PREEMPT_VOLUNTARY=n | ||
18 | CONFIG_PREEMPT=n | ||
19 | #CHECK#CONFIG_TREE_RCU=y | ||
20 | CONFIG_RCU_TORTURE_TEST=m | ||
21 | CONFIG_MODULE_UNLOAD=y | ||
22 | CONFIG_SYSFS_DEPRECATED_V2=y | ||
23 | CONFIG_IKCONFIG=y | ||
24 | CONFIG_IKCONFIG_PROC=y | ||
25 | CONFIG_PRINTK_TIME=y | ||
26 | |||
diff --git a/tools/testing/selftests/rcutorture/configs/v3.12/N8-2-T-NH-SD-SMP-HP b/tools/testing/selftests/rcutorture/configs/v3.12/N8-2-T-NH-SD-SMP-HP new file mode 100644 index 000000000000..285da2dd8ac3 --- /dev/null +++ b/tools/testing/selftests/rcutorture/configs/v3.12/N8-2-T-NH-SD-SMP-HP | |||
@@ -0,0 +1,22 @@ | |||
1 | CONFIG_RCU_TRACE=y | ||
2 | CONFIG_DEBUG_KERNEL=y | ||
3 | CONFIG_RCU_CPU_STALL_INFO=y | ||
4 | CONFIG_NO_HZ=y | ||
5 | CONFIG_SMP=y | ||
6 | CONFIG_RCU_FANOUT=14 | ||
7 | CONFIG_NR_CPUS=16 | ||
8 | CONFIG_RCU_FANOUT_EXACT=y | ||
9 | CONFIG_HOTPLUG_CPU=y | ||
10 | CONFIG_SUSPEND=n | ||
11 | CONFIG_HIBERNATION=n | ||
12 | CONFIG_PREEMPT_NONE=y | ||
13 | CONFIG_PREEMPT_VOLUNTARY=n | ||
14 | CONFIG_PREEMPT=n | ||
15 | #CHECK#CONFIG_TREE_RCU=y | ||
16 | CONFIG_RCU_TORTURE_TEST=m | ||
17 | CONFIG_MODULE_UNLOAD=y | ||
18 | CONFIG_SYSFS_DEPRECATED_V2=y | ||
19 | CONFIG_IKCONFIG=y | ||
20 | CONFIG_IKCONFIG_PROC=y | ||
21 | CONFIG_PRINTK_TIME=y | ||
22 | |||
diff --git a/tools/testing/selftests/rcutorture/configs/v3.12/NT1-nh b/tools/testing/selftests/rcutorture/configs/v3.12/NT1-nh new file mode 100644 index 000000000000..023f312a931c --- /dev/null +++ b/tools/testing/selftests/rcutorture/configs/v3.12/NT1-nh | |||
@@ -0,0 +1,23 @@ | |||
1 | #CHECK#CONFIG_TINY_RCU=y | ||
2 | CONFIG_RCU_TRACE=y | ||
3 | CONFIG_RCU_TORTURE_TEST=m | ||
4 | CONFIG_MODULE_UNLOAD=y | ||
5 | CONFIG_SUSPEND=n | ||
6 | CONFIG_HIBERNATION=n | ||
7 | # | ||
8 | CONFIG_SMP=n | ||
9 | # | ||
10 | CONFIG_HOTPLUG_CPU=n | ||
11 | # | ||
12 | CONFIG_NO_HZ=n | ||
13 | # | ||
14 | CONFIG_PREEMPT_NONE=y | ||
15 | CONFIG_PREEMPT_VOLUNTARY=n | ||
16 | CONFIG_PREEMPT=n | ||
17 | CONFIG_PROVE_LOCKING=y | ||
18 | CONFIG_PROVE_RCU=y | ||
19 | CONFIG_SYSFS_DEPRECATED_V2=y | ||
20 | CONFIG_IKCONFIG=y | ||
21 | CONFIG_IKCONFIG_PROC=y | ||
22 | CONFIG_PRINTK_TIME=y | ||
23 | |||
diff --git a/tools/testing/selftests/rcutorture/configs/v3.12/NT3-NH b/tools/testing/selftests/rcutorture/configs/v3.12/NT3-NH new file mode 100644 index 000000000000..6fd0235dae73 --- /dev/null +++ b/tools/testing/selftests/rcutorture/configs/v3.12/NT3-NH | |||
@@ -0,0 +1,20 @@ | |||
1 | #CHECK#CONFIG_TINY_RCU=y | ||
2 | CONFIG_RCU_TORTURE_TEST=m | ||
3 | CONFIG_MODULE_UNLOAD=y | ||
4 | CONFIG_SUSPEND=n | ||
5 | CONFIG_HIBERNATION=n | ||
6 | # | ||
7 | CONFIG_SMP=n | ||
8 | # | ||
9 | CONFIG_HOTPLUG_CPU=n | ||
10 | # | ||
11 | CONFIG_NO_HZ=y | ||
12 | # | ||
13 | CONFIG_PREEMPT_NONE=y | ||
14 | CONFIG_PREEMPT_VOLUNTARY=n | ||
15 | CONFIG_PREEMPT=n | ||
16 | CONFIG_SYSFS_DEPRECATED_V2=y | ||
17 | CONFIG_IKCONFIG=y | ||
18 | CONFIG_IKCONFIG_PROC=y | ||
19 | CONFIG_PRINTK_TIME=y | ||
20 | |||
diff --git a/tools/testing/selftests/rcutorture/configs/v3.12/P1-S-T-NH-SD-SMP-HP b/tools/testing/selftests/rcutorture/configs/v3.12/P1-S-T-NH-SD-SMP-HP new file mode 100644 index 000000000000..9647c44cf4b7 --- /dev/null +++ b/tools/testing/selftests/rcutorture/configs/v3.12/P1-S-T-NH-SD-SMP-HP | |||
@@ -0,0 +1,20 @@ | |||
1 | CONFIG_RCU_TRACE=y | ||
2 | CONFIG_RCU_CPU_STALL_INFO=y | ||
3 | CONFIG_NO_HZ=y | ||
4 | CONFIG_RCU_FAST_NO_HZ=y | ||
5 | CONFIG_SMP=y | ||
6 | CONFIG_RCU_FANOUT=8 | ||
7 | CONFIG_NR_CPUS=8 | ||
8 | CONFIG_RCU_FANOUT_EXACT=n | ||
9 | CONFIG_HOTPLUG_CPU=y | ||
10 | CONFIG_PREEMPT_NONE=n | ||
11 | CONFIG_PREEMPT_VOLUNTARY=n | ||
12 | CONFIG_PREEMPT=y | ||
13 | #CHECK#CONFIG_TREE_PREEMPT_RCU=y | ||
14 | CONFIG_RCU_TORTURE_TEST=m | ||
15 | CONFIG_MODULE_UNLOAD=y | ||
16 | CONFIG_SYSFS_DEPRECATED_V2=y | ||
17 | CONFIG_IKCONFIG=y | ||
18 | CONFIG_IKCONFIG_PROC=y | ||
19 | CONFIG_PRINTK_TIME=y | ||
20 | |||
diff --git a/tools/testing/selftests/rcutorture/configs/v3.12/P2-2-t-nh-sd-SMP-hp b/tools/testing/selftests/rcutorture/configs/v3.12/P2-2-t-nh-sd-SMP-hp new file mode 100644 index 000000000000..0f3b667d2a9f --- /dev/null +++ b/tools/testing/selftests/rcutorture/configs/v3.12/P2-2-t-nh-sd-SMP-hp | |||
@@ -0,0 +1,20 @@ | |||
1 | CONFIG_RCU_TRACE=n | ||
2 | CONFIG_NO_HZ=n | ||
3 | CONFIG_SMP=y | ||
4 | CONFIG_RCU_FANOUT=4 | ||
5 | CONFIG_NR_CPUS=8 | ||
6 | CONFIG_RCU_FANOUT_EXACT=n | ||
7 | CONFIG_HOTPLUG_CPU=n | ||
8 | CONFIG_SUSPEND=n | ||
9 | CONFIG_HIBERNATION=n | ||
10 | CONFIG_PREEMPT_NONE=n | ||
11 | CONFIG_PREEMPT_VOLUNTARY=n | ||
12 | CONFIG_PREEMPT=y | ||
13 | #CHECK#CONFIG_TREE_PREEMPT_RCU=y | ||
14 | CONFIG_RCU_TORTURE_TEST=m | ||
15 | CONFIG_MODULE_UNLOAD=y | ||
16 | CONFIG_SYSFS_DEPRECATED_V2=y | ||
17 | CONFIG_IKCONFIG=y | ||
18 | CONFIG_IKCONFIG_PROC=y | ||
19 | CONFIG_PRINTK_TIME=y | ||
20 | |||
diff --git a/tools/testing/selftests/rcutorture/configs/v3.12/P3-3-T-nh-SD-SMP-hp b/tools/testing/selftests/rcutorture/configs/v3.12/P3-3-T-nh-SD-SMP-hp new file mode 100644 index 000000000000..b035e141bf2a --- /dev/null +++ b/tools/testing/selftests/rcutorture/configs/v3.12/P3-3-T-nh-SD-SMP-hp | |||
@@ -0,0 +1,20 @@ | |||
1 | CONFIG_RCU_TRACE=y | ||
2 | CONFIG_NO_HZ=n | ||
3 | CONFIG_SMP=y | ||
4 | CONFIG_RCU_FANOUT=2 | ||
5 | CONFIG_NR_CPUS=8 | ||
6 | CONFIG_RCU_FANOUT_EXACT=n | ||
7 | CONFIG_HOTPLUG_CPU=n | ||
8 | CONFIG_SUSPEND=n | ||
9 | CONFIG_HIBERNATION=n | ||
10 | CONFIG_PREEMPT_NONE=n | ||
11 | CONFIG_PREEMPT_VOLUNTARY=n | ||
12 | CONFIG_PREEMPT=y | ||
13 | #CHECK#CONFIG_TREE_PREEMPT_RCU=y | ||
14 | CONFIG_RCU_TORTURE_TEST=m | ||
15 | CONFIG_MODULE_UNLOAD=y | ||
16 | CONFIG_SYSFS_DEPRECATED_V2=y | ||
17 | CONFIG_IKCONFIG=y | ||
18 | CONFIG_IKCONFIG_PROC=y | ||
19 | CONFIG_PRINTK_TIME=y | ||
20 | |||
diff --git a/tools/testing/selftests/rcutorture/configs/v3.12/P4-A-t-NH-sd-SMP-HP b/tools/testing/selftests/rcutorture/configs/v3.12/P4-A-t-NH-sd-SMP-HP new file mode 100644 index 000000000000..3ccf6a9447f5 --- /dev/null +++ b/tools/testing/selftests/rcutorture/configs/v3.12/P4-A-t-NH-sd-SMP-HP | |||
@@ -0,0 +1,22 @@ | |||
1 | CONFIG_RCU_TRACE=n | ||
2 | CONFIG_NO_HZ=y | ||
3 | CONFIG_SMP=y | ||
4 | CONFIG_RCU_FANOUT=6 | ||
5 | CONFIG_NR_CPUS=8 | ||
6 | CONFIG_RCU_FANOUT_EXACT=n | ||
7 | CONFIG_HOTPLUG_CPU=y | ||
8 | CONFIG_PREEMPT_NONE=n | ||
9 | CONFIG_PREEMPT_VOLUNTARY=n | ||
10 | CONFIG_PREEMPT=y | ||
11 | #CHECK#CONFIG_TREE_PREEMPT_RCU=y | ||
12 | CONFIG_RCU_TORTURE_TEST=m | ||
13 | CONFIG_MODULE_UNLOAD=y | ||
14 | CONFIG_RT_MUTEXES=y | ||
15 | CONFIG_RCU_BOOST=y | ||
16 | CONFIG_RCU_BOOST_PRIO=2 | ||
17 | CONFIG_PROVE_LOCKING=y | ||
18 | CONFIG_PROVE_RCU=y | ||
19 | CONFIG_IKCONFIG=y | ||
20 | CONFIG_IKCONFIG_PROC=y | ||
21 | CONFIG_PRINTK_TIME=y | ||
22 | |||
diff --git a/tools/testing/selftests/rcutorture/configs/v3.12/P5-U-T-NH-sd-SMP-hp b/tools/testing/selftests/rcutorture/configs/v3.12/P5-U-T-NH-sd-SMP-hp new file mode 100644 index 000000000000..ef624ce73d8e --- /dev/null +++ b/tools/testing/selftests/rcutorture/configs/v3.12/P5-U-T-NH-sd-SMP-hp | |||
@@ -0,0 +1,28 @@ | |||
1 | CONFIG_RCU_TRACE=y | ||
2 | CONFIG_RCU_CPU_STALL_INFO=y | ||
3 | CONFIG_NO_HZ=y | ||
4 | CONFIG_SMP=y | ||
5 | CONFIG_RCU_FANOUT=6 | ||
6 | CONFIG_NR_CPUS=8 | ||
7 | CONFIG_RCU_FANOUT_EXACT=y | ||
8 | CONFIG_HOTPLUG_CPU=n | ||
9 | CONFIG_SUSPEND=n | ||
10 | CONFIG_HIBERNATION=n | ||
11 | CONFIG_PREEMPT_NONE=n | ||
12 | CONFIG_PREEMPT_VOLUNTARY=n | ||
13 | CONFIG_PREEMPT=y | ||
14 | #CHECK#CONFIG_TREE_PREEMPT_RCU=y | ||
15 | CONFIG_DEBUG_KERNEL=y | ||
16 | CONFIG_PROVE_RCU_DELAY=y | ||
17 | CONFIG_DEBUG_OBJECTS=y | ||
18 | CONFIG_DEBUG_OBJECTS_RCU_HEAD=y | ||
19 | CONFIG_RT_MUTEXES=y | ||
20 | CONFIG_RCU_BOOST=y | ||
21 | CONFIG_RCU_BOOST_PRIO=2 | ||
22 | CONFIG_RCU_TORTURE_TEST=m | ||
23 | CONFIG_MODULE_UNLOAD=y | ||
24 | CONFIG_SYSFS_DEPRECATED_V2=y | ||
25 | CONFIG_IKCONFIG=y | ||
26 | CONFIG_IKCONFIG_PROC=y | ||
27 | CONFIG_PRINTK_TIME=y | ||
28 | |||
diff --git a/tools/testing/selftests/rcutorture/configs/v3.12/P6---t-nh-SD-smp-hp b/tools/testing/selftests/rcutorture/configs/v3.12/P6---t-nh-SD-smp-hp new file mode 100644 index 000000000000..f4c9175828bf --- /dev/null +++ b/tools/testing/selftests/rcutorture/configs/v3.12/P6---t-nh-SD-smp-hp | |||
@@ -0,0 +1,18 @@ | |||
1 | CONFIG_RCU_TRACE=n | ||
2 | CONFIG_NO_HZ=n | ||
3 | CONFIG_SMP=n | ||
4 | CONFIG_RCU_FANOUT_EXACT=n | ||
5 | CONFIG_HOTPLUG_CPU=n | ||
6 | CONFIG_SUSPEND=n | ||
7 | CONFIG_HIBERNATION=n | ||
8 | CONFIG_PREEMPT_NONE=n | ||
9 | CONFIG_PREEMPT_VOLUNTARY=n | ||
10 | CONFIG_PREEMPT=y | ||
11 | CONFIG_TREE_PREEMPT_RCU=y | ||
12 | CONFIG_RCU_TORTURE_TEST=m | ||
13 | CONFIG_MODULE_UNLOAD=y | ||
14 | CONFIG_SYSFS_DEPRECATED_V2=y | ||
15 | CONFIG_IKCONFIG=y | ||
16 | CONFIG_IKCONFIG_PROC=y | ||
17 | CONFIG_PRINTK_TIME=y | ||
18 | |||
diff --git a/tools/testing/selftests/rcutorture/configs/v3.12/P7-4-T-NH-SD-SMP-HP b/tools/testing/selftests/rcutorture/configs/v3.12/P7-4-T-NH-SD-SMP-HP new file mode 100644 index 000000000000..77a8c5b75763 --- /dev/null +++ b/tools/testing/selftests/rcutorture/configs/v3.12/P7-4-T-NH-SD-SMP-HP | |||
@@ -0,0 +1,30 @@ | |||
1 | CONFIG_RCU_TRACE=y | ||
2 | CONFIG_NO_HZ=y | ||
3 | CONFIG_SMP=y | ||
4 | CONFIG_RCU_FANOUT=2 | ||
5 | CONFIG_NR_CPUS=16 | ||
6 | CONFIG_RCU_FANOUT_EXACT=n | ||
7 | CONFIG_HOTPLUG_CPU=y | ||
8 | CONFIG_RCU_NOCB_CPU=y | ||
9 | CONFIG_RCU_NOCB_CPU_NONE=n | ||
10 | CONFIG_RCU_NOCB_CPU_ZERO=n | ||
11 | CONFIG_RCU_NOCB_CPU_ALL=y | ||
12 | CONFIG_SUSPEND=n | ||
13 | CONFIG_HIBERNATION=n | ||
14 | CONFIG_PREEMPT_NONE=n | ||
15 | CONFIG_PREEMPT_VOLUNTARY=n | ||
16 | CONFIG_PREEMPT=y | ||
17 | #CHECK#CONFIG_TREE_PREEMPT_RCU=y | ||
18 | CONFIG_RCU_TORTURE_TEST=m | ||
19 | CONFIG_MODULE_UNLOAD=y | ||
20 | CONFIG_PROVE_LOCKING=y | ||
21 | CONFIG_PROVE_RCU=y | ||
22 | CONFIG_DEBUG_KERNEL=y | ||
23 | CONFIG_DEBUG_OBJECTS=y | ||
24 | CONFIG_DEBUG_OBJECTS_RCU_HEAD=y | ||
25 | CONFIG_SYSFS_DEPRECATED_V2=y | ||
26 | CONFIG_SLUB=y | ||
27 | CONFIG_IKCONFIG=y | ||
28 | CONFIG_IKCONFIG_PROC=y | ||
29 | CONFIG_PRINTK_TIME=y | ||
30 | |||
diff --git a/tools/testing/selftests/rcutorture/configs/v3.12/P7-4-T-NH-SD-SMP-HP-all b/tools/testing/selftests/rcutorture/configs/v3.12/P7-4-T-NH-SD-SMP-HP-all new file mode 100644 index 000000000000..0eecebc6e95f --- /dev/null +++ b/tools/testing/selftests/rcutorture/configs/v3.12/P7-4-T-NH-SD-SMP-HP-all | |||
@@ -0,0 +1,30 @@ | |||
1 | CONFIG_RCU_TRACE=y | ||
2 | CONFIG_NO_HZ=y | ||
3 | CONFIG_SMP=y | ||
4 | CONFIG_RCU_FANOUT=2 | ||
5 | CONFIG_NR_CPUS=16 | ||
6 | CONFIG_RCU_FANOUT_EXACT=n | ||
7 | CONFIG_HOTPLUG_CPU=y | ||
8 | CONFIG_RCU_NOCB_CPU=y | ||
9 | CONFIG_RCU_NOCB_CPU_NONE=y | ||
10 | CONFIG_RCU_NOCB_CPU_ZERO=n | ||
11 | CONFIG_RCU_NOCB_CPU_ALL=n | ||
12 | CONFIG_SUSPEND=n | ||
13 | CONFIG_HIBERNATION=n | ||
14 | CONFIG_PREEMPT_NONE=n | ||
15 | CONFIG_PREEMPT_VOLUNTARY=n | ||
16 | CONFIG_PREEMPT=y | ||
17 | #CHECK#CONFIG_TREE_PREEMPT_RCU=y | ||
18 | CONFIG_RCU_TORTURE_TEST=m | ||
19 | CONFIG_MODULE_UNLOAD=y | ||
20 | CONFIG_PROVE_LOCKING=y | ||
21 | CONFIG_PROVE_RCU=y | ||
22 | CONFIG_DEBUG_KERNEL=y | ||
23 | CONFIG_DEBUG_OBJECTS=y | ||
24 | CONFIG_DEBUG_OBJECTS_RCU_HEAD=y | ||
25 | CONFIG_SYSFS_DEPRECATED_V2=y | ||
26 | CONFIG_SLUB=y | ||
27 | CONFIG_IKCONFIG=y | ||
28 | CONFIG_IKCONFIG_PROC=y | ||
29 | CONFIG_PRINTK_TIME=y | ||
30 | |||
diff --git a/tools/testing/selftests/rcutorture/configs/v3.12/P7-4-T-NH-SD-SMP-HP-none b/tools/testing/selftests/rcutorture/configs/v3.12/P7-4-T-NH-SD-SMP-HP-none new file mode 100644 index 000000000000..0eecebc6e95f --- /dev/null +++ b/tools/testing/selftests/rcutorture/configs/v3.12/P7-4-T-NH-SD-SMP-HP-none | |||
@@ -0,0 +1,30 @@ | |||
1 | CONFIG_RCU_TRACE=y | ||
2 | CONFIG_NO_HZ=y | ||
3 | CONFIG_SMP=y | ||
4 | CONFIG_RCU_FANOUT=2 | ||
5 | CONFIG_NR_CPUS=16 | ||
6 | CONFIG_RCU_FANOUT_EXACT=n | ||
7 | CONFIG_HOTPLUG_CPU=y | ||
8 | CONFIG_RCU_NOCB_CPU=y | ||
9 | CONFIG_RCU_NOCB_CPU_NONE=y | ||
10 | CONFIG_RCU_NOCB_CPU_ZERO=n | ||
11 | CONFIG_RCU_NOCB_CPU_ALL=n | ||
12 | CONFIG_SUSPEND=n | ||
13 | CONFIG_HIBERNATION=n | ||
14 | CONFIG_PREEMPT_NONE=n | ||
15 | CONFIG_PREEMPT_VOLUNTARY=n | ||
16 | CONFIG_PREEMPT=y | ||
17 | #CHECK#CONFIG_TREE_PREEMPT_RCU=y | ||
18 | CONFIG_RCU_TORTURE_TEST=m | ||
19 | CONFIG_MODULE_UNLOAD=y | ||
20 | CONFIG_PROVE_LOCKING=y | ||
21 | CONFIG_PROVE_RCU=y | ||
22 | CONFIG_DEBUG_KERNEL=y | ||
23 | CONFIG_DEBUG_OBJECTS=y | ||
24 | CONFIG_DEBUG_OBJECTS_RCU_HEAD=y | ||
25 | CONFIG_SYSFS_DEPRECATED_V2=y | ||
26 | CONFIG_SLUB=y | ||
27 | CONFIG_IKCONFIG=y | ||
28 | CONFIG_IKCONFIG_PROC=y | ||
29 | CONFIG_PRINTK_TIME=y | ||
30 | |||
diff --git a/tools/testing/selftests/rcutorture/configs/v3.12/P7-4-T-NH-SD-SMP-hp b/tools/testing/selftests/rcutorture/configs/v3.12/P7-4-T-NH-SD-SMP-hp new file mode 100644 index 000000000000..588bc70420cd --- /dev/null +++ b/tools/testing/selftests/rcutorture/configs/v3.12/P7-4-T-NH-SD-SMP-hp | |||
@@ -0,0 +1,30 @@ | |||
1 | CONFIG_RCU_TRACE=y | ||
2 | CONFIG_NO_HZ=y | ||
3 | CONFIG_SMP=y | ||
4 | CONFIG_RCU_FANOUT=2 | ||
5 | CONFIG_NR_CPUS=16 | ||
6 | CONFIG_RCU_FANOUT_EXACT=n | ||
7 | CONFIG_HOTPLUG_CPU=n | ||
8 | CONFIG_RCU_NOCB_CPU=y | ||
9 | CONFIG_RCU_NOCB_CPU_NONE=n | ||
10 | CONFIG_RCU_NOCB_CPU_ZERO=y | ||
11 | CONFIG_RCU_NOCB_CPU_ALL=n | ||
12 | CONFIG_SUSPEND=n | ||
13 | CONFIG_HIBERNATION=n | ||
14 | CONFIG_PREEMPT_NONE=n | ||
15 | CONFIG_PREEMPT_VOLUNTARY=n | ||
16 | CONFIG_PREEMPT=y | ||
17 | #CHECK#CONFIG_TREE_PREEMPT_RCU=y | ||
18 | CONFIG_RCU_TORTURE_TEST=m | ||
19 | CONFIG_MODULE_UNLOAD=y | ||
20 | CONFIG_PROVE_LOCKING=y | ||
21 | CONFIG_PROVE_RCU=y | ||
22 | CONFIG_DEBUG_KERNEL=y | ||
23 | CONFIG_DEBUG_OBJECTS=y | ||
24 | CONFIG_DEBUG_OBJECTS_RCU_HEAD=y | ||
25 | CONFIG_SYSFS_DEPRECATED_V2=y | ||
26 | CONFIG_SLUB=y | ||
27 | CONFIG_IKCONFIG=y | ||
28 | CONFIG_IKCONFIG_PROC=y | ||
29 | CONFIG_PRINTK_TIME=y | ||
30 | |||
diff --git a/tools/testing/selftests/rcutorture/configs/v3.12/PT1-nh b/tools/testing/selftests/rcutorture/configs/v3.12/PT1-nh new file mode 100644 index 000000000000..e3361c3894a1 --- /dev/null +++ b/tools/testing/selftests/rcutorture/configs/v3.12/PT1-nh | |||
@@ -0,0 +1,23 @@ | |||
1 | CONFIG_TINY_PREEMPT_RCU=y | ||
2 | CONFIG_RCU_BOOST=y | ||
3 | CONFIG_RCU_BOOST_PRIO=2 | ||
4 | CONFIG_RCU_TRACE=y | ||
5 | CONFIG_RCU_TORTURE_TEST=m | ||
6 | CONFIG_MODULE_UNLOAD=y | ||
7 | CONFIG_SUSPEND=n | ||
8 | CONFIG_HIBERNATION=n | ||
9 | # | ||
10 | CONFIG_SMP=n | ||
11 | # | ||
12 | CONFIG_HOTPLUG_CPU=n | ||
13 | # | ||
14 | CONFIG_NO_HZ=n | ||
15 | # | ||
16 | CONFIG_PREEMPT_NONE=n | ||
17 | CONFIG_PREEMPT_VOLUNTARY=n | ||
18 | CONFIG_PREEMPT=y | ||
19 | CONFIG_SYSFS_DEPRECATED_V2=y | ||
20 | CONFIG_IKCONFIG=y | ||
21 | CONFIG_IKCONFIG_PROC=y | ||
22 | CONFIG_PRINTK_TIME=y | ||
23 | |||
diff --git a/tools/testing/selftests/rcutorture/configs/v3.12/PT2-NH b/tools/testing/selftests/rcutorture/configs/v3.12/PT2-NH new file mode 100644 index 000000000000..64abfc3b4d94 --- /dev/null +++ b/tools/testing/selftests/rcutorture/configs/v3.12/PT2-NH | |||
@@ -0,0 +1,22 @@ | |||
1 | CONFIG_TINY_PREEMPT_RCU=y | ||
2 | CONFIG_RCU_TORTURE_TEST=m | ||
3 | CONFIG_MODULE_UNLOAD=y | ||
4 | CONFIG_SUSPEND=n | ||
5 | CONFIG_HIBERNATION=n | ||
6 | # | ||
7 | CONFIG_SMP=n | ||
8 | # | ||
9 | CONFIG_HOTPLUG_CPU=n | ||
10 | # | ||
11 | CONFIG_NO_HZ=y | ||
12 | # | ||
13 | CONFIG_PREEMPT_NONE=n | ||
14 | CONFIG_PREEMPT_VOLUNTARY=n | ||
15 | CONFIG_PREEMPT=y | ||
16 | CONFIG_PROVE_LOCKING=y | ||
17 | CONFIG_PROVE_RCU=y | ||
18 | CONFIG_SYSFS_DEPRECATED_V2=y | ||
19 | CONFIG_IKCONFIG=y | ||
20 | CONFIG_IKCONFIG_PROC=y | ||
21 | CONFIG_PRINTK_TIME=y | ||
22 | |||
diff --git a/tools/testing/selftests/rcutorture/configs/v3.3/CFLIST b/tools/testing/selftests/rcutorture/configs/v3.3/CFLIST new file mode 100644 index 000000000000..18223947bbcb --- /dev/null +++ b/tools/testing/selftests/rcutorture/configs/v3.3/CFLIST | |||
@@ -0,0 +1,14 @@ | |||
1 | P1-S-T-NH-SD-SMP-HP | ||
2 | P2-2-t-nh-sd-SMP-hp | ||
3 | P3-3-T-nh-SD-SMP-hp | ||
4 | P4-A-t-NH-sd-SMP-HP | ||
5 | P5-U-T-NH-sd-SMP-hp | ||
6 | N1-S-T-NH-SD-SMP-HP | ||
7 | N2-2-t-nh-sd-SMP-hp | ||
8 | N3-3-T-nh-SD-SMP-hp | ||
9 | N4-A-t-NH-sd-SMP-HP | ||
10 | N5-U-T-NH-sd-SMP-hp | ||
11 | PT1-nh | ||
12 | PT2-NH | ||
13 | NT1-nh | ||
14 | NT3-NH | ||
diff --git a/tools/testing/selftests/rcutorture/configs/v3.3/N1-S-T-NH-SD-SMP-HP b/tools/testing/selftests/rcutorture/configs/v3.3/N1-S-T-NH-SD-SMP-HP new file mode 100644 index 000000000000..d81e11d280aa --- /dev/null +++ b/tools/testing/selftests/rcutorture/configs/v3.3/N1-S-T-NH-SD-SMP-HP | |||
@@ -0,0 +1,19 @@ | |||
1 | CONFIG_RCU_TRACE=y | ||
2 | CONFIG_RCU_FAST_NO_HZ=y | ||
3 | CONFIG_NO_HZ=y | ||
4 | CONFIG_SMP=y | ||
5 | CONFIG_RCU_FANOUT=8 | ||
6 | CONFIG_NR_CPUS=8 | ||
7 | CONFIG_RCU_FANOUT_EXACT=n | ||
8 | CONFIG_HOTPLUG_CPU=y | ||
9 | CONFIG_PREEMPT_NONE=y | ||
10 | CONFIG_PREEMPT_VOLUNTARY=n | ||
11 | CONFIG_PREEMPT=n | ||
12 | #CHECK#CONFIG_TREE_RCU=y | ||
13 | CONFIG_RCU_TORTURE_TEST=m | ||
14 | CONFIG_MODULE_UNLOAD=y | ||
15 | CONFIG_SYSFS_DEPRECATED_V2=y | ||
16 | CONFIG_IKCONFIG=y | ||
17 | CONFIG_IKCONFIG_PROC=y | ||
18 | CONFIG_PRINTK_TIME=y | ||
19 | |||
diff --git a/tools/testing/selftests/rcutorture/configs/v3.3/N2-2-t-nh-sd-SMP-hp b/tools/testing/selftests/rcutorture/configs/v3.3/N2-2-t-nh-sd-SMP-hp new file mode 100644 index 000000000000..02e418572b1b --- /dev/null +++ b/tools/testing/selftests/rcutorture/configs/v3.3/N2-2-t-nh-sd-SMP-hp | |||
@@ -0,0 +1,20 @@ | |||
1 | CONFIG_RCU_TRACE=n | ||
2 | CONFIG_NO_HZ=n | ||
3 | CONFIG_SMP=y | ||
4 | CONFIG_RCU_FANOUT=4 | ||
5 | CONFIG_NR_CPUS=8 | ||
6 | CONFIG_RCU_FANOUT_EXACT=n | ||
7 | CONFIG_HOTPLUG_CPU=n | ||
8 | CONFIG_SUSPEND=n | ||
9 | CONFIG_HIBERNATION=n | ||
10 | CONFIG_PREEMPT_NONE=y | ||
11 | CONFIG_PREEMPT_VOLUNTARY=n | ||
12 | CONFIG_PREEMPT=n | ||
13 | #CHECK#CONFIG_TREE_RCU=y | ||
14 | CONFIG_RCU_TORTURE_TEST=m | ||
15 | CONFIG_MODULE_UNLOAD=y | ||
16 | CONFIG_SYSFS_DEPRECATED_V2=y | ||
17 | CONFIG_IKCONFIG=y | ||
18 | CONFIG_IKCONFIG_PROC=y | ||
19 | CONFIG_PRINTK_TIME=y | ||
20 | |||
diff --git a/tools/testing/selftests/rcutorture/configs/v3.3/N3-3-T-nh-SD-SMP-hp b/tools/testing/selftests/rcutorture/configs/v3.3/N3-3-T-nh-SD-SMP-hp new file mode 100644 index 000000000000..b3100f69c8cf --- /dev/null +++ b/tools/testing/selftests/rcutorture/configs/v3.3/N3-3-T-nh-SD-SMP-hp | |||
@@ -0,0 +1,22 @@ | |||
1 | CONFIG_RCU_TRACE=y | ||
2 | CONFIG_NO_HZ=n | ||
3 | CONFIG_SMP=y | ||
4 | CONFIG_RCU_FANOUT=2 | ||
5 | CONFIG_NR_CPUS=8 | ||
6 | CONFIG_RCU_FANOUT_EXACT=n | ||
7 | CONFIG_HOTPLUG_CPU=n | ||
8 | CONFIG_SUSPEND=n | ||
9 | CONFIG_HIBERNATION=n | ||
10 | CONFIG_PREEMPT_NONE=y | ||
11 | CONFIG_PREEMPT_VOLUNTARY=n | ||
12 | CONFIG_PREEMPT=n | ||
13 | #CHECK#CONFIG_TREE_RCU=y | ||
14 | CONFIG_RCU_TORTURE_TEST=m | ||
15 | CONFIG_MODULE_UNLOAD=y | ||
16 | CONFIG_PROVE_LOCKING=y | ||
17 | CONFIG_PROVE_RCU=y | ||
18 | CONFIG_SYSFS_DEPRECATED_V2=y | ||
19 | CONFIG_IKCONFIG=y | ||
20 | CONFIG_IKCONFIG_PROC=y | ||
21 | CONFIG_PRINTK_TIME=y | ||
22 | |||
diff --git a/tools/testing/selftests/rcutorture/configs/v3.3/N4-A-t-NH-sd-SMP-HP b/tools/testing/selftests/rcutorture/configs/v3.3/N4-A-t-NH-sd-SMP-HP new file mode 100644 index 000000000000..c56b44530725 --- /dev/null +++ b/tools/testing/selftests/rcutorture/configs/v3.3/N4-A-t-NH-sd-SMP-HP | |||
@@ -0,0 +1,18 @@ | |||
1 | CONFIG_RCU_TRACE=n | ||
2 | CONFIG_NO_HZ=y | ||
3 | CONFIG_SMP=y | ||
4 | CONFIG_RCU_FANOUT=6 | ||
5 | CONFIG_NR_CPUS=8 | ||
6 | CONFIG_RCU_FANOUT_EXACT=n | ||
7 | CONFIG_HOTPLUG_CPU=y | ||
8 | CONFIG_PREEMPT_NONE=y | ||
9 | CONFIG_PREEMPT_VOLUNTARY=n | ||
10 | CONFIG_PREEMPT=n | ||
11 | #CHECK#CONFIG_TREE_RCU=y | ||
12 | CONFIG_RCU_TORTURE_TEST=m | ||
13 | CONFIG_MODULE_UNLOAD=y | ||
14 | CONFIG_SYSFS_DEPRECATED_V2=y | ||
15 | CONFIG_IKCONFIG=y | ||
16 | CONFIG_IKCONFIG_PROC=y | ||
17 | CONFIG_PRINTK_TIME=y | ||
18 | |||
diff --git a/tools/testing/selftests/rcutorture/configs/v3.3/N5-U-T-NH-sd-SMP-hp b/tools/testing/selftests/rcutorture/configs/v3.3/N5-U-T-NH-sd-SMP-hp new file mode 100644 index 000000000000..90d924fea9e9 --- /dev/null +++ b/tools/testing/selftests/rcutorture/configs/v3.3/N5-U-T-NH-sd-SMP-hp | |||
@@ -0,0 +1,22 @@ | |||
1 | CONFIG_RCU_TRACE=y | ||
2 | CONFIG_DEBUG_KERNEL=y | ||
3 | CONFIG_RCU_CPU_STALL_INFO=y | ||
4 | CONFIG_NO_HZ=y | ||
5 | CONFIG_SMP=y | ||
6 | CONFIG_RCU_FANOUT=6 | ||
7 | CONFIG_NR_CPUS=8 | ||
8 | CONFIG_RCU_FANOUT_EXACT=y | ||
9 | CONFIG_HOTPLUG_CPU=n | ||
10 | CONFIG_SUSPEND=n | ||
11 | CONFIG_HIBERNATION=n | ||
12 | CONFIG_PREEMPT_NONE=y | ||
13 | CONFIG_PREEMPT_VOLUNTARY=n | ||
14 | CONFIG_PREEMPT=n | ||
15 | #CHECK#CONFIG_TREE_RCU=y | ||
16 | CONFIG_RCU_TORTURE_TEST=m | ||
17 | CONFIG_MODULE_UNLOAD=y | ||
18 | CONFIG_SYSFS_DEPRECATED_V2=y | ||
19 | CONFIG_IKCONFIG=y | ||
20 | CONFIG_IKCONFIG_PROC=y | ||
21 | CONFIG_PRINTK_TIME=y | ||
22 | |||
diff --git a/tools/testing/selftests/rcutorture/configs/v3.3/NT1-nh b/tools/testing/selftests/rcutorture/configs/v3.3/NT1-nh new file mode 100644 index 000000000000..023f312a931c --- /dev/null +++ b/tools/testing/selftests/rcutorture/configs/v3.3/NT1-nh | |||
@@ -0,0 +1,23 @@ | |||
1 | #CHECK#CONFIG_TINY_RCU=y | ||
2 | CONFIG_RCU_TRACE=y | ||
3 | CONFIG_RCU_TORTURE_TEST=m | ||
4 | CONFIG_MODULE_UNLOAD=y | ||
5 | CONFIG_SUSPEND=n | ||
6 | CONFIG_HIBERNATION=n | ||
7 | # | ||
8 | CONFIG_SMP=n | ||
9 | # | ||
10 | CONFIG_HOTPLUG_CPU=n | ||
11 | # | ||
12 | CONFIG_NO_HZ=n | ||
13 | # | ||
14 | CONFIG_PREEMPT_NONE=y | ||
15 | CONFIG_PREEMPT_VOLUNTARY=n | ||
16 | CONFIG_PREEMPT=n | ||
17 | CONFIG_PROVE_LOCKING=y | ||
18 | CONFIG_PROVE_RCU=y | ||
19 | CONFIG_SYSFS_DEPRECATED_V2=y | ||
20 | CONFIG_IKCONFIG=y | ||
21 | CONFIG_IKCONFIG_PROC=y | ||
22 | CONFIG_PRINTK_TIME=y | ||
23 | |||
diff --git a/tools/testing/selftests/rcutorture/configs/v3.3/NT3-NH b/tools/testing/selftests/rcutorture/configs/v3.3/NT3-NH new file mode 100644 index 000000000000..6fd0235dae73 --- /dev/null +++ b/tools/testing/selftests/rcutorture/configs/v3.3/NT3-NH | |||
@@ -0,0 +1,20 @@ | |||
1 | #CHECK#CONFIG_TINY_RCU=y | ||
2 | CONFIG_RCU_TORTURE_TEST=m | ||
3 | CONFIG_MODULE_UNLOAD=y | ||
4 | CONFIG_SUSPEND=n | ||
5 | CONFIG_HIBERNATION=n | ||
6 | # | ||
7 | CONFIG_SMP=n | ||
8 | # | ||
9 | CONFIG_HOTPLUG_CPU=n | ||
10 | # | ||
11 | CONFIG_NO_HZ=y | ||
12 | # | ||
13 | CONFIG_PREEMPT_NONE=y | ||
14 | CONFIG_PREEMPT_VOLUNTARY=n | ||
15 | CONFIG_PREEMPT=n | ||
16 | CONFIG_SYSFS_DEPRECATED_V2=y | ||
17 | CONFIG_IKCONFIG=y | ||
18 | CONFIG_IKCONFIG_PROC=y | ||
19 | CONFIG_PRINTK_TIME=y | ||
20 | |||
diff --git a/tools/testing/selftests/rcutorture/configs/v3.3/P1-S-T-NH-SD-SMP-HP b/tools/testing/selftests/rcutorture/configs/v3.3/P1-S-T-NH-SD-SMP-HP new file mode 100644 index 000000000000..9647c44cf4b7 --- /dev/null +++ b/tools/testing/selftests/rcutorture/configs/v3.3/P1-S-T-NH-SD-SMP-HP | |||
@@ -0,0 +1,20 @@ | |||
1 | CONFIG_RCU_TRACE=y | ||
2 | CONFIG_RCU_CPU_STALL_INFO=y | ||
3 | CONFIG_NO_HZ=y | ||
4 | CONFIG_RCU_FAST_NO_HZ=y | ||
5 | CONFIG_SMP=y | ||
6 | CONFIG_RCU_FANOUT=8 | ||
7 | CONFIG_NR_CPUS=8 | ||
8 | CONFIG_RCU_FANOUT_EXACT=n | ||
9 | CONFIG_HOTPLUG_CPU=y | ||
10 | CONFIG_PREEMPT_NONE=n | ||
11 | CONFIG_PREEMPT_VOLUNTARY=n | ||
12 | CONFIG_PREEMPT=y | ||
13 | #CHECK#CONFIG_TREE_PREEMPT_RCU=y | ||
14 | CONFIG_RCU_TORTURE_TEST=m | ||
15 | CONFIG_MODULE_UNLOAD=y | ||
16 | CONFIG_SYSFS_DEPRECATED_V2=y | ||
17 | CONFIG_IKCONFIG=y | ||
18 | CONFIG_IKCONFIG_PROC=y | ||
19 | CONFIG_PRINTK_TIME=y | ||
20 | |||
diff --git a/tools/testing/selftests/rcutorture/configs/v3.3/P2-2-t-nh-sd-SMP-hp b/tools/testing/selftests/rcutorture/configs/v3.3/P2-2-t-nh-sd-SMP-hp new file mode 100644 index 000000000000..0f3b667d2a9f --- /dev/null +++ b/tools/testing/selftests/rcutorture/configs/v3.3/P2-2-t-nh-sd-SMP-hp | |||
@@ -0,0 +1,20 @@ | |||
1 | CONFIG_RCU_TRACE=n | ||
2 | CONFIG_NO_HZ=n | ||
3 | CONFIG_SMP=y | ||
4 | CONFIG_RCU_FANOUT=4 | ||
5 | CONFIG_NR_CPUS=8 | ||
6 | CONFIG_RCU_FANOUT_EXACT=n | ||
7 | CONFIG_HOTPLUG_CPU=n | ||
8 | CONFIG_SUSPEND=n | ||
9 | CONFIG_HIBERNATION=n | ||
10 | CONFIG_PREEMPT_NONE=n | ||
11 | CONFIG_PREEMPT_VOLUNTARY=n | ||
12 | CONFIG_PREEMPT=y | ||
13 | #CHECK#CONFIG_TREE_PREEMPT_RCU=y | ||
14 | CONFIG_RCU_TORTURE_TEST=m | ||
15 | CONFIG_MODULE_UNLOAD=y | ||
16 | CONFIG_SYSFS_DEPRECATED_V2=y | ||
17 | CONFIG_IKCONFIG=y | ||
18 | CONFIG_IKCONFIG_PROC=y | ||
19 | CONFIG_PRINTK_TIME=y | ||
20 | |||
diff --git a/tools/testing/selftests/rcutorture/configs/v3.3/P3-3-T-nh-SD-SMP-hp b/tools/testing/selftests/rcutorture/configs/v3.3/P3-3-T-nh-SD-SMP-hp new file mode 100644 index 000000000000..b035e141bf2a --- /dev/null +++ b/tools/testing/selftests/rcutorture/configs/v3.3/P3-3-T-nh-SD-SMP-hp | |||
@@ -0,0 +1,20 @@ | |||
1 | CONFIG_RCU_TRACE=y | ||
2 | CONFIG_NO_HZ=n | ||
3 | CONFIG_SMP=y | ||
4 | CONFIG_RCU_FANOUT=2 | ||
5 | CONFIG_NR_CPUS=8 | ||
6 | CONFIG_RCU_FANOUT_EXACT=n | ||
7 | CONFIG_HOTPLUG_CPU=n | ||
8 | CONFIG_SUSPEND=n | ||
9 | CONFIG_HIBERNATION=n | ||
10 | CONFIG_PREEMPT_NONE=n | ||
11 | CONFIG_PREEMPT_VOLUNTARY=n | ||
12 | CONFIG_PREEMPT=y | ||
13 | #CHECK#CONFIG_TREE_PREEMPT_RCU=y | ||
14 | CONFIG_RCU_TORTURE_TEST=m | ||
15 | CONFIG_MODULE_UNLOAD=y | ||
16 | CONFIG_SYSFS_DEPRECATED_V2=y | ||
17 | CONFIG_IKCONFIG=y | ||
18 | CONFIG_IKCONFIG_PROC=y | ||
19 | CONFIG_PRINTK_TIME=y | ||
20 | |||
diff --git a/tools/testing/selftests/rcutorture/configs/v3.3/P4-A-t-NH-sd-SMP-HP b/tools/testing/selftests/rcutorture/configs/v3.3/P4-A-t-NH-sd-SMP-HP new file mode 100644 index 000000000000..3ccf6a9447f5 --- /dev/null +++ b/tools/testing/selftests/rcutorture/configs/v3.3/P4-A-t-NH-sd-SMP-HP | |||
@@ -0,0 +1,22 @@ | |||
1 | CONFIG_RCU_TRACE=n | ||
2 | CONFIG_NO_HZ=y | ||
3 | CONFIG_SMP=y | ||
4 | CONFIG_RCU_FANOUT=6 | ||
5 | CONFIG_NR_CPUS=8 | ||
6 | CONFIG_RCU_FANOUT_EXACT=n | ||
7 | CONFIG_HOTPLUG_CPU=y | ||
8 | CONFIG_PREEMPT_NONE=n | ||
9 | CONFIG_PREEMPT_VOLUNTARY=n | ||
10 | CONFIG_PREEMPT=y | ||
11 | #CHECK#CONFIG_TREE_PREEMPT_RCU=y | ||
12 | CONFIG_RCU_TORTURE_TEST=m | ||
13 | CONFIG_MODULE_UNLOAD=y | ||
14 | CONFIG_RT_MUTEXES=y | ||
15 | CONFIG_RCU_BOOST=y | ||
16 | CONFIG_RCU_BOOST_PRIO=2 | ||
17 | CONFIG_PROVE_LOCKING=y | ||
18 | CONFIG_PROVE_RCU=y | ||
19 | CONFIG_IKCONFIG=y | ||
20 | CONFIG_IKCONFIG_PROC=y | ||
21 | CONFIG_PRINTK_TIME=y | ||
22 | |||
diff --git a/tools/testing/selftests/rcutorture/configs/v3.3/P5-U-T-NH-sd-SMP-hp b/tools/testing/selftests/rcutorture/configs/v3.3/P5-U-T-NH-sd-SMP-hp new file mode 100644 index 000000000000..ef624ce73d8e --- /dev/null +++ b/tools/testing/selftests/rcutorture/configs/v3.3/P5-U-T-NH-sd-SMP-hp | |||
@@ -0,0 +1,28 @@ | |||
1 | CONFIG_RCU_TRACE=y | ||
2 | CONFIG_RCU_CPU_STALL_INFO=y | ||
3 | CONFIG_NO_HZ=y | ||
4 | CONFIG_SMP=y | ||
5 | CONFIG_RCU_FANOUT=6 | ||
6 | CONFIG_NR_CPUS=8 | ||
7 | CONFIG_RCU_FANOUT_EXACT=y | ||
8 | CONFIG_HOTPLUG_CPU=n | ||
9 | CONFIG_SUSPEND=n | ||
10 | CONFIG_HIBERNATION=n | ||
11 | CONFIG_PREEMPT_NONE=n | ||
12 | CONFIG_PREEMPT_VOLUNTARY=n | ||
13 | CONFIG_PREEMPT=y | ||
14 | #CHECK#CONFIG_TREE_PREEMPT_RCU=y | ||
15 | CONFIG_DEBUG_KERNEL=y | ||
16 | CONFIG_PROVE_RCU_DELAY=y | ||
17 | CONFIG_DEBUG_OBJECTS=y | ||
18 | CONFIG_DEBUG_OBJECTS_RCU_HEAD=y | ||
19 | CONFIG_RT_MUTEXES=y | ||
20 | CONFIG_RCU_BOOST=y | ||
21 | CONFIG_RCU_BOOST_PRIO=2 | ||
22 | CONFIG_RCU_TORTURE_TEST=m | ||
23 | CONFIG_MODULE_UNLOAD=y | ||
24 | CONFIG_SYSFS_DEPRECATED_V2=y | ||
25 | CONFIG_IKCONFIG=y | ||
26 | CONFIG_IKCONFIG_PROC=y | ||
27 | CONFIG_PRINTK_TIME=y | ||
28 | |||
diff --git a/tools/testing/selftests/rcutorture/configs/v3.3/PT1-nh b/tools/testing/selftests/rcutorture/configs/v3.3/PT1-nh new file mode 100644 index 000000000000..e3361c3894a1 --- /dev/null +++ b/tools/testing/selftests/rcutorture/configs/v3.3/PT1-nh | |||
@@ -0,0 +1,23 @@ | |||
1 | CONFIG_TINY_PREEMPT_RCU=y | ||
2 | CONFIG_RCU_BOOST=y | ||
3 | CONFIG_RCU_BOOST_PRIO=2 | ||
4 | CONFIG_RCU_TRACE=y | ||
5 | CONFIG_RCU_TORTURE_TEST=m | ||
6 | CONFIG_MODULE_UNLOAD=y | ||
7 | CONFIG_SUSPEND=n | ||
8 | CONFIG_HIBERNATION=n | ||
9 | # | ||
10 | CONFIG_SMP=n | ||
11 | # | ||
12 | CONFIG_HOTPLUG_CPU=n | ||
13 | # | ||
14 | CONFIG_NO_HZ=n | ||
15 | # | ||
16 | CONFIG_PREEMPT_NONE=n | ||
17 | CONFIG_PREEMPT_VOLUNTARY=n | ||
18 | CONFIG_PREEMPT=y | ||
19 | CONFIG_SYSFS_DEPRECATED_V2=y | ||
20 | CONFIG_IKCONFIG=y | ||
21 | CONFIG_IKCONFIG_PROC=y | ||
22 | CONFIG_PRINTK_TIME=y | ||
23 | |||
diff --git a/tools/testing/selftests/rcutorture/configs/v3.3/PT2-NH b/tools/testing/selftests/rcutorture/configs/v3.3/PT2-NH new file mode 100644 index 000000000000..64abfc3b4d94 --- /dev/null +++ b/tools/testing/selftests/rcutorture/configs/v3.3/PT2-NH | |||
@@ -0,0 +1,22 @@ | |||
1 | CONFIG_TINY_PREEMPT_RCU=y | ||
2 | CONFIG_RCU_TORTURE_TEST=m | ||
3 | CONFIG_MODULE_UNLOAD=y | ||
4 | CONFIG_SUSPEND=n | ||
5 | CONFIG_HIBERNATION=n | ||
6 | # | ||
7 | CONFIG_SMP=n | ||
8 | # | ||
9 | CONFIG_HOTPLUG_CPU=n | ||
10 | # | ||
11 | CONFIG_NO_HZ=y | ||
12 | # | ||
13 | CONFIG_PREEMPT_NONE=n | ||
14 | CONFIG_PREEMPT_VOLUNTARY=n | ||
15 | CONFIG_PREEMPT=y | ||
16 | CONFIG_PROVE_LOCKING=y | ||
17 | CONFIG_PROVE_RCU=y | ||
18 | CONFIG_SYSFS_DEPRECATED_V2=y | ||
19 | CONFIG_IKCONFIG=y | ||
20 | CONFIG_IKCONFIG_PROC=y | ||
21 | CONFIG_PRINTK_TIME=y | ||
22 | |||
diff --git a/tools/testing/selftests/rcutorture/configs/v3.3/ver_functions.sh b/tools/testing/selftests/rcutorture/configs/v3.3/ver_functions.sh new file mode 100644 index 000000000000..c37432f3572c --- /dev/null +++ b/tools/testing/selftests/rcutorture/configs/v3.3/ver_functions.sh | |||
@@ -0,0 +1,41 @@ | |||
1 | #!/bin/bash | ||
2 | # | ||
3 | # Kernel-version-dependent shell functions for the rest of the scripts. | ||
4 | # | ||
5 | # This program is free software; you can redistribute it and/or modify | ||
6 | # it under the terms of the GNU General Public License as published by | ||
7 | # the Free Software Foundation; either version 2 of the License, or | ||
8 | # (at your option) any later version. | ||
9 | # | ||
10 | # This program is distributed in the hope that it will be useful, | ||
11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | # GNU General Public License for more details. | ||
14 | # | ||
15 | # You should have received a copy of the GNU General Public License | ||
16 | # along with this program; if not, you can access it online at | ||
17 | # http://www.gnu.org/licenses/gpl-2.0.html. | ||
18 | # | ||
19 | # Copyright (C) IBM Corporation, 2013 | ||
20 | # | ||
21 | # Authors: Paul E. McKenney <paulmck@linux.vnet.ibm.com> | ||
22 | |||
23 | # rcutorture_param_n_barrier_cbs bootparam-string | ||
24 | # | ||
25 | # Adds n_barrier_cbs rcutorture module parameter to kernels having it. | ||
26 | rcutorture_param_n_barrier_cbs () { | ||
27 | echo $1 | ||
28 | } | ||
29 | |||
30 | # rcutorture_param_onoff bootparam-string config-file | ||
31 | # | ||
32 | # Adds onoff rcutorture module parameters to kernels having it. | ||
33 | rcutorture_param_onoff () { | ||
34 | if ! bootparam_hotplug_cpu "$1" && configfrag_hotplug_cpu "$2" | ||
35 | then | ||
36 | echo CPU-hotplug kernel, adding rcutorture onoff. | ||
37 | echo $1 rcutorture.onoff_interval=3 rcutorture.onoff_holdoff=30 | ||
38 | else | ||
39 | echo $1 | ||
40 | fi | ||
41 | } | ||
diff --git a/tools/testing/selftests/rcutorture/configs/v3.5/CFLIST b/tools/testing/selftests/rcutorture/configs/v3.5/CFLIST new file mode 100644 index 000000000000..18223947bbcb --- /dev/null +++ b/tools/testing/selftests/rcutorture/configs/v3.5/CFLIST | |||
@@ -0,0 +1,14 @@ | |||
1 | P1-S-T-NH-SD-SMP-HP | ||
2 | P2-2-t-nh-sd-SMP-hp | ||
3 | P3-3-T-nh-SD-SMP-hp | ||
4 | P4-A-t-NH-sd-SMP-HP | ||
5 | P5-U-T-NH-sd-SMP-hp | ||
6 | N1-S-T-NH-SD-SMP-HP | ||
7 | N2-2-t-nh-sd-SMP-hp | ||
8 | N3-3-T-nh-SD-SMP-hp | ||
9 | N4-A-t-NH-sd-SMP-HP | ||
10 | N5-U-T-NH-sd-SMP-hp | ||
11 | PT1-nh | ||
12 | PT2-NH | ||
13 | NT1-nh | ||
14 | NT3-NH | ||
diff --git a/tools/testing/selftests/rcutorture/configs/v3.5/N1-S-T-NH-SD-SMP-HP b/tools/testing/selftests/rcutorture/configs/v3.5/N1-S-T-NH-SD-SMP-HP new file mode 100644 index 000000000000..d81e11d280aa --- /dev/null +++ b/tools/testing/selftests/rcutorture/configs/v3.5/N1-S-T-NH-SD-SMP-HP | |||
@@ -0,0 +1,19 @@ | |||
1 | CONFIG_RCU_TRACE=y | ||
2 | CONFIG_RCU_FAST_NO_HZ=y | ||
3 | CONFIG_NO_HZ=y | ||
4 | CONFIG_SMP=y | ||
5 | CONFIG_RCU_FANOUT=8 | ||
6 | CONFIG_NR_CPUS=8 | ||
7 | CONFIG_RCU_FANOUT_EXACT=n | ||
8 | CONFIG_HOTPLUG_CPU=y | ||
9 | CONFIG_PREEMPT_NONE=y | ||
10 | CONFIG_PREEMPT_VOLUNTARY=n | ||
11 | CONFIG_PREEMPT=n | ||
12 | #CHECK#CONFIG_TREE_RCU=y | ||
13 | CONFIG_RCU_TORTURE_TEST=m | ||
14 | CONFIG_MODULE_UNLOAD=y | ||
15 | CONFIG_SYSFS_DEPRECATED_V2=y | ||
16 | CONFIG_IKCONFIG=y | ||
17 | CONFIG_IKCONFIG_PROC=y | ||
18 | CONFIG_PRINTK_TIME=y | ||
19 | |||
diff --git a/tools/testing/selftests/rcutorture/configs/v3.5/N2-2-t-nh-sd-SMP-hp b/tools/testing/selftests/rcutorture/configs/v3.5/N2-2-t-nh-sd-SMP-hp new file mode 100644 index 000000000000..02e418572b1b --- /dev/null +++ b/tools/testing/selftests/rcutorture/configs/v3.5/N2-2-t-nh-sd-SMP-hp | |||
@@ -0,0 +1,20 @@ | |||
1 | CONFIG_RCU_TRACE=n | ||
2 | CONFIG_NO_HZ=n | ||
3 | CONFIG_SMP=y | ||
4 | CONFIG_RCU_FANOUT=4 | ||
5 | CONFIG_NR_CPUS=8 | ||
6 | CONFIG_RCU_FANOUT_EXACT=n | ||
7 | CONFIG_HOTPLUG_CPU=n | ||
8 | CONFIG_SUSPEND=n | ||
9 | CONFIG_HIBERNATION=n | ||
10 | CONFIG_PREEMPT_NONE=y | ||
11 | CONFIG_PREEMPT_VOLUNTARY=n | ||
12 | CONFIG_PREEMPT=n | ||
13 | #CHECK#CONFIG_TREE_RCU=y | ||
14 | CONFIG_RCU_TORTURE_TEST=m | ||
15 | CONFIG_MODULE_UNLOAD=y | ||
16 | CONFIG_SYSFS_DEPRECATED_V2=y | ||
17 | CONFIG_IKCONFIG=y | ||
18 | CONFIG_IKCONFIG_PROC=y | ||
19 | CONFIG_PRINTK_TIME=y | ||
20 | |||
diff --git a/tools/testing/selftests/rcutorture/configs/v3.5/N3-3-T-nh-SD-SMP-hp b/tools/testing/selftests/rcutorture/configs/v3.5/N3-3-T-nh-SD-SMP-hp new file mode 100644 index 000000000000..b3100f69c8cf --- /dev/null +++ b/tools/testing/selftests/rcutorture/configs/v3.5/N3-3-T-nh-SD-SMP-hp | |||
@@ -0,0 +1,22 @@ | |||
1 | CONFIG_RCU_TRACE=y | ||
2 | CONFIG_NO_HZ=n | ||
3 | CONFIG_SMP=y | ||
4 | CONFIG_RCU_FANOUT=2 | ||
5 | CONFIG_NR_CPUS=8 | ||
6 | CONFIG_RCU_FANOUT_EXACT=n | ||
7 | CONFIG_HOTPLUG_CPU=n | ||
8 | CONFIG_SUSPEND=n | ||
9 | CONFIG_HIBERNATION=n | ||
10 | CONFIG_PREEMPT_NONE=y | ||
11 | CONFIG_PREEMPT_VOLUNTARY=n | ||
12 | CONFIG_PREEMPT=n | ||
13 | #CHECK#CONFIG_TREE_RCU=y | ||
14 | CONFIG_RCU_TORTURE_TEST=m | ||
15 | CONFIG_MODULE_UNLOAD=y | ||
16 | CONFIG_PROVE_LOCKING=y | ||
17 | CONFIG_PROVE_RCU=y | ||
18 | CONFIG_SYSFS_DEPRECATED_V2=y | ||
19 | CONFIG_IKCONFIG=y | ||
20 | CONFIG_IKCONFIG_PROC=y | ||
21 | CONFIG_PRINTK_TIME=y | ||
22 | |||
diff --git a/tools/testing/selftests/rcutorture/configs/v3.5/N4-A-t-NH-sd-SMP-HP b/tools/testing/selftests/rcutorture/configs/v3.5/N4-A-t-NH-sd-SMP-HP new file mode 100644 index 000000000000..c56b44530725 --- /dev/null +++ b/tools/testing/selftests/rcutorture/configs/v3.5/N4-A-t-NH-sd-SMP-HP | |||
@@ -0,0 +1,18 @@ | |||
1 | CONFIG_RCU_TRACE=n | ||
2 | CONFIG_NO_HZ=y | ||
3 | CONFIG_SMP=y | ||
4 | CONFIG_RCU_FANOUT=6 | ||
5 | CONFIG_NR_CPUS=8 | ||
6 | CONFIG_RCU_FANOUT_EXACT=n | ||
7 | CONFIG_HOTPLUG_CPU=y | ||
8 | CONFIG_PREEMPT_NONE=y | ||
9 | CONFIG_PREEMPT_VOLUNTARY=n | ||
10 | CONFIG_PREEMPT=n | ||
11 | #CHECK#CONFIG_TREE_RCU=y | ||
12 | CONFIG_RCU_TORTURE_TEST=m | ||
13 | CONFIG_MODULE_UNLOAD=y | ||
14 | CONFIG_SYSFS_DEPRECATED_V2=y | ||
15 | CONFIG_IKCONFIG=y | ||
16 | CONFIG_IKCONFIG_PROC=y | ||
17 | CONFIG_PRINTK_TIME=y | ||
18 | |||
diff --git a/tools/testing/selftests/rcutorture/configs/v3.5/N5-U-T-NH-sd-SMP-hp b/tools/testing/selftests/rcutorture/configs/v3.5/N5-U-T-NH-sd-SMP-hp new file mode 100644 index 000000000000..90d924fea9e9 --- /dev/null +++ b/tools/testing/selftests/rcutorture/configs/v3.5/N5-U-T-NH-sd-SMP-hp | |||
@@ -0,0 +1,22 @@ | |||
1 | CONFIG_RCU_TRACE=y | ||
2 | CONFIG_DEBUG_KERNEL=y | ||
3 | CONFIG_RCU_CPU_STALL_INFO=y | ||
4 | CONFIG_NO_HZ=y | ||
5 | CONFIG_SMP=y | ||
6 | CONFIG_RCU_FANOUT=6 | ||
7 | CONFIG_NR_CPUS=8 | ||
8 | CONFIG_RCU_FANOUT_EXACT=y | ||
9 | CONFIG_HOTPLUG_CPU=n | ||
10 | CONFIG_SUSPEND=n | ||
11 | CONFIG_HIBERNATION=n | ||
12 | CONFIG_PREEMPT_NONE=y | ||
13 | CONFIG_PREEMPT_VOLUNTARY=n | ||
14 | CONFIG_PREEMPT=n | ||
15 | #CHECK#CONFIG_TREE_RCU=y | ||
16 | CONFIG_RCU_TORTURE_TEST=m | ||
17 | CONFIG_MODULE_UNLOAD=y | ||
18 | CONFIG_SYSFS_DEPRECATED_V2=y | ||
19 | CONFIG_IKCONFIG=y | ||
20 | CONFIG_IKCONFIG_PROC=y | ||
21 | CONFIG_PRINTK_TIME=y | ||
22 | |||
diff --git a/tools/testing/selftests/rcutorture/configs/v3.5/NT1-nh b/tools/testing/selftests/rcutorture/configs/v3.5/NT1-nh new file mode 100644 index 000000000000..023f312a931c --- /dev/null +++ b/tools/testing/selftests/rcutorture/configs/v3.5/NT1-nh | |||
@@ -0,0 +1,23 @@ | |||
1 | #CHECK#CONFIG_TINY_RCU=y | ||
2 | CONFIG_RCU_TRACE=y | ||
3 | CONFIG_RCU_TORTURE_TEST=m | ||
4 | CONFIG_MODULE_UNLOAD=y | ||
5 | CONFIG_SUSPEND=n | ||
6 | CONFIG_HIBERNATION=n | ||
7 | # | ||
8 | CONFIG_SMP=n | ||
9 | # | ||
10 | CONFIG_HOTPLUG_CPU=n | ||
11 | # | ||
12 | CONFIG_NO_HZ=n | ||
13 | # | ||
14 | CONFIG_PREEMPT_NONE=y | ||
15 | CONFIG_PREEMPT_VOLUNTARY=n | ||
16 | CONFIG_PREEMPT=n | ||
17 | CONFIG_PROVE_LOCKING=y | ||
18 | CONFIG_PROVE_RCU=y | ||
19 | CONFIG_SYSFS_DEPRECATED_V2=y | ||
20 | CONFIG_IKCONFIG=y | ||
21 | CONFIG_IKCONFIG_PROC=y | ||
22 | CONFIG_PRINTK_TIME=y | ||
23 | |||
diff --git a/tools/testing/selftests/rcutorture/configs/v3.5/NT3-NH b/tools/testing/selftests/rcutorture/configs/v3.5/NT3-NH new file mode 100644 index 000000000000..6fd0235dae73 --- /dev/null +++ b/tools/testing/selftests/rcutorture/configs/v3.5/NT3-NH | |||
@@ -0,0 +1,20 @@ | |||
1 | #CHECK#CONFIG_TINY_RCU=y | ||
2 | CONFIG_RCU_TORTURE_TEST=m | ||
3 | CONFIG_MODULE_UNLOAD=y | ||
4 | CONFIG_SUSPEND=n | ||
5 | CONFIG_HIBERNATION=n | ||
6 | # | ||
7 | CONFIG_SMP=n | ||
8 | # | ||
9 | CONFIG_HOTPLUG_CPU=n | ||
10 | # | ||
11 | CONFIG_NO_HZ=y | ||
12 | # | ||
13 | CONFIG_PREEMPT_NONE=y | ||
14 | CONFIG_PREEMPT_VOLUNTARY=n | ||
15 | CONFIG_PREEMPT=n | ||
16 | CONFIG_SYSFS_DEPRECATED_V2=y | ||
17 | CONFIG_IKCONFIG=y | ||
18 | CONFIG_IKCONFIG_PROC=y | ||
19 | CONFIG_PRINTK_TIME=y | ||
20 | |||
diff --git a/tools/testing/selftests/rcutorture/configs/v3.5/P1-S-T-NH-SD-SMP-HP b/tools/testing/selftests/rcutorture/configs/v3.5/P1-S-T-NH-SD-SMP-HP new file mode 100644 index 000000000000..9647c44cf4b7 --- /dev/null +++ b/tools/testing/selftests/rcutorture/configs/v3.5/P1-S-T-NH-SD-SMP-HP | |||
@@ -0,0 +1,20 @@ | |||
1 | CONFIG_RCU_TRACE=y | ||
2 | CONFIG_RCU_CPU_STALL_INFO=y | ||
3 | CONFIG_NO_HZ=y | ||
4 | CONFIG_RCU_FAST_NO_HZ=y | ||
5 | CONFIG_SMP=y | ||
6 | CONFIG_RCU_FANOUT=8 | ||
7 | CONFIG_NR_CPUS=8 | ||
8 | CONFIG_RCU_FANOUT_EXACT=n | ||
9 | CONFIG_HOTPLUG_CPU=y | ||
10 | CONFIG_PREEMPT_NONE=n | ||
11 | CONFIG_PREEMPT_VOLUNTARY=n | ||
12 | CONFIG_PREEMPT=y | ||
13 | #CHECK#CONFIG_TREE_PREEMPT_RCU=y | ||
14 | CONFIG_RCU_TORTURE_TEST=m | ||
15 | CONFIG_MODULE_UNLOAD=y | ||
16 | CONFIG_SYSFS_DEPRECATED_V2=y | ||
17 | CONFIG_IKCONFIG=y | ||
18 | CONFIG_IKCONFIG_PROC=y | ||
19 | CONFIG_PRINTK_TIME=y | ||
20 | |||
diff --git a/tools/testing/selftests/rcutorture/configs/v3.5/P2-2-t-nh-sd-SMP-hp b/tools/testing/selftests/rcutorture/configs/v3.5/P2-2-t-nh-sd-SMP-hp new file mode 100644 index 000000000000..0f3b667d2a9f --- /dev/null +++ b/tools/testing/selftests/rcutorture/configs/v3.5/P2-2-t-nh-sd-SMP-hp | |||
@@ -0,0 +1,20 @@ | |||
1 | CONFIG_RCU_TRACE=n | ||
2 | CONFIG_NO_HZ=n | ||
3 | CONFIG_SMP=y | ||
4 | CONFIG_RCU_FANOUT=4 | ||
5 | CONFIG_NR_CPUS=8 | ||
6 | CONFIG_RCU_FANOUT_EXACT=n | ||
7 | CONFIG_HOTPLUG_CPU=n | ||
8 | CONFIG_SUSPEND=n | ||
9 | CONFIG_HIBERNATION=n | ||
10 | CONFIG_PREEMPT_NONE=n | ||
11 | CONFIG_PREEMPT_VOLUNTARY=n | ||
12 | CONFIG_PREEMPT=y | ||
13 | #CHECK#CONFIG_TREE_PREEMPT_RCU=y | ||
14 | CONFIG_RCU_TORTURE_TEST=m | ||
15 | CONFIG_MODULE_UNLOAD=y | ||
16 | CONFIG_SYSFS_DEPRECATED_V2=y | ||
17 | CONFIG_IKCONFIG=y | ||
18 | CONFIG_IKCONFIG_PROC=y | ||
19 | CONFIG_PRINTK_TIME=y | ||
20 | |||
diff --git a/tools/testing/selftests/rcutorture/configs/v3.5/P3-3-T-nh-SD-SMP-hp b/tools/testing/selftests/rcutorture/configs/v3.5/P3-3-T-nh-SD-SMP-hp new file mode 100644 index 000000000000..b035e141bf2a --- /dev/null +++ b/tools/testing/selftests/rcutorture/configs/v3.5/P3-3-T-nh-SD-SMP-hp | |||
@@ -0,0 +1,20 @@ | |||
1 | CONFIG_RCU_TRACE=y | ||
2 | CONFIG_NO_HZ=n | ||
3 | CONFIG_SMP=y | ||
4 | CONFIG_RCU_FANOUT=2 | ||
5 | CONFIG_NR_CPUS=8 | ||
6 | CONFIG_RCU_FANOUT_EXACT=n | ||
7 | CONFIG_HOTPLUG_CPU=n | ||
8 | CONFIG_SUSPEND=n | ||
9 | CONFIG_HIBERNATION=n | ||
10 | CONFIG_PREEMPT_NONE=n | ||
11 | CONFIG_PREEMPT_VOLUNTARY=n | ||
12 | CONFIG_PREEMPT=y | ||
13 | #CHECK#CONFIG_TREE_PREEMPT_RCU=y | ||
14 | CONFIG_RCU_TORTURE_TEST=m | ||
15 | CONFIG_MODULE_UNLOAD=y | ||
16 | CONFIG_SYSFS_DEPRECATED_V2=y | ||
17 | CONFIG_IKCONFIG=y | ||
18 | CONFIG_IKCONFIG_PROC=y | ||
19 | CONFIG_PRINTK_TIME=y | ||
20 | |||
diff --git a/tools/testing/selftests/rcutorture/configs/v3.5/P4-A-t-NH-sd-SMP-HP b/tools/testing/selftests/rcutorture/configs/v3.5/P4-A-t-NH-sd-SMP-HP new file mode 100644 index 000000000000..3ccf6a9447f5 --- /dev/null +++ b/tools/testing/selftests/rcutorture/configs/v3.5/P4-A-t-NH-sd-SMP-HP | |||
@@ -0,0 +1,22 @@ | |||
1 | CONFIG_RCU_TRACE=n | ||
2 | CONFIG_NO_HZ=y | ||
3 | CONFIG_SMP=y | ||
4 | CONFIG_RCU_FANOUT=6 | ||
5 | CONFIG_NR_CPUS=8 | ||
6 | CONFIG_RCU_FANOUT_EXACT=n | ||
7 | CONFIG_HOTPLUG_CPU=y | ||
8 | CONFIG_PREEMPT_NONE=n | ||
9 | CONFIG_PREEMPT_VOLUNTARY=n | ||
10 | CONFIG_PREEMPT=y | ||
11 | #CHECK#CONFIG_TREE_PREEMPT_RCU=y | ||
12 | CONFIG_RCU_TORTURE_TEST=m | ||
13 | CONFIG_MODULE_UNLOAD=y | ||
14 | CONFIG_RT_MUTEXES=y | ||
15 | CONFIG_RCU_BOOST=y | ||
16 | CONFIG_RCU_BOOST_PRIO=2 | ||
17 | CONFIG_PROVE_LOCKING=y | ||
18 | CONFIG_PROVE_RCU=y | ||
19 | CONFIG_IKCONFIG=y | ||
20 | CONFIG_IKCONFIG_PROC=y | ||
21 | CONFIG_PRINTK_TIME=y | ||
22 | |||
diff --git a/tools/testing/selftests/rcutorture/configs/v3.5/P5-U-T-NH-sd-SMP-hp b/tools/testing/selftests/rcutorture/configs/v3.5/P5-U-T-NH-sd-SMP-hp new file mode 100644 index 000000000000..ef624ce73d8e --- /dev/null +++ b/tools/testing/selftests/rcutorture/configs/v3.5/P5-U-T-NH-sd-SMP-hp | |||
@@ -0,0 +1,28 @@ | |||
1 | CONFIG_RCU_TRACE=y | ||
2 | CONFIG_RCU_CPU_STALL_INFO=y | ||
3 | CONFIG_NO_HZ=y | ||
4 | CONFIG_SMP=y | ||
5 | CONFIG_RCU_FANOUT=6 | ||
6 | CONFIG_NR_CPUS=8 | ||
7 | CONFIG_RCU_FANOUT_EXACT=y | ||
8 | CONFIG_HOTPLUG_CPU=n | ||
9 | CONFIG_SUSPEND=n | ||
10 | CONFIG_HIBERNATION=n | ||
11 | CONFIG_PREEMPT_NONE=n | ||
12 | CONFIG_PREEMPT_VOLUNTARY=n | ||
13 | CONFIG_PREEMPT=y | ||
14 | #CHECK#CONFIG_TREE_PREEMPT_RCU=y | ||
15 | CONFIG_DEBUG_KERNEL=y | ||
16 | CONFIG_PROVE_RCU_DELAY=y | ||
17 | CONFIG_DEBUG_OBJECTS=y | ||
18 | CONFIG_DEBUG_OBJECTS_RCU_HEAD=y | ||
19 | CONFIG_RT_MUTEXES=y | ||
20 | CONFIG_RCU_BOOST=y | ||
21 | CONFIG_RCU_BOOST_PRIO=2 | ||
22 | CONFIG_RCU_TORTURE_TEST=m | ||
23 | CONFIG_MODULE_UNLOAD=y | ||
24 | CONFIG_SYSFS_DEPRECATED_V2=y | ||
25 | CONFIG_IKCONFIG=y | ||
26 | CONFIG_IKCONFIG_PROC=y | ||
27 | CONFIG_PRINTK_TIME=y | ||
28 | |||
diff --git a/tools/testing/selftests/rcutorture/configs/v3.5/PT1-nh b/tools/testing/selftests/rcutorture/configs/v3.5/PT1-nh new file mode 100644 index 000000000000..e3361c3894a1 --- /dev/null +++ b/tools/testing/selftests/rcutorture/configs/v3.5/PT1-nh | |||
@@ -0,0 +1,23 @@ | |||
1 | CONFIG_TINY_PREEMPT_RCU=y | ||
2 | CONFIG_RCU_BOOST=y | ||
3 | CONFIG_RCU_BOOST_PRIO=2 | ||
4 | CONFIG_RCU_TRACE=y | ||
5 | CONFIG_RCU_TORTURE_TEST=m | ||
6 | CONFIG_MODULE_UNLOAD=y | ||
7 | CONFIG_SUSPEND=n | ||
8 | CONFIG_HIBERNATION=n | ||
9 | # | ||
10 | CONFIG_SMP=n | ||
11 | # | ||
12 | CONFIG_HOTPLUG_CPU=n | ||
13 | # | ||
14 | CONFIG_NO_HZ=n | ||
15 | # | ||
16 | CONFIG_PREEMPT_NONE=n | ||
17 | CONFIG_PREEMPT_VOLUNTARY=n | ||
18 | CONFIG_PREEMPT=y | ||
19 | CONFIG_SYSFS_DEPRECATED_V2=y | ||
20 | CONFIG_IKCONFIG=y | ||
21 | CONFIG_IKCONFIG_PROC=y | ||
22 | CONFIG_PRINTK_TIME=y | ||
23 | |||
diff --git a/tools/testing/selftests/rcutorture/configs/v3.5/PT2-NH b/tools/testing/selftests/rcutorture/configs/v3.5/PT2-NH new file mode 100644 index 000000000000..64abfc3b4d94 --- /dev/null +++ b/tools/testing/selftests/rcutorture/configs/v3.5/PT2-NH | |||
@@ -0,0 +1,22 @@ | |||
1 | CONFIG_TINY_PREEMPT_RCU=y | ||
2 | CONFIG_RCU_TORTURE_TEST=m | ||
3 | CONFIG_MODULE_UNLOAD=y | ||
4 | CONFIG_SUSPEND=n | ||
5 | CONFIG_HIBERNATION=n | ||
6 | # | ||
7 | CONFIG_SMP=n | ||
8 | # | ||
9 | CONFIG_HOTPLUG_CPU=n | ||
10 | # | ||
11 | CONFIG_NO_HZ=y | ||
12 | # | ||
13 | CONFIG_PREEMPT_NONE=n | ||
14 | CONFIG_PREEMPT_VOLUNTARY=n | ||
15 | CONFIG_PREEMPT=y | ||
16 | CONFIG_PROVE_LOCKING=y | ||
17 | CONFIG_PROVE_RCU=y | ||
18 | CONFIG_SYSFS_DEPRECATED_V2=y | ||
19 | CONFIG_IKCONFIG=y | ||
20 | CONFIG_IKCONFIG_PROC=y | ||
21 | CONFIG_PRINTK_TIME=y | ||
22 | |||
diff --git a/tools/testing/selftests/rcutorture/configs/v3.5/ver_functions.sh b/tools/testing/selftests/rcutorture/configs/v3.5/ver_functions.sh new file mode 100644 index 000000000000..6a5f13aab44d --- /dev/null +++ b/tools/testing/selftests/rcutorture/configs/v3.5/ver_functions.sh | |||
@@ -0,0 +1,46 @@ | |||
1 | #!/bin/bash | ||
2 | # | ||
3 | # Kernel-version-dependent shell functions for the rest of the scripts. | ||
4 | # | ||
5 | # This program is free software; you can redistribute it and/or modify | ||
6 | # it under the terms of the GNU General Public License as published by | ||
7 | # the Free Software Foundation; either version 2 of the License, or | ||
8 | # (at your option) any later version. | ||
9 | # | ||
10 | # This program is distributed in the hope that it will be useful, | ||
11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | # GNU General Public License for more details. | ||
14 | # | ||
15 | # You should have received a copy of the GNU General Public License | ||
16 | # along with this program; if not, you can access it online at | ||
17 | # http://www.gnu.org/licenses/gpl-2.0.html. | ||
18 | # | ||
19 | # Copyright (C) IBM Corporation, 2013 | ||
20 | # | ||
21 | # Authors: Paul E. McKenney <paulmck@linux.vnet.ibm.com> | ||
22 | |||
23 | # rcutorture_param_n_barrier_cbs bootparam-string | ||
24 | # | ||
25 | # Adds n_barrier_cbs rcutorture module parameter to kernels having it. | ||
26 | rcutorture_param_n_barrier_cbs () { | ||
27 | if echo $1 | grep -q "rcutorture\.n_barrier_cbs" | ||
28 | then | ||
29 | echo $1 | ||
30 | else | ||
31 | echo $1 rcutorture.n_barrier_cbs=4 | ||
32 | fi | ||
33 | } | ||
34 | |||
35 | # rcutorture_param_onoff bootparam-string config-file | ||
36 | # | ||
37 | # Adds onoff rcutorture module parameters to kernels having it. | ||
38 | rcutorture_param_onoff () { | ||
39 | if ! bootparam_hotplug_cpu "$1" && configfrag_hotplug_cpu "$2" | ||
40 | then | ||
41 | echo CPU-hotplug kernel, adding rcutorture onoff. | ||
42 | echo $1 rcutorture.onoff_interval=3 rcutorture.onoff_holdoff=30 | ||
43 | else | ||
44 | echo $1 | ||
45 | fi | ||
46 | } | ||
diff --git a/tools/testing/selftests/rcutorture/configs/ver_functions.sh b/tools/testing/selftests/rcutorture/configs/ver_functions.sh new file mode 100644 index 000000000000..5e40eadea777 --- /dev/null +++ b/tools/testing/selftests/rcutorture/configs/ver_functions.sh | |||
@@ -0,0 +1,46 @@ | |||
1 | #!/bin/bash | ||
2 | # | ||
3 | # Kernel-version-dependent shell functions for the rest of the scripts. | ||
4 | # | ||
5 | # This program is free software; you can redistribute it and/or modify | ||
6 | # it under the terms of the GNU General Public License as published by | ||
7 | # the Free Software Foundation; either version 2 of the License, or | ||
8 | # (at your option) any later version. | ||
9 | # | ||
10 | # This program is distributed in the hope that it will be useful, | ||
11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | # GNU General Public License for more details. | ||
14 | # | ||
15 | # You should have received a copy of the GNU General Public License | ||
16 | # along with this program; if not, you can access it online at | ||
17 | # http://www.gnu.org/licenses/gpl-2.0.html. | ||
18 | # | ||
19 | # Copyright (C) IBM Corporation, 2013 | ||
20 | # | ||
21 | # Authors: Paul E. McKenney <paulmck@linux.vnet.ibm.com> | ||
22 | |||
23 | # rcutorture_param_n_barrier_cbs bootparam-string | ||
24 | # | ||
25 | # Adds n_barrier_cbs rcutorture module parameter to kernels having it. | ||
26 | rcutorture_param_n_barrier_cbs () { | ||
27 | if echo $1 | grep -q "rcutorture\.n_barrier_cbs" | ||
28 | then | ||
29 | echo $1 | ||
30 | else | ||
31 | echo $1 rcutorture.n_barrier_cbs=4 | ||
32 | fi | ||
33 | } | ||
34 | |||
35 | # rcutorture_param_onoff bootparam-string config-file | ||
36 | # | ||
37 | # Adds onoff rcutorture module parameters to kernels having it. | ||
38 | rcutorture_param_onoff () { | ||
39 | if ! bootparam_hotplug_cpu "$1" && configfrag_hotplug_cpu "$2" | ||
40 | then | ||
41 | echo CPU-hotplug kernel, adding rcutorture onoff. 1>&2 | ||
42 | echo $1 rcutorture.onoff_interval=3 rcutorture.onoff_holdoff=30 | ||
43 | else | ||
44 | echo $1 | ||
45 | fi | ||
46 | } | ||
diff --git a/tools/testing/selftests/rcutorture/doc/TINY_RCU.txt b/tools/testing/selftests/rcutorture/doc/TINY_RCU.txt new file mode 100644 index 000000000000..28db67b54e55 --- /dev/null +++ b/tools/testing/selftests/rcutorture/doc/TINY_RCU.txt | |||
@@ -0,0 +1,40 @@ | |||
1 | This document gives a brief rationale for the TINY_RCU test cases. | ||
2 | |||
3 | |||
4 | Kconfig Parameters: | ||
5 | |||
6 | CONFIG_DEBUG_LOCK_ALLOC -- Do all three and none of the three. | ||
7 | CONFIG_PREEMPT_COUNT | ||
8 | CONFIG_RCU_TRACE | ||
9 | |||
10 | The theory here is that randconfig testing will hit the other six possible | ||
11 | combinations of these parameters. | ||
12 | |||
13 | |||
14 | Kconfig Parameters Ignored: | ||
15 | |||
16 | CONFIG_DEBUG_OBJECTS_RCU_HEAD | ||
17 | CONFIG_PROVE_RCU | ||
18 | |||
19 | In common code tested by TREE_RCU test cases. | ||
20 | |||
21 | CONFIG_NO_HZ_FULL_SYSIDLE | ||
22 | CONFIG_RCU_NOCB_CPU | ||
23 | CONFIG_RCU_USER_QS | ||
24 | |||
25 | Meaningless for TINY_RCU. | ||
26 | |||
27 | CONFIG_RCU_STALL_COMMON | ||
28 | CONFIG_RCU_TORTURE_TEST | ||
29 | |||
30 | Redundant with CONFIG_RCU_TRACE. | ||
31 | |||
32 | CONFIG_HOTPLUG_CPU | ||
33 | CONFIG_PREEMPT | ||
34 | CONFIG_PREEMPT_RCU | ||
35 | CONFIG_SMP | ||
36 | CONFIG_TINY_RCU | ||
37 | CONFIG_TREE_PREEMPT_RCU | ||
38 | CONFIG_TREE_RCU | ||
39 | |||
40 | All forced by CONFIG_TINY_RCU. | ||
diff --git a/tools/testing/selftests/rcutorture/doc/TREE_RCU-Kconfig.txt b/tools/testing/selftests/rcutorture/doc/TREE_RCU-Kconfig.txt new file mode 100644 index 000000000000..adbb76cffb49 --- /dev/null +++ b/tools/testing/selftests/rcutorture/doc/TREE_RCU-Kconfig.txt | |||
@@ -0,0 +1,95 @@ | |||
1 | This document gives a brief rationale for the TREE_RCU-related test | ||
2 | cases, a group that includes TREE_PREEMPT_RCU. | ||
3 | |||
4 | |||
5 | Kconfig Parameters: | ||
6 | |||
7 | CONFIG_DEBUG_LOCK_ALLOC -- Do three, covering CONFIG_PROVE_LOCKING & not. | ||
8 | CONFIG_DEBUG_OBJECTS_RCU_HEAD -- Do one. | ||
9 | CONFIG_HOTPLUG_CPU -- Do half. (Every second.) | ||
10 | CONFIG_HZ_PERIODIC -- Do one. | ||
11 | CONFIG_NO_HZ_IDLE -- Do those not otherwise specified. (Groups of two.) | ||
12 | CONFIG_NO_HZ_FULL -- Do two, one with CONFIG_NO_HZ_FULL_SYSIDLE. | ||
13 | CONFIG_NO_HZ_FULL_SYSIDLE -- Do one. | ||
14 | CONFIG_PREEMPT -- Do half. (First three and #8.) | ||
15 | CONFIG_PROVE_LOCKING -- Do all but two, covering CONFIG_PROVE_RCU and not. | ||
16 | CONFIG_PROVE_RCU -- Do all but one under CONFIG_PROVE_LOCKING. | ||
17 | CONFIG_PROVE_RCU_DELAY -- Do one. | ||
18 | CONFIG_RCU_BOOST -- one of TREE_PREEMPT_RCU. | ||
19 | CONFIG_RCU_BOOST_PRIO -- set to 2 for _BOOST testing. | ||
20 | CONFIG_RCU_CPU_STALL_INFO -- do one with and without _VERBOSE. | ||
21 | CONFIG_RCU_CPU_STALL_VERBOSE -- do one with and without _INFO. | ||
22 | CONFIG_RCU_FANOUT -- Cover hierarchy as currently, but overlap with others. | ||
23 | CONFIG_RCU_FANOUT_EXACT -- Do one. | ||
24 | CONFIG_RCU_FANOUT_LEAF -- Do one non-default. | ||
25 | CONFIG_RCU_FAST_NO_HZ -- Do one, but not with CONFIG_RCU_NOCB_CPU_ALL. | ||
26 | CONFIG_RCU_NOCB_CPU -- Do three, see below. | ||
27 | CONFIG_RCU_NOCB_CPU_ALL -- Do one. | ||
28 | CONFIG_RCU_NOCB_CPU_NONE -- Do one. | ||
29 | CONFIG_RCU_NOCB_CPU_ZERO -- Do one. | ||
30 | CONFIG_RCU_TRACE -- Do half. | ||
31 | CONFIG_SMP -- Need one !SMP for TREE_PREEMPT_RCU. | ||
32 | RCU-bh: Do one with PREEMPT and one with !PREEMPT. | ||
33 | RCU-sched: Do one with PREEMPT but not BOOST. | ||
34 | |||
35 | |||
36 | Hierarchy: | ||
37 | |||
38 | TREE01. CONFIG_NR_CPUS=8, CONFIG_RCU_FANOUT=8, CONFIG_RCU_FANOUT_EXACT=n. | ||
39 | TREE02. CONFIG_NR_CPUS=8, CONFIG_RCU_FANOUT=3, CONFIG_RCU_FANOUT_EXACT=n, | ||
40 | CONFIG_RCU_FANOUT_LEAF=3. | ||
41 | TREE03. CONFIG_NR_CPUS=8, CONFIG_RCU_FANOUT=4, CONFIG_RCU_FANOUT_EXACT=n, | ||
42 | CONFIG_RCU_FANOUT_LEAF=4. | ||
43 | TREE04. CONFIG_NR_CPUS=8, CONFIG_RCU_FANOUT=2, CONFIG_RCU_FANOUT_EXACT=n, | ||
44 | CONFIG_RCU_FANOUT_LEAF=2. | ||
45 | TREE05. CONFIG_NR_CPUS=8, CONFIG_RCU_FANOUT=6, CONFIG_RCU_FANOUT_EXACT=n | ||
46 | CONFIG_RCU_FANOUT_LEAF=6. | ||
47 | TREE06. CONFIG_NR_CPUS=8, CONFIG_RCU_FANOUT=6, CONFIG_RCU_FANOUT_EXACT=y | ||
48 | CONFIG_RCU_FANOUT_LEAF=6. | ||
49 | TREE07. CONFIG_NR_CPUS=16, CONFIG_RCU_FANOUT=2, CONFIG_RCU_FANOUT_EXACT=n, | ||
50 | CONFIG_RCU_FANOUT_LEAF=2. | ||
51 | TREE08. CONFIG_NR_CPUS=16, CONFIG_RCU_FANOUT=3, CONFIG_RCU_FANOUT_EXACT=y, | ||
52 | CONFIG_RCU_FANOUT_LEAF=2. | ||
53 | TREE09. CONFIG_NR_CPUS=1. | ||
54 | |||
55 | |||
56 | Kconfig Parameters Ignored: | ||
57 | |||
58 | CONFIG_64BIT | ||
59 | |||
60 | Used only to check CONFIG_RCU_FANOUT value, inspection suffices. | ||
61 | |||
62 | CONFIG_NO_HZ_FULL_SYSIDLE_SMALL | ||
63 | |||
64 | Defer until Frederic uses this. | ||
65 | |||
66 | CONFIG_PREEMPT_COUNT | ||
67 | CONFIG_PREEMPT_RCU | ||
68 | |||
69 | Redundant with CONFIG_PREEMPT, ignore. | ||
70 | |||
71 | CONFIG_RCU_BOOST_DELAY | ||
72 | |||
73 | Inspection suffices, ignore. | ||
74 | |||
75 | CONFIG_RCU_CPU_STALL_TIMEOUT | ||
76 | |||
77 | Inspection suffices, ignore. | ||
78 | |||
79 | CONFIG_RCU_STALL_COMMON | ||
80 | |||
81 | Implied by TREE_RCU and TREE_PREEMPT_RCU. | ||
82 | |||
83 | CONFIG_RCU_TORTURE_TEST | ||
84 | CONFIG_RCU_TORTURE_TEST_RUNNABLE | ||
85 | |||
86 | Always used in KVM testing. | ||
87 | |||
88 | CONFIG_RCU_USER_QS | ||
89 | |||
90 | Redundant with CONFIG_NO_HZ_FULL. | ||
91 | |||
92 | CONFIG_TREE_PREEMPT_RCU | ||
93 | CONFIG_TREE_RCU | ||
94 | |||
95 | These are controlled by CONFIG_PREEMPT. | ||
diff --git a/tools/testing/selftests/rcutorture/doc/initrd.txt b/tools/testing/selftests/rcutorture/doc/initrd.txt new file mode 100644 index 000000000000..49d134c25c04 --- /dev/null +++ b/tools/testing/selftests/rcutorture/doc/initrd.txt | |||
@@ -0,0 +1,90 @@ | |||
1 | This document describes one way to create the initrd directory hierarchy | ||
2 | in order to allow an initrd to be built into your kernel. The trick | ||
3 | here is to steal the initrd file used on your Linux laptop, Ubuntu in | ||
4 | this case. There are probably much better ways of doing this. | ||
5 | |||
6 | That said, here are the commands: | ||
7 | |||
8 | ------------------------------------------------------------------------ | ||
9 | zcat /initrd.img > /tmp/initrd.img.zcat | ||
10 | mkdir initrd | ||
11 | cd initrd | ||
12 | cpio -id < /tmp/initrd.img.zcat | ||
13 | ------------------------------------------------------------------------ | ||
14 | |||
15 | Interestingly enough, if you are running rcutorture, you don't really | ||
16 | need userspace in many cases. Running without userspace has the | ||
17 | advantage of allowing you to test your kernel independently of the | ||
18 | distro in place, the root-filesystem layout, and so on. To make this | ||
19 | happen, put the following script in the initrd's tree's "/init" file, | ||
20 | with 0755 mode. | ||
21 | |||
22 | ------------------------------------------------------------------------ | ||
23 | #!/bin/sh | ||
24 | |||
25 | [ -d /dev ] || mkdir -m 0755 /dev | ||
26 | [ -d /root ] || mkdir -m 0700 /root | ||
27 | [ -d /sys ] || mkdir /sys | ||
28 | [ -d /proc ] || mkdir /proc | ||
29 | [ -d /tmp ] || mkdir /tmp | ||
30 | mkdir -p /var/lock | ||
31 | mount -t sysfs -o nodev,noexec,nosuid sysfs /sys | ||
32 | mount -t proc -o nodev,noexec,nosuid proc /proc | ||
33 | # Some things don't work properly without /etc/mtab. | ||
34 | ln -sf /proc/mounts /etc/mtab | ||
35 | |||
36 | # Note that this only becomes /dev on the real filesystem if udev's scripts | ||
37 | # are used; which they will be, but it's worth pointing out | ||
38 | if ! mount -t devtmpfs -o mode=0755 udev /dev; then | ||
39 | echo "W: devtmpfs not available, falling back to tmpfs for /dev" | ||
40 | mount -t tmpfs -o mode=0755 udev /dev | ||
41 | [ -e /dev/console ] || mknod --mode=600 /dev/console c 5 1 | ||
42 | [ -e /dev/kmsg ] || mknod --mode=644 /dev/kmsg c 1 11 | ||
43 | [ -e /dev/null ] || mknod --mode=666 /dev/null c 1 3 | ||
44 | fi | ||
45 | |||
46 | mkdir /dev/pts | ||
47 | mount -t devpts -o noexec,nosuid,gid=5,mode=0620 devpts /dev/pts || true | ||
48 | mount -t tmpfs -o "nosuid,size=20%,mode=0755" tmpfs /run | ||
49 | mkdir /run/initramfs | ||
50 | # compatibility symlink for the pre-oneiric locations | ||
51 | ln -s /run/initramfs /dev/.initramfs | ||
52 | |||
53 | # Export relevant variables | ||
54 | export ROOT= | ||
55 | export ROOTDELAY= | ||
56 | export ROOTFLAGS= | ||
57 | export ROOTFSTYPE= | ||
58 | export IP= | ||
59 | export BOOT= | ||
60 | export BOOTIF= | ||
61 | export UBIMTD= | ||
62 | export break= | ||
63 | export init=/sbin/init | ||
64 | export quiet=n | ||
65 | export readonly=y | ||
66 | export rootmnt=/root | ||
67 | export debug= | ||
68 | export panic= | ||
69 | export blacklist= | ||
70 | export resume= | ||
71 | export resume_offset= | ||
72 | export recovery= | ||
73 | |||
74 | for i in /sys/devices/system/cpu/cpu*/online | ||
75 | do | ||
76 | case $i in | ||
77 | '/sys/devices/system/cpu/cpu0/online') | ||
78 | ;; | ||
79 | '/sys/devices/system/cpu/cpu*/online') | ||
80 | ;; | ||
81 | *) | ||
82 | echo 1 > $i | ||
83 | ;; | ||
84 | esac | ||
85 | done | ||
86 | |||
87 | while : | ||
88 | do | ||
89 | sleep 10 | ||
90 | done | ||
diff --git a/tools/testing/selftests/rcutorture/doc/rcu-test-image.txt b/tools/testing/selftests/rcutorture/doc/rcu-test-image.txt new file mode 100644 index 000000000000..66efb59a1bd1 --- /dev/null +++ b/tools/testing/selftests/rcutorture/doc/rcu-test-image.txt | |||
@@ -0,0 +1,42 @@ | |||
1 | This document describes one way to created the rcu-test-image file | ||
2 | that contains the filesystem used by the guest-OS kernel. There are | ||
3 | probably much better ways of doing this, and this filesystem could no | ||
4 | doubt be smaller. It is probably also possible to simply download | ||
5 | an appropriate image from any number of places. | ||
6 | |||
7 | That said, here are the commands: | ||
8 | |||
9 | ------------------------------------------------------------------------ | ||
10 | dd if=/dev/zero of=rcu-test-image bs=400M count=1 | ||
11 | mkfs.ext3 ./rcu-test-image | ||
12 | sudo mount -o loop ./rcu-test-image /mnt | ||
13 | |||
14 | # Replace "precise" below with your favorite Ubuntu release. | ||
15 | # Empirical evidence says this image will work for 64-bit, but... | ||
16 | # Note that debootstrap does take a few minutes to run. Or longer. | ||
17 | sudo debootstrap --verbose --arch i386 precise /mnt http://archive.ubuntu.com/ubuntu | ||
18 | cat << '___EOF___' | sudo dd of=/mnt/etc/fstab | ||
19 | # UNCONFIGURED FSTAB FOR BASE SYSTEM | ||
20 | # | ||
21 | /dev/vda / ext3 defaults 1 1 | ||
22 | dev /dev tmpfs rw 0 0 | ||
23 | tmpfs /dev/shm tmpfs defaults 0 0 | ||
24 | devpts /dev/pts devpts gid=5,mode=620 0 0 | ||
25 | sysfs /sys sysfs defaults 0 0 | ||
26 | proc /proc proc defaults 0 0 | ||
27 | ___EOF___ | ||
28 | sudo umount /mnt | ||
29 | ------------------------------------------------------------------------ | ||
30 | |||
31 | |||
32 | References: | ||
33 | |||
34 | http://sripathikodi.blogspot.com/2010/02/creating-kvm-bootable-fedora-system.html | ||
35 | https://help.ubuntu.com/community/KVM/CreateGuests | ||
36 | https://help.ubuntu.com/community/JeOSVMBuilder | ||
37 | http://wiki.libvirt.org/page/UbuntuKVMWalkthrough | ||
38 | http://www.moe.co.uk/2011/01/07/pci_add_option_rom-failed-to-find-romfile-pxe-rtl8139-bin/ -- "apt-get install kvm-pxe" | ||
39 | http://www.landley.net/writing/rootfs-howto.html | ||
40 | http://en.wikipedia.org/wiki/Initrd | ||
41 | http://en.wikipedia.org/wiki/Cpio | ||
42 | http://wiki.libvirt.org/page/UbuntuKVMWalkthrough | ||
diff --git a/tools/testing/selftests/user/Makefile b/tools/testing/selftests/user/Makefile new file mode 100644 index 000000000000..396255bd720e --- /dev/null +++ b/tools/testing/selftests/user/Makefile | |||
@@ -0,0 +1,13 @@ | |||
1 | # Makefile for user memory selftests | ||
2 | |||
3 | # No binaries, but make sure arg-less "make" doesn't trigger "run_tests" | ||
4 | all: | ||
5 | |||
6 | run_tests: all | ||
7 | @if /sbin/modprobe test_user_copy ; then \ | ||
8 | rmmod test_user_copy; \ | ||
9 | echo "user_copy: ok"; \ | ||
10 | else \ | ||
11 | echo "user_copy: [FAIL]"; \ | ||
12 | exit 1; \ | ||
13 | fi | ||
diff --git a/tools/vm/Makefile b/tools/vm/Makefile index 24e9ddd93fa4..3d907dacf2ac 100644 --- a/tools/vm/Makefile +++ b/tools/vm/Makefile | |||
@@ -2,21 +2,21 @@ | |||
2 | # | 2 | # |
3 | TARGETS=page-types slabinfo | 3 | TARGETS=page-types slabinfo |
4 | 4 | ||
5 | LK_DIR = ../lib/lk | 5 | LIB_DIR = ../lib/api |
6 | LIBLK = $(LK_DIR)/liblk.a | 6 | LIBS = $(LIB_DIR)/libapikfs.a |
7 | 7 | ||
8 | CC = $(CROSS_COMPILE)gcc | 8 | CC = $(CROSS_COMPILE)gcc |
9 | CFLAGS = -Wall -Wextra -I../lib/ | 9 | CFLAGS = -Wall -Wextra -I../lib/ |
10 | LDFLAGS = $(LIBLK) | 10 | LDFLAGS = $(LIBS) |
11 | 11 | ||
12 | $(TARGETS): liblk | 12 | $(TARGETS): $(LIBS) |
13 | 13 | ||
14 | liblk: | 14 | $(LIBS): |
15 | make -C $(LK_DIR) | 15 | make -C $(LIB_DIR) |
16 | 16 | ||
17 | %: %.c | 17 | %: %.c |
18 | $(CC) $(CFLAGS) -o $@ $< $(LDFLAGS) | 18 | $(CC) $(CFLAGS) -o $@ $< $(LDFLAGS) |
19 | 19 | ||
20 | clean: | 20 | clean: |
21 | $(RM) page-types slabinfo | 21 | $(RM) page-types slabinfo |
22 | make -C ../lib/lk clean | 22 | make -C $(LIB_DIR) clean |
diff --git a/tools/vm/page-types.c b/tools/vm/page-types.c index d5e9d6d185c8..f9be24d9efac 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 | #include <lk/debugfs.h> | 39 | #include <api/fs/debugfs.h> |
40 | 40 | ||
41 | #ifndef MAX_PATH | 41 | #ifndef MAX_PATH |
42 | # define MAX_PATH 256 | 42 | # define MAX_PATH 256 |