diff options
Diffstat (limited to 'tools')
163 files changed, 6469 insertions, 2448 deletions
diff --git a/tools/Makefile b/tools/Makefile index a9b02008443c..927cd46d36dc 100644 --- a/tools/Makefile +++ b/tools/Makefile | |||
@@ -39,10 +39,10 @@ cpupower: FORCE | |||
39 | cgroup firewire guest usb virtio vm net: FORCE | 39 | cgroup firewire guest usb virtio vm net: FORCE |
40 | $(call descend,$@) | 40 | $(call descend,$@) |
41 | 41 | ||
42 | liblk: FORCE | 42 | libapikfs: FORCE |
43 | $(call descend,lib/lk) | 43 | $(call descend,lib/api) |
44 | 44 | ||
45 | perf: liblk FORCE | 45 | perf: libapikfs FORCE |
46 | $(call descend,$@) | 46 | $(call descend,$@) |
47 | 47 | ||
48 | selftests: FORCE | 48 | selftests: FORCE |
@@ -80,10 +80,10 @@ cpupower_clean: | |||
80 | cgroup_clean firewire_clean lguest_clean usb_clean virtio_clean vm_clean net_clean: | 80 | cgroup_clean firewire_clean lguest_clean usb_clean virtio_clean vm_clean net_clean: |
81 | $(call descend,$(@:_clean=),clean) | 81 | $(call descend,$(@:_clean=),clean) |
82 | 82 | ||
83 | liblk_clean: | 83 | libapikfs_clean: |
84 | $(call descend,lib/lk,clean) | 84 | $(call descend,lib/api,clean) |
85 | 85 | ||
86 | perf_clean: liblk_clean | 86 | perf_clean: libapikfs_clean |
87 | $(call descend,$(@:_clean=),clean) | 87 | $(call descend,$(@:_clean=),clean) |
88 | 88 | ||
89 | selftests_clean: | 89 | selftests_clean: |
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/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..f778d48ac609 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="$(DESTDIR)/$(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 | ||
@@ -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..2ce565a73dd5 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 | } |
diff --git a/tools/lib/traceevent/event-parse.h b/tools/lib/traceevent/event-parse.h index 8d73d2594f65..cf5db9013f2c 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)) |
@@ -355,12 +356,35 @@ enum pevent_flag { | |||
355 | _PE(READ_FORMAT_FAILED, "failed to read event format"), \ | 356 | _PE(READ_FORMAT_FAILED, "failed to read event format"), \ |
356 | _PE(READ_PRINT_FAILED, "failed to read event print fmt"), \ | 357 | _PE(READ_PRINT_FAILED, "failed to read event print fmt"), \ |
357 | _PE(OLD_FTRACE_ARG_FAILED,"failed to allocate field name for ftrace"),\ | 358 | _PE(OLD_FTRACE_ARG_FAILED,"failed to allocate field name for ftrace"),\ |
358 | _PE(INVALID_ARG_TYPE, "invalid argument type") | 359 | _PE(INVALID_ARG_TYPE, "invalid argument type"), \ |
360 | _PE(INVALID_EXP_TYPE, "invalid expression type"), \ | ||
361 | _PE(INVALID_OP_TYPE, "invalid operator type"), \ | ||
362 | _PE(INVALID_EVENT_NAME, "invalid event name"), \ | ||
363 | _PE(EVENT_NOT_FOUND, "no event found"), \ | ||
364 | _PE(SYNTAX_ERROR, "syntax error"), \ | ||
365 | _PE(ILLEGAL_RVALUE, "illegal rvalue"), \ | ||
366 | _PE(ILLEGAL_LVALUE, "illegal lvalue for string comparison"), \ | ||
367 | _PE(INVALID_REGEX, "regex did not compute"), \ | ||
368 | _PE(ILLEGAL_STRING_CMP, "illegal comparison for string"), \ | ||
369 | _PE(ILLEGAL_INTEGER_CMP,"illegal comparison for integer"), \ | ||
370 | _PE(REPARENT_NOT_OP, "cannot reparent other than OP"), \ | ||
371 | _PE(REPARENT_FAILED, "failed to reparent filter OP"), \ | ||
372 | _PE(BAD_FILTER_ARG, "bad arg in filter tree"), \ | ||
373 | _PE(UNEXPECTED_TYPE, "unexpected type (not a value)"), \ | ||
374 | _PE(ILLEGAL_TOKEN, "illegal token"), \ | ||
375 | _PE(INVALID_PAREN, "open parenthesis cannot come here"), \ | ||
376 | _PE(UNBALANCED_PAREN, "unbalanced number of parenthesis"), \ | ||
377 | _PE(UNKNOWN_TOKEN, "unknown token"), \ | ||
378 | _PE(FILTER_NOT_FOUND, "no filter found"), \ | ||
379 | _PE(NOT_A_NUMBER, "must have number field"), \ | ||
380 | _PE(NO_FILTER, "no filters exists"), \ | ||
381 | _PE(FILTER_MISS, "record does not match to filter") | ||
359 | 382 | ||
360 | #undef _PE | 383 | #undef _PE |
361 | #define _PE(__code, __str) PEVENT_ERRNO__ ## __code | 384 | #define _PE(__code, __str) PEVENT_ERRNO__ ## __code |
362 | enum pevent_errno { | 385 | enum pevent_errno { |
363 | PEVENT_ERRNO__SUCCESS = 0, | 386 | PEVENT_ERRNO__SUCCESS = 0, |
387 | PEVENT_ERRNO__FILTER_MATCH = PEVENT_ERRNO__SUCCESS, | ||
364 | 388 | ||
365 | /* | 389 | /* |
366 | * Choose an arbitrary negative big number not to clash with standard | 390 | * Choose an arbitrary negative big number not to clash with standard |
@@ -377,6 +401,11 @@ enum pevent_errno { | |||
377 | }; | 401 | }; |
378 | #undef _PE | 402 | #undef _PE |
379 | 403 | ||
404 | struct plugin_list; | ||
405 | |||
406 | struct plugin_list *traceevent_load_plugins(struct pevent *pevent); | ||
407 | void traceevent_unload_plugins(struct plugin_list *plugin_list); | ||
408 | |||
380 | struct cmdline; | 409 | struct cmdline; |
381 | struct cmdline_list; | 410 | struct cmdline_list; |
382 | struct func_map; | 411 | struct func_map; |
@@ -522,6 +551,15 @@ __data2host8(struct pevent *pevent, unsigned long long data) | |||
522 | __data2host8(pevent, __val); \ | 551 | __data2host8(pevent, __val); \ |
523 | }) | 552 | }) |
524 | 553 | ||
554 | static inline int traceevent_host_bigendian(void) | ||
555 | { | ||
556 | unsigned char str[] = { 0x1, 0x2, 0x3, 0x4 }; | ||
557 | unsigned int val; | ||
558 | |||
559 | memcpy(&val, str, 4); | ||
560 | return val == 0x01020304; | ||
561 | } | ||
562 | |||
525 | /* taken from kernel/trace/trace.h */ | 563 | /* taken from kernel/trace/trace.h */ |
526 | enum trace_flag_type { | 564 | enum trace_flag_type { |
527 | TRACE_FLAG_IRQS_OFF = 0x01, | 565 | TRACE_FLAG_IRQS_OFF = 0x01, |
@@ -547,7 +585,9 @@ int pevent_parse_header_page(struct pevent *pevent, char *buf, unsigned long siz | |||
547 | 585 | ||
548 | enum pevent_errno pevent_parse_event(struct pevent *pevent, const char *buf, | 586 | enum pevent_errno pevent_parse_event(struct pevent *pevent, const char *buf, |
549 | unsigned long size, const char *sys); | 587 | unsigned long size, const char *sys); |
550 | enum pevent_errno pevent_parse_format(struct event_format **eventp, const char *buf, | 588 | enum pevent_errno pevent_parse_format(struct pevent *pevent, |
589 | struct event_format **eventp, | ||
590 | const char *buf, | ||
551 | unsigned long size, const char *sys); | 591 | unsigned long size, const char *sys); |
552 | void pevent_free_format(struct event_format *event); | 592 | void pevent_free_format(struct event_format *event); |
553 | 593 | ||
@@ -811,18 +851,22 @@ struct filter_type { | |||
811 | struct filter_arg *filter; | 851 | struct filter_arg *filter; |
812 | }; | 852 | }; |
813 | 853 | ||
854 | #define PEVENT_FILTER_ERROR_BUFSZ 1024 | ||
855 | |||
814 | struct event_filter { | 856 | struct event_filter { |
815 | struct pevent *pevent; | 857 | struct pevent *pevent; |
816 | int filters; | 858 | int filters; |
817 | struct filter_type *event_filters; | 859 | struct filter_type *event_filters; |
860 | char error_buffer[PEVENT_FILTER_ERROR_BUFSZ]; | ||
818 | }; | 861 | }; |
819 | 862 | ||
820 | struct event_filter *pevent_filter_alloc(struct pevent *pevent); | 863 | struct event_filter *pevent_filter_alloc(struct pevent *pevent); |
821 | 864 | ||
822 | #define FILTER_NONE -2 | 865 | /* for backward compatibility */ |
823 | #define FILTER_NOEXIST -1 | 866 | #define FILTER_NONE PEVENT_ERRNO__FILTER_NOT_FOUND |
824 | #define FILTER_MISS 0 | 867 | #define FILTER_NOEXIST PEVENT_ERRNO__NO_FILTER |
825 | #define FILTER_MATCH 1 | 868 | #define FILTER_MISS PEVENT_ERRNO__FILTER_MISS |
869 | #define FILTER_MATCH PEVENT_ERRNO__FILTER_MATCH | ||
826 | 870 | ||
827 | enum filter_trivial_type { | 871 | enum filter_trivial_type { |
828 | FILTER_TRIVIAL_FALSE, | 872 | FILTER_TRIVIAL_FALSE, |
@@ -830,20 +874,21 @@ enum filter_trivial_type { | |||
830 | FILTER_TRIVIAL_BOTH, | 874 | FILTER_TRIVIAL_BOTH, |
831 | }; | 875 | }; |
832 | 876 | ||
833 | int pevent_filter_add_filter_str(struct event_filter *filter, | 877 | enum pevent_errno pevent_filter_add_filter_str(struct event_filter *filter, |
834 | const char *filter_str, | 878 | const char *filter_str); |
835 | char **error_str); | ||
836 | 879 | ||
880 | enum pevent_errno pevent_filter_match(struct event_filter *filter, | ||
881 | struct pevent_record *record); | ||
837 | 882 | ||
838 | int pevent_filter_match(struct event_filter *filter, | 883 | int pevent_filter_strerror(struct event_filter *filter, enum pevent_errno err, |
839 | struct pevent_record *record); | 884 | char *buf, size_t buflen); |
840 | 885 | ||
841 | int pevent_event_filtered(struct event_filter *filter, | 886 | int pevent_event_filtered(struct event_filter *filter, |
842 | int event_id); | 887 | int event_id); |
843 | 888 | ||
844 | void pevent_filter_reset(struct event_filter *filter); | 889 | void pevent_filter_reset(struct event_filter *filter); |
845 | 890 | ||
846 | void pevent_filter_clear_trivial(struct event_filter *filter, | 891 | int pevent_filter_clear_trivial(struct event_filter *filter, |
847 | enum filter_trivial_type type); | 892 | enum filter_trivial_type type); |
848 | 893 | ||
849 | void pevent_filter_free(struct event_filter *filter); | 894 | 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..125f5676bcb5 --- /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) | ||
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(); | ||
211 | dlclose(list->handle); | ||
212 | free(list->name); | ||
213 | free(list); | ||
214 | } | ||
215 | } | ||
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/plugin_cfg80211.c b/tools/lib/traceevent/plugin_cfg80211.c new file mode 100644 index 000000000000..dcab8e873c21 --- /dev/null +++ b/tools/lib/traceevent/plugin_cfg80211.c | |||
@@ -0,0 +1,24 @@ | |||
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 *) 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 | } | ||
diff --git a/tools/lib/traceevent/plugin_function.c b/tools/lib/traceevent/plugin_function.c new file mode 100644 index 000000000000..aad92ad5e96f --- /dev/null +++ b/tools/lib/traceevent/plugin_function.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 | #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(void) | ||
148 | { | ||
149 | int i, x; | ||
150 | |||
151 | for (i = 0; i <= cpus; i++) { | ||
152 | for (x = 0; x < fstack[i].size && fstack[i].stack[x]; x++) | ||
153 | free(fstack[i].stack[x]); | ||
154 | free(fstack[i].stack); | ||
155 | } | ||
156 | |||
157 | free(fstack); | ||
158 | fstack = NULL; | ||
159 | cpus = -1; | ||
160 | } | ||
diff --git a/tools/lib/traceevent/plugin_hrtimer.c b/tools/lib/traceevent/plugin_hrtimer.c new file mode 100644 index 000000000000..0b0ebf30aa44 --- /dev/null +++ b/tools/lib/traceevent/plugin_hrtimer.c | |||
@@ -0,0 +1,78 @@ | |||
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 | } | ||
diff --git a/tools/lib/traceevent/plugin_jbd2.c b/tools/lib/traceevent/plugin_jbd2.c new file mode 100644 index 000000000000..2f93f81f0bac --- /dev/null +++ b/tools/lib/traceevent/plugin_jbd2.c | |||
@@ -0,0 +1,68 @@ | |||
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 | } | ||
diff --git a/tools/lib/traceevent/plugin_kmem.c b/tools/lib/traceevent/plugin_kmem.c new file mode 100644 index 000000000000..7115c8037ea8 --- /dev/null +++ b/tools/lib/traceevent/plugin_kmem.c | |||
@@ -0,0 +1,72 @@ | |||
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 | } | ||
diff --git a/tools/lib/traceevent/plugin_kvm.c b/tools/lib/traceevent/plugin_kvm.c new file mode 100644 index 000000000000..a0e282c6b967 --- /dev/null +++ b/tools/lib/traceevent/plugin_kvm.c | |||
@@ -0,0 +1,436 @@ | |||
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 | } | ||
diff --git a/tools/lib/traceevent/plugin_mac80211.c b/tools/lib/traceevent/plugin_mac80211.c new file mode 100644 index 000000000000..558a3b91c046 --- /dev/null +++ b/tools/lib/traceevent/plugin_mac80211.c | |||
@@ -0,0 +1,95 @@ | |||
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 | } | ||
diff --git a/tools/lib/traceevent/plugin_sched_switch.c b/tools/lib/traceevent/plugin_sched_switch.c new file mode 100644 index 000000000000..fea3724aa24f --- /dev/null +++ b/tools/lib/traceevent/plugin_sched_switch.c | |||
@@ -0,0 +1,148 @@ | |||
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 | } | ||
diff --git a/tools/lib/traceevent/plugin_scsi.c b/tools/lib/traceevent/plugin_scsi.c new file mode 100644 index 000000000000..6fb8e3e3fcad --- /dev/null +++ b/tools/lib/traceevent/plugin_scsi.c | |||
@@ -0,0 +1,423 @@ | |||
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 *) 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 | } | ||
diff --git a/tools/lib/traceevent/plugin_xen.c b/tools/lib/traceevent/plugin_xen.c new file mode 100644 index 000000000000..e7794298f3a9 --- /dev/null +++ b/tools/lib/traceevent/plugin_xen.c | |||
@@ -0,0 +1,130 @@ | |||
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 | } | ||
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..82bffac036e1 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=:: |
@@ -201,11 +203,15 @@ abort events and some memory events in precise mode on modern Intel CPUs. | |||
201 | --transaction:: | 203 | --transaction:: |
202 | Record transaction flags for transaction related events. | 204 | Record transaction flags for transaction related events. |
203 | 205 | ||
204 | --force-per-cpu:: | 206 | --per-thread:: |
205 | Force the use of per-cpu mmaps. By default, when tasks are specified (i.e. -p, | 207 | 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 | 208 | 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 | 209 | inheritance is automatically disabled. --per-thread is ignored with a warning |
208 | automatically enabled. Add the -i option also to disable inheritance. | 210 | if combined with -a or -C options. |
211 | |||
212 | --initial-delay msecs:: | ||
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..eefb9fb0c02f 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 | ||
@@ -77,3 +80,5 @@ clean: | |||
77 | %: | 80 | %: |
78 | $(print_msg) | 81 | $(print_msg) |
79 | $(make) | 82 | $(make) |
83 | |||
84 | .PHONY: tags TAGS | ||
diff --git a/tools/perf/Makefile.perf b/tools/perf/Makefile.perf index 7fc8f179cae7..87d7726cee2d 100644 --- a/tools/perf/Makefile.perf +++ b/tools/perf/Makefile.perf | |||
@@ -86,7 +86,7 @@ FLEX = flex | |||
86 | BISON = bison | 86 | BISON = bison |
87 | STRIP = strip | 87 | STRIP = strip |
88 | 88 | ||
89 | LK_DIR = $(srctree)/tools/lib/lk/ | 89 | LIB_DIR = $(srctree)/tools/lib/api/ |
90 | TRACE_EVENT_DIR = $(srctree)/tools/lib/traceevent/ | 90 | TRACE_EVENT_DIR = $(srctree)/tools/lib/traceevent/ |
91 | 91 | ||
92 | # include config/Makefile by default and rule out | 92 | # include config/Makefile by default and rule out |
@@ -105,7 +105,7 @@ ifeq ($(config),1) | |||
105 | include config/Makefile | 105 | include config/Makefile |
106 | endif | 106 | endif |
107 | 107 | ||
108 | export prefix bindir sharedir sysconfdir | 108 | export prefix bindir sharedir sysconfdir DESTDIR |
109 | 109 | ||
110 | # sparse is architecture-neutral, which means that we need to tell it | 110 | # sparse is architecture-neutral, which means that we need to tell it |
111 | # explicitly what architecture to check for. Fix this up for yours.. | 111 | # explicitly what architecture to check for. Fix this up for yours.. |
@@ -127,20 +127,20 @@ strip-libs = $(filter-out -l%,$(1)) | |||
127 | ifneq ($(OUTPUT),) | 127 | ifneq ($(OUTPUT),) |
128 | TE_PATH=$(OUTPUT) | 128 | TE_PATH=$(OUTPUT) |
129 | ifneq ($(subdir),) | 129 | ifneq ($(subdir),) |
130 | LK_PATH=$(OUTPUT)/../lib/lk/ | 130 | LIB_PATH=$(OUTPUT)/../lib/api/ |
131 | else | 131 | else |
132 | LK_PATH=$(OUTPUT) | 132 | LIB_PATH=$(OUTPUT) |
133 | endif | 133 | endif |
134 | else | 134 | else |
135 | TE_PATH=$(TRACE_EVENT_DIR) | 135 | TE_PATH=$(TRACE_EVENT_DIR) |
136 | LK_PATH=$(LK_DIR) | 136 | LIB_PATH=$(LIB_DIR) |
137 | endif | 137 | endif |
138 | 138 | ||
139 | LIBTRACEEVENT = $(TE_PATH)libtraceevent.a | 139 | LIBTRACEEVENT = $(TE_PATH)libtraceevent.a |
140 | export LIBTRACEEVENT | 140 | export LIBTRACEEVENT |
141 | 141 | ||
142 | LIBLK = $(LK_PATH)liblk.a | 142 | LIBAPIKFS = $(LIB_PATH)libapikfs.a |
143 | export LIBLK | 143 | export LIBAPIKFS |
144 | 144 | ||
145 | # python extension build directories | 145 | # python extension build directories |
146 | PYTHON_EXTBUILD := $(OUTPUT)python_ext_build/ | 146 | PYTHON_EXTBUILD := $(OUTPUT)python_ext_build/ |
@@ -151,7 +151,7 @@ export PYTHON_EXTBUILD_LIB PYTHON_EXTBUILD_TMP | |||
151 | python-clean := $(call QUIET_CLEAN, python) $(RM) -r $(PYTHON_EXTBUILD) $(OUTPUT)python/perf.so | 151 | python-clean := $(call QUIET_CLEAN, python) $(RM) -r $(PYTHON_EXTBUILD) $(OUTPUT)python/perf.so |
152 | 152 | ||
153 | PYTHON_EXT_SRCS := $(shell grep -v ^\# util/python-ext-sources) | 153 | PYTHON_EXT_SRCS := $(shell grep -v ^\# util/python-ext-sources) |
154 | PYTHON_EXT_DEPS := util/python-ext-sources util/setup.py $(LIBTRACEEVENT) $(LIBLK) | 154 | PYTHON_EXT_DEPS := util/python-ext-sources util/setup.py $(LIBTRACEEVENT) $(LIBAPIKFS) |
155 | 155 | ||
156 | $(OUTPUT)python/perf.so: $(PYTHON_EXT_SRCS) $(PYTHON_EXT_DEPS) | 156 | $(OUTPUT)python/perf.so: $(PYTHON_EXT_SRCS) $(PYTHON_EXT_DEPS) |
157 | $(QUIET_GEN)CFLAGS='$(CFLAGS)' $(PYTHON_WORD) util/setup.py \ | 157 | $(QUIET_GEN)CFLAGS='$(CFLAGS)' $(PYTHON_WORD) util/setup.py \ |
@@ -202,6 +202,7 @@ $(OUTPUT)util/pmu.o: $(OUTPUT)util/pmu-flex.c $(OUTPUT)util/pmu-bison.c | |||
202 | 202 | ||
203 | LIB_FILE=$(OUTPUT)libperf.a | 203 | LIB_FILE=$(OUTPUT)libperf.a |
204 | 204 | ||
205 | LIB_H += ../lib/symbol/kallsyms.h | ||
205 | LIB_H += ../../include/uapi/linux/perf_event.h | 206 | LIB_H += ../../include/uapi/linux/perf_event.h |
206 | LIB_H += ../../include/linux/rbtree.h | 207 | LIB_H += ../../include/linux/rbtree.h |
207 | LIB_H += ../../include/linux/list.h | 208 | LIB_H += ../../include/linux/list.h |
@@ -210,7 +211,7 @@ LIB_H += ../../include/linux/hash.h | |||
210 | LIB_H += ../../include/linux/stringify.h | 211 | LIB_H += ../../include/linux/stringify.h |
211 | LIB_H += util/include/linux/bitmap.h | 212 | LIB_H += util/include/linux/bitmap.h |
212 | LIB_H += util/include/linux/bitops.h | 213 | LIB_H += util/include/linux/bitops.h |
213 | LIB_H += util/include/linux/compiler.h | 214 | LIB_H += ../include/linux/compiler.h |
214 | LIB_H += util/include/linux/const.h | 215 | LIB_H += util/include/linux/const.h |
215 | LIB_H += util/include/linux/ctype.h | 216 | LIB_H += util/include/linux/ctype.h |
216 | LIB_H += util/include/linux/kernel.h | 217 | LIB_H += util/include/linux/kernel.h |
@@ -225,7 +226,7 @@ LIB_H += util/include/linux/string.h | |||
225 | LIB_H += util/include/linux/types.h | 226 | LIB_H += util/include/linux/types.h |
226 | LIB_H += util/include/linux/linkage.h | 227 | LIB_H += util/include/linux/linkage.h |
227 | LIB_H += util/include/asm/asm-offsets.h | 228 | LIB_H += util/include/asm/asm-offsets.h |
228 | LIB_H += util/include/asm/bug.h | 229 | LIB_H += ../include/asm/bug.h |
229 | LIB_H += util/include/asm/byteorder.h | 230 | LIB_H += util/include/asm/byteorder.h |
230 | LIB_H += util/include/asm/hweight.h | 231 | LIB_H += util/include/asm/hweight.h |
231 | LIB_H += util/include/asm/swab.h | 232 | LIB_H += util/include/asm/swab.h |
@@ -312,6 +313,7 @@ LIB_OBJS += $(OUTPUT)util/evlist.o | |||
312 | LIB_OBJS += $(OUTPUT)util/evsel.o | 313 | LIB_OBJS += $(OUTPUT)util/evsel.o |
313 | LIB_OBJS += $(OUTPUT)util/exec_cmd.o | 314 | LIB_OBJS += $(OUTPUT)util/exec_cmd.o |
314 | LIB_OBJS += $(OUTPUT)util/help.o | 315 | LIB_OBJS += $(OUTPUT)util/help.o |
316 | LIB_OBJS += $(OUTPUT)util/kallsyms.o | ||
315 | LIB_OBJS += $(OUTPUT)util/levenshtein.o | 317 | LIB_OBJS += $(OUTPUT)util/levenshtein.o |
316 | LIB_OBJS += $(OUTPUT)util/parse-options.o | 318 | LIB_OBJS += $(OUTPUT)util/parse-options.o |
317 | LIB_OBJS += $(OUTPUT)util/parse-events.o | 319 | LIB_OBJS += $(OUTPUT)util/parse-events.o |
@@ -353,6 +355,7 @@ LIB_OBJS += $(OUTPUT)util/pmu-bison.o | |||
353 | LIB_OBJS += $(OUTPUT)util/trace-event-read.o | 355 | LIB_OBJS += $(OUTPUT)util/trace-event-read.o |
354 | LIB_OBJS += $(OUTPUT)util/trace-event-info.o | 356 | LIB_OBJS += $(OUTPUT)util/trace-event-info.o |
355 | LIB_OBJS += $(OUTPUT)util/trace-event-scripting.o | 357 | LIB_OBJS += $(OUTPUT)util/trace-event-scripting.o |
358 | LIB_OBJS += $(OUTPUT)util/trace-event.o | ||
356 | LIB_OBJS += $(OUTPUT)util/svghelper.o | 359 | LIB_OBJS += $(OUTPUT)util/svghelper.o |
357 | LIB_OBJS += $(OUTPUT)util/sort.o | 360 | LIB_OBJS += $(OUTPUT)util/sort.o |
358 | LIB_OBJS += $(OUTPUT)util/hist.o | 361 | LIB_OBJS += $(OUTPUT)util/hist.o |
@@ -438,7 +441,7 @@ BUILTIN_OBJS += $(OUTPUT)builtin-inject.o | |||
438 | BUILTIN_OBJS += $(OUTPUT)tests/builtin-test.o | 441 | BUILTIN_OBJS += $(OUTPUT)tests/builtin-test.o |
439 | BUILTIN_OBJS += $(OUTPUT)builtin-mem.o | 442 | BUILTIN_OBJS += $(OUTPUT)builtin-mem.o |
440 | 443 | ||
441 | PERFLIBS = $(LIB_FILE) $(LIBLK) $(LIBTRACEEVENT) | 444 | PERFLIBS = $(LIB_FILE) $(LIBAPIKFS) $(LIBTRACEEVENT) |
442 | 445 | ||
443 | # We choose to avoid "if .. else if .. else .. endif endif" | 446 | # We choose to avoid "if .. else if .. else .. endif endif" |
444 | # because maintaining the nesting to match is a pain. If | 447 | # because maintaining the nesting to match is a pain. If |
@@ -486,6 +489,7 @@ ifndef NO_SLANG | |||
486 | LIB_OBJS += $(OUTPUT)ui/browsers/hists.o | 489 | LIB_OBJS += $(OUTPUT)ui/browsers/hists.o |
487 | LIB_OBJS += $(OUTPUT)ui/browsers/map.o | 490 | LIB_OBJS += $(OUTPUT)ui/browsers/map.o |
488 | LIB_OBJS += $(OUTPUT)ui/browsers/scripts.o | 491 | LIB_OBJS += $(OUTPUT)ui/browsers/scripts.o |
492 | LIB_OBJS += $(OUTPUT)ui/browsers/header.o | ||
489 | LIB_OBJS += $(OUTPUT)ui/tui/setup.o | 493 | LIB_OBJS += $(OUTPUT)ui/tui/setup.o |
490 | LIB_OBJS += $(OUTPUT)ui/tui/util.o | 494 | LIB_OBJS += $(OUTPUT)ui/tui/util.o |
491 | LIB_OBJS += $(OUTPUT)ui/tui/helpline.o | 495 | LIB_OBJS += $(OUTPUT)ui/tui/helpline.o |
@@ -671,6 +675,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 | 675 | $(OUTPUT)ui/browsers/scripts.o: ui/browsers/scripts.c $(OUTPUT)PERF-CFLAGS |
672 | $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) -DENABLE_SLFUTURE_CONST $< | 676 | $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) -DENABLE_SLFUTURE_CONST $< |
673 | 677 | ||
678 | $(OUTPUT)util/kallsyms.o: ../lib/symbol/kallsyms.c $(OUTPUT)PERF-CFLAGS | ||
679 | $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) $< | ||
680 | |||
674 | $(OUTPUT)util/rbtree.o: ../../lib/rbtree.c $(OUTPUT)PERF-CFLAGS | 681 | $(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)"' $< | 682 | $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) -Wno-unused-parameter -DETC_PERFCONFIG='"$(ETC_PERFCONFIG_SQ)"' $< |
676 | 683 | ||
@@ -710,26 +717,33 @@ $(LIB_FILE): $(LIB_OBJS) | |||
710 | # libtraceevent.a | 717 | # libtraceevent.a |
711 | TE_SOURCES = $(wildcard $(TRACE_EVENT_DIR)*.[ch]) | 718 | TE_SOURCES = $(wildcard $(TRACE_EVENT_DIR)*.[ch]) |
712 | 719 | ||
713 | $(LIBTRACEEVENT): $(TE_SOURCES) | 720 | LIBTRACEEVENT_FLAGS = $(QUIET_SUBDIR1) O=$(OUTPUT) |
714 | $(QUIET_SUBDIR0)$(TRACE_EVENT_DIR) $(QUIET_SUBDIR1) O=$(OUTPUT) CFLAGS="-g -Wall $(EXTRA_CFLAGS)" libtraceevent.a | 721 | LIBTRACEEVENT_FLAGS += CFLAGS="-g -Wall $(EXTRA_CFLAGS)" |
722 | LIBTRACEEVENT_FLAGS += plugin_dir=$(plugindir_SQ) | ||
723 | |||
724 | $(LIBTRACEEVENT): $(TE_SOURCES) $(OUTPUT)PERF-CFLAGS | ||
725 | $(QUIET_SUBDIR0)$(TRACE_EVENT_DIR) $(LIBTRACEEVENT_FLAGS) libtraceevent.a plugins | ||
715 | 726 | ||
716 | $(LIBTRACEEVENT)-clean: | 727 | $(LIBTRACEEVENT)-clean: |
717 | $(call QUIET_CLEAN, libtraceevent) | 728 | $(call QUIET_CLEAN, libtraceevent) |
718 | @$(MAKE) -C $(TRACE_EVENT_DIR) O=$(OUTPUT) clean >/dev/null | 729 | @$(MAKE) -C $(TRACE_EVENT_DIR) O=$(OUTPUT) clean >/dev/null |
719 | 730 | ||
720 | LIBLK_SOURCES = $(wildcard $(LK_PATH)*.[ch]) | 731 | install-traceevent-plugins: $(LIBTRACEEVENT) |
732 | $(QUIET_SUBDIR0)$(TRACE_EVENT_DIR) $(LIBTRACEEVENT_FLAGS) install_plugins | ||
733 | |||
734 | LIBAPIKFS_SOURCES = $(wildcard $(LIB_PATH)fs/*.[ch]) | ||
721 | 735 | ||
722 | # if subdir is set, we've been called from above so target has been built | 736 | # if subdir is set, we've been called from above so target has been built |
723 | # already | 737 | # already |
724 | $(LIBLK): $(LIBLK_SOURCES) | 738 | $(LIBAPIKFS): $(LIBAPIKFS_SOURCES) |
725 | ifeq ($(subdir),) | 739 | ifeq ($(subdir),) |
726 | $(QUIET_SUBDIR0)$(LK_DIR) $(QUIET_SUBDIR1) O=$(OUTPUT) liblk.a | 740 | $(QUIET_SUBDIR0)$(LIB_DIR) $(QUIET_SUBDIR1) O=$(OUTPUT) libapikfs.a |
727 | endif | 741 | endif |
728 | 742 | ||
729 | $(LIBLK)-clean: | 743 | $(LIBAPIKFS)-clean: |
730 | ifeq ($(subdir),) | 744 | ifeq ($(subdir),) |
731 | $(call QUIET_CLEAN, liblk) | 745 | $(call QUIET_CLEAN, libapikfs) |
732 | @$(MAKE) -C $(LK_DIR) O=$(OUTPUT) clean >/dev/null | 746 | @$(MAKE) -C $(LIB_DIR) O=$(OUTPUT) clean >/dev/null |
733 | endif | 747 | endif |
734 | 748 | ||
735 | help: | 749 | help: |
@@ -785,7 +799,7 @@ cscope: | |||
785 | 799 | ||
786 | ### Detect prefix changes | 800 | ### Detect prefix changes |
787 | TRACK_CFLAGS = $(subst ','\'',$(CFLAGS)):\ | 801 | TRACK_CFLAGS = $(subst ','\'',$(CFLAGS)):\ |
788 | $(bindir_SQ):$(perfexecdir_SQ):$(template_dir_SQ):$(prefix_SQ) | 802 | $(bindir_SQ):$(perfexecdir_SQ):$(template_dir_SQ):$(prefix_SQ):$(plugindir_SQ) |
789 | 803 | ||
790 | $(OUTPUT)PERF-CFLAGS: .FORCE-PERF-CFLAGS | 804 | $(OUTPUT)PERF-CFLAGS: .FORCE-PERF-CFLAGS |
791 | @FLAGS='$(TRACK_CFLAGS)'; \ | 805 | @FLAGS='$(TRACK_CFLAGS)'; \ |
@@ -840,16 +854,16 @@ ifndef NO_LIBPYTHON | |||
840 | $(INSTALL) scripts/python/*.py -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/python'; \ | 854 | $(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' | 855 | $(INSTALL) scripts/python/bin/* -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/python/bin' |
842 | endif | 856 | endif |
843 | $(call QUIET_INSTALL, bash_completion-script) \ | 857 | $(call QUIET_INSTALL, perf_completion-script) \ |
844 | $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(sysconfdir_SQ)/bash_completion.d'; \ | 858 | $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(sysconfdir_SQ)/bash_completion.d'; \ |
845 | $(INSTALL) bash_completion '$(DESTDIR_SQ)$(sysconfdir_SQ)/bash_completion.d/perf' | 859 | $(INSTALL) perf-completion.sh '$(DESTDIR_SQ)$(sysconfdir_SQ)/bash_completion.d/perf' |
846 | $(call QUIET_INSTALL, tests) \ | 860 | $(call QUIET_INSTALL, tests) \ |
847 | $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests'; \ | 861 | $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests'; \ |
848 | $(INSTALL) tests/attr.py '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests'; \ | 862 | $(INSTALL) tests/attr.py '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests'; \ |
849 | $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests/attr'; \ | 863 | $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests/attr'; \ |
850 | $(INSTALL) tests/attr/* '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests/attr' | 864 | $(INSTALL) tests/attr/* '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests/attr' |
851 | 865 | ||
852 | install: install-bin try-install-man | 866 | install: install-bin try-install-man install-traceevent-plugins |
853 | 867 | ||
854 | install-python_ext: | 868 | install-python_ext: |
855 | $(PYTHON_WORD) util/setup.py --quiet install --root='/$(DESTDIR_SQ)' | 869 | $(PYTHON_WORD) util/setup.py --quiet install --root='/$(DESTDIR_SQ)' |
@@ -868,12 +882,11 @@ config-clean: | |||
868 | $(call QUIET_CLEAN, config) | 882 | $(call QUIET_CLEAN, config) |
869 | @$(MAKE) -C config/feature-checks clean >/dev/null | 883 | @$(MAKE) -C config/feature-checks clean >/dev/null |
870 | 884 | ||
871 | clean: $(LIBTRACEEVENT)-clean $(LIBLK)-clean config-clean | 885 | 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) | 886 | $(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 | 887 | $(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* | 888 | $(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) | 889 | $(QUIET_SUBDIR0)Documentation $(QUIET_SUBDIR1) clean |
876 | @$(MAKE) -C Documentation O=$(OUTPUT) clean >/dev/null | ||
877 | $(python-clean) | 890 | $(python-clean) |
878 | 891 | ||
879 | # | 892 | # |
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/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-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..43ff33d0007b 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" |
@@ -169,6 +169,7 @@ static int opt_set_target(const struct option *opt, const char *str, | |||
169 | int unset __maybe_unused) | 169 | int unset __maybe_unused) |
170 | { | 170 | { |
171 | int ret = -ENOENT; | 171 | int ret = -ENOENT; |
172 | char *tmp; | ||
172 | 173 | ||
173 | if (str && !params.target) { | 174 | if (str && !params.target) { |
174 | if (!strcmp(opt->long_name, "exec")) | 175 | if (!strcmp(opt->long_name, "exec")) |
@@ -180,7 +181,19 @@ static int opt_set_target(const struct option *opt, const char *str, | |||
180 | else | 181 | else |
181 | return ret; | 182 | return ret; |
182 | 183 | ||
183 | params.target = str; | 184 | /* Expand given path to absolute path, except for modulename */ |
185 | if (params.uprobes || strchr(str, '/')) { | ||
186 | tmp = realpath(str, NULL); | ||
187 | if (!tmp) { | ||
188 | pr_warning("Failed to get the absolute path of %s: %m\n", str); | ||
189 | return ret; | ||
190 | } | ||
191 | } else { | ||
192 | tmp = strdup(str); | ||
193 | if (!tmp) | ||
194 | return -ENOMEM; | ||
195 | } | ||
196 | params.target = tmp; | ||
184 | ret = 0; | 197 | ret = 0; |
185 | } | 198 | } |
186 | 199 | ||
@@ -411,7 +424,7 @@ int cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused) | |||
411 | } | 424 | } |
412 | 425 | ||
413 | #ifdef HAVE_DWARF_SUPPORT | 426 | #ifdef HAVE_DWARF_SUPPORT |
414 | if (params.show_lines && !params.uprobes) { | 427 | if (params.show_lines) { |
415 | if (params.mod_events) { | 428 | if (params.mod_events) { |
416 | pr_err(" Error: Don't use --line with" | 429 | pr_err(" Error: Don't use --line with" |
417 | " --add/--del.\n"); | 430 | " --add/--del.\n"); |
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index 7c8020a32784..07d4cf8d3fd3 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) |
@@ -320,14 +301,14 @@ static struct perf_event_header finished_round_event = { | |||
320 | .type = PERF_RECORD_FINISHED_ROUND, | 301 | .type = PERF_RECORD_FINISHED_ROUND, |
321 | }; | 302 | }; |
322 | 303 | ||
323 | static int perf_record__mmap_read_all(struct perf_record *rec) | 304 | static int record__mmap_read_all(struct record *rec) |
324 | { | 305 | { |
325 | int i; | 306 | int i; |
326 | int rc = 0; | 307 | int rc = 0; |
327 | 308 | ||
328 | for (i = 0; i < rec->evlist->nr_mmaps; i++) { | 309 | for (i = 0; i < rec->evlist->nr_mmaps; i++) { |
329 | if (rec->evlist->mmap[i].base) { | 310 | if (rec->evlist->mmap[i].base) { |
330 | if (perf_record__mmap_read(rec, &rec->evlist->mmap[i]) != 0) { | 311 | if (record__mmap_read(rec, &rec->evlist->mmap[i]) != 0) { |
331 | rc = -1; | 312 | rc = -1; |
332 | goto out; | 313 | goto out; |
333 | } | 314 | } |
@@ -335,16 +316,14 @@ static int perf_record__mmap_read_all(struct perf_record *rec) | |||
335 | } | 316 | } |
336 | 317 | ||
337 | if (perf_header__has_feat(&rec->session->header, HEADER_TRACING_DATA)) | 318 | if (perf_header__has_feat(&rec->session->header, HEADER_TRACING_DATA)) |
338 | rc = write_output(rec, &finished_round_event, | 319 | rc = record__write(rec, &finished_round_event, sizeof(finished_round_event)); |
339 | sizeof(finished_round_event)); | ||
340 | 320 | ||
341 | out: | 321 | out: |
342 | return rc; | 322 | return rc; |
343 | } | 323 | } |
344 | 324 | ||
345 | static void perf_record__init_features(struct perf_record *rec) | 325 | static void record__init_features(struct record *rec) |
346 | { | 326 | { |
347 | struct perf_evlist *evsel_list = rec->evlist; | ||
348 | struct perf_session *session = rec->session; | 327 | struct perf_session *session = rec->session; |
349 | int feat; | 328 | int feat; |
350 | 329 | ||
@@ -354,32 +333,46 @@ static void perf_record__init_features(struct perf_record *rec) | |||
354 | if (rec->no_buildid) | 333 | if (rec->no_buildid) |
355 | perf_header__clear_feat(&session->header, HEADER_BUILD_ID); | 334 | perf_header__clear_feat(&session->header, HEADER_BUILD_ID); |
356 | 335 | ||
357 | if (!have_tracepoints(&evsel_list->entries)) | 336 | if (!have_tracepoints(&rec->evlist->entries)) |
358 | perf_header__clear_feat(&session->header, HEADER_TRACING_DATA); | 337 | perf_header__clear_feat(&session->header, HEADER_TRACING_DATA); |
359 | 338 | ||
360 | if (!rec->opts.branch_stack) | 339 | if (!rec->opts.branch_stack) |
361 | perf_header__clear_feat(&session->header, HEADER_BRANCH_STACK); | 340 | perf_header__clear_feat(&session->header, HEADER_BRANCH_STACK); |
362 | } | 341 | } |
363 | 342 | ||
364 | static int __cmd_record(struct perf_record *rec, int argc, const char **argv) | 343 | static volatile int workload_exec_errno; |
344 | |||
345 | /* | ||
346 | * perf_evlist__prepare_workload will send a SIGUSR1 | ||
347 | * if the fork fails, since we asked by setting its | ||
348 | * want_signal to true. | ||
349 | */ | ||
350 | static void workload_exec_failed_signal(int signo, siginfo_t *info, | ||
351 | void *ucontext __maybe_unused) | ||
352 | { | ||
353 | workload_exec_errno = info->si_value.sival_int; | ||
354 | done = 1; | ||
355 | signr = signo; | ||
356 | child_finished = 1; | ||
357 | } | ||
358 | |||
359 | static int __cmd_record(struct record *rec, int argc, const char **argv) | ||
365 | { | 360 | { |
366 | int err; | 361 | int err; |
367 | unsigned long waking = 0; | 362 | unsigned long waking = 0; |
368 | const bool forks = argc > 0; | 363 | const bool forks = argc > 0; |
369 | struct machine *machine; | 364 | struct machine *machine; |
370 | struct perf_tool *tool = &rec->tool; | 365 | struct perf_tool *tool = &rec->tool; |
371 | struct perf_record_opts *opts = &rec->opts; | 366 | struct record_opts *opts = &rec->opts; |
372 | struct perf_evlist *evsel_list = rec->evlist; | ||
373 | struct perf_data_file *file = &rec->file; | 367 | struct perf_data_file *file = &rec->file; |
374 | struct perf_session *session; | 368 | struct perf_session *session; |
375 | bool disabled = false; | 369 | bool disabled = false; |
376 | 370 | ||
377 | rec->progname = argv[0]; | 371 | rec->progname = argv[0]; |
378 | 372 | ||
379 | on_exit(perf_record__sig_exit, rec); | 373 | on_exit(record__sig_exit, rec); |
380 | signal(SIGCHLD, sig_handler); | 374 | signal(SIGCHLD, sig_handler); |
381 | signal(SIGINT, sig_handler); | 375 | signal(SIGINT, sig_handler); |
382 | signal(SIGUSR1, sig_handler); | ||
383 | signal(SIGTERM, sig_handler); | 376 | signal(SIGTERM, sig_handler); |
384 | 377 | ||
385 | session = perf_session__new(file, false, NULL); | 378 | session = perf_session__new(file, false, NULL); |
@@ -390,37 +383,37 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv) | |||
390 | 383 | ||
391 | rec->session = session; | 384 | rec->session = session; |
392 | 385 | ||
393 | perf_record__init_features(rec); | 386 | record__init_features(rec); |
394 | 387 | ||
395 | if (forks) { | 388 | if (forks) { |
396 | err = perf_evlist__prepare_workload(evsel_list, &opts->target, | 389 | err = perf_evlist__prepare_workload(rec->evlist, &opts->target, |
397 | argv, file->is_pipe, | 390 | argv, file->is_pipe, |
398 | true); | 391 | workload_exec_failed_signal); |
399 | if (err < 0) { | 392 | if (err < 0) { |
400 | pr_err("Couldn't run the workload!\n"); | 393 | pr_err("Couldn't run the workload!\n"); |
401 | goto out_delete_session; | 394 | goto out_delete_session; |
402 | } | 395 | } |
403 | } | 396 | } |
404 | 397 | ||
405 | if (perf_record__open(rec) != 0) { | 398 | if (record__open(rec) != 0) { |
406 | err = -1; | 399 | err = -1; |
407 | goto out_delete_session; | 400 | goto out_delete_session; |
408 | } | 401 | } |
409 | 402 | ||
410 | if (!evsel_list->nr_groups) | 403 | if (!rec->evlist->nr_groups) |
411 | perf_header__clear_feat(&session->header, HEADER_GROUP_DESC); | 404 | perf_header__clear_feat(&session->header, HEADER_GROUP_DESC); |
412 | 405 | ||
413 | /* | 406 | /* |
414 | * perf_session__delete(session) will be called at perf_record__exit() | 407 | * perf_session__delete(session) will be called at record__exit() |
415 | */ | 408 | */ |
416 | on_exit(perf_record__exit, rec); | 409 | on_exit(record__exit, rec); |
417 | 410 | ||
418 | if (file->is_pipe) { | 411 | if (file->is_pipe) { |
419 | err = perf_header__write_pipe(file->fd); | 412 | err = perf_header__write_pipe(file->fd); |
420 | if (err < 0) | 413 | if (err < 0) |
421 | goto out_delete_session; | 414 | goto out_delete_session; |
422 | } else { | 415 | } else { |
423 | err = perf_session__write_header(session, evsel_list, | 416 | err = perf_session__write_header(session, rec->evlist, |
424 | file->fd, false); | 417 | file->fd, false); |
425 | if (err < 0) | 418 | if (err < 0) |
426 | goto out_delete_session; | 419 | goto out_delete_session; |
@@ -444,7 +437,7 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv) | |||
444 | goto out_delete_session; | 437 | goto out_delete_session; |
445 | } | 438 | } |
446 | 439 | ||
447 | if (have_tracepoints(&evsel_list->entries)) { | 440 | if (have_tracepoints(&rec->evlist->entries)) { |
448 | /* | 441 | /* |
449 | * FIXME err <= 0 here actually means that | 442 | * FIXME err <= 0 here actually means that |
450 | * there were no tracepoints so its not really | 443 | * there were no tracepoints so its not really |
@@ -453,7 +446,7 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv) | |||
453 | * return this more properly and also | 446 | * return this more properly and also |
454 | * propagate errors that now are calling die() | 447 | * propagate errors that now are calling die() |
455 | */ | 448 | */ |
456 | err = perf_event__synthesize_tracing_data(tool, file->fd, evsel_list, | 449 | err = perf_event__synthesize_tracing_data(tool, file->fd, rec->evlist, |
457 | process_synthesized_event); | 450 | process_synthesized_event); |
458 | if (err <= 0) { | 451 | if (err <= 0) { |
459 | pr_err("Couldn't record tracing data.\n"); | 452 | pr_err("Couldn't record tracing data.\n"); |
@@ -485,7 +478,7 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv) | |||
485 | perf_event__synthesize_guest_os, tool); | 478 | perf_event__synthesize_guest_os, tool); |
486 | } | 479 | } |
487 | 480 | ||
488 | err = __machine__synthesize_threads(machine, tool, &opts->target, evsel_list->threads, | 481 | err = __machine__synthesize_threads(machine, tool, &opts->target, rec->evlist->threads, |
489 | process_synthesized_event, opts->sample_address); | 482 | process_synthesized_event, opts->sample_address); |
490 | if (err != 0) | 483 | if (err != 0) |
491 | goto out_delete_session; | 484 | goto out_delete_session; |
@@ -506,19 +499,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, | 499 | * (apart from group members) have enable_on_exec=1 set, |
507 | * so don't spoil it by prematurely enabling them. | 500 | * so don't spoil it by prematurely enabling them. |
508 | */ | 501 | */ |
509 | if (!target__none(&opts->target)) | 502 | if (!target__none(&opts->target) && !opts->initial_delay) |
510 | perf_evlist__enable(evsel_list); | 503 | perf_evlist__enable(rec->evlist); |
511 | 504 | ||
512 | /* | 505 | /* |
513 | * Let the child rip | 506 | * Let the child rip |
514 | */ | 507 | */ |
515 | if (forks) | 508 | if (forks) |
516 | perf_evlist__start_workload(evsel_list); | 509 | perf_evlist__start_workload(rec->evlist); |
510 | |||
511 | if (opts->initial_delay) { | ||
512 | usleep(opts->initial_delay * 1000); | ||
513 | perf_evlist__enable(rec->evlist); | ||
514 | } | ||
517 | 515 | ||
518 | for (;;) { | 516 | for (;;) { |
519 | int hits = rec->samples; | 517 | int hits = rec->samples; |
520 | 518 | ||
521 | if (perf_record__mmap_read_all(rec) < 0) { | 519 | if (record__mmap_read_all(rec) < 0) { |
522 | err = -1; | 520 | err = -1; |
523 | goto out_delete_session; | 521 | goto out_delete_session; |
524 | } | 522 | } |
@@ -526,7 +524,7 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv) | |||
526 | if (hits == rec->samples) { | 524 | if (hits == rec->samples) { |
527 | if (done) | 525 | if (done) |
528 | break; | 526 | break; |
529 | err = poll(evsel_list->pollfd, evsel_list->nr_fds, -1); | 527 | err = poll(rec->evlist->pollfd, rec->evlist->nr_fds, -1); |
530 | waking++; | 528 | waking++; |
531 | } | 529 | } |
532 | 530 | ||
@@ -536,11 +534,19 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv) | |||
536 | * disable events in this case. | 534 | * disable events in this case. |
537 | */ | 535 | */ |
538 | if (done && !disabled && !target__none(&opts->target)) { | 536 | if (done && !disabled && !target__none(&opts->target)) { |
539 | perf_evlist__disable(evsel_list); | 537 | perf_evlist__disable(rec->evlist); |
540 | disabled = true; | 538 | disabled = true; |
541 | } | 539 | } |
542 | } | 540 | } |
543 | 541 | ||
542 | if (forks && workload_exec_errno) { | ||
543 | char msg[512]; | ||
544 | const char *emsg = strerror_r(workload_exec_errno, msg, sizeof(msg)); | ||
545 | pr_err("Workload failed: %s\n", emsg); | ||
546 | err = -1; | ||
547 | goto out_delete_session; | ||
548 | } | ||
549 | |||
544 | if (quiet || signr == SIGUSR1) | 550 | if (quiet || signr == SIGUSR1) |
545 | return 0; | 551 | return 0; |
546 | 552 | ||
@@ -677,7 +683,7 @@ static int get_stack_size(char *str, unsigned long *_size) | |||
677 | } | 683 | } |
678 | #endif /* HAVE_LIBUNWIND_SUPPORT */ | 684 | #endif /* HAVE_LIBUNWIND_SUPPORT */ |
679 | 685 | ||
680 | int record_parse_callchain(const char *arg, struct perf_record_opts *opts) | 686 | int record_parse_callchain(const char *arg, struct record_opts *opts) |
681 | { | 687 | { |
682 | char *tok, *name, *saveptr = NULL; | 688 | char *tok, *name, *saveptr = NULL; |
683 | char *buf; | 689 | char *buf; |
@@ -733,7 +739,7 @@ int record_parse_callchain(const char *arg, struct perf_record_opts *opts) | |||
733 | return ret; | 739 | return ret; |
734 | } | 740 | } |
735 | 741 | ||
736 | static void callchain_debug(struct perf_record_opts *opts) | 742 | static void callchain_debug(struct record_opts *opts) |
737 | { | 743 | { |
738 | pr_debug("callchain: type %d\n", opts->call_graph); | 744 | pr_debug("callchain: type %d\n", opts->call_graph); |
739 | 745 | ||
@@ -746,7 +752,7 @@ int record_parse_callchain_opt(const struct option *opt, | |||
746 | const char *arg, | 752 | const char *arg, |
747 | int unset) | 753 | int unset) |
748 | { | 754 | { |
749 | struct perf_record_opts *opts = opt->value; | 755 | struct record_opts *opts = opt->value; |
750 | int ret; | 756 | int ret; |
751 | 757 | ||
752 | /* --no-call-graph */ | 758 | /* --no-call-graph */ |
@@ -767,7 +773,7 @@ int record_callchain_opt(const struct option *opt, | |||
767 | const char *arg __maybe_unused, | 773 | const char *arg __maybe_unused, |
768 | int unset __maybe_unused) | 774 | int unset __maybe_unused) |
769 | { | 775 | { |
770 | struct perf_record_opts *opts = opt->value; | 776 | struct record_opts *opts = opt->value; |
771 | 777 | ||
772 | if (opts->call_graph == CALLCHAIN_NONE) | 778 | if (opts->call_graph == CALLCHAIN_NONE) |
773 | opts->call_graph = CALLCHAIN_FP; | 779 | opts->call_graph = CALLCHAIN_FP; |
@@ -783,8 +789,8 @@ static const char * const record_usage[] = { | |||
783 | }; | 789 | }; |
784 | 790 | ||
785 | /* | 791 | /* |
786 | * XXX Ideally would be local to cmd_record() and passed to a perf_record__new | 792 | * 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 | 793 | * 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 | 794 | * after cmd_record() exits, but since record_options need to be accessible to |
789 | * builtin-script, leave it here. | 795 | * builtin-script, leave it here. |
790 | * | 796 | * |
@@ -792,7 +798,7 @@ static const char * const record_usage[] = { | |||
792 | * | 798 | * |
793 | * Just say no to tons of global variables, sigh. | 799 | * Just say no to tons of global variables, sigh. |
794 | */ | 800 | */ |
795 | static struct perf_record record = { | 801 | static struct record record = { |
796 | .opts = { | 802 | .opts = { |
797 | .mmap_pages = UINT_MAX, | 803 | .mmap_pages = UINT_MAX, |
798 | .user_freq = UINT_MAX, | 804 | .user_freq = UINT_MAX, |
@@ -800,6 +806,7 @@ static struct perf_record record = { | |||
800 | .freq = 4000, | 806 | .freq = 4000, |
801 | .target = { | 807 | .target = { |
802 | .uses_mmap = true, | 808 | .uses_mmap = true, |
809 | .default_per_cpu = true, | ||
803 | }, | 810 | }, |
804 | }, | 811 | }, |
805 | }; | 812 | }; |
@@ -815,7 +822,7 @@ const char record_callchain_help[] = CALLCHAIN_HELP "fp"; | |||
815 | /* | 822 | /* |
816 | * XXX Will stay a global variable till we fix builtin-script.c to stop messing | 823 | * 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 | 824 | * 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, | 825 | * from builtin-record.c, i.e. use record_opts, |
819 | * perf_evlist__prepare_workload, etc instead of fork+exec'in 'perf record', | 826 | * perf_evlist__prepare_workload, etc instead of fork+exec'in 'perf record', |
820 | * using pipes, etc. | 827 | * using pipes, etc. |
821 | */ | 828 | */ |
@@ -842,8 +849,9 @@ const struct option record_options[] = { | |||
842 | OPT_U64('c', "count", &record.opts.user_interval, "event period to sample"), | 849 | OPT_U64('c', "count", &record.opts.user_interval, "event period to sample"), |
843 | OPT_STRING('o', "output", &record.file.path, "file", | 850 | OPT_STRING('o', "output", &record.file.path, "file", |
844 | "output file name"), | 851 | "output file name"), |
845 | OPT_BOOLEAN('i', "no-inherit", &record.opts.no_inherit, | 852 | OPT_BOOLEAN_SET('i', "no-inherit", &record.opts.no_inherit, |
846 | "child tasks do not inherit counters"), | 853 | &record.opts.no_inherit_set, |
854 | "child tasks do not inherit counters"), | ||
847 | OPT_UINTEGER('F', "freq", &record.opts.user_freq, "profile at this frequency"), | 855 | OPT_UINTEGER('F', "freq", &record.opts.user_freq, "profile at this frequency"), |
848 | OPT_CALLBACK('m', "mmap-pages", &record.opts.mmap_pages, "pages", | 856 | OPT_CALLBACK('m', "mmap-pages", &record.opts.mmap_pages, "pages", |
849 | "number of mmap data pages", | 857 | "number of mmap data pages", |
@@ -874,6 +882,8 @@ const struct option record_options[] = { | |||
874 | OPT_CALLBACK('G', "cgroup", &record.evlist, "name", | 882 | OPT_CALLBACK('G', "cgroup", &record.evlist, "name", |
875 | "monitor event in cgroup name only", | 883 | "monitor event in cgroup name only", |
876 | parse_cgroups), | 884 | parse_cgroups), |
885 | OPT_UINTEGER(0, "initial-delay", &record.opts.initial_delay, | ||
886 | "ms to wait before starting measurement after program start"), | ||
877 | OPT_STRING('u', "uid", &record.opts.target.uid_str, "user", | 887 | OPT_STRING('u', "uid", &record.opts.target.uid_str, "user", |
878 | "user to profile"), | 888 | "user to profile"), |
879 | 889 | ||
@@ -888,24 +898,21 @@ const struct option record_options[] = { | |||
888 | "sample by weight (on special events only)"), | 898 | "sample by weight (on special events only)"), |
889 | OPT_BOOLEAN(0, "transaction", &record.opts.sample_transaction, | 899 | OPT_BOOLEAN(0, "transaction", &record.opts.sample_transaction, |
890 | "sample transaction flags (special events only)"), | 900 | "sample transaction flags (special events only)"), |
891 | OPT_BOOLEAN(0, "force-per-cpu", &record.opts.target.force_per_cpu, | 901 | OPT_BOOLEAN(0, "per-thread", &record.opts.target.per_thread, |
892 | "force the use of per-cpu mmaps"), | 902 | "use per-thread mmaps"), |
893 | OPT_END() | 903 | OPT_END() |
894 | }; | 904 | }; |
895 | 905 | ||
896 | int cmd_record(int argc, const char **argv, const char *prefix __maybe_unused) | 906 | int cmd_record(int argc, const char **argv, const char *prefix __maybe_unused) |
897 | { | 907 | { |
898 | int err = -ENOMEM; | 908 | int err = -ENOMEM; |
899 | struct perf_evlist *evsel_list; | 909 | struct record *rec = &record; |
900 | struct perf_record *rec = &record; | ||
901 | char errbuf[BUFSIZ]; | 910 | char errbuf[BUFSIZ]; |
902 | 911 | ||
903 | evsel_list = perf_evlist__new(); | 912 | rec->evlist = perf_evlist__new(); |
904 | if (evsel_list == NULL) | 913 | if (rec->evlist == NULL) |
905 | return -ENOMEM; | 914 | return -ENOMEM; |
906 | 915 | ||
907 | rec->evlist = evsel_list; | ||
908 | |||
909 | argc = parse_options(argc, argv, record_options, record_usage, | 916 | argc = parse_options(argc, argv, record_options, record_usage, |
910 | PARSE_OPT_STOP_AT_NON_OPTION); | 917 | PARSE_OPT_STOP_AT_NON_OPTION); |
911 | if (!argc && target__none(&rec->opts.target)) | 918 | if (!argc && target__none(&rec->opts.target)) |
@@ -932,12 +939,15 @@ int cmd_record(int argc, const char **argv, const char *prefix __maybe_unused) | |||
932 | if (rec->no_buildid_cache || rec->no_buildid) | 939 | if (rec->no_buildid_cache || rec->no_buildid) |
933 | disable_buildid_cache(); | 940 | disable_buildid_cache(); |
934 | 941 | ||
935 | if (evsel_list->nr_entries == 0 && | 942 | if (rec->evlist->nr_entries == 0 && |
936 | perf_evlist__add_default(evsel_list) < 0) { | 943 | perf_evlist__add_default(rec->evlist) < 0) { |
937 | pr_err("Not enough memory for event selector list\n"); | 944 | pr_err("Not enough memory for event selector list\n"); |
938 | goto out_symbol_exit; | 945 | goto out_symbol_exit; |
939 | } | 946 | } |
940 | 947 | ||
948 | if (rec->opts.target.tid && !rec->opts.no_inherit_set) | ||
949 | rec->opts.no_inherit = true; | ||
950 | |||
941 | err = target__validate(&rec->opts.target); | 951 | err = target__validate(&rec->opts.target); |
942 | if (err) { | 952 | if (err) { |
943 | target__strerror(&rec->opts.target, err, errbuf, BUFSIZ); | 953 | target__strerror(&rec->opts.target, err, errbuf, BUFSIZ); |
@@ -956,20 +966,15 @@ int cmd_record(int argc, const char **argv, const char *prefix __maybe_unused) | |||
956 | } | 966 | } |
957 | 967 | ||
958 | err = -ENOMEM; | 968 | err = -ENOMEM; |
959 | if (perf_evlist__create_maps(evsel_list, &rec->opts.target) < 0) | 969 | if (perf_evlist__create_maps(rec->evlist, &rec->opts.target) < 0) |
960 | usage_with_options(record_usage, record_options); | 970 | usage_with_options(record_usage, record_options); |
961 | 971 | ||
962 | if (perf_record_opts__config(&rec->opts)) { | 972 | if (record_opts__config(&rec->opts)) { |
963 | err = -EINVAL; | 973 | err = -EINVAL; |
964 | goto out_free_fd; | 974 | goto out_symbol_exit; |
965 | } | 975 | } |
966 | 976 | ||
967 | err = __cmd_record(&record, argc, argv); | 977 | 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: | 978 | out_symbol_exit: |
974 | symbol__exit(); | 979 | symbol__exit(); |
975 | return err; | 980 | return err; |
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index 8cf8e66ba594..46864dd7eb83 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,40 @@ 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__resolve_callchain(struct report *rep, struct symbol **parent, |
77 | struct addr_location *al, | 79 | struct perf_evsel *evsel, struct addr_location *al, |
78 | struct perf_sample *sample, | 80 | struct perf_sample *sample) |
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 | if ((sort__has_parent || symbol_conf.use_callchain) && sample->callchain) { |
83 | return machine__resolve_callchain(al->machine, evsel, al->thread, sample, | ||
84 | parent, al, rep->max_stack); | ||
85 | } | ||
86 | return 0; | ||
87 | } | ||
88 | |||
89 | static int hist_entry__append_callchain(struct hist_entry *he, struct perf_sample *sample) | ||
90 | { | ||
91 | if (!symbol_conf.use_callchain) | ||
92 | return 0; | ||
93 | return callchain_append(he->callchain, &callchain_cursor, sample->period); | ||
94 | } | ||
95 | |||
96 | static int report__add_mem_hist_entry(struct perf_tool *tool, struct addr_location *al, | ||
97 | struct perf_sample *sample, struct perf_evsel *evsel, | ||
98 | union perf_event *event) | ||
99 | { | ||
100 | struct report *rep = container_of(tool, struct report, tool); | ||
84 | struct symbol *parent = NULL; | 101 | struct symbol *parent = NULL; |
85 | u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; | 102 | u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; |
86 | int err = 0; | ||
87 | struct hist_entry *he; | 103 | struct hist_entry *he; |
88 | struct mem_info *mi, *mx; | 104 | struct mem_info *mi, *mx; |
89 | uint64_t cost; | 105 | uint64_t cost; |
106 | int err = report__resolve_callchain(rep, &parent, evsel, al, sample); | ||
90 | 107 | ||
91 | if ((sort__has_parent || symbol_conf.use_callchain) && | 108 | if (err) |
92 | sample->callchain) { | 109 | 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 | 110 | ||
100 | mi = machine__resolve_mem(machine, al->thread, sample, cpumode); | 111 | mi = machine__resolve_mem(al->machine, al->thread, sample, cpumode); |
101 | if (!mi) | 112 | if (!mi) |
102 | return -ENOMEM; | 113 | return -ENOMEM; |
103 | 114 | ||
@@ -120,77 +131,36 @@ static int perf_report__add_mem_hist_entry(struct perf_tool *tool, | |||
120 | if (!he) | 131 | if (!he) |
121 | return -ENOMEM; | 132 | return -ENOMEM; |
122 | 133 | ||
123 | /* | 134 | err = hist_entry__inc_addr_samples(he, evsel->idx, al->addr); |
124 | * In the TUI browser, we are doing integrated annotation, | 135 | if (err) |
125 | * so we don't allocate the extra space needed because the stdio | 136 | goto out; |
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); | ||
137 | if (err) | ||
138 | goto out; | ||
139 | } | ||
140 | |||
141 | if (sort__has_sym && he->mem_info->daddr.sym && use_browser > 0) { | ||
142 | struct annotation *notes; | ||
143 | 137 | ||
144 | mx = he->mem_info; | 138 | mx = he->mem_info; |
145 | 139 | err = addr_map_symbol__inc_samples(&mx->daddr, evsel->idx); | |
146 | notes = symbol__annotation(mx->daddr.sym); | 140 | if (err) |
147 | if (notes->src == NULL && symbol__alloc_hist(mx->daddr.sym) < 0) | 141 | goto out; |
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) | ||
155 | goto out; | ||
156 | } | ||
157 | 142 | ||
158 | evsel->hists.stats.total_period += cost; | 143 | evsel->hists.stats.total_period += cost; |
159 | hists__inc_nr_events(&evsel->hists, PERF_RECORD_SAMPLE); | 144 | hists__inc_nr_events(&evsel->hists, PERF_RECORD_SAMPLE); |
160 | err = 0; | 145 | 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: | 146 | out: |
168 | return err; | 147 | return err; |
169 | } | 148 | } |
170 | 149 | ||
171 | static int perf_report__add_branch_hist_entry(struct perf_tool *tool, | 150 | static int report__add_branch_hist_entry(struct perf_tool *tool, struct addr_location *al, |
172 | struct addr_location *al, | 151 | struct perf_sample *sample, struct perf_evsel *evsel) |
173 | struct perf_sample *sample, | ||
174 | struct perf_evsel *evsel, | ||
175 | struct machine *machine) | ||
176 | { | 152 | { |
177 | struct perf_report *rep = container_of(tool, struct perf_report, tool); | 153 | struct report *rep = container_of(tool, struct report, tool); |
178 | struct symbol *parent = NULL; | 154 | struct symbol *parent = NULL; |
179 | int err = 0; | ||
180 | unsigned i; | 155 | unsigned i; |
181 | struct hist_entry *he; | 156 | struct hist_entry *he; |
182 | struct branch_info *bi, *bx; | 157 | struct branch_info *bi, *bx; |
158 | int err = report__resolve_callchain(rep, &parent, evsel, al, sample); | ||
183 | 159 | ||
184 | if ((sort__has_parent || symbol_conf.use_callchain) | 160 | if (err) |
185 | && sample->callchain) { | 161 | 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 | 162 | ||
193 | bi = machine__resolve_bstack(machine, al->thread, | 163 | bi = machine__resolve_bstack(al->machine, al->thread, |
194 | sample->branch_stack); | 164 | sample->branch_stack); |
195 | if (!bi) | 165 | if (!bi) |
196 | return -ENOMEM; | 166 | return -ENOMEM; |
@@ -212,35 +182,15 @@ static int perf_report__add_branch_hist_entry(struct perf_tool *tool, | |||
212 | he = __hists__add_entry(&evsel->hists, al, parent, &bi[i], NULL, | 182 | he = __hists__add_entry(&evsel->hists, al, parent, &bi[i], NULL, |
213 | 1, 1, 0); | 183 | 1, 1, 0); |
214 | if (he) { | 184 | if (he) { |
215 | struct annotation *notes; | ||
216 | bx = he->branch_info; | 185 | bx = he->branch_info; |
217 | if (bx->from.sym && use_browser == 1 && sort__has_sym) { | 186 | err = addr_map_symbol__inc_samples(&bx->from, evsel->idx); |
218 | notes = symbol__annotation(bx->from.sym); | 187 | if (err) |
219 | if (!notes->src | 188 | goto out; |
220 | && symbol__alloc_hist(bx->from.sym) < 0) | 189 | |
221 | goto out; | 190 | err = addr_map_symbol__inc_samples(&bx->to, evsel->idx); |
222 | 191 | if (err) | |
223 | err = symbol__inc_addr_samples(bx->from.sym, | 192 | goto out; |
224 | bx->from.map, | ||
225 | evsel->idx, | ||
226 | bx->from.al_addr); | ||
227 | if (err) | ||
228 | goto out; | ||
229 | } | ||
230 | 193 | ||
231 | if (bx->to.sym && use_browser == 1 && sort__has_sym) { | ||
232 | notes = symbol__annotation(bx->to.sym); | ||
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) | ||
242 | goto out; | ||
243 | } | ||
244 | evsel->hists.stats.total_period += 1; | 194 | evsel->hists.stats.total_period += 1; |
245 | hists__inc_nr_events(&evsel->hists, PERF_RECORD_SAMPLE); | 195 | hists__inc_nr_events(&evsel->hists, PERF_RECORD_SAMPLE); |
246 | } else | 196 | } else |
@@ -252,24 +202,16 @@ out: | |||
252 | return err; | 202 | return err; |
253 | } | 203 | } |
254 | 204 | ||
255 | static int perf_evsel__add_hist_entry(struct perf_tool *tool, | 205 | static int report__add_hist_entry(struct perf_tool *tool, struct perf_evsel *evsel, |
256 | struct perf_evsel *evsel, | 206 | struct addr_location *al, struct perf_sample *sample) |
257 | struct addr_location *al, | ||
258 | struct perf_sample *sample, | ||
259 | struct machine *machine) | ||
260 | { | 207 | { |
261 | struct perf_report *rep = container_of(tool, struct perf_report, tool); | 208 | struct report *rep = container_of(tool, struct report, tool); |
262 | struct symbol *parent = NULL; | 209 | struct symbol *parent = NULL; |
263 | int err = 0; | ||
264 | struct hist_entry *he; | 210 | struct hist_entry *he; |
211 | int err = report__resolve_callchain(rep, &parent, evsel, al, sample); | ||
265 | 212 | ||
266 | if ((sort__has_parent || symbol_conf.use_callchain) && sample->callchain) { | 213 | if (err) |
267 | err = machine__resolve_callchain(machine, evsel, al->thread, | 214 | return err; |
268 | sample, &parent, al, | ||
269 | rep->max_stack); | ||
270 | if (err) | ||
271 | return err; | ||
272 | } | ||
273 | 215 | ||
274 | he = __hists__add_entry(&evsel->hists, al, parent, NULL, NULL, | 216 | he = __hists__add_entry(&evsel->hists, al, parent, NULL, NULL, |
275 | sample->period, sample->weight, | 217 | sample->period, sample->weight, |
@@ -277,30 +219,11 @@ static int perf_evsel__add_hist_entry(struct perf_tool *tool, | |||
277 | if (he == NULL) | 219 | if (he == NULL) |
278 | return -ENOMEM; | 220 | return -ENOMEM; |
279 | 221 | ||
280 | if (symbol_conf.use_callchain) { | 222 | err = hist_entry__append_callchain(he, sample); |
281 | err = callchain_append(he->callchain, | 223 | if (err) |
282 | &callchain_cursor, | 224 | 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 | |||
301 | err = hist_entry__inc_addr_samples(he, evsel->idx, al->addr); | ||
302 | } | ||
303 | 225 | ||
226 | err = hist_entry__inc_addr_samples(he, evsel->idx, al->addr); | ||
304 | evsel->hists.stats.total_period += sample->period; | 227 | evsel->hists.stats.total_period += sample->period; |
305 | hists__inc_nr_events(&evsel->hists, PERF_RECORD_SAMPLE); | 228 | hists__inc_nr_events(&evsel->hists, PERF_RECORD_SAMPLE); |
306 | out: | 229 | out: |
@@ -314,13 +237,13 @@ static int process_sample_event(struct perf_tool *tool, | |||
314 | struct perf_evsel *evsel, | 237 | struct perf_evsel *evsel, |
315 | struct machine *machine) | 238 | struct machine *machine) |
316 | { | 239 | { |
317 | struct perf_report *rep = container_of(tool, struct perf_report, tool); | 240 | struct report *rep = container_of(tool, struct report, tool); |
318 | struct addr_location al; | 241 | struct addr_location al; |
319 | int ret; | 242 | int ret; |
320 | 243 | ||
321 | if (perf_event__preprocess_sample(event, machine, &al, sample) < 0) { | 244 | if (perf_event__preprocess_sample(event, machine, &al, sample) < 0) { |
322 | fprintf(stderr, "problem processing %d event, skipping it.\n", | 245 | pr_debug("problem processing %d event, skipping it.\n", |
323 | event->header.type); | 246 | event->header.type); |
324 | return -1; | 247 | return -1; |
325 | } | 248 | } |
326 | 249 | ||
@@ -331,21 +254,18 @@ static int process_sample_event(struct perf_tool *tool, | |||
331 | return 0; | 254 | return 0; |
332 | 255 | ||
333 | if (sort__mode == SORT_MODE__BRANCH) { | 256 | if (sort__mode == SORT_MODE__BRANCH) { |
334 | ret = perf_report__add_branch_hist_entry(tool, &al, sample, | 257 | ret = report__add_branch_hist_entry(tool, &al, sample, evsel); |
335 | evsel, machine); | ||
336 | if (ret < 0) | 258 | if (ret < 0) |
337 | pr_debug("problem adding lbr entry, skipping event\n"); | 259 | pr_debug("problem adding lbr entry, skipping event\n"); |
338 | } else if (rep->mem_mode == 1) { | 260 | } else if (rep->mem_mode == 1) { |
339 | ret = perf_report__add_mem_hist_entry(tool, &al, sample, | 261 | ret = report__add_mem_hist_entry(tool, &al, sample, evsel, event); |
340 | evsel, machine, event); | ||
341 | if (ret < 0) | 262 | if (ret < 0) |
342 | pr_debug("problem adding mem entry, skipping event\n"); | 263 | pr_debug("problem adding mem entry, skipping event\n"); |
343 | } else { | 264 | } else { |
344 | if (al.map != NULL) | 265 | if (al.map != NULL) |
345 | al.map->dso->hit = 1; | 266 | al.map->dso->hit = 1; |
346 | 267 | ||
347 | ret = perf_evsel__add_hist_entry(tool, evsel, &al, sample, | 268 | ret = report__add_hist_entry(tool, evsel, &al, sample); |
348 | machine); | ||
349 | if (ret < 0) | 269 | if (ret < 0) |
350 | pr_debug("problem incrementing symbol period, skipping event\n"); | 270 | pr_debug("problem incrementing symbol period, skipping event\n"); |
351 | } | 271 | } |
@@ -358,7 +278,7 @@ static int process_read_event(struct perf_tool *tool, | |||
358 | struct perf_evsel *evsel, | 278 | struct perf_evsel *evsel, |
359 | struct machine *machine __maybe_unused) | 279 | struct machine *machine __maybe_unused) |
360 | { | 280 | { |
361 | struct perf_report *rep = container_of(tool, struct perf_report, tool); | 281 | struct report *rep = container_of(tool, struct report, tool); |
362 | 282 | ||
363 | if (rep->show_threads) { | 283 | if (rep->show_threads) { |
364 | const char *name = evsel ? perf_evsel__name(evsel) : "unknown"; | 284 | const char *name = evsel ? perf_evsel__name(evsel) : "unknown"; |
@@ -377,7 +297,7 @@ static int process_read_event(struct perf_tool *tool, | |||
377 | } | 297 | } |
378 | 298 | ||
379 | /* For pipe mode, sample_type is not currently set */ | 299 | /* For pipe mode, sample_type is not currently set */ |
380 | static int perf_report__setup_sample_type(struct perf_report *rep) | 300 | static int report__setup_sample_type(struct report *rep) |
381 | { | 301 | { |
382 | struct perf_session *session = rep->session; | 302 | struct perf_session *session = rep->session; |
383 | u64 sample_type = perf_evlist__combined_sample_type(session->evlist); | 303 | u64 sample_type = perf_evlist__combined_sample_type(session->evlist); |
@@ -422,8 +342,7 @@ static void sig_handler(int sig __maybe_unused) | |||
422 | session_done = 1; | 342 | session_done = 1; |
423 | } | 343 | } |
424 | 344 | ||
425 | static size_t hists__fprintf_nr_sample_events(struct perf_report *rep, | 345 | static size_t hists__fprintf_nr_sample_events(struct hists *hists, struct report *rep, |
426 | struct hists *hists, | ||
427 | const char *evname, FILE *fp) | 346 | const char *evname, FILE *fp) |
428 | { | 347 | { |
429 | size_t ret; | 348 | size_t ret; |
@@ -460,12 +379,12 @@ static size_t hists__fprintf_nr_sample_events(struct perf_report *rep, | |||
460 | } | 379 | } |
461 | 380 | ||
462 | static int perf_evlist__tty_browse_hists(struct perf_evlist *evlist, | 381 | static int perf_evlist__tty_browse_hists(struct perf_evlist *evlist, |
463 | struct perf_report *rep, | 382 | struct report *rep, |
464 | const char *help) | 383 | const char *help) |
465 | { | 384 | { |
466 | struct perf_evsel *pos; | 385 | struct perf_evsel *pos; |
467 | 386 | ||
468 | list_for_each_entry(pos, &evlist->entries, node) { | 387 | evlist__for_each(evlist, pos) { |
469 | struct hists *hists = &pos->hists; | 388 | struct hists *hists = &pos->hists; |
470 | const char *evname = perf_evsel__name(pos); | 389 | const char *evname = perf_evsel__name(pos); |
471 | 390 | ||
@@ -473,7 +392,7 @@ static int perf_evlist__tty_browse_hists(struct perf_evlist *evlist, | |||
473 | !perf_evsel__is_group_leader(pos)) | 392 | !perf_evsel__is_group_leader(pos)) |
474 | continue; | 393 | continue; |
475 | 394 | ||
476 | hists__fprintf_nr_sample_events(rep, hists, evname, stdout); | 395 | hists__fprintf_nr_sample_events(hists, rep, evname, stdout); |
477 | hists__fprintf(hists, true, 0, 0, rep->min_percent, stdout); | 396 | hists__fprintf(hists, true, 0, 0, rep->min_percent, stdout); |
478 | fprintf(stdout, "\n\n"); | 397 | fprintf(stdout, "\n\n"); |
479 | } | 398 | } |
@@ -493,43 +412,11 @@ static int perf_evlist__tty_browse_hists(struct perf_evlist *evlist, | |||
493 | return 0; | 412 | return 0; |
494 | } | 413 | } |
495 | 414 | ||
496 | static int __cmd_report(struct perf_report *rep) | 415 | static void report__warn_kptr_restrict(const struct report *rep) |
497 | { | 416 | { |
498 | int ret = -EINVAL; | 417 | struct map *kernel_map = rep->session->machines.host.vmlinux_maps[MAP__FUNCTION]; |
499 | u64 nr_samples; | 418 | 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 | |||
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 | 419 | ||
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 || | 420 | if (kernel_map == NULL || |
534 | (kernel_map->dso->hit && | 421 | (kernel_map->dso->hit && |
535 | (kernel_kmap->ref_reloc_sym == NULL || | 422 | (kernel_kmap->ref_reloc_sym == NULL || |
@@ -552,26 +439,73 @@ static int __cmd_report(struct perf_report *rep) | |||
552 | "Samples in kernel modules can't be resolved as well.\n\n", | 439 | "Samples in kernel modules can't be resolved as well.\n\n", |
553 | desc); | 440 | desc); |
554 | } | 441 | } |
442 | } | ||
555 | 443 | ||
556 | if (verbose > 3) | 444 | static int report__gtk_browse_hists(struct report *rep, const char *help) |
557 | perf_session__fprintf(session, stdout); | 445 | { |
446 | int (*hist_browser)(struct perf_evlist *evlist, const char *help, | ||
447 | struct hist_browser_timer *timer, float min_pcnt); | ||
558 | 448 | ||
559 | if (verbose > 2) | 449 | hist_browser = dlsym(perf_gtk_handle, "perf_evlist__gtk_browse_hists"); |
560 | perf_session__fprintf_dsos(session, stdout); | ||
561 | 450 | ||
562 | if (dump_trace) { | 451 | if (hist_browser == NULL) { |
563 | perf_session__fprintf_nr_events(session, stdout); | 452 | ui__error("GTK browser not found!\n"); |
564 | return 0; | 453 | return -1; |
565 | } | 454 | } |
566 | 455 | ||
567 | nr_samples = 0; | 456 | return hist_browser(rep->session->evlist, help, NULL, rep->min_percent); |
568 | list_for_each_entry(pos, &session->evlist->entries, node) | 457 | } |
458 | |||
459 | static int report__browse_hists(struct report *rep) | ||
460 | { | ||
461 | int ret; | ||
462 | struct perf_session *session = rep->session; | ||
463 | struct perf_evlist *evlist = session->evlist; | ||
464 | const char *help = "For a higher level overview, try: perf report --sort comm,dso"; | ||
465 | |||
466 | switch (use_browser) { | ||
467 | case 1: | ||
468 | ret = perf_evlist__tui_browse_hists(evlist, help, NULL, | ||
469 | rep->min_percent, | ||
470 | &session->header.env); | ||
471 | /* | ||
472 | * Usually "ret" is the last pressed key, and we only | ||
473 | * care if the key notifies us to switch data file. | ||
474 | */ | ||
475 | if (ret != K_SWITCH_INPUT_DATA) | ||
476 | ret = 0; | ||
477 | break; | ||
478 | case 2: | ||
479 | ret = report__gtk_browse_hists(rep, help); | ||
480 | break; | ||
481 | default: | ||
482 | ret = perf_evlist__tty_browse_hists(evlist, rep, help); | ||
483 | break; | ||
484 | } | ||
485 | |||
486 | return ret; | ||
487 | } | ||
488 | |||
489 | static u64 report__collapse_hists(struct report *rep) | ||
490 | { | ||
491 | struct ui_progress prog; | ||
492 | struct perf_evsel *pos; | ||
493 | u64 nr_samples = 0; | ||
494 | /* | ||
495 | * Count number of histogram entries to use when showing progress, | ||
496 | * reusing nr_samples variable. | ||
497 | */ | ||
498 | evlist__for_each(rep->session->evlist, pos) | ||
569 | nr_samples += pos->hists.nr_entries; | 499 | nr_samples += pos->hists.nr_entries; |
570 | 500 | ||
571 | ui_progress__init(&prog, nr_samples, "Merging related events..."); | 501 | ui_progress__init(&prog, nr_samples, "Merging related events..."); |
572 | 502 | /* | |
503 | * Count total number of samples, will be used to check if this | ||
504 | * session had any. | ||
505 | */ | ||
573 | nr_samples = 0; | 506 | nr_samples = 0; |
574 | list_for_each_entry(pos, &session->evlist->entries, node) { | 507 | |
508 | evlist__for_each(rep->session->evlist, pos) { | ||
575 | struct hists *hists = &pos->hists; | 509 | struct hists *hists = &pos->hists; |
576 | 510 | ||
577 | if (pos->idx == 0) | 511 | if (pos->idx == 0) |
@@ -589,8 +523,57 @@ static int __cmd_report(struct perf_report *rep) | |||
589 | hists__link(leader_hists, hists); | 523 | hists__link(leader_hists, hists); |
590 | } | 524 | } |
591 | } | 525 | } |
526 | |||
592 | ui_progress__finish(); | 527 | ui_progress__finish(); |
593 | 528 | ||
529 | return nr_samples; | ||
530 | } | ||
531 | |||
532 | static int __cmd_report(struct report *rep) | ||
533 | { | ||
534 | int ret; | ||
535 | u64 nr_samples; | ||
536 | struct perf_session *session = rep->session; | ||
537 | struct perf_evsel *pos; | ||
538 | struct perf_data_file *file = session->file; | ||
539 | |||
540 | signal(SIGINT, sig_handler); | ||
541 | |||
542 | if (rep->cpu_list) { | ||
543 | ret = perf_session__cpu_bitmap(session, rep->cpu_list, | ||
544 | rep->cpu_bitmap); | ||
545 | if (ret) | ||
546 | return ret; | ||
547 | } | ||
548 | |||
549 | if (rep->show_threads) | ||
550 | perf_read_values_init(&rep->show_threads_values); | ||
551 | |||
552 | ret = report__setup_sample_type(rep); | ||
553 | if (ret) | ||
554 | return ret; | ||
555 | |||
556 | ret = perf_session__process_events(session, &rep->tool); | ||
557 | if (ret) | ||
558 | return ret; | ||
559 | |||
560 | report__warn_kptr_restrict(rep); | ||
561 | |||
562 | if (use_browser == 0) { | ||
563 | if (verbose > 3) | ||
564 | perf_session__fprintf(session, stdout); | ||
565 | |||
566 | if (verbose > 2) | ||
567 | perf_session__fprintf_dsos(session, stdout); | ||
568 | |||
569 | if (dump_trace) { | ||
570 | perf_session__fprintf_nr_events(session, stdout); | ||
571 | return 0; | ||
572 | } | ||
573 | } | ||
574 | |||
575 | nr_samples = report__collapse_hists(rep); | ||
576 | |||
594 | if (session_done()) | 577 | if (session_done()) |
595 | return 0; | 578 | return 0; |
596 | 579 | ||
@@ -599,47 +582,16 @@ static int __cmd_report(struct perf_report *rep) | |||
599 | return 0; | 582 | return 0; |
600 | } | 583 | } |
601 | 584 | ||
602 | list_for_each_entry(pos, &session->evlist->entries, node) | 585 | evlist__for_each(session->evlist, pos) |
603 | hists__output_resort(&pos->hists); | 586 | hists__output_resort(&pos->hists); |
604 | 587 | ||
605 | if (use_browser > 0) { | 588 | 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 | } | 589 | } |
638 | 590 | ||
639 | static int | 591 | static int |
640 | parse_callchain_opt(const struct option *opt, const char *arg, int unset) | 592 | parse_callchain_opt(const struct option *opt, const char *arg, int unset) |
641 | { | 593 | { |
642 | struct perf_report *rep = (struct perf_report *)opt->value; | 594 | struct report *rep = (struct report *)opt->value; |
643 | char *tok, *tok2; | 595 | char *tok, *tok2; |
644 | char *endptr; | 596 | char *endptr; |
645 | 597 | ||
@@ -721,7 +673,7 @@ parse_callchain_opt(const struct option *opt, const char *arg, int unset) | |||
721 | return -1; | 673 | return -1; |
722 | setup: | 674 | setup: |
723 | if (callchain_register_param(&callchain_param) < 0) { | 675 | if (callchain_register_param(&callchain_param) < 0) { |
724 | fprintf(stderr, "Can't register callchain params\n"); | 676 | pr_err("Can't register callchain params\n"); |
725 | return -1; | 677 | return -1; |
726 | } | 678 | } |
727 | return 0; | 679 | return 0; |
@@ -759,7 +711,7 @@ static int | |||
759 | parse_percent_limit(const struct option *opt, const char *str, | 711 | parse_percent_limit(const struct option *opt, const char *str, |
760 | int unset __maybe_unused) | 712 | int unset __maybe_unused) |
761 | { | 713 | { |
762 | struct perf_report *rep = opt->value; | 714 | struct report *rep = opt->value; |
763 | 715 | ||
764 | rep->min_percent = strtof(str, NULL); | 716 | rep->min_percent = strtof(str, NULL); |
765 | return 0; | 717 | return 0; |
@@ -777,7 +729,7 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused) | |||
777 | "perf report [<options>]", | 729 | "perf report [<options>]", |
778 | NULL | 730 | NULL |
779 | }; | 731 | }; |
780 | struct perf_report report = { | 732 | struct report report = { |
781 | .tool = { | 733 | .tool = { |
782 | .sample = process_sample_event, | 734 | .sample = process_sample_event, |
783 | .mmap = perf_event__process_mmap, | 735 | .mmap = perf_event__process_mmap, |
@@ -820,6 +772,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"), | 772 | OPT_BOOLEAN(0, "gtk", &report.use_gtk, "Use the GTK2 interface"), |
821 | OPT_BOOLEAN(0, "stdio", &report.use_stdio, | 773 | OPT_BOOLEAN(0, "stdio", &report.use_stdio, |
822 | "Use the stdio interface"), | 774 | "Use the stdio interface"), |
775 | OPT_BOOLEAN(0, "header", &report.header, "Show data header."), | ||
776 | OPT_BOOLEAN(0, "header-only", &report.header_only, | ||
777 | "Show only data header."), | ||
823 | OPT_STRING('s', "sort", &sort_order, "key[,key2...]", | 778 | OPT_STRING('s', "sort", &sort_order, "key[,key2...]", |
824 | "sort by key(s): pid, comm, dso, symbol, parent, cpu, srcline," | 779 | "sort by key(s): pid, comm, dso, symbol, parent, cpu, srcline," |
825 | " dso_to, dso_from, symbol_to, symbol_from, mispredict," | 780 | " dso_to, dso_from, symbol_to, symbol_from, mispredict," |
@@ -890,7 +845,7 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused) | |||
890 | .mode = PERF_DATA_MODE_READ, | 845 | .mode = PERF_DATA_MODE_READ, |
891 | }; | 846 | }; |
892 | 847 | ||
893 | perf_config(perf_report_config, &report); | 848 | perf_config(report__config, &report); |
894 | 849 | ||
895 | argc = parse_options(argc, argv, options, report_usage, 0); | 850 | argc = parse_options(argc, argv, options, report_usage, 0); |
896 | 851 | ||
@@ -940,7 +895,7 @@ repeat: | |||
940 | } | 895 | } |
941 | if (report.mem_mode) { | 896 | if (report.mem_mode) { |
942 | if (sort__mode == SORT_MODE__BRANCH) { | 897 | if (sort__mode == SORT_MODE__BRANCH) { |
943 | fprintf(stderr, "branch and mem mode incompatible\n"); | 898 | pr_err("branch and mem mode incompatible\n"); |
944 | goto error; | 899 | goto error; |
945 | } | 900 | } |
946 | sort__mode = SORT_MODE__MEMORY; | 901 | sort__mode = SORT_MODE__MEMORY; |
@@ -963,6 +918,10 @@ repeat: | |||
963 | goto error; | 918 | goto error; |
964 | } | 919 | } |
965 | 920 | ||
921 | /* Force tty output for header output. */ | ||
922 | if (report.header || report.header_only) | ||
923 | use_browser = 0; | ||
924 | |||
966 | if (strcmp(input_name, "-") != 0) | 925 | if (strcmp(input_name, "-") != 0) |
967 | setup_browser(true); | 926 | setup_browser(true); |
968 | else { | 927 | else { |
@@ -970,6 +929,16 @@ repeat: | |||
970 | perf_hpp__init(); | 929 | perf_hpp__init(); |
971 | } | 930 | } |
972 | 931 | ||
932 | if (report.header || report.header_only) { | ||
933 | perf_session__fprintf_info(session, stdout, | ||
934 | report.show_full_info); | ||
935 | if (report.header_only) | ||
936 | return 0; | ||
937 | } else if (use_browser == 0) { | ||
938 | fputs("# To display the perf.data header info, please use --header/--header-only options.\n#\n", | ||
939 | stdout); | ||
940 | } | ||
941 | |||
973 | /* | 942 | /* |
974 | * Only in the TUI browser we are doing integrated annotation, | 943 | * 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 | 944 | * 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..652af0b66a62 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 | |||
442 | 408 | ||
443 | prev_p = find_create_pid(sw->prev_pid); | 409 | prev_p = find_create_pid(tchart, prev_pid); |
444 | 410 | ||
445 | p = find_create_pid(sw->next_pid); | 411 | p = find_create_pid(tchart, 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; | ||
469 | 457 | ||
470 | static int process_sample_event(struct perf_tool *tool __maybe_unused, | 458 | if (perf_event__preprocess_sample(event, machine, &al, sample) < 0) { |
471 | union perf_event *event __maybe_unused, | 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); | ||
518 | |||
519 | static int process_sample_event(struct perf_tool *tool, | ||
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,74 @@ 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) |
950 | 1039 | tchart->proc_num = 0; | |
951 | 1040 | ||
952 | count = determine_display_tasks(TIME_THRESH); | 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); | ||
953 | 1047 | ||
954 | /* We'd like to show at least 15 tasks; be less picky if we have fewer */ | 1048 | 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 | 1049 | ||
960 | svg_time_grid(); | 1050 | svg_time_grid(); |
961 | svg_legenda(); | 1051 | svg_legenda(); |
962 | 1052 | ||
963 | for (i = 0; i < numcpus; i++) | 1053 | for (i = 0; i < tchart->numcpus; i++) |
964 | svg_cpu_box(i, max_freq, turbo_frequency); | 1054 | svg_cpu_box(i, tchart->max_freq, tchart->turbo_frequency); |
965 | 1055 | ||
966 | draw_cpu_usage(); | 1056 | draw_cpu_usage(tchart); |
967 | draw_process_bars(); | 1057 | if (tchart->proc_num) |
968 | draw_c_p_states(); | 1058 | draw_process_bars(tchart); |
969 | draw_wakeups(); | 1059 | if (!tchart->tasks_only) |
1060 | draw_c_p_states(tchart); | ||
1061 | if (tchart->proc_num) | ||
1062 | draw_wakeups(tchart); | ||
970 | 1063 | ||
971 | svg_close(); | 1064 | svg_close(); |
972 | } | 1065 | } |
973 | 1066 | ||
974 | static int __cmd_timechart(const char *output_name) | 1067 | static int process_header(struct perf_file_section *section __maybe_unused, |
1068 | struct perf_header *ph, | ||
1069 | int feat, | ||
1070 | int fd __maybe_unused, | ||
1071 | void *data) | ||
1072 | { | ||
1073 | struct timechart *tchart = data; | ||
1074 | |||
1075 | switch (feat) { | ||
1076 | case HEADER_NRCPUS: | ||
1077 | tchart->numcpus = ph->env.nr_cpus_avail; | ||
1078 | break; | ||
1079 | |||
1080 | case HEADER_CPU_TOPOLOGY: | ||
1081 | if (!tchart->topology) | ||
1082 | break; | ||
1083 | |||
1084 | if (svg_build_topology_map(ph->env.sibling_cores, | ||
1085 | ph->env.nr_sibling_cores, | ||
1086 | ph->env.sibling_threads, | ||
1087 | ph->env.nr_sibling_threads)) | ||
1088 | fprintf(stderr, "problem building topology\n"); | ||
1089 | break; | ||
1090 | |||
1091 | default: | ||
1092 | break; | ||
1093 | } | ||
1094 | |||
1095 | return 0; | ||
1096 | } | ||
1097 | |||
1098 | static int __cmd_timechart(struct timechart *tchart, const char *output_name) | ||
975 | { | 1099 | { |
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[] = { | 1100 | const struct perf_evsel_str_handler power_tracepoints[] = { |
984 | { "power:cpu_idle", process_sample_cpu_idle }, | 1101 | { "power:cpu_idle", process_sample_cpu_idle }, |
985 | { "power:cpu_frequency", process_sample_cpu_frequency }, | 1102 | { "power:cpu_frequency", process_sample_cpu_frequency }, |
@@ -997,12 +1114,17 @@ static int __cmd_timechart(const char *output_name) | |||
997 | }; | 1114 | }; |
998 | 1115 | ||
999 | struct perf_session *session = perf_session__new(&file, false, | 1116 | struct perf_session *session = perf_session__new(&file, false, |
1000 | &perf_timechart); | 1117 | &tchart->tool); |
1001 | int ret = -EINVAL; | 1118 | int ret = -EINVAL; |
1002 | 1119 | ||
1003 | if (session == NULL) | 1120 | if (session == NULL) |
1004 | return -ENOMEM; | 1121 | return -ENOMEM; |
1005 | 1122 | ||
1123 | (void)perf_header__process_sections(&session->header, | ||
1124 | perf_data_file__fd(session->file), | ||
1125 | tchart, | ||
1126 | process_header); | ||
1127 | |||
1006 | if (!perf_session__has_traces(session, "timechart record")) | 1128 | if (!perf_session__has_traces(session, "timechart record")) |
1007 | goto out_delete; | 1129 | goto out_delete; |
1008 | 1130 | ||
@@ -1012,69 +1134,111 @@ static int __cmd_timechart(const char *output_name) | |||
1012 | goto out_delete; | 1134 | goto out_delete; |
1013 | } | 1135 | } |
1014 | 1136 | ||
1015 | ret = perf_session__process_events(session, &perf_timechart); | 1137 | ret = perf_session__process_events(session, &tchart->tool); |
1016 | if (ret) | 1138 | if (ret) |
1017 | goto out_delete; | 1139 | goto out_delete; |
1018 | 1140 | ||
1019 | end_sample_processing(); | 1141 | end_sample_processing(tchart); |
1020 | 1142 | ||
1021 | sort_pids(); | 1143 | sort_pids(tchart); |
1022 | 1144 | ||
1023 | write_svg_file(output_name); | 1145 | write_svg_file(tchart, output_name); |
1024 | 1146 | ||
1025 | pr_info("Written %2.1f seconds of trace to %s.\n", | 1147 | pr_info("Written %2.1f seconds of trace to %s.\n", |
1026 | (last_time - first_time) / 1000000000.0, output_name); | 1148 | (tchart->last_time - tchart->first_time) / 1000000000.0, output_name); |
1027 | out_delete: | 1149 | out_delete: |
1028 | perf_session__delete(session); | 1150 | perf_session__delete(session); |
1029 | return ret; | 1151 | return ret; |
1030 | } | 1152 | } |
1031 | 1153 | ||
1032 | static int __cmd_record(int argc, const char **argv) | 1154 | static int timechart__record(struct timechart *tchart, int argc, const char **argv) |
1033 | { | 1155 | { |
1034 | #ifdef SUPPORT_OLD_POWER_EVENTS | 1156 | unsigned int rec_argc, i, j; |
1035 | const char * const record_old_args[] = { | 1157 | const char **rec_argv; |
1158 | const char **p; | ||
1159 | unsigned int record_elems; | ||
1160 | |||
1161 | const char * const common_args[] = { | ||
1036 | "record", "-a", "-R", "-c", "1", | 1162 | "record", "-a", "-R", "-c", "1", |
1163 | }; | ||
1164 | unsigned int common_args_nr = ARRAY_SIZE(common_args); | ||
1165 | |||
1166 | const char * const backtrace_args[] = { | ||
1167 | "-g", | ||
1168 | }; | ||
1169 | unsigned int backtrace_args_no = ARRAY_SIZE(backtrace_args); | ||
1170 | |||
1171 | const char * const power_args[] = { | ||
1172 | "-e", "power:cpu_frequency", | ||
1173 | "-e", "power:cpu_idle", | ||
1174 | }; | ||
1175 | unsigned int power_args_nr = ARRAY_SIZE(power_args); | ||
1176 | |||
1177 | const char * const old_power_args[] = { | ||
1178 | #ifdef SUPPORT_OLD_POWER_EVENTS | ||
1037 | "-e", "power:power_start", | 1179 | "-e", "power:power_start", |
1038 | "-e", "power:power_end", | 1180 | "-e", "power:power_end", |
1039 | "-e", "power:power_frequency", | 1181 | "-e", "power:power_frequency", |
1040 | "-e", "sched:sched_wakeup", | ||
1041 | "-e", "sched:sched_switch", | ||
1042 | }; | ||
1043 | #endif | 1182 | #endif |
1044 | const char * const record_new_args[] = { | 1183 | }; |
1045 | "record", "-a", "-R", "-c", "1", | 1184 | unsigned int old_power_args_nr = ARRAY_SIZE(old_power_args); |
1046 | "-e", "power:cpu_frequency", | 1185 | |
1047 | "-e", "power:cpu_idle", | 1186 | const char * const tasks_args[] = { |
1048 | "-e", "sched:sched_wakeup", | 1187 | "-e", "sched:sched_wakeup", |
1049 | "-e", "sched:sched_switch", | 1188 | "-e", "sched:sched_switch", |
1050 | }; | 1189 | }; |
1051 | unsigned int rec_argc, i, j; | 1190 | 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 | 1191 | ||
1056 | #ifdef SUPPORT_OLD_POWER_EVENTS | 1192 | #ifdef SUPPORT_OLD_POWER_EVENTS |
1057 | if (!is_valid_tracepoint("power:cpu_idle") && | 1193 | if (!is_valid_tracepoint("power:cpu_idle") && |
1058 | is_valid_tracepoint("power:power_start")) { | 1194 | is_valid_tracepoint("power:power_start")) { |
1059 | use_old_power_events = 1; | 1195 | use_old_power_events = 1; |
1060 | record_args = record_old_args; | 1196 | power_args_nr = 0; |
1061 | record_elems = ARRAY_SIZE(record_old_args); | 1197 | } else { |
1198 | old_power_args_nr = 0; | ||
1062 | } | 1199 | } |
1063 | #endif | 1200 | #endif |
1064 | 1201 | ||
1065 | rec_argc = record_elems + argc - 1; | 1202 | if (tchart->power_only) |
1203 | tasks_args_nr = 0; | ||
1204 | |||
1205 | if (tchart->tasks_only) { | ||
1206 | power_args_nr = 0; | ||
1207 | old_power_args_nr = 0; | ||
1208 | } | ||
1209 | |||
1210 | if (!tchart->with_backtrace) | ||
1211 | backtrace_args_no = 0; | ||
1212 | |||
1213 | record_elems = common_args_nr + tasks_args_nr + | ||
1214 | power_args_nr + old_power_args_nr + backtrace_args_no; | ||
1215 | |||
1216 | rec_argc = record_elems + argc; | ||
1066 | rec_argv = calloc(rec_argc + 1, sizeof(char *)); | 1217 | rec_argv = calloc(rec_argc + 1, sizeof(char *)); |
1067 | 1218 | ||
1068 | if (rec_argv == NULL) | 1219 | if (rec_argv == NULL) |
1069 | return -ENOMEM; | 1220 | return -ENOMEM; |
1070 | 1221 | ||
1071 | for (i = 0; i < record_elems; i++) | 1222 | p = rec_argv; |
1072 | rec_argv[i] = strdup(record_args[i]); | 1223 | for (i = 0; i < common_args_nr; i++) |
1224 | *p++ = strdup(common_args[i]); | ||
1225 | |||
1226 | for (i = 0; i < backtrace_args_no; i++) | ||
1227 | *p++ = strdup(backtrace_args[i]); | ||
1228 | |||
1229 | for (i = 0; i < tasks_args_nr; i++) | ||
1230 | *p++ = strdup(tasks_args[i]); | ||
1231 | |||
1232 | for (i = 0; i < power_args_nr; i++) | ||
1233 | *p++ = strdup(power_args[i]); | ||
1073 | 1234 | ||
1074 | for (j = 1; j < (unsigned int)argc; j++, i++) | 1235 | for (i = 0; i < old_power_args_nr; i++) |
1075 | rec_argv[i] = argv[j]; | 1236 | *p++ = strdup(old_power_args[i]); |
1076 | 1237 | ||
1077 | return cmd_record(i, rec_argv, NULL); | 1238 | for (j = 1; j < (unsigned int)argc; j++) |
1239 | *p++ = argv[j]; | ||
1240 | |||
1241 | return cmd_record(rec_argc, rec_argv, NULL); | ||
1078 | } | 1242 | } |
1079 | 1243 | ||
1080 | static int | 1244 | static int |
@@ -1086,20 +1250,56 @@ parse_process(const struct option *opt __maybe_unused, const char *arg, | |||
1086 | return 0; | 1250 | return 0; |
1087 | } | 1251 | } |
1088 | 1252 | ||
1253 | static int | ||
1254 | parse_highlight(const struct option *opt __maybe_unused, const char *arg, | ||
1255 | int __maybe_unused unset) | ||
1256 | { | ||
1257 | unsigned long duration = strtoul(arg, NULL, 0); | ||
1258 | |||
1259 | if (svg_highlight || svg_highlight_name) | ||
1260 | return -1; | ||
1261 | |||
1262 | if (duration) | ||
1263 | svg_highlight = duration; | ||
1264 | else | ||
1265 | svg_highlight_name = strdup(arg); | ||
1266 | |||
1267 | return 0; | ||
1268 | } | ||
1269 | |||
1089 | int cmd_timechart(int argc, const char **argv, | 1270 | int cmd_timechart(int argc, const char **argv, |
1090 | const char *prefix __maybe_unused) | 1271 | const char *prefix __maybe_unused) |
1091 | { | 1272 | { |
1273 | struct timechart tchart = { | ||
1274 | .tool = { | ||
1275 | .comm = process_comm_event, | ||
1276 | .fork = process_fork_event, | ||
1277 | .exit = process_exit_event, | ||
1278 | .sample = process_sample_event, | ||
1279 | .ordered_samples = true, | ||
1280 | }, | ||
1281 | .proc_num = 15, | ||
1282 | }; | ||
1092 | const char *output_name = "output.svg"; | 1283 | const char *output_name = "output.svg"; |
1093 | const struct option options[] = { | 1284 | const struct option timechart_options[] = { |
1094 | OPT_STRING('i', "input", &input_name, "file", "input file name"), | 1285 | OPT_STRING('i', "input", &input_name, "file", "input file name"), |
1095 | OPT_STRING('o', "output", &output_name, "file", "output file name"), | 1286 | OPT_STRING('o', "output", &output_name, "file", "output file name"), |
1096 | OPT_INTEGER('w', "width", &svg_page_width, "page width"), | 1287 | OPT_INTEGER('w', "width", &svg_page_width, "page width"), |
1097 | OPT_BOOLEAN('P', "power-only", &power_only, "output power data only"), | 1288 | OPT_CALLBACK(0, "highlight", NULL, "duration or task name", |
1289 | "highlight tasks. Pass duration in ns or process name.", | ||
1290 | parse_highlight), | ||
1291 | OPT_BOOLEAN('P', "power-only", &tchart.power_only, "output power data only"), | ||
1292 | OPT_BOOLEAN('T', "tasks-only", &tchart.tasks_only, | ||
1293 | "output processes data only"), | ||
1098 | OPT_CALLBACK('p', "process", NULL, "process", | 1294 | OPT_CALLBACK('p', "process", NULL, "process", |
1099 | "process selector. Pass a pid or process name.", | 1295 | "process selector. Pass a pid or process name.", |
1100 | parse_process), | 1296 | parse_process), |
1101 | OPT_STRING(0, "symfs", &symbol_conf.symfs, "directory", | 1297 | OPT_STRING(0, "symfs", &symbol_conf.symfs, "directory", |
1102 | "Look for files with symbols relative to this directory"), | 1298 | "Look for files with symbols relative to this directory"), |
1299 | OPT_INTEGER('n', "proc-num", &tchart.proc_num, | ||
1300 | "min. number of tasks to print"), | ||
1301 | OPT_BOOLEAN('t', "topology", &tchart.topology, | ||
1302 | "sort CPUs according to topology"), | ||
1103 | OPT_END() | 1303 | OPT_END() |
1104 | }; | 1304 | }; |
1105 | const char * const timechart_usage[] = { | 1305 | const char * const timechart_usage[] = { |
@@ -1107,17 +1307,41 @@ int cmd_timechart(int argc, const char **argv, | |||
1107 | NULL | 1307 | NULL |
1108 | }; | 1308 | }; |
1109 | 1309 | ||
1110 | argc = parse_options(argc, argv, options, timechart_usage, | 1310 | const struct option record_options[] = { |
1311 | OPT_BOOLEAN('P', "power-only", &tchart.power_only, "output power data only"), | ||
1312 | OPT_BOOLEAN('T', "tasks-only", &tchart.tasks_only, | ||
1313 | "output processes data only"), | ||
1314 | OPT_BOOLEAN('g', "callchain", &tchart.with_backtrace, "record callchain"), | ||
1315 | OPT_END() | ||
1316 | }; | ||
1317 | const char * const record_usage[] = { | ||
1318 | "perf timechart record [<options>]", | ||
1319 | NULL | ||
1320 | }; | ||
1321 | argc = parse_options(argc, argv, timechart_options, timechart_usage, | ||
1111 | PARSE_OPT_STOP_AT_NON_OPTION); | 1322 | PARSE_OPT_STOP_AT_NON_OPTION); |
1112 | 1323 | ||
1324 | if (tchart.power_only && tchart.tasks_only) { | ||
1325 | pr_err("-P and -T options cannot be used at the same time.\n"); | ||
1326 | return -1; | ||
1327 | } | ||
1328 | |||
1113 | symbol__init(); | 1329 | symbol__init(); |
1114 | 1330 | ||
1115 | if (argc && !strncmp(argv[0], "rec", 3)) | 1331 | if (argc && !strncmp(argv[0], "rec", 3)) { |
1116 | return __cmd_record(argc, argv); | 1332 | argc = parse_options(argc, argv, record_options, record_usage, |
1117 | else if (argc) | 1333 | PARSE_OPT_STOP_AT_NON_OPTION); |
1118 | usage_with_options(timechart_usage, options); | 1334 | |
1335 | if (tchart.power_only && tchart.tasks_only) { | ||
1336 | pr_err("-P and -T options cannot be used at the same time.\n"); | ||
1337 | return -1; | ||
1338 | } | ||
1339 | |||
1340 | return timechart__record(&tchart, argc, argv); | ||
1341 | } else if (argc) | ||
1342 | usage_with_options(timechart_usage, timechart_options); | ||
1119 | 1343 | ||
1120 | setup_pager(); | 1344 | setup_pager(); |
1121 | 1345 | ||
1122 | return __cmd_timechart(output_name); | 1346 | return __cmd_timechart(&tchart, output_name); |
1123 | } | 1347 | } |
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index 71e6402729a8..569dd87690ef 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c | |||
@@ -189,21 +189,18 @@ 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 | err = hist_entry__inc_addr_samples(he, counter, ip); |
202 | 194 | ||
203 | pthread_mutex_unlock(¬es->lock); | 195 | pthread_mutex_unlock(¬es->lock); |
204 | 196 | ||
205 | if (err == -ERANGE && !he->ms.map->erange_warned) | 197 | if (err == -ERANGE && !he->ms.map->erange_warned) |
206 | ui__warn_map_erange(he->ms.map, sym, ip); | 198 | ui__warn_map_erange(he->ms.map, sym, ip); |
199 | else if (err == -ENOMEM) { | ||
200 | pr_err("Not enough memory for annotating '%s' symbol!\n", | ||
201 | sym->name); | ||
202 | sleep(1); | ||
203 | } | ||
207 | } | 204 | } |
208 | 205 | ||
209 | static void perf_top__show_details(struct perf_top *top) | 206 | static void perf_top__show_details(struct perf_top *top) |
@@ -485,7 +482,7 @@ static bool perf_top__handle_keypress(struct perf_top *top, int c) | |||
485 | 482 | ||
486 | fprintf(stderr, "\nAvailable events:"); | 483 | fprintf(stderr, "\nAvailable events:"); |
487 | 484 | ||
488 | list_for_each_entry(top->sym_evsel, &top->evlist->entries, node) | 485 | 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)); | 486 | fprintf(stderr, "\n\t%d %s", top->sym_evsel->idx, perf_evsel__name(top->sym_evsel)); |
490 | 487 | ||
491 | prompt_integer(&counter, "Enter details event counter"); | 488 | prompt_integer(&counter, "Enter details event counter"); |
@@ -496,7 +493,7 @@ static bool perf_top__handle_keypress(struct perf_top *top, int c) | |||
496 | sleep(1); | 493 | sleep(1); |
497 | break; | 494 | break; |
498 | } | 495 | } |
499 | list_for_each_entry(top->sym_evsel, &top->evlist->entries, node) | 496 | evlist__for_each(top->evlist, top->sym_evsel) |
500 | if (top->sym_evsel->idx == counter) | 497 | if (top->sym_evsel->idx == counter) |
501 | break; | 498 | break; |
502 | } else | 499 | } else |
@@ -578,7 +575,7 @@ static void *display_thread_tui(void *arg) | |||
578 | * Zooming in/out UIDs. For now juse use whatever the user passed | 575 | * Zooming in/out UIDs. For now juse use whatever the user passed |
579 | * via --uid. | 576 | * via --uid. |
580 | */ | 577 | */ |
581 | list_for_each_entry(pos, &top->evlist->entries, node) | 578 | evlist__for_each(top->evlist, pos) |
582 | pos->hists.uid_filter_str = top->record_opts.target.uid_str; | 579 | pos->hists.uid_filter_str = top->record_opts.target.uid_str; |
583 | 580 | ||
584 | perf_evlist__tui_browse_hists(top->evlist, help, &hbt, top->min_percent, | 581 | perf_evlist__tui_browse_hists(top->evlist, help, &hbt, top->min_percent, |
@@ -634,26 +631,9 @@ repeat: | |||
634 | return NULL; | 631 | return NULL; |
635 | } | 632 | } |
636 | 633 | ||
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) | 634 | static int symbol_filter(struct map *map __maybe_unused, struct symbol *sym) |
654 | { | 635 | { |
655 | const char *name = sym->name; | 636 | const char *name = sym->name; |
656 | int i; | ||
657 | 637 | ||
658 | /* | 638 | /* |
659 | * ppc64 uses function descriptors and appends a '.' to the | 639 | * ppc64 uses function descriptors and appends a '.' to the |
@@ -671,12 +651,8 @@ static int symbol_filter(struct map *map __maybe_unused, struct symbol *sym) | |||
671 | strstr(name, "_text_end")) | 651 | strstr(name, "_text_end")) |
672 | return 1; | 652 | return 1; |
673 | 653 | ||
674 | for (i = 0; skip_symbols[i]; i++) { | 654 | if (symbol__is_idle(sym)) |
675 | if (!strcmp(skip_symbols[i], name)) { | 655 | sym->ignore = true; |
676 | sym->ignore = true; | ||
677 | break; | ||
678 | } | ||
679 | } | ||
680 | 656 | ||
681 | return 0; | 657 | return 0; |
682 | } | 658 | } |
@@ -878,11 +854,11 @@ static int perf_top__start_counters(struct perf_top *top) | |||
878 | char msg[512]; | 854 | char msg[512]; |
879 | struct perf_evsel *counter; | 855 | struct perf_evsel *counter; |
880 | struct perf_evlist *evlist = top->evlist; | 856 | struct perf_evlist *evlist = top->evlist; |
881 | struct perf_record_opts *opts = &top->record_opts; | 857 | struct record_opts *opts = &top->record_opts; |
882 | 858 | ||
883 | perf_evlist__config(evlist, opts); | 859 | perf_evlist__config(evlist, opts); |
884 | 860 | ||
885 | list_for_each_entry(counter, &evlist->entries, node) { | 861 | evlist__for_each(evlist, counter) { |
886 | try_again: | 862 | try_again: |
887 | if (perf_evsel__open(counter, top->evlist->cpus, | 863 | if (perf_evsel__open(counter, top->evlist->cpus, |
888 | top->evlist->threads) < 0) { | 864 | top->evlist->threads) < 0) { |
@@ -930,7 +906,7 @@ static int perf_top__setup_sample_type(struct perf_top *top __maybe_unused) | |||
930 | 906 | ||
931 | static int __cmd_top(struct perf_top *top) | 907 | static int __cmd_top(struct perf_top *top) |
932 | { | 908 | { |
933 | struct perf_record_opts *opts = &top->record_opts; | 909 | struct record_opts *opts = &top->record_opts; |
934 | pthread_t thread; | 910 | pthread_t thread; |
935 | int ret; | 911 | int ret; |
936 | 912 | ||
@@ -1052,7 +1028,7 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused) | |||
1052 | .max_stack = PERF_MAX_STACK_DEPTH, | 1028 | .max_stack = PERF_MAX_STACK_DEPTH, |
1053 | .sym_pcnt_filter = 5, | 1029 | .sym_pcnt_filter = 5, |
1054 | }; | 1030 | }; |
1055 | struct perf_record_opts *opts = &top.record_opts; | 1031 | struct record_opts *opts = &top.record_opts; |
1056 | struct target *target = &opts->target; | 1032 | struct target *target = &opts->target; |
1057 | const struct option options[] = { | 1033 | const struct option options[] = { |
1058 | OPT_CALLBACK('e', "event", &top.evlist, "event", | 1034 | OPT_CALLBACK('e', "event", &top.evlist, "event", |
@@ -1084,7 +1060,7 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused) | |||
1084 | "dump the symbol table used for profiling"), | 1060 | "dump the symbol table used for profiling"), |
1085 | OPT_INTEGER('f', "count-filter", &top.count_filter, | 1061 | OPT_INTEGER('f', "count-filter", &top.count_filter, |
1086 | "only display functions with more events than this"), | 1062 | "only display functions with more events than this"), |
1087 | OPT_BOOLEAN('g', "group", &opts->group, | 1063 | OPT_BOOLEAN(0, "group", &opts->group, |
1088 | "put the counters into a counter group"), | 1064 | "put the counters into a counter group"), |
1089 | OPT_BOOLEAN('i', "no-inherit", &opts->no_inherit, | 1065 | OPT_BOOLEAN('i', "no-inherit", &opts->no_inherit, |
1090 | "child tasks do not inherit counters"), | 1066 | "child tasks do not inherit counters"), |
@@ -1105,7 +1081,7 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused) | |||
1105 | " abort, in_tx, transaction"), | 1081 | " abort, in_tx, transaction"), |
1106 | OPT_BOOLEAN('n', "show-nr-samples", &symbol_conf.show_nr_samples, | 1082 | OPT_BOOLEAN('n', "show-nr-samples", &symbol_conf.show_nr_samples, |
1107 | "Show a column with the number of samples"), | 1083 | "Show a column with the number of samples"), |
1108 | OPT_CALLBACK_NOOPT('G', NULL, &top.record_opts, | 1084 | OPT_CALLBACK_NOOPT('g', NULL, &top.record_opts, |
1109 | NULL, "enables call-graph recording", | 1085 | NULL, "enables call-graph recording", |
1110 | &callchain_opt), | 1086 | &callchain_opt), |
1111 | OPT_CALLBACK(0, "call-graph", &top.record_opts, | 1087 | OPT_CALLBACK(0, "call-graph", &top.record_opts, |
@@ -1195,7 +1171,7 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused) | |||
1195 | if (!top.evlist->nr_entries && | 1171 | if (!top.evlist->nr_entries && |
1196 | perf_evlist__add_default(top.evlist) < 0) { | 1172 | perf_evlist__add_default(top.evlist) < 0) { |
1197 | ui__error("Not enough memory for event selector list\n"); | 1173 | ui__error("Not enough memory for event selector list\n"); |
1198 | goto out_delete_maps; | 1174 | goto out_delete_evlist; |
1199 | } | 1175 | } |
1200 | 1176 | ||
1201 | symbol_conf.nr_events = top.evlist->nr_entries; | 1177 | symbol_conf.nr_events = top.evlist->nr_entries; |
@@ -1203,9 +1179,9 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused) | |||
1203 | if (top.delay_secs < 1) | 1179 | if (top.delay_secs < 1) |
1204 | top.delay_secs = 1; | 1180 | top.delay_secs = 1; |
1205 | 1181 | ||
1206 | if (perf_record_opts__config(opts)) { | 1182 | if (record_opts__config(opts)) { |
1207 | status = -EINVAL; | 1183 | status = -EINVAL; |
1208 | goto out_delete_maps; | 1184 | goto out_delete_evlist; |
1209 | } | 1185 | } |
1210 | 1186 | ||
1211 | top.sym_evsel = perf_evlist__first(top.evlist); | 1187 | top.sym_evsel = perf_evlist__first(top.evlist); |
@@ -1230,8 +1206,6 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused) | |||
1230 | 1206 | ||
1231 | status = __cmd_top(&top); | 1207 | status = __cmd_top(&top); |
1232 | 1208 | ||
1233 | out_delete_maps: | ||
1234 | perf_evlist__delete_maps(top.evlist); | ||
1235 | out_delete_evlist: | 1209 | out_delete_evlist: |
1236 | perf_evlist__delete(top.evlist); | 1210 | perf_evlist__delete(top.evlist); |
1237 | 1211 | ||
diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c index 8be17fc462ba..4bd44aba343e 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> |
@@ -144,8 +146,7 @@ static int perf_evsel__init_tp_ptr_field(struct perf_evsel *evsel, | |||
144 | 146 | ||
145 | static void perf_evsel__delete_priv(struct perf_evsel *evsel) | 147 | static void perf_evsel__delete_priv(struct perf_evsel *evsel) |
146 | { | 148 | { |
147 | free(evsel->priv); | 149 | zfree(&evsel->priv); |
148 | evsel->priv = NULL; | ||
149 | perf_evsel__delete(evsel); | 150 | perf_evsel__delete(evsel); |
150 | } | 151 | } |
151 | 152 | ||
@@ -163,8 +164,7 @@ static int perf_evsel__init_syscall_tp(struct perf_evsel *evsel, void *handler) | |||
163 | return -ENOMEM; | 164 | return -ENOMEM; |
164 | 165 | ||
165 | out_delete: | 166 | out_delete: |
166 | free(evsel->priv); | 167 | zfree(&evsel->priv); |
167 | evsel->priv = NULL; | ||
168 | return -ENOENT; | 168 | return -ENOENT; |
169 | } | 169 | } |
170 | 170 | ||
@@ -172,6 +172,10 @@ static struct perf_evsel *perf_evsel__syscall_newtp(const char *direction, void | |||
172 | { | 172 | { |
173 | struct perf_evsel *evsel = perf_evsel__newtp("raw_syscalls", direction); | 173 | struct perf_evsel *evsel = perf_evsel__newtp("raw_syscalls", direction); |
174 | 174 | ||
175 | /* older kernel (e.g., RHEL6) use syscalls:{enter,exit} */ | ||
176 | if (evsel == NULL) | ||
177 | evsel = perf_evsel__newtp("syscalls", direction); | ||
178 | |||
175 | if (evsel) { | 179 | if (evsel) { |
176 | if (perf_evsel__init_syscall_tp(evsel, handler)) | 180 | if (perf_evsel__init_syscall_tp(evsel, handler)) |
177 | goto out_delete; | 181 | goto out_delete; |
@@ -1153,29 +1157,30 @@ struct trace { | |||
1153 | int max; | 1157 | int max; |
1154 | struct syscall *table; | 1158 | struct syscall *table; |
1155 | } syscalls; | 1159 | } syscalls; |
1156 | struct perf_record_opts opts; | 1160 | struct record_opts opts; |
1157 | struct machine *host; | 1161 | struct machine *host; |
1158 | u64 base_time; | 1162 | u64 base_time; |
1159 | bool full_time; | ||
1160 | FILE *output; | 1163 | FILE *output; |
1161 | unsigned long nr_events; | 1164 | unsigned long nr_events; |
1162 | struct strlist *ev_qualifier; | 1165 | struct strlist *ev_qualifier; |
1163 | bool not_ev_qualifier; | ||
1164 | bool live; | ||
1165 | const char *last_vfs_getname; | 1166 | const char *last_vfs_getname; |
1166 | struct intlist *tid_list; | 1167 | struct intlist *tid_list; |
1167 | struct intlist *pid_list; | 1168 | struct intlist *pid_list; |
1169 | double duration_filter; | ||
1170 | double runtime_ms; | ||
1171 | struct { | ||
1172 | u64 vfs_getname, | ||
1173 | proc_getname; | ||
1174 | } stats; | ||
1175 | bool not_ev_qualifier; | ||
1176 | bool live; | ||
1177 | bool full_time; | ||
1168 | bool sched; | 1178 | bool sched; |
1169 | bool multiple_threads; | 1179 | bool multiple_threads; |
1170 | bool summary; | 1180 | bool summary; |
1171 | bool summary_only; | 1181 | bool summary_only; |
1172 | bool show_comm; | 1182 | bool show_comm; |
1173 | bool show_tool_stats; | 1183 | bool show_tool_stats; |
1174 | double duration_filter; | ||
1175 | double runtime_ms; | ||
1176 | struct { | ||
1177 | u64 vfs_getname, proc_getname; | ||
1178 | } stats; | ||
1179 | }; | 1184 | }; |
1180 | 1185 | ||
1181 | static int trace__set_fd_pathname(struct thread *thread, int fd, const char *pathname) | 1186 | static int trace__set_fd_pathname(struct thread *thread, int fd, const char *pathname) |
@@ -1272,10 +1277,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); | 1277 | size_t printed = syscall_arg__scnprintf_fd(bf, size, arg); |
1273 | struct thread_trace *ttrace = arg->thread->priv; | 1278 | struct thread_trace *ttrace = arg->thread->priv; |
1274 | 1279 | ||
1275 | if (ttrace && fd >= 0 && fd <= ttrace->paths.max) { | 1280 | if (ttrace && fd >= 0 && fd <= ttrace->paths.max) |
1276 | free(ttrace->paths.table[fd]); | 1281 | zfree(&ttrace->paths.table[fd]); |
1277 | ttrace->paths.table[fd] = NULL; | ||
1278 | } | ||
1279 | 1282 | ||
1280 | return printed; | 1283 | return printed; |
1281 | } | 1284 | } |
@@ -1430,11 +1433,11 @@ static int trace__read_syscall_info(struct trace *trace, int id) | |||
1430 | sc->fmt = syscall_fmt__find(sc->name); | 1433 | sc->fmt = syscall_fmt__find(sc->name); |
1431 | 1434 | ||
1432 | snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->name); | 1435 | snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->name); |
1433 | sc->tp_format = event_format__new("syscalls", tp_name); | 1436 | sc->tp_format = trace_event__tp_format("syscalls", tp_name); |
1434 | 1437 | ||
1435 | if (sc->tp_format == NULL && sc->fmt && sc->fmt->alias) { | 1438 | if (sc->tp_format == NULL && sc->fmt && sc->fmt->alias) { |
1436 | snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->fmt->alias); | 1439 | snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->fmt->alias); |
1437 | sc->tp_format = event_format__new("syscalls", tp_name); | 1440 | sc->tp_format = trace_event__tp_format("syscalls", tp_name); |
1438 | } | 1441 | } |
1439 | 1442 | ||
1440 | if (sc->tp_format == NULL) | 1443 | if (sc->tp_format == NULL) |
@@ -1764,8 +1767,10 @@ static int trace__process_sample(struct perf_tool *tool, | |||
1764 | if (!trace->full_time && trace->base_time == 0) | 1767 | if (!trace->full_time && trace->base_time == 0) |
1765 | trace->base_time = sample->time; | 1768 | trace->base_time = sample->time; |
1766 | 1769 | ||
1767 | if (handler) | 1770 | if (handler) { |
1771 | ++trace->nr_events; | ||
1768 | handler(trace, evsel, sample); | 1772 | handler(trace, evsel, sample); |
1773 | } | ||
1769 | 1774 | ||
1770 | return err; | 1775 | return err; |
1771 | } | 1776 | } |
@@ -1800,10 +1805,11 @@ static int trace__record(int argc, const char **argv) | |||
1800 | "-R", | 1805 | "-R", |
1801 | "-m", "1024", | 1806 | "-m", "1024", |
1802 | "-c", "1", | 1807 | "-c", "1", |
1803 | "-e", "raw_syscalls:sys_enter,raw_syscalls:sys_exit", | 1808 | "-e", |
1804 | }; | 1809 | }; |
1805 | 1810 | ||
1806 | rec_argc = ARRAY_SIZE(record_args) + argc; | 1811 | /* +1 is for the event string below */ |
1812 | rec_argc = ARRAY_SIZE(record_args) + 1 + argc; | ||
1807 | rec_argv = calloc(rec_argc + 1, sizeof(char *)); | 1813 | rec_argv = calloc(rec_argc + 1, sizeof(char *)); |
1808 | 1814 | ||
1809 | if (rec_argv == NULL) | 1815 | if (rec_argv == NULL) |
@@ -1812,6 +1818,17 @@ static int trace__record(int argc, const char **argv) | |||
1812 | for (i = 0; i < ARRAY_SIZE(record_args); i++) | 1818 | for (i = 0; i < ARRAY_SIZE(record_args); i++) |
1813 | rec_argv[i] = record_args[i]; | 1819 | rec_argv[i] = record_args[i]; |
1814 | 1820 | ||
1821 | /* event string may be different for older kernels - e.g., RHEL6 */ | ||
1822 | if (is_valid_tracepoint("raw_syscalls:sys_enter")) | ||
1823 | rec_argv[i] = "raw_syscalls:sys_enter,raw_syscalls:sys_exit"; | ||
1824 | else if (is_valid_tracepoint("syscalls:sys_enter")) | ||
1825 | rec_argv[i] = "syscalls:sys_enter,syscalls:sys_exit"; | ||
1826 | else { | ||
1827 | pr_err("Neither raw_syscalls nor syscalls events exist.\n"); | ||
1828 | return -1; | ||
1829 | } | ||
1830 | i++; | ||
1831 | |||
1815 | for (j = 0; j < (unsigned int)argc; j++, i++) | 1832 | for (j = 0; j < (unsigned int)argc; j++, i++) |
1816 | rec_argv[i] = argv[j]; | 1833 | rec_argv[i] = argv[j]; |
1817 | 1834 | ||
@@ -1869,7 +1886,7 @@ static int trace__run(struct trace *trace, int argc, const char **argv) | |||
1869 | err = trace__symbols_init(trace, evlist); | 1886 | err = trace__symbols_init(trace, evlist); |
1870 | if (err < 0) { | 1887 | if (err < 0) { |
1871 | fprintf(trace->output, "Problems initializing symbol libraries!\n"); | 1888 | fprintf(trace->output, "Problems initializing symbol libraries!\n"); |
1872 | goto out_delete_maps; | 1889 | goto out_delete_evlist; |
1873 | } | 1890 | } |
1874 | 1891 | ||
1875 | perf_evlist__config(evlist, &trace->opts); | 1892 | perf_evlist__config(evlist, &trace->opts); |
@@ -1879,10 +1896,10 @@ static int trace__run(struct trace *trace, int argc, const char **argv) | |||
1879 | 1896 | ||
1880 | if (forks) { | 1897 | if (forks) { |
1881 | err = perf_evlist__prepare_workload(evlist, &trace->opts.target, | 1898 | err = perf_evlist__prepare_workload(evlist, &trace->opts.target, |
1882 | argv, false, false); | 1899 | argv, false, NULL); |
1883 | if (err < 0) { | 1900 | if (err < 0) { |
1884 | fprintf(trace->output, "Couldn't run the workload!\n"); | 1901 | fprintf(trace->output, "Couldn't run the workload!\n"); |
1885 | goto out_delete_maps; | 1902 | goto out_delete_evlist; |
1886 | } | 1903 | } |
1887 | } | 1904 | } |
1888 | 1905 | ||
@@ -1890,10 +1907,10 @@ static int trace__run(struct trace *trace, int argc, const char **argv) | |||
1890 | if (err < 0) | 1907 | if (err < 0) |
1891 | goto out_error_open; | 1908 | goto out_error_open; |
1892 | 1909 | ||
1893 | err = perf_evlist__mmap(evlist, UINT_MAX, false); | 1910 | err = perf_evlist__mmap(evlist, trace->opts.mmap_pages, false); |
1894 | if (err < 0) { | 1911 | if (err < 0) { |
1895 | fprintf(trace->output, "Couldn't mmap the events: %s\n", strerror(errno)); | 1912 | fprintf(trace->output, "Couldn't mmap the events: %s\n", strerror(errno)); |
1896 | goto out_close_evlist; | 1913 | goto out_delete_evlist; |
1897 | } | 1914 | } |
1898 | 1915 | ||
1899 | perf_evlist__enable(evlist); | 1916 | perf_evlist__enable(evlist); |
@@ -1977,11 +1994,6 @@ out_disable: | |||
1977 | } | 1994 | } |
1978 | } | 1995 | } |
1979 | 1996 | ||
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: | 1997 | out_delete_evlist: |
1986 | perf_evlist__delete(evlist); | 1998 | perf_evlist__delete(evlist); |
1987 | out: | 1999 | out: |
@@ -2047,6 +2059,10 @@ static int trace__replay(struct trace *trace) | |||
2047 | 2059 | ||
2048 | evsel = perf_evlist__find_tracepoint_by_name(session->evlist, | 2060 | evsel = perf_evlist__find_tracepoint_by_name(session->evlist, |
2049 | "raw_syscalls:sys_enter"); | 2061 | "raw_syscalls:sys_enter"); |
2062 | /* older kernels have syscalls tp versus raw_syscalls */ | ||
2063 | if (evsel == NULL) | ||
2064 | evsel = perf_evlist__find_tracepoint_by_name(session->evlist, | ||
2065 | "syscalls:sys_enter"); | ||
2050 | if (evsel == NULL) { | 2066 | if (evsel == NULL) { |
2051 | pr_err("Data file does not have raw_syscalls:sys_enter event\n"); | 2067 | pr_err("Data file does not have raw_syscalls:sys_enter event\n"); |
2052 | goto out; | 2068 | goto out; |
@@ -2060,6 +2076,9 @@ static int trace__replay(struct trace *trace) | |||
2060 | 2076 | ||
2061 | evsel = perf_evlist__find_tracepoint_by_name(session->evlist, | 2077 | evsel = perf_evlist__find_tracepoint_by_name(session->evlist, |
2062 | "raw_syscalls:sys_exit"); | 2078 | "raw_syscalls:sys_exit"); |
2079 | if (evsel == NULL) | ||
2080 | evsel = perf_evlist__find_tracepoint_by_name(session->evlist, | ||
2081 | "syscalls:sys_exit"); | ||
2063 | if (evsel == NULL) { | 2082 | if (evsel == NULL) { |
2064 | pr_err("Data file does not have raw_syscalls:sys_exit event\n"); | 2083 | pr_err("Data file does not have raw_syscalls:sys_exit event\n"); |
2065 | goto out; | 2084 | goto out; |
@@ -2158,7 +2177,6 @@ static int trace__fprintf_one_thread(struct thread *thread, void *priv) | |||
2158 | size_t printed = data->printed; | 2177 | size_t printed = data->printed; |
2159 | struct trace *trace = data->trace; | 2178 | struct trace *trace = data->trace; |
2160 | struct thread_trace *ttrace = thread->priv; | 2179 | struct thread_trace *ttrace = thread->priv; |
2161 | const char *color; | ||
2162 | double ratio; | 2180 | double ratio; |
2163 | 2181 | ||
2164 | if (ttrace == NULL) | 2182 | if (ttrace == NULL) |
@@ -2166,17 +2184,9 @@ static int trace__fprintf_one_thread(struct thread *thread, void *priv) | |||
2166 | 2184 | ||
2167 | ratio = (double)ttrace->nr_events / trace->nr_events * 100.0; | 2185 | ratio = (double)ttrace->nr_events / trace->nr_events * 100.0; |
2168 | 2186 | ||
2169 | color = PERF_COLOR_NORMAL; | 2187 | 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); | 2188 | printed += fprintf(fp, "%lu events, ", ttrace->nr_events); |
2179 | printed += color_fprintf(fp, color, "%.1f%%", ratio); | 2189 | printed += fprintf(fp, "%.1f%%", ratio); |
2180 | printed += fprintf(fp, ", %.3f msec\n", ttrace->runtime_ms); | 2190 | printed += fprintf(fp, ", %.3f msec\n", ttrace->runtime_ms); |
2181 | printed += thread__dump_stats(ttrace, trace, fp); | 2191 | printed += thread__dump_stats(ttrace, trace, fp); |
2182 | 2192 | ||
diff --git a/tools/perf/config/Makefile b/tools/perf/config/Makefile index f7d11a811c74..01dd43df0d04 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 |
@@ -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 ','\'',$(prefix)/$(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..7cf6fcdacebe 100644 --- a/tools/perf/config/feature-checks/Makefile +++ b/tools/perf/config/feature-checks/Makefile | |||
@@ -1,94 +1,90 @@ | |||
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 | ||
31 | 30 | ||
32 | CC := $(CC) -MD | 31 | CC := $(CC) -MD |
33 | 32 | ||
34 | all: $(FILES) | 33 | all: $(FILES) |
35 | 34 | ||
36 | BUILD = $(CC) $(CFLAGS) $(LDFLAGS) -o $(OUTPUT)$@ $@.c | 35 | BUILD = $(CC) $(CFLAGS) -o $(OUTPUT)$@ $(patsubst %.bin,%.c,$@) $(LDFLAGS) |
37 | 36 | ||
38 | ############################### | 37 | ############################### |
39 | 38 | ||
40 | test-all: | 39 | 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 | 40 | $(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 | 41 | ||
43 | test-hello: | 42 | test-hello.bin: |
44 | $(BUILD) | 43 | $(BUILD) |
45 | 44 | ||
46 | test-stackprotector-all: | 45 | test-stackprotector-all.bin: |
47 | $(BUILD) -Werror -fstack-protector-all | 46 | $(BUILD) -Werror -fstack-protector-all |
48 | 47 | ||
49 | test-stackprotector: | 48 | test-fortify-source.bin: |
50 | $(BUILD) -Werror -fstack-protector -Wstack-protector | ||
51 | |||
52 | test-fortify-source: | ||
53 | $(BUILD) -O2 -Werror -D_FORTIFY_SOURCE=2 | 49 | $(BUILD) -O2 -Werror -D_FORTIFY_SOURCE=2 |
54 | 50 | ||
55 | test-bionic: | 51 | test-bionic.bin: |
56 | $(BUILD) | 52 | $(BUILD) |
57 | 53 | ||
58 | test-libelf: | 54 | test-libelf.bin: |
59 | $(BUILD) -lelf | 55 | $(BUILD) -lelf |
60 | 56 | ||
61 | test-glibc: | 57 | test-glibc.bin: |
62 | $(BUILD) | 58 | $(BUILD) |
63 | 59 | ||
64 | test-dwarf: | 60 | test-dwarf.bin: |
65 | $(BUILD) -ldw | 61 | $(BUILD) -ldw |
66 | 62 | ||
67 | test-libelf-mmap: | 63 | test-libelf-mmap.bin: |
68 | $(BUILD) -lelf | 64 | $(BUILD) -lelf |
69 | 65 | ||
70 | test-libelf-getphdrnum: | 66 | test-libelf-getphdrnum.bin: |
71 | $(BUILD) -lelf | 67 | $(BUILD) -lelf |
72 | 68 | ||
73 | test-libnuma: | 69 | test-libnuma.bin: |
74 | $(BUILD) -lnuma | 70 | $(BUILD) -lnuma |
75 | 71 | ||
76 | test-libunwind: | 72 | test-libunwind.bin: |
77 | $(BUILD) $(LIBUNWIND_LIBS) -lelf | 73 | $(BUILD) -lelf |
78 | 74 | ||
79 | test-libunwind-debug-frame: | 75 | test-libunwind-debug-frame.bin: |
80 | $(BUILD) $(LIBUNWIND_LIBS) -lelf | 76 | $(BUILD) -lelf |
81 | 77 | ||
82 | test-libaudit: | 78 | test-libaudit.bin: |
83 | $(BUILD) -laudit | 79 | $(BUILD) -laudit |
84 | 80 | ||
85 | test-libslang: | 81 | test-libslang.bin: |
86 | $(BUILD) -I/usr/include/slang -lslang | 82 | $(BUILD) -I/usr/include/slang -lslang |
87 | 83 | ||
88 | test-gtk2: | 84 | test-gtk2.bin: |
89 | $(BUILD) $(shell pkg-config --libs --cflags gtk+-2.0 2>/dev/null) | 85 | $(BUILD) $(shell pkg-config --libs --cflags gtk+-2.0 2>/dev/null) |
90 | 86 | ||
91 | test-gtk2-infobar: | 87 | test-gtk2-infobar.bin: |
92 | $(BUILD) $(shell pkg-config --libs --cflags gtk+-2.0 2>/dev/null) | 88 | $(BUILD) $(shell pkg-config --libs --cflags gtk+-2.0 2>/dev/null) |
93 | 89 | ||
94 | grep-libs = $(filter -l%,$(1)) | 90 | grep-libs = $(filter -l%,$(1)) |
@@ -100,7 +96,7 @@ PERL_EMBED_LIBADD = $(call grep-libs,$(PERL_EMBED_LDOPTS)) | |||
100 | PERL_EMBED_CCOPTS = `perl -MExtUtils::Embed -e ccopts 2>/dev/null` | 96 | PERL_EMBED_CCOPTS = `perl -MExtUtils::Embed -e ccopts 2>/dev/null` |
101 | FLAGS_PERL_EMBED=$(PERL_EMBED_CCOPTS) $(PERL_EMBED_LDOPTS) | 97 | FLAGS_PERL_EMBED=$(PERL_EMBED_CCOPTS) $(PERL_EMBED_LDOPTS) |
102 | 98 | ||
103 | test-libperl: | 99 | test-libperl.bin: |
104 | $(BUILD) $(FLAGS_PERL_EMBED) | 100 | $(BUILD) $(FLAGS_PERL_EMBED) |
105 | 101 | ||
106 | override PYTHON := python | 102 | override PYTHON := python |
@@ -117,31 +113,31 @@ PYTHON_EMBED_LIBADD = $(call grep-libs,$(PYTHON_EMBED_LDOPTS)) | |||
117 | PYTHON_EMBED_CCOPTS = $(shell $(PYTHON_CONFIG_SQ) --cflags 2>/dev/null) | 113 | PYTHON_EMBED_CCOPTS = $(shell $(PYTHON_CONFIG_SQ) --cflags 2>/dev/null) |
118 | FLAGS_PYTHON_EMBED = $(PYTHON_EMBED_CCOPTS) $(PYTHON_EMBED_LDOPTS) | 114 | FLAGS_PYTHON_EMBED = $(PYTHON_EMBED_CCOPTS) $(PYTHON_EMBED_LDOPTS) |
119 | 115 | ||
120 | test-libpython: | 116 | test-libpython.bin: |
121 | $(BUILD) $(FLAGS_PYTHON_EMBED) | 117 | $(BUILD) $(FLAGS_PYTHON_EMBED) |
122 | 118 | ||
123 | test-libpython-version: | 119 | test-libpython-version.bin: |
124 | $(BUILD) $(FLAGS_PYTHON_EMBED) | 120 | $(BUILD) $(FLAGS_PYTHON_EMBED) |
125 | 121 | ||
126 | test-libbfd: | 122 | test-libbfd.bin: |
127 | $(BUILD) -DPACKAGE='"perf"' -lbfd -ldl | 123 | $(BUILD) -DPACKAGE='"perf"' -lbfd -ldl |
128 | 124 | ||
129 | test-liberty: | 125 | test-liberty.bin: |
130 | $(CC) -o $(OUTPUT)$@ test-libbfd.c -DPACKAGE='"perf"' -lbfd -ldl -liberty | 126 | $(CC) -o $(OUTPUT)$@ test-libbfd.c -DPACKAGE='"perf"' -lbfd -ldl -liberty |
131 | 127 | ||
132 | test-liberty-z: | 128 | test-liberty-z.bin: |
133 | $(CC) -o $(OUTPUT)$@ test-libbfd.c -DPACKAGE='"perf"' -lbfd -ldl -liberty -lz | 129 | $(CC) -o $(OUTPUT)$@ test-libbfd.c -DPACKAGE='"perf"' -lbfd -ldl -liberty -lz |
134 | 130 | ||
135 | test-cplus-demangle: | 131 | test-cplus-demangle.bin: |
136 | $(BUILD) -liberty | 132 | $(BUILD) -liberty |
137 | 133 | ||
138 | test-on-exit: | 134 | test-on-exit.bin: |
139 | $(BUILD) | 135 | $(BUILD) |
140 | 136 | ||
141 | test-backtrace: | 137 | test-backtrace.bin: |
142 | $(BUILD) | 138 | $(BUILD) |
143 | 139 | ||
144 | test-timerfd: | 140 | test-timerfd.bin: |
145 | $(BUILD) | 141 | $(BUILD) |
146 | 142 | ||
147 | -include *.d | 143 | -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/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..af1ce6e14a93 100644 --- a/tools/perf/perf.h +++ b/tools/perf/perf.h | |||
@@ -247,13 +247,14 @@ enum perf_call_graph_mode { | |||
247 | CALLCHAIN_DWARF | 247 | CALLCHAIN_DWARF |
248 | }; | 248 | }; |
249 | 249 | ||
250 | struct perf_record_opts { | 250 | struct record_opts { |
251 | struct target target; | 251 | struct target target; |
252 | int call_graph; | 252 | int call_graph; |
253 | bool group; | 253 | bool group; |
254 | bool inherit_stat; | 254 | bool inherit_stat; |
255 | bool no_delay; | 255 | bool no_delay; |
256 | bool no_inherit; | 256 | bool no_inherit; |
257 | bool no_inherit_set; | ||
257 | bool no_samples; | 258 | bool no_samples; |
258 | bool raw_samples; | 259 | bool raw_samples; |
259 | bool sample_address; | 260 | bool sample_address; |
@@ -268,6 +269,7 @@ struct perf_record_opts { | |||
268 | u64 user_interval; | 269 | u64 user_interval; |
269 | u16 stack_dump_size; | 270 | u16 stack_dump_size; |
270 | bool sample_transaction; | 271 | bool sample_transaction; |
272 | unsigned initial_delay; | ||
271 | }; | 273 | }; |
272 | 274 | ||
273 | #endif | 275 | #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..5a016f66f5d2 100644 --- a/tools/perf/tests/open-syscall-tp-fields.c +++ b/tools/perf/tests/open-syscall-tp-fields.c | |||
@@ -6,7 +6,7 @@ | |||
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, |
@@ -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..39cc7c3c0d0c 100644 --- a/tools/perf/tests/perf-record.c +++ b/tools/perf/tests/perf-record.c | |||
@@ -34,7 +34,7 @@ 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, |
@@ -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/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..469eb679fb9d 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c | |||
@@ -26,10 +26,10 @@ static int disasm_line__parse(char *line, char **namep, char **rawp); | |||
26 | 26 | ||
27 | static void ins__delete(struct ins_operands *ops) | 27 | static void ins__delete(struct ins_operands *ops) |
28 | { | 28 | { |
29 | free(ops->source.raw); | 29 | zfree(&ops->source.raw); |
30 | free(ops->source.name); | 30 | zfree(&ops->source.name); |
31 | free(ops->target.raw); | 31 | zfree(&ops->target.raw); |
32 | free(ops->target.name); | 32 | zfree(&ops->target.name); |
33 | } | 33 | } |
34 | 34 | ||
35 | static int ins__raw_scnprintf(struct ins *ins, char *bf, size_t size, | 35 | static int ins__raw_scnprintf(struct ins *ins, char *bf, size_t size, |
@@ -185,8 +185,7 @@ static int lock__parse(struct ins_operands *ops) | |||
185 | return 0; | 185 | return 0; |
186 | 186 | ||
187 | out_free_ops: | 187 | out_free_ops: |
188 | free(ops->locked.ops); | 188 | zfree(&ops->locked.ops); |
189 | ops->locked.ops = NULL; | ||
190 | return 0; | 189 | return 0; |
191 | } | 190 | } |
192 | 191 | ||
@@ -205,9 +204,9 @@ static int lock__scnprintf(struct ins *ins, char *bf, size_t size, | |||
205 | 204 | ||
206 | static void lock__delete(struct ins_operands *ops) | 205 | static void lock__delete(struct ins_operands *ops) |
207 | { | 206 | { |
208 | free(ops->locked.ops); | 207 | zfree(&ops->locked.ops); |
209 | free(ops->target.raw); | 208 | zfree(&ops->target.raw); |
210 | free(ops->target.name); | 209 | zfree(&ops->target.name); |
211 | } | 210 | } |
212 | 211 | ||
213 | static struct ins_ops lock_ops = { | 212 | static struct ins_ops lock_ops = { |
@@ -256,8 +255,7 @@ static int mov__parse(struct ins_operands *ops) | |||
256 | return 0; | 255 | return 0; |
257 | 256 | ||
258 | out_free_source: | 257 | out_free_source: |
259 | free(ops->source.raw); | 258 | zfree(&ops->source.raw); |
260 | ops->source.raw = NULL; | ||
261 | return -1; | 259 | return -1; |
262 | } | 260 | } |
263 | 261 | ||
@@ -464,17 +462,12 @@ void symbol__annotate_zero_histograms(struct symbol *sym) | |||
464 | pthread_mutex_unlock(¬es->lock); | 462 | pthread_mutex_unlock(¬es->lock); |
465 | } | 463 | } |
466 | 464 | ||
467 | int symbol__inc_addr_samples(struct symbol *sym, struct map *map, | 465 | static int __symbol__inc_addr_samples(struct symbol *sym, struct map *map, |
468 | int evidx, u64 addr) | 466 | struct annotation *notes, int evidx, u64 addr) |
469 | { | 467 | { |
470 | unsigned offset; | 468 | unsigned offset; |
471 | struct annotation *notes; | ||
472 | struct sym_hist *h; | 469 | struct sym_hist *h; |
473 | 470 | ||
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)); | 471 | pr_debug3("%s: addr=%#" PRIx64 "\n", __func__, map->unmap_ip(map, addr)); |
479 | 472 | ||
480 | if (addr < sym->start || addr > sym->end) | 473 | if (addr < sym->start || addr > sym->end) |
@@ -491,6 +484,33 @@ int symbol__inc_addr_samples(struct symbol *sym, struct map *map, | |||
491 | return 0; | 484 | return 0; |
492 | } | 485 | } |
493 | 486 | ||
487 | static int symbol__inc_addr_samples(struct symbol *sym, struct map *map, | ||
488 | int evidx, u64 addr) | ||
489 | { | ||
490 | struct annotation *notes; | ||
491 | |||
492 | if (sym == NULL || use_browser != 1 || !sort__has_sym) | ||
493 | return 0; | ||
494 | |||
495 | notes = symbol__annotation(sym); | ||
496 | if (notes->src == NULL) { | ||
497 | if (symbol__alloc_hist(sym) < 0) | ||
498 | return -ENOMEM; | ||
499 | } | ||
500 | |||
501 | return __symbol__inc_addr_samples(sym, map, notes, evidx, addr); | ||
502 | } | ||
503 | |||
504 | int addr_map_symbol__inc_samples(struct addr_map_symbol *ams, int evidx) | ||
505 | { | ||
506 | return symbol__inc_addr_samples(ams->sym, ams->map, evidx, ams->al_addr); | ||
507 | } | ||
508 | |||
509 | int hist_entry__inc_addr_samples(struct hist_entry *he, int evidx, u64 ip) | ||
510 | { | ||
511 | return symbol__inc_addr_samples(he->ms.sym, he->ms.map, evidx, ip); | ||
512 | } | ||
513 | |||
494 | static void disasm_line__init_ins(struct disasm_line *dl) | 514 | static void disasm_line__init_ins(struct disasm_line *dl) |
495 | { | 515 | { |
496 | dl->ins = ins__find(dl->name); | 516 | dl->ins = ins__find(dl->name); |
@@ -538,8 +558,7 @@ static int disasm_line__parse(char *line, char **namep, char **rawp) | |||
538 | return 0; | 558 | return 0; |
539 | 559 | ||
540 | out_free_name: | 560 | out_free_name: |
541 | free(*namep); | 561 | zfree(namep); |
542 | *namep = NULL; | ||
543 | return -1; | 562 | return -1; |
544 | } | 563 | } |
545 | 564 | ||
@@ -564,7 +583,7 @@ static struct disasm_line *disasm_line__new(s64 offset, char *line, size_t privs | |||
564 | return dl; | 583 | return dl; |
565 | 584 | ||
566 | out_free_line: | 585 | out_free_line: |
567 | free(dl->line); | 586 | zfree(&dl->line); |
568 | out_delete: | 587 | out_delete: |
569 | free(dl); | 588 | free(dl); |
570 | return NULL; | 589 | return NULL; |
@@ -572,8 +591,8 @@ out_delete: | |||
572 | 591 | ||
573 | void disasm_line__free(struct disasm_line *dl) | 592 | void disasm_line__free(struct disasm_line *dl) |
574 | { | 593 | { |
575 | free(dl->line); | 594 | zfree(&dl->line); |
576 | free(dl->name); | 595 | zfree(&dl->name); |
577 | if (dl->ins && dl->ins->ops->free) | 596 | if (dl->ins && dl->ins->ops->free) |
578 | dl->ins->ops->free(&dl->ops); | 597 | dl->ins->ops->free(&dl->ops); |
579 | else | 598 | else |
@@ -900,7 +919,7 @@ fallback: | |||
900 | * cache, or is just a kallsyms file, well, lets hope that this | 919 | * cache, or is just a kallsyms file, well, lets hope that this |
901 | * DSO is the same as when 'perf record' ran. | 920 | * DSO is the same as when 'perf record' ran. |
902 | */ | 921 | */ |
903 | filename = dso->long_name; | 922 | filename = (char *)dso->long_name; |
904 | snprintf(symfs_filename, sizeof(symfs_filename), "%s%s", | 923 | snprintf(symfs_filename, sizeof(symfs_filename), "%s%s", |
905 | symbol_conf.symfs, filename); | 924 | symbol_conf.symfs, filename); |
906 | free_filename = false; | 925 | free_filename = false; |
@@ -1091,8 +1110,7 @@ static void symbol__free_source_line(struct symbol *sym, int len) | |||
1091 | src_line = (void *)src_line + sizeof_src_line; | 1110 | src_line = (void *)src_line + sizeof_src_line; |
1092 | } | 1111 | } |
1093 | 1112 | ||
1094 | free(notes->src->lines); | 1113 | zfree(¬es->src->lines); |
1095 | notes->src->lines = NULL; | ||
1096 | } | 1114 | } |
1097 | 1115 | ||
1098 | /* Get the filename:line for the colored entries */ | 1116 | /* Get the filename:line for the colored entries */ |
@@ -1376,3 +1394,8 @@ int symbol__tty_annotate(struct symbol *sym, struct map *map, | |||
1376 | 1394 | ||
1377 | return 0; | 1395 | return 0; |
1378 | } | 1396 | } |
1397 | |||
1398 | int hist_entry__annotate(struct hist_entry *he, size_t privsize) | ||
1399 | { | ||
1400 | return symbol__annotate(he->ms.sym, he->ms.map, privsize); | ||
1401 | } | ||
diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h index 834b7b57b788..b2aef59d6bb2 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, |
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.h b/tools/perf/util/callchain.h index 4f7f989876ec..08b25af9eea1 100644 --- a/tools/perf/util/callchain.h +++ b/tools/perf/util/callchain.h | |||
@@ -146,7 +146,7 @@ static inline void callchain_cursor_advance(struct callchain_cursor *cursor) | |||
146 | 146 | ||
147 | struct option; | 147 | struct option; |
148 | 148 | ||
149 | int record_parse_callchain(const char *arg, struct perf_record_opts *opts); | 149 | 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); | 150 | 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); | 151 | int record_callchain_opt(const struct option *opt, const char *arg, int unset); |
152 | 152 | ||
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..67d1e404c0cb 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 | } |
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..1fc1c2f04772 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 | ||
@@ -637,6 +659,7 @@ void thread__find_addr_map(struct thread *thread, | |||
637 | struct map_groups *mg = &thread->mg; | 659 | struct map_groups *mg = &thread->mg; |
638 | bool load_map = false; | 660 | bool load_map = false; |
639 | 661 | ||
662 | al->machine = machine; | ||
640 | al->thread = thread; | 663 | al->thread = thread; |
641 | al->addr = addr; | 664 | al->addr = addr; |
642 | al->cpumode = cpumode; | 665 | al->cpumode = cpumode; |
@@ -657,15 +680,10 @@ void thread__find_addr_map(struct thread *thread, | |||
657 | al->level = 'g'; | 680 | al->level = 'g'; |
658 | mg = &machine->kmaps; | 681 | mg = &machine->kmaps; |
659 | load_map = true; | 682 | load_map = true; |
683 | } else if (cpumode == PERF_RECORD_MISC_GUEST_USER && perf_guest) { | ||
684 | al->level = 'u'; | ||
660 | } else { | 685 | } else { |
661 | /* | 686 | 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; | 687 | al->map = NULL; |
670 | 688 | ||
671 | if ((cpumode == PERF_RECORD_MISC_GUEST_USER || | 689 | if ((cpumode == PERF_RECORD_MISC_GUEST_USER || |
@@ -732,8 +750,7 @@ int perf_event__preprocess_sample(const union perf_event *event, | |||
732 | if (thread == NULL) | 750 | if (thread == NULL) |
733 | return -1; | 751 | return -1; |
734 | 752 | ||
735 | if (symbol_conf.comm_list && | 753 | if (thread__is_filtered(thread)) |
736 | !strlist__has_entry(symbol_conf.comm_list, thread__comm_str(thread))) | ||
737 | goto out_filtered; | 754 | goto out_filtered; |
738 | 755 | ||
739 | dump_printf(" ... thread: %s:%d\n", thread__comm_str(thread), thread->tid); | 756 | 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..faf6e219be21 100644 --- a/tools/perf/util/event.h +++ b/tools/perf/util/event.h | |||
@@ -266,6 +266,13 @@ int perf_event__synthesize_sample(union perf_event *event, u64 type, | |||
266 | const struct perf_sample *sample, | 266 | const struct perf_sample *sample, |
267 | bool swapped); | 267 | bool swapped); |
268 | 268 | ||
269 | int perf_event__synthesize_mmap_events(struct perf_tool *tool, | ||
270 | union perf_event *event, | ||
271 | pid_t pid, pid_t tgid, | ||
272 | perf_event__handler_t process, | ||
273 | struct machine *machine, | ||
274 | bool mmap_data); | ||
275 | |||
269 | size_t perf_event__fprintf_comm(union perf_event *event, FILE *fp); | 276 | 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); | 277 | 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); | 278 | size_t perf_event__fprintf_mmap2(union perf_event *event, FILE *fp); |
diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c index bbc746aa5716..40bd2c04df8a 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 | } |
@@ -1008,7 +1004,7 @@ void perf_evlist__close(struct perf_evlist *evlist) | |||
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); |
1010 | 1006 | ||
1011 | list_for_each_entry_reverse(evsel, &evlist->entries, node) | 1007 | evlist__for_each_reverse(evlist, evsel) |
1012 | perf_evsel__close(evsel, ncpus, nthreads); | 1008 | perf_evsel__close(evsel, ncpus, nthreads); |
1013 | } | 1009 | } |
1014 | 1010 | ||
@@ -1019,7 +1015,7 @@ int perf_evlist__open(struct perf_evlist *evlist) | |||
1019 | 1015 | ||
1020 | perf_evlist__update_id_pos(evlist); | 1016 | perf_evlist__update_id_pos(evlist); |
1021 | 1017 | ||
1022 | list_for_each_entry(evsel, &evlist->entries, node) { | 1018 | evlist__for_each(evlist, evsel) { |
1023 | err = perf_evsel__open(evsel, evlist->cpus, evlist->threads); | 1019 | err = perf_evsel__open(evsel, evlist->cpus, evlist->threads); |
1024 | if (err < 0) | 1020 | if (err < 0) |
1025 | goto out_err; | 1021 | goto out_err; |
@@ -1034,7 +1030,7 @@ out_err: | |||
1034 | 1030 | ||
1035 | int perf_evlist__prepare_workload(struct perf_evlist *evlist, struct target *target, | 1031 | int perf_evlist__prepare_workload(struct perf_evlist *evlist, struct target *target, |
1036 | const char *argv[], bool pipe_output, | 1032 | const char *argv[], bool pipe_output, |
1037 | bool want_signal) | 1033 | void (*exec_error)(int signo, siginfo_t *info, void *ucontext)) |
1038 | { | 1034 | { |
1039 | int child_ready_pipe[2], go_pipe[2]; | 1035 | int child_ready_pipe[2], go_pipe[2]; |
1040 | char bf; | 1036 | char bf; |
@@ -1078,12 +1074,25 @@ int perf_evlist__prepare_workload(struct perf_evlist *evlist, struct target *tar | |||
1078 | 1074 | ||
1079 | execvp(argv[0], (char **)argv); | 1075 | execvp(argv[0], (char **)argv); |
1080 | 1076 | ||
1081 | perror(argv[0]); | 1077 | if (exec_error) { |
1082 | if (want_signal) | 1078 | union sigval val; |
1083 | kill(getppid(), SIGUSR1); | 1079 | |
1080 | val.sival_int = errno; | ||
1081 | if (sigqueue(getppid(), SIGUSR1, val)) | ||
1082 | perror(argv[0]); | ||
1083 | } else | ||
1084 | perror(argv[0]); | ||
1084 | exit(-1); | 1085 | exit(-1); |
1085 | } | 1086 | } |
1086 | 1087 | ||
1088 | if (exec_error) { | ||
1089 | struct sigaction act = { | ||
1090 | .sa_flags = SA_SIGINFO, | ||
1091 | .sa_sigaction = exec_error, | ||
1092 | }; | ||
1093 | sigaction(SIGUSR1, &act, NULL); | ||
1094 | } | ||
1095 | |||
1087 | if (target__none(target)) | 1096 | if (target__none(target)) |
1088 | evlist->threads->map[0] = evlist->workload.pid; | 1097 | evlist->threads->map[0] = evlist->workload.pid; |
1089 | 1098 | ||
@@ -1145,7 +1154,7 @@ size_t perf_evlist__fprintf(struct perf_evlist *evlist, FILE *fp) | |||
1145 | struct perf_evsel *evsel; | 1154 | struct perf_evsel *evsel; |
1146 | size_t printed = 0; | 1155 | size_t printed = 0; |
1147 | 1156 | ||
1148 | list_for_each_entry(evsel, &evlist->entries, node) { | 1157 | evlist__for_each(evlist, evsel) { |
1149 | printed += fprintf(fp, "%s%s", evsel->idx ? ", " : "", | 1158 | printed += fprintf(fp, "%s%s", evsel->idx ? ", " : "", |
1150 | perf_evsel__name(evsel)); | 1159 | perf_evsel__name(evsel)); |
1151 | } | 1160 | } |
@@ -1193,8 +1202,7 @@ int perf_evlist__strerror_open(struct perf_evlist *evlist __maybe_unused, | |||
1193 | "Error:\t%s.\n" | 1202 | "Error:\t%s.\n" |
1194 | "Hint:\tCheck /proc/sys/kernel/perf_event_paranoid setting.", emsg); | 1203 | "Hint:\tCheck /proc/sys/kernel/perf_event_paranoid setting.", emsg); |
1195 | 1204 | ||
1196 | if (filename__read_int("/proc/sys/kernel/perf_event_paranoid", &value)) | 1205 | value = perf_event_paranoid(); |
1197 | break; | ||
1198 | 1206 | ||
1199 | printed += scnprintf(buf + printed, size - printed, "\nHint:\t"); | 1207 | printed += scnprintf(buf + printed, size - printed, "\nHint:\t"); |
1200 | 1208 | ||
@@ -1215,3 +1223,20 @@ int perf_evlist__strerror_open(struct perf_evlist *evlist __maybe_unused, | |||
1215 | 1223 | ||
1216 | return 0; | 1224 | return 0; |
1217 | } | 1225 | } |
1226 | |||
1227 | void perf_evlist__to_front(struct perf_evlist *evlist, | ||
1228 | struct perf_evsel *move_evsel) | ||
1229 | { | ||
1230 | struct perf_evsel *evsel, *n; | ||
1231 | LIST_HEAD(move); | ||
1232 | |||
1233 | if (move_evsel == perf_evlist__first(evlist)) | ||
1234 | return; | ||
1235 | |||
1236 | evlist__for_each_safe(evlist, n, evsel) { | ||
1237 | if (evsel->leader == move_evsel->leader) | ||
1238 | list_move_tail(&evsel->node, &move); | ||
1239 | } | ||
1240 | |||
1241 | list_splice(&move, &evlist->entries); | ||
1242 | } | ||
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..cd4630abfa43 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) { |
@@ -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 | ||
@@ -1998,8 +1960,7 @@ bool perf_evsel__fallback(struct perf_evsel *evsel, int err, | |||
1998 | evsel->attr.type = PERF_TYPE_SOFTWARE; | 1960 | evsel->attr.type = PERF_TYPE_SOFTWARE; |
1999 | evsel->attr.config = PERF_COUNT_SW_CPU_CLOCK; | 1961 | evsel->attr.config = PERF_COUNT_SW_CPU_CLOCK; |
2000 | 1962 | ||
2001 | free(evsel->name); | 1963 | zfree(&evsel->name); |
2002 | evsel->name = NULL; | ||
2003 | return true; | 1964 | return true; |
2004 | } | 1965 | } |
2005 | 1966 | ||
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..bb3e0ede6183 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 | } |
@@ -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..4ed3e883240d 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" |
@@ -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 |
@@ -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/machine.c b/tools/perf/util/machine.c index 84cdb072ac83..0130279aac51 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) |
@@ -502,15 +503,11 @@ static u64 machine__get_kernel_start_addr(struct machine *machine) | |||
502 | char path[PATH_MAX]; | 503 | char path[PATH_MAX]; |
503 | struct process_args args; | 504 | struct process_args args; |
504 | 505 | ||
505 | if (machine__is_host(machine)) { | 506 | if (machine__is_default_guest(machine)) |
506 | filename = "/proc/kallsyms"; | 507 | filename = (char *)symbol_conf.default_guest_kallsyms; |
507 | } else { | 508 | else { |
508 | if (machine__is_default_guest(machine)) | 509 | sprintf(path, "%s/proc/kallsyms", machine->root_dir); |
509 | filename = (char *)symbol_conf.default_guest_kallsyms; | 510 | filename = path; |
510 | else { | ||
511 | sprintf(path, "%s/proc/kallsyms", machine->root_dir); | ||
512 | filename = path; | ||
513 | } | ||
514 | } | 511 | } |
515 | 512 | ||
516 | if (symbol__restricted_filename(filename, "/proc/kallsyms")) | 513 | if (symbol__restricted_filename(filename, "/proc/kallsyms")) |
@@ -565,11 +562,10 @@ void machine__destroy_kernel_maps(struct machine *machine) | |||
565 | * on one of them. | 562 | * on one of them. |
566 | */ | 563 | */ |
567 | if (type == MAP__FUNCTION) { | 564 | if (type == MAP__FUNCTION) { |
568 | free((char *)kmap->ref_reloc_sym->name); | 565 | zfree((char **)&kmap->ref_reloc_sym->name); |
569 | kmap->ref_reloc_sym->name = NULL; | 566 | zfree(&kmap->ref_reloc_sym); |
570 | free(kmap->ref_reloc_sym); | 567 | } else |
571 | } | 568 | kmap->ref_reloc_sym = NULL; |
572 | kmap->ref_reloc_sym = NULL; | ||
573 | } | 569 | } |
574 | 570 | ||
575 | map__delete(machine->vmlinux_maps[type]); | 571 | map__delete(machine->vmlinux_maps[type]); |
@@ -767,8 +763,7 @@ static int map_groups__set_modules_path_dir(struct map_groups *mg, | |||
767 | ret = -1; | 763 | ret = -1; |
768 | goto out; | 764 | goto out; |
769 | } | 765 | } |
770 | dso__set_long_name(map->dso, long_name); | 766 | dso__set_long_name(map->dso, long_name, true); |
771 | map->dso->lname_alloc = 1; | ||
772 | dso__kernel_module_get_build_id(map->dso, ""); | 767 | dso__kernel_module_get_build_id(map->dso, ""); |
773 | } | 768 | } |
774 | } | 769 | } |
@@ -939,8 +934,7 @@ static int machine__process_kernel_mmap_event(struct machine *machine, | |||
939 | if (name == NULL) | 934 | if (name == NULL) |
940 | goto out_problem; | 935 | goto out_problem; |
941 | 936 | ||
942 | map->dso->short_name = name; | 937 | dso__set_short_name(map->dso, name, true); |
943 | map->dso->sname_alloc = 1; | ||
944 | map->end = map->start + event->mmap.len; | 938 | map->end = map->start + event->mmap.len; |
945 | } else if (is_kernel_mmap) { | 939 | } else if (is_kernel_mmap) { |
946 | const char *symbol_name = (event->mmap.filename + | 940 | const char *symbol_name = (event->mmap.filename + |
diff --git a/tools/perf/util/map.c b/tools/perf/util/map.c index ef5bc913ca7a..9b9bd719aa19 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] = { |
@@ -252,6 +253,22 @@ size_t map__fprintf_dsoname(struct map *map, FILE *fp) | |||
252 | return fprintf(fp, "%s", dsoname); | 253 | return fprintf(fp, "%s", dsoname); |
253 | } | 254 | } |
254 | 255 | ||
256 | int map__fprintf_srcline(struct map *map, u64 addr, const char *prefix, | ||
257 | FILE *fp) | ||
258 | { | ||
259 | char *srcline; | ||
260 | int ret = 0; | ||
261 | |||
262 | if (map && map->dso) { | ||
263 | srcline = get_srcline(map->dso, | ||
264 | map__rip_2objdump(map, addr)); | ||
265 | if (srcline != SRCLINE_UNKNOWN) | ||
266 | ret = fprintf(fp, "%s%s", prefix, srcline); | ||
267 | free_srcline(srcline); | ||
268 | } | ||
269 | return ret; | ||
270 | } | ||
271 | |||
255 | /** | 272 | /** |
256 | * map__rip_2objdump - convert symbol start address to objdump address. | 273 | * map__rip_2objdump - convert symbol start address to objdump address. |
257 | * @map: memory map | 274 | * @map: memory map |
diff --git a/tools/perf/util/map.h b/tools/perf/util/map.h index e4e259c3ba16..18068c6b71c1 100644 --- a/tools/perf/util/map.h +++ b/tools/perf/util/map.h | |||
@@ -103,6 +103,8 @@ struct map *map__clone(struct map *map); | |||
103 | int map__overlap(struct map *l, struct map *r); | 103 | int map__overlap(struct map *l, struct map *r); |
104 | size_t map__fprintf(struct map *map, FILE *fp); | 104 | size_t map__fprintf(struct map *map, FILE *fp); |
105 | size_t map__fprintf_dsoname(struct map *map, FILE *fp); | 105 | size_t map__fprintf_dsoname(struct map *map, FILE *fp); |
106 | int map__fprintf_srcline(struct map *map, u64 addr, const char *prefix, | ||
107 | FILE *fp); | ||
106 | 108 | ||
107 | int map__load(struct map *map, symbol_filter_t filter); | 109 | int map__load(struct map *map, symbol_filter_t filter); |
108 | struct symbol *map__find_symbol(struct map *map, | 110 | 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..a7f1b6a91fdd 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 | 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 | ||
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..d9cab4d27192 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 | 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,42 @@ 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 | 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 | 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 | *unit = NULL; | ||
644 | *scale = 0; | ||
645 | |||
521 | list_for_each_entry_safe(term, h, head_terms, list) { | 646 | list_for_each_entry_safe(term, h, head_terms, list) { |
522 | alias = pmu_find_alias(pmu, term); | 647 | alias = pmu_find_alias(pmu, term); |
523 | if (!alias) | 648 | if (!alias) |
@@ -525,6 +650,11 @@ int perf_pmu__check_alias(struct perf_pmu *pmu, struct list_head *head_terms) | |||
525 | ret = pmu_alias_terms(alias, &term->list); | 650 | ret = pmu_alias_terms(alias, &term->list); |
526 | if (ret) | 651 | if (ret) |
527 | return ret; | 652 | return ret; |
653 | |||
654 | ret = check_unit_scale(alias, unit, scale); | ||
655 | if (ret) | ||
656 | return ret; | ||
657 | |||
528 | list_del(&term->list); | 658 | list_del(&term->list); |
529 | free(term); | 659 | free(term); |
530 | } | 660 | } |
@@ -625,7 +755,7 @@ void print_pmu_events(const char *event_glob, bool name_only) | |||
625 | continue; | 755 | continue; |
626 | } | 756 | } |
627 | printf(" %-50s [Kernel PMU event]\n", aliases[j]); | 757 | printf(" %-50s [Kernel PMU event]\n", aliases[j]); |
628 | free(aliases[j]); | 758 | zfree(&aliases[j]); |
629 | printed++; | 759 | printed++; |
630 | } | 760 | } |
631 | if (printed) | 761 | if (printed) |
diff --git a/tools/perf/util/pmu.h b/tools/perf/util/pmu.h index 1179b26f244a..9183380e2038 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 | 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..a4ee6b4a840f 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" |
@@ -154,7 +154,7 @@ static struct dso *kernel_get_module_dso(const char *module) | |||
154 | 154 | ||
155 | vmlinux_name = symbol_conf.vmlinux_name; | 155 | vmlinux_name = symbol_conf.vmlinux_name; |
156 | if (vmlinux_name) { | 156 | if (vmlinux_name) { |
157 | if (dso__load_vmlinux(dso, map, vmlinux_name, NULL) <= 0) | 157 | if (dso__load_vmlinux(dso, map, vmlinux_name, false, NULL) <= 0) |
158 | return NULL; | 158 | return NULL; |
159 | } else { | 159 | } else { |
160 | if (dso__load_vmlinux_path(dso, map, NULL) <= 0) { | 160 | if (dso__load_vmlinux_path(dso, map, NULL) <= 0) { |
@@ -172,6 +172,54 @@ const char *kernel_get_module_path(const char *module) | |||
172 | return (dso) ? dso->long_name : NULL; | 172 | return (dso) ? dso->long_name : NULL; |
173 | } | 173 | } |
174 | 174 | ||
175 | #ifdef HAVE_DWARF_SUPPORT | ||
176 | /* Copied from unwind.c */ | ||
177 | static Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep, | ||
178 | GElf_Shdr *shp, const char *name) | ||
179 | { | ||
180 | Elf_Scn *sec = NULL; | ||
181 | |||
182 | while ((sec = elf_nextscn(elf, sec)) != NULL) { | ||
183 | char *str; | ||
184 | |||
185 | gelf_getshdr(sec, shp); | ||
186 | str = elf_strptr(elf, ep->e_shstrndx, shp->sh_name); | ||
187 | if (!strcmp(name, str)) | ||
188 | break; | ||
189 | } | ||
190 | |||
191 | return sec; | ||
192 | } | ||
193 | |||
194 | static int get_text_start_address(const char *exec, unsigned long *address) | ||
195 | { | ||
196 | Elf *elf; | ||
197 | GElf_Ehdr ehdr; | ||
198 | GElf_Shdr shdr; | ||
199 | int fd, ret = -ENOENT; | ||
200 | |||
201 | fd = open(exec, O_RDONLY); | ||
202 | if (fd < 0) | ||
203 | return -errno; | ||
204 | |||
205 | elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL); | ||
206 | if (elf == NULL) | ||
207 | return -EINVAL; | ||
208 | |||
209 | if (gelf_getehdr(elf, &ehdr) == NULL) | ||
210 | goto out; | ||
211 | |||
212 | if (!elf_section_by_name(elf, &ehdr, &shdr, ".text")) | ||
213 | goto out; | ||
214 | |||
215 | *address = shdr.sh_addr - shdr.sh_offset; | ||
216 | ret = 0; | ||
217 | out: | ||
218 | elf_end(elf); | ||
219 | return ret; | ||
220 | } | ||
221 | #endif | ||
222 | |||
175 | static int init_user_exec(void) | 223 | static int init_user_exec(void) |
176 | { | 224 | { |
177 | int ret = 0; | 225 | int ret = 0; |
@@ -186,6 +234,37 @@ static int init_user_exec(void) | |||
186 | return ret; | 234 | return ret; |
187 | } | 235 | } |
188 | 236 | ||
237 | static int convert_exec_to_group(const char *exec, char **result) | ||
238 | { | ||
239 | char *ptr1, *ptr2, *exec_copy; | ||
240 | char buf[64]; | ||
241 | int ret; | ||
242 | |||
243 | exec_copy = strdup(exec); | ||
244 | if (!exec_copy) | ||
245 | return -ENOMEM; | ||
246 | |||
247 | ptr1 = basename(exec_copy); | ||
248 | if (!ptr1) { | ||
249 | ret = -EINVAL; | ||
250 | goto out; | ||
251 | } | ||
252 | |||
253 | ptr2 = strpbrk(ptr1, "-._"); | ||
254 | if (ptr2) | ||
255 | *ptr2 = '\0'; | ||
256 | ret = e_snprintf(buf, 64, "%s_%s", PERFPROBE_GROUP, ptr1); | ||
257 | if (ret < 0) | ||
258 | goto out; | ||
259 | |||
260 | *result = strdup(buf); | ||
261 | ret = *result ? 0 : -ENOMEM; | ||
262 | |||
263 | out: | ||
264 | free(exec_copy); | ||
265 | return ret; | ||
266 | } | ||
267 | |||
189 | static int convert_to_perf_probe_point(struct probe_trace_point *tp, | 268 | static int convert_to_perf_probe_point(struct probe_trace_point *tp, |
190 | struct perf_probe_point *pp) | 269 | struct perf_probe_point *pp) |
191 | { | 270 | { |
@@ -261,6 +340,40 @@ static int kprobe_convert_to_perf_probe(struct probe_trace_point *tp, | |||
261 | return 0; | 340 | return 0; |
262 | } | 341 | } |
263 | 342 | ||
343 | static int add_exec_to_probe_trace_events(struct probe_trace_event *tevs, | ||
344 | int ntevs, const char *exec) | ||
345 | { | ||
346 | int i, ret = 0; | ||
347 | unsigned long offset, stext = 0; | ||
348 | char buf[32]; | ||
349 | |||
350 | if (!exec) | ||
351 | return 0; | ||
352 | |||
353 | ret = get_text_start_address(exec, &stext); | ||
354 | if (ret < 0) | ||
355 | return ret; | ||
356 | |||
357 | for (i = 0; i < ntevs && ret >= 0; i++) { | ||
358 | offset = tevs[i].point.address - stext; | ||
359 | offset += tevs[i].point.offset; | ||
360 | tevs[i].point.offset = 0; | ||
361 | zfree(&tevs[i].point.symbol); | ||
362 | ret = e_snprintf(buf, 32, "0x%lx", offset); | ||
363 | if (ret < 0) | ||
364 | break; | ||
365 | tevs[i].point.module = strdup(exec); | ||
366 | tevs[i].point.symbol = strdup(buf); | ||
367 | if (!tevs[i].point.symbol || !tevs[i].point.module) { | ||
368 | ret = -ENOMEM; | ||
369 | break; | ||
370 | } | ||
371 | tevs[i].uprobes = true; | ||
372 | } | ||
373 | |||
374 | return ret; | ||
375 | } | ||
376 | |||
264 | static int add_module_to_probe_trace_events(struct probe_trace_event *tevs, | 377 | static int add_module_to_probe_trace_events(struct probe_trace_event *tevs, |
265 | int ntevs, const char *module) | 378 | int ntevs, const char *module) |
266 | { | 379 | { |
@@ -290,9 +403,7 @@ static int add_module_to_probe_trace_events(struct probe_trace_event *tevs, | |||
290 | } | 403 | } |
291 | } | 404 | } |
292 | 405 | ||
293 | if (tmp) | 406 | free(tmp); |
294 | free(tmp); | ||
295 | |||
296 | return ret; | 407 | return ret; |
297 | } | 408 | } |
298 | 409 | ||
@@ -305,15 +416,6 @@ static int try_to_find_probe_trace_events(struct perf_probe_event *pev, | |||
305 | struct debuginfo *dinfo; | 416 | struct debuginfo *dinfo; |
306 | int ntevs, ret = 0; | 417 | int ntevs, ret = 0; |
307 | 418 | ||
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); | 419 | dinfo = open_debuginfo(target); |
318 | 420 | ||
319 | if (!dinfo) { | 421 | if (!dinfo) { |
@@ -332,9 +434,14 @@ static int try_to_find_probe_trace_events(struct perf_probe_event *pev, | |||
332 | 434 | ||
333 | if (ntevs > 0) { /* Succeeded to find trace events */ | 435 | if (ntevs > 0) { /* Succeeded to find trace events */ |
334 | pr_debug("find %d probe_trace_events.\n", ntevs); | 436 | pr_debug("find %d probe_trace_events.\n", ntevs); |
335 | if (target) | 437 | if (target) { |
336 | ret = add_module_to_probe_trace_events(*tevs, ntevs, | 438 | if (pev->uprobes) |
337 | target); | 439 | ret = add_exec_to_probe_trace_events(*tevs, |
440 | ntevs, target); | ||
441 | else | ||
442 | ret = add_module_to_probe_trace_events(*tevs, | ||
443 | ntevs, target); | ||
444 | } | ||
338 | return ret < 0 ? ret : ntevs; | 445 | return ret < 0 ? ret : ntevs; |
339 | } | 446 | } |
340 | 447 | ||
@@ -401,15 +508,13 @@ static int get_real_path(const char *raw_path, const char *comp_dir, | |||
401 | case EFAULT: | 508 | case EFAULT: |
402 | raw_path = strchr(++raw_path, '/'); | 509 | raw_path = strchr(++raw_path, '/'); |
403 | if (!raw_path) { | 510 | if (!raw_path) { |
404 | free(*new_path); | 511 | zfree(new_path); |
405 | *new_path = NULL; | ||
406 | return -ENOENT; | 512 | return -ENOENT; |
407 | } | 513 | } |
408 | continue; | 514 | continue; |
409 | 515 | ||
410 | default: | 516 | default: |
411 | free(*new_path); | 517 | zfree(new_path); |
412 | *new_path = NULL; | ||
413 | return -errno; | 518 | return -errno; |
414 | } | 519 | } |
415 | } | 520 | } |
@@ -580,7 +685,7 @@ static int show_available_vars_at(struct debuginfo *dinfo, | |||
580 | */ | 685 | */ |
581 | fprintf(stdout, "\t@<%s+%lu>\n", vl->point.symbol, | 686 | fprintf(stdout, "\t@<%s+%lu>\n", vl->point.symbol, |
582 | vl->point.offset); | 687 | vl->point.offset); |
583 | free(vl->point.symbol); | 688 | zfree(&vl->point.symbol); |
584 | nvars = 0; | 689 | nvars = 0; |
585 | if (vl->vars) { | 690 | if (vl->vars) { |
586 | strlist__for_each(node, vl->vars) { | 691 | strlist__for_each(node, vl->vars) { |
@@ -647,16 +752,14 @@ static int kprobe_convert_to_perf_probe(struct probe_trace_point *tp, | |||
647 | 752 | ||
648 | static int try_to_find_probe_trace_events(struct perf_probe_event *pev, | 753 | static int try_to_find_probe_trace_events(struct perf_probe_event *pev, |
649 | struct probe_trace_event **tevs __maybe_unused, | 754 | struct probe_trace_event **tevs __maybe_unused, |
650 | int max_tevs __maybe_unused, const char *target) | 755 | int max_tevs __maybe_unused, |
756 | const char *target __maybe_unused) | ||
651 | { | 757 | { |
652 | if (perf_probe_event_need_dwarf(pev)) { | 758 | if (perf_probe_event_need_dwarf(pev)) { |
653 | pr_warning("Debuginfo-analysis is not supported.\n"); | 759 | pr_warning("Debuginfo-analysis is not supported.\n"); |
654 | return -ENOSYS; | 760 | return -ENOSYS; |
655 | } | 761 | } |
656 | 762 | ||
657 | if (pev->uprobes) | ||
658 | return convert_name_to_addr(pev, target); | ||
659 | |||
660 | return 0; | 763 | return 0; |
661 | } | 764 | } |
662 | 765 | ||
@@ -1278,8 +1381,7 @@ static char *synthesize_perf_probe_point(struct perf_probe_point *pp) | |||
1278 | error: | 1381 | error: |
1279 | pr_debug("Failed to synthesize perf probe point: %s\n", | 1382 | pr_debug("Failed to synthesize perf probe point: %s\n", |
1280 | strerror(-ret)); | 1383 | strerror(-ret)); |
1281 | if (buf) | 1384 | free(buf); |
1282 | free(buf); | ||
1283 | return NULL; | 1385 | return NULL; |
1284 | } | 1386 | } |
1285 | 1387 | ||
@@ -1480,34 +1582,25 @@ void clear_perf_probe_event(struct perf_probe_event *pev) | |||
1480 | struct perf_probe_arg_field *field, *next; | 1582 | struct perf_probe_arg_field *field, *next; |
1481 | int i; | 1583 | int i; |
1482 | 1584 | ||
1483 | if (pev->event) | 1585 | free(pev->event); |
1484 | free(pev->event); | 1586 | free(pev->group); |
1485 | if (pev->group) | 1587 | free(pp->file); |
1486 | free(pev->group); | 1588 | free(pp->function); |
1487 | if (pp->file) | 1589 | free(pp->lazy_line); |
1488 | free(pp->file); | 1590 | |
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++) { | 1591 | for (i = 0; i < pev->nargs; i++) { |
1494 | if (pev->args[i].name) | 1592 | free(pev->args[i].name); |
1495 | free(pev->args[i].name); | 1593 | free(pev->args[i].var); |
1496 | if (pev->args[i].var) | 1594 | 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; | 1595 | field = pev->args[i].field; |
1501 | while (field) { | 1596 | while (field) { |
1502 | next = field->next; | 1597 | next = field->next; |
1503 | if (field->name) | 1598 | zfree(&field->name); |
1504 | free(field->name); | ||
1505 | free(field); | 1599 | free(field); |
1506 | field = next; | 1600 | field = next; |
1507 | } | 1601 | } |
1508 | } | 1602 | } |
1509 | if (pev->args) | 1603 | free(pev->args); |
1510 | free(pev->args); | ||
1511 | memset(pev, 0, sizeof(*pev)); | 1604 | memset(pev, 0, sizeof(*pev)); |
1512 | } | 1605 | } |
1513 | 1606 | ||
@@ -1516,21 +1609,14 @@ static void clear_probe_trace_event(struct probe_trace_event *tev) | |||
1516 | struct probe_trace_arg_ref *ref, *next; | 1609 | struct probe_trace_arg_ref *ref, *next; |
1517 | int i; | 1610 | int i; |
1518 | 1611 | ||
1519 | if (tev->event) | 1612 | free(tev->event); |
1520 | free(tev->event); | 1613 | free(tev->group); |
1521 | if (tev->group) | 1614 | free(tev->point.symbol); |
1522 | free(tev->group); | 1615 | 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++) { | 1616 | for (i = 0; i < tev->nargs; i++) { |
1528 | if (tev->args[i].name) | 1617 | free(tev->args[i].name); |
1529 | free(tev->args[i].name); | 1618 | free(tev->args[i].value); |
1530 | if (tev->args[i].value) | 1619 | 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; | 1620 | ref = tev->args[i].ref; |
1535 | while (ref) { | 1621 | while (ref) { |
1536 | next = ref->next; | 1622 | next = ref->next; |
@@ -1538,8 +1624,7 @@ static void clear_probe_trace_event(struct probe_trace_event *tev) | |||
1538 | ref = next; | 1624 | ref = next; |
1539 | } | 1625 | } |
1540 | } | 1626 | } |
1541 | if (tev->args) | 1627 | free(tev->args); |
1542 | free(tev->args); | ||
1543 | memset(tev, 0, sizeof(*tev)); | 1628 | memset(tev, 0, sizeof(*tev)); |
1544 | } | 1629 | } |
1545 | 1630 | ||
@@ -1913,14 +1998,29 @@ static int convert_to_probe_trace_events(struct perf_probe_event *pev, | |||
1913 | int max_tevs, const char *target) | 1998 | int max_tevs, const char *target) |
1914 | { | 1999 | { |
1915 | struct symbol *sym; | 2000 | struct symbol *sym; |
1916 | int ret = 0, i; | 2001 | int ret, i; |
1917 | struct probe_trace_event *tev; | 2002 | struct probe_trace_event *tev; |
1918 | 2003 | ||
2004 | if (pev->uprobes && !pev->group) { | ||
2005 | /* Replace group name if not given */ | ||
2006 | ret = convert_exec_to_group(target, &pev->group); | ||
2007 | if (ret != 0) { | ||
2008 | pr_warning("Failed to make a group name.\n"); | ||
2009 | return ret; | ||
2010 | } | ||
2011 | } | ||
2012 | |||
1919 | /* Convert perf_probe_event with debuginfo */ | 2013 | /* Convert perf_probe_event with debuginfo */ |
1920 | ret = try_to_find_probe_trace_events(pev, tevs, max_tevs, target); | 2014 | ret = try_to_find_probe_trace_events(pev, tevs, max_tevs, target); |
1921 | if (ret != 0) | 2015 | if (ret != 0) |
1922 | return ret; /* Found in debuginfo or got an error */ | 2016 | return ret; /* Found in debuginfo or got an error */ |
1923 | 2017 | ||
2018 | if (pev->uprobes) { | ||
2019 | ret = convert_name_to_addr(pev, target); | ||
2020 | if (ret < 0) | ||
2021 | return ret; | ||
2022 | } | ||
2023 | |||
1924 | /* Allocate trace event buffer */ | 2024 | /* Allocate trace event buffer */ |
1925 | tev = *tevs = zalloc(sizeof(struct probe_trace_event)); | 2025 | tev = *tevs = zalloc(sizeof(struct probe_trace_event)); |
1926 | if (tev == NULL) | 2026 | if (tev == NULL) |
@@ -2056,7 +2156,7 @@ end: | |||
2056 | for (i = 0; i < npevs; i++) { | 2156 | for (i = 0; i < npevs; i++) { |
2057 | for (j = 0; j < pkgs[i].ntevs; j++) | 2157 | for (j = 0; j < pkgs[i].ntevs; j++) |
2058 | clear_probe_trace_event(&pkgs[i].tevs[j]); | 2158 | clear_probe_trace_event(&pkgs[i].tevs[j]); |
2059 | free(pkgs[i].tevs); | 2159 | zfree(&pkgs[i].tevs); |
2060 | } | 2160 | } |
2061 | free(pkgs); | 2161 | free(pkgs); |
2062 | 2162 | ||
@@ -2281,7 +2381,7 @@ static int convert_name_to_addr(struct perf_probe_event *pev, const char *exec) | |||
2281 | struct perf_probe_point *pp = &pev->point; | 2381 | struct perf_probe_point *pp = &pev->point; |
2282 | struct symbol *sym; | 2382 | struct symbol *sym; |
2283 | struct map *map = NULL; | 2383 | struct map *map = NULL; |
2284 | char *function = NULL, *name = NULL; | 2384 | char *function = NULL; |
2285 | int ret = -EINVAL; | 2385 | int ret = -EINVAL; |
2286 | unsigned long long vaddr = 0; | 2386 | unsigned long long vaddr = 0; |
2287 | 2387 | ||
@@ -2297,12 +2397,7 @@ static int convert_name_to_addr(struct perf_probe_event *pev, const char *exec) | |||
2297 | goto out; | 2397 | goto out; |
2298 | } | 2398 | } |
2299 | 2399 | ||
2300 | name = realpath(exec, NULL); | 2400 | 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) { | 2401 | if (!map) { |
2307 | pr_warning("Cannot find appropriate DSO for %s.\n", exec); | 2402 | pr_warning("Cannot find appropriate DSO for %s.\n", exec); |
2308 | goto out; | 2403 | goto out; |
@@ -2367,7 +2462,5 @@ out: | |||
2367 | } | 2462 | } |
2368 | if (function) | 2463 | if (function) |
2369 | free(function); | 2464 | free(function); |
2370 | if (name) | ||
2371 | free(name); | ||
2372 | return ret; | 2465 | return ret; |
2373 | } | 2466 | } |
diff --git a/tools/perf/util/probe-event.h b/tools/perf/util/probe-event.h index f9f3de8b4220..d481c46e0796 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 | ||
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..7acc03e8f3b2 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; |
@@ -1158,7 +1142,7 @@ static int __perf_session__process_pipe_events(struct perf_session *session, | |||
1158 | void *buf = NULL; | 1142 | void *buf = NULL; |
1159 | int skip = 0; | 1143 | int skip = 0; |
1160 | u64 head; | 1144 | u64 head; |
1161 | int err; | 1145 | ssize_t err; |
1162 | void *p; | 1146 | void *p; |
1163 | 1147 | ||
1164 | perf_tool__fill_defaults(tool); | 1148 | perf_tool__fill_defaults(tool); |
@@ -1400,7 +1384,7 @@ bool perf_session__has_traces(struct perf_session *session, const char *msg) | |||
1400 | { | 1384 | { |
1401 | struct perf_evsel *evsel; | 1385 | struct perf_evsel *evsel; |
1402 | 1386 | ||
1403 | list_for_each_entry(evsel, &session->evlist->entries, node) { | 1387 | evlist__for_each(session->evlist, evsel) { |
1404 | if (evsel->attr.type == PERF_TYPE_TRACEPOINT) | 1388 | if (evsel->attr.type == PERF_TYPE_TRACEPOINT) |
1405 | return true; | 1389 | return true; |
1406 | } | 1390 | } |
@@ -1458,7 +1442,7 @@ size_t perf_session__fprintf_nr_events(struct perf_session *session, FILE *fp) | |||
1458 | 1442 | ||
1459 | ret += events_stats__fprintf(&session->stats, fp); | 1443 | ret += events_stats__fprintf(&session->stats, fp); |
1460 | 1444 | ||
1461 | list_for_each_entry(pos, &session->evlist->entries, node) { | 1445 | evlist__for_each(session->evlist, pos) { |
1462 | ret += fprintf(fp, "%s stats:\n", perf_evsel__name(pos)); | 1446 | ret += fprintf(fp, "%s stats:\n", perf_evsel__name(pos)); |
1463 | ret += events_stats__fprintf(&pos->hists.stats, fp); | 1447 | ret += events_stats__fprintf(&pos->hists.stats, fp); |
1464 | } | 1448 | } |
@@ -1480,35 +1464,30 @@ struct perf_evsel *perf_session__find_first_evtype(struct perf_session *session, | |||
1480 | { | 1464 | { |
1481 | struct perf_evsel *pos; | 1465 | struct perf_evsel *pos; |
1482 | 1466 | ||
1483 | list_for_each_entry(pos, &session->evlist->entries, node) { | 1467 | evlist__for_each(session->evlist, pos) { |
1484 | if (pos->attr.type == type) | 1468 | if (pos->attr.type == type) |
1485 | return pos; | 1469 | return pos; |
1486 | } | 1470 | } |
1487 | return NULL; | 1471 | return NULL; |
1488 | } | 1472 | } |
1489 | 1473 | ||
1490 | void perf_evsel__print_ip(struct perf_evsel *evsel, union perf_event *event, | 1474 | void perf_evsel__print_ip(struct perf_evsel *evsel, struct perf_sample *sample, |
1491 | struct perf_sample *sample, struct machine *machine, | 1475 | struct addr_location *al, |
1492 | unsigned int print_opts, unsigned int stack_depth) | 1476 | unsigned int print_opts, unsigned int stack_depth) |
1493 | { | 1477 | { |
1494 | struct addr_location al; | ||
1495 | struct callchain_cursor_node *node; | 1478 | struct callchain_cursor_node *node; |
1496 | int print_ip = print_opts & PRINT_IP_OPT_IP; | 1479 | int print_ip = print_opts & PRINT_IP_OPT_IP; |
1497 | int print_sym = print_opts & PRINT_IP_OPT_SYM; | 1480 | int print_sym = print_opts & PRINT_IP_OPT_SYM; |
1498 | int print_dso = print_opts & PRINT_IP_OPT_DSO; | 1481 | int print_dso = print_opts & PRINT_IP_OPT_DSO; |
1499 | int print_symoffset = print_opts & PRINT_IP_OPT_SYMOFFSET; | 1482 | int print_symoffset = print_opts & PRINT_IP_OPT_SYMOFFSET; |
1500 | int print_oneline = print_opts & PRINT_IP_OPT_ONELINE; | 1483 | int print_oneline = print_opts & PRINT_IP_OPT_ONELINE; |
1484 | int print_srcline = print_opts & PRINT_IP_OPT_SRCLINE; | ||
1501 | char s = print_oneline ? ' ' : '\t'; | 1485 | char s = print_oneline ? ' ' : '\t'; |
1502 | 1486 | ||
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) { | 1487 | if (symbol_conf.use_callchain && sample->callchain) { |
1488 | struct addr_location node_al; | ||
1510 | 1489 | ||
1511 | if (machine__resolve_callchain(machine, evsel, al.thread, | 1490 | if (machine__resolve_callchain(al->machine, evsel, al->thread, |
1512 | sample, NULL, NULL, | 1491 | sample, NULL, NULL, |
1513 | PERF_MAX_STACK_DEPTH) != 0) { | 1492 | PERF_MAX_STACK_DEPTH) != 0) { |
1514 | if (verbose) | 1493 | if (verbose) |
@@ -1517,20 +1496,31 @@ void perf_evsel__print_ip(struct perf_evsel *evsel, union perf_event *event, | |||
1517 | } | 1496 | } |
1518 | callchain_cursor_commit(&callchain_cursor); | 1497 | callchain_cursor_commit(&callchain_cursor); |
1519 | 1498 | ||
1499 | if (print_symoffset) | ||
1500 | node_al = *al; | ||
1501 | |||
1520 | while (stack_depth) { | 1502 | while (stack_depth) { |
1503 | u64 addr = 0; | ||
1504 | |||
1521 | node = callchain_cursor_current(&callchain_cursor); | 1505 | node = callchain_cursor_current(&callchain_cursor); |
1522 | if (!node) | 1506 | if (!node) |
1523 | break; | 1507 | break; |
1524 | 1508 | ||
1509 | if (node->sym && node->sym->ignore) | ||
1510 | goto next; | ||
1511 | |||
1525 | if (print_ip) | 1512 | if (print_ip) |
1526 | printf("%c%16" PRIx64, s, node->ip); | 1513 | printf("%c%16" PRIx64, s, node->ip); |
1527 | 1514 | ||
1515 | if (node->map) | ||
1516 | addr = node->map->map_ip(node->map, node->ip); | ||
1517 | |||
1528 | if (print_sym) { | 1518 | if (print_sym) { |
1529 | printf(" "); | 1519 | printf(" "); |
1530 | if (print_symoffset) { | 1520 | if (print_symoffset) { |
1531 | al.addr = node->ip; | 1521 | node_al.addr = addr; |
1532 | al.map = node->map; | 1522 | node_al.map = node->map; |
1533 | symbol__fprintf_symname_offs(node->sym, &al, stdout); | 1523 | symbol__fprintf_symname_offs(node->sym, &node_al, stdout); |
1534 | } else | 1524 | } else |
1535 | symbol__fprintf_symname(node->sym, stdout); | 1525 | symbol__fprintf_symname(node->sym, stdout); |
1536 | } | 1526 | } |
@@ -1541,32 +1531,42 @@ void perf_evsel__print_ip(struct perf_evsel *evsel, union perf_event *event, | |||
1541 | printf(")"); | 1531 | printf(")"); |
1542 | } | 1532 | } |
1543 | 1533 | ||
1534 | if (print_srcline) | ||
1535 | map__fprintf_srcline(node->map, addr, "\n ", | ||
1536 | stdout); | ||
1537 | |||
1544 | if (!print_oneline) | 1538 | if (!print_oneline) |
1545 | printf("\n"); | 1539 | printf("\n"); |
1546 | 1540 | ||
1547 | callchain_cursor_advance(&callchain_cursor); | ||
1548 | |||
1549 | stack_depth--; | 1541 | stack_depth--; |
1542 | next: | ||
1543 | callchain_cursor_advance(&callchain_cursor); | ||
1550 | } | 1544 | } |
1551 | 1545 | ||
1552 | } else { | 1546 | } else { |
1547 | if (al->sym && al->sym->ignore) | ||
1548 | return; | ||
1549 | |||
1553 | if (print_ip) | 1550 | if (print_ip) |
1554 | printf("%16" PRIx64, sample->ip); | 1551 | printf("%16" PRIx64, sample->ip); |
1555 | 1552 | ||
1556 | if (print_sym) { | 1553 | if (print_sym) { |
1557 | printf(" "); | 1554 | printf(" "); |
1558 | if (print_symoffset) | 1555 | if (print_symoffset) |
1559 | symbol__fprintf_symname_offs(al.sym, &al, | 1556 | symbol__fprintf_symname_offs(al->sym, al, |
1560 | stdout); | 1557 | stdout); |
1561 | else | 1558 | else |
1562 | symbol__fprintf_symname(al.sym, stdout); | 1559 | symbol__fprintf_symname(al->sym, stdout); |
1563 | } | 1560 | } |
1564 | 1561 | ||
1565 | if (print_dso) { | 1562 | if (print_dso) { |
1566 | printf(" ("); | 1563 | printf(" ("); |
1567 | map__fprintf_dsoname(al.map, stdout); | 1564 | map__fprintf_dsoname(al->map, stdout); |
1568 | printf(")"); | 1565 | printf(")"); |
1569 | } | 1566 | } |
1567 | |||
1568 | if (print_srcline) | ||
1569 | map__fprintf_srcline(al->map, al->addr, "\n ", stdout); | ||
1570 | } | 1570 | } |
1571 | } | 1571 | } |
1572 | 1572 | ||
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..7e67879ebd25 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((void **)&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((void **)&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..61a90bf24b4d 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((void **)&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..4b0a127a4d3b 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 |
@@ -553,7 +554,7 @@ bool symsrc__has_symtab(struct symsrc *ss) | |||
553 | 554 | ||
554 | void symsrc__destroy(struct symsrc *ss) | 555 | void symsrc__destroy(struct symsrc *ss) |
555 | { | 556 | { |
556 | free(ss->name); | 557 | zfree(&ss->name); |
557 | elf_end(ss->elf); | 558 | elf_end(ss->elf); |
558 | close(ss->fd); | 559 | close(ss->fd); |
559 | } | 560 | } |
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..39ce9adbaaf0 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; | ||
530 | |||
531 | for (i = 0; idle_symbols[i]; i++) { | ||
532 | if (!strcmp(idle_symbols[i], sym->name)) | ||
533 | return true; | ||
534 | } | ||
572 | 535 | ||
573 | return isupper(type) ? STB_GLOBAL : STB_LOCAL; | 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, |
@@ -833,7 +796,7 @@ static void delete_modules(struct rb_root *modules) | |||
833 | mi = rb_entry(next, struct module_info, rb_node); | 796 | mi = rb_entry(next, struct module_info, rb_node); |
834 | next = rb_next(&mi->rb_node); | 797 | next = rb_next(&mi->rb_node); |
835 | rb_erase(&mi->rb_node, modules); | 798 | rb_erase(&mi->rb_node, modules); |
836 | free(mi->name); | 799 | zfree(&mi->name); |
837 | free(mi); | 800 | free(mi); |
838 | } | 801 | } |
839 | } | 802 | } |
@@ -1126,10 +1089,10 @@ static int dso__load_kcore(struct dso *dso, struct map *map, | |||
1126 | * dso__data_read_addr(). | 1089 | * dso__data_read_addr(). |
1127 | */ | 1090 | */ |
1128 | if (dso->kernel == DSO_TYPE_GUEST_KERNEL) | 1091 | if (dso->kernel == DSO_TYPE_GUEST_KERNEL) |
1129 | dso->data_type = DSO_BINARY_TYPE__GUEST_KCORE; | 1092 | dso->binary_type = DSO_BINARY_TYPE__GUEST_KCORE; |
1130 | else | 1093 | else |
1131 | dso->data_type = DSO_BINARY_TYPE__KCORE; | 1094 | dso->binary_type = DSO_BINARY_TYPE__KCORE; |
1132 | dso__set_long_name(dso, strdup(kcore_filename)); | 1095 | dso__set_long_name(dso, strdup(kcore_filename), true); |
1133 | 1096 | ||
1134 | close(fd); | 1097 | close(fd); |
1135 | 1098 | ||
@@ -1295,8 +1258,8 @@ int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter) | |||
1295 | 1258 | ||
1296 | enum dso_binary_type symtab_type = binary_type_symtab[i]; | 1259 | enum dso_binary_type symtab_type = binary_type_symtab[i]; |
1297 | 1260 | ||
1298 | if (dso__binary_type_file(dso, symtab_type, | 1261 | if (dso__read_binary_type_filename(dso, symtab_type, |
1299 | root_dir, name, PATH_MAX)) | 1262 | root_dir, name, PATH_MAX)) |
1300 | continue; | 1263 | continue; |
1301 | 1264 | ||
1302 | /* Name is now the name of the next image to try */ | 1265 | /* Name is now the name of the next image to try */ |
@@ -1306,6 +1269,8 @@ int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter) | |||
1306 | if (!syms_ss && symsrc__has_symtab(ss)) { | 1269 | if (!syms_ss && symsrc__has_symtab(ss)) { |
1307 | syms_ss = ss; | 1270 | syms_ss = ss; |
1308 | next_slot = true; | 1271 | next_slot = true; |
1272 | if (!dso->symsrc_filename) | ||
1273 | dso->symsrc_filename = strdup(name); | ||
1309 | } | 1274 | } |
1310 | 1275 | ||
1311 | if (!runtime_ss && symsrc__possibly_runtime(ss)) { | 1276 | if (!runtime_ss && symsrc__possibly_runtime(ss)) { |
@@ -1376,7 +1341,8 @@ struct map *map_groups__find_by_name(struct map_groups *mg, | |||
1376 | } | 1341 | } |
1377 | 1342 | ||
1378 | int dso__load_vmlinux(struct dso *dso, struct map *map, | 1343 | int dso__load_vmlinux(struct dso *dso, struct map *map, |
1379 | const char *vmlinux, symbol_filter_t filter) | 1344 | const char *vmlinux, bool vmlinux_allocated, |
1345 | symbol_filter_t filter) | ||
1380 | { | 1346 | { |
1381 | int err = -1; | 1347 | int err = -1; |
1382 | struct symsrc ss; | 1348 | struct symsrc ss; |
@@ -1402,10 +1368,10 @@ int dso__load_vmlinux(struct dso *dso, struct map *map, | |||
1402 | 1368 | ||
1403 | if (err > 0) { | 1369 | if (err > 0) { |
1404 | if (dso->kernel == DSO_TYPE_GUEST_KERNEL) | 1370 | if (dso->kernel == DSO_TYPE_GUEST_KERNEL) |
1405 | dso->data_type = DSO_BINARY_TYPE__GUEST_VMLINUX; | 1371 | dso->binary_type = DSO_BINARY_TYPE__GUEST_VMLINUX; |
1406 | else | 1372 | else |
1407 | dso->data_type = DSO_BINARY_TYPE__VMLINUX; | 1373 | dso->binary_type = DSO_BINARY_TYPE__VMLINUX; |
1408 | dso__set_long_name(dso, (char *)vmlinux); | 1374 | dso__set_long_name(dso, vmlinux, vmlinux_allocated); |
1409 | dso__set_loaded(dso, map->type); | 1375 | dso__set_loaded(dso, map->type); |
1410 | pr_debug("Using %s for symbols\n", symfs_vmlinux); | 1376 | pr_debug("Using %s for symbols\n", symfs_vmlinux); |
1411 | } | 1377 | } |
@@ -1424,21 +1390,16 @@ int dso__load_vmlinux_path(struct dso *dso, struct map *map, | |||
1424 | 1390 | ||
1425 | filename = dso__build_id_filename(dso, NULL, 0); | 1391 | filename = dso__build_id_filename(dso, NULL, 0); |
1426 | if (filename != NULL) { | 1392 | if (filename != NULL) { |
1427 | err = dso__load_vmlinux(dso, map, filename, filter); | 1393 | err = dso__load_vmlinux(dso, map, filename, true, filter); |
1428 | if (err > 0) { | 1394 | if (err > 0) |
1429 | dso->lname_alloc = 1; | ||
1430 | goto out; | 1395 | goto out; |
1431 | } | ||
1432 | free(filename); | 1396 | free(filename); |
1433 | } | 1397 | } |
1434 | 1398 | ||
1435 | for (i = 0; i < vmlinux_path__nr_entries; ++i) { | 1399 | for (i = 0; i < vmlinux_path__nr_entries; ++i) { |
1436 | err = dso__load_vmlinux(dso, map, vmlinux_path[i], filter); | 1400 | err = dso__load_vmlinux(dso, map, vmlinux_path[i], false, filter); |
1437 | if (err > 0) { | 1401 | if (err > 0) |
1438 | dso__set_long_name(dso, strdup(vmlinux_path[i])); | ||
1439 | dso->lname_alloc = 1; | ||
1440 | break; | 1402 | break; |
1441 | } | ||
1442 | } | 1403 | } |
1443 | out: | 1404 | out: |
1444 | return err; | 1405 | return err; |
@@ -1496,14 +1457,15 @@ static char *dso__find_kallsyms(struct dso *dso, struct map *map) | |||
1496 | 1457 | ||
1497 | build_id__sprintf(dso->build_id, sizeof(dso->build_id), sbuild_id); | 1458 | build_id__sprintf(dso->build_id, sizeof(dso->build_id), sbuild_id); |
1498 | 1459 | ||
1460 | scnprintf(path, sizeof(path), "%s/[kernel.kcore]/%s", buildid_dir, | ||
1461 | sbuild_id); | ||
1462 | |||
1499 | /* Use /proc/kallsyms if possible */ | 1463 | /* Use /proc/kallsyms if possible */ |
1500 | if (is_host) { | 1464 | if (is_host) { |
1501 | DIR *d; | 1465 | DIR *d; |
1502 | int fd; | 1466 | int fd; |
1503 | 1467 | ||
1504 | /* If no cached kcore go with /proc/kallsyms */ | 1468 | /* 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); | 1469 | d = opendir(path); |
1508 | if (!d) | 1470 | if (!d) |
1509 | goto proc_kallsyms; | 1471 | goto proc_kallsyms; |
@@ -1528,6 +1490,10 @@ static char *dso__find_kallsyms(struct dso *dso, struct map *map) | |||
1528 | goto proc_kallsyms; | 1490 | goto proc_kallsyms; |
1529 | } | 1491 | } |
1530 | 1492 | ||
1493 | /* Find kallsyms in build-id cache with kcore */ | ||
1494 | if (!find_matching_kcore(map, path, sizeof(path))) | ||
1495 | return strdup(path); | ||
1496 | |||
1531 | scnprintf(path, sizeof(path), "%s/[kernel.kallsyms]/%s", | 1497 | scnprintf(path, sizeof(path), "%s/[kernel.kallsyms]/%s", |
1532 | buildid_dir, sbuild_id); | 1498 | buildid_dir, sbuild_id); |
1533 | 1499 | ||
@@ -1570,15 +1536,8 @@ static int dso__load_kernel_sym(struct dso *dso, struct map *map, | |||
1570 | } | 1536 | } |
1571 | 1537 | ||
1572 | if (!symbol_conf.ignore_vmlinux && symbol_conf.vmlinux_name != NULL) { | 1538 | if (!symbol_conf.ignore_vmlinux && symbol_conf.vmlinux_name != NULL) { |
1573 | err = dso__load_vmlinux(dso, map, | 1539 | return dso__load_vmlinux(dso, map, symbol_conf.vmlinux_name, |
1574 | symbol_conf.vmlinux_name, filter); | 1540 | 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 | } | 1541 | } |
1583 | 1542 | ||
1584 | if (!symbol_conf.ignore_vmlinux && vmlinux_path != NULL) { | 1543 | if (!symbol_conf.ignore_vmlinux && vmlinux_path != NULL) { |
@@ -1604,7 +1563,7 @@ do_kallsyms: | |||
1604 | free(kallsyms_allocated_filename); | 1563 | free(kallsyms_allocated_filename); |
1605 | 1564 | ||
1606 | if (err > 0 && !dso__is_kcore(dso)) { | 1565 | if (err > 0 && !dso__is_kcore(dso)) { |
1607 | dso__set_long_name(dso, strdup("[kernel.kallsyms]")); | 1566 | dso__set_long_name(dso, "[kernel.kallsyms]", false); |
1608 | map__fixup_start(map); | 1567 | map__fixup_start(map); |
1609 | map__fixup_end(map); | 1568 | map__fixup_end(map); |
1610 | } | 1569 | } |
@@ -1634,7 +1593,8 @@ static int dso__load_guest_kernel_sym(struct dso *dso, struct map *map, | |||
1634 | */ | 1593 | */ |
1635 | if (symbol_conf.default_guest_vmlinux_name != NULL) { | 1594 | if (symbol_conf.default_guest_vmlinux_name != NULL) { |
1636 | err = dso__load_vmlinux(dso, map, | 1595 | err = dso__load_vmlinux(dso, map, |
1637 | symbol_conf.default_guest_vmlinux_name, filter); | 1596 | symbol_conf.default_guest_vmlinux_name, |
1597 | false, filter); | ||
1638 | return err; | 1598 | return err; |
1639 | } | 1599 | } |
1640 | 1600 | ||
@@ -1651,7 +1611,7 @@ static int dso__load_guest_kernel_sym(struct dso *dso, struct map *map, | |||
1651 | pr_debug("Using %s for symbols\n", kallsyms_filename); | 1611 | pr_debug("Using %s for symbols\n", kallsyms_filename); |
1652 | if (err > 0 && !dso__is_kcore(dso)) { | 1612 | if (err > 0 && !dso__is_kcore(dso)) { |
1653 | machine__mmap_name(machine, path, sizeof(path)); | 1613 | machine__mmap_name(machine, path, sizeof(path)); |
1654 | dso__set_long_name(dso, strdup(path)); | 1614 | dso__set_long_name(dso, strdup(path), true); |
1655 | map__fixup_start(map); | 1615 | map__fixup_start(map); |
1656 | map__fixup_end(map); | 1616 | map__fixup_end(map); |
1657 | } | 1617 | } |
@@ -1661,13 +1621,10 @@ static int dso__load_guest_kernel_sym(struct dso *dso, struct map *map, | |||
1661 | 1621 | ||
1662 | static void vmlinux_path__exit(void) | 1622 | static void vmlinux_path__exit(void) |
1663 | { | 1623 | { |
1664 | while (--vmlinux_path__nr_entries >= 0) { | 1624 | while (--vmlinux_path__nr_entries >= 0) |
1665 | free(vmlinux_path[vmlinux_path__nr_entries]); | 1625 | zfree(&vmlinux_path[vmlinux_path__nr_entries]); |
1666 | vmlinux_path[vmlinux_path__nr_entries] = NULL; | ||
1667 | } | ||
1668 | 1626 | ||
1669 | free(vmlinux_path); | 1627 | zfree(&vmlinux_path); |
1670 | vmlinux_path = NULL; | ||
1671 | } | 1628 | } |
1672 | 1629 | ||
1673 | static int vmlinux_path__init(void) | 1630 | static int vmlinux_path__init(void) |
@@ -1719,7 +1676,7 @@ out_fail: | |||
1719 | return -1; | 1676 | return -1; |
1720 | } | 1677 | } |
1721 | 1678 | ||
1722 | static int setup_list(struct strlist **list, const char *list_str, | 1679 | int setup_list(struct strlist **list, const char *list_str, |
1723 | const char *list_name) | 1680 | const char *list_name) |
1724 | { | 1681 | { |
1725 | if (list_str == NULL) | 1682 | if (list_str == NULL) |
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h index 07de8fea2f48..cbd680361806 100644 --- a/tools/perf/util/symbol.h +++ b/tools/perf/util/symbol.h | |||
@@ -164,6 +164,7 @@ struct mem_info { | |||
164 | }; | 164 | }; |
165 | 165 | ||
166 | struct addr_location { | 166 | struct addr_location { |
167 | struct machine *machine; | ||
167 | struct thread *thread; | 168 | struct thread *thread; |
168 | struct map *map; | 169 | struct map *map; |
169 | struct symbol *sym; | 170 | struct symbol *sym; |
@@ -206,7 +207,8 @@ bool symsrc__possibly_runtime(struct symsrc *ss); | |||
206 | 207 | ||
207 | int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter); | 208 | int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter); |
208 | int dso__load_vmlinux(struct dso *dso, struct map *map, | 209 | int dso__load_vmlinux(struct dso *dso, struct map *map, |
209 | const char *vmlinux, symbol_filter_t filter); | 210 | const char *vmlinux, bool vmlinux_allocated, |
211 | symbol_filter_t filter); | ||
210 | int dso__load_vmlinux_path(struct dso *dso, struct map *map, | 212 | int dso__load_vmlinux_path(struct dso *dso, struct map *map, |
211 | symbol_filter_t filter); | 213 | symbol_filter_t filter); |
212 | int dso__load_kallsyms(struct dso *dso, const char *filename, struct map *map, | 214 | int dso__load_kallsyms(struct dso *dso, const char *filename, struct map *map, |
@@ -220,9 +222,6 @@ struct symbol *dso__first_symbol(struct dso *dso, enum map_type type); | |||
220 | 222 | ||
221 | int filename__read_build_id(const char *filename, void *bf, size_t size); | 223 | 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); | 224 | 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, | 225 | int modules__parse(const char *filename, void *arg, |
227 | int (*process_module)(void *arg, const char *name, | 226 | int (*process_module)(void *arg, const char *name, |
228 | u64 start)); | 227 | u64 start)); |
@@ -240,6 +239,7 @@ size_t symbol__fprintf(struct symbol *sym, FILE *fp); | |||
240 | bool symbol_type__is_a(char symbol_type, enum map_type map_type); | 239 | bool symbol_type__is_a(char symbol_type, enum map_type map_type); |
241 | bool symbol__restricted_filename(const char *filename, | 240 | bool symbol__restricted_filename(const char *filename, |
242 | const char *restricted_filename); | 241 | const char *restricted_filename); |
242 | bool symbol__is_idle(struct symbol *sym); | ||
243 | 243 | ||
244 | int dso__load_sym(struct dso *dso, struct map *map, struct symsrc *syms_ss, | 244 | int dso__load_sym(struct dso *dso, struct map *map, struct symsrc *syms_ss, |
245 | struct symsrc *runtime_ss, symbol_filter_t filter, | 245 | struct symsrc *runtime_ss, symbol_filter_t filter, |
@@ -273,4 +273,7 @@ void kcore_extract__delete(struct kcore_extract *kce); | |||
273 | int kcore_copy(const char *from_dir, const char *to_dir); | 273 | int kcore_copy(const char *from_dir, const char *to_dir); |
274 | int compare_proc_modules(const char *from, const char *to); | 274 | int compare_proc_modules(const char *from, const char *to); |
275 | 275 | ||
276 | int setup_list(struct strlist **list, const char *list_str, | ||
277 | const char *list_name); | ||
278 | |||
276 | #endif /* __PERF_SYMBOL */ | 279 | #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..e3948612543e 100644 --- a/tools/perf/util/thread.c +++ b/tools/perf/util/thread.c | |||
@@ -126,7 +126,7 @@ int thread__fork(struct thread *thread, struct thread *parent, u64 timestamp) | |||
126 | if (!comm) | 126 | if (!comm) |
127 | return -ENOMEM; | 127 | return -ENOMEM; |
128 | err = thread__set_comm(thread, comm, timestamp); | 128 | err = thread__set_comm(thread, comm, timestamp); |
129 | if (!err) | 129 | if (err) |
130 | return err; | 130 | return err; |
131 | thread->comm_set = true; | 131 | thread->comm_set = true; |
132 | } | 132 | } |
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..d9f5f6137ab3 --- /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 | pevent_free(t->pevent); | ||
38 | traceevent_unload_plugins(t->plugin_list); | ||
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..416f22bf3693 100644 --- a/tools/perf/util/unwind.c +++ b/tools/perf/util/unwind.c | |||
@@ -340,10 +340,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 */ | 340 | /* Check the .debug_frame section for unwinding info */ |
341 | if (!read_unwind_spec_debug_frame(map->dso, ui->machine, &segbase)) { | 341 | if (!read_unwind_spec_debug_frame(map->dso, ui->machine, &segbase)) { |
342 | memset(&di, 0, sizeof(di)); | 342 | memset(&di, 0, sizeof(di)); |
343 | dwarf_find_debug_frame(0, &di, ip, 0, map->dso->name, | 343 | if (dwarf_find_debug_frame(0, &di, ip, 0, map->dso->name, |
344 | map->start, map->end); | 344 | map->start, map->end)) |
345 | return dwarf_search_unwind_table(as, ip, &di, pi, | 345 | return dwarf_search_unwind_table(as, ip, &di, pi, |
346 | need_unwind_info, arg); | 346 | need_unwind_info, arg); |
347 | } | 347 | } |
348 | #endif | 348 | #endif |
349 | 349 | ||
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/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/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 |