diff options
author | Ingo Molnar <mingo@kernel.org> | 2013-07-19 03:35:30 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@kernel.org> | 2013-07-19 03:35:30 -0400 |
commit | 5a9821321e0a61674fd5c4b5a9e95007d0e7e052 (patch) | |
tree | 6138bbc657a866f4373f774501c7698338f9354b /tools | |
parent | e43fff2b98b4e99b189c086a9cf740b19eaf3538 (diff) | |
parent | 2a08c3ec4f7d6058a450d2d4bc6e366955872707 (diff) |
Merge tag 'perf-core-for-mingo' of git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux into perf/core
Pull perf/core improvements and fixes from Arnaldo Carvalho de Melo:
* Add missing 'finished_round' event forwarding in 'perf inject', from Adrian Hunter.
* Assorted tidy ups, from Adrian Hunter.
* Fall back to sysfs event names when parsing fails, from Andi Kleen.
* List pmu events in perf list, from Andi Kleen.
* Cleanup some memory allocation/freeing uses, from David Ahern.
* Add option to collapse undesired parts of call graph, from Greg Price.
* Prep work for multi perf data file storage, from Jiri Olsa.
* Add support for more than two files comparision in 'perf diff', from Jiri Olsa
* A few more 'perf test' improvements, from Jiri Olsa
* libtraceevent cleanups, from Namhyung Kim.
* Remove odd build stall in 'perf sched' by moving a large struct initialization
from a local variable to a global one, from Namhyung Kim.
* Add support for callchains in the gtk UI, from Namhyung Kim.
* Do not apply symfs for an absolute vmlinux path, fix from Namhyung Kim.
* Use default include path notation for libtraceevent, from Robert Richter.
* Fix 'make tools/perf', from Robert Richter.
* Make Power7 events available, from Runzhen Wang.
* Add --objdump option to 'perf top', from Sukadev Bhattiprolu.
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Diffstat (limited to 'tools')
65 files changed, 2366 insertions, 1090 deletions
diff --git a/tools/lib/traceevent/Makefile b/tools/lib/traceevent/Makefile index 0b0a90787db6..0794acca46a3 100644 --- a/tools/lib/traceevent/Makefile +++ b/tools/lib/traceevent/Makefile | |||
@@ -39,13 +39,8 @@ bindir_relative = bin | |||
39 | bindir = $(prefix)/$(bindir_relative) | 39 | bindir = $(prefix)/$(bindir_relative) |
40 | man_dir = $(prefix)/share/man | 40 | man_dir = $(prefix)/share/man |
41 | man_dir_SQ = '$(subst ','\'',$(man_dir))' | 41 | man_dir_SQ = '$(subst ','\'',$(man_dir))' |
42 | html_install = $(prefix)/share/kernelshark/html | ||
43 | html_install_SQ = '$(subst ','\'',$(html_install))' | ||
44 | img_install = $(prefix)/share/kernelshark/html/images | ||
45 | img_install_SQ = '$(subst ','\'',$(img_install))' | ||
46 | 42 | ||
47 | export man_dir man_dir_SQ html_install html_install_SQ INSTALL | 43 | export man_dir man_dir_SQ INSTALL |
48 | export img_install img_install_SQ | ||
49 | export DESTDIR DESTDIR_SQ | 44 | export DESTDIR DESTDIR_SQ |
50 | 45 | ||
51 | # copy a bit from Linux kbuild | 46 | # copy a bit from Linux kbuild |
@@ -76,10 +71,7 @@ $(if $(BUILD_OUTPUT),, \ | |||
76 | 71 | ||
77 | all: sub-make | 72 | all: sub-make |
78 | 73 | ||
79 | gui: force | 74 | $(MAKECMDGOALS): sub-make |
80 | $(call build_output, all_cmd) | ||
81 | |||
82 | $(filter-out gui,$(MAKECMDGOALS)): sub-make | ||
83 | 75 | ||
84 | sub-make: force | 76 | sub-make: force |
85 | $(call build_output, $(MAKECMDGOALS)) | 77 | $(call build_output, $(MAKECMDGOALS)) |
@@ -189,6 +181,7 @@ $(obj)/%.o: $(src)/%.c | |||
189 | $(Q)$(call do_compile) | 181 | $(Q)$(call do_compile) |
190 | 182 | ||
191 | PEVENT_LIB_OBJS = event-parse.o trace-seq.o parse-filter.o parse-utils.o | 183 | PEVENT_LIB_OBJS = event-parse.o trace-seq.o parse-filter.o parse-utils.o |
184 | PEVENT_LIB_OBJS += kbuffer-parse.o | ||
192 | 185 | ||
193 | ALL_OBJS = $(PEVENT_LIB_OBJS) | 186 | ALL_OBJS = $(PEVENT_LIB_OBJS) |
194 | 187 | ||
@@ -258,9 +251,6 @@ define check_deps | |||
258 | $(RM) $@.$$$$ | 251 | $(RM) $@.$$$$ |
259 | endef | 252 | endef |
260 | 253 | ||
261 | $(gui_deps): ks_version.h | ||
262 | $(non_gui_deps): tc_version.h | ||
263 | |||
264 | $(all_deps): .%.d: $(src)/%.c | 254 | $(all_deps): .%.d: $(src)/%.c |
265 | $(Q)$(call check_deps) | 255 | $(Q)$(call check_deps) |
266 | 256 | ||
@@ -300,7 +290,7 @@ define do_install | |||
300 | $(INSTALL) $1 '$(DESTDIR_SQ)$2' | 290 | $(INSTALL) $1 '$(DESTDIR_SQ)$2' |
301 | endef | 291 | endef |
302 | 292 | ||
303 | install_lib: all_cmd install_plugins install_python | 293 | install_lib: all_cmd |
304 | $(Q)$(call do_install,$(LIB_FILE),$(bindir_SQ)) | 294 | $(Q)$(call do_install,$(LIB_FILE),$(bindir_SQ)) |
305 | 295 | ||
306 | install: install_lib | 296 | install: install_lib |
diff --git a/tools/lib/traceevent/event-parse.c b/tools/lib/traceevent/event-parse.c index 82b0606dcb8a..d1c2a6a4cd32 100644 --- a/tools/lib/traceevent/event-parse.c +++ b/tools/lib/traceevent/event-parse.c | |||
@@ -5450,10 +5450,9 @@ int pevent_register_print_function(struct pevent *pevent, | |||
5450 | * If @id is >= 0, then it is used to find the event. | 5450 | * If @id is >= 0, then it is used to find the event. |
5451 | * else @sys_name and @event_name are used. | 5451 | * else @sys_name and @event_name are used. |
5452 | */ | 5452 | */ |
5453 | int pevent_register_event_handler(struct pevent *pevent, | 5453 | int pevent_register_event_handler(struct pevent *pevent, int id, |
5454 | int id, char *sys_name, char *event_name, | 5454 | const char *sys_name, const char *event_name, |
5455 | pevent_event_handler_func func, | 5455 | pevent_event_handler_func func, void *context) |
5456 | void *context) | ||
5457 | { | 5456 | { |
5458 | struct event_format *event; | 5457 | struct event_format *event; |
5459 | struct event_handler *handle; | 5458 | struct event_handler *handle; |
diff --git a/tools/lib/traceevent/event-parse.h b/tools/lib/traceevent/event-parse.h index 7be7e89533e4..c37b2026d04a 100644 --- a/tools/lib/traceevent/event-parse.h +++ b/tools/lib/traceevent/event-parse.h | |||
@@ -69,6 +69,7 @@ struct trace_seq { | |||
69 | }; | 69 | }; |
70 | 70 | ||
71 | void trace_seq_init(struct trace_seq *s); | 71 | void trace_seq_init(struct trace_seq *s); |
72 | void trace_seq_reset(struct trace_seq *s); | ||
72 | void trace_seq_destroy(struct trace_seq *s); | 73 | void trace_seq_destroy(struct trace_seq *s); |
73 | 74 | ||
74 | extern int trace_seq_printf(struct trace_seq *s, const char *fmt, ...) | 75 | extern int trace_seq_printf(struct trace_seq *s, const char *fmt, ...) |
@@ -399,6 +400,7 @@ struct pevent { | |||
399 | 400 | ||
400 | int cpus; | 401 | int cpus; |
401 | int long_size; | 402 | int long_size; |
403 | int page_size; | ||
402 | 404 | ||
403 | struct cmdline *cmdlines; | 405 | struct cmdline *cmdlines; |
404 | struct cmdline_list *cmdlist; | 406 | struct cmdline_list *cmdlist; |
@@ -561,7 +563,8 @@ int pevent_print_num_field(struct trace_seq *s, const char *fmt, | |||
561 | struct event_format *event, const char *name, | 563 | struct event_format *event, const char *name, |
562 | struct pevent_record *record, int err); | 564 | struct pevent_record *record, int err); |
563 | 565 | ||
564 | int pevent_register_event_handler(struct pevent *pevent, int id, char *sys_name, char *event_name, | 566 | int pevent_register_event_handler(struct pevent *pevent, int id, |
567 | const char *sys_name, const char *event_name, | ||
565 | pevent_event_handler_func func, void *context); | 568 | pevent_event_handler_func func, void *context); |
566 | int pevent_register_print_function(struct pevent *pevent, | 569 | int pevent_register_print_function(struct pevent *pevent, |
567 | pevent_func_handler func, | 570 | pevent_func_handler func, |
@@ -619,6 +622,16 @@ static inline void pevent_set_long_size(struct pevent *pevent, int long_size) | |||
619 | pevent->long_size = long_size; | 622 | pevent->long_size = long_size; |
620 | } | 623 | } |
621 | 624 | ||
625 | static inline int pevent_get_page_size(struct pevent *pevent) | ||
626 | { | ||
627 | return pevent->page_size; | ||
628 | } | ||
629 | |||
630 | static inline void pevent_set_page_size(struct pevent *pevent, int _page_size) | ||
631 | { | ||
632 | pevent->page_size = _page_size; | ||
633 | } | ||
634 | |||
622 | static inline int pevent_is_file_bigendian(struct pevent *pevent) | 635 | static inline int pevent_is_file_bigendian(struct pevent *pevent) |
623 | { | 636 | { |
624 | return pevent->file_bigendian; | 637 | return pevent->file_bigendian; |
diff --git a/tools/lib/traceevent/kbuffer-parse.c b/tools/lib/traceevent/kbuffer-parse.c new file mode 100644 index 000000000000..dcc665228c71 --- /dev/null +++ b/tools/lib/traceevent/kbuffer-parse.c | |||
@@ -0,0 +1,732 @@ | |||
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, write to the Free Software | ||
17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||
18 | * | ||
19 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
20 | */ | ||
21 | #include <stdio.h> | ||
22 | #include <stdlib.h> | ||
23 | #include <string.h> | ||
24 | |||
25 | #include "kbuffer.h" | ||
26 | |||
27 | #define MISSING_EVENTS (1 << 31) | ||
28 | #define MISSING_STORED (1 << 30) | ||
29 | |||
30 | #define COMMIT_MASK ((1 << 27) - 1) | ||
31 | |||
32 | enum { | ||
33 | KBUFFER_FL_HOST_BIG_ENDIAN = (1<<0), | ||
34 | KBUFFER_FL_BIG_ENDIAN = (1<<1), | ||
35 | KBUFFER_FL_LONG_8 = (1<<2), | ||
36 | KBUFFER_FL_OLD_FORMAT = (1<<3), | ||
37 | }; | ||
38 | |||
39 | #define ENDIAN_MASK (KBUFFER_FL_HOST_BIG_ENDIAN | KBUFFER_FL_BIG_ENDIAN) | ||
40 | |||
41 | /** kbuffer | ||
42 | * @timestamp - timestamp of current event | ||
43 | * @lost_events - # of lost events between this subbuffer and previous | ||
44 | * @flags - special flags of the kbuffer | ||
45 | * @subbuffer - pointer to the sub-buffer page | ||
46 | * @data - pointer to the start of data on the sub-buffer page | ||
47 | * @index - index from @data to the @curr event data | ||
48 | * @curr - offset from @data to the start of current event | ||
49 | * (includes metadata) | ||
50 | * @next - offset from @data to the start of next event | ||
51 | * @size - The size of data on @data | ||
52 | * @start - The offset from @subbuffer where @data lives | ||
53 | * | ||
54 | * @read_4 - Function to read 4 raw bytes (may swap) | ||
55 | * @read_8 - Function to read 8 raw bytes (may swap) | ||
56 | * @read_long - Function to read a long word (4 or 8 bytes with needed swap) | ||
57 | */ | ||
58 | struct kbuffer { | ||
59 | unsigned long long timestamp; | ||
60 | long long lost_events; | ||
61 | unsigned long flags; | ||
62 | void *subbuffer; | ||
63 | void *data; | ||
64 | unsigned int index; | ||
65 | unsigned int curr; | ||
66 | unsigned int next; | ||
67 | unsigned int size; | ||
68 | unsigned int start; | ||
69 | |||
70 | unsigned int (*read_4)(void *ptr); | ||
71 | unsigned long long (*read_8)(void *ptr); | ||
72 | unsigned long long (*read_long)(struct kbuffer *kbuf, void *ptr); | ||
73 | int (*next_event)(struct kbuffer *kbuf); | ||
74 | }; | ||
75 | |||
76 | static void *zmalloc(size_t size) | ||
77 | { | ||
78 | return calloc(1, size); | ||
79 | } | ||
80 | |||
81 | static int host_is_bigendian(void) | ||
82 | { | ||
83 | unsigned char str[] = { 0x1, 0x2, 0x3, 0x4 }; | ||
84 | unsigned int *ptr; | ||
85 | |||
86 | ptr = (unsigned int *)str; | ||
87 | return *ptr == 0x01020304; | ||
88 | } | ||
89 | |||
90 | static int do_swap(struct kbuffer *kbuf) | ||
91 | { | ||
92 | return ((kbuf->flags & KBUFFER_FL_HOST_BIG_ENDIAN) + kbuf->flags) & | ||
93 | ENDIAN_MASK; | ||
94 | } | ||
95 | |||
96 | static unsigned long long __read_8(void *ptr) | ||
97 | { | ||
98 | unsigned long long data = *(unsigned long long *)ptr; | ||
99 | |||
100 | return data; | ||
101 | } | ||
102 | |||
103 | static unsigned long long __read_8_sw(void *ptr) | ||
104 | { | ||
105 | unsigned long long data = *(unsigned long long *)ptr; | ||
106 | unsigned long long swap; | ||
107 | |||
108 | swap = ((data & 0xffULL) << 56) | | ||
109 | ((data & (0xffULL << 8)) << 40) | | ||
110 | ((data & (0xffULL << 16)) << 24) | | ||
111 | ((data & (0xffULL << 24)) << 8) | | ||
112 | ((data & (0xffULL << 32)) >> 8) | | ||
113 | ((data & (0xffULL << 40)) >> 24) | | ||
114 | ((data & (0xffULL << 48)) >> 40) | | ||
115 | ((data & (0xffULL << 56)) >> 56); | ||
116 | |||
117 | return swap; | ||
118 | } | ||
119 | |||
120 | static unsigned int __read_4(void *ptr) | ||
121 | { | ||
122 | unsigned int data = *(unsigned int *)ptr; | ||
123 | |||
124 | return data; | ||
125 | } | ||
126 | |||
127 | static unsigned int __read_4_sw(void *ptr) | ||
128 | { | ||
129 | unsigned int data = *(unsigned int *)ptr; | ||
130 | unsigned int swap; | ||
131 | |||
132 | swap = ((data & 0xffULL) << 24) | | ||
133 | ((data & (0xffULL << 8)) << 8) | | ||
134 | ((data & (0xffULL << 16)) >> 8) | | ||
135 | ((data & (0xffULL << 24)) >> 24); | ||
136 | |||
137 | return swap; | ||
138 | } | ||
139 | |||
140 | static unsigned long long read_8(struct kbuffer *kbuf, void *ptr) | ||
141 | { | ||
142 | return kbuf->read_8(ptr); | ||
143 | } | ||
144 | |||
145 | static unsigned int read_4(struct kbuffer *kbuf, void *ptr) | ||
146 | { | ||
147 | return kbuf->read_4(ptr); | ||
148 | } | ||
149 | |||
150 | static unsigned long long __read_long_8(struct kbuffer *kbuf, void *ptr) | ||
151 | { | ||
152 | return kbuf->read_8(ptr); | ||
153 | } | ||
154 | |||
155 | static unsigned long long __read_long_4(struct kbuffer *kbuf, void *ptr) | ||
156 | { | ||
157 | return kbuf->read_4(ptr); | ||
158 | } | ||
159 | |||
160 | static unsigned long long read_long(struct kbuffer *kbuf, void *ptr) | ||
161 | { | ||
162 | return kbuf->read_long(kbuf, ptr); | ||
163 | } | ||
164 | |||
165 | static int calc_index(struct kbuffer *kbuf, void *ptr) | ||
166 | { | ||
167 | return (unsigned long)ptr - (unsigned long)kbuf->data; | ||
168 | } | ||
169 | |||
170 | static int __next_event(struct kbuffer *kbuf); | ||
171 | |||
172 | /** | ||
173 | * kbuffer_alloc - allocat a new kbuffer | ||
174 | * @size; enum to denote size of word | ||
175 | * @endian: enum to denote endianness | ||
176 | * | ||
177 | * Allocates and returns a new kbuffer. | ||
178 | */ | ||
179 | struct kbuffer * | ||
180 | kbuffer_alloc(enum kbuffer_long_size size, enum kbuffer_endian endian) | ||
181 | { | ||
182 | struct kbuffer *kbuf; | ||
183 | int flags = 0; | ||
184 | |||
185 | switch (size) { | ||
186 | case KBUFFER_LSIZE_4: | ||
187 | break; | ||
188 | case KBUFFER_LSIZE_8: | ||
189 | flags |= KBUFFER_FL_LONG_8; | ||
190 | break; | ||
191 | default: | ||
192 | return NULL; | ||
193 | } | ||
194 | |||
195 | switch (endian) { | ||
196 | case KBUFFER_ENDIAN_LITTLE: | ||
197 | break; | ||
198 | case KBUFFER_ENDIAN_BIG: | ||
199 | flags |= KBUFFER_FL_BIG_ENDIAN; | ||
200 | break; | ||
201 | default: | ||
202 | return NULL; | ||
203 | } | ||
204 | |||
205 | kbuf = zmalloc(sizeof(*kbuf)); | ||
206 | if (!kbuf) | ||
207 | return NULL; | ||
208 | |||
209 | kbuf->flags = flags; | ||
210 | |||
211 | if (host_is_bigendian()) | ||
212 | kbuf->flags |= KBUFFER_FL_HOST_BIG_ENDIAN; | ||
213 | |||
214 | if (do_swap(kbuf)) { | ||
215 | kbuf->read_8 = __read_8_sw; | ||
216 | kbuf->read_4 = __read_4_sw; | ||
217 | } else { | ||
218 | kbuf->read_8 = __read_8; | ||
219 | kbuf->read_4 = __read_4; | ||
220 | } | ||
221 | |||
222 | if (kbuf->flags & KBUFFER_FL_LONG_8) | ||
223 | kbuf->read_long = __read_long_8; | ||
224 | else | ||
225 | kbuf->read_long = __read_long_4; | ||
226 | |||
227 | /* May be changed by kbuffer_set_old_format() */ | ||
228 | kbuf->next_event = __next_event; | ||
229 | |||
230 | return kbuf; | ||
231 | } | ||
232 | |||
233 | /** kbuffer_free - free an allocated kbuffer | ||
234 | * @kbuf: The kbuffer to free | ||
235 | * | ||
236 | * Can take NULL as a parameter. | ||
237 | */ | ||
238 | void kbuffer_free(struct kbuffer *kbuf) | ||
239 | { | ||
240 | free(kbuf); | ||
241 | } | ||
242 | |||
243 | static unsigned int type4host(struct kbuffer *kbuf, | ||
244 | unsigned int type_len_ts) | ||
245 | { | ||
246 | if (kbuf->flags & KBUFFER_FL_BIG_ENDIAN) | ||
247 | return (type_len_ts >> 29) & 3; | ||
248 | else | ||
249 | return type_len_ts & 3; | ||
250 | } | ||
251 | |||
252 | static unsigned int len4host(struct kbuffer *kbuf, | ||
253 | unsigned int type_len_ts) | ||
254 | { | ||
255 | if (kbuf->flags & KBUFFER_FL_BIG_ENDIAN) | ||
256 | return (type_len_ts >> 27) & 7; | ||
257 | else | ||
258 | return (type_len_ts >> 2) & 7; | ||
259 | } | ||
260 | |||
261 | static unsigned int type_len4host(struct kbuffer *kbuf, | ||
262 | unsigned int type_len_ts) | ||
263 | { | ||
264 | if (kbuf->flags & KBUFFER_FL_BIG_ENDIAN) | ||
265 | return (type_len_ts >> 27) & ((1 << 5) - 1); | ||
266 | else | ||
267 | return type_len_ts & ((1 << 5) - 1); | ||
268 | } | ||
269 | |||
270 | static unsigned int ts4host(struct kbuffer *kbuf, | ||
271 | unsigned int type_len_ts) | ||
272 | { | ||
273 | if (kbuf->flags & KBUFFER_FL_BIG_ENDIAN) | ||
274 | return type_len_ts & ((1 << 27) - 1); | ||
275 | else | ||
276 | return type_len_ts >> 5; | ||
277 | } | ||
278 | |||
279 | /* | ||
280 | * Linux 2.6.30 and earlier (not much ealier) had a different | ||
281 | * ring buffer format. It should be obsolete, but we handle it anyway. | ||
282 | */ | ||
283 | enum old_ring_buffer_type { | ||
284 | OLD_RINGBUF_TYPE_PADDING, | ||
285 | OLD_RINGBUF_TYPE_TIME_EXTEND, | ||
286 | OLD_RINGBUF_TYPE_TIME_STAMP, | ||
287 | OLD_RINGBUF_TYPE_DATA, | ||
288 | }; | ||
289 | |||
290 | static unsigned int old_update_pointers(struct kbuffer *kbuf) | ||
291 | { | ||
292 | unsigned long long extend; | ||
293 | unsigned int type_len_ts; | ||
294 | unsigned int type; | ||
295 | unsigned int len; | ||
296 | unsigned int delta; | ||
297 | unsigned int length; | ||
298 | void *ptr = kbuf->data + kbuf->curr; | ||
299 | |||
300 | type_len_ts = read_4(kbuf, ptr); | ||
301 | ptr += 4; | ||
302 | |||
303 | type = type4host(kbuf, type_len_ts); | ||
304 | len = len4host(kbuf, type_len_ts); | ||
305 | delta = ts4host(kbuf, type_len_ts); | ||
306 | |||
307 | switch (type) { | ||
308 | case OLD_RINGBUF_TYPE_PADDING: | ||
309 | kbuf->next = kbuf->size; | ||
310 | return 0; | ||
311 | |||
312 | case OLD_RINGBUF_TYPE_TIME_EXTEND: | ||
313 | extend = read_4(kbuf, ptr); | ||
314 | extend <<= TS_SHIFT; | ||
315 | extend += delta; | ||
316 | delta = extend; | ||
317 | ptr += 4; | ||
318 | break; | ||
319 | |||
320 | case OLD_RINGBUF_TYPE_TIME_STAMP: | ||
321 | /* should never happen! */ | ||
322 | kbuf->curr = kbuf->size; | ||
323 | kbuf->next = kbuf->size; | ||
324 | kbuf->index = kbuf->size; | ||
325 | return -1; | ||
326 | default: | ||
327 | if (len) | ||
328 | length = len * 4; | ||
329 | else { | ||
330 | length = read_4(kbuf, ptr); | ||
331 | length -= 4; | ||
332 | ptr += 4; | ||
333 | } | ||
334 | break; | ||
335 | } | ||
336 | |||
337 | kbuf->timestamp += delta; | ||
338 | kbuf->index = calc_index(kbuf, ptr); | ||
339 | kbuf->next = kbuf->index + length; | ||
340 | |||
341 | return type; | ||
342 | } | ||
343 | |||
344 | static int __old_next_event(struct kbuffer *kbuf) | ||
345 | { | ||
346 | int type; | ||
347 | |||
348 | do { | ||
349 | kbuf->curr = kbuf->next; | ||
350 | if (kbuf->next >= kbuf->size) | ||
351 | return -1; | ||
352 | type = old_update_pointers(kbuf); | ||
353 | } while (type == OLD_RINGBUF_TYPE_TIME_EXTEND || type == OLD_RINGBUF_TYPE_PADDING); | ||
354 | |||
355 | return 0; | ||
356 | } | ||
357 | |||
358 | static unsigned int | ||
359 | translate_data(struct kbuffer *kbuf, void *data, void **rptr, | ||
360 | unsigned long long *delta, int *length) | ||
361 | { | ||
362 | unsigned long long extend; | ||
363 | unsigned int type_len_ts; | ||
364 | unsigned int type_len; | ||
365 | |||
366 | type_len_ts = read_4(kbuf, data); | ||
367 | data += 4; | ||
368 | |||
369 | type_len = type_len4host(kbuf, type_len_ts); | ||
370 | *delta = ts4host(kbuf, type_len_ts); | ||
371 | |||
372 | switch (type_len) { | ||
373 | case KBUFFER_TYPE_PADDING: | ||
374 | *length = read_4(kbuf, data); | ||
375 | data += *length; | ||
376 | break; | ||
377 | |||
378 | case KBUFFER_TYPE_TIME_EXTEND: | ||
379 | extend = read_4(kbuf, data); | ||
380 | data += 4; | ||
381 | extend <<= TS_SHIFT; | ||
382 | extend += *delta; | ||
383 | *delta = extend; | ||
384 | *length = 0; | ||
385 | break; | ||
386 | |||
387 | case KBUFFER_TYPE_TIME_STAMP: | ||
388 | data += 12; | ||
389 | *length = 0; | ||
390 | break; | ||
391 | case 0: | ||
392 | *length = read_4(kbuf, data) - 4; | ||
393 | *length = (*length + 3) & ~3; | ||
394 | data += 4; | ||
395 | break; | ||
396 | default: | ||
397 | *length = type_len * 4; | ||
398 | break; | ||
399 | } | ||
400 | |||
401 | *rptr = data; | ||
402 | |||
403 | return type_len; | ||
404 | } | ||
405 | |||
406 | static unsigned int update_pointers(struct kbuffer *kbuf) | ||
407 | { | ||
408 | unsigned long long delta; | ||
409 | unsigned int type_len; | ||
410 | int length; | ||
411 | void *ptr = kbuf->data + kbuf->curr; | ||
412 | |||
413 | type_len = translate_data(kbuf, ptr, &ptr, &delta, &length); | ||
414 | |||
415 | kbuf->timestamp += delta; | ||
416 | kbuf->index = calc_index(kbuf, ptr); | ||
417 | kbuf->next = kbuf->index + length; | ||
418 | |||
419 | return type_len; | ||
420 | } | ||
421 | |||
422 | /** | ||
423 | * kbuffer_translate_data - read raw data to get a record | ||
424 | * @swap: Set to 1 if bytes in words need to be swapped when read | ||
425 | * @data: The raw data to read | ||
426 | * @size: Address to store the size of the event data. | ||
427 | * | ||
428 | * Returns a pointer to the event data. To determine the entire | ||
429 | * record size (record metadata + data) just add the difference between | ||
430 | * @data and the returned value to @size. | ||
431 | */ | ||
432 | void *kbuffer_translate_data(int swap, void *data, unsigned int *size) | ||
433 | { | ||
434 | unsigned long long delta; | ||
435 | struct kbuffer kbuf; | ||
436 | int type_len; | ||
437 | int length; | ||
438 | void *ptr; | ||
439 | |||
440 | if (swap) { | ||
441 | kbuf.read_8 = __read_8_sw; | ||
442 | kbuf.read_4 = __read_4_sw; | ||
443 | kbuf.flags = host_is_bigendian() ? 0 : KBUFFER_FL_BIG_ENDIAN; | ||
444 | } else { | ||
445 | kbuf.read_8 = __read_8; | ||
446 | kbuf.read_4 = __read_4; | ||
447 | kbuf.flags = host_is_bigendian() ? KBUFFER_FL_BIG_ENDIAN: 0; | ||
448 | } | ||
449 | |||
450 | type_len = translate_data(&kbuf, data, &ptr, &delta, &length); | ||
451 | switch (type_len) { | ||
452 | case KBUFFER_TYPE_PADDING: | ||
453 | case KBUFFER_TYPE_TIME_EXTEND: | ||
454 | case KBUFFER_TYPE_TIME_STAMP: | ||
455 | return NULL; | ||
456 | }; | ||
457 | |||
458 | *size = length; | ||
459 | |||
460 | return ptr; | ||
461 | } | ||
462 | |||
463 | static int __next_event(struct kbuffer *kbuf) | ||
464 | { | ||
465 | int type; | ||
466 | |||
467 | do { | ||
468 | kbuf->curr = kbuf->next; | ||
469 | if (kbuf->next >= kbuf->size) | ||
470 | return -1; | ||
471 | type = update_pointers(kbuf); | ||
472 | } while (type == KBUFFER_TYPE_TIME_EXTEND || type == KBUFFER_TYPE_PADDING); | ||
473 | |||
474 | return 0; | ||
475 | } | ||
476 | |||
477 | static int next_event(struct kbuffer *kbuf) | ||
478 | { | ||
479 | return kbuf->next_event(kbuf); | ||
480 | } | ||
481 | |||
482 | /** | ||
483 | * kbuffer_next_event - increment the current pointer | ||
484 | * @kbuf: The kbuffer to read | ||
485 | * @ts: Address to store the next record's timestamp (may be NULL to ignore) | ||
486 | * | ||
487 | * Increments the pointers into the subbuffer of the kbuffer to point to the | ||
488 | * next event so that the next kbuffer_read_event() will return a | ||
489 | * new event. | ||
490 | * | ||
491 | * Returns the data of the next event if a new event exists on the subbuffer, | ||
492 | * NULL otherwise. | ||
493 | */ | ||
494 | void *kbuffer_next_event(struct kbuffer *kbuf, unsigned long long *ts) | ||
495 | { | ||
496 | int ret; | ||
497 | |||
498 | if (!kbuf || !kbuf->subbuffer) | ||
499 | return NULL; | ||
500 | |||
501 | ret = next_event(kbuf); | ||
502 | if (ret < 0) | ||
503 | return NULL; | ||
504 | |||
505 | if (ts) | ||
506 | *ts = kbuf->timestamp; | ||
507 | |||
508 | return kbuf->data + kbuf->index; | ||
509 | } | ||
510 | |||
511 | /** | ||
512 | * kbuffer_load_subbuffer - load a new subbuffer into the kbuffer | ||
513 | * @kbuf: The kbuffer to load | ||
514 | * @subbuffer: The subbuffer to load into @kbuf. | ||
515 | * | ||
516 | * Load a new subbuffer (page) into @kbuf. This will reset all | ||
517 | * the pointers and update the @kbuf timestamp. The next read will | ||
518 | * return the first event on @subbuffer. | ||
519 | * | ||
520 | * Returns 0 on succes, -1 otherwise. | ||
521 | */ | ||
522 | int kbuffer_load_subbuffer(struct kbuffer *kbuf, void *subbuffer) | ||
523 | { | ||
524 | unsigned long long flags; | ||
525 | void *ptr = subbuffer; | ||
526 | |||
527 | if (!kbuf || !subbuffer) | ||
528 | return -1; | ||
529 | |||
530 | kbuf->subbuffer = subbuffer; | ||
531 | |||
532 | kbuf->timestamp = read_8(kbuf, ptr); | ||
533 | ptr += 8; | ||
534 | |||
535 | kbuf->curr = 0; | ||
536 | |||
537 | if (kbuf->flags & KBUFFER_FL_LONG_8) | ||
538 | kbuf->start = 16; | ||
539 | else | ||
540 | kbuf->start = 12; | ||
541 | |||
542 | kbuf->data = subbuffer + kbuf->start; | ||
543 | |||
544 | flags = read_long(kbuf, ptr); | ||
545 | kbuf->size = (unsigned int)flags & COMMIT_MASK; | ||
546 | |||
547 | if (flags & MISSING_EVENTS) { | ||
548 | if (flags & MISSING_STORED) { | ||
549 | ptr = kbuf->data + kbuf->size; | ||
550 | kbuf->lost_events = read_long(kbuf, ptr); | ||
551 | } else | ||
552 | kbuf->lost_events = -1; | ||
553 | } else | ||
554 | kbuf->lost_events = 0; | ||
555 | |||
556 | kbuf->index = 0; | ||
557 | kbuf->next = 0; | ||
558 | |||
559 | next_event(kbuf); | ||
560 | |||
561 | return 0; | ||
562 | } | ||
563 | |||
564 | /** | ||
565 | * kbuffer_read_event - read the next event in the kbuffer subbuffer | ||
566 | * @kbuf: The kbuffer to read from | ||
567 | * @ts: The address to store the timestamp of the event (may be NULL to ignore) | ||
568 | * | ||
569 | * Returns a pointer to the data part of the current event. | ||
570 | * NULL if no event is left on the subbuffer. | ||
571 | */ | ||
572 | void *kbuffer_read_event(struct kbuffer *kbuf, unsigned long long *ts) | ||
573 | { | ||
574 | if (!kbuf || !kbuf->subbuffer) | ||
575 | return NULL; | ||
576 | |||
577 | if (kbuf->curr >= kbuf->size) | ||
578 | return NULL; | ||
579 | |||
580 | if (ts) | ||
581 | *ts = kbuf->timestamp; | ||
582 | return kbuf->data + kbuf->index; | ||
583 | } | ||
584 | |||
585 | /** | ||
586 | * kbuffer_timestamp - Return the timestamp of the current event | ||
587 | * @kbuf: The kbuffer to read from | ||
588 | * | ||
589 | * Returns the timestamp of the current (next) event. | ||
590 | */ | ||
591 | unsigned long long kbuffer_timestamp(struct kbuffer *kbuf) | ||
592 | { | ||
593 | return kbuf->timestamp; | ||
594 | } | ||
595 | |||
596 | /** | ||
597 | * kbuffer_read_at_offset - read the event that is at offset | ||
598 | * @kbuf: The kbuffer to read from | ||
599 | * @offset: The offset into the subbuffer | ||
600 | * @ts: The address to store the timestamp of the event (may be NULL to ignore) | ||
601 | * | ||
602 | * The @offset must be an index from the @kbuf subbuffer beginning. | ||
603 | * If @offset is bigger than the stored subbuffer, NULL will be returned. | ||
604 | * | ||
605 | * Returns the data of the record that is at @offset. Note, @offset does | ||
606 | * not need to be the start of the record, the offset just needs to be | ||
607 | * in the record (or beginning of it). | ||
608 | * | ||
609 | * Note, the kbuf timestamp and pointers are updated to the | ||
610 | * returned record. That is, kbuffer_read_event() will return the same | ||
611 | * data and timestamp, and kbuffer_next_event() will increment from | ||
612 | * this record. | ||
613 | */ | ||
614 | void *kbuffer_read_at_offset(struct kbuffer *kbuf, int offset, | ||
615 | unsigned long long *ts) | ||
616 | { | ||
617 | void *data; | ||
618 | |||
619 | if (offset < kbuf->start) | ||
620 | offset = 0; | ||
621 | else | ||
622 | offset -= kbuf->start; | ||
623 | |||
624 | /* Reset the buffer */ | ||
625 | kbuffer_load_subbuffer(kbuf, kbuf->subbuffer); | ||
626 | |||
627 | while (kbuf->curr < offset) { | ||
628 | data = kbuffer_next_event(kbuf, ts); | ||
629 | if (!data) | ||
630 | break; | ||
631 | } | ||
632 | |||
633 | return data; | ||
634 | } | ||
635 | |||
636 | /** | ||
637 | * kbuffer_subbuffer_size - the size of the loaded subbuffer | ||
638 | * @kbuf: The kbuffer to read from | ||
639 | * | ||
640 | * Returns the size of the subbuffer. Note, this size is | ||
641 | * where the last event resides. The stored subbuffer may actually be | ||
642 | * bigger due to padding and such. | ||
643 | */ | ||
644 | int kbuffer_subbuffer_size(struct kbuffer *kbuf) | ||
645 | { | ||
646 | return kbuf->size; | ||
647 | } | ||
648 | |||
649 | /** | ||
650 | * kbuffer_curr_index - Return the index of the record | ||
651 | * @kbuf: The kbuffer to read from | ||
652 | * | ||
653 | * Returns the index from the start of the data part of | ||
654 | * the subbuffer to the current location. Note this is not | ||
655 | * from the start of the subbuffer. An index of zero will | ||
656 | * point to the first record. Use kbuffer_curr_offset() for | ||
657 | * the actually offset (that can be used by kbuffer_read_at_offset()) | ||
658 | */ | ||
659 | int kbuffer_curr_index(struct kbuffer *kbuf) | ||
660 | { | ||
661 | return kbuf->curr; | ||
662 | } | ||
663 | |||
664 | /** | ||
665 | * kbuffer_curr_offset - Return the offset of the record | ||
666 | * @kbuf: The kbuffer to read from | ||
667 | * | ||
668 | * Returns the offset from the start of the subbuffer to the | ||
669 | * current location. | ||
670 | */ | ||
671 | int kbuffer_curr_offset(struct kbuffer *kbuf) | ||
672 | { | ||
673 | return kbuf->curr + kbuf->start; | ||
674 | } | ||
675 | |||
676 | /** | ||
677 | * kbuffer_event_size - return the size of the event data | ||
678 | * @kbuf: The kbuffer to read | ||
679 | * | ||
680 | * Returns the size of the event data (the payload not counting | ||
681 | * the meta data of the record) of the current event. | ||
682 | */ | ||
683 | int kbuffer_event_size(struct kbuffer *kbuf) | ||
684 | { | ||
685 | return kbuf->next - kbuf->index; | ||
686 | } | ||
687 | |||
688 | /** | ||
689 | * kbuffer_curr_size - return the size of the entire record | ||
690 | * @kbuf: The kbuffer to read | ||
691 | * | ||
692 | * Returns the size of the entire record (meta data and payload) | ||
693 | * of the current event. | ||
694 | */ | ||
695 | int kbuffer_curr_size(struct kbuffer *kbuf) | ||
696 | { | ||
697 | return kbuf->next - kbuf->curr; | ||
698 | } | ||
699 | |||
700 | /** | ||
701 | * kbuffer_missed_events - return the # of missed events from last event. | ||
702 | * @kbuf: The kbuffer to read from | ||
703 | * | ||
704 | * Returns the # of missed events (if recorded) before the current | ||
705 | * event. Note, only events on the beginning of a subbuffer can | ||
706 | * have missed events, all other events within the buffer will be | ||
707 | * zero. | ||
708 | */ | ||
709 | int kbuffer_missed_events(struct kbuffer *kbuf) | ||
710 | { | ||
711 | /* Only the first event can have missed events */ | ||
712 | if (kbuf->curr) | ||
713 | return 0; | ||
714 | |||
715 | return kbuf->lost_events; | ||
716 | } | ||
717 | |||
718 | /** | ||
719 | * kbuffer_set_old_forma - set the kbuffer to use the old format parsing | ||
720 | * @kbuf: The kbuffer to set | ||
721 | * | ||
722 | * This is obsolete (or should be). The first kernels to use the | ||
723 | * new ring buffer had a slightly different ring buffer format | ||
724 | * (2.6.30 and earlier). It is still somewhat supported by kbuffer, | ||
725 | * but should not be counted on in the future. | ||
726 | */ | ||
727 | void kbuffer_set_old_format(struct kbuffer *kbuf) | ||
728 | { | ||
729 | kbuf->flags |= KBUFFER_FL_OLD_FORMAT; | ||
730 | |||
731 | kbuf->next_event = __old_next_event; | ||
732 | } | ||
diff --git a/tools/lib/traceevent/kbuffer.h b/tools/lib/traceevent/kbuffer.h new file mode 100644 index 000000000000..c831f64b17a0 --- /dev/null +++ b/tools/lib/traceevent/kbuffer.h | |||
@@ -0,0 +1,67 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2012 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, write to the Free Software | ||
17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||
18 | * | ||
19 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
20 | */ | ||
21 | #ifndef _KBUFFER_H | ||
22 | #define _KBUFFER_H | ||
23 | |||
24 | #ifndef TS_SHIFT | ||
25 | #define TS_SHIFT 27 | ||
26 | #endif | ||
27 | |||
28 | enum kbuffer_endian { | ||
29 | KBUFFER_ENDIAN_BIG, | ||
30 | KBUFFER_ENDIAN_LITTLE, | ||
31 | }; | ||
32 | |||
33 | enum kbuffer_long_size { | ||
34 | KBUFFER_LSIZE_4, | ||
35 | KBUFFER_LSIZE_8, | ||
36 | }; | ||
37 | |||
38 | enum { | ||
39 | KBUFFER_TYPE_PADDING = 29, | ||
40 | KBUFFER_TYPE_TIME_EXTEND = 30, | ||
41 | KBUFFER_TYPE_TIME_STAMP = 31, | ||
42 | }; | ||
43 | |||
44 | struct kbuffer; | ||
45 | |||
46 | struct kbuffer *kbuffer_alloc(enum kbuffer_long_size size, enum kbuffer_endian endian); | ||
47 | void kbuffer_free(struct kbuffer *kbuf); | ||
48 | int kbuffer_load_subbuffer(struct kbuffer *kbuf, void *subbuffer); | ||
49 | void *kbuffer_read_event(struct kbuffer *kbuf, unsigned long long *ts); | ||
50 | void *kbuffer_next_event(struct kbuffer *kbuf, unsigned long long *ts); | ||
51 | unsigned long long kbuffer_timestamp(struct kbuffer *kbuf); | ||
52 | |||
53 | void *kbuffer_translate_data(int swap, void *data, unsigned int *size); | ||
54 | |||
55 | void *kbuffer_read_at_offset(struct kbuffer *kbuf, int offset, unsigned long long *ts); | ||
56 | |||
57 | int kbuffer_curr_index(struct kbuffer *kbuf); | ||
58 | |||
59 | int kbuffer_curr_offset(struct kbuffer *kbuf); | ||
60 | int kbuffer_curr_size(struct kbuffer *kbuf); | ||
61 | int kbuffer_event_size(struct kbuffer *kbuf); | ||
62 | int kbuffer_missed_events(struct kbuffer *kbuf); | ||
63 | int kbuffer_subbuffer_size(struct kbuffer *kbuf); | ||
64 | |||
65 | void kbuffer_set_old_format(struct kbuffer *kbuf); | ||
66 | |||
67 | #endif /* _K_BUFFER_H */ | ||
diff --git a/tools/lib/traceevent/trace-seq.c b/tools/lib/traceevent/trace-seq.c index a57db805136a..d7f2e68bc5b9 100644 --- a/tools/lib/traceevent/trace-seq.c +++ b/tools/lib/traceevent/trace-seq.c | |||
@@ -49,6 +49,19 @@ void trace_seq_init(struct trace_seq *s) | |||
49 | } | 49 | } |
50 | 50 | ||
51 | /** | 51 | /** |
52 | * trace_seq_reset - re-initialize the trace_seq structure | ||
53 | * @s: a pointer to the trace_seq structure to reset | ||
54 | */ | ||
55 | void trace_seq_reset(struct trace_seq *s) | ||
56 | { | ||
57 | if (!s) | ||
58 | return; | ||
59 | TRACE_SEQ_CHECK(s); | ||
60 | s->len = 0; | ||
61 | s->readpos = 0; | ||
62 | } | ||
63 | |||
64 | /** | ||
52 | * trace_seq_destroy - free up memory of a trace_seq | 65 | * trace_seq_destroy - free up memory of a trace_seq |
53 | * @s: a pointer to the trace_seq to free the buffer | 66 | * @s: a pointer to the trace_seq to free the buffer |
54 | * | 67 | * |
diff --git a/tools/perf/Documentation/perf-diff.txt b/tools/perf/Documentation/perf-diff.txt index 5b3123d5721f..fdfceee0ffd0 100644 --- a/tools/perf/Documentation/perf-diff.txt +++ b/tools/perf/Documentation/perf-diff.txt | |||
@@ -3,17 +3,17 @@ perf-diff(1) | |||
3 | 3 | ||
4 | NAME | 4 | NAME |
5 | ---- | 5 | ---- |
6 | perf-diff - Read two perf.data files and display the differential profile | 6 | perf-diff - Read perf.data files and display the differential profile |
7 | 7 | ||
8 | SYNOPSIS | 8 | SYNOPSIS |
9 | -------- | 9 | -------- |
10 | [verse] | 10 | [verse] |
11 | 'perf diff' [oldfile] [newfile] | 11 | 'perf diff' [baseline file] [data file1] [[data file2] ... ] |
12 | 12 | ||
13 | DESCRIPTION | 13 | DESCRIPTION |
14 | ----------- | 14 | ----------- |
15 | This command displays the performance difference amongst two perf.data files | 15 | This command displays the performance difference amongst two or more perf.data |
16 | captured via perf record. | 16 | files captured via perf record. |
17 | 17 | ||
18 | If no parameters are passed it will assume perf.data.old and perf.data. | 18 | If no parameters are passed it will assume perf.data.old and perf.data. |
19 | 19 | ||
@@ -75,8 +75,6 @@ OPTIONS | |||
75 | -c:: | 75 | -c:: |
76 | --compute:: | 76 | --compute:: |
77 | Differential computation selection - delta,ratio,wdiff (default is delta). | 77 | Differential computation selection - delta,ratio,wdiff (default is delta). |
78 | If '+' is specified as a first character, the output is sorted based | ||
79 | on the computation results. | ||
80 | See COMPARISON METHODS section for more info. | 78 | See COMPARISON METHODS section for more info. |
81 | 79 | ||
82 | -p:: | 80 | -p:: |
@@ -87,6 +85,63 @@ OPTIONS | |||
87 | --formula:: | 85 | --formula:: |
88 | Show formula for given computation. | 86 | Show formula for given computation. |
89 | 87 | ||
88 | -o:: | ||
89 | --order:: | ||
90 | Specify compute sorting column number. | ||
91 | |||
92 | COMPARISON | ||
93 | ---------- | ||
94 | The comparison is governed by the baseline file. The baseline perf.data | ||
95 | file is iterated for samples. All other perf.data files specified on | ||
96 | the command line are searched for the baseline sample pair. If the pair | ||
97 | is found, specified computation is made and result is displayed. | ||
98 | |||
99 | All samples from non-baseline perf.data files, that do not match any | ||
100 | baseline entry, are displayed with empty space within baseline column | ||
101 | and possible computation results (delta) in their related column. | ||
102 | |||
103 | Example files samples: | ||
104 | - file A with samples f1, f2, f3, f4, f6 | ||
105 | - file B with samples f2, f4, f5 | ||
106 | - file C with samples f1, f2, f5 | ||
107 | |||
108 | Example output: | ||
109 | x - computation takes place for pair | ||
110 | b - baseline sample percentage | ||
111 | |||
112 | - perf diff A B C | ||
113 | |||
114 | baseline/A compute/B compute/C samples | ||
115 | --------------------------------------- | ||
116 | b x f1 | ||
117 | b x x f2 | ||
118 | b f3 | ||
119 | b x f4 | ||
120 | b f6 | ||
121 | x x f5 | ||
122 | |||
123 | - perf diff B A C | ||
124 | |||
125 | baseline/B compute/A compute/C samples | ||
126 | --------------------------------------- | ||
127 | b x x f2 | ||
128 | b x f4 | ||
129 | b x f5 | ||
130 | x x f1 | ||
131 | x f3 | ||
132 | x f6 | ||
133 | |||
134 | - perf diff C B A | ||
135 | |||
136 | baseline/C compute/B compute/A samples | ||
137 | --------------------------------------- | ||
138 | b x f1 | ||
139 | b x x f2 | ||
140 | b x f5 | ||
141 | x f3 | ||
142 | x x f4 | ||
143 | x f6 | ||
144 | |||
90 | COMPARISON METHODS | 145 | COMPARISON METHODS |
91 | ------------------ | 146 | ------------------ |
92 | delta | 147 | delta |
@@ -96,7 +151,7 @@ If specified the 'Delta' column is displayed with value 'd' computed as: | |||
96 | d = A->period_percent - B->period_percent | 151 | d = A->period_percent - B->period_percent |
97 | 152 | ||
98 | with: | 153 | with: |
99 | - A/B being matching hist entry from first/second file specified | 154 | - A/B being matching hist entry from data/baseline file specified |
100 | (or perf.data/perf.data.old) respectively. | 155 | (or perf.data/perf.data.old) respectively. |
101 | 156 | ||
102 | - period_percent being the % of the hist entry period value within | 157 | - period_percent being the % of the hist entry period value within |
@@ -109,24 +164,26 @@ If specified the 'Ratio' column is displayed with value 'r' computed as: | |||
109 | r = A->period / B->period | 164 | r = A->period / B->period |
110 | 165 | ||
111 | with: | 166 | with: |
112 | - A/B being matching hist entry from first/second file specified | 167 | - A/B being matching hist entry from data/baseline file specified |
113 | (or perf.data/perf.data.old) respectively. | 168 | (or perf.data/perf.data.old) respectively. |
114 | 169 | ||
115 | - period being the hist entry period value | 170 | - period being the hist entry period value |
116 | 171 | ||
117 | wdiff | 172 | wdiff:WEIGHT-B,WEIGHT-A |
118 | ~~~~~ | 173 | ~~~~~~~~~~~~~~~~~~~~~~~ |
119 | If specified the 'Weighted diff' column is displayed with value 'd' computed as: | 174 | If specified the 'Weighted diff' column is displayed with value 'd' computed as: |
120 | 175 | ||
121 | d = B->period * WEIGHT-A - A->period * WEIGHT-B | 176 | d = B->period * WEIGHT-A - A->period * WEIGHT-B |
122 | 177 | ||
123 | - A/B being matching hist entry from first/second file specified | 178 | - A/B being matching hist entry from data/baseline file specified |
124 | (or perf.data/perf.data.old) respectively. | 179 | (or perf.data/perf.data.old) respectively. |
125 | 180 | ||
126 | - period being the hist entry period value | 181 | - period being the hist entry period value |
127 | 182 | ||
128 | - WEIGHT-A/WEIGHT-B being user suplied weights in the the '-c' option | 183 | - WEIGHT-A/WEIGHT-B being user suplied weights in the the '-c' option |
129 | behind ':' separator like '-c wdiff:1,2'. | 184 | behind ':' separator like '-c wdiff:1,2'. |
185 | - WIEGHT-A being the weight of the data file | ||
186 | - WIEGHT-B being the weight of the baseline data file | ||
130 | 187 | ||
131 | SEE ALSO | 188 | SEE ALSO |
132 | -------- | 189 | -------- |
diff --git a/tools/perf/Documentation/perf-list.txt b/tools/perf/Documentation/perf-list.txt index d1e39dc8c810..826f3d6d1d28 100644 --- a/tools/perf/Documentation/perf-list.txt +++ b/tools/perf/Documentation/perf-list.txt | |||
@@ -8,7 +8,7 @@ perf-list - List all symbolic event types | |||
8 | SYNOPSIS | 8 | SYNOPSIS |
9 | -------- | 9 | -------- |
10 | [verse] | 10 | [verse] |
11 | 'perf list' [hw|sw|cache|tracepoint|event_glob] | 11 | 'perf list' [hw|sw|cache|tracepoint|pmu|event_glob] |
12 | 12 | ||
13 | DESCRIPTION | 13 | DESCRIPTION |
14 | ----------- | 14 | ----------- |
@@ -104,6 +104,8 @@ To limit the list use: | |||
104 | 'subsys_glob:event_glob' to filter by tracepoint subsystems such as sched, | 104 | 'subsys_glob:event_glob' to filter by tracepoint subsystems such as sched, |
105 | block, etc. | 105 | block, etc. |
106 | 106 | ||
107 | . 'pmu' to print the kernel supplied PMU events. | ||
108 | |||
107 | . If none of the above is matched, it will apply the supplied glob to all | 109 | . If none of the above is matched, it will apply the supplied glob to all |
108 | events, printing the ones that match. | 110 | events, printing the ones that match. |
109 | 111 | ||
diff --git a/tools/perf/Documentation/perf-report.txt b/tools/perf/Documentation/perf-report.txt index 66dab7410c1d..747ff50284b7 100644 --- a/tools/perf/Documentation/perf-report.txt +++ b/tools/perf/Documentation/perf-report.txt | |||
@@ -135,6 +135,11 @@ OPTIONS | |||
135 | --inverted:: | 135 | --inverted:: |
136 | alias for inverted caller based call graph. | 136 | alias for inverted caller based call graph. |
137 | 137 | ||
138 | --ignore-callees=<regex>:: | ||
139 | Ignore callees of the function(s) matching the given regex. | ||
140 | This has the effect of collecting the callers of each such | ||
141 | function into one place in the call-graph tree. | ||
142 | |||
138 | --pretty=<key>:: | 143 | --pretty=<key>:: |
139 | Pretty printing style. key: normal, raw | 144 | Pretty printing style. key: normal, raw |
140 | 145 | ||
diff --git a/tools/perf/Documentation/perf-top.txt b/tools/perf/Documentation/perf-top.txt index 7fdd1909e376..58d6598a9686 100644 --- a/tools/perf/Documentation/perf-top.txt +++ b/tools/perf/Documentation/perf-top.txt | |||
@@ -155,6 +155,11 @@ Default is to monitor all CPUS. | |||
155 | 155 | ||
156 | Default: fractal,0.5,callee. | 156 | Default: fractal,0.5,callee. |
157 | 157 | ||
158 | --ignore-callees=<regex>:: | ||
159 | Ignore callees of the function(s) matching the given regex. | ||
160 | This has the effect of collecting the callers of each such | ||
161 | function into one place in the call-graph tree. | ||
162 | |||
158 | --percent-limit:: | 163 | --percent-limit:: |
159 | Do not show entries which have an overhead under that percent. | 164 | Do not show entries which have an overhead under that percent. |
160 | (Default: 0). | 165 | (Default: 0). |
diff --git a/tools/perf/Makefile b/tools/perf/Makefile index 641fccddb249..2a6902677141 100644 --- a/tools/perf/Makefile +++ b/tools/perf/Makefile | |||
@@ -124,7 +124,7 @@ strip-libs = $(filter-out -l%,$(1)) | |||
124 | ifneq ($(OUTPUT),) | 124 | ifneq ($(OUTPUT),) |
125 | TE_PATH=$(OUTPUT) | 125 | TE_PATH=$(OUTPUT) |
126 | ifneq ($(subdir),) | 126 | ifneq ($(subdir),) |
127 | LK_PATH=$(objtree)/lib/lk/ | 127 | LK_PATH=$(OUTPUT)/../lib/lk/ |
128 | else | 128 | else |
129 | LK_PATH=$(OUTPUT) | 129 | LK_PATH=$(OUTPUT) |
130 | endif | 130 | endif |
@@ -281,7 +281,7 @@ LIB_H += util/cpumap.h | |||
281 | LIB_H += util/top.h | 281 | LIB_H += util/top.h |
282 | LIB_H += $(ARCH_INCLUDE) | 282 | LIB_H += $(ARCH_INCLUDE) |
283 | LIB_H += util/cgroup.h | 283 | LIB_H += util/cgroup.h |
284 | LIB_H += $(TRACE_EVENT_DIR)event-parse.h | 284 | LIB_H += $(LIB_INCLUDE)traceevent/event-parse.h |
285 | LIB_H += util/target.h | 285 | LIB_H += util/target.h |
286 | LIB_H += util/rblist.h | 286 | LIB_H += util/rblist.h |
287 | LIB_H += util/intlist.h | 287 | LIB_H += util/intlist.h |
diff --git a/tools/perf/builtin-diff.c b/tools/perf/builtin-diff.c index 0aac5f3e594d..93de3ac177c5 100644 --- a/tools/perf/builtin-diff.c +++ b/tools/perf/builtin-diff.c | |||
@@ -18,15 +18,53 @@ | |||
18 | #include "util/util.h" | 18 | #include "util/util.h" |
19 | 19 | ||
20 | #include <stdlib.h> | 20 | #include <stdlib.h> |
21 | #include <math.h> | ||
21 | 22 | ||
22 | static char const *input_old = "perf.data.old", | 23 | /* Diff command specific HPP columns. */ |
23 | *input_new = "perf.data"; | 24 | enum { |
24 | static char diff__default_sort_order[] = "dso,symbol"; | 25 | PERF_HPP_DIFF__BASELINE, |
25 | static bool force; | 26 | PERF_HPP_DIFF__PERIOD, |
27 | PERF_HPP_DIFF__PERIOD_BASELINE, | ||
28 | PERF_HPP_DIFF__DELTA, | ||
29 | PERF_HPP_DIFF__RATIO, | ||
30 | PERF_HPP_DIFF__WEIGHTED_DIFF, | ||
31 | PERF_HPP_DIFF__FORMULA, | ||
32 | |||
33 | PERF_HPP_DIFF__MAX_INDEX | ||
34 | }; | ||
35 | |||
36 | struct diff_hpp_fmt { | ||
37 | struct perf_hpp_fmt fmt; | ||
38 | int idx; | ||
39 | char *header; | ||
40 | int header_width; | ||
41 | }; | ||
42 | |||
43 | struct data__file { | ||
44 | struct perf_session *session; | ||
45 | const char *file; | ||
46 | int idx; | ||
47 | struct hists *hists; | ||
48 | struct diff_hpp_fmt fmt[PERF_HPP_DIFF__MAX_INDEX]; | ||
49 | }; | ||
50 | |||
51 | static struct data__file *data__files; | ||
52 | static int data__files_cnt; | ||
53 | |||
54 | #define data__for_each_file_start(i, d, s) \ | ||
55 | for (i = s, d = &data__files[s]; \ | ||
56 | i < data__files_cnt; \ | ||
57 | i++, d = &data__files[i]) | ||
58 | |||
59 | #define data__for_each_file(i, d) data__for_each_file_start(i, d, 0) | ||
60 | #define data__for_each_file_new(i, d) data__for_each_file_start(i, d, 1) | ||
61 | |||
62 | static char diff__default_sort_order[] = "dso,symbol"; | ||
63 | static bool force; | ||
26 | static bool show_period; | 64 | static bool show_period; |
27 | static bool show_formula; | 65 | static bool show_formula; |
28 | static bool show_baseline_only; | 66 | static bool show_baseline_only; |
29 | static bool sort_compute; | 67 | static unsigned int sort_compute; |
30 | 68 | ||
31 | static s64 compute_wdiff_w1; | 69 | static s64 compute_wdiff_w1; |
32 | static s64 compute_wdiff_w2; | 70 | static s64 compute_wdiff_w2; |
@@ -46,6 +84,47 @@ const char *compute_names[COMPUTE_MAX] = { | |||
46 | 84 | ||
47 | static int compute; | 85 | static int compute; |
48 | 86 | ||
87 | static int compute_2_hpp[COMPUTE_MAX] = { | ||
88 | [COMPUTE_DELTA] = PERF_HPP_DIFF__DELTA, | ||
89 | [COMPUTE_RATIO] = PERF_HPP_DIFF__RATIO, | ||
90 | [COMPUTE_WEIGHTED_DIFF] = PERF_HPP_DIFF__WEIGHTED_DIFF, | ||
91 | }; | ||
92 | |||
93 | #define MAX_COL_WIDTH 70 | ||
94 | |||
95 | static struct header_column { | ||
96 | const char *name; | ||
97 | int width; | ||
98 | } columns[PERF_HPP_DIFF__MAX_INDEX] = { | ||
99 | [PERF_HPP_DIFF__BASELINE] = { | ||
100 | .name = "Baseline", | ||
101 | }, | ||
102 | [PERF_HPP_DIFF__PERIOD] = { | ||
103 | .name = "Period", | ||
104 | .width = 14, | ||
105 | }, | ||
106 | [PERF_HPP_DIFF__PERIOD_BASELINE] = { | ||
107 | .name = "Base period", | ||
108 | .width = 14, | ||
109 | }, | ||
110 | [PERF_HPP_DIFF__DELTA] = { | ||
111 | .name = "Delta", | ||
112 | .width = 7, | ||
113 | }, | ||
114 | [PERF_HPP_DIFF__RATIO] = { | ||
115 | .name = "Ratio", | ||
116 | .width = 14, | ||
117 | }, | ||
118 | [PERF_HPP_DIFF__WEIGHTED_DIFF] = { | ||
119 | .name = "Weighted diff", | ||
120 | .width = 14, | ||
121 | }, | ||
122 | [PERF_HPP_DIFF__FORMULA] = { | ||
123 | .name = "Formula", | ||
124 | .width = MAX_COL_WIDTH, | ||
125 | } | ||
126 | }; | ||
127 | |||
49 | static int setup_compute_opt_wdiff(char *opt) | 128 | static int setup_compute_opt_wdiff(char *opt) |
50 | { | 129 | { |
51 | char *w1_str = opt; | 130 | char *w1_str = opt; |
@@ -109,13 +188,6 @@ static int setup_compute(const struct option *opt, const char *str, | |||
109 | return 0; | 188 | return 0; |
110 | } | 189 | } |
111 | 190 | ||
112 | if (*str == '+') { | ||
113 | sort_compute = true; | ||
114 | cstr = (char *) ++str; | ||
115 | if (!*str) | ||
116 | return 0; | ||
117 | } | ||
118 | |||
119 | option = strchr(str, ':'); | 191 | option = strchr(str, ':'); |
120 | if (option) { | 192 | if (option) { |
121 | unsigned len = option++ - str; | 193 | unsigned len = option++ - str; |
@@ -145,42 +217,42 @@ static int setup_compute(const struct option *opt, const char *str, | |||
145 | return -EINVAL; | 217 | return -EINVAL; |
146 | } | 218 | } |
147 | 219 | ||
148 | double perf_diff__period_percent(struct hist_entry *he, u64 period) | 220 | static double period_percent(struct hist_entry *he, u64 period) |
149 | { | 221 | { |
150 | u64 total = he->hists->stats.total_period; | 222 | u64 total = he->hists->stats.total_period; |
151 | return (period * 100.0) / total; | 223 | return (period * 100.0) / total; |
152 | } | 224 | } |
153 | 225 | ||
154 | double perf_diff__compute_delta(struct hist_entry *he, struct hist_entry *pair) | 226 | static double compute_delta(struct hist_entry *he, struct hist_entry *pair) |
155 | { | 227 | { |
156 | double new_percent = perf_diff__period_percent(he, he->stat.period); | 228 | double old_percent = period_percent(he, he->stat.period); |
157 | double old_percent = perf_diff__period_percent(pair, pair->stat.period); | 229 | double new_percent = period_percent(pair, pair->stat.period); |
158 | 230 | ||
159 | he->diff.period_ratio_delta = new_percent - old_percent; | 231 | pair->diff.period_ratio_delta = new_percent - old_percent; |
160 | he->diff.computed = true; | 232 | pair->diff.computed = true; |
161 | return he->diff.period_ratio_delta; | 233 | return pair->diff.period_ratio_delta; |
162 | } | 234 | } |
163 | 235 | ||
164 | double perf_diff__compute_ratio(struct hist_entry *he, struct hist_entry *pair) | 236 | static double compute_ratio(struct hist_entry *he, struct hist_entry *pair) |
165 | { | 237 | { |
166 | double new_period = he->stat.period; | 238 | double old_period = he->stat.period ?: 1; |
167 | double old_period = pair->stat.period; | 239 | double new_period = pair->stat.period; |
168 | 240 | ||
169 | he->diff.computed = true; | 241 | pair->diff.computed = true; |
170 | he->diff.period_ratio = new_period / old_period; | 242 | pair->diff.period_ratio = new_period / old_period; |
171 | return he->diff.period_ratio; | 243 | return pair->diff.period_ratio; |
172 | } | 244 | } |
173 | 245 | ||
174 | s64 perf_diff__compute_wdiff(struct hist_entry *he, struct hist_entry *pair) | 246 | static s64 compute_wdiff(struct hist_entry *he, struct hist_entry *pair) |
175 | { | 247 | { |
176 | u64 new_period = he->stat.period; | 248 | u64 old_period = he->stat.period; |
177 | u64 old_period = pair->stat.period; | 249 | u64 new_period = pair->stat.period; |
178 | 250 | ||
179 | he->diff.computed = true; | 251 | pair->diff.computed = true; |
180 | he->diff.wdiff = new_period * compute_wdiff_w2 - | 252 | pair->diff.wdiff = new_period * compute_wdiff_w2 - |
181 | old_period * compute_wdiff_w1; | 253 | old_period * compute_wdiff_w1; |
182 | 254 | ||
183 | return he->diff.wdiff; | 255 | return pair->diff.wdiff; |
184 | } | 256 | } |
185 | 257 | ||
186 | static int formula_delta(struct hist_entry *he, struct hist_entry *pair, | 258 | static int formula_delta(struct hist_entry *he, struct hist_entry *pair, |
@@ -189,15 +261,15 @@ static int formula_delta(struct hist_entry *he, struct hist_entry *pair, | |||
189 | return scnprintf(buf, size, | 261 | return scnprintf(buf, size, |
190 | "(%" PRIu64 " * 100 / %" PRIu64 ") - " | 262 | "(%" PRIu64 " * 100 / %" PRIu64 ") - " |
191 | "(%" PRIu64 " * 100 / %" PRIu64 ")", | 263 | "(%" PRIu64 " * 100 / %" PRIu64 ")", |
192 | he->stat.period, he->hists->stats.total_period, | 264 | pair->stat.period, pair->hists->stats.total_period, |
193 | pair->stat.period, pair->hists->stats.total_period); | 265 | he->stat.period, he->hists->stats.total_period); |
194 | } | 266 | } |
195 | 267 | ||
196 | static int formula_ratio(struct hist_entry *he, struct hist_entry *pair, | 268 | static int formula_ratio(struct hist_entry *he, struct hist_entry *pair, |
197 | char *buf, size_t size) | 269 | char *buf, size_t size) |
198 | { | 270 | { |
199 | double new_period = he->stat.period; | 271 | double old_period = he->stat.period; |
200 | double old_period = pair->stat.period; | 272 | double new_period = pair->stat.period; |
201 | 273 | ||
202 | return scnprintf(buf, size, "%.0F / %.0F", new_period, old_period); | 274 | return scnprintf(buf, size, "%.0F / %.0F", new_period, old_period); |
203 | } | 275 | } |
@@ -205,16 +277,16 @@ static int formula_ratio(struct hist_entry *he, struct hist_entry *pair, | |||
205 | static int formula_wdiff(struct hist_entry *he, struct hist_entry *pair, | 277 | static int formula_wdiff(struct hist_entry *he, struct hist_entry *pair, |
206 | char *buf, size_t size) | 278 | char *buf, size_t size) |
207 | { | 279 | { |
208 | u64 new_period = he->stat.period; | 280 | u64 old_period = he->stat.period; |
209 | u64 old_period = pair->stat.period; | 281 | u64 new_period = pair->stat.period; |
210 | 282 | ||
211 | return scnprintf(buf, size, | 283 | return scnprintf(buf, size, |
212 | "(%" PRIu64 " * " "%" PRId64 ") - (%" PRIu64 " * " "%" PRId64 ")", | 284 | "(%" PRIu64 " * " "%" PRId64 ") - (%" PRIu64 " * " "%" PRId64 ")", |
213 | new_period, compute_wdiff_w2, old_period, compute_wdiff_w1); | 285 | new_period, compute_wdiff_w2, old_period, compute_wdiff_w1); |
214 | } | 286 | } |
215 | 287 | ||
216 | int perf_diff__formula(struct hist_entry *he, struct hist_entry *pair, | 288 | static int formula_fprintf(struct hist_entry *he, struct hist_entry *pair, |
217 | char *buf, size_t size) | 289 | char *buf, size_t size) |
218 | { | 290 | { |
219 | switch (compute) { | 291 | switch (compute) { |
220 | case COMPUTE_DELTA: | 292 | case COMPUTE_DELTA: |
@@ -299,6 +371,29 @@ static void perf_evlist__collapse_resort(struct perf_evlist *evlist) | |||
299 | } | 371 | } |
300 | } | 372 | } |
301 | 373 | ||
374 | static struct hist_entry* | ||
375 | get_pair_data(struct hist_entry *he, struct data__file *d) | ||
376 | { | ||
377 | if (hist_entry__has_pairs(he)) { | ||
378 | struct hist_entry *pair; | ||
379 | |||
380 | list_for_each_entry(pair, &he->pairs.head, pairs.node) | ||
381 | if (pair->hists == d->hists) | ||
382 | return pair; | ||
383 | } | ||
384 | |||
385 | return NULL; | ||
386 | } | ||
387 | |||
388 | static struct hist_entry* | ||
389 | get_pair_fmt(struct hist_entry *he, struct diff_hpp_fmt *dfmt) | ||
390 | { | ||
391 | void *ptr = dfmt - dfmt->idx; | ||
392 | struct data__file *d = container_of(ptr, struct data__file, fmt); | ||
393 | |||
394 | return get_pair_data(he, d); | ||
395 | } | ||
396 | |||
302 | static void hists__baseline_only(struct hists *hists) | 397 | static void hists__baseline_only(struct hists *hists) |
303 | { | 398 | { |
304 | struct rb_root *root; | 399 | struct rb_root *root; |
@@ -333,22 +428,24 @@ static void hists__precompute(struct hists *hists) | |||
333 | 428 | ||
334 | next = rb_first(root); | 429 | next = rb_first(root); |
335 | while (next != NULL) { | 430 | while (next != NULL) { |
336 | struct hist_entry *he = rb_entry(next, struct hist_entry, rb_node_in); | 431 | struct hist_entry *he, *pair; |
337 | struct hist_entry *pair = hist_entry__next_pair(he); | ||
338 | 432 | ||
433 | he = rb_entry(next, struct hist_entry, rb_node_in); | ||
339 | next = rb_next(&he->rb_node_in); | 434 | next = rb_next(&he->rb_node_in); |
435 | |||
436 | pair = get_pair_data(he, &data__files[sort_compute]); | ||
340 | if (!pair) | 437 | if (!pair) |
341 | continue; | 438 | continue; |
342 | 439 | ||
343 | switch (compute) { | 440 | switch (compute) { |
344 | case COMPUTE_DELTA: | 441 | case COMPUTE_DELTA: |
345 | perf_diff__compute_delta(he, pair); | 442 | compute_delta(he, pair); |
346 | break; | 443 | break; |
347 | case COMPUTE_RATIO: | 444 | case COMPUTE_RATIO: |
348 | perf_diff__compute_ratio(he, pair); | 445 | compute_ratio(he, pair); |
349 | break; | 446 | break; |
350 | case COMPUTE_WEIGHTED_DIFF: | 447 | case COMPUTE_WEIGHTED_DIFF: |
351 | perf_diff__compute_wdiff(he, pair); | 448 | compute_wdiff(he, pair); |
352 | break; | 449 | break; |
353 | default: | 450 | default: |
354 | BUG_ON(1); | 451 | BUG_ON(1); |
@@ -367,7 +464,7 @@ static int64_t cmp_doubles(double l, double r) | |||
367 | } | 464 | } |
368 | 465 | ||
369 | static int64_t | 466 | static int64_t |
370 | hist_entry__cmp_compute(struct hist_entry *left, struct hist_entry *right, | 467 | __hist_entry__cmp_compute(struct hist_entry *left, struct hist_entry *right, |
371 | int c) | 468 | int c) |
372 | { | 469 | { |
373 | switch (c) { | 470 | switch (c) { |
@@ -399,6 +496,36 @@ hist_entry__cmp_compute(struct hist_entry *left, struct hist_entry *right, | |||
399 | return 0; | 496 | return 0; |
400 | } | 497 | } |
401 | 498 | ||
499 | static int64_t | ||
500 | hist_entry__cmp_compute(struct hist_entry *left, struct hist_entry *right, | ||
501 | int c) | ||
502 | { | ||
503 | bool pairs_left = hist_entry__has_pairs(left); | ||
504 | bool pairs_right = hist_entry__has_pairs(right); | ||
505 | struct hist_entry *p_right, *p_left; | ||
506 | |||
507 | if (!pairs_left && !pairs_right) | ||
508 | return 0; | ||
509 | |||
510 | if (!pairs_left || !pairs_right) | ||
511 | return pairs_left ? -1 : 1; | ||
512 | |||
513 | p_left = get_pair_data(left, &data__files[sort_compute]); | ||
514 | p_right = get_pair_data(right, &data__files[sort_compute]); | ||
515 | |||
516 | if (!p_left && !p_right) | ||
517 | return 0; | ||
518 | |||
519 | if (!p_left || !p_right) | ||
520 | return p_left ? -1 : 1; | ||
521 | |||
522 | /* | ||
523 | * We have 2 entries of same kind, let's | ||
524 | * make the data comparison. | ||
525 | */ | ||
526 | return __hist_entry__cmp_compute(p_left, p_right, c); | ||
527 | } | ||
528 | |||
402 | static void insert_hist_entry_by_compute(struct rb_root *root, | 529 | static void insert_hist_entry_by_compute(struct rb_root *root, |
403 | struct hist_entry *he, | 530 | struct hist_entry *he, |
404 | int c) | 531 | int c) |
@@ -448,75 +575,121 @@ static void hists__compute_resort(struct hists *hists) | |||
448 | } | 575 | } |
449 | } | 576 | } |
450 | 577 | ||
451 | static void hists__process(struct hists *old, struct hists *new) | 578 | static void hists__process(struct hists *hists) |
452 | { | 579 | { |
453 | hists__match(new, old); | ||
454 | |||
455 | if (show_baseline_only) | 580 | if (show_baseline_only) |
456 | hists__baseline_only(new); | 581 | hists__baseline_only(hists); |
457 | else | ||
458 | hists__link(new, old); | ||
459 | 582 | ||
460 | if (sort_compute) { | 583 | if (sort_compute) { |
461 | hists__precompute(new); | 584 | hists__precompute(hists); |
462 | hists__compute_resort(new); | 585 | hists__compute_resort(hists); |
463 | } else { | 586 | } else { |
464 | hists__output_resort(new); | 587 | hists__output_resort(hists); |
465 | } | 588 | } |
466 | 589 | ||
467 | hists__fprintf(new, true, 0, 0, 0, stdout); | 590 | hists__fprintf(hists, true, 0, 0, 0, stdout); |
468 | } | 591 | } |
469 | 592 | ||
470 | static int __cmd_diff(void) | 593 | static void data__fprintf(void) |
471 | { | 594 | { |
472 | int ret, i; | 595 | struct data__file *d; |
473 | #define older (session[0]) | 596 | int i; |
474 | #define newer (session[1]) | 597 | |
475 | struct perf_session *session[2]; | 598 | fprintf(stdout, "# Data files:\n"); |
476 | struct perf_evlist *evlist_new, *evlist_old; | 599 | |
477 | struct perf_evsel *evsel; | 600 | data__for_each_file(i, d) |
601 | fprintf(stdout, "# [%d] %s %s\n", | ||
602 | d->idx, d->file, | ||
603 | !d->idx ? "(Baseline)" : ""); | ||
604 | |||
605 | fprintf(stdout, "#\n"); | ||
606 | } | ||
607 | |||
608 | static void data_process(void) | ||
609 | { | ||
610 | struct perf_evlist *evlist_base = data__files[0].session->evlist; | ||
611 | struct perf_evsel *evsel_base; | ||
478 | bool first = true; | 612 | bool first = true; |
479 | 613 | ||
480 | older = perf_session__new(input_old, O_RDONLY, force, false, | 614 | list_for_each_entry(evsel_base, &evlist_base->entries, node) { |
481 | &tool); | 615 | struct data__file *d; |
482 | newer = perf_session__new(input_new, O_RDONLY, force, false, | 616 | int i; |
483 | &tool); | ||
484 | if (session[0] == NULL || session[1] == NULL) | ||
485 | return -ENOMEM; | ||
486 | 617 | ||
487 | for (i = 0; i < 2; ++i) { | 618 | data__for_each_file_new(i, d) { |
488 | ret = perf_session__process_events(session[i], &tool); | 619 | struct perf_evlist *evlist = d->session->evlist; |
489 | if (ret) | 620 | struct perf_evsel *evsel; |
490 | goto out_delete; | ||
491 | } | ||
492 | 621 | ||
493 | evlist_old = older->evlist; | 622 | evsel = evsel_match(evsel_base, evlist); |
494 | evlist_new = newer->evlist; | 623 | if (!evsel) |
624 | continue; | ||
495 | 625 | ||
496 | perf_evlist__collapse_resort(evlist_old); | 626 | d->hists = &evsel->hists; |
497 | perf_evlist__collapse_resort(evlist_new); | ||
498 | 627 | ||
499 | list_for_each_entry(evsel, &evlist_new->entries, node) { | 628 | hists__match(&evsel_base->hists, &evsel->hists); |
500 | struct perf_evsel *evsel_old; | ||
501 | 629 | ||
502 | evsel_old = evsel_match(evsel, evlist_old); | 630 | if (!show_baseline_only) |
503 | if (!evsel_old) | 631 | hists__link(&evsel_base->hists, |
504 | continue; | 632 | &evsel->hists); |
633 | } | ||
505 | 634 | ||
506 | fprintf(stdout, "%s# Event '%s'\n#\n", first ? "" : "\n", | 635 | fprintf(stdout, "%s# Event '%s'\n#\n", first ? "" : "\n", |
507 | perf_evsel__name(evsel)); | 636 | perf_evsel__name(evsel_base)); |
508 | 637 | ||
509 | first = false; | 638 | first = false; |
510 | 639 | ||
511 | hists__process(&evsel_old->hists, &evsel->hists); | 640 | if (verbose || data__files_cnt > 2) |
641 | data__fprintf(); | ||
642 | |||
643 | hists__process(&evsel_base->hists); | ||
644 | } | ||
645 | } | ||
646 | |||
647 | static void data__free(struct data__file *d) | ||
648 | { | ||
649 | int col; | ||
650 | |||
651 | for (col = 0; col < PERF_HPP_DIFF__MAX_INDEX; col++) { | ||
652 | struct diff_hpp_fmt *fmt = &d->fmt[col]; | ||
653 | |||
654 | free(fmt->header); | ||
512 | } | 655 | } |
656 | } | ||
513 | 657 | ||
514 | out_delete: | 658 | static int __cmd_diff(void) |
515 | for (i = 0; i < 2; ++i) | 659 | { |
516 | perf_session__delete(session[i]); | 660 | struct data__file *d; |
661 | int ret = -EINVAL, i; | ||
662 | |||
663 | data__for_each_file(i, d) { | ||
664 | d->session = perf_session__new(d->file, O_RDONLY, force, | ||
665 | false, &tool); | ||
666 | if (!d->session) { | ||
667 | pr_err("Failed to open %s\n", d->file); | ||
668 | ret = -ENOMEM; | ||
669 | goto out_delete; | ||
670 | } | ||
671 | |||
672 | ret = perf_session__process_events(d->session, &tool); | ||
673 | if (ret) { | ||
674 | pr_err("Failed to process %s\n", d->file); | ||
675 | goto out_delete; | ||
676 | } | ||
677 | |||
678 | perf_evlist__collapse_resort(d->session->evlist); | ||
679 | } | ||
680 | |||
681 | data_process(); | ||
682 | |||
683 | out_delete: | ||
684 | data__for_each_file(i, d) { | ||
685 | if (d->session) | ||
686 | perf_session__delete(d->session); | ||
687 | |||
688 | data__free(d); | ||
689 | } | ||
690 | |||
691 | free(data__files); | ||
517 | return ret; | 692 | return ret; |
518 | #undef older | ||
519 | #undef newer | ||
520 | } | 693 | } |
521 | 694 | ||
522 | static const char * const diff_usage[] = { | 695 | static const char * const diff_usage[] = { |
@@ -555,61 +728,310 @@ static const struct option options[] = { | |||
555 | "columns '.' is reserved."), | 728 | "columns '.' is reserved."), |
556 | OPT_STRING(0, "symfs", &symbol_conf.symfs, "directory", | 729 | OPT_STRING(0, "symfs", &symbol_conf.symfs, "directory", |
557 | "Look for files with symbols relative to this directory"), | 730 | "Look for files with symbols relative to this directory"), |
731 | OPT_UINTEGER('o', "order", &sort_compute, "Specify compute sorting."), | ||
558 | OPT_END() | 732 | OPT_END() |
559 | }; | 733 | }; |
560 | 734 | ||
561 | static void ui_init(void) | 735 | static double baseline_percent(struct hist_entry *he) |
562 | { | 736 | { |
563 | /* | 737 | struct hists *hists = he->hists; |
564 | * Display baseline/delta/ratio | 738 | return 100.0 * he->stat.period / hists->stats.total_period; |
565 | * formula/periods columns. | 739 | } |
566 | */ | ||
567 | perf_hpp__column_enable(PERF_HPP__BASELINE); | ||
568 | 740 | ||
569 | switch (compute) { | 741 | static int hpp__color_baseline(struct perf_hpp_fmt *fmt, |
570 | case COMPUTE_DELTA: | 742 | struct perf_hpp *hpp, struct hist_entry *he) |
571 | perf_hpp__column_enable(PERF_HPP__DELTA); | 743 | { |
744 | struct diff_hpp_fmt *dfmt = | ||
745 | container_of(fmt, struct diff_hpp_fmt, fmt); | ||
746 | double percent = baseline_percent(he); | ||
747 | char pfmt[20] = " "; | ||
748 | |||
749 | if (!he->dummy) { | ||
750 | scnprintf(pfmt, 20, "%%%d.2f%%%%", dfmt->header_width - 1); | ||
751 | return percent_color_snprintf(hpp->buf, hpp->size, | ||
752 | pfmt, percent); | ||
753 | } else | ||
754 | return scnprintf(hpp->buf, hpp->size, "%*s", | ||
755 | dfmt->header_width, pfmt); | ||
756 | } | ||
757 | |||
758 | static int hpp__entry_baseline(struct hist_entry *he, char *buf, size_t size) | ||
759 | { | ||
760 | double percent = baseline_percent(he); | ||
761 | const char *fmt = symbol_conf.field_sep ? "%.2f" : "%6.2f%%"; | ||
762 | int ret = 0; | ||
763 | |||
764 | if (!he->dummy) | ||
765 | ret = scnprintf(buf, size, fmt, percent); | ||
766 | |||
767 | return ret; | ||
768 | } | ||
769 | |||
770 | static void | ||
771 | hpp__entry_unpair(struct hist_entry *he, int idx, char *buf, size_t size) | ||
772 | { | ||
773 | switch (idx) { | ||
774 | case PERF_HPP_DIFF__PERIOD_BASELINE: | ||
775 | scnprintf(buf, size, "%" PRIu64, he->stat.period); | ||
572 | break; | 776 | break; |
573 | case COMPUTE_RATIO: | 777 | |
574 | perf_hpp__column_enable(PERF_HPP__RATIO); | 778 | default: |
575 | break; | 779 | break; |
576 | case COMPUTE_WEIGHTED_DIFF: | 780 | } |
577 | perf_hpp__column_enable(PERF_HPP__WEIGHTED_DIFF); | 781 | } |
782 | |||
783 | static void | ||
784 | hpp__entry_pair(struct hist_entry *he, struct hist_entry *pair, | ||
785 | int idx, char *buf, size_t size) | ||
786 | { | ||
787 | double diff; | ||
788 | double ratio; | ||
789 | s64 wdiff; | ||
790 | |||
791 | switch (idx) { | ||
792 | case PERF_HPP_DIFF__DELTA: | ||
793 | if (pair->diff.computed) | ||
794 | diff = pair->diff.period_ratio_delta; | ||
795 | else | ||
796 | diff = compute_delta(he, pair); | ||
797 | |||
798 | if (fabs(diff) >= 0.01) | ||
799 | scnprintf(buf, size, "%+4.2F%%", diff); | ||
800 | break; | ||
801 | |||
802 | case PERF_HPP_DIFF__RATIO: | ||
803 | /* No point for ratio number if we are dummy.. */ | ||
804 | if (he->dummy) | ||
805 | break; | ||
806 | |||
807 | if (pair->diff.computed) | ||
808 | ratio = pair->diff.period_ratio; | ||
809 | else | ||
810 | ratio = compute_ratio(he, pair); | ||
811 | |||
812 | if (ratio > 0.0) | ||
813 | scnprintf(buf, size, "%14.6F", ratio); | ||
814 | break; | ||
815 | |||
816 | case PERF_HPP_DIFF__WEIGHTED_DIFF: | ||
817 | /* No point for wdiff number if we are dummy.. */ | ||
818 | if (he->dummy) | ||
819 | break; | ||
820 | |||
821 | if (pair->diff.computed) | ||
822 | wdiff = pair->diff.wdiff; | ||
823 | else | ||
824 | wdiff = compute_wdiff(he, pair); | ||
825 | |||
826 | if (wdiff != 0) | ||
827 | scnprintf(buf, size, "%14ld", wdiff); | ||
828 | break; | ||
829 | |||
830 | case PERF_HPP_DIFF__FORMULA: | ||
831 | formula_fprintf(he, pair, buf, size); | ||
832 | break; | ||
833 | |||
834 | case PERF_HPP_DIFF__PERIOD: | ||
835 | scnprintf(buf, size, "%" PRIu64, pair->stat.period); | ||
578 | break; | 836 | break; |
837 | |||
579 | default: | 838 | default: |
580 | BUG_ON(1); | 839 | BUG_ON(1); |
581 | }; | 840 | }; |
841 | } | ||
842 | |||
843 | static void | ||
844 | __hpp__entry_global(struct hist_entry *he, struct diff_hpp_fmt *dfmt, | ||
845 | char *buf, size_t size) | ||
846 | { | ||
847 | struct hist_entry *pair = get_pair_fmt(he, dfmt); | ||
848 | int idx = dfmt->idx; | ||
849 | |||
850 | /* baseline is special */ | ||
851 | if (idx == PERF_HPP_DIFF__BASELINE) | ||
852 | hpp__entry_baseline(he, buf, size); | ||
853 | else { | ||
854 | if (pair) | ||
855 | hpp__entry_pair(he, pair, idx, buf, size); | ||
856 | else | ||
857 | hpp__entry_unpair(he, idx, buf, size); | ||
858 | } | ||
859 | } | ||
860 | |||
861 | static int hpp__entry_global(struct perf_hpp_fmt *_fmt, struct perf_hpp *hpp, | ||
862 | struct hist_entry *he) | ||
863 | { | ||
864 | struct diff_hpp_fmt *dfmt = | ||
865 | container_of(_fmt, struct diff_hpp_fmt, fmt); | ||
866 | char buf[MAX_COL_WIDTH] = " "; | ||
867 | |||
868 | __hpp__entry_global(he, dfmt, buf, MAX_COL_WIDTH); | ||
869 | |||
870 | if (symbol_conf.field_sep) | ||
871 | return scnprintf(hpp->buf, hpp->size, "%s", buf); | ||
872 | else | ||
873 | return scnprintf(hpp->buf, hpp->size, "%*s", | ||
874 | dfmt->header_width, buf); | ||
875 | } | ||
876 | |||
877 | static int hpp__header(struct perf_hpp_fmt *fmt, | ||
878 | struct perf_hpp *hpp) | ||
879 | { | ||
880 | struct diff_hpp_fmt *dfmt = | ||
881 | container_of(fmt, struct diff_hpp_fmt, fmt); | ||
582 | 882 | ||
583 | if (show_formula) | 883 | BUG_ON(!dfmt->header); |
584 | perf_hpp__column_enable(PERF_HPP__FORMULA); | 884 | return scnprintf(hpp->buf, hpp->size, dfmt->header); |
885 | } | ||
585 | 886 | ||
586 | if (show_period) { | 887 | static int hpp__width(struct perf_hpp_fmt *fmt, |
587 | perf_hpp__column_enable(PERF_HPP__PERIOD); | 888 | struct perf_hpp *hpp __maybe_unused) |
588 | perf_hpp__column_enable(PERF_HPP__PERIOD_BASELINE); | 889 | { |
890 | struct diff_hpp_fmt *dfmt = | ||
891 | container_of(fmt, struct diff_hpp_fmt, fmt); | ||
892 | |||
893 | BUG_ON(dfmt->header_width <= 0); | ||
894 | return dfmt->header_width; | ||
895 | } | ||
896 | |||
897 | static void init_header(struct data__file *d, struct diff_hpp_fmt *dfmt) | ||
898 | { | ||
899 | #define MAX_HEADER_NAME 100 | ||
900 | char buf_indent[MAX_HEADER_NAME]; | ||
901 | char buf[MAX_HEADER_NAME]; | ||
902 | const char *header = NULL; | ||
903 | int width = 0; | ||
904 | |||
905 | BUG_ON(dfmt->idx >= PERF_HPP_DIFF__MAX_INDEX); | ||
906 | header = columns[dfmt->idx].name; | ||
907 | width = columns[dfmt->idx].width; | ||
908 | |||
909 | /* Only our defined HPP fmts should appear here. */ | ||
910 | BUG_ON(!header); | ||
911 | |||
912 | if (data__files_cnt > 2) | ||
913 | scnprintf(buf, MAX_HEADER_NAME, "%s/%d", header, d->idx); | ||
914 | |||
915 | #define NAME (data__files_cnt > 2 ? buf : header) | ||
916 | dfmt->header_width = width; | ||
917 | width = (int) strlen(NAME); | ||
918 | if (dfmt->header_width < width) | ||
919 | dfmt->header_width = width; | ||
920 | |||
921 | scnprintf(buf_indent, MAX_HEADER_NAME, "%*s", | ||
922 | dfmt->header_width, NAME); | ||
923 | |||
924 | dfmt->header = strdup(buf_indent); | ||
925 | #undef MAX_HEADER_NAME | ||
926 | #undef NAME | ||
927 | } | ||
928 | |||
929 | static void data__hpp_register(struct data__file *d, int idx) | ||
930 | { | ||
931 | struct diff_hpp_fmt *dfmt = &d->fmt[idx]; | ||
932 | struct perf_hpp_fmt *fmt = &dfmt->fmt; | ||
933 | |||
934 | dfmt->idx = idx; | ||
935 | |||
936 | fmt->header = hpp__header; | ||
937 | fmt->width = hpp__width; | ||
938 | fmt->entry = hpp__entry_global; | ||
939 | |||
940 | /* TODO more colors */ | ||
941 | if (idx == PERF_HPP_DIFF__BASELINE) | ||
942 | fmt->color = hpp__color_baseline; | ||
943 | |||
944 | init_header(d, dfmt); | ||
945 | perf_hpp__column_register(fmt); | ||
946 | } | ||
947 | |||
948 | static void ui_init(void) | ||
949 | { | ||
950 | struct data__file *d; | ||
951 | int i; | ||
952 | |||
953 | data__for_each_file(i, d) { | ||
954 | |||
955 | /* | ||
956 | * Baseline or compute realted columns: | ||
957 | * | ||
958 | * PERF_HPP_DIFF__BASELINE | ||
959 | * PERF_HPP_DIFF__DELTA | ||
960 | * PERF_HPP_DIFF__RATIO | ||
961 | * PERF_HPP_DIFF__WEIGHTED_DIFF | ||
962 | */ | ||
963 | data__hpp_register(d, i ? compute_2_hpp[compute] : | ||
964 | PERF_HPP_DIFF__BASELINE); | ||
965 | |||
966 | /* | ||
967 | * And the rest: | ||
968 | * | ||
969 | * PERF_HPP_DIFF__FORMULA | ||
970 | * PERF_HPP_DIFF__PERIOD | ||
971 | * PERF_HPP_DIFF__PERIOD_BASELINE | ||
972 | */ | ||
973 | if (show_formula && i) | ||
974 | data__hpp_register(d, PERF_HPP_DIFF__FORMULA); | ||
975 | |||
976 | if (show_period) | ||
977 | data__hpp_register(d, i ? PERF_HPP_DIFF__PERIOD : | ||
978 | PERF_HPP_DIFF__PERIOD_BASELINE); | ||
589 | } | 979 | } |
590 | } | 980 | } |
591 | 981 | ||
592 | int cmd_diff(int argc, const char **argv, const char *prefix __maybe_unused) | 982 | static int data_init(int argc, const char **argv) |
593 | { | 983 | { |
594 | sort_order = diff__default_sort_order; | 984 | struct data__file *d; |
595 | argc = parse_options(argc, argv, options, diff_usage, 0); | 985 | static const char *defaults[] = { |
986 | "perf.data.old", | ||
987 | "perf.data", | ||
988 | }; | ||
989 | bool use_default = true; | ||
990 | int i; | ||
991 | |||
992 | data__files_cnt = 2; | ||
993 | |||
596 | if (argc) { | 994 | if (argc) { |
597 | if (argc > 2) | 995 | if (argc == 1) |
598 | usage_with_options(diff_usage, options); | 996 | defaults[1] = argv[0]; |
599 | if (argc == 2) { | 997 | else { |
600 | input_old = argv[0]; | 998 | data__files_cnt = argc; |
601 | input_new = argv[1]; | 999 | use_default = false; |
602 | } else | 1000 | } |
603 | input_new = argv[0]; | ||
604 | } else if (symbol_conf.default_guest_vmlinux_name || | 1001 | } else if (symbol_conf.default_guest_vmlinux_name || |
605 | symbol_conf.default_guest_kallsyms) { | 1002 | symbol_conf.default_guest_kallsyms) { |
606 | input_old = "perf.data.host"; | 1003 | defaults[0] = "perf.data.host"; |
607 | input_new = "perf.data.guest"; | 1004 | defaults[1] = "perf.data.guest"; |
608 | } | 1005 | } |
609 | 1006 | ||
1007 | if (sort_compute >= (unsigned int) data__files_cnt) { | ||
1008 | pr_err("Order option out of limit.\n"); | ||
1009 | return -EINVAL; | ||
1010 | } | ||
1011 | |||
1012 | data__files = zalloc(sizeof(*data__files) * data__files_cnt); | ||
1013 | if (!data__files) | ||
1014 | return -ENOMEM; | ||
1015 | |||
1016 | data__for_each_file(i, d) { | ||
1017 | d->file = use_default ? defaults[i] : argv[i]; | ||
1018 | d->idx = i; | ||
1019 | } | ||
1020 | |||
1021 | return 0; | ||
1022 | } | ||
1023 | |||
1024 | int cmd_diff(int argc, const char **argv, const char *prefix __maybe_unused) | ||
1025 | { | ||
1026 | sort_order = diff__default_sort_order; | ||
1027 | argc = parse_options(argc, argv, options, diff_usage, 0); | ||
1028 | |||
610 | if (symbol__init() < 0) | 1029 | if (symbol__init() < 0) |
611 | return -1; | 1030 | return -1; |
612 | 1031 | ||
1032 | if (data_init(argc, argv) < 0) | ||
1033 | return -1; | ||
1034 | |||
613 | ui_init(); | 1035 | ui_init(); |
614 | 1036 | ||
615 | if (setup_sorting() < 0) | 1037 | if (setup_sorting() < 0) |
diff --git a/tools/perf/builtin-inject.c b/tools/perf/builtin-inject.c index 84ad6abe4258..1d8de2e4a407 100644 --- a/tools/perf/builtin-inject.c +++ b/tools/perf/builtin-inject.c | |||
@@ -38,8 +38,7 @@ struct event_entry { | |||
38 | }; | 38 | }; |
39 | 39 | ||
40 | static int perf_event__repipe_synth(struct perf_tool *tool, | 40 | static int perf_event__repipe_synth(struct perf_tool *tool, |
41 | union perf_event *event, | 41 | union perf_event *event) |
42 | struct machine *machine __maybe_unused) | ||
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 | uint32_t size; |
@@ -65,39 +64,28 @@ static int perf_event__repipe_op2_synth(struct perf_tool *tool, | |||
65 | struct perf_session *session | 64 | struct perf_session *session |
66 | __maybe_unused) | 65 | __maybe_unused) |
67 | { | 66 | { |
68 | return perf_event__repipe_synth(tool, event, NULL); | 67 | return perf_event__repipe_synth(tool, event); |
69 | } | 68 | } |
70 | 69 | ||
71 | static int perf_event__repipe_event_type_synth(struct perf_tool *tool, | 70 | static int perf_event__repipe_attr(struct perf_tool *tool, |
72 | union perf_event *event) | 71 | union perf_event *event, |
73 | { | 72 | struct perf_evlist **pevlist) |
74 | return perf_event__repipe_synth(tool, event, NULL); | ||
75 | } | ||
76 | |||
77 | static int perf_event__repipe_tracing_data_synth(union perf_event *event, | ||
78 | struct perf_session *session | ||
79 | __maybe_unused) | ||
80 | { | ||
81 | return perf_event__repipe_synth(NULL, event, NULL); | ||
82 | } | ||
83 | |||
84 | static int perf_event__repipe_attr(union perf_event *event, | ||
85 | struct perf_evlist **pevlist __maybe_unused) | ||
86 | { | 73 | { |
87 | int ret; | 74 | int ret; |
88 | ret = perf_event__process_attr(event, pevlist); | 75 | |
76 | ret = perf_event__process_attr(tool, event, pevlist); | ||
89 | if (ret) | 77 | if (ret) |
90 | return ret; | 78 | return ret; |
91 | 79 | ||
92 | return perf_event__repipe_synth(NULL, event, NULL); | 80 | return perf_event__repipe_synth(tool, event); |
93 | } | 81 | } |
94 | 82 | ||
95 | static int perf_event__repipe(struct perf_tool *tool, | 83 | static int perf_event__repipe(struct perf_tool *tool, |
96 | union perf_event *event, | 84 | union perf_event *event, |
97 | struct perf_sample *sample __maybe_unused, | 85 | struct perf_sample *sample __maybe_unused, |
98 | struct machine *machine) | 86 | struct machine *machine __maybe_unused) |
99 | { | 87 | { |
100 | return perf_event__repipe_synth(tool, event, machine); | 88 | return perf_event__repipe_synth(tool, event); |
101 | } | 89 | } |
102 | 90 | ||
103 | typedef int (*inject_handler)(struct perf_tool *tool, | 91 | typedef int (*inject_handler)(struct perf_tool *tool, |
@@ -119,7 +107,7 @@ static int perf_event__repipe_sample(struct perf_tool *tool, | |||
119 | 107 | ||
120 | build_id__mark_dso_hit(tool, event, sample, evsel, machine); | 108 | build_id__mark_dso_hit(tool, event, sample, evsel, machine); |
121 | 109 | ||
122 | return perf_event__repipe_synth(tool, event, machine); | 110 | return perf_event__repipe_synth(tool, event); |
123 | } | 111 | } |
124 | 112 | ||
125 | static int perf_event__repipe_mmap(struct perf_tool *tool, | 113 | static int perf_event__repipe_mmap(struct perf_tool *tool, |
@@ -148,13 +136,14 @@ static int perf_event__repipe_fork(struct perf_tool *tool, | |||
148 | return err; | 136 | return err; |
149 | } | 137 | } |
150 | 138 | ||
151 | static int perf_event__repipe_tracing_data(union perf_event *event, | 139 | static int perf_event__repipe_tracing_data(struct perf_tool *tool, |
140 | union perf_event *event, | ||
152 | struct perf_session *session) | 141 | struct perf_session *session) |
153 | { | 142 | { |
154 | int err; | 143 | int err; |
155 | 144 | ||
156 | perf_event__repipe_synth(NULL, event, NULL); | 145 | perf_event__repipe_synth(tool, event); |
157 | err = perf_event__process_tracing_data(event, session); | 146 | err = perf_event__process_tracing_data(tool, event, session); |
158 | 147 | ||
159 | return err; | 148 | return err; |
160 | } | 149 | } |
@@ -407,8 +396,8 @@ int cmd_inject(int argc, const char **argv, const char *prefix __maybe_unused) | |||
407 | .throttle = perf_event__repipe, | 396 | .throttle = perf_event__repipe, |
408 | .unthrottle = perf_event__repipe, | 397 | .unthrottle = perf_event__repipe, |
409 | .attr = perf_event__repipe_attr, | 398 | .attr = perf_event__repipe_attr, |
410 | .event_type = perf_event__repipe_event_type_synth, | 399 | .tracing_data = perf_event__repipe_op2_synth, |
411 | .tracing_data = perf_event__repipe_tracing_data_synth, | 400 | .finished_round = perf_event__repipe_op2_synth, |
412 | .build_id = perf_event__repipe_op2_synth, | 401 | .build_id = perf_event__repipe_op2_synth, |
413 | }, | 402 | }, |
414 | .input_name = "-", | 403 | .input_name = "-", |
diff --git a/tools/perf/builtin-kmem.c b/tools/perf/builtin-kmem.c index 0259502638b4..b49f5c58e152 100644 --- a/tools/perf/builtin-kmem.c +++ b/tools/perf/builtin-kmem.c | |||
@@ -313,7 +313,7 @@ static int process_sample_event(struct perf_tool *tool __maybe_unused, | |||
313 | return -1; | 313 | return -1; |
314 | } | 314 | } |
315 | 315 | ||
316 | dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid); | 316 | dump_printf(" ... thread: %s:%d\n", thread->comm, thread->tid); |
317 | 317 | ||
318 | if (evsel->handler.func != NULL) { | 318 | if (evsel->handler.func != NULL) { |
319 | tracepoint_handler f = evsel->handler.func; | 319 | tracepoint_handler f = evsel->handler.func; |
diff --git a/tools/perf/builtin-list.c b/tools/perf/builtin-list.c index 1948eceb517a..e79f423cc302 100644 --- a/tools/perf/builtin-list.c +++ b/tools/perf/builtin-list.c | |||
@@ -13,6 +13,7 @@ | |||
13 | 13 | ||
14 | #include "util/parse-events.h" | 14 | #include "util/parse-events.h" |
15 | #include "util/cache.h" | 15 | #include "util/cache.h" |
16 | #include "util/pmu.h" | ||
16 | 17 | ||
17 | int cmd_list(int argc, const char **argv, const char *prefix __maybe_unused) | 18 | int cmd_list(int argc, const char **argv, const char *prefix __maybe_unused) |
18 | { | 19 | { |
@@ -37,6 +38,8 @@ int cmd_list(int argc, const char **argv, const char *prefix __maybe_unused) | |||
37 | else if (strcmp(argv[i], "cache") == 0 || | 38 | else if (strcmp(argv[i], "cache") == 0 || |
38 | strcmp(argv[i], "hwcache") == 0) | 39 | strcmp(argv[i], "hwcache") == 0) |
39 | print_hwcache_events(NULL, false); | 40 | print_hwcache_events(NULL, false); |
41 | else if (strcmp(argv[i], "pmu") == 0) | ||
42 | print_pmu_events(NULL, false); | ||
40 | else if (strcmp(argv[i], "--raw-dump") == 0) | 43 | else if (strcmp(argv[i], "--raw-dump") == 0) |
41 | print_events(NULL, true); | 44 | print_events(NULL, true); |
42 | else { | 45 | else { |
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index ecca62e27b28..a41ac41546c9 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c | |||
@@ -474,13 +474,6 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv) | |||
474 | goto out_delete_session; | 474 | goto out_delete_session; |
475 | } | 475 | } |
476 | 476 | ||
477 | err = perf_event__synthesize_event_types(tool, process_synthesized_event, | ||
478 | machine); | ||
479 | if (err < 0) { | ||
480 | pr_err("Couldn't synthesize event_types.\n"); | ||
481 | goto out_delete_session; | ||
482 | } | ||
483 | |||
484 | if (have_tracepoints(&evsel_list->entries)) { | 477 | if (have_tracepoints(&evsel_list->entries)) { |
485 | /* | 478 | /* |
486 | * FIXME err <= 0 here actually means that | 479 | * FIXME err <= 0 here actually means that |
@@ -904,7 +897,6 @@ const struct option record_options[] = { | |||
904 | int cmd_record(int argc, const char **argv, const char *prefix __maybe_unused) | 897 | int cmd_record(int argc, const char **argv, const char *prefix __maybe_unused) |
905 | { | 898 | { |
906 | int err = -ENOMEM; | 899 | int err = -ENOMEM; |
907 | struct perf_evsel *pos; | ||
908 | struct perf_evlist *evsel_list; | 900 | struct perf_evlist *evsel_list; |
909 | struct perf_record *rec = &record; | 901 | struct perf_record *rec = &record; |
910 | char errbuf[BUFSIZ]; | 902 | char errbuf[BUFSIZ]; |
@@ -968,11 +960,6 @@ int cmd_record(int argc, const char **argv, const char *prefix __maybe_unused) | |||
968 | if (perf_evlist__create_maps(evsel_list, &rec->opts.target) < 0) | 960 | if (perf_evlist__create_maps(evsel_list, &rec->opts.target) < 0) |
969 | usage_with_options(record_usage, record_options); | 961 | usage_with_options(record_usage, record_options); |
970 | 962 | ||
971 | list_for_each_entry(pos, &evsel_list->entries, node) { | ||
972 | if (perf_header__push_event(pos->attr.config, perf_evsel__name(pos))) | ||
973 | goto out_free_fd; | ||
974 | } | ||
975 | |||
976 | if (rec->opts.user_interval != ULLONG_MAX) | 963 | if (rec->opts.user_interval != ULLONG_MAX) |
977 | rec->opts.default_interval = rec->opts.user_interval; | 964 | rec->opts.default_interval = rec->opts.user_interval; |
978 | if (rec->opts.user_freq != UINT_MAX) | 965 | if (rec->opts.user_freq != UINT_MAX) |
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index 3662047cc6b1..a34c587900c7 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c | |||
@@ -89,7 +89,7 @@ static int perf_report__add_mem_hist_entry(struct perf_tool *tool, | |||
89 | if ((sort__has_parent || symbol_conf.use_callchain) && | 89 | if ((sort__has_parent || symbol_conf.use_callchain) && |
90 | sample->callchain) { | 90 | sample->callchain) { |
91 | err = machine__resolve_callchain(machine, evsel, al->thread, | 91 | err = machine__resolve_callchain(machine, evsel, al->thread, |
92 | sample, &parent); | 92 | sample, &parent, al); |
93 | if (err) | 93 | if (err) |
94 | return err; | 94 | return err; |
95 | } | 95 | } |
@@ -180,7 +180,7 @@ static int perf_report__add_branch_hist_entry(struct perf_tool *tool, | |||
180 | if ((sort__has_parent || symbol_conf.use_callchain) | 180 | if ((sort__has_parent || symbol_conf.use_callchain) |
181 | && sample->callchain) { | 181 | && sample->callchain) { |
182 | err = machine__resolve_callchain(machine, evsel, al->thread, | 182 | err = machine__resolve_callchain(machine, evsel, al->thread, |
183 | sample, &parent); | 183 | sample, &parent, al); |
184 | if (err) | 184 | if (err) |
185 | return err; | 185 | return err; |
186 | } | 186 | } |
@@ -254,7 +254,7 @@ static int perf_evsel__add_hist_entry(struct perf_evsel *evsel, | |||
254 | 254 | ||
255 | if ((sort__has_parent || symbol_conf.use_callchain) && sample->callchain) { | 255 | if ((sort__has_parent || symbol_conf.use_callchain) && sample->callchain) { |
256 | err = machine__resolve_callchain(machine, evsel, al->thread, | 256 | err = machine__resolve_callchain(machine, evsel, al->thread, |
257 | sample, &parent); | 257 | sample, &parent, al); |
258 | if (err) | 258 | if (err) |
259 | return err; | 259 | return err; |
260 | } | 260 | } |
@@ -497,7 +497,7 @@ static int __cmd_report(struct perf_report *rep) | |||
497 | ret = perf_session__cpu_bitmap(session, rep->cpu_list, | 497 | ret = perf_session__cpu_bitmap(session, rep->cpu_list, |
498 | rep->cpu_bitmap); | 498 | rep->cpu_bitmap); |
499 | if (ret) | 499 | if (ret) |
500 | goto out_delete; | 500 | return ret; |
501 | } | 501 | } |
502 | 502 | ||
503 | if (use_browser <= 0) | 503 | if (use_browser <= 0) |
@@ -508,11 +508,11 @@ static int __cmd_report(struct perf_report *rep) | |||
508 | 508 | ||
509 | ret = perf_report__setup_sample_type(rep); | 509 | ret = perf_report__setup_sample_type(rep); |
510 | if (ret) | 510 | if (ret) |
511 | goto out_delete; | 511 | return ret; |
512 | 512 | ||
513 | ret = perf_session__process_events(session, &rep->tool); | 513 | ret = perf_session__process_events(session, &rep->tool); |
514 | if (ret) | 514 | if (ret) |
515 | goto out_delete; | 515 | return ret; |
516 | 516 | ||
517 | kernel_map = session->machines.host.vmlinux_maps[MAP__FUNCTION]; | 517 | kernel_map = session->machines.host.vmlinux_maps[MAP__FUNCTION]; |
518 | kernel_kmap = map__kmap(kernel_map); | 518 | kernel_kmap = map__kmap(kernel_map); |
@@ -547,7 +547,7 @@ static int __cmd_report(struct perf_report *rep) | |||
547 | 547 | ||
548 | if (dump_trace) { | 548 | if (dump_trace) { |
549 | perf_session__fprintf_nr_events(session, stdout); | 549 | perf_session__fprintf_nr_events(session, stdout); |
550 | goto out_delete; | 550 | return 0; |
551 | } | 551 | } |
552 | 552 | ||
553 | nr_samples = 0; | 553 | nr_samples = 0; |
@@ -572,7 +572,7 @@ static int __cmd_report(struct perf_report *rep) | |||
572 | 572 | ||
573 | if (nr_samples == 0) { | 573 | if (nr_samples == 0) { |
574 | ui__error("The %s file has no samples!\n", session->filename); | 574 | ui__error("The %s file has no samples!\n", session->filename); |
575 | goto out_delete; | 575 | return 0; |
576 | } | 576 | } |
577 | 577 | ||
578 | list_for_each_entry(pos, &session->evlist->entries, node) | 578 | list_for_each_entry(pos, &session->evlist->entries, node) |
@@ -598,19 +598,6 @@ static int __cmd_report(struct perf_report *rep) | |||
598 | } else | 598 | } else |
599 | perf_evlist__tty_browse_hists(session->evlist, rep, help); | 599 | perf_evlist__tty_browse_hists(session->evlist, rep, help); |
600 | 600 | ||
601 | out_delete: | ||
602 | /* | ||
603 | * Speed up the exit process, for large files this can | ||
604 | * take quite a while. | ||
605 | * | ||
606 | * XXX Enable this when using valgrind or if we ever | ||
607 | * librarize this command. | ||
608 | * | ||
609 | * Also experiment with obstacks to see how much speed | ||
610 | * up we'll get here. | ||
611 | * | ||
612 | * perf_session__delete(session); | ||
613 | */ | ||
614 | return ret; | 601 | return ret; |
615 | } | 602 | } |
616 | 603 | ||
@@ -694,6 +681,24 @@ setup: | |||
694 | return 0; | 681 | return 0; |
695 | } | 682 | } |
696 | 683 | ||
684 | int | ||
685 | report_parse_ignore_callees_opt(const struct option *opt __maybe_unused, | ||
686 | const char *arg, int unset __maybe_unused) | ||
687 | { | ||
688 | if (arg) { | ||
689 | int err = regcomp(&ignore_callees_regex, arg, REG_EXTENDED); | ||
690 | if (err) { | ||
691 | char buf[BUFSIZ]; | ||
692 | regerror(err, &ignore_callees_regex, buf, sizeof(buf)); | ||
693 | pr_err("Invalid --ignore-callees regex: %s\n%s", arg, buf); | ||
694 | return -1; | ||
695 | } | ||
696 | have_ignore_callees = 1; | ||
697 | } | ||
698 | |||
699 | return 0; | ||
700 | } | ||
701 | |||
697 | static int | 702 | static int |
698 | parse_branch_mode(const struct option *opt __maybe_unused, | 703 | parse_branch_mode(const struct option *opt __maybe_unused, |
699 | const char *str __maybe_unused, int unset) | 704 | const char *str __maybe_unused, int unset) |
@@ -736,7 +741,6 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused) | |||
736 | .lost = perf_event__process_lost, | 741 | .lost = perf_event__process_lost, |
737 | .read = process_read_event, | 742 | .read = process_read_event, |
738 | .attr = perf_event__process_attr, | 743 | .attr = perf_event__process_attr, |
739 | .event_type = perf_event__process_event_type, | ||
740 | .tracing_data = perf_event__process_tracing_data, | 744 | .tracing_data = perf_event__process_tracing_data, |
741 | .build_id = perf_event__process_build_id, | 745 | .build_id = perf_event__process_build_id, |
742 | .ordered_samples = true, | 746 | .ordered_samples = true, |
@@ -784,6 +788,9 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused) | |||
784 | "Default: fractal,0.5,callee", &parse_callchain_opt, callchain_default_opt), | 788 | "Default: fractal,0.5,callee", &parse_callchain_opt, callchain_default_opt), |
785 | OPT_BOOLEAN('G', "inverted", &report.inverted_callchain, | 789 | OPT_BOOLEAN('G', "inverted", &report.inverted_callchain, |
786 | "alias for inverted call graph"), | 790 | "alias for inverted call graph"), |
791 | OPT_CALLBACK(0, "ignore-callees", NULL, "regex", | ||
792 | "ignore callees of these functions in call graphs", | ||
793 | report_parse_ignore_callees_opt), | ||
787 | OPT_STRING('d', "dsos", &symbol_conf.dso_list_str, "dso[,dso...]", | 794 | OPT_STRING('d', "dsos", &symbol_conf.dso_list_str, "dso[,dso...]", |
788 | "only consider symbols in these dsos"), | 795 | "only consider symbols in these dsos"), |
789 | OPT_STRING('c', "comms", &symbol_conf.comm_list_str, "comm[,comm...]", | 796 | OPT_STRING('c', "comms", &symbol_conf.comm_list_str, "comm[,comm...]", |
@@ -853,7 +860,6 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused) | |||
853 | setup_browser(true); | 860 | setup_browser(true); |
854 | else { | 861 | else { |
855 | use_browser = 0; | 862 | use_browser = 0; |
856 | perf_hpp__column_enable(PERF_HPP__OVERHEAD); | ||
857 | perf_hpp__init(); | 863 | perf_hpp__init(); |
858 | } | 864 | } |
859 | 865 | ||
@@ -931,14 +937,6 @@ repeat: | |||
931 | if (parent_pattern != default_parent_pattern) { | 937 | if (parent_pattern != default_parent_pattern) { |
932 | if (sort_dimension__add("parent") < 0) | 938 | if (sort_dimension__add("parent") < 0) |
933 | goto error; | 939 | goto error; |
934 | |||
935 | /* | ||
936 | * Only show the parent fields if we explicitly | ||
937 | * sort that way. If we only use parent machinery | ||
938 | * for filtering, we don't want it. | ||
939 | */ | ||
940 | if (!strstr(sort_order, "parent")) | ||
941 | sort_parent.elide = 1; | ||
942 | } | 940 | } |
943 | 941 | ||
944 | if (argc) { | 942 | if (argc) { |
diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c index fed9ae432c16..948183adb6e5 100644 --- a/tools/perf/builtin-sched.c +++ b/tools/perf/builtin-sched.c | |||
@@ -1075,7 +1075,7 @@ static int latency_migrate_task_event(struct perf_sched *sched, | |||
1075 | if (!atoms) { | 1075 | if (!atoms) { |
1076 | if (thread_atoms_insert(sched, migrant)) | 1076 | if (thread_atoms_insert(sched, migrant)) |
1077 | return -1; | 1077 | return -1; |
1078 | register_pid(sched, migrant->pid, migrant->comm); | 1078 | register_pid(sched, migrant->tid, migrant->comm); |
1079 | atoms = thread_atoms_search(&sched->atom_root, migrant, &sched->cmp_pid); | 1079 | atoms = thread_atoms_search(&sched->atom_root, migrant, &sched->cmp_pid); |
1080 | if (!atoms) { | 1080 | if (!atoms) { |
1081 | pr_err("migration-event: Internal tree error"); | 1081 | pr_err("migration-event: Internal tree error"); |
@@ -1115,7 +1115,7 @@ static void output_lat_thread(struct perf_sched *sched, struct work_atoms *work_ | |||
1115 | sched->all_runtime += work_list->total_runtime; | 1115 | sched->all_runtime += work_list->total_runtime; |
1116 | sched->all_count += work_list->nb_atoms; | 1116 | sched->all_count += work_list->nb_atoms; |
1117 | 1117 | ||
1118 | ret = printf(" %s:%d ", work_list->thread->comm, work_list->thread->pid); | 1118 | ret = printf(" %s:%d ", work_list->thread->comm, work_list->thread->tid); |
1119 | 1119 | ||
1120 | for (i = 0; i < 24 - ret; i++) | 1120 | for (i = 0; i < 24 - ret; i++) |
1121 | printf(" "); | 1121 | printf(" "); |
@@ -1131,9 +1131,9 @@ static void output_lat_thread(struct perf_sched *sched, struct work_atoms *work_ | |||
1131 | 1131 | ||
1132 | static int pid_cmp(struct work_atoms *l, struct work_atoms *r) | 1132 | static int pid_cmp(struct work_atoms *l, struct work_atoms *r) |
1133 | { | 1133 | { |
1134 | if (l->thread->pid < r->thread->pid) | 1134 | if (l->thread->tid < r->thread->tid) |
1135 | return -1; | 1135 | return -1; |
1136 | if (l->thread->pid > r->thread->pid) | 1136 | if (l->thread->tid > r->thread->tid) |
1137 | return 1; | 1137 | return 1; |
1138 | 1138 | ||
1139 | return 0; | 1139 | return 0; |
@@ -1321,7 +1321,7 @@ static int map_switch_event(struct perf_sched *sched, struct perf_evsel *evsel, | |||
1321 | printf("*"); | 1321 | printf("*"); |
1322 | 1322 | ||
1323 | if (sched->curr_thread[cpu]) { | 1323 | if (sched->curr_thread[cpu]) { |
1324 | if (sched->curr_thread[cpu]->pid) | 1324 | if (sched->curr_thread[cpu]->tid) |
1325 | printf("%2s ", sched->curr_thread[cpu]->shortname); | 1325 | printf("%2s ", sched->curr_thread[cpu]->shortname); |
1326 | else | 1326 | else |
1327 | printf(". "); | 1327 | printf(". "); |
@@ -1332,7 +1332,7 @@ static int map_switch_event(struct perf_sched *sched, struct perf_evsel *evsel, | |||
1332 | printf(" %12.6f secs ", (double)timestamp/1e9); | 1332 | printf(" %12.6f secs ", (double)timestamp/1e9); |
1333 | if (new_shortname) { | 1333 | if (new_shortname) { |
1334 | printf("%s => %s:%d\n", | 1334 | printf("%s => %s:%d\n", |
1335 | sched_in->shortname, sched_in->comm, sched_in->pid); | 1335 | sched_in->shortname, sched_in->comm, sched_in->tid); |
1336 | } else { | 1336 | } else { |
1337 | printf("\n"); | 1337 | printf("\n"); |
1338 | } | 1338 | } |
@@ -1662,28 +1662,29 @@ static int __cmd_record(int argc, const char **argv) | |||
1662 | return cmd_record(i, rec_argv, NULL); | 1662 | return cmd_record(i, rec_argv, NULL); |
1663 | } | 1663 | } |
1664 | 1664 | ||
1665 | static const char default_sort_order[] = "avg, max, switch, runtime"; | ||
1666 | static struct perf_sched sched = { | ||
1667 | .tool = { | ||
1668 | .sample = perf_sched__process_tracepoint_sample, | ||
1669 | .comm = perf_event__process_comm, | ||
1670 | .lost = perf_event__process_lost, | ||
1671 | .fork = perf_event__process_fork, | ||
1672 | .ordered_samples = true, | ||
1673 | }, | ||
1674 | .cmp_pid = LIST_HEAD_INIT(sched.cmp_pid), | ||
1675 | .sort_list = LIST_HEAD_INIT(sched.sort_list), | ||
1676 | .start_work_mutex = PTHREAD_MUTEX_INITIALIZER, | ||
1677 | .work_done_wait_mutex = PTHREAD_MUTEX_INITIALIZER, | ||
1678 | .curr_pid = { [0 ... MAX_CPUS - 1] = -1 }, | ||
1679 | .sort_order = default_sort_order, | ||
1680 | .replay_repeat = 10, | ||
1681 | .profile_cpu = -1, | ||
1682 | .next_shortname1 = 'A', | ||
1683 | .next_shortname2 = '0', | ||
1684 | }; | ||
1685 | |||
1665 | int cmd_sched(int argc, const char **argv, const char *prefix __maybe_unused) | 1686 | int cmd_sched(int argc, const char **argv, const char *prefix __maybe_unused) |
1666 | { | 1687 | { |
1667 | const char default_sort_order[] = "avg, max, switch, runtime"; | ||
1668 | struct perf_sched sched = { | ||
1669 | .tool = { | ||
1670 | .sample = perf_sched__process_tracepoint_sample, | ||
1671 | .comm = perf_event__process_comm, | ||
1672 | .lost = perf_event__process_lost, | ||
1673 | .fork = perf_event__process_fork, | ||
1674 | .ordered_samples = true, | ||
1675 | }, | ||
1676 | .cmp_pid = LIST_HEAD_INIT(sched.cmp_pid), | ||
1677 | .sort_list = LIST_HEAD_INIT(sched.sort_list), | ||
1678 | .start_work_mutex = PTHREAD_MUTEX_INITIALIZER, | ||
1679 | .work_done_wait_mutex = PTHREAD_MUTEX_INITIALIZER, | ||
1680 | .curr_pid = { [0 ... MAX_CPUS - 1] = -1 }, | ||
1681 | .sort_order = default_sort_order, | ||
1682 | .replay_repeat = 10, | ||
1683 | .profile_cpu = -1, | ||
1684 | .next_shortname1 = 'A', | ||
1685 | .next_shortname2 = '0', | ||
1686 | }; | ||
1687 | const struct option latency_options[] = { | 1688 | const struct option latency_options[] = { |
1688 | OPT_STRING('s', "sort", &sched.sort_order, "key[,key2...]", | 1689 | OPT_STRING('s', "sort", &sched.sort_order, "key[,key2...]", |
1689 | "sort by key(s): runtime, switch, avg, max"), | 1690 | "sort by key(s): runtime, switch, avg, max"), |
diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c index 92d4658f56fb..ecb697998d3b 100644 --- a/tools/perf/builtin-script.c +++ b/tools/perf/builtin-script.c | |||
@@ -24,6 +24,7 @@ static u64 last_timestamp; | |||
24 | static u64 nr_unordered; | 24 | static u64 nr_unordered; |
25 | extern const struct option record_options[]; | 25 | extern const struct option record_options[]; |
26 | static bool no_callchain; | 26 | static bool no_callchain; |
27 | static bool latency_format; | ||
27 | static bool system_wide; | 28 | static bool system_wide; |
28 | static const char *cpu_list; | 29 | static const char *cpu_list; |
29 | static DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS); | 30 | static DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS); |
@@ -523,7 +524,6 @@ static struct perf_tool perf_script = { | |||
523 | .exit = perf_event__process_exit, | 524 | .exit = perf_event__process_exit, |
524 | .fork = perf_event__process_fork, | 525 | .fork = perf_event__process_fork, |
525 | .attr = perf_event__process_attr, | 526 | .attr = perf_event__process_attr, |
526 | .event_type = perf_event__process_event_type, | ||
527 | .tracing_data = perf_event__process_tracing_data, | 527 | .tracing_data = perf_event__process_tracing_data, |
528 | .build_id = perf_event__process_build_id, | 528 | .build_id = perf_event__process_build_id, |
529 | .ordered_samples = true, | 529 | .ordered_samples = true, |
diff --git a/tools/perf/builtin-timechart.c b/tools/perf/builtin-timechart.c index 4536a92b18f3..c2e02319347a 100644 --- a/tools/perf/builtin-timechart.c +++ b/tools/perf/builtin-timechart.c | |||
@@ -12,6 +12,8 @@ | |||
12 | * of the License. | 12 | * of the License. |
13 | */ | 13 | */ |
14 | 14 | ||
15 | #include <traceevent/event-parse.h> | ||
16 | |||
15 | #include "builtin.h" | 17 | #include "builtin.h" |
16 | 18 | ||
17 | #include "util/util.h" | 19 | #include "util/util.h" |
@@ -19,6 +21,7 @@ | |||
19 | #include "util/color.h" | 21 | #include "util/color.h" |
20 | #include <linux/list.h> | 22 | #include <linux/list.h> |
21 | #include "util/cache.h" | 23 | #include "util/cache.h" |
24 | #include "util/evlist.h" | ||
22 | #include "util/evsel.h" | 25 | #include "util/evsel.h" |
23 | #include <linux/rbtree.h> | 26 | #include <linux/rbtree.h> |
24 | #include "util/symbol.h" | 27 | #include "util/symbol.h" |
@@ -328,25 +331,6 @@ struct wakeup_entry { | |||
328 | int success; | 331 | int success; |
329 | }; | 332 | }; |
330 | 333 | ||
331 | /* | ||
332 | * trace_flag_type is an enumeration that holds different | ||
333 | * states when a trace occurs. These are: | ||
334 | * IRQS_OFF - interrupts were disabled | ||
335 | * IRQS_NOSUPPORT - arch does not support irqs_disabled_flags | ||
336 | * NEED_RESCED - reschedule is requested | ||
337 | * HARDIRQ - inside an interrupt handler | ||
338 | * SOFTIRQ - inside a softirq handler | ||
339 | */ | ||
340 | enum trace_flag_type { | ||
341 | TRACE_FLAG_IRQS_OFF = 0x01, | ||
342 | TRACE_FLAG_IRQS_NOSUPPORT = 0x02, | ||
343 | TRACE_FLAG_NEED_RESCHED = 0x04, | ||
344 | TRACE_FLAG_HARDIRQ = 0x08, | ||
345 | TRACE_FLAG_SOFTIRQ = 0x10, | ||
346 | }; | ||
347 | |||
348 | |||
349 | |||
350 | struct sched_switch { | 334 | struct sched_switch { |
351 | struct trace_entry te; | 335 | struct trace_entry te; |
352 | char prev_comm[TASK_COMM_LEN]; | 336 | char prev_comm[TASK_COMM_LEN]; |
@@ -479,6 +463,8 @@ static void sched_switch(int cpu, u64 timestamp, struct trace_entry *te) | |||
479 | } | 463 | } |
480 | } | 464 | } |
481 | 465 | ||
466 | typedef int (*tracepoint_handler)(struct perf_evsel *evsel, | ||
467 | struct perf_sample *sample); | ||
482 | 468 | ||
483 | static int process_sample_event(struct perf_tool *tool __maybe_unused, | 469 | static int process_sample_event(struct perf_tool *tool __maybe_unused, |
484 | union perf_event *event __maybe_unused, | 470 | union perf_event *event __maybe_unused, |
@@ -486,8 +472,6 @@ static int process_sample_event(struct perf_tool *tool __maybe_unused, | |||
486 | struct perf_evsel *evsel, | 472 | struct perf_evsel *evsel, |
487 | struct machine *machine __maybe_unused) | 473 | struct machine *machine __maybe_unused) |
488 | { | 474 | { |
489 | struct trace_entry *te; | ||
490 | |||
491 | if (evsel->attr.sample_type & PERF_SAMPLE_TIME) { | 475 | if (evsel->attr.sample_type & PERF_SAMPLE_TIME) { |
492 | if (!first_time || first_time > sample->time) | 476 | if (!first_time || first_time > sample->time) |
493 | first_time = sample->time; | 477 | first_time = sample->time; |
@@ -495,69 +479,90 @@ static int process_sample_event(struct perf_tool *tool __maybe_unused, | |||
495 | last_time = sample->time; | 479 | last_time = sample->time; |
496 | } | 480 | } |
497 | 481 | ||
498 | te = (void *)sample->raw_data; | 482 | if (sample->cpu > numcpus) |
499 | if ((evsel->attr.sample_type & PERF_SAMPLE_RAW) && sample->raw_size > 0) { | 483 | numcpus = sample->cpu; |
500 | char *event_str; | 484 | |
501 | #ifdef SUPPORT_OLD_POWER_EVENTS | 485 | if (evsel->handler.func != NULL) { |
502 | struct power_entry_old *peo; | 486 | tracepoint_handler f = evsel->handler.func; |
503 | peo = (void *)te; | 487 | return f(evsel, sample); |
504 | #endif | 488 | } |
505 | /* | 489 | |
506 | * FIXME: use evsel, its already mapped from id to perf_evsel, | 490 | return 0; |
507 | * remove perf_header__find_event infrastructure bits. | 491 | } |
508 | * Mapping all these "power:cpu_idle" strings to the tracepoint | 492 | |
509 | * ID and then just comparing against evsel->attr.config. | 493 | static int |
510 | * | 494 | process_sample_cpu_idle(struct perf_evsel *evsel __maybe_unused, |
511 | * e.g.: | 495 | struct perf_sample *sample) |
512 | * | 496 | { |
513 | * if (evsel->attr.config == power_cpu_idle_id) | 497 | struct power_processor_entry *ppe = sample->raw_data; |
514 | */ | 498 | |
515 | event_str = perf_header__find_event(te->type); | 499 | if (ppe->state == (u32) PWR_EVENT_EXIT) |
516 | 500 | c_state_end(ppe->cpu_id, sample->time); | |
517 | if (!event_str) | 501 | else |
518 | return 0; | 502 | c_state_start(ppe->cpu_id, sample->time, ppe->state); |
519 | 503 | return 0; | |
520 | if (sample->cpu > numcpus) | 504 | } |
521 | numcpus = sample->cpu; | 505 | |
522 | 506 | static int | |
523 | if (strcmp(event_str, "power:cpu_idle") == 0) { | 507 | process_sample_cpu_frequency(struct perf_evsel *evsel __maybe_unused, |
524 | struct power_processor_entry *ppe = (void *)te; | 508 | struct perf_sample *sample) |
525 | if (ppe->state == (u32)PWR_EVENT_EXIT) | 509 | { |
526 | c_state_end(ppe->cpu_id, sample->time); | 510 | struct power_processor_entry *ppe = sample->raw_data; |
527 | else | 511 | |
528 | c_state_start(ppe->cpu_id, sample->time, | 512 | p_state_change(ppe->cpu_id, sample->time, ppe->state); |
529 | ppe->state); | 513 | return 0; |
530 | } | 514 | } |
531 | else if (strcmp(event_str, "power:cpu_frequency") == 0) { | 515 | |
532 | struct power_processor_entry *ppe = (void *)te; | 516 | static int |
533 | p_state_change(ppe->cpu_id, sample->time, ppe->state); | 517 | process_sample_sched_wakeup(struct perf_evsel *evsel __maybe_unused, |
534 | } | 518 | struct perf_sample *sample) |
519 | { | ||
520 | struct trace_entry *te = sample->raw_data; | ||
521 | |||
522 | sched_wakeup(sample->cpu, sample->time, sample->pid, te); | ||
523 | return 0; | ||
524 | } | ||
535 | 525 | ||
536 | else if (strcmp(event_str, "sched:sched_wakeup") == 0) | 526 | static int |
537 | sched_wakeup(sample->cpu, sample->time, sample->pid, te); | 527 | process_sample_sched_switch(struct perf_evsel *evsel __maybe_unused, |
528 | struct perf_sample *sample) | ||
529 | { | ||
530 | struct trace_entry *te = sample->raw_data; | ||
538 | 531 | ||
539 | else if (strcmp(event_str, "sched:sched_switch") == 0) | 532 | sched_switch(sample->cpu, sample->time, te); |
540 | sched_switch(sample->cpu, sample->time, te); | 533 | return 0; |
534 | } | ||
541 | 535 | ||
542 | #ifdef SUPPORT_OLD_POWER_EVENTS | 536 | #ifdef SUPPORT_OLD_POWER_EVENTS |
543 | if (use_old_power_events) { | 537 | static int |
544 | if (strcmp(event_str, "power:power_start") == 0) | 538 | process_sample_power_start(struct perf_evsel *evsel __maybe_unused, |
545 | c_state_start(peo->cpu_id, sample->time, | 539 | struct perf_sample *sample) |
546 | peo->value); | 540 | { |
547 | 541 | struct power_entry_old *peo = sample->raw_data; | |
548 | else if (strcmp(event_str, "power:power_end") == 0) | 542 | |
549 | c_state_end(sample->cpu, sample->time); | 543 | c_state_start(peo->cpu_id, sample->time, peo->value); |
550 | |||
551 | else if (strcmp(event_str, | ||
552 | "power:power_frequency") == 0) | ||
553 | p_state_change(peo->cpu_id, sample->time, | ||
554 | peo->value); | ||
555 | } | ||
556 | #endif | ||
557 | } | ||
558 | return 0; | 544 | return 0; |
559 | } | 545 | } |
560 | 546 | ||
547 | static int | ||
548 | process_sample_power_end(struct perf_evsel *evsel __maybe_unused, | ||
549 | struct perf_sample *sample) | ||
550 | { | ||
551 | c_state_end(sample->cpu, sample->time); | ||
552 | return 0; | ||
553 | } | ||
554 | |||
555 | static int | ||
556 | process_sample_power_frequency(struct perf_evsel *evsel __maybe_unused, | ||
557 | struct perf_sample *sample) | ||
558 | { | ||
559 | struct power_entry_old *peo = sample->raw_data; | ||
560 | |||
561 | p_state_change(peo->cpu_id, sample->time, peo->value); | ||
562 | return 0; | ||
563 | } | ||
564 | #endif /* SUPPORT_OLD_POWER_EVENTS */ | ||
565 | |||
561 | /* | 566 | /* |
562 | * After the last sample we need to wrap up the current C/P state | 567 | * After the last sample we need to wrap up the current C/P state |
563 | * and close out each CPU for these. | 568 | * and close out each CPU for these. |
@@ -974,6 +979,17 @@ static int __cmd_timechart(const char *output_name) | |||
974 | .sample = process_sample_event, | 979 | .sample = process_sample_event, |
975 | .ordered_samples = true, | 980 | .ordered_samples = true, |
976 | }; | 981 | }; |
982 | const struct perf_evsel_str_handler power_tracepoints[] = { | ||
983 | { "power:cpu_idle", process_sample_cpu_idle }, | ||
984 | { "power:cpu_frequency", process_sample_cpu_frequency }, | ||
985 | { "sched:sched_wakeup", process_sample_sched_wakeup }, | ||
986 | { "sched:sched_switch", process_sample_sched_switch }, | ||
987 | #ifdef SUPPORT_OLD_POWER_EVENTS | ||
988 | { "power:power_start", process_sample_power_start }, | ||
989 | { "power:power_end", process_sample_power_end }, | ||
990 | { "power:power_frequency", process_sample_power_frequency }, | ||
991 | #endif | ||
992 | }; | ||
977 | struct perf_session *session = perf_session__new(input_name, O_RDONLY, | 993 | struct perf_session *session = perf_session__new(input_name, O_RDONLY, |
978 | 0, false, &perf_timechart); | 994 | 0, false, &perf_timechart); |
979 | int ret = -EINVAL; | 995 | int ret = -EINVAL; |
@@ -984,6 +1000,12 @@ static int __cmd_timechart(const char *output_name) | |||
984 | if (!perf_session__has_traces(session, "timechart record")) | 1000 | if (!perf_session__has_traces(session, "timechart record")) |
985 | goto out_delete; | 1001 | goto out_delete; |
986 | 1002 | ||
1003 | if (perf_session__set_tracepoints_handlers(session, | ||
1004 | power_tracepoints)) { | ||
1005 | pr_err("Initializing session tracepoint handlers failed\n"); | ||
1006 | goto out_delete; | ||
1007 | } | ||
1008 | |||
987 | ret = perf_session__process_events(session, &perf_timechart); | 1009 | ret = perf_session__process_events(session, &perf_timechart); |
988 | if (ret) | 1010 | if (ret) |
989 | goto out_delete; | 1011 | goto out_delete; |
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index e06c4f869330..bbf463572777 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c | |||
@@ -40,6 +40,7 @@ | |||
40 | #include "util/xyarray.h" | 40 | #include "util/xyarray.h" |
41 | #include "util/sort.h" | 41 | #include "util/sort.h" |
42 | #include "util/intlist.h" | 42 | #include "util/intlist.h" |
43 | #include "arch/common.h" | ||
43 | 44 | ||
44 | #include "util/debug.h" | 45 | #include "util/debug.h" |
45 | 46 | ||
@@ -772,8 +773,7 @@ static void perf_event__process_sample(struct perf_tool *tool, | |||
772 | sample->callchain) { | 773 | sample->callchain) { |
773 | err = machine__resolve_callchain(machine, evsel, | 774 | err = machine__resolve_callchain(machine, evsel, |
774 | al.thread, sample, | 775 | al.thread, sample, |
775 | &parent); | 776 | &parent, &al); |
776 | |||
777 | if (err) | 777 | if (err) |
778 | return; | 778 | return; |
779 | } | 779 | } |
@@ -939,6 +939,12 @@ static int __cmd_top(struct perf_top *top) | |||
939 | if (top->session == NULL) | 939 | if (top->session == NULL) |
940 | return -ENOMEM; | 940 | return -ENOMEM; |
941 | 941 | ||
942 | if (!objdump_path) { | ||
943 | ret = perf_session_env__lookup_objdump(&top->session->header.env); | ||
944 | if (ret) | ||
945 | goto out_delete; | ||
946 | } | ||
947 | |||
942 | ret = perf_top__setup_sample_type(top); | 948 | ret = perf_top__setup_sample_type(top); |
943 | if (ret) | 949 | if (ret) |
944 | goto out_delete; | 950 | goto out_delete; |
@@ -1102,6 +1108,9 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused) | |||
1102 | OPT_CALLBACK_DEFAULT('G', "call-graph", &top.record_opts, | 1108 | OPT_CALLBACK_DEFAULT('G', "call-graph", &top.record_opts, |
1103 | "mode[,dump_size]", record_callchain_help, | 1109 | "mode[,dump_size]", record_callchain_help, |
1104 | &parse_callchain_opt, "fp"), | 1110 | &parse_callchain_opt, "fp"), |
1111 | OPT_CALLBACK(0, "ignore-callees", NULL, "regex", | ||
1112 | "ignore callees of these functions in call graphs", | ||
1113 | report_parse_ignore_callees_opt), | ||
1105 | OPT_BOOLEAN(0, "show-total-period", &symbol_conf.show_total_period, | 1114 | OPT_BOOLEAN(0, "show-total-period", &symbol_conf.show_total_period, |
1106 | "Show a column with the sum of periods"), | 1115 | "Show a column with the sum of periods"), |
1107 | OPT_STRING(0, "dsos", &symbol_conf.dso_list_str, "dso[,dso...]", | 1116 | OPT_STRING(0, "dsos", &symbol_conf.dso_list_str, "dso[,dso...]", |
@@ -1114,6 +1123,8 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused) | |||
1114 | "Interleave source code with assembly code (default)"), | 1123 | "Interleave source code with assembly code (default)"), |
1115 | OPT_BOOLEAN(0, "asm-raw", &symbol_conf.annotate_asm_raw, | 1124 | OPT_BOOLEAN(0, "asm-raw", &symbol_conf.annotate_asm_raw, |
1116 | "Display raw encoding of assembly instructions (default)"), | 1125 | "Display raw encoding of assembly instructions (default)"), |
1126 | OPT_STRING(0, "objdump", &objdump_path, "path", | ||
1127 | "objdump binary to use for disassembly and annotations"), | ||
1117 | OPT_STRING('M', "disassembler-style", &disassembler_style, "disassembler style", | 1128 | OPT_STRING('M', "disassembler-style", &disassembler_style, "disassembler style", |
1118 | "Specify disassembler style (e.g. -M intel for intel syntax)"), | 1129 | "Specify disassembler style (e.g. -M intel for intel syntax)"), |
1119 | OPT_STRING('u', "uid", &target->uid_str, "user", "user to profile"), | 1130 | OPT_STRING('u', "uid", &target->uid_str, "user", "user to profile"), |
diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c index ab3ed4af1466..0e4b67f6bbd1 100644 --- a/tools/perf/builtin-trace.c +++ b/tools/perf/builtin-trace.c | |||
@@ -1,3 +1,4 @@ | |||
1 | #include <traceevent/event-parse.h> | ||
1 | #include "builtin.h" | 2 | #include "builtin.h" |
2 | #include "util/color.h" | 3 | #include "util/color.h" |
3 | #include "util/evlist.h" | 4 | #include "util/evlist.h" |
@@ -5,7 +6,6 @@ | |||
5 | #include "util/thread.h" | 6 | #include "util/thread.h" |
6 | #include "util/parse-options.h" | 7 | #include "util/parse-options.h" |
7 | #include "util/thread_map.h" | 8 | #include "util/thread_map.h" |
8 | #include "event-parse.h" | ||
9 | 9 | ||
10 | #include <libaudit.h> | 10 | #include <libaudit.h> |
11 | #include <stdlib.h> | 11 | #include <stdlib.h> |
@@ -142,7 +142,7 @@ static size_t trace__fprintf_entry_head(struct trace *trace, struct thread *thre | |||
142 | printed += fprintf_duration(duration, fp); | 142 | printed += fprintf_duration(duration, fp); |
143 | 143 | ||
144 | if (trace->multiple_threads) | 144 | if (trace->multiple_threads) |
145 | printed += fprintf(fp, "%d ", thread->pid); | 145 | printed += fprintf(fp, "%d ", thread->tid); |
146 | 146 | ||
147 | return printed; | 147 | return printed; |
148 | } | 148 | } |
@@ -593,7 +593,7 @@ static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp) | |||
593 | color = PERF_COLOR_YELLOW; | 593 | color = PERF_COLOR_YELLOW; |
594 | 594 | ||
595 | printed += color_fprintf(fp, color, "%20s", thread->comm); | 595 | printed += color_fprintf(fp, color, "%20s", thread->comm); |
596 | printed += fprintf(fp, " - %-5d :%11lu [", thread->pid, ttrace->nr_events); | 596 | printed += fprintf(fp, " - %-5d :%11lu [", thread->tid, ttrace->nr_events); |
597 | printed += color_fprintf(fp, color, "%5.1f%%", ratio); | 597 | printed += color_fprintf(fp, color, "%5.1f%%", ratio); |
598 | printed += fprintf(fp, " ] %10.3f ms\n", ttrace->runtime_ms); | 598 | printed += fprintf(fp, " ] %10.3f ms\n", ttrace->runtime_ms); |
599 | } | 599 | } |
diff --git a/tools/perf/config/Makefile b/tools/perf/config/Makefile index b5d9238cb181..214e17e97e5c 100644 --- a/tools/perf/config/Makefile +++ b/tools/perf/config/Makefile | |||
@@ -46,6 +46,8 @@ ifneq ($(obj-perf),) | |||
46 | obj-perf := $(abspath $(obj-perf))/ | 46 | obj-perf := $(abspath $(obj-perf))/ |
47 | endif | 47 | endif |
48 | 48 | ||
49 | LIB_INCLUDE := $(srctree)/tools/lib/ | ||
50 | |||
49 | # include ARCH specific config | 51 | # include ARCH specific config |
50 | -include $(src-perf)/arch/$(ARCH)/Makefile | 52 | -include $(src-perf)/arch/$(ARCH)/Makefile |
51 | 53 | ||
@@ -121,8 +123,7 @@ endif | |||
121 | 123 | ||
122 | CFLAGS += -I$(src-perf)/util | 124 | CFLAGS += -I$(src-perf)/util |
123 | CFLAGS += -I$(src-perf) | 125 | CFLAGS += -I$(src-perf) |
124 | CFLAGS += -I$(TRACE_EVENT_DIR) | 126 | CFLAGS += -I$(LIB_INCLUDE) |
125 | CFLAGS += -I$(srctree)/tools/lib/ | ||
126 | 127 | ||
127 | CFLAGS += -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE | 128 | CFLAGS += -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE |
128 | 129 | ||
diff --git a/tools/perf/tests/dso-data.c b/tools/perf/tests/dso-data.c index 5eaffa2de9c5..dffe0551acaa 100644 --- a/tools/perf/tests/dso-data.c +++ b/tools/perf/tests/dso-data.c | |||
@@ -10,14 +10,6 @@ | |||
10 | #include "symbol.h" | 10 | #include "symbol.h" |
11 | #include "tests.h" | 11 | #include "tests.h" |
12 | 12 | ||
13 | #define TEST_ASSERT_VAL(text, cond) \ | ||
14 | do { \ | ||
15 | if (!(cond)) { \ | ||
16 | pr_debug("FAILED %s:%d %s\n", __FILE__, __LINE__, text); \ | ||
17 | return -1; \ | ||
18 | } \ | ||
19 | } while (0) | ||
20 | |||
21 | static char *test_file(int size) | 13 | static char *test_file(int size) |
22 | { | 14 | { |
23 | static char buf_templ[] = "/tmp/test-XXXXXX"; | 15 | static char buf_templ[] = "/tmp/test-XXXXXX"; |
diff --git a/tools/perf/tests/evsel-tp-sched.c b/tools/perf/tests/evsel-tp-sched.c index a5d2fcc5ae35..9b98c1554833 100644 --- a/tools/perf/tests/evsel-tp-sched.c +++ b/tools/perf/tests/evsel-tp-sched.c | |||
@@ -1,6 +1,6 @@ | |||
1 | #include <traceevent/event-parse.h> | ||
1 | #include "evsel.h" | 2 | #include "evsel.h" |
2 | #include "tests.h" | 3 | #include "tests.h" |
3 | #include "event-parse.h" | ||
4 | 4 | ||
5 | static int perf_evsel__test_field(struct perf_evsel *evsel, const char *name, | 5 | static int perf_evsel__test_field(struct perf_evsel *evsel, const char *name, |
6 | int size, bool should_be_signed) | 6 | int size, bool should_be_signed) |
@@ -49,7 +49,7 @@ int test__perf_evsel__tp_sched_test(void) | |||
49 | if (perf_evsel__test_field(evsel, "prev_prio", 4, true)) | 49 | if (perf_evsel__test_field(evsel, "prev_prio", 4, true)) |
50 | ret = -1; | 50 | ret = -1; |
51 | 51 | ||
52 | if (perf_evsel__test_field(evsel, "prev_state", 8, true)) | 52 | if (perf_evsel__test_field(evsel, "prev_state", sizeof(long), true)) |
53 | ret = -1; | 53 | ret = -1; |
54 | 54 | ||
55 | if (perf_evsel__test_field(evsel, "next_comm", 16, true)) | 55 | if (perf_evsel__test_field(evsel, "next_comm", 16, true)) |
diff --git a/tools/perf/tests/parse-events.c b/tools/perf/tests/parse-events.c index 0275bab4ea9e..344c844ffc1e 100644 --- a/tools/perf/tests/parse-events.c +++ b/tools/perf/tests/parse-events.c | |||
@@ -7,14 +7,6 @@ | |||
7 | #include "tests.h" | 7 | #include "tests.h" |
8 | #include <linux/hw_breakpoint.h> | 8 | #include <linux/hw_breakpoint.h> |
9 | 9 | ||
10 | #define TEST_ASSERT_VAL(text, cond) \ | ||
11 | do { \ | ||
12 | if (!(cond)) { \ | ||
13 | pr_debug("FAILED %s:%d %s\n", __FILE__, __LINE__, text); \ | ||
14 | return -1; \ | ||
15 | } \ | ||
16 | } while (0) | ||
17 | |||
18 | #define PERF_TP_SAMPLE_TYPE (PERF_SAMPLE_RAW | PERF_SAMPLE_TIME | \ | 10 | #define PERF_TP_SAMPLE_TYPE (PERF_SAMPLE_RAW | PERF_SAMPLE_TIME | \ |
19 | PERF_SAMPLE_CPU | PERF_SAMPLE_PERIOD) | 11 | PERF_SAMPLE_CPU | PERF_SAMPLE_PERIOD) |
20 | 12 | ||
@@ -1254,24 +1246,20 @@ static int test_events(struct evlist_test *events, unsigned cnt) | |||
1254 | 1246 | ||
1255 | static int test_term(struct terms_test *t) | 1247 | static int test_term(struct terms_test *t) |
1256 | { | 1248 | { |
1257 | struct list_head *terms; | 1249 | struct list_head terms; |
1258 | int ret; | 1250 | int ret; |
1259 | 1251 | ||
1260 | terms = malloc(sizeof(*terms)); | 1252 | INIT_LIST_HEAD(&terms); |
1261 | if (!terms) | ||
1262 | return -ENOMEM; | ||
1263 | |||
1264 | INIT_LIST_HEAD(terms); | ||
1265 | 1253 | ||
1266 | ret = parse_events_terms(terms, t->str); | 1254 | ret = parse_events_terms(&terms, t->str); |
1267 | if (ret) { | 1255 | if (ret) { |
1268 | pr_debug("failed to parse terms '%s', err %d\n", | 1256 | pr_debug("failed to parse terms '%s', err %d\n", |
1269 | t->str , ret); | 1257 | t->str , ret); |
1270 | return ret; | 1258 | return ret; |
1271 | } | 1259 | } |
1272 | 1260 | ||
1273 | ret = t->check(terms); | 1261 | ret = t->check(&terms); |
1274 | parse_events__free_terms(terms); | 1262 | parse_events__free_terms(&terms); |
1275 | 1263 | ||
1276 | return ret; | 1264 | return ret; |
1277 | } | 1265 | } |
diff --git a/tools/perf/tests/tests.h b/tools/perf/tests/tests.h index dd7feae2d37b..07a92f9c6712 100644 --- a/tools/perf/tests/tests.h +++ b/tools/perf/tests/tests.h | |||
@@ -1,6 +1,14 @@ | |||
1 | #ifndef TESTS_H | 1 | #ifndef TESTS_H |
2 | #define TESTS_H | 2 | #define TESTS_H |
3 | 3 | ||
4 | #define TEST_ASSERT_VAL(text, cond) \ | ||
5 | do { \ | ||
6 | if (!(cond)) { \ | ||
7 | pr_debug("FAILED %s:%d %s\n", __FILE__, __LINE__, text); \ | ||
8 | return -1; \ | ||
9 | } \ | ||
10 | } while (0) | ||
11 | |||
4 | enum { | 12 | enum { |
5 | TEST_OK = 0, | 13 | TEST_OK = 0, |
6 | TEST_FAIL = -1, | 14 | TEST_FAIL = -1, |
diff --git a/tools/perf/tests/vmlinux-kallsyms.c b/tools/perf/tests/vmlinux-kallsyms.c index 7b4c4d26d1ba..add15392c622 100644 --- a/tools/perf/tests/vmlinux-kallsyms.c +++ b/tools/perf/tests/vmlinux-kallsyms.c | |||
@@ -139,11 +139,18 @@ next_pair: | |||
139 | * _really_ have a problem. | 139 | * _really_ have a problem. |
140 | */ | 140 | */ |
141 | s64 skew = sym->end - pair->end; | 141 | s64 skew = sym->end - pair->end; |
142 | if (llabs(skew) < page_size) | 142 | if (llabs(skew) >= page_size) |
143 | continue; | 143 | pr_debug("%#" PRIx64 ": diff end addr for %s v: %#" PRIx64 " k: %#" PRIx64 "\n", |
144 | sym->start, sym->name, sym->end, pair->end); | ||
145 | |||
146 | /* | ||
147 | * Do not count this as a failure, because we | ||
148 | * could really find a case where it's not | ||
149 | * possible to get proper function end from | ||
150 | * kallsyms. | ||
151 | */ | ||
152 | continue; | ||
144 | 153 | ||
145 | pr_debug("%#" PRIx64 ": diff end addr for %s v: %#" PRIx64 " k: %#" PRIx64 "\n", | ||
146 | sym->start, sym->name, sym->end, pair->end); | ||
147 | } else { | 154 | } else { |
148 | struct rb_node *nnd; | 155 | struct rb_node *nnd; |
149 | detour: | 156 | detour: |
diff --git a/tools/perf/ui/browsers/hists.c b/tools/perf/ui/browsers/hists.c index fc0bd3843d34..7ef36c360471 100644 --- a/tools/perf/ui/browsers/hists.c +++ b/tools/perf/ui/browsers/hists.c | |||
@@ -685,8 +685,10 @@ static u64 __hpp_get_##_field(struct hist_entry *he) \ | |||
685 | return he->stat._field; \ | 685 | return he->stat._field; \ |
686 | } \ | 686 | } \ |
687 | \ | 687 | \ |
688 | static int hist_browser__hpp_color_##_type(struct perf_hpp *hpp, \ | 688 | static int \ |
689 | struct hist_entry *he) \ | 689 | hist_browser__hpp_color_##_type(struct perf_hpp_fmt *fmt __maybe_unused,\ |
690 | struct perf_hpp *hpp, \ | ||
691 | struct hist_entry *he) \ | ||
690 | { \ | 692 | { \ |
691 | return __hpp__color_fmt(hpp, he, __hpp_get_##_field, _cb); \ | 693 | return __hpp__color_fmt(hpp, he, __hpp_get_##_field, _cb); \ |
692 | } | 694 | } |
@@ -701,8 +703,6 @@ __HPP_COLOR_PERCENT_FN(overhead_guest_us, period_guest_us, NULL) | |||
701 | 703 | ||
702 | void hist_browser__init_hpp(void) | 704 | void hist_browser__init_hpp(void) |
703 | { | 705 | { |
704 | perf_hpp__column_enable(PERF_HPP__OVERHEAD); | ||
705 | |||
706 | perf_hpp__init(); | 706 | perf_hpp__init(); |
707 | 707 | ||
708 | perf_hpp__format[PERF_HPP__OVERHEAD].color = | 708 | perf_hpp__format[PERF_HPP__OVERHEAD].color = |
@@ -762,9 +762,9 @@ static int hist_browser__show_entry(struct hist_browser *browser, | |||
762 | first = false; | 762 | first = false; |
763 | 763 | ||
764 | if (fmt->color) { | 764 | if (fmt->color) { |
765 | width -= fmt->color(&hpp, entry); | 765 | width -= fmt->color(fmt, &hpp, entry); |
766 | } else { | 766 | } else { |
767 | width -= fmt->entry(&hpp, entry); | 767 | width -= fmt->entry(fmt, &hpp, entry); |
768 | slsmg_printf("%s", s); | 768 | slsmg_printf("%s", s); |
769 | } | 769 | } |
770 | } | 770 | } |
@@ -1256,7 +1256,7 @@ static int hists__browser_title(struct hists *hists, char *bf, size_t size, | |||
1256 | printed += scnprintf(bf + printed, size - printed, | 1256 | printed += scnprintf(bf + printed, size - printed, |
1257 | ", Thread: %s(%d)", | 1257 | ", Thread: %s(%d)", |
1258 | (thread->comm_set ? thread->comm : ""), | 1258 | (thread->comm_set ? thread->comm : ""), |
1259 | thread->pid); | 1259 | thread->tid); |
1260 | if (dso) | 1260 | if (dso) |
1261 | printed += scnprintf(bf + printed, size - printed, | 1261 | printed += scnprintf(bf + printed, size - printed, |
1262 | ", DSO: %s", dso->short_name); | 1262 | ", DSO: %s", dso->short_name); |
@@ -1579,7 +1579,7 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events, | |||
1579 | asprintf(&options[nr_options], "Zoom %s %s(%d) thread", | 1579 | asprintf(&options[nr_options], "Zoom %s %s(%d) thread", |
1580 | (browser->hists->thread_filter ? "out of" : "into"), | 1580 | (browser->hists->thread_filter ? "out of" : "into"), |
1581 | (thread->comm_set ? thread->comm : ""), | 1581 | (thread->comm_set ? thread->comm : ""), |
1582 | thread->pid) > 0) | 1582 | thread->tid) > 0) |
1583 | zoom_thread = nr_options++; | 1583 | zoom_thread = nr_options++; |
1584 | 1584 | ||
1585 | if (dso != NULL && | 1585 | if (dso != NULL && |
@@ -1702,7 +1702,7 @@ zoom_out_thread: | |||
1702 | } else { | 1702 | } else { |
1703 | ui_helpline__fpush("To zoom out press <- or -> + \"Zoom out of %s(%d) thread\"", | 1703 | ui_helpline__fpush("To zoom out press <- or -> + \"Zoom out of %s(%d) thread\"", |
1704 | thread->comm_set ? thread->comm : "", | 1704 | thread->comm_set ? thread->comm : "", |
1705 | thread->pid); | 1705 | thread->tid); |
1706 | browser->hists->thread_filter = thread; | 1706 | browser->hists->thread_filter = thread; |
1707 | sort_thread.elide = true; | 1707 | sort_thread.elide = true; |
1708 | pstack__push(fstack, &browser->hists->thread_filter); | 1708 | pstack__push(fstack, &browser->hists->thread_filter); |
diff --git a/tools/perf/ui/gtk/hists.c b/tools/perf/ui/gtk/hists.c index 9708dd5fb8f3..cb2ed1980147 100644 --- a/tools/perf/ui/gtk/hists.c +++ b/tools/perf/ui/gtk/hists.c | |||
@@ -91,7 +91,8 @@ static u64 he_get_##_field(struct hist_entry *he) \ | |||
91 | return he->stat._field; \ | 91 | return he->stat._field; \ |
92 | } \ | 92 | } \ |
93 | \ | 93 | \ |
94 | static int perf_gtk__hpp_color_##_type(struct perf_hpp *hpp, \ | 94 | static int perf_gtk__hpp_color_##_type(struct perf_hpp_fmt *fmt __maybe_unused, \ |
95 | struct perf_hpp *hpp, \ | ||
95 | struct hist_entry *he) \ | 96 | struct hist_entry *he) \ |
96 | { \ | 97 | { \ |
97 | return __hpp__color_fmt(hpp, he, he_get_##_field); \ | 98 | return __hpp__color_fmt(hpp, he, he_get_##_field); \ |
@@ -124,6 +125,81 @@ void perf_gtk__init_hpp(void) | |||
124 | perf_gtk__hpp_color_overhead_guest_us; | 125 | perf_gtk__hpp_color_overhead_guest_us; |
125 | } | 126 | } |
126 | 127 | ||
128 | static void callchain_list__sym_name(struct callchain_list *cl, | ||
129 | char *bf, size_t bfsize) | ||
130 | { | ||
131 | if (cl->ms.sym) | ||
132 | scnprintf(bf, bfsize, "%s", cl->ms.sym->name); | ||
133 | else | ||
134 | scnprintf(bf, bfsize, "%#" PRIx64, cl->ip); | ||
135 | } | ||
136 | |||
137 | static void perf_gtk__add_callchain(struct rb_root *root, GtkTreeStore *store, | ||
138 | GtkTreeIter *parent, int col, u64 total) | ||
139 | { | ||
140 | struct rb_node *nd; | ||
141 | bool has_single_node = (rb_first(root) == rb_last(root)); | ||
142 | |||
143 | for (nd = rb_first(root); nd; nd = rb_next(nd)) { | ||
144 | struct callchain_node *node; | ||
145 | struct callchain_list *chain; | ||
146 | GtkTreeIter iter, new_parent; | ||
147 | bool need_new_parent; | ||
148 | double percent; | ||
149 | u64 hits, child_total; | ||
150 | |||
151 | node = rb_entry(nd, struct callchain_node, rb_node); | ||
152 | |||
153 | hits = callchain_cumul_hits(node); | ||
154 | percent = 100.0 * hits / total; | ||
155 | |||
156 | new_parent = *parent; | ||
157 | need_new_parent = !has_single_node && (node->val_nr > 1); | ||
158 | |||
159 | list_for_each_entry(chain, &node->val, list) { | ||
160 | char buf[128]; | ||
161 | |||
162 | gtk_tree_store_append(store, &iter, &new_parent); | ||
163 | |||
164 | scnprintf(buf, sizeof(buf), "%5.2f%%", percent); | ||
165 | gtk_tree_store_set(store, &iter, 0, buf, -1); | ||
166 | |||
167 | callchain_list__sym_name(chain, buf, sizeof(buf)); | ||
168 | gtk_tree_store_set(store, &iter, col, buf, -1); | ||
169 | |||
170 | if (need_new_parent) { | ||
171 | /* | ||
172 | * Only show the top-most symbol in a callchain | ||
173 | * if it's not the only callchain. | ||
174 | */ | ||
175 | new_parent = iter; | ||
176 | need_new_parent = false; | ||
177 | } | ||
178 | } | ||
179 | |||
180 | if (callchain_param.mode == CHAIN_GRAPH_REL) | ||
181 | child_total = node->children_hit; | ||
182 | else | ||
183 | child_total = total; | ||
184 | |||
185 | /* Now 'iter' contains info of the last callchain_list */ | ||
186 | perf_gtk__add_callchain(&node->rb_root, store, &iter, col, | ||
187 | child_total); | ||
188 | } | ||
189 | } | ||
190 | |||
191 | static void on_row_activated(GtkTreeView *view, GtkTreePath *path, | ||
192 | GtkTreeViewColumn *col __maybe_unused, | ||
193 | gpointer user_data __maybe_unused) | ||
194 | { | ||
195 | bool expanded = gtk_tree_view_row_expanded(view, path); | ||
196 | |||
197 | if (expanded) | ||
198 | gtk_tree_view_collapse_row(view, path); | ||
199 | else | ||
200 | gtk_tree_view_expand_row(view, path, FALSE); | ||
201 | } | ||
202 | |||
127 | static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists, | 203 | static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists, |
128 | float min_pcnt) | 204 | float min_pcnt) |
129 | { | 205 | { |
@@ -131,10 +207,11 @@ static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists, | |||
131 | GType col_types[MAX_COLUMNS]; | 207 | GType col_types[MAX_COLUMNS]; |
132 | GtkCellRenderer *renderer; | 208 | GtkCellRenderer *renderer; |
133 | struct sort_entry *se; | 209 | struct sort_entry *se; |
134 | GtkListStore *store; | 210 | GtkTreeStore *store; |
135 | struct rb_node *nd; | 211 | struct rb_node *nd; |
136 | GtkWidget *view; | 212 | GtkWidget *view; |
137 | int col_idx; | 213 | int col_idx; |
214 | int sym_col = -1; | ||
138 | int nr_cols; | 215 | int nr_cols; |
139 | char s[512]; | 216 | char s[512]; |
140 | 217 | ||
@@ -153,10 +230,13 @@ static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists, | |||
153 | if (se->elide) | 230 | if (se->elide) |
154 | continue; | 231 | continue; |
155 | 232 | ||
233 | if (se == &sort_sym) | ||
234 | sym_col = nr_cols; | ||
235 | |||
156 | col_types[nr_cols++] = G_TYPE_STRING; | 236 | col_types[nr_cols++] = G_TYPE_STRING; |
157 | } | 237 | } |
158 | 238 | ||
159 | store = gtk_list_store_newv(nr_cols, col_types); | 239 | store = gtk_tree_store_newv(nr_cols, col_types); |
160 | 240 | ||
161 | view = gtk_tree_view_new(); | 241 | view = gtk_tree_view_new(); |
162 | 242 | ||
@@ -165,7 +245,7 @@ static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists, | |||
165 | col_idx = 0; | 245 | col_idx = 0; |
166 | 246 | ||
167 | perf_hpp__for_each_format(fmt) { | 247 | perf_hpp__for_each_format(fmt) { |
168 | fmt->header(&hpp); | 248 | fmt->header(fmt, &hpp); |
169 | 249 | ||
170 | gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view), | 250 | gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view), |
171 | -1, ltrim(s), | 251 | -1, ltrim(s), |
@@ -183,6 +263,18 @@ static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists, | |||
183 | col_idx++, NULL); | 263 | col_idx++, NULL); |
184 | } | 264 | } |
185 | 265 | ||
266 | for (col_idx = 0; col_idx < nr_cols; col_idx++) { | ||
267 | GtkTreeViewColumn *column; | ||
268 | |||
269 | column = gtk_tree_view_get_column(GTK_TREE_VIEW(view), col_idx); | ||
270 | gtk_tree_view_column_set_resizable(column, TRUE); | ||
271 | |||
272 | if (col_idx == sym_col) { | ||
273 | gtk_tree_view_set_expander_column(GTK_TREE_VIEW(view), | ||
274 | column); | ||
275 | } | ||
276 | } | ||
277 | |||
186 | gtk_tree_view_set_model(GTK_TREE_VIEW(view), GTK_TREE_MODEL(store)); | 278 | gtk_tree_view_set_model(GTK_TREE_VIEW(view), GTK_TREE_MODEL(store)); |
187 | 279 | ||
188 | g_object_unref(GTK_TREE_MODEL(store)); | 280 | g_object_unref(GTK_TREE_MODEL(store)); |
@@ -199,17 +291,17 @@ static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists, | |||
199 | if (percent < min_pcnt) | 291 | if (percent < min_pcnt) |
200 | continue; | 292 | continue; |
201 | 293 | ||
202 | gtk_list_store_append(store, &iter); | 294 | gtk_tree_store_append(store, &iter, NULL); |
203 | 295 | ||
204 | col_idx = 0; | 296 | col_idx = 0; |
205 | 297 | ||
206 | perf_hpp__for_each_format(fmt) { | 298 | perf_hpp__for_each_format(fmt) { |
207 | if (fmt->color) | 299 | if (fmt->color) |
208 | fmt->color(&hpp, h); | 300 | fmt->color(fmt, &hpp, h); |
209 | else | 301 | else |
210 | fmt->entry(&hpp, h); | 302 | fmt->entry(fmt, &hpp, h); |
211 | 303 | ||
212 | gtk_list_store_set(store, &iter, col_idx++, s, -1); | 304 | gtk_tree_store_set(store, &iter, col_idx++, s, -1); |
213 | } | 305 | } |
214 | 306 | ||
215 | list_for_each_entry(se, &hist_entry__sort_list, list) { | 307 | list_for_each_entry(se, &hist_entry__sort_list, list) { |
@@ -219,10 +311,26 @@ static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists, | |||
219 | se->se_snprintf(h, s, ARRAY_SIZE(s), | 311 | se->se_snprintf(h, s, ARRAY_SIZE(s), |
220 | hists__col_len(hists, se->se_width_idx)); | 312 | hists__col_len(hists, se->se_width_idx)); |
221 | 313 | ||
222 | gtk_list_store_set(store, &iter, col_idx++, s, -1); | 314 | gtk_tree_store_set(store, &iter, col_idx++, s, -1); |
315 | } | ||
316 | |||
317 | if (symbol_conf.use_callchain && sort__has_sym) { | ||
318 | u64 total; | ||
319 | |||
320 | if (callchain_param.mode == CHAIN_GRAPH_REL) | ||
321 | total = h->stat.period; | ||
322 | else | ||
323 | total = hists->stats.total_period; | ||
324 | |||
325 | perf_gtk__add_callchain(&h->sorted_chain, store, &iter, | ||
326 | sym_col, total); | ||
223 | } | 327 | } |
224 | } | 328 | } |
225 | 329 | ||
330 | gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(view), TRUE); | ||
331 | |||
332 | g_signal_connect(view, "row-activated", | ||
333 | G_CALLBACK(on_row_activated), NULL); | ||
226 | gtk_container_add(GTK_CONTAINER(window), view); | 334 | gtk_container_add(GTK_CONTAINER(window), view); |
227 | } | 335 | } |
228 | 336 | ||
diff --git a/tools/perf/ui/hist.c b/tools/perf/ui/hist.c index 4bf91b09d62d..0a193281eba8 100644 --- a/tools/perf/ui/hist.c +++ b/tools/perf/ui/hist.c | |||
@@ -1,4 +1,5 @@ | |||
1 | #include <math.h> | 1 | #include <math.h> |
2 | #include <linux/compiler.h> | ||
2 | 3 | ||
3 | #include "../util/hist.h" | 4 | #include "../util/hist.h" |
4 | #include "../util/util.h" | 5 | #include "../util/util.h" |
@@ -79,7 +80,8 @@ static int __hpp__fmt(struct perf_hpp *hpp, struct hist_entry *he, | |||
79 | } | 80 | } |
80 | 81 | ||
81 | #define __HPP_HEADER_FN(_type, _str, _min_width, _unit_width) \ | 82 | #define __HPP_HEADER_FN(_type, _str, _min_width, _unit_width) \ |
82 | static int hpp__header_##_type(struct perf_hpp *hpp) \ | 83 | static int hpp__header_##_type(struct perf_hpp_fmt *fmt __maybe_unused, \ |
84 | struct perf_hpp *hpp) \ | ||
83 | { \ | 85 | { \ |
84 | int len = _min_width; \ | 86 | int len = _min_width; \ |
85 | \ | 87 | \ |
@@ -92,7 +94,8 @@ static int hpp__header_##_type(struct perf_hpp *hpp) \ | |||
92 | } | 94 | } |
93 | 95 | ||
94 | #define __HPP_WIDTH_FN(_type, _min_width, _unit_width) \ | 96 | #define __HPP_WIDTH_FN(_type, _min_width, _unit_width) \ |
95 | static int hpp__width_##_type(struct perf_hpp *hpp __maybe_unused) \ | 97 | static int hpp__width_##_type(struct perf_hpp_fmt *fmt __maybe_unused, \ |
98 | struct perf_hpp *hpp __maybe_unused) \ | ||
96 | { \ | 99 | { \ |
97 | int len = _min_width; \ | 100 | int len = _min_width; \ |
98 | \ | 101 | \ |
@@ -110,14 +113,16 @@ static u64 he_get_##_field(struct hist_entry *he) \ | |||
110 | return he->stat._field; \ | 113 | return he->stat._field; \ |
111 | } \ | 114 | } \ |
112 | \ | 115 | \ |
113 | static int hpp__color_##_type(struct perf_hpp *hpp, struct hist_entry *he) \ | 116 | static int hpp__color_##_type(struct perf_hpp_fmt *fmt __maybe_unused, \ |
117 | struct perf_hpp *hpp, struct hist_entry *he) \ | ||
114 | { \ | 118 | { \ |
115 | return __hpp__fmt(hpp, he, he_get_##_field, " %6.2f%%", \ | 119 | return __hpp__fmt(hpp, he, he_get_##_field, " %6.2f%%", \ |
116 | (hpp_snprint_fn)percent_color_snprintf, true); \ | 120 | (hpp_snprint_fn)percent_color_snprintf, true); \ |
117 | } | 121 | } |
118 | 122 | ||
119 | #define __HPP_ENTRY_PERCENT_FN(_type, _field) \ | 123 | #define __HPP_ENTRY_PERCENT_FN(_type, _field) \ |
120 | static int hpp__entry_##_type(struct perf_hpp *hpp, struct hist_entry *he) \ | 124 | static int hpp__entry_##_type(struct perf_hpp_fmt *_fmt __maybe_unused, \ |
125 | struct perf_hpp *hpp, struct hist_entry *he) \ | ||
121 | { \ | 126 | { \ |
122 | const char *fmt = symbol_conf.field_sep ? " %.2f" : " %6.2f%%"; \ | 127 | const char *fmt = symbol_conf.field_sep ? " %.2f" : " %6.2f%%"; \ |
123 | return __hpp__fmt(hpp, he, he_get_##_field, fmt, \ | 128 | return __hpp__fmt(hpp, he, he_get_##_field, fmt, \ |
@@ -130,7 +135,8 @@ static u64 he_get_raw_##_field(struct hist_entry *he) \ | |||
130 | return he->stat._field; \ | 135 | return he->stat._field; \ |
131 | } \ | 136 | } \ |
132 | \ | 137 | \ |
133 | static int hpp__entry_##_type(struct perf_hpp *hpp, struct hist_entry *he) \ | 138 | static int hpp__entry_##_type(struct perf_hpp_fmt *_fmt __maybe_unused, \ |
139 | struct perf_hpp *hpp, struct hist_entry *he) \ | ||
134 | { \ | 140 | { \ |
135 | const char *fmt = symbol_conf.field_sep ? " %"PRIu64 : " %11"PRIu64; \ | 141 | const char *fmt = symbol_conf.field_sep ? " %"PRIu64 : " %11"PRIu64; \ |
136 | return __hpp__fmt(hpp, he, he_get_raw_##_field, fmt, scnprintf, false); \ | 142 | return __hpp__fmt(hpp, he, he_get_raw_##_field, fmt, scnprintf, false); \ |
@@ -157,196 +163,6 @@ HPP_PERCENT_FNS(overhead_guest_us, "guest usr", period_guest_us, 9, 8) | |||
157 | HPP_RAW_FNS(samples, "Samples", nr_events, 12, 12) | 163 | HPP_RAW_FNS(samples, "Samples", nr_events, 12, 12) |
158 | HPP_RAW_FNS(period, "Period", period, 12, 12) | 164 | HPP_RAW_FNS(period, "Period", period, 12, 12) |
159 | 165 | ||
160 | |||
161 | static int hpp__header_baseline(struct perf_hpp *hpp) | ||
162 | { | ||
163 | return scnprintf(hpp->buf, hpp->size, "Baseline"); | ||
164 | } | ||
165 | |||
166 | static int hpp__width_baseline(struct perf_hpp *hpp __maybe_unused) | ||
167 | { | ||
168 | return 8; | ||
169 | } | ||
170 | |||
171 | static double baseline_percent(struct hist_entry *he) | ||
172 | { | ||
173 | struct hist_entry *pair = hist_entry__next_pair(he); | ||
174 | struct hists *pair_hists = pair ? pair->hists : NULL; | ||
175 | double percent = 0.0; | ||
176 | |||
177 | if (pair) { | ||
178 | u64 total_period = pair_hists->stats.total_period; | ||
179 | u64 base_period = pair->stat.period; | ||
180 | |||
181 | percent = 100.0 * base_period / total_period; | ||
182 | } | ||
183 | |||
184 | return percent; | ||
185 | } | ||
186 | |||
187 | static int hpp__color_baseline(struct perf_hpp *hpp, struct hist_entry *he) | ||
188 | { | ||
189 | double percent = baseline_percent(he); | ||
190 | |||
191 | if (hist_entry__has_pairs(he) || symbol_conf.field_sep) | ||
192 | return percent_color_snprintf(hpp->buf, hpp->size, " %6.2f%%", percent); | ||
193 | else | ||
194 | return scnprintf(hpp->buf, hpp->size, " "); | ||
195 | } | ||
196 | |||
197 | static int hpp__entry_baseline(struct perf_hpp *hpp, struct hist_entry *he) | ||
198 | { | ||
199 | double percent = baseline_percent(he); | ||
200 | const char *fmt = symbol_conf.field_sep ? "%.2f" : " %6.2f%%"; | ||
201 | |||
202 | if (hist_entry__has_pairs(he) || symbol_conf.field_sep) | ||
203 | return scnprintf(hpp->buf, hpp->size, fmt, percent); | ||
204 | else | ||
205 | return scnprintf(hpp->buf, hpp->size, " "); | ||
206 | } | ||
207 | |||
208 | static int hpp__header_period_baseline(struct perf_hpp *hpp) | ||
209 | { | ||
210 | const char *fmt = symbol_conf.field_sep ? "%s" : "%12s"; | ||
211 | |||
212 | return scnprintf(hpp->buf, hpp->size, fmt, "Period Base"); | ||
213 | } | ||
214 | |||
215 | static int hpp__width_period_baseline(struct perf_hpp *hpp __maybe_unused) | ||
216 | { | ||
217 | return 12; | ||
218 | } | ||
219 | |||
220 | static int hpp__entry_period_baseline(struct perf_hpp *hpp, struct hist_entry *he) | ||
221 | { | ||
222 | struct hist_entry *pair = hist_entry__next_pair(he); | ||
223 | u64 period = pair ? pair->stat.period : 0; | ||
224 | const char *fmt = symbol_conf.field_sep ? "%" PRIu64 : "%12" PRIu64; | ||
225 | |||
226 | return scnprintf(hpp->buf, hpp->size, fmt, period); | ||
227 | } | ||
228 | |||
229 | static int hpp__header_delta(struct perf_hpp *hpp) | ||
230 | { | ||
231 | const char *fmt = symbol_conf.field_sep ? "%s" : "%7s"; | ||
232 | |||
233 | return scnprintf(hpp->buf, hpp->size, fmt, "Delta"); | ||
234 | } | ||
235 | |||
236 | static int hpp__width_delta(struct perf_hpp *hpp __maybe_unused) | ||
237 | { | ||
238 | return 7; | ||
239 | } | ||
240 | |||
241 | static int hpp__entry_delta(struct perf_hpp *hpp, struct hist_entry *he) | ||
242 | { | ||
243 | struct hist_entry *pair = hist_entry__next_pair(he); | ||
244 | const char *fmt = symbol_conf.field_sep ? "%s" : "%7.7s"; | ||
245 | char buf[32] = " "; | ||
246 | double diff = 0.0; | ||
247 | |||
248 | if (pair) { | ||
249 | if (he->diff.computed) | ||
250 | diff = he->diff.period_ratio_delta; | ||
251 | else | ||
252 | diff = perf_diff__compute_delta(he, pair); | ||
253 | } else | ||
254 | diff = perf_diff__period_percent(he, he->stat.period); | ||
255 | |||
256 | if (fabs(diff) >= 0.01) | ||
257 | scnprintf(buf, sizeof(buf), "%+4.2F%%", diff); | ||
258 | |||
259 | return scnprintf(hpp->buf, hpp->size, fmt, buf); | ||
260 | } | ||
261 | |||
262 | static int hpp__header_ratio(struct perf_hpp *hpp) | ||
263 | { | ||
264 | const char *fmt = symbol_conf.field_sep ? "%s" : "%14s"; | ||
265 | |||
266 | return scnprintf(hpp->buf, hpp->size, fmt, "Ratio"); | ||
267 | } | ||
268 | |||
269 | static int hpp__width_ratio(struct perf_hpp *hpp __maybe_unused) | ||
270 | { | ||
271 | return 14; | ||
272 | } | ||
273 | |||
274 | static int hpp__entry_ratio(struct perf_hpp *hpp, struct hist_entry *he) | ||
275 | { | ||
276 | struct hist_entry *pair = hist_entry__next_pair(he); | ||
277 | const char *fmt = symbol_conf.field_sep ? "%s" : "%14s"; | ||
278 | char buf[32] = " "; | ||
279 | double ratio = 0.0; | ||
280 | |||
281 | if (pair) { | ||
282 | if (he->diff.computed) | ||
283 | ratio = he->diff.period_ratio; | ||
284 | else | ||
285 | ratio = perf_diff__compute_ratio(he, pair); | ||
286 | } | ||
287 | |||
288 | if (ratio > 0.0) | ||
289 | scnprintf(buf, sizeof(buf), "%+14.6F", ratio); | ||
290 | |||
291 | return scnprintf(hpp->buf, hpp->size, fmt, buf); | ||
292 | } | ||
293 | |||
294 | static int hpp__header_wdiff(struct perf_hpp *hpp) | ||
295 | { | ||
296 | const char *fmt = symbol_conf.field_sep ? "%s" : "%14s"; | ||
297 | |||
298 | return scnprintf(hpp->buf, hpp->size, fmt, "Weighted diff"); | ||
299 | } | ||
300 | |||
301 | static int hpp__width_wdiff(struct perf_hpp *hpp __maybe_unused) | ||
302 | { | ||
303 | return 14; | ||
304 | } | ||
305 | |||
306 | static int hpp__entry_wdiff(struct perf_hpp *hpp, struct hist_entry *he) | ||
307 | { | ||
308 | struct hist_entry *pair = hist_entry__next_pair(he); | ||
309 | const char *fmt = symbol_conf.field_sep ? "%s" : "%14s"; | ||
310 | char buf[32] = " "; | ||
311 | s64 wdiff = 0; | ||
312 | |||
313 | if (pair) { | ||
314 | if (he->diff.computed) | ||
315 | wdiff = he->diff.wdiff; | ||
316 | else | ||
317 | wdiff = perf_diff__compute_wdiff(he, pair); | ||
318 | } | ||
319 | |||
320 | if (wdiff != 0) | ||
321 | scnprintf(buf, sizeof(buf), "%14ld", wdiff); | ||
322 | |||
323 | return scnprintf(hpp->buf, hpp->size, fmt, buf); | ||
324 | } | ||
325 | |||
326 | static int hpp__header_formula(struct perf_hpp *hpp) | ||
327 | { | ||
328 | const char *fmt = symbol_conf.field_sep ? "%s" : "%70s"; | ||
329 | |||
330 | return scnprintf(hpp->buf, hpp->size, fmt, "Formula"); | ||
331 | } | ||
332 | |||
333 | static int hpp__width_formula(struct perf_hpp *hpp __maybe_unused) | ||
334 | { | ||
335 | return 70; | ||
336 | } | ||
337 | |||
338 | static int hpp__entry_formula(struct perf_hpp *hpp, struct hist_entry *he) | ||
339 | { | ||
340 | struct hist_entry *pair = hist_entry__next_pair(he); | ||
341 | const char *fmt = symbol_conf.field_sep ? "%s" : "%-70s"; | ||
342 | char buf[96] = " "; | ||
343 | |||
344 | if (pair) | ||
345 | perf_diff__formula(he, pair, buf, sizeof(buf)); | ||
346 | |||
347 | return scnprintf(hpp->buf, hpp->size, fmt, buf); | ||
348 | } | ||
349 | |||
350 | #define HPP__COLOR_PRINT_FNS(_name) \ | 166 | #define HPP__COLOR_PRINT_FNS(_name) \ |
351 | { \ | 167 | { \ |
352 | .header = hpp__header_ ## _name, \ | 168 | .header = hpp__header_ ## _name, \ |
@@ -363,19 +179,13 @@ static int hpp__entry_formula(struct perf_hpp *hpp, struct hist_entry *he) | |||
363 | } | 179 | } |
364 | 180 | ||
365 | struct perf_hpp_fmt perf_hpp__format[] = { | 181 | struct perf_hpp_fmt perf_hpp__format[] = { |
366 | HPP__COLOR_PRINT_FNS(baseline), | ||
367 | HPP__COLOR_PRINT_FNS(overhead), | 182 | HPP__COLOR_PRINT_FNS(overhead), |
368 | HPP__COLOR_PRINT_FNS(overhead_sys), | 183 | HPP__COLOR_PRINT_FNS(overhead_sys), |
369 | HPP__COLOR_PRINT_FNS(overhead_us), | 184 | HPP__COLOR_PRINT_FNS(overhead_us), |
370 | HPP__COLOR_PRINT_FNS(overhead_guest_sys), | 185 | HPP__COLOR_PRINT_FNS(overhead_guest_sys), |
371 | HPP__COLOR_PRINT_FNS(overhead_guest_us), | 186 | HPP__COLOR_PRINT_FNS(overhead_guest_us), |
372 | HPP__PRINT_FNS(samples), | 187 | HPP__PRINT_FNS(samples), |
373 | HPP__PRINT_FNS(period), | 188 | HPP__PRINT_FNS(period) |
374 | HPP__PRINT_FNS(period_baseline), | ||
375 | HPP__PRINT_FNS(delta), | ||
376 | HPP__PRINT_FNS(ratio), | ||
377 | HPP__PRINT_FNS(wdiff), | ||
378 | HPP__PRINT_FNS(formula) | ||
379 | }; | 189 | }; |
380 | 190 | ||
381 | LIST_HEAD(perf_hpp__list); | 191 | LIST_HEAD(perf_hpp__list); |
@@ -396,6 +206,8 @@ LIST_HEAD(perf_hpp__list); | |||
396 | 206 | ||
397 | void perf_hpp__init(void) | 207 | void perf_hpp__init(void) |
398 | { | 208 | { |
209 | perf_hpp__column_enable(PERF_HPP__OVERHEAD); | ||
210 | |||
399 | if (symbol_conf.show_cpu_utilization) { | 211 | if (symbol_conf.show_cpu_utilization) { |
400 | perf_hpp__column_enable(PERF_HPP__OVERHEAD_SYS); | 212 | perf_hpp__column_enable(PERF_HPP__OVERHEAD_SYS); |
401 | perf_hpp__column_enable(PERF_HPP__OVERHEAD_US); | 213 | perf_hpp__column_enable(PERF_HPP__OVERHEAD_US); |
@@ -424,46 +236,6 @@ void perf_hpp__column_enable(unsigned col) | |||
424 | perf_hpp__column_register(&perf_hpp__format[col]); | 236 | perf_hpp__column_register(&perf_hpp__format[col]); |
425 | } | 237 | } |
426 | 238 | ||
427 | static inline void advance_hpp(struct perf_hpp *hpp, int inc) | ||
428 | { | ||
429 | hpp->buf += inc; | ||
430 | hpp->size -= inc; | ||
431 | } | ||
432 | |||
433 | int hist_entry__period_snprintf(struct perf_hpp *hpp, struct hist_entry *he, | ||
434 | bool color) | ||
435 | { | ||
436 | const char *sep = symbol_conf.field_sep; | ||
437 | struct perf_hpp_fmt *fmt; | ||
438 | char *start = hpp->buf; | ||
439 | int ret; | ||
440 | bool first = true; | ||
441 | |||
442 | if (symbol_conf.exclude_other && !he->parent) | ||
443 | return 0; | ||
444 | |||
445 | perf_hpp__for_each_format(fmt) { | ||
446 | /* | ||
447 | * If there's no field_sep, we still need | ||
448 | * to display initial ' '. | ||
449 | */ | ||
450 | if (!sep || !first) { | ||
451 | ret = scnprintf(hpp->buf, hpp->size, "%s", sep ?: " "); | ||
452 | advance_hpp(hpp, ret); | ||
453 | } else | ||
454 | first = false; | ||
455 | |||
456 | if (color && fmt->color) | ||
457 | ret = fmt->color(hpp, he); | ||
458 | else | ||
459 | ret = fmt->entry(hpp, he); | ||
460 | |||
461 | advance_hpp(hpp, ret); | ||
462 | } | ||
463 | |||
464 | return hpp->buf - start; | ||
465 | } | ||
466 | |||
467 | int hist_entry__sort_snprintf(struct hist_entry *he, char *s, size_t size, | 239 | int hist_entry__sort_snprintf(struct hist_entry *he, char *s, size_t size, |
468 | struct hists *hists) | 240 | struct hists *hists) |
469 | { | 241 | { |
@@ -499,7 +271,7 @@ unsigned int hists__sort_list_width(struct hists *hists) | |||
499 | if (i) | 271 | if (i) |
500 | ret += 2; | 272 | ret += 2; |
501 | 273 | ||
502 | ret += fmt->width(&dummy_hpp); | 274 | ret += fmt->width(fmt, &dummy_hpp); |
503 | } | 275 | } |
504 | 276 | ||
505 | list_for_each_entry(se, &hist_entry__sort_list, list) | 277 | list_for_each_entry(se, &hist_entry__sort_list, list) |
diff --git a/tools/perf/ui/setup.c b/tools/perf/ui/setup.c index ae6a789cb0f6..47d9a571f261 100644 --- a/tools/perf/ui/setup.c +++ b/tools/perf/ui/setup.c | |||
@@ -30,7 +30,6 @@ void setup_browser(bool fallback_to_pager) | |||
30 | if (fallback_to_pager) | 30 | if (fallback_to_pager) |
31 | setup_pager(); | 31 | setup_pager(); |
32 | 32 | ||
33 | perf_hpp__column_enable(PERF_HPP__OVERHEAD); | ||
34 | perf_hpp__init(); | 33 | perf_hpp__init(); |
35 | break; | 34 | break; |
36 | } | 35 | } |
diff --git a/tools/perf/ui/stdio/hist.c b/tools/perf/ui/stdio/hist.c index ae7a75432249..5b4fb330f656 100644 --- a/tools/perf/ui/stdio/hist.c +++ b/tools/perf/ui/stdio/hist.c | |||
@@ -308,6 +308,47 @@ static size_t hist_entry__callchain_fprintf(struct hist_entry *he, | |||
308 | return hist_entry_callchain__fprintf(he, total_period, left_margin, fp); | 308 | return hist_entry_callchain__fprintf(he, total_period, left_margin, fp); |
309 | } | 309 | } |
310 | 310 | ||
311 | static inline void advance_hpp(struct perf_hpp *hpp, int inc) | ||
312 | { | ||
313 | hpp->buf += inc; | ||
314 | hpp->size -= inc; | ||
315 | } | ||
316 | |||
317 | static int hist_entry__period_snprintf(struct perf_hpp *hpp, | ||
318 | struct hist_entry *he, | ||
319 | bool color) | ||
320 | { | ||
321 | const char *sep = symbol_conf.field_sep; | ||
322 | struct perf_hpp_fmt *fmt; | ||
323 | char *start = hpp->buf; | ||
324 | int ret; | ||
325 | bool first = true; | ||
326 | |||
327 | if (symbol_conf.exclude_other && !he->parent) | ||
328 | return 0; | ||
329 | |||
330 | perf_hpp__for_each_format(fmt) { | ||
331 | /* | ||
332 | * If there's no field_sep, we still need | ||
333 | * to display initial ' '. | ||
334 | */ | ||
335 | if (!sep || !first) { | ||
336 | ret = scnprintf(hpp->buf, hpp->size, "%s", sep ?: " "); | ||
337 | advance_hpp(hpp, ret); | ||
338 | } else | ||
339 | first = false; | ||
340 | |||
341 | if (color && fmt->color) | ||
342 | ret = fmt->color(fmt, hpp, he); | ||
343 | else | ||
344 | ret = fmt->entry(fmt, hpp, he); | ||
345 | |||
346 | advance_hpp(hpp, ret); | ||
347 | } | ||
348 | |||
349 | return hpp->buf - start; | ||
350 | } | ||
351 | |||
311 | static int hist_entry__fprintf(struct hist_entry *he, size_t size, | 352 | static int hist_entry__fprintf(struct hist_entry *he, size_t size, |
312 | struct hists *hists, FILE *fp) | 353 | struct hists *hists, FILE *fp) |
313 | { | 354 | { |
@@ -365,7 +406,7 @@ size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows, | |||
365 | else | 406 | else |
366 | first = false; | 407 | first = false; |
367 | 408 | ||
368 | fmt->header(&dummy_hpp); | 409 | fmt->header(fmt, &dummy_hpp); |
369 | fprintf(fp, "%s", bf); | 410 | fprintf(fp, "%s", bf); |
370 | } | 411 | } |
371 | 412 | ||
@@ -410,7 +451,7 @@ size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows, | |||
410 | else | 451 | else |
411 | first = false; | 452 | first = false; |
412 | 453 | ||
413 | width = fmt->width(&dummy_hpp); | 454 | width = fmt->width(fmt, &dummy_hpp); |
414 | for (i = 0; i < width; i++) | 455 | for (i = 0; i < width; i++) |
415 | fprintf(fp, "."); | 456 | fprintf(fp, "."); |
416 | } | 457 | } |
diff --git a/tools/perf/util/cpumap.h b/tools/perf/util/cpumap.h index 9bed02e5fb3d..b123bb9d6f55 100644 --- a/tools/perf/util/cpumap.h +++ b/tools/perf/util/cpumap.h | |||
@@ -41,7 +41,7 @@ static inline int cpu_map__nr(const struct cpu_map *map) | |||
41 | return map ? map->nr : 1; | 41 | return map ? map->nr : 1; |
42 | } | 42 | } |
43 | 43 | ||
44 | static inline bool cpu_map__all(const struct cpu_map *map) | 44 | static inline bool cpu_map__empty(const struct cpu_map *map) |
45 | { | 45 | { |
46 | return map ? map->map[0] == -1 : true; | 46 | return map ? map->map[0] == -1 : true; |
47 | } | 47 | } |
diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c index 5cd13d768cec..95412705d0d2 100644 --- a/tools/perf/util/event.c +++ b/tools/perf/util/event.c | |||
@@ -686,7 +686,7 @@ int perf_event__preprocess_sample(const union perf_event *event, | |||
686 | !strlist__has_entry(symbol_conf.comm_list, thread->comm)) | 686 | !strlist__has_entry(symbol_conf.comm_list, thread->comm)) |
687 | goto out_filtered; | 687 | goto out_filtered; |
688 | 688 | ||
689 | dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid); | 689 | dump_printf(" ... thread: %s:%d\n", thread->comm, thread->tid); |
690 | /* | 690 | /* |
691 | * Have we already created the kernel maps for this machine? | 691 | * Have we already created the kernel maps for this machine? |
692 | * | 692 | * |
diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h index 181389535c0c..1ebb8fb0178c 100644 --- a/tools/perf/util/event.h +++ b/tools/perf/util/event.h | |||
@@ -116,7 +116,7 @@ struct build_id_event { | |||
116 | enum perf_user_event_type { /* above any possible kernel type */ | 116 | enum perf_user_event_type { /* above any possible kernel type */ |
117 | PERF_RECORD_USER_TYPE_START = 64, | 117 | PERF_RECORD_USER_TYPE_START = 64, |
118 | PERF_RECORD_HEADER_ATTR = 64, | 118 | PERF_RECORD_HEADER_ATTR = 64, |
119 | PERF_RECORD_HEADER_EVENT_TYPE = 65, | 119 | PERF_RECORD_HEADER_EVENT_TYPE = 65, /* depreceated */ |
120 | PERF_RECORD_HEADER_TRACING_DATA = 66, | 120 | PERF_RECORD_HEADER_TRACING_DATA = 66, |
121 | PERF_RECORD_HEADER_BUILD_ID = 67, | 121 | PERF_RECORD_HEADER_BUILD_ID = 67, |
122 | PERF_RECORD_FINISHED_ROUND = 68, | 122 | PERF_RECORD_FINISHED_ROUND = 68, |
diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c index 8065ce8fa9a5..42ea4e947eb8 100644 --- a/tools/perf/util/evlist.c +++ b/tools/perf/util/evlist.c | |||
@@ -403,16 +403,20 @@ union perf_event *perf_evlist__mmap_read(struct perf_evlist *evlist, int idx) | |||
403 | return event; | 403 | return event; |
404 | } | 404 | } |
405 | 405 | ||
406 | static void __perf_evlist__munmap(struct perf_evlist *evlist, int idx) | ||
407 | { | ||
408 | if (evlist->mmap[idx].base != NULL) { | ||
409 | munmap(evlist->mmap[idx].base, evlist->mmap_len); | ||
410 | evlist->mmap[idx].base = NULL; | ||
411 | } | ||
412 | } | ||
413 | |||
406 | void perf_evlist__munmap(struct perf_evlist *evlist) | 414 | void perf_evlist__munmap(struct perf_evlist *evlist) |
407 | { | 415 | { |
408 | int i; | 416 | int i; |
409 | 417 | ||
410 | for (i = 0; i < evlist->nr_mmaps; i++) { | 418 | for (i = 0; i < evlist->nr_mmaps; i++) |
411 | if (evlist->mmap[i].base != NULL) { | 419 | __perf_evlist__munmap(evlist, i); |
412 | munmap(evlist->mmap[i].base, evlist->mmap_len); | ||
413 | evlist->mmap[i].base = NULL; | ||
414 | } | ||
415 | } | ||
416 | 420 | ||
417 | free(evlist->mmap); | 421 | free(evlist->mmap); |
418 | evlist->mmap = NULL; | 422 | evlist->mmap = NULL; |
@@ -421,7 +425,7 @@ void perf_evlist__munmap(struct perf_evlist *evlist) | |||
421 | static int perf_evlist__alloc_mmap(struct perf_evlist *evlist) | 425 | static int perf_evlist__alloc_mmap(struct perf_evlist *evlist) |
422 | { | 426 | { |
423 | evlist->nr_mmaps = cpu_map__nr(evlist->cpus); | 427 | evlist->nr_mmaps = cpu_map__nr(evlist->cpus); |
424 | if (cpu_map__all(evlist->cpus)) | 428 | if (cpu_map__empty(evlist->cpus)) |
425 | evlist->nr_mmaps = thread_map__nr(evlist->threads); | 429 | evlist->nr_mmaps = thread_map__nr(evlist->threads); |
426 | evlist->mmap = zalloc(evlist->nr_mmaps * sizeof(struct perf_mmap)); | 430 | evlist->mmap = zalloc(evlist->nr_mmaps * sizeof(struct perf_mmap)); |
427 | return evlist->mmap != NULL ? 0 : -ENOMEM; | 431 | return evlist->mmap != NULL ? 0 : -ENOMEM; |
@@ -477,12 +481,8 @@ static int perf_evlist__mmap_per_cpu(struct perf_evlist *evlist, int prot, int m | |||
477 | return 0; | 481 | return 0; |
478 | 482 | ||
479 | out_unmap: | 483 | out_unmap: |
480 | for (cpu = 0; cpu < nr_cpus; cpu++) { | 484 | for (cpu = 0; cpu < nr_cpus; cpu++) |
481 | if (evlist->mmap[cpu].base != NULL) { | 485 | __perf_evlist__munmap(evlist, cpu); |
482 | munmap(evlist->mmap[cpu].base, evlist->mmap_len); | ||
483 | evlist->mmap[cpu].base = NULL; | ||
484 | } | ||
485 | } | ||
486 | return -1; | 486 | return -1; |
487 | } | 487 | } |
488 | 488 | ||
@@ -517,12 +517,8 @@ static int perf_evlist__mmap_per_thread(struct perf_evlist *evlist, int prot, in | |||
517 | return 0; | 517 | return 0; |
518 | 518 | ||
519 | out_unmap: | 519 | out_unmap: |
520 | for (thread = 0; thread < nr_threads; thread++) { | 520 | for (thread = 0; thread < nr_threads; thread++) |
521 | if (evlist->mmap[thread].base != NULL) { | 521 | __perf_evlist__munmap(evlist, thread); |
522 | munmap(evlist->mmap[thread].base, evlist->mmap_len); | ||
523 | evlist->mmap[thread].base = NULL; | ||
524 | } | ||
525 | } | ||
526 | return -1; | 522 | return -1; |
527 | } | 523 | } |
528 | 524 | ||
@@ -573,7 +569,7 @@ int perf_evlist__mmap(struct perf_evlist *evlist, unsigned int pages, | |||
573 | return -ENOMEM; | 569 | return -ENOMEM; |
574 | } | 570 | } |
575 | 571 | ||
576 | if (cpu_map__all(cpus)) | 572 | if (cpu_map__empty(cpus)) |
577 | return perf_evlist__mmap_per_thread(evlist, prot, mask); | 573 | return perf_evlist__mmap_per_thread(evlist, prot, mask); |
578 | 574 | ||
579 | return perf_evlist__mmap_per_cpu(evlist, prot, mask); | 575 | return perf_evlist__mmap_per_cpu(evlist, prot, mask); |
@@ -838,7 +834,7 @@ out_close_ready_pipe: | |||
838 | int perf_evlist__start_workload(struct perf_evlist *evlist) | 834 | int perf_evlist__start_workload(struct perf_evlist *evlist) |
839 | { | 835 | { |
840 | if (evlist->workload.cork_fd > 0) { | 836 | if (evlist->workload.cork_fd > 0) { |
841 | char bf; | 837 | char bf = 0; |
842 | int ret; | 838 | int ret; |
843 | /* | 839 | /* |
844 | * Remove the cork, let it rip! | 840 | * Remove the cork, let it rip! |
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index c9c7494506a1..a6354619fa5d 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c | |||
@@ -9,17 +9,17 @@ | |||
9 | 9 | ||
10 | #include <byteswap.h> | 10 | #include <byteswap.h> |
11 | #include <linux/bitops.h> | 11 | #include <linux/bitops.h> |
12 | #include "asm/bug.h" | ||
13 | #include <lk/debugfs.h> | 12 | #include <lk/debugfs.h> |
14 | #include "event-parse.h" | 13 | #include <traceevent/event-parse.h> |
14 | #include <linux/hw_breakpoint.h> | ||
15 | #include <linux/perf_event.h> | ||
16 | #include "asm/bug.h" | ||
15 | #include "evsel.h" | 17 | #include "evsel.h" |
16 | #include "evlist.h" | 18 | #include "evlist.h" |
17 | #include "util.h" | 19 | #include "util.h" |
18 | #include "cpumap.h" | 20 | #include "cpumap.h" |
19 | #include "thread_map.h" | 21 | #include "thread_map.h" |
20 | #include "target.h" | 22 | #include "target.h" |
21 | #include <linux/hw_breakpoint.h> | ||
22 | #include <linux/perf_event.h> | ||
23 | #include "perf_regs.h" | 23 | #include "perf_regs.h" |
24 | 24 | ||
25 | static struct { | 25 | static struct { |
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index a4dafbee2511..f558f83769af 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c | |||
@@ -25,41 +25,9 @@ | |||
25 | 25 | ||
26 | static bool no_buildid_cache = false; | 26 | static bool no_buildid_cache = false; |
27 | 27 | ||
28 | static int trace_event_count; | ||
29 | static struct perf_trace_event_type *trace_events; | ||
30 | |||
31 | static u32 header_argc; | 28 | static u32 header_argc; |
32 | static const char **header_argv; | 29 | static const char **header_argv; |
33 | 30 | ||
34 | int perf_header__push_event(u64 id, const char *name) | ||
35 | { | ||
36 | struct perf_trace_event_type *nevents; | ||
37 | |||
38 | if (strlen(name) > MAX_EVENT_NAME) | ||
39 | pr_warning("Event %s will be truncated\n", name); | ||
40 | |||
41 | nevents = realloc(trace_events, (trace_event_count + 1) * sizeof(*trace_events)); | ||
42 | if (nevents == NULL) | ||
43 | return -ENOMEM; | ||
44 | trace_events = nevents; | ||
45 | |||
46 | memset(&trace_events[trace_event_count], 0, sizeof(struct perf_trace_event_type)); | ||
47 | trace_events[trace_event_count].event_id = id; | ||
48 | strncpy(trace_events[trace_event_count].name, name, MAX_EVENT_NAME - 1); | ||
49 | trace_event_count++; | ||
50 | return 0; | ||
51 | } | ||
52 | |||
53 | char *perf_header__find_event(u64 id) | ||
54 | { | ||
55 | int i; | ||
56 | for (i = 0 ; i < trace_event_count; i++) { | ||
57 | if (trace_events[i].event_id == id) | ||
58 | return trace_events[i].name; | ||
59 | } | ||
60 | return NULL; | ||
61 | } | ||
62 | |||
63 | /* | 31 | /* |
64 | * magic2 = "PERFILE2" | 32 | * magic2 = "PERFILE2" |
65 | * must be a numerical value to let the endianness | 33 | * must be a numerical value to let the endianness |
@@ -2257,7 +2225,7 @@ static int perf_header__adds_write(struct perf_header *header, | |||
2257 | 2225 | ||
2258 | sec_size = sizeof(*feat_sec) * nr_sections; | 2226 | sec_size = sizeof(*feat_sec) * nr_sections; |
2259 | 2227 | ||
2260 | sec_start = header->data_offset + header->data_size; | 2228 | sec_start = header->feat_offset; |
2261 | lseek(fd, sec_start + sec_size, SEEK_SET); | 2229 | lseek(fd, sec_start + sec_size, SEEK_SET); |
2262 | 2230 | ||
2263 | for_each_set_bit(feat, header->adds_features, HEADER_FEAT_BITS) { | 2231 | for_each_set_bit(feat, header->adds_features, HEADER_FEAT_BITS) { |
@@ -2304,6 +2272,7 @@ int perf_session__write_header(struct perf_session *session, | |||
2304 | struct perf_file_attr f_attr; | 2272 | struct perf_file_attr f_attr; |
2305 | struct perf_header *header = &session->header; | 2273 | struct perf_header *header = &session->header; |
2306 | struct perf_evsel *evsel; | 2274 | struct perf_evsel *evsel; |
2275 | u64 attr_offset; | ||
2307 | int err; | 2276 | int err; |
2308 | 2277 | ||
2309 | lseek(fd, sizeof(f_header), SEEK_SET); | 2278 | lseek(fd, sizeof(f_header), SEEK_SET); |
@@ -2317,7 +2286,7 @@ int perf_session__write_header(struct perf_session *session, | |||
2317 | } | 2286 | } |
2318 | } | 2287 | } |
2319 | 2288 | ||
2320 | header->attr_offset = lseek(fd, 0, SEEK_CUR); | 2289 | attr_offset = lseek(fd, 0, SEEK_CUR); |
2321 | 2290 | ||
2322 | list_for_each_entry(evsel, &evlist->entries, node) { | 2291 | list_for_each_entry(evsel, &evlist->entries, node) { |
2323 | f_attr = (struct perf_file_attr){ | 2292 | f_attr = (struct perf_file_attr){ |
@@ -2334,17 +2303,8 @@ int perf_session__write_header(struct perf_session *session, | |||
2334 | } | 2303 | } |
2335 | } | 2304 | } |
2336 | 2305 | ||
2337 | header->event_offset = lseek(fd, 0, SEEK_CUR); | ||
2338 | header->event_size = trace_event_count * sizeof(struct perf_trace_event_type); | ||
2339 | if (trace_events) { | ||
2340 | err = do_write(fd, trace_events, header->event_size); | ||
2341 | if (err < 0) { | ||
2342 | pr_debug("failed to write perf header events\n"); | ||
2343 | return err; | ||
2344 | } | ||
2345 | } | ||
2346 | |||
2347 | header->data_offset = lseek(fd, 0, SEEK_CUR); | 2306 | header->data_offset = lseek(fd, 0, SEEK_CUR); |
2307 | header->feat_offset = header->data_offset + header->data_size; | ||
2348 | 2308 | ||
2349 | if (at_exit) { | 2309 | if (at_exit) { |
2350 | err = perf_header__adds_write(header, evlist, fd); | 2310 | err = perf_header__adds_write(header, evlist, fd); |
@@ -2357,17 +2317,14 @@ int perf_session__write_header(struct perf_session *session, | |||
2357 | .size = sizeof(f_header), | 2317 | .size = sizeof(f_header), |
2358 | .attr_size = sizeof(f_attr), | 2318 | .attr_size = sizeof(f_attr), |
2359 | .attrs = { | 2319 | .attrs = { |
2360 | .offset = header->attr_offset, | 2320 | .offset = attr_offset, |
2361 | .size = evlist->nr_entries * sizeof(f_attr), | 2321 | .size = evlist->nr_entries * sizeof(f_attr), |
2362 | }, | 2322 | }, |
2363 | .data = { | 2323 | .data = { |
2364 | .offset = header->data_offset, | 2324 | .offset = header->data_offset, |
2365 | .size = header->data_size, | 2325 | .size = header->data_size, |
2366 | }, | 2326 | }, |
2367 | .event_types = { | 2327 | /* event_types is ignored, store zeros */ |
2368 | .offset = header->event_offset, | ||
2369 | .size = header->event_size, | ||
2370 | }, | ||
2371 | }; | 2328 | }; |
2372 | 2329 | ||
2373 | memcpy(&f_header.adds_features, &header->adds_features, sizeof(header->adds_features)); | 2330 | memcpy(&f_header.adds_features, &header->adds_features, sizeof(header->adds_features)); |
@@ -2417,7 +2374,7 @@ int perf_header__process_sections(struct perf_header *header, int fd, | |||
2417 | 2374 | ||
2418 | sec_size = sizeof(*feat_sec) * nr_sections; | 2375 | sec_size = sizeof(*feat_sec) * nr_sections; |
2419 | 2376 | ||
2420 | lseek(fd, header->data_offset + header->data_size, SEEK_SET); | 2377 | lseek(fd, header->feat_offset, SEEK_SET); |
2421 | 2378 | ||
2422 | err = perf_header__getbuffer64(header, fd, feat_sec, sec_size); | 2379 | err = perf_header__getbuffer64(header, fd, feat_sec, sec_size); |
2423 | if (err < 0) | 2380 | if (err < 0) |
@@ -2523,6 +2480,7 @@ static int check_magic_endian(u64 magic, uint64_t hdr_sz, | |||
2523 | /* check for legacy format */ | 2480 | /* check for legacy format */ |
2524 | ret = memcmp(&magic, __perf_magic1, sizeof(magic)); | 2481 | ret = memcmp(&magic, __perf_magic1, sizeof(magic)); |
2525 | if (ret == 0) { | 2482 | if (ret == 0) { |
2483 | ph->version = PERF_HEADER_VERSION_1; | ||
2526 | pr_debug("legacy perf.data format\n"); | 2484 | pr_debug("legacy perf.data format\n"); |
2527 | if (is_pipe) | 2485 | if (is_pipe) |
2528 | return try_all_pipe_abis(hdr_sz, ph); | 2486 | return try_all_pipe_abis(hdr_sz, ph); |
@@ -2544,6 +2502,7 @@ static int check_magic_endian(u64 magic, uint64_t hdr_sz, | |||
2544 | return -1; | 2502 | return -1; |
2545 | 2503 | ||
2546 | ph->needs_swap = true; | 2504 | ph->needs_swap = true; |
2505 | ph->version = PERF_HEADER_VERSION_2; | ||
2547 | 2506 | ||
2548 | return 0; | 2507 | return 0; |
2549 | } | 2508 | } |
@@ -2614,10 +2573,9 @@ int perf_file_header__read(struct perf_file_header *header, | |||
2614 | memcpy(&ph->adds_features, &header->adds_features, | 2573 | memcpy(&ph->adds_features, &header->adds_features, |
2615 | sizeof(ph->adds_features)); | 2574 | sizeof(ph->adds_features)); |
2616 | 2575 | ||
2617 | ph->event_offset = header->event_types.offset; | ||
2618 | ph->event_size = header->event_types.size; | ||
2619 | ph->data_offset = header->data.offset; | 2576 | ph->data_offset = header->data.offset; |
2620 | ph->data_size = header->data.size; | 2577 | ph->data_size = header->data.size; |
2578 | ph->feat_offset = header->data.offset + header->data.size; | ||
2621 | return 0; | 2579 | return 0; |
2622 | } | 2580 | } |
2623 | 2581 | ||
@@ -2666,19 +2624,17 @@ static int perf_file_header__read_pipe(struct perf_pipe_file_header *header, | |||
2666 | return 0; | 2624 | return 0; |
2667 | } | 2625 | } |
2668 | 2626 | ||
2669 | static int perf_header__read_pipe(struct perf_session *session, int fd) | 2627 | static int perf_header__read_pipe(struct perf_session *session) |
2670 | { | 2628 | { |
2671 | struct perf_header *header = &session->header; | 2629 | struct perf_header *header = &session->header; |
2672 | struct perf_pipe_file_header f_header; | 2630 | struct perf_pipe_file_header f_header; |
2673 | 2631 | ||
2674 | if (perf_file_header__read_pipe(&f_header, header, fd, | 2632 | if (perf_file_header__read_pipe(&f_header, header, session->fd, |
2675 | session->repipe) < 0) { | 2633 | session->repipe) < 0) { |
2676 | pr_debug("incompatible file format\n"); | 2634 | pr_debug("incompatible file format\n"); |
2677 | return -EINVAL; | 2635 | return -EINVAL; |
2678 | } | 2636 | } |
2679 | 2637 | ||
2680 | session->fd = fd; | ||
2681 | |||
2682 | return 0; | 2638 | return 0; |
2683 | } | 2639 | } |
2684 | 2640 | ||
@@ -2772,20 +2728,21 @@ static int perf_evlist__prepare_tracepoint_events(struct perf_evlist *evlist, | |||
2772 | return 0; | 2728 | return 0; |
2773 | } | 2729 | } |
2774 | 2730 | ||
2775 | int perf_session__read_header(struct perf_session *session, int fd) | 2731 | int perf_session__read_header(struct perf_session *session) |
2776 | { | 2732 | { |
2777 | struct perf_header *header = &session->header; | 2733 | struct perf_header *header = &session->header; |
2778 | struct perf_file_header f_header; | 2734 | struct perf_file_header f_header; |
2779 | struct perf_file_attr f_attr; | 2735 | struct perf_file_attr f_attr; |
2780 | u64 f_id; | 2736 | u64 f_id; |
2781 | int nr_attrs, nr_ids, i, j; | 2737 | int nr_attrs, nr_ids, i, j; |
2738 | int fd = session->fd; | ||
2782 | 2739 | ||
2783 | session->evlist = perf_evlist__new(); | 2740 | session->evlist = perf_evlist__new(); |
2784 | if (session->evlist == NULL) | 2741 | if (session->evlist == NULL) |
2785 | return -ENOMEM; | 2742 | return -ENOMEM; |
2786 | 2743 | ||
2787 | if (session->fd_pipe) | 2744 | if (session->fd_pipe) |
2788 | return perf_header__read_pipe(session, fd); | 2745 | return perf_header__read_pipe(session); |
2789 | 2746 | ||
2790 | if (perf_file_header__read(&f_header, header, fd) < 0) | 2747 | if (perf_file_header__read(&f_header, header, fd) < 0) |
2791 | return -EINVAL; | 2748 | return -EINVAL; |
@@ -2839,22 +2796,9 @@ int perf_session__read_header(struct perf_session *session, int fd) | |||
2839 | 2796 | ||
2840 | symbol_conf.nr_events = nr_attrs; | 2797 | symbol_conf.nr_events = nr_attrs; |
2841 | 2798 | ||
2842 | if (f_header.event_types.size) { | ||
2843 | lseek(fd, f_header.event_types.offset, SEEK_SET); | ||
2844 | trace_events = malloc(f_header.event_types.size); | ||
2845 | if (trace_events == NULL) | ||
2846 | return -ENOMEM; | ||
2847 | if (perf_header__getbuffer64(header, fd, trace_events, | ||
2848 | f_header.event_types.size)) | ||
2849 | goto out_errno; | ||
2850 | trace_event_count = f_header.event_types.size / sizeof(struct perf_trace_event_type); | ||
2851 | } | ||
2852 | |||
2853 | perf_header__process_sections(header, fd, &session->pevent, | 2799 | perf_header__process_sections(header, fd, &session->pevent, |
2854 | perf_file_section__process); | 2800 | perf_file_section__process); |
2855 | 2801 | ||
2856 | lseek(fd, header->data_offset, SEEK_SET); | ||
2857 | |||
2858 | if (perf_evlist__prepare_tracepoint_events(session->evlist, | 2802 | if (perf_evlist__prepare_tracepoint_events(session->evlist, |
2859 | session->pevent)) | 2803 | session->pevent)) |
2860 | goto out_delete_evlist; | 2804 | goto out_delete_evlist; |
@@ -2922,7 +2866,8 @@ int perf_event__synthesize_attrs(struct perf_tool *tool, | |||
2922 | return err; | 2866 | return err; |
2923 | } | 2867 | } |
2924 | 2868 | ||
2925 | int perf_event__process_attr(union perf_event *event, | 2869 | int perf_event__process_attr(struct perf_tool *tool __maybe_unused, |
2870 | union perf_event *event, | ||
2926 | struct perf_evlist **pevlist) | 2871 | struct perf_evlist **pevlist) |
2927 | { | 2872 | { |
2928 | u32 i, ids, n_ids; | 2873 | u32 i, ids, n_ids; |
@@ -2961,64 +2906,6 @@ int perf_event__process_attr(union perf_event *event, | |||
2961 | return 0; | 2906 | return 0; |
2962 | } | 2907 | } |
2963 | 2908 | ||
2964 | int perf_event__synthesize_event_type(struct perf_tool *tool, | ||
2965 | u64 event_id, char *name, | ||
2966 | perf_event__handler_t process, | ||
2967 | struct machine *machine) | ||
2968 | { | ||
2969 | union perf_event ev; | ||
2970 | size_t size = 0; | ||
2971 | int err = 0; | ||
2972 | |||
2973 | memset(&ev, 0, sizeof(ev)); | ||
2974 | |||
2975 | ev.event_type.event_type.event_id = event_id; | ||
2976 | memset(ev.event_type.event_type.name, 0, MAX_EVENT_NAME); | ||
2977 | strncpy(ev.event_type.event_type.name, name, MAX_EVENT_NAME - 1); | ||
2978 | |||
2979 | ev.event_type.header.type = PERF_RECORD_HEADER_EVENT_TYPE; | ||
2980 | size = strlen(ev.event_type.event_type.name); | ||
2981 | size = PERF_ALIGN(size, sizeof(u64)); | ||
2982 | ev.event_type.header.size = sizeof(ev.event_type) - | ||
2983 | (sizeof(ev.event_type.event_type.name) - size); | ||
2984 | |||
2985 | err = process(tool, &ev, NULL, machine); | ||
2986 | |||
2987 | return err; | ||
2988 | } | ||
2989 | |||
2990 | int perf_event__synthesize_event_types(struct perf_tool *tool, | ||
2991 | perf_event__handler_t process, | ||
2992 | struct machine *machine) | ||
2993 | { | ||
2994 | struct perf_trace_event_type *type; | ||
2995 | int i, err = 0; | ||
2996 | |||
2997 | for (i = 0; i < trace_event_count; i++) { | ||
2998 | type = &trace_events[i]; | ||
2999 | |||
3000 | err = perf_event__synthesize_event_type(tool, type->event_id, | ||
3001 | type->name, process, | ||
3002 | machine); | ||
3003 | if (err) { | ||
3004 | pr_debug("failed to create perf header event type\n"); | ||
3005 | return err; | ||
3006 | } | ||
3007 | } | ||
3008 | |||
3009 | return err; | ||
3010 | } | ||
3011 | |||
3012 | int perf_event__process_event_type(struct perf_tool *tool __maybe_unused, | ||
3013 | union perf_event *event) | ||
3014 | { | ||
3015 | if (perf_header__push_event(event->event_type.event_type.event_id, | ||
3016 | event->event_type.event_type.name) < 0) | ||
3017 | return -ENOMEM; | ||
3018 | |||
3019 | return 0; | ||
3020 | } | ||
3021 | |||
3022 | int perf_event__synthesize_tracing_data(struct perf_tool *tool, int fd, | 2909 | int perf_event__synthesize_tracing_data(struct perf_tool *tool, int fd, |
3023 | struct perf_evlist *evlist, | 2910 | struct perf_evlist *evlist, |
3024 | perf_event__handler_t process) | 2911 | perf_event__handler_t process) |
@@ -3065,7 +2952,8 @@ int perf_event__synthesize_tracing_data(struct perf_tool *tool, int fd, | |||
3065 | return aligned_size; | 2952 | return aligned_size; |
3066 | } | 2953 | } |
3067 | 2954 | ||
3068 | int perf_event__process_tracing_data(union perf_event *event, | 2955 | int perf_event__process_tracing_data(struct perf_tool *tool __maybe_unused, |
2956 | union perf_event *event, | ||
3069 | struct perf_session *session) | 2957 | struct perf_session *session) |
3070 | { | 2958 | { |
3071 | ssize_t size_read, padding, size = event->tracing_data.size; | 2959 | ssize_t size_read, padding, size = event->tracing_data.size; |
diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h index 16a3e83c584e..307c9aed972e 100644 --- a/tools/perf/util/header.h +++ b/tools/perf/util/header.h | |||
@@ -34,6 +34,11 @@ enum { | |||
34 | HEADER_FEAT_BITS = 256, | 34 | HEADER_FEAT_BITS = 256, |
35 | }; | 35 | }; |
36 | 36 | ||
37 | enum perf_header_version { | ||
38 | PERF_HEADER_VERSION_1, | ||
39 | PERF_HEADER_VERSION_2, | ||
40 | }; | ||
41 | |||
37 | struct perf_file_section { | 42 | struct perf_file_section { |
38 | u64 offset; | 43 | u64 offset; |
39 | u64 size; | 44 | u64 size; |
@@ -45,6 +50,7 @@ struct perf_file_header { | |||
45 | u64 attr_size; | 50 | u64 attr_size; |
46 | struct perf_file_section attrs; | 51 | struct perf_file_section attrs; |
47 | struct perf_file_section data; | 52 | struct perf_file_section data; |
53 | /* event_types is ignored */ | ||
48 | struct perf_file_section event_types; | 54 | struct perf_file_section event_types; |
49 | DECLARE_BITMAP(adds_features, HEADER_FEAT_BITS); | 55 | DECLARE_BITMAP(adds_features, HEADER_FEAT_BITS); |
50 | }; | 56 | }; |
@@ -84,28 +90,24 @@ struct perf_session_env { | |||
84 | }; | 90 | }; |
85 | 91 | ||
86 | struct perf_header { | 92 | struct perf_header { |
87 | bool needs_swap; | 93 | enum perf_header_version version; |
88 | s64 attr_offset; | 94 | bool needs_swap; |
89 | u64 data_offset; | 95 | u64 data_offset; |
90 | u64 data_size; | 96 | u64 data_size; |
91 | u64 event_offset; | 97 | u64 feat_offset; |
92 | u64 event_size; | ||
93 | DECLARE_BITMAP(adds_features, HEADER_FEAT_BITS); | 98 | DECLARE_BITMAP(adds_features, HEADER_FEAT_BITS); |
94 | struct perf_session_env env; | 99 | struct perf_session_env env; |
95 | }; | 100 | }; |
96 | 101 | ||
97 | struct perf_evlist; | 102 | struct perf_evlist; |
98 | struct perf_session; | 103 | struct perf_session; |
99 | 104 | ||
100 | int perf_session__read_header(struct perf_session *session, int fd); | 105 | int perf_session__read_header(struct perf_session *session); |
101 | int perf_session__write_header(struct perf_session *session, | 106 | int perf_session__write_header(struct perf_session *session, |
102 | struct perf_evlist *evlist, | 107 | struct perf_evlist *evlist, |
103 | int fd, bool at_exit); | 108 | int fd, bool at_exit); |
104 | int perf_header__write_pipe(int fd); | 109 | int perf_header__write_pipe(int fd); |
105 | 110 | ||
106 | int perf_header__push_event(u64 id, const char *name); | ||
107 | char *perf_header__find_event(u64 id); | ||
108 | |||
109 | void perf_header__set_feat(struct perf_header *header, int feat); | 111 | void perf_header__set_feat(struct perf_header *header, int feat); |
110 | void perf_header__clear_feat(struct perf_header *header, int feat); | 112 | void perf_header__clear_feat(struct perf_header *header, int feat); |
111 | bool perf_header__has_feat(const struct perf_header *header, int feat); | 113 | bool perf_header__has_feat(const struct perf_header *header, int feat); |
@@ -130,22 +132,14 @@ int perf_event__synthesize_attr(struct perf_tool *tool, | |||
130 | int perf_event__synthesize_attrs(struct perf_tool *tool, | 132 | int perf_event__synthesize_attrs(struct perf_tool *tool, |
131 | struct perf_session *session, | 133 | struct perf_session *session, |
132 | perf_event__handler_t process); | 134 | perf_event__handler_t process); |
133 | int perf_event__process_attr(union perf_event *event, struct perf_evlist **pevlist); | 135 | int perf_event__process_attr(struct perf_tool *tool, union perf_event *event, |
134 | 136 | struct perf_evlist **pevlist); | |
135 | int perf_event__synthesize_event_type(struct perf_tool *tool, | ||
136 | u64 event_id, char *name, | ||
137 | perf_event__handler_t process, | ||
138 | struct machine *machine); | ||
139 | int perf_event__synthesize_event_types(struct perf_tool *tool, | ||
140 | perf_event__handler_t process, | ||
141 | struct machine *machine); | ||
142 | int perf_event__process_event_type(struct perf_tool *tool, | ||
143 | union perf_event *event); | ||
144 | 137 | ||
145 | int perf_event__synthesize_tracing_data(struct perf_tool *tool, | 138 | int perf_event__synthesize_tracing_data(struct perf_tool *tool, |
146 | int fd, struct perf_evlist *evlist, | 139 | int fd, struct perf_evlist *evlist, |
147 | perf_event__handler_t process); | 140 | perf_event__handler_t process); |
148 | int perf_event__process_tracing_data(union perf_event *event, | 141 | int perf_event__process_tracing_data(struct perf_tool *tool, |
142 | union perf_event *event, | ||
149 | struct perf_session *session); | 143 | struct perf_session *session); |
150 | 144 | ||
151 | int perf_event__synthesize_build_id(struct perf_tool *tool, | 145 | int perf_event__synthesize_build_id(struct perf_tool *tool, |
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c index b11a6cfdb414..a9dd1b9d8907 100644 --- a/tools/perf/util/hist.c +++ b/tools/perf/util/hist.c | |||
@@ -912,6 +912,7 @@ static struct hist_entry *hists__add_dummy_entry(struct hists *hists, | |||
912 | rb_link_node(&he->rb_node_in, parent, p); | 912 | rb_link_node(&he->rb_node_in, parent, p); |
913 | rb_insert_color(&he->rb_node_in, root); | 913 | rb_insert_color(&he->rb_node_in, root); |
914 | hists__inc_nr_entries(hists, he); | 914 | hists__inc_nr_entries(hists, he); |
915 | he->dummy = true; | ||
915 | } | 916 | } |
916 | out: | 917 | out: |
917 | return he; | 918 | return he; |
diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h index 2d3790fd99bb..1329b6b6ffe6 100644 --- a/tools/perf/util/hist.h +++ b/tools/perf/util/hist.h | |||
@@ -141,10 +141,12 @@ struct perf_hpp { | |||
141 | }; | 141 | }; |
142 | 142 | ||
143 | struct perf_hpp_fmt { | 143 | struct perf_hpp_fmt { |
144 | int (*header)(struct perf_hpp *hpp); | 144 | int (*header)(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp); |
145 | int (*width)(struct perf_hpp *hpp); | 145 | int (*width)(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp); |
146 | int (*color)(struct perf_hpp *hpp, struct hist_entry *he); | 146 | int (*color)(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp, |
147 | int (*entry)(struct perf_hpp *hpp, struct hist_entry *he); | 147 | struct hist_entry *he); |
148 | int (*entry)(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp, | ||
149 | struct hist_entry *he); | ||
148 | 150 | ||
149 | struct list_head list; | 151 | struct list_head list; |
150 | }; | 152 | }; |
@@ -157,7 +159,7 @@ extern struct list_head perf_hpp__list; | |||
157 | extern struct perf_hpp_fmt perf_hpp__format[]; | 159 | extern struct perf_hpp_fmt perf_hpp__format[]; |
158 | 160 | ||
159 | enum { | 161 | enum { |
160 | PERF_HPP__BASELINE, | 162 | /* Matches perf_hpp__format array. */ |
161 | PERF_HPP__OVERHEAD, | 163 | PERF_HPP__OVERHEAD, |
162 | PERF_HPP__OVERHEAD_SYS, | 164 | PERF_HPP__OVERHEAD_SYS, |
163 | PERF_HPP__OVERHEAD_US, | 165 | PERF_HPP__OVERHEAD_US, |
@@ -165,11 +167,6 @@ enum { | |||
165 | PERF_HPP__OVERHEAD_GUEST_US, | 167 | PERF_HPP__OVERHEAD_GUEST_US, |
166 | PERF_HPP__SAMPLES, | 168 | PERF_HPP__SAMPLES, |
167 | PERF_HPP__PERIOD, | 169 | PERF_HPP__PERIOD, |
168 | PERF_HPP__PERIOD_BASELINE, | ||
169 | PERF_HPP__DELTA, | ||
170 | PERF_HPP__RATIO, | ||
171 | PERF_HPP__WEIGHTED_DIFF, | ||
172 | PERF_HPP__FORMULA, | ||
173 | 170 | ||
174 | PERF_HPP__MAX_INDEX | 171 | PERF_HPP__MAX_INDEX |
175 | }; | 172 | }; |
@@ -177,8 +174,6 @@ enum { | |||
177 | void perf_hpp__init(void); | 174 | void perf_hpp__init(void); |
178 | void perf_hpp__column_register(struct perf_hpp_fmt *format); | 175 | void perf_hpp__column_register(struct perf_hpp_fmt *format); |
179 | void perf_hpp__column_enable(unsigned col); | 176 | void perf_hpp__column_enable(unsigned col); |
180 | int hist_entry__period_snprintf(struct perf_hpp *hpp, struct hist_entry *he, | ||
181 | bool color); | ||
182 | 177 | ||
183 | struct perf_evlist; | 178 | struct perf_evlist; |
184 | 179 | ||
@@ -245,11 +240,4 @@ int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist __maybe_unused, | |||
245 | #endif | 240 | #endif |
246 | 241 | ||
247 | unsigned int hists__sort_list_width(struct hists *self); | 242 | unsigned int hists__sort_list_width(struct hists *self); |
248 | |||
249 | double perf_diff__compute_delta(struct hist_entry *he, struct hist_entry *pair); | ||
250 | double perf_diff__compute_ratio(struct hist_entry *he, struct hist_entry *pair); | ||
251 | s64 perf_diff__compute_wdiff(struct hist_entry *he, struct hist_entry *pair); | ||
252 | int perf_diff__formula(struct hist_entry *he, struct hist_entry *pair, | ||
253 | char *buf, size_t size); | ||
254 | double perf_diff__period_percent(struct hist_entry *he, u64 period); | ||
255 | #endif /* __PERF_HIST_H */ | 243 | #endif /* __PERF_HIST_H */ |
diff --git a/tools/perf/util/include/linux/string.h b/tools/perf/util/include/linux/string.h index 6f19c548ecc0..97a800738226 100644 --- a/tools/perf/util/include/linux/string.h +++ b/tools/perf/util/include/linux/string.h | |||
@@ -1,3 +1,4 @@ | |||
1 | #include <string.h> | 1 | #include <string.h> |
2 | 2 | ||
3 | void *memdup(const void *src, size_t len); | 3 | void *memdup(const void *src, size_t len); |
4 | int str_append(char **s, int *len, const char *a); | ||
diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c index b2ecad6ec46b..f9f9d6381b9a 100644 --- a/tools/perf/util/machine.c +++ b/tools/perf/util/machine.c | |||
@@ -233,7 +233,7 @@ void machines__set_id_hdr_size(struct machines *machines, u16 id_hdr_size) | |||
233 | return; | 233 | return; |
234 | } | 234 | } |
235 | 235 | ||
236 | static struct thread *__machine__findnew_thread(struct machine *machine, pid_t pid, | 236 | static struct thread *__machine__findnew_thread(struct machine *machine, pid_t tid, |
237 | bool create) | 237 | bool create) |
238 | { | 238 | { |
239 | struct rb_node **p = &machine->threads.rb_node; | 239 | struct rb_node **p = &machine->threads.rb_node; |
@@ -241,23 +241,23 @@ static struct thread *__machine__findnew_thread(struct machine *machine, pid_t p | |||
241 | struct thread *th; | 241 | struct thread *th; |
242 | 242 | ||
243 | /* | 243 | /* |
244 | * Font-end cache - PID lookups come in blocks, | 244 | * Front-end cache - TID lookups come in blocks, |
245 | * so most of the time we dont have to look up | 245 | * so most of the time we dont have to look up |
246 | * the full rbtree: | 246 | * the full rbtree: |
247 | */ | 247 | */ |
248 | if (machine->last_match && machine->last_match->pid == pid) | 248 | if (machine->last_match && machine->last_match->tid == tid) |
249 | return machine->last_match; | 249 | return machine->last_match; |
250 | 250 | ||
251 | while (*p != NULL) { | 251 | while (*p != NULL) { |
252 | parent = *p; | 252 | parent = *p; |
253 | th = rb_entry(parent, struct thread, rb_node); | 253 | th = rb_entry(parent, struct thread, rb_node); |
254 | 254 | ||
255 | if (th->pid == pid) { | 255 | if (th->tid == tid) { |
256 | machine->last_match = th; | 256 | machine->last_match = th; |
257 | return th; | 257 | return th; |
258 | } | 258 | } |
259 | 259 | ||
260 | if (pid < th->pid) | 260 | if (tid < th->tid) |
261 | p = &(*p)->rb_left; | 261 | p = &(*p)->rb_left; |
262 | else | 262 | else |
263 | p = &(*p)->rb_right; | 263 | p = &(*p)->rb_right; |
@@ -266,7 +266,7 @@ static struct thread *__machine__findnew_thread(struct machine *machine, pid_t p | |||
266 | if (!create) | 266 | if (!create) |
267 | return NULL; | 267 | return NULL; |
268 | 268 | ||
269 | th = thread__new(pid); | 269 | th = thread__new(tid); |
270 | if (th != NULL) { | 270 | if (th != NULL) { |
271 | rb_link_node(&th->rb_node, parent, p); | 271 | rb_link_node(&th->rb_node, parent, p); |
272 | rb_insert_color(&th->rb_node, &machine->threads); | 272 | rb_insert_color(&th->rb_node, &machine->threads); |
@@ -276,14 +276,14 @@ static struct thread *__machine__findnew_thread(struct machine *machine, pid_t p | |||
276 | return th; | 276 | return th; |
277 | } | 277 | } |
278 | 278 | ||
279 | struct thread *machine__findnew_thread(struct machine *machine, pid_t pid) | 279 | struct thread *machine__findnew_thread(struct machine *machine, pid_t tid) |
280 | { | 280 | { |
281 | return __machine__findnew_thread(machine, pid, true); | 281 | return __machine__findnew_thread(machine, tid, true); |
282 | } | 282 | } |
283 | 283 | ||
284 | struct thread *machine__find_thread(struct machine *machine, pid_t pid) | 284 | struct thread *machine__find_thread(struct machine *machine, pid_t tid) |
285 | { | 285 | { |
286 | return __machine__findnew_thread(machine, pid, false); | 286 | return __machine__findnew_thread(machine, tid, false); |
287 | } | 287 | } |
288 | 288 | ||
289 | int machine__process_comm_event(struct machine *machine, union perf_event *event) | 289 | int machine__process_comm_event(struct machine *machine, union perf_event *event) |
@@ -1058,11 +1058,10 @@ int machine__process_event(struct machine *machine, union perf_event *event) | |||
1058 | return ret; | 1058 | return ret; |
1059 | } | 1059 | } |
1060 | 1060 | ||
1061 | static bool symbol__match_parent_regex(struct symbol *sym) | 1061 | static bool symbol__match_regex(struct symbol *sym, regex_t *regex) |
1062 | { | 1062 | { |
1063 | if (sym->name && !regexec(&parent_regex, sym->name, 0, NULL, 0)) | 1063 | if (sym->name && !regexec(regex, sym->name, 0, NULL, 0)) |
1064 | return 1; | 1064 | return 1; |
1065 | |||
1066 | return 0; | 1065 | return 0; |
1067 | } | 1066 | } |
1068 | 1067 | ||
@@ -1159,8 +1158,8 @@ struct branch_info *machine__resolve_bstack(struct machine *machine, | |||
1159 | static int machine__resolve_callchain_sample(struct machine *machine, | 1158 | static int machine__resolve_callchain_sample(struct machine *machine, |
1160 | struct thread *thread, | 1159 | struct thread *thread, |
1161 | struct ip_callchain *chain, | 1160 | struct ip_callchain *chain, |
1162 | struct symbol **parent) | 1161 | struct symbol **parent, |
1163 | 1162 | struct addr_location *root_al) | |
1164 | { | 1163 | { |
1165 | u8 cpumode = PERF_RECORD_MISC_USER; | 1164 | u8 cpumode = PERF_RECORD_MISC_USER; |
1166 | unsigned int i; | 1165 | unsigned int i; |
@@ -1211,8 +1210,15 @@ static int machine__resolve_callchain_sample(struct machine *machine, | |||
1211 | MAP__FUNCTION, ip, &al, NULL); | 1210 | MAP__FUNCTION, ip, &al, NULL); |
1212 | if (al.sym != NULL) { | 1211 | if (al.sym != NULL) { |
1213 | if (sort__has_parent && !*parent && | 1212 | if (sort__has_parent && !*parent && |
1214 | symbol__match_parent_regex(al.sym)) | 1213 | symbol__match_regex(al.sym, &parent_regex)) |
1215 | *parent = al.sym; | 1214 | *parent = al.sym; |
1215 | else if (have_ignore_callees && root_al && | ||
1216 | symbol__match_regex(al.sym, &ignore_callees_regex)) { | ||
1217 | /* Treat this symbol as the root, | ||
1218 | forgetting its callees. */ | ||
1219 | *root_al = al; | ||
1220 | callchain_cursor_reset(&callchain_cursor); | ||
1221 | } | ||
1216 | if (!symbol_conf.use_callchain) | 1222 | if (!symbol_conf.use_callchain) |
1217 | break; | 1223 | break; |
1218 | } | 1224 | } |
@@ -1237,15 +1243,13 @@ int machine__resolve_callchain(struct machine *machine, | |||
1237 | struct perf_evsel *evsel, | 1243 | struct perf_evsel *evsel, |
1238 | struct thread *thread, | 1244 | struct thread *thread, |
1239 | struct perf_sample *sample, | 1245 | struct perf_sample *sample, |
1240 | struct symbol **parent) | 1246 | struct symbol **parent, |
1241 | 1247 | struct addr_location *root_al) | |
1242 | { | 1248 | { |
1243 | int ret; | 1249 | int ret; |
1244 | 1250 | ||
1245 | callchain_cursor_reset(&callchain_cursor); | ||
1246 | |||
1247 | ret = machine__resolve_callchain_sample(machine, thread, | 1251 | ret = machine__resolve_callchain_sample(machine, thread, |
1248 | sample->callchain, parent); | 1252 | sample->callchain, parent, root_al); |
1249 | if (ret) | 1253 | if (ret) |
1250 | return ret; | 1254 | return ret; |
1251 | 1255 | ||
diff --git a/tools/perf/util/machine.h b/tools/perf/util/machine.h index 77940680f1fc..5bb6244194d5 100644 --- a/tools/perf/util/machine.h +++ b/tools/perf/util/machine.h | |||
@@ -5,6 +5,7 @@ | |||
5 | #include <linux/rbtree.h> | 5 | #include <linux/rbtree.h> |
6 | #include "map.h" | 6 | #include "map.h" |
7 | 7 | ||
8 | struct addr_location; | ||
8 | struct branch_stack; | 9 | struct branch_stack; |
9 | struct perf_evsel; | 10 | struct perf_evsel; |
10 | struct perf_sample; | 11 | struct perf_sample; |
@@ -36,7 +37,7 @@ struct map *machine__kernel_map(struct machine *machine, enum map_type type) | |||
36 | return machine->vmlinux_maps[type]; | 37 | return machine->vmlinux_maps[type]; |
37 | } | 38 | } |
38 | 39 | ||
39 | struct thread *machine__find_thread(struct machine *machine, pid_t pid); | 40 | struct thread *machine__find_thread(struct machine *machine, pid_t tid); |
40 | 41 | ||
41 | int machine__process_comm_event(struct machine *machine, union perf_event *event); | 42 | int machine__process_comm_event(struct machine *machine, union perf_event *event); |
42 | int machine__process_exit_event(struct machine *machine, union perf_event *event); | 43 | int machine__process_exit_event(struct machine *machine, union perf_event *event); |
@@ -83,7 +84,8 @@ int machine__resolve_callchain(struct machine *machine, | |||
83 | struct perf_evsel *evsel, | 84 | struct perf_evsel *evsel, |
84 | struct thread *thread, | 85 | struct thread *thread, |
85 | struct perf_sample *sample, | 86 | struct perf_sample *sample, |
86 | struct symbol **parent); | 87 | struct symbol **parent, |
88 | struct addr_location *root_al); | ||
87 | 89 | ||
88 | /* | 90 | /* |
89 | * Default guest kernel is defined by parameter --guestkallsyms | 91 | * Default guest kernel is defined by parameter --guestkallsyms |
@@ -99,7 +101,7 @@ static inline bool machine__is_host(struct machine *machine) | |||
99 | return machine ? machine->pid == HOST_KERNEL_ID : false; | 101 | return machine ? machine->pid == HOST_KERNEL_ID : false; |
100 | } | 102 | } |
101 | 103 | ||
102 | struct thread *machine__findnew_thread(struct machine *machine, pid_t pid); | 104 | struct thread *machine__findnew_thread(struct machine *machine, pid_t tid); |
103 | 105 | ||
104 | size_t machine__fprintf(struct machine *machine, FILE *fp); | 106 | size_t machine__fprintf(struct machine *machine, FILE *fp); |
105 | 107 | ||
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index 995fc25db8c6..2c460ede0a69 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c | |||
@@ -6,7 +6,7 @@ | |||
6 | #include "parse-options.h" | 6 | #include "parse-options.h" |
7 | #include "parse-events.h" | 7 | #include "parse-events.h" |
8 | #include "exec_cmd.h" | 8 | #include "exec_cmd.h" |
9 | #include "string.h" | 9 | #include "linux/string.h" |
10 | #include "symbol.h" | 10 | #include "symbol.h" |
11 | #include "cache.h" | 11 | #include "cache.h" |
12 | #include "header.h" | 12 | #include "header.h" |
@@ -217,6 +217,29 @@ struct tracepoint_path *tracepoint_id_to_path(u64 config) | |||
217 | return NULL; | 217 | return NULL; |
218 | } | 218 | } |
219 | 219 | ||
220 | struct tracepoint_path *tracepoint_name_to_path(const char *name) | ||
221 | { | ||
222 | struct tracepoint_path *path = zalloc(sizeof(*path)); | ||
223 | char *str = strchr(name, ':'); | ||
224 | |||
225 | if (path == NULL || str == NULL) { | ||
226 | free(path); | ||
227 | return NULL; | ||
228 | } | ||
229 | |||
230 | path->system = strndup(name, str - name); | ||
231 | path->name = strdup(str+1); | ||
232 | |||
233 | if (path->system == NULL || path->name == NULL) { | ||
234 | free(path->system); | ||
235 | free(path->name); | ||
236 | free(path); | ||
237 | path = NULL; | ||
238 | } | ||
239 | |||
240 | return path; | ||
241 | } | ||
242 | |||
220 | const char *event_type(int type) | 243 | const char *event_type(int type) |
221 | { | 244 | { |
222 | switch (type) { | 245 | switch (type) { |
@@ -241,40 +264,29 @@ const char *event_type(int type) | |||
241 | 264 | ||
242 | 265 | ||
243 | 266 | ||
244 | static int __add_event(struct list_head **_list, int *idx, | 267 | static int __add_event(struct list_head *list, int *idx, |
245 | struct perf_event_attr *attr, | 268 | struct perf_event_attr *attr, |
246 | char *name, struct cpu_map *cpus) | 269 | char *name, struct cpu_map *cpus) |
247 | { | 270 | { |
248 | struct perf_evsel *evsel; | 271 | struct perf_evsel *evsel; |
249 | struct list_head *list = *_list; | ||
250 | |||
251 | if (!list) { | ||
252 | list = malloc(sizeof(*list)); | ||
253 | if (!list) | ||
254 | return -ENOMEM; | ||
255 | INIT_LIST_HEAD(list); | ||
256 | } | ||
257 | 272 | ||
258 | event_attr_init(attr); | 273 | event_attr_init(attr); |
259 | 274 | ||
260 | evsel = perf_evsel__new(attr, (*idx)++); | 275 | evsel = perf_evsel__new(attr, (*idx)++); |
261 | if (!evsel) { | 276 | if (!evsel) |
262 | free(list); | ||
263 | return -ENOMEM; | 277 | return -ENOMEM; |
264 | } | ||
265 | 278 | ||
266 | evsel->cpus = cpus; | 279 | evsel->cpus = cpus; |
267 | if (name) | 280 | if (name) |
268 | evsel->name = strdup(name); | 281 | evsel->name = strdup(name); |
269 | list_add_tail(&evsel->node, list); | 282 | list_add_tail(&evsel->node, list); |
270 | *_list = list; | ||
271 | return 0; | 283 | return 0; |
272 | } | 284 | } |
273 | 285 | ||
274 | static int add_event(struct list_head **_list, int *idx, | 286 | static int add_event(struct list_head *list, int *idx, |
275 | struct perf_event_attr *attr, char *name) | 287 | struct perf_event_attr *attr, char *name) |
276 | { | 288 | { |
277 | return __add_event(_list, idx, attr, name, NULL); | 289 | return __add_event(list, idx, attr, name, NULL); |
278 | } | 290 | } |
279 | 291 | ||
280 | static int parse_aliases(char *str, const char *names[][PERF_EVSEL__MAX_ALIASES], int size) | 292 | static int parse_aliases(char *str, const char *names[][PERF_EVSEL__MAX_ALIASES], int size) |
@@ -295,7 +307,7 @@ static int parse_aliases(char *str, const char *names[][PERF_EVSEL__MAX_ALIASES] | |||
295 | return -1; | 307 | return -1; |
296 | } | 308 | } |
297 | 309 | ||
298 | int parse_events_add_cache(struct list_head **list, int *idx, | 310 | int parse_events_add_cache(struct list_head *list, int *idx, |
299 | char *type, char *op_result1, char *op_result2) | 311 | char *type, char *op_result1, char *op_result2) |
300 | { | 312 | { |
301 | struct perf_event_attr attr; | 313 | struct perf_event_attr attr; |
@@ -356,31 +368,21 @@ int parse_events_add_cache(struct list_head **list, int *idx, | |||
356 | return add_event(list, idx, &attr, name); | 368 | return add_event(list, idx, &attr, name); |
357 | } | 369 | } |
358 | 370 | ||
359 | static int add_tracepoint(struct list_head **listp, int *idx, | 371 | static int add_tracepoint(struct list_head *list, int *idx, |
360 | char *sys_name, char *evt_name) | 372 | char *sys_name, char *evt_name) |
361 | { | 373 | { |
362 | struct perf_evsel *evsel; | 374 | struct perf_evsel *evsel; |
363 | struct list_head *list = *listp; | ||
364 | |||
365 | if (!list) { | ||
366 | list = malloc(sizeof(*list)); | ||
367 | if (!list) | ||
368 | return -ENOMEM; | ||
369 | INIT_LIST_HEAD(list); | ||
370 | } | ||
371 | 375 | ||
372 | evsel = perf_evsel__newtp(sys_name, evt_name, (*idx)++); | 376 | evsel = perf_evsel__newtp(sys_name, evt_name, (*idx)++); |
373 | if (!evsel) { | 377 | if (!evsel) |
374 | free(list); | ||
375 | return -ENOMEM; | 378 | return -ENOMEM; |
376 | } | ||
377 | 379 | ||
378 | list_add_tail(&evsel->node, list); | 380 | list_add_tail(&evsel->node, list); |
379 | *listp = list; | 381 | |
380 | return 0; | 382 | return 0; |
381 | } | 383 | } |
382 | 384 | ||
383 | static int add_tracepoint_multi_event(struct list_head **list, int *idx, | 385 | static int add_tracepoint_multi_event(struct list_head *list, int *idx, |
384 | char *sys_name, char *evt_name) | 386 | char *sys_name, char *evt_name) |
385 | { | 387 | { |
386 | char evt_path[MAXPATHLEN]; | 388 | char evt_path[MAXPATHLEN]; |
@@ -412,7 +414,7 @@ static int add_tracepoint_multi_event(struct list_head **list, int *idx, | |||
412 | return ret; | 414 | return ret; |
413 | } | 415 | } |
414 | 416 | ||
415 | static int add_tracepoint_event(struct list_head **list, int *idx, | 417 | static int add_tracepoint_event(struct list_head *list, int *idx, |
416 | char *sys_name, char *evt_name) | 418 | char *sys_name, char *evt_name) |
417 | { | 419 | { |
418 | return strpbrk(evt_name, "*?") ? | 420 | return strpbrk(evt_name, "*?") ? |
@@ -420,7 +422,7 @@ static int add_tracepoint_event(struct list_head **list, int *idx, | |||
420 | add_tracepoint(list, idx, sys_name, evt_name); | 422 | add_tracepoint(list, idx, sys_name, evt_name); |
421 | } | 423 | } |
422 | 424 | ||
423 | static int add_tracepoint_multi_sys(struct list_head **list, int *idx, | 425 | static int add_tracepoint_multi_sys(struct list_head *list, int *idx, |
424 | char *sys_name, char *evt_name) | 426 | char *sys_name, char *evt_name) |
425 | { | 427 | { |
426 | struct dirent *events_ent; | 428 | struct dirent *events_ent; |
@@ -452,7 +454,7 @@ static int add_tracepoint_multi_sys(struct list_head **list, int *idx, | |||
452 | return ret; | 454 | return ret; |
453 | } | 455 | } |
454 | 456 | ||
455 | int parse_events_add_tracepoint(struct list_head **list, int *idx, | 457 | int parse_events_add_tracepoint(struct list_head *list, int *idx, |
456 | char *sys, char *event) | 458 | char *sys, char *event) |
457 | { | 459 | { |
458 | int ret; | 460 | int ret; |
@@ -507,7 +509,7 @@ do { \ | |||
507 | return 0; | 509 | return 0; |
508 | } | 510 | } |
509 | 511 | ||
510 | int parse_events_add_breakpoint(struct list_head **list, int *idx, | 512 | int parse_events_add_breakpoint(struct list_head *list, int *idx, |
511 | void *ptr, char *type) | 513 | void *ptr, char *type) |
512 | { | 514 | { |
513 | struct perf_event_attr attr; | 515 | struct perf_event_attr attr; |
@@ -588,7 +590,7 @@ static int config_attr(struct perf_event_attr *attr, | |||
588 | return 0; | 590 | return 0; |
589 | } | 591 | } |
590 | 592 | ||
591 | int parse_events_add_numeric(struct list_head **list, int *idx, | 593 | int parse_events_add_numeric(struct list_head *list, int *idx, |
592 | u32 type, u64 config, | 594 | u32 type, u64 config, |
593 | struct list_head *head_config) | 595 | struct list_head *head_config) |
594 | { | 596 | { |
@@ -621,7 +623,7 @@ static char *pmu_event_name(struct list_head *head_terms) | |||
621 | return NULL; | 623 | return NULL; |
622 | } | 624 | } |
623 | 625 | ||
624 | int parse_events_add_pmu(struct list_head **list, int *idx, | 626 | int parse_events_add_pmu(struct list_head *list, int *idx, |
625 | char *name, struct list_head *head_config) | 627 | char *name, struct list_head *head_config) |
626 | { | 628 | { |
627 | struct perf_event_attr attr; | 629 | struct perf_event_attr attr; |
@@ -664,6 +666,7 @@ void parse_events__set_leader(char *name, struct list_head *list) | |||
664 | leader->group_name = name ? strdup(name) : NULL; | 666 | leader->group_name = name ? strdup(name) : NULL; |
665 | } | 667 | } |
666 | 668 | ||
669 | /* list_event is assumed to point to malloc'ed memory */ | ||
667 | void parse_events_update_lists(struct list_head *list_event, | 670 | void parse_events_update_lists(struct list_head *list_event, |
668 | struct list_head *list_all) | 671 | struct list_head *list_all) |
669 | { | 672 | { |
@@ -820,6 +823,32 @@ int parse_events_name(struct list_head *list, char *name) | |||
820 | return 0; | 823 | return 0; |
821 | } | 824 | } |
822 | 825 | ||
826 | static int parse_events__scanner(const char *str, void *data, int start_token); | ||
827 | |||
828 | static int parse_events_fixup(int ret, const char *str, void *data, | ||
829 | int start_token) | ||
830 | { | ||
831 | char *o = strdup(str); | ||
832 | char *s = NULL; | ||
833 | char *t = o; | ||
834 | char *p; | ||
835 | int len = 0; | ||
836 | |||
837 | if (!o) | ||
838 | return ret; | ||
839 | while ((p = strsep(&t, ",")) != NULL) { | ||
840 | if (s) | ||
841 | str_append(&s, &len, ","); | ||
842 | str_append(&s, &len, "cpu/"); | ||
843 | str_append(&s, &len, p); | ||
844 | str_append(&s, &len, "/"); | ||
845 | } | ||
846 | free(o); | ||
847 | if (!s) | ||
848 | return -ENOMEM; | ||
849 | return parse_events__scanner(s, data, start_token); | ||
850 | } | ||
851 | |||
823 | static int parse_events__scanner(const char *str, void *data, int start_token) | 852 | static int parse_events__scanner(const char *str, void *data, int start_token) |
824 | { | 853 | { |
825 | YY_BUFFER_STATE buffer; | 854 | YY_BUFFER_STATE buffer; |
@@ -840,6 +869,8 @@ static int parse_events__scanner(const char *str, void *data, int start_token) | |||
840 | parse_events__flush_buffer(buffer, scanner); | 869 | parse_events__flush_buffer(buffer, scanner); |
841 | parse_events__delete_buffer(buffer, scanner); | 870 | parse_events__delete_buffer(buffer, scanner); |
842 | parse_events_lex_destroy(scanner); | 871 | parse_events_lex_destroy(scanner); |
872 | if (ret && !strchr(str, '/')) | ||
873 | ret = parse_events_fixup(ret, str, data, start_token); | ||
843 | return ret; | 874 | return ret; |
844 | } | 875 | } |
845 | 876 | ||
@@ -1079,6 +1110,8 @@ int print_hwcache_events(const char *event_glob, bool name_only) | |||
1079 | } | 1110 | } |
1080 | } | 1111 | } |
1081 | 1112 | ||
1113 | if (printed) | ||
1114 | printf("\n"); | ||
1082 | return printed; | 1115 | return printed; |
1083 | } | 1116 | } |
1084 | 1117 | ||
@@ -1133,11 +1166,12 @@ void print_events(const char *event_glob, bool name_only) | |||
1133 | 1166 | ||
1134 | print_hwcache_events(event_glob, name_only); | 1167 | print_hwcache_events(event_glob, name_only); |
1135 | 1168 | ||
1169 | print_pmu_events(event_glob, name_only); | ||
1170 | |||
1136 | if (event_glob != NULL) | 1171 | if (event_glob != NULL) |
1137 | return; | 1172 | return; |
1138 | 1173 | ||
1139 | if (!name_only) { | 1174 | if (!name_only) { |
1140 | printf("\n"); | ||
1141 | printf(" %-50s [%s]\n", | 1175 | printf(" %-50s [%s]\n", |
1142 | "rNNN", | 1176 | "rNNN", |
1143 | event_type_descriptors[PERF_TYPE_RAW]); | 1177 | event_type_descriptors[PERF_TYPE_RAW]); |
@@ -1237,6 +1271,4 @@ void parse_events__free_terms(struct list_head *terms) | |||
1237 | 1271 | ||
1238 | list_for_each_entry_safe(term, h, terms, list) | 1272 | list_for_each_entry_safe(term, h, terms, list) |
1239 | free(term); | 1273 | free(term); |
1240 | |||
1241 | free(terms); | ||
1242 | } | 1274 | } |
diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h index 8a4859315fd9..f1cb4c4b3c70 100644 --- a/tools/perf/util/parse-events.h +++ b/tools/perf/util/parse-events.h | |||
@@ -23,6 +23,7 @@ struct tracepoint_path { | |||
23 | }; | 23 | }; |
24 | 24 | ||
25 | extern struct tracepoint_path *tracepoint_id_to_path(u64 config); | 25 | extern struct tracepoint_path *tracepoint_id_to_path(u64 config); |
26 | extern struct tracepoint_path *tracepoint_name_to_path(const char *name); | ||
26 | extern bool have_tracepoints(struct list_head *evlist); | 27 | extern bool have_tracepoints(struct list_head *evlist); |
27 | 28 | ||
28 | const char *event_type(int type); | 29 | const char *event_type(int type); |
@@ -84,16 +85,16 @@ void parse_events__free_terms(struct list_head *terms); | |||
84 | int parse_events__modifier_event(struct list_head *list, char *str, bool add); | 85 | int parse_events__modifier_event(struct list_head *list, char *str, bool add); |
85 | int parse_events__modifier_group(struct list_head *list, char *event_mod); | 86 | int parse_events__modifier_group(struct list_head *list, char *event_mod); |
86 | int parse_events_name(struct list_head *list, char *name); | 87 | int parse_events_name(struct list_head *list, char *name); |
87 | int parse_events_add_tracepoint(struct list_head **list, int *idx, | 88 | int parse_events_add_tracepoint(struct list_head *list, int *idx, |
88 | char *sys, char *event); | 89 | char *sys, char *event); |
89 | int parse_events_add_numeric(struct list_head **list, int *idx, | 90 | int parse_events_add_numeric(struct list_head *list, int *idx, |
90 | u32 type, u64 config, | 91 | u32 type, u64 config, |
91 | struct list_head *head_config); | 92 | struct list_head *head_config); |
92 | int parse_events_add_cache(struct list_head **list, int *idx, | 93 | int parse_events_add_cache(struct list_head *list, int *idx, |
93 | char *type, char *op_result1, char *op_result2); | 94 | char *type, char *op_result1, char *op_result2); |
94 | int parse_events_add_breakpoint(struct list_head **list, int *idx, | 95 | int parse_events_add_breakpoint(struct list_head *list, int *idx, |
95 | void *ptr, char *type); | 96 | void *ptr, char *type); |
96 | int parse_events_add_pmu(struct list_head **list, int *idx, | 97 | int parse_events_add_pmu(struct list_head *list, int *idx, |
97 | char *pmu , struct list_head *head_config); | 98 | char *pmu , struct list_head *head_config); |
98 | void parse_events__set_leader(char *name, struct list_head *list); | 99 | void parse_events__set_leader(char *name, struct list_head *list); |
99 | void parse_events_update_lists(struct list_head *list_event, | 100 | void parse_events_update_lists(struct list_head *list_event, |
diff --git a/tools/perf/util/parse-events.y b/tools/perf/util/parse-events.y index afc44c18dfe1..4eb67ec333f1 100644 --- a/tools/perf/util/parse-events.y +++ b/tools/perf/util/parse-events.y | |||
@@ -22,6 +22,13 @@ do { \ | |||
22 | YYABORT; \ | 22 | YYABORT; \ |
23 | } while (0) | 23 | } while (0) |
24 | 24 | ||
25 | #define ALLOC_LIST(list) \ | ||
26 | do { \ | ||
27 | list = malloc(sizeof(*list)); \ | ||
28 | ABORT_ON(!list); \ | ||
29 | INIT_LIST_HEAD(list); \ | ||
30 | } while (0) | ||
31 | |||
25 | static inc_group_count(struct list_head *list, | 32 | static inc_group_count(struct list_head *list, |
26 | struct parse_events_evlist *data) | 33 | struct parse_events_evlist *data) |
27 | { | 34 | { |
@@ -196,9 +203,10 @@ event_pmu: | |||
196 | PE_NAME '/' event_config '/' | 203 | PE_NAME '/' event_config '/' |
197 | { | 204 | { |
198 | struct parse_events_evlist *data = _data; | 205 | struct parse_events_evlist *data = _data; |
199 | struct list_head *list = NULL; | 206 | struct list_head *list; |
200 | 207 | ||
201 | ABORT_ON(parse_events_add_pmu(&list, &data->idx, $1, $3)); | 208 | ALLOC_LIST(list); |
209 | ABORT_ON(parse_events_add_pmu(list, &data->idx, $1, $3)); | ||
202 | parse_events__free_terms($3); | 210 | parse_events__free_terms($3); |
203 | $$ = list; | 211 | $$ = list; |
204 | } | 212 | } |
@@ -212,11 +220,12 @@ event_legacy_symbol: | |||
212 | value_sym '/' event_config '/' | 220 | value_sym '/' event_config '/' |
213 | { | 221 | { |
214 | struct parse_events_evlist *data = _data; | 222 | struct parse_events_evlist *data = _data; |
215 | struct list_head *list = NULL; | 223 | struct list_head *list; |
216 | int type = $1 >> 16; | 224 | int type = $1 >> 16; |
217 | int config = $1 & 255; | 225 | int config = $1 & 255; |
218 | 226 | ||
219 | ABORT_ON(parse_events_add_numeric(&list, &data->idx, | 227 | ALLOC_LIST(list); |
228 | ABORT_ON(parse_events_add_numeric(list, &data->idx, | ||
220 | type, config, $3)); | 229 | type, config, $3)); |
221 | parse_events__free_terms($3); | 230 | parse_events__free_terms($3); |
222 | $$ = list; | 231 | $$ = list; |
@@ -225,11 +234,12 @@ value_sym '/' event_config '/' | |||
225 | value_sym sep_slash_dc | 234 | value_sym sep_slash_dc |
226 | { | 235 | { |
227 | struct parse_events_evlist *data = _data; | 236 | struct parse_events_evlist *data = _data; |
228 | struct list_head *list = NULL; | 237 | struct list_head *list; |
229 | int type = $1 >> 16; | 238 | int type = $1 >> 16; |
230 | int config = $1 & 255; | 239 | int config = $1 & 255; |
231 | 240 | ||
232 | ABORT_ON(parse_events_add_numeric(&list, &data->idx, | 241 | ALLOC_LIST(list); |
242 | ABORT_ON(parse_events_add_numeric(list, &data->idx, | ||
233 | type, config, NULL)); | 243 | type, config, NULL)); |
234 | $$ = list; | 244 | $$ = list; |
235 | } | 245 | } |
@@ -238,27 +248,30 @@ event_legacy_cache: | |||
238 | PE_NAME_CACHE_TYPE '-' PE_NAME_CACHE_OP_RESULT '-' PE_NAME_CACHE_OP_RESULT | 248 | PE_NAME_CACHE_TYPE '-' PE_NAME_CACHE_OP_RESULT '-' PE_NAME_CACHE_OP_RESULT |
239 | { | 249 | { |
240 | struct parse_events_evlist *data = _data; | 250 | struct parse_events_evlist *data = _data; |
241 | struct list_head *list = NULL; | 251 | struct list_head *list; |
242 | 252 | ||
243 | ABORT_ON(parse_events_add_cache(&list, &data->idx, $1, $3, $5)); | 253 | ALLOC_LIST(list); |
254 | ABORT_ON(parse_events_add_cache(list, &data->idx, $1, $3, $5)); | ||
244 | $$ = list; | 255 | $$ = list; |
245 | } | 256 | } |
246 | | | 257 | | |
247 | PE_NAME_CACHE_TYPE '-' PE_NAME_CACHE_OP_RESULT | 258 | PE_NAME_CACHE_TYPE '-' PE_NAME_CACHE_OP_RESULT |
248 | { | 259 | { |
249 | struct parse_events_evlist *data = _data; | 260 | struct parse_events_evlist *data = _data; |
250 | struct list_head *list = NULL; | 261 | struct list_head *list; |
251 | 262 | ||
252 | ABORT_ON(parse_events_add_cache(&list, &data->idx, $1, $3, NULL)); | 263 | ALLOC_LIST(list); |
264 | ABORT_ON(parse_events_add_cache(list, &data->idx, $1, $3, NULL)); | ||
253 | $$ = list; | 265 | $$ = list; |
254 | } | 266 | } |
255 | | | 267 | | |
256 | PE_NAME_CACHE_TYPE | 268 | PE_NAME_CACHE_TYPE |
257 | { | 269 | { |
258 | struct parse_events_evlist *data = _data; | 270 | struct parse_events_evlist *data = _data; |
259 | struct list_head *list = NULL; | 271 | struct list_head *list; |
260 | 272 | ||
261 | ABORT_ON(parse_events_add_cache(&list, &data->idx, $1, NULL, NULL)); | 273 | ALLOC_LIST(list); |
274 | ABORT_ON(parse_events_add_cache(list, &data->idx, $1, NULL, NULL)); | ||
262 | $$ = list; | 275 | $$ = list; |
263 | } | 276 | } |
264 | 277 | ||
@@ -266,9 +279,10 @@ event_legacy_mem: | |||
266 | PE_PREFIX_MEM PE_VALUE ':' PE_MODIFIER_BP sep_dc | 279 | PE_PREFIX_MEM PE_VALUE ':' PE_MODIFIER_BP sep_dc |
267 | { | 280 | { |
268 | struct parse_events_evlist *data = _data; | 281 | struct parse_events_evlist *data = _data; |
269 | struct list_head *list = NULL; | 282 | struct list_head *list; |
270 | 283 | ||
271 | ABORT_ON(parse_events_add_breakpoint(&list, &data->idx, | 284 | ALLOC_LIST(list); |
285 | ABORT_ON(parse_events_add_breakpoint(list, &data->idx, | ||
272 | (void *) $2, $4)); | 286 | (void *) $2, $4)); |
273 | $$ = list; | 287 | $$ = list; |
274 | } | 288 | } |
@@ -276,9 +290,10 @@ PE_PREFIX_MEM PE_VALUE ':' PE_MODIFIER_BP sep_dc | |||
276 | PE_PREFIX_MEM PE_VALUE sep_dc | 290 | PE_PREFIX_MEM PE_VALUE sep_dc |
277 | { | 291 | { |
278 | struct parse_events_evlist *data = _data; | 292 | struct parse_events_evlist *data = _data; |
279 | struct list_head *list = NULL; | 293 | struct list_head *list; |
280 | 294 | ||
281 | ABORT_ON(parse_events_add_breakpoint(&list, &data->idx, | 295 | ALLOC_LIST(list); |
296 | ABORT_ON(parse_events_add_breakpoint(list, &data->idx, | ||
282 | (void *) $2, NULL)); | 297 | (void *) $2, NULL)); |
283 | $$ = list; | 298 | $$ = list; |
284 | } | 299 | } |
@@ -287,9 +302,10 @@ event_legacy_tracepoint: | |||
287 | PE_NAME ':' PE_NAME | 302 | PE_NAME ':' PE_NAME |
288 | { | 303 | { |
289 | struct parse_events_evlist *data = _data; | 304 | struct parse_events_evlist *data = _data; |
290 | struct list_head *list = NULL; | 305 | struct list_head *list; |
291 | 306 | ||
292 | ABORT_ON(parse_events_add_tracepoint(&list, &data->idx, $1, $3)); | 307 | ALLOC_LIST(list); |
308 | ABORT_ON(parse_events_add_tracepoint(list, &data->idx, $1, $3)); | ||
293 | $$ = list; | 309 | $$ = list; |
294 | } | 310 | } |
295 | 311 | ||
@@ -297,9 +313,10 @@ event_legacy_numeric: | |||
297 | PE_VALUE ':' PE_VALUE | 313 | PE_VALUE ':' PE_VALUE |
298 | { | 314 | { |
299 | struct parse_events_evlist *data = _data; | 315 | struct parse_events_evlist *data = _data; |
300 | struct list_head *list = NULL; | 316 | struct list_head *list; |
301 | 317 | ||
302 | ABORT_ON(parse_events_add_numeric(&list, &data->idx, (u32)$1, $3, NULL)); | 318 | ALLOC_LIST(list); |
319 | ABORT_ON(parse_events_add_numeric(list, &data->idx, (u32)$1, $3, NULL)); | ||
303 | $$ = list; | 320 | $$ = list; |
304 | } | 321 | } |
305 | 322 | ||
@@ -307,9 +324,10 @@ event_legacy_raw: | |||
307 | PE_RAW | 324 | PE_RAW |
308 | { | 325 | { |
309 | struct parse_events_evlist *data = _data; | 326 | struct parse_events_evlist *data = _data; |
310 | struct list_head *list = NULL; | 327 | struct list_head *list; |
311 | 328 | ||
312 | ABORT_ON(parse_events_add_numeric(&list, &data->idx, | 329 | ALLOC_LIST(list); |
330 | ABORT_ON(parse_events_add_numeric(list, &data->idx, | ||
313 | PERF_TYPE_RAW, $1, NULL)); | 331 | PERF_TYPE_RAW, $1, NULL)); |
314 | $$ = list; | 332 | $$ = list; |
315 | } | 333 | } |
diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c index 4c6f9c490a8d..bc9d8069d376 100644 --- a/tools/perf/util/pmu.c +++ b/tools/perf/util/pmu.c | |||
@@ -73,7 +73,7 @@ int perf_pmu__format_parse(char *dir, struct list_head *head) | |||
73 | * located at: | 73 | * located at: |
74 | * /sys/bus/event_source/devices/<dev>/format as sysfs group attributes. | 74 | * /sys/bus/event_source/devices/<dev>/format as sysfs group attributes. |
75 | */ | 75 | */ |
76 | static int pmu_format(char *name, struct list_head *format) | 76 | static int pmu_format(const char *name, struct list_head *format) |
77 | { | 77 | { |
78 | struct stat st; | 78 | struct stat st; |
79 | char path[PATH_MAX]; | 79 | char path[PATH_MAX]; |
@@ -162,7 +162,7 @@ static int pmu_aliases_parse(char *dir, struct list_head *head) | |||
162 | * Reading the pmu event aliases definition, which should be located at: | 162 | * Reading the pmu event aliases definition, which should be located at: |
163 | * /sys/bus/event_source/devices/<dev>/events as sysfs group attributes. | 163 | * /sys/bus/event_source/devices/<dev>/events as sysfs group attributes. |
164 | */ | 164 | */ |
165 | static int pmu_aliases(char *name, struct list_head *head) | 165 | static int pmu_aliases(const char *name, struct list_head *head) |
166 | { | 166 | { |
167 | struct stat st; | 167 | struct stat st; |
168 | char path[PATH_MAX]; | 168 | char path[PATH_MAX]; |
@@ -208,7 +208,7 @@ static int pmu_alias_terms(struct perf_pmu_alias *alias, | |||
208 | * located at: | 208 | * located at: |
209 | * /sys/bus/event_source/devices/<dev>/type as sysfs attribute. | 209 | * /sys/bus/event_source/devices/<dev>/type as sysfs attribute. |
210 | */ | 210 | */ |
211 | static int pmu_type(char *name, __u32 *type) | 211 | static int pmu_type(const char *name, __u32 *type) |
212 | { | 212 | { |
213 | struct stat st; | 213 | struct stat st; |
214 | char path[PATH_MAX]; | 214 | char path[PATH_MAX]; |
@@ -266,7 +266,7 @@ static void pmu_read_sysfs(void) | |||
266 | closedir(dir); | 266 | closedir(dir); |
267 | } | 267 | } |
268 | 268 | ||
269 | static struct cpu_map *pmu_cpumask(char *name) | 269 | static struct cpu_map *pmu_cpumask(const char *name) |
270 | { | 270 | { |
271 | struct stat st; | 271 | struct stat st; |
272 | char path[PATH_MAX]; | 272 | char path[PATH_MAX]; |
@@ -293,7 +293,7 @@ static struct cpu_map *pmu_cpumask(char *name) | |||
293 | return cpus; | 293 | return cpus; |
294 | } | 294 | } |
295 | 295 | ||
296 | static struct perf_pmu *pmu_lookup(char *name) | 296 | static struct perf_pmu *pmu_lookup(const char *name) |
297 | { | 297 | { |
298 | struct perf_pmu *pmu; | 298 | struct perf_pmu *pmu; |
299 | LIST_HEAD(format); | 299 | LIST_HEAD(format); |
@@ -330,7 +330,7 @@ static struct perf_pmu *pmu_lookup(char *name) | |||
330 | return pmu; | 330 | return pmu; |
331 | } | 331 | } |
332 | 332 | ||
333 | static struct perf_pmu *pmu_find(char *name) | 333 | static struct perf_pmu *pmu_find(const char *name) |
334 | { | 334 | { |
335 | struct perf_pmu *pmu; | 335 | struct perf_pmu *pmu; |
336 | 336 | ||
@@ -356,7 +356,7 @@ struct perf_pmu *perf_pmu__scan(struct perf_pmu *pmu) | |||
356 | return NULL; | 356 | return NULL; |
357 | } | 357 | } |
358 | 358 | ||
359 | struct perf_pmu *perf_pmu__find(char *name) | 359 | struct perf_pmu *perf_pmu__find(const char *name) |
360 | { | 360 | { |
361 | struct perf_pmu *pmu; | 361 | struct perf_pmu *pmu; |
362 | 362 | ||
@@ -564,3 +564,76 @@ void perf_pmu__set_format(unsigned long *bits, long from, long to) | |||
564 | for (b = from; b <= to; b++) | 564 | for (b = from; b <= to; b++) |
565 | set_bit(b, bits); | 565 | set_bit(b, bits); |
566 | } | 566 | } |
567 | |||
568 | static char *format_alias(char *buf, int len, struct perf_pmu *pmu, | ||
569 | struct perf_pmu_alias *alias) | ||
570 | { | ||
571 | snprintf(buf, len, "%s/%s/", pmu->name, alias->name); | ||
572 | return buf; | ||
573 | } | ||
574 | |||
575 | static char *format_alias_or(char *buf, int len, struct perf_pmu *pmu, | ||
576 | struct perf_pmu_alias *alias) | ||
577 | { | ||
578 | snprintf(buf, len, "%s OR %s/%s/", alias->name, pmu->name, alias->name); | ||
579 | return buf; | ||
580 | } | ||
581 | |||
582 | static int cmp_string(const void *a, const void *b) | ||
583 | { | ||
584 | const char * const *as = a; | ||
585 | const char * const *bs = b; | ||
586 | return strcmp(*as, *bs); | ||
587 | } | ||
588 | |||
589 | void print_pmu_events(const char *event_glob, bool name_only) | ||
590 | { | ||
591 | struct perf_pmu *pmu; | ||
592 | struct perf_pmu_alias *alias; | ||
593 | char buf[1024]; | ||
594 | int printed = 0; | ||
595 | int len, j; | ||
596 | char **aliases; | ||
597 | |||
598 | pmu = NULL; | ||
599 | len = 0; | ||
600 | while ((pmu = perf_pmu__scan(pmu)) != NULL) | ||
601 | list_for_each_entry(alias, &pmu->aliases, list) | ||
602 | len++; | ||
603 | aliases = malloc(sizeof(char *) * len); | ||
604 | if (!aliases) | ||
605 | return; | ||
606 | pmu = NULL; | ||
607 | j = 0; | ||
608 | while ((pmu = perf_pmu__scan(pmu)) != NULL) | ||
609 | list_for_each_entry(alias, &pmu->aliases, list) { | ||
610 | char *name = format_alias(buf, sizeof(buf), pmu, alias); | ||
611 | bool is_cpu = !strcmp(pmu->name, "cpu"); | ||
612 | |||
613 | if (event_glob != NULL && | ||
614 | !(strglobmatch(name, event_glob) || | ||
615 | (!is_cpu && strglobmatch(alias->name, | ||
616 | event_glob)))) | ||
617 | continue; | ||
618 | aliases[j] = name; | ||
619 | if (is_cpu && !name_only) | ||
620 | aliases[j] = format_alias_or(buf, sizeof(buf), | ||
621 | pmu, alias); | ||
622 | aliases[j] = strdup(aliases[j]); | ||
623 | j++; | ||
624 | } | ||
625 | len = j; | ||
626 | qsort(aliases, len, sizeof(char *), cmp_string); | ||
627 | for (j = 0; j < len; j++) { | ||
628 | if (name_only) { | ||
629 | printf("%s ", aliases[j]); | ||
630 | continue; | ||
631 | } | ||
632 | printf(" %-50s [Kernel PMU event]\n", aliases[j]); | ||
633 | free(aliases[j]); | ||
634 | printed++; | ||
635 | } | ||
636 | if (printed) | ||
637 | printf("\n"); | ||
638 | free(aliases); | ||
639 | } | ||
diff --git a/tools/perf/util/pmu.h b/tools/perf/util/pmu.h index 32fe55b659fa..6b2cbe2d4cc3 100644 --- a/tools/perf/util/pmu.h +++ b/tools/perf/util/pmu.h | |||
@@ -3,6 +3,7 @@ | |||
3 | 3 | ||
4 | #include <linux/bitops.h> | 4 | #include <linux/bitops.h> |
5 | #include <linux/perf_event.h> | 5 | #include <linux/perf_event.h> |
6 | #include <stdbool.h> | ||
6 | 7 | ||
7 | enum { | 8 | enum { |
8 | PERF_PMU_FORMAT_VALUE_CONFIG, | 9 | PERF_PMU_FORMAT_VALUE_CONFIG, |
@@ -21,7 +22,7 @@ struct perf_pmu { | |||
21 | struct list_head list; | 22 | struct list_head list; |
22 | }; | 23 | }; |
23 | 24 | ||
24 | struct perf_pmu *perf_pmu__find(char *name); | 25 | struct perf_pmu *perf_pmu__find(const char *name); |
25 | int perf_pmu__config(struct perf_pmu *pmu, struct perf_event_attr *attr, | 26 | int perf_pmu__config(struct perf_pmu *pmu, struct perf_event_attr *attr, |
26 | struct list_head *head_terms); | 27 | struct list_head *head_terms); |
27 | int perf_pmu__config_terms(struct list_head *formats, | 28 | int perf_pmu__config_terms(struct list_head *formats, |
@@ -40,5 +41,7 @@ int perf_pmu__format_parse(char *dir, struct list_head *head); | |||
40 | 41 | ||
41 | struct perf_pmu *perf_pmu__scan(struct perf_pmu *pmu); | 42 | struct perf_pmu *perf_pmu__scan(struct perf_pmu *pmu); |
42 | 43 | ||
44 | void print_pmu_events(const char *event_glob, bool name_only); | ||
45 | |||
43 | int perf_pmu__test(void); | 46 | int perf_pmu__test(void); |
44 | #endif /* __PMU_H */ | 47 | #endif /* __PMU_H */ |
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index cf1fe01b7e89..272c9cf57122 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c | |||
@@ -1,4 +1,5 @@ | |||
1 | #include <linux/kernel.h> | 1 | #include <linux/kernel.h> |
2 | #include <traceevent/event-parse.h> | ||
2 | 3 | ||
3 | #include <byteswap.h> | 4 | #include <byteswap.h> |
4 | #include <unistd.h> | 5 | #include <unistd.h> |
@@ -12,7 +13,6 @@ | |||
12 | #include "sort.h" | 13 | #include "sort.h" |
13 | #include "util.h" | 14 | #include "util.h" |
14 | #include "cpumap.h" | 15 | #include "cpumap.h" |
15 | #include "event-parse.h" | ||
16 | #include "perf_regs.h" | 16 | #include "perf_regs.h" |
17 | #include "vdso.h" | 17 | #include "vdso.h" |
18 | 18 | ||
@@ -24,7 +24,7 @@ static int perf_session__open(struct perf_session *self, bool force) | |||
24 | self->fd_pipe = true; | 24 | self->fd_pipe = true; |
25 | self->fd = STDIN_FILENO; | 25 | self->fd = STDIN_FILENO; |
26 | 26 | ||
27 | if (perf_session__read_header(self, self->fd) < 0) | 27 | if (perf_session__read_header(self) < 0) |
28 | pr_err("incompatible file format (rerun with -v to learn more)"); | 28 | pr_err("incompatible file format (rerun with -v to learn more)"); |
29 | 29 | ||
30 | return 0; | 30 | return 0; |
@@ -56,7 +56,7 @@ static int perf_session__open(struct perf_session *self, bool force) | |||
56 | goto out_close; | 56 | goto out_close; |
57 | } | 57 | } |
58 | 58 | ||
59 | if (perf_session__read_header(self, self->fd) < 0) { | 59 | if (perf_session__read_header(self) < 0) { |
60 | pr_err("incompatible file format (rerun with -v to learn more)"); | 60 | pr_err("incompatible file format (rerun with -v to learn more)"); |
61 | goto out_close; | 61 | goto out_close; |
62 | } | 62 | } |
@@ -193,7 +193,9 @@ void perf_session__delete(struct perf_session *self) | |||
193 | vdso__exit(); | 193 | vdso__exit(); |
194 | } | 194 | } |
195 | 195 | ||
196 | static int process_event_synth_tracing_data_stub(union perf_event *event | 196 | static int process_event_synth_tracing_data_stub(struct perf_tool *tool |
197 | __maybe_unused, | ||
198 | union perf_event *event | ||
197 | __maybe_unused, | 199 | __maybe_unused, |
198 | struct perf_session *session | 200 | struct perf_session *session |
199 | __maybe_unused) | 201 | __maybe_unused) |
@@ -202,7 +204,8 @@ static int process_event_synth_tracing_data_stub(union perf_event *event | |||
202 | return 0; | 204 | return 0; |
203 | } | 205 | } |
204 | 206 | ||
205 | static int process_event_synth_attr_stub(union perf_event *event __maybe_unused, | 207 | static int process_event_synth_attr_stub(struct perf_tool *tool __maybe_unused, |
208 | union perf_event *event __maybe_unused, | ||
206 | struct perf_evlist **pevlist | 209 | struct perf_evlist **pevlist |
207 | __maybe_unused) | 210 | __maybe_unused) |
208 | { | 211 | { |
@@ -238,13 +241,6 @@ static int process_finished_round_stub(struct perf_tool *tool __maybe_unused, | |||
238 | return 0; | 241 | return 0; |
239 | } | 242 | } |
240 | 243 | ||
241 | static int process_event_type_stub(struct perf_tool *tool __maybe_unused, | ||
242 | union perf_event *event __maybe_unused) | ||
243 | { | ||
244 | dump_printf(": unhandled!\n"); | ||
245 | return 0; | ||
246 | } | ||
247 | |||
248 | static int process_finished_round(struct perf_tool *tool, | 244 | static int process_finished_round(struct perf_tool *tool, |
249 | union perf_event *event, | 245 | union perf_event *event, |
250 | struct perf_session *session); | 246 | struct perf_session *session); |
@@ -271,8 +267,6 @@ static void perf_tool__fill_defaults(struct perf_tool *tool) | |||
271 | tool->unthrottle = process_event_stub; | 267 | tool->unthrottle = process_event_stub; |
272 | if (tool->attr == NULL) | 268 | if (tool->attr == NULL) |
273 | tool->attr = process_event_synth_attr_stub; | 269 | tool->attr = process_event_synth_attr_stub; |
274 | if (tool->event_type == NULL) | ||
275 | tool->event_type = process_event_type_stub; | ||
276 | if (tool->tracing_data == NULL) | 270 | if (tool->tracing_data == NULL) |
277 | tool->tracing_data = process_event_synth_tracing_data_stub; | 271 | tool->tracing_data = process_event_synth_tracing_data_stub; |
278 | if (tool->build_id == NULL) | 272 | if (tool->build_id == NULL) |
@@ -921,16 +915,14 @@ static int perf_session__process_user_event(struct perf_session *session, union | |||
921 | /* These events are processed right away */ | 915 | /* These events are processed right away */ |
922 | switch (event->header.type) { | 916 | switch (event->header.type) { |
923 | case PERF_RECORD_HEADER_ATTR: | 917 | case PERF_RECORD_HEADER_ATTR: |
924 | err = tool->attr(event, &session->evlist); | 918 | err = tool->attr(tool, event, &session->evlist); |
925 | if (err == 0) | 919 | if (err == 0) |
926 | perf_session__set_id_hdr_size(session); | 920 | perf_session__set_id_hdr_size(session); |
927 | return err; | 921 | return err; |
928 | case PERF_RECORD_HEADER_EVENT_TYPE: | ||
929 | return tool->event_type(tool, event); | ||
930 | case PERF_RECORD_HEADER_TRACING_DATA: | 922 | case PERF_RECORD_HEADER_TRACING_DATA: |
931 | /* setup for reading amidst mmap */ | 923 | /* setup for reading amidst mmap */ |
932 | lseek(session->fd, file_offset, SEEK_SET); | 924 | lseek(session->fd, file_offset, SEEK_SET); |
933 | return tool->tracing_data(event, session); | 925 | return tool->tracing_data(tool, event, session); |
934 | case PERF_RECORD_HEADER_BUILD_ID: | 926 | case PERF_RECORD_HEADER_BUILD_ID: |
935 | return tool->build_id(tool, event, session); | 927 | return tool->build_id(tool, event, session); |
936 | case PERF_RECORD_FINISHED_ROUND: | 928 | case PERF_RECORD_FINISHED_ROUND: |
@@ -1091,8 +1083,10 @@ more: | |||
1091 | perf_event_header__bswap(&event->header); | 1083 | perf_event_header__bswap(&event->header); |
1092 | 1084 | ||
1093 | size = event->header.size; | 1085 | size = event->header.size; |
1094 | if (size == 0) | 1086 | if (size < sizeof(struct perf_event_header)) { |
1095 | size = 8; | 1087 | pr_err("bad event header size\n"); |
1088 | goto out_err; | ||
1089 | } | ||
1096 | 1090 | ||
1097 | if (size > cur_size) { | 1091 | if (size > cur_size) { |
1098 | void *new = realloc(buf, size); | 1092 | void *new = realloc(buf, size); |
@@ -1161,8 +1155,12 @@ fetch_mmaped_event(struct perf_session *session, | |||
1161 | if (session->header.needs_swap) | 1155 | if (session->header.needs_swap) |
1162 | perf_event_header__bswap(&event->header); | 1156 | perf_event_header__bswap(&event->header); |
1163 | 1157 | ||
1164 | if (head + event->header.size > mmap_size) | 1158 | if (head + event->header.size > mmap_size) { |
1159 | /* We're not fetching the event so swap back again */ | ||
1160 | if (session->header.needs_swap) | ||
1161 | perf_event_header__bswap(&event->header); | ||
1165 | return NULL; | 1162 | return NULL; |
1163 | } | ||
1166 | 1164 | ||
1167 | return event; | 1165 | return event; |
1168 | } | 1166 | } |
@@ -1242,7 +1240,7 @@ more: | |||
1242 | 1240 | ||
1243 | size = event->header.size; | 1241 | size = event->header.size; |
1244 | 1242 | ||
1245 | if (size == 0 || | 1243 | if (size < sizeof(struct perf_event_header) || |
1246 | perf_session__process_event(session, event, tool, file_pos) < 0) { | 1244 | perf_session__process_event(session, event, tool, file_pos) < 0) { |
1247 | pr_err("%#" PRIx64 " [%#x]: failed to process type: %d\n", | 1245 | pr_err("%#" PRIx64 " [%#x]: failed to process type: %d\n", |
1248 | file_offset + head, event->header.size, | 1246 | file_offset + head, event->header.size, |
@@ -1397,9 +1395,8 @@ void perf_evsel__print_ip(struct perf_evsel *evsel, union perf_event *event, | |||
1397 | 1395 | ||
1398 | if (symbol_conf.use_callchain && sample->callchain) { | 1396 | if (symbol_conf.use_callchain && sample->callchain) { |
1399 | 1397 | ||
1400 | |||
1401 | if (machine__resolve_callchain(machine, evsel, al.thread, | 1398 | if (machine__resolve_callchain(machine, evsel, al.thread, |
1402 | sample, NULL) != 0) { | 1399 | sample, NULL, NULL) != 0) { |
1403 | if (verbose) | 1400 | if (verbose) |
1404 | error("Failed to resolve callchain. Skipping\n"); | 1401 | error("Failed to resolve callchain. Skipping\n"); |
1405 | return; | 1402 | return; |
diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h index f3b235ec7bf4..ad8d3d4ef14e 100644 --- a/tools/perf/util/session.h +++ b/tools/perf/util/session.h | |||
@@ -37,7 +37,6 @@ struct perf_session { | |||
37 | int fd; | 37 | int fd; |
38 | bool fd_pipe; | 38 | bool fd_pipe; |
39 | bool repipe; | 39 | bool repipe; |
40 | char *cwd; | ||
41 | struct ordered_samples ordered_samples; | 40 | struct ordered_samples ordered_samples; |
42 | char filename[1]; | 41 | char filename[1]; |
43 | }; | 42 | }; |
diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c index 313a5a730112..cb2b108635ee 100644 --- a/tools/perf/util/sort.c +++ b/tools/perf/util/sort.c | |||
@@ -7,6 +7,8 @@ const char default_parent_pattern[] = "^sys_|^do_page_fault"; | |||
7 | const char *parent_pattern = default_parent_pattern; | 7 | const char *parent_pattern = default_parent_pattern; |
8 | const char default_sort_order[] = "comm,dso,symbol"; | 8 | const char default_sort_order[] = "comm,dso,symbol"; |
9 | const char *sort_order = default_sort_order; | 9 | const char *sort_order = default_sort_order; |
10 | regex_t ignore_callees_regex; | ||
11 | int have_ignore_callees = 0; | ||
10 | int sort__need_collapse = 0; | 12 | int sort__need_collapse = 0; |
11 | int sort__has_parent = 0; | 13 | int sort__has_parent = 0; |
12 | int sort__has_sym = 0; | 14 | int sort__has_sym = 0; |
@@ -55,14 +57,14 @@ static int64_t cmp_null(void *l, void *r) | |||
55 | static int64_t | 57 | static int64_t |
56 | sort__thread_cmp(struct hist_entry *left, struct hist_entry *right) | 58 | sort__thread_cmp(struct hist_entry *left, struct hist_entry *right) |
57 | { | 59 | { |
58 | return right->thread->pid - left->thread->pid; | 60 | return right->thread->tid - left->thread->tid; |
59 | } | 61 | } |
60 | 62 | ||
61 | static int hist_entry__thread_snprintf(struct hist_entry *self, char *bf, | 63 | static int hist_entry__thread_snprintf(struct hist_entry *self, char *bf, |
62 | size_t size, unsigned int width) | 64 | size_t size, unsigned int width) |
63 | { | 65 | { |
64 | return repsep_snprintf(bf, size, "%*s:%5d", width - 6, | 66 | return repsep_snprintf(bf, size, "%*s:%5d", width - 6, |
65 | self->thread->comm ?: "", self->thread->pid); | 67 | self->thread->comm ?: "", self->thread->tid); |
66 | } | 68 | } |
67 | 69 | ||
68 | struct sort_entry sort_thread = { | 70 | struct sort_entry sort_thread = { |
@@ -77,7 +79,7 @@ struct sort_entry sort_thread = { | |||
77 | static int64_t | 79 | static int64_t |
78 | sort__comm_cmp(struct hist_entry *left, struct hist_entry *right) | 80 | sort__comm_cmp(struct hist_entry *left, struct hist_entry *right) |
79 | { | 81 | { |
80 | return right->thread->pid - left->thread->pid; | 82 | return right->thread->tid - left->thread->tid; |
81 | } | 83 | } |
82 | 84 | ||
83 | static int64_t | 85 | static int64_t |
diff --git a/tools/perf/util/sort.h b/tools/perf/util/sort.h index 45ac84c1e037..586022dc3264 100644 --- a/tools/perf/util/sort.h +++ b/tools/perf/util/sort.h | |||
@@ -29,6 +29,8 @@ extern const char *sort_order; | |||
29 | extern const char default_parent_pattern[]; | 29 | extern const char default_parent_pattern[]; |
30 | extern const char *parent_pattern; | 30 | extern const char *parent_pattern; |
31 | extern const char default_sort_order[]; | 31 | extern const char default_sort_order[]; |
32 | extern regex_t ignore_callees_regex; | ||
33 | extern int have_ignore_callees; | ||
32 | extern int sort__need_collapse; | 34 | extern int sort__need_collapse; |
33 | extern int sort__has_parent; | 35 | extern int sort__has_parent; |
34 | extern int sort__has_sym; | 36 | extern int sort__has_sym; |
@@ -87,6 +89,9 @@ struct hist_entry { | |||
87 | 89 | ||
88 | struct hist_entry_diff diff; | 90 | struct hist_entry_diff diff; |
89 | 91 | ||
92 | /* We are added by hists__add_dummy_entry. */ | ||
93 | bool dummy; | ||
94 | |||
90 | /* XXX These two should move to some tree widget lib */ | 95 | /* XXX These two should move to some tree widget lib */ |
91 | u16 row_offset; | 96 | u16 row_offset; |
92 | u16 nr_rows; | 97 | u16 nr_rows; |
@@ -183,4 +188,6 @@ int setup_sorting(void); | |||
183 | extern int sort_dimension__add(const char *); | 188 | extern int sort_dimension__add(const char *); |
184 | void sort__setup_elide(FILE *fp); | 189 | void sort__setup_elide(FILE *fp); |
185 | 190 | ||
191 | int report_parse_ignore_callees_opt(const struct option *opt, const char *arg, int unset); | ||
192 | |||
186 | #endif /* __PERF_SORT_H */ | 193 | #endif /* __PERF_SORT_H */ |
diff --git a/tools/perf/util/string.c b/tools/perf/util/string.c index 29c7b2cb2521..f0b0c008c507 100644 --- a/tools/perf/util/string.c +++ b/tools/perf/util/string.c | |||
@@ -387,3 +387,27 @@ void *memdup(const void *src, size_t len) | |||
387 | 387 | ||
388 | return p; | 388 | return p; |
389 | } | 389 | } |
390 | |||
391 | /** | ||
392 | * str_append - reallocate string and append another | ||
393 | * @s: pointer to string pointer | ||
394 | * @len: pointer to len (initialized) | ||
395 | * @a: string to append. | ||
396 | */ | ||
397 | int str_append(char **s, int *len, const char *a) | ||
398 | { | ||
399 | int olen = *s ? strlen(*s) : 0; | ||
400 | int nlen = olen + strlen(a) + 1; | ||
401 | if (*len < nlen) { | ||
402 | *len = *len * 2; | ||
403 | if (*len < nlen) | ||
404 | *len = nlen; | ||
405 | *s = realloc(*s, *len); | ||
406 | if (!*s) | ||
407 | return -ENOMEM; | ||
408 | if (olen == 0) | ||
409 | **s = 0; | ||
410 | } | ||
411 | strcat(*s, a); | ||
412 | return 0; | ||
413 | } | ||
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index d5528e1cc03a..02718e728d59 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c | |||
@@ -888,8 +888,11 @@ int dso__load_vmlinux(struct dso *dso, struct map *map, | |||
888 | char symfs_vmlinux[PATH_MAX]; | 888 | char symfs_vmlinux[PATH_MAX]; |
889 | enum dso_binary_type symtab_type; | 889 | enum dso_binary_type symtab_type; |
890 | 890 | ||
891 | snprintf(symfs_vmlinux, sizeof(symfs_vmlinux), "%s%s", | 891 | if (vmlinux[0] == '/') |
892 | symbol_conf.symfs, vmlinux); | 892 | snprintf(symfs_vmlinux, sizeof(symfs_vmlinux), "%s", vmlinux); |
893 | else | ||
894 | snprintf(symfs_vmlinux, sizeof(symfs_vmlinux), "%s%s", | ||
895 | symbol_conf.symfs, vmlinux); | ||
893 | 896 | ||
894 | if (dso->kernel == DSO_TYPE_GUEST_KERNEL) | 897 | if (dso->kernel == DSO_TYPE_GUEST_KERNEL) |
895 | symtab_type = DSO_BINARY_TYPE__GUEST_VMLINUX; | 898 | symtab_type = DSO_BINARY_TYPE__GUEST_VMLINUX; |
diff --git a/tools/perf/util/thread.c b/tools/perf/util/thread.c index 40399cbcca77..6feeb88eb5b0 100644 --- a/tools/perf/util/thread.c +++ b/tools/perf/util/thread.c | |||
@@ -7,17 +7,17 @@ | |||
7 | #include "util.h" | 7 | #include "util.h" |
8 | #include "debug.h" | 8 | #include "debug.h" |
9 | 9 | ||
10 | struct thread *thread__new(pid_t pid) | 10 | struct thread *thread__new(pid_t tid) |
11 | { | 11 | { |
12 | struct thread *self = zalloc(sizeof(*self)); | 12 | struct thread *self = zalloc(sizeof(*self)); |
13 | 13 | ||
14 | if (self != NULL) { | 14 | if (self != NULL) { |
15 | map_groups__init(&self->mg); | 15 | map_groups__init(&self->mg); |
16 | self->pid = pid; | 16 | self->tid = tid; |
17 | self->ppid = -1; | 17 | self->ppid = -1; |
18 | self->comm = malloc(32); | 18 | self->comm = malloc(32); |
19 | if (self->comm) | 19 | if (self->comm) |
20 | snprintf(self->comm, 32, ":%d", self->pid); | 20 | snprintf(self->comm, 32, ":%d", self->tid); |
21 | } | 21 | } |
22 | 22 | ||
23 | return self; | 23 | return self; |
@@ -57,7 +57,7 @@ int thread__comm_len(struct thread *self) | |||
57 | 57 | ||
58 | size_t thread__fprintf(struct thread *thread, FILE *fp) | 58 | size_t thread__fprintf(struct thread *thread, FILE *fp) |
59 | { | 59 | { |
60 | return fprintf(fp, "Thread %d %s\n", thread->pid, thread->comm) + | 60 | return fprintf(fp, "Thread %d %s\n", thread->tid, thread->comm) + |
61 | map_groups__fprintf(&thread->mg, verbose, fp); | 61 | map_groups__fprintf(&thread->mg, verbose, fp); |
62 | } | 62 | } |
63 | 63 | ||
@@ -84,7 +84,7 @@ int thread__fork(struct thread *self, struct thread *parent) | |||
84 | if (map_groups__clone(&self->mg, &parent->mg, i) < 0) | 84 | if (map_groups__clone(&self->mg, &parent->mg, i) < 0) |
85 | return -ENOMEM; | 85 | return -ENOMEM; |
86 | 86 | ||
87 | self->ppid = parent->pid; | 87 | self->ppid = parent->tid; |
88 | 88 | ||
89 | return 0; | 89 | return 0; |
90 | } | 90 | } |
diff --git a/tools/perf/util/thread.h b/tools/perf/util/thread.h index eeb7ac62b9e3..0fe1f9c05865 100644 --- a/tools/perf/util/thread.h +++ b/tools/perf/util/thread.h | |||
@@ -12,7 +12,7 @@ struct thread { | |||
12 | struct list_head node; | 12 | struct list_head node; |
13 | }; | 13 | }; |
14 | struct map_groups mg; | 14 | struct map_groups mg; |
15 | pid_t pid; | 15 | pid_t tid; |
16 | pid_t ppid; | 16 | pid_t ppid; |
17 | char shortname[3]; | 17 | char shortname[3]; |
18 | bool comm_set; | 18 | bool comm_set; |
@@ -24,7 +24,7 @@ struct thread { | |||
24 | 24 | ||
25 | struct machine; | 25 | struct machine; |
26 | 26 | ||
27 | struct thread *thread__new(pid_t pid); | 27 | struct thread *thread__new(pid_t tid); |
28 | void thread__delete(struct thread *self); | 28 | void thread__delete(struct thread *self); |
29 | 29 | ||
30 | int thread__set_comm(struct thread *self, const char *comm); | 30 | int thread__set_comm(struct thread *self, const char *comm); |
@@ -47,4 +47,14 @@ void thread__find_addr_location(struct thread *thread, struct machine *machine, | |||
47 | u8 cpumode, enum map_type type, u64 addr, | 47 | u8 cpumode, enum map_type type, u64 addr, |
48 | struct addr_location *al, | 48 | struct addr_location *al, |
49 | symbol_filter_t filter); | 49 | symbol_filter_t filter); |
50 | |||
51 | static inline void *thread__priv(struct thread *thread) | ||
52 | { | ||
53 | return thread->priv; | ||
54 | } | ||
55 | |||
56 | static inline void thread__set_priv(struct thread *thread, void *p) | ||
57 | { | ||
58 | thread->priv = p; | ||
59 | } | ||
50 | #endif /* __PERF_THREAD_H */ | 60 | #endif /* __PERF_THREAD_H */ |
diff --git a/tools/perf/util/tool.h b/tools/perf/util/tool.h index b0e1aadba8d5..62b16b6165ba 100644 --- a/tools/perf/util/tool.h +++ b/tools/perf/util/tool.h | |||
@@ -18,12 +18,9 @@ typedef int (*event_sample)(struct perf_tool *tool, union perf_event *event, | |||
18 | typedef int (*event_op)(struct perf_tool *tool, union perf_event *event, | 18 | typedef int (*event_op)(struct perf_tool *tool, union perf_event *event, |
19 | struct perf_sample *sample, struct machine *machine); | 19 | struct perf_sample *sample, struct machine *machine); |
20 | 20 | ||
21 | typedef int (*event_attr_op)(union perf_event *event, | 21 | typedef int (*event_attr_op)(struct perf_tool *tool, |
22 | union perf_event *event, | ||
22 | struct perf_evlist **pevlist); | 23 | struct perf_evlist **pevlist); |
23 | typedef int (*event_simple_op)(struct perf_tool *tool, union perf_event *event); | ||
24 | |||
25 | typedef int (*event_synth_op)(union perf_event *event, | ||
26 | struct perf_session *session); | ||
27 | 24 | ||
28 | typedef int (*event_op2)(struct perf_tool *tool, union perf_event *event, | 25 | typedef int (*event_op2)(struct perf_tool *tool, union perf_event *event, |
29 | struct perf_session *session); | 26 | struct perf_session *session); |
@@ -39,8 +36,7 @@ struct perf_tool { | |||
39 | throttle, | 36 | throttle, |
40 | unthrottle; | 37 | unthrottle; |
41 | event_attr_op attr; | 38 | event_attr_op attr; |
42 | event_synth_op tracing_data; | 39 | event_op2 tracing_data; |
43 | event_simple_op event_type; | ||
44 | event_op2 finished_round, | 40 | event_op2 finished_round, |
45 | build_id; | 41 | build_id; |
46 | bool ordered_samples; | 42 | bool ordered_samples; |
diff --git a/tools/perf/util/trace-event-info.c b/tools/perf/util/trace-event-info.c index 3917eb9a8479..f3c9e551bd35 100644 --- a/tools/perf/util/trace-event-info.c +++ b/tools/perf/util/trace-event-info.c | |||
@@ -46,65 +46,6 @@ | |||
46 | static int output_fd; | 46 | static int output_fd; |
47 | 47 | ||
48 | 48 | ||
49 | static const char *find_debugfs(void) | ||
50 | { | ||
51 | const char *path = perf_debugfs_mount(NULL); | ||
52 | |||
53 | if (!path) | ||
54 | pr_debug("Your kernel does not support the debugfs filesystem"); | ||
55 | |||
56 | return path; | ||
57 | } | ||
58 | |||
59 | /* | ||
60 | * Finds the path to the debugfs/tracing | ||
61 | * Allocates the string and stores it. | ||
62 | */ | ||
63 | static const char *find_tracing_dir(void) | ||
64 | { | ||
65 | static char *tracing; | ||
66 | static int tracing_found; | ||
67 | const char *debugfs; | ||
68 | |||
69 | if (tracing_found) | ||
70 | return tracing; | ||
71 | |||
72 | debugfs = find_debugfs(); | ||
73 | if (!debugfs) | ||
74 | return NULL; | ||
75 | |||
76 | tracing = malloc(strlen(debugfs) + 9); | ||
77 | if (!tracing) | ||
78 | return NULL; | ||
79 | |||
80 | sprintf(tracing, "%s/tracing", debugfs); | ||
81 | |||
82 | tracing_found = 1; | ||
83 | return tracing; | ||
84 | } | ||
85 | |||
86 | static char *get_tracing_file(const char *name) | ||
87 | { | ||
88 | const char *tracing; | ||
89 | char *file; | ||
90 | |||
91 | tracing = find_tracing_dir(); | ||
92 | if (!tracing) | ||
93 | return NULL; | ||
94 | |||
95 | file = malloc(strlen(tracing) + strlen(name) + 2); | ||
96 | if (!file) | ||
97 | return NULL; | ||
98 | |||
99 | sprintf(file, "%s/%s", tracing, name); | ||
100 | return file; | ||
101 | } | ||
102 | |||
103 | static void put_tracing_file(char *file) | ||
104 | { | ||
105 | free(file); | ||
106 | } | ||
107 | |||
108 | int bigendian(void) | 49 | int bigendian(void) |
109 | { | 50 | { |
110 | unsigned char str[] = { 0x1, 0x2, 0x3, 0x4, 0x0, 0x0, 0x0, 0x0}; | 51 | unsigned char str[] = { 0x1, 0x2, 0x3, 0x4, 0x0, 0x0, 0x0, 0x0}; |
@@ -160,7 +101,7 @@ out: | |||
160 | return err; | 101 | return err; |
161 | } | 102 | } |
162 | 103 | ||
163 | static int read_header_files(void) | 104 | static int record_header_files(void) |
164 | { | 105 | { |
165 | char *path; | 106 | char *path; |
166 | struct stat st; | 107 | struct stat st; |
@@ -299,7 +240,7 @@ out: | |||
299 | return err; | 240 | return err; |
300 | } | 241 | } |
301 | 242 | ||
302 | static int read_ftrace_files(struct tracepoint_path *tps) | 243 | static int record_ftrace_files(struct tracepoint_path *tps) |
303 | { | 244 | { |
304 | char *path; | 245 | char *path; |
305 | int ret; | 246 | int ret; |
@@ -328,7 +269,7 @@ static bool system_in_tp_list(char *sys, struct tracepoint_path *tps) | |||
328 | return false; | 269 | return false; |
329 | } | 270 | } |
330 | 271 | ||
331 | static int read_event_files(struct tracepoint_path *tps) | 272 | static int record_event_files(struct tracepoint_path *tps) |
332 | { | 273 | { |
333 | struct dirent *dent; | 274 | struct dirent *dent; |
334 | struct stat st; | 275 | struct stat st; |
@@ -403,7 +344,7 @@ out: | |||
403 | return err; | 344 | return err; |
404 | } | 345 | } |
405 | 346 | ||
406 | static int read_proc_kallsyms(void) | 347 | static int record_proc_kallsyms(void) |
407 | { | 348 | { |
408 | unsigned int size; | 349 | unsigned int size; |
409 | const char *path = "/proc/kallsyms"; | 350 | const char *path = "/proc/kallsyms"; |
@@ -421,7 +362,7 @@ static int read_proc_kallsyms(void) | |||
421 | return record_file(path, 4); | 362 | return record_file(path, 4); |
422 | } | 363 | } |
423 | 364 | ||
424 | static int read_ftrace_printk(void) | 365 | static int record_ftrace_printk(void) |
425 | { | 366 | { |
426 | unsigned int size; | 367 | unsigned int size; |
427 | char *path; | 368 | char *path; |
@@ -473,12 +414,27 @@ get_tracepoints_path(struct list_head *pattrs) | |||
473 | if (pos->attr.type != PERF_TYPE_TRACEPOINT) | 414 | if (pos->attr.type != PERF_TYPE_TRACEPOINT) |
474 | continue; | 415 | continue; |
475 | ++nr_tracepoints; | 416 | ++nr_tracepoints; |
417 | |||
418 | if (pos->name) { | ||
419 | ppath->next = tracepoint_name_to_path(pos->name); | ||
420 | if (ppath->next) | ||
421 | goto next; | ||
422 | |||
423 | if (strchr(pos->name, ':') == NULL) | ||
424 | goto try_id; | ||
425 | |||
426 | goto error; | ||
427 | } | ||
428 | |||
429 | try_id: | ||
476 | ppath->next = tracepoint_id_to_path(pos->attr.config); | 430 | ppath->next = tracepoint_id_to_path(pos->attr.config); |
477 | if (!ppath->next) { | 431 | if (!ppath->next) { |
432 | error: | ||
478 | pr_debug("No memory to alloc tracepoints list\n"); | 433 | pr_debug("No memory to alloc tracepoints list\n"); |
479 | put_tracepoints_path(&path); | 434 | put_tracepoints_path(&path); |
480 | return NULL; | 435 | return NULL; |
481 | } | 436 | } |
437 | next: | ||
482 | ppath = ppath->next; | 438 | ppath = ppath->next; |
483 | } | 439 | } |
484 | 440 | ||
@@ -520,8 +476,6 @@ static int tracing_data_header(void) | |||
520 | else | 476 | else |
521 | buf[0] = 0; | 477 | buf[0] = 0; |
522 | 478 | ||
523 | read_trace_init(buf[0], buf[0]); | ||
524 | |||
525 | if (write(output_fd, buf, 1) != 1) | 479 | if (write(output_fd, buf, 1) != 1) |
526 | return -1; | 480 | return -1; |
527 | 481 | ||
@@ -583,19 +537,19 @@ struct tracing_data *tracing_data_get(struct list_head *pattrs, | |||
583 | err = tracing_data_header(); | 537 | err = tracing_data_header(); |
584 | if (err) | 538 | if (err) |
585 | goto out; | 539 | goto out; |
586 | err = read_header_files(); | 540 | err = record_header_files(); |
587 | if (err) | 541 | if (err) |
588 | goto out; | 542 | goto out; |
589 | err = read_ftrace_files(tps); | 543 | err = record_ftrace_files(tps); |
590 | if (err) | 544 | if (err) |
591 | goto out; | 545 | goto out; |
592 | err = read_event_files(tps); | 546 | err = record_event_files(tps); |
593 | if (err) | 547 | if (err) |
594 | goto out; | 548 | goto out; |
595 | err = read_proc_kallsyms(); | 549 | err = record_proc_kallsyms(); |
596 | if (err) | 550 | if (err) |
597 | goto out; | 551 | goto out; |
598 | err = read_ftrace_printk(); | 552 | err = record_ftrace_printk(); |
599 | 553 | ||
600 | out: | 554 | out: |
601 | /* | 555 | /* |
diff --git a/tools/perf/util/trace-event-parse.c b/tools/perf/util/trace-event-parse.c index 4454835a9ebc..fe7a27d67d2b 100644 --- a/tools/perf/util/trace-event-parse.c +++ b/tools/perf/util/trace-event-parse.c | |||
@@ -28,12 +28,6 @@ | |||
28 | #include "util.h" | 28 | #include "util.h" |
29 | #include "trace-event.h" | 29 | #include "trace-event.h" |
30 | 30 | ||
31 | int header_page_size_size; | ||
32 | int header_page_ts_size; | ||
33 | int header_page_data_offset; | ||
34 | |||
35 | bool latency_format; | ||
36 | |||
37 | struct pevent *read_trace_init(int file_bigendian, int host_bigendian) | 31 | struct pevent *read_trace_init(int file_bigendian, int host_bigendian) |
38 | { | 32 | { |
39 | struct pevent *pevent = pevent_alloc(); | 33 | struct pevent *pevent = pevent_alloc(); |
diff --git a/tools/perf/util/trace-event-read.c b/tools/perf/util/trace-event-read.c index af215c0d2379..f2112270c663 100644 --- a/tools/perf/util/trace-event-read.c +++ b/tools/perf/util/trace-event-read.c | |||
@@ -39,10 +39,6 @@ | |||
39 | 39 | ||
40 | static int input_fd; | 40 | static int input_fd; |
41 | 41 | ||
42 | int file_bigendian; | ||
43 | int host_bigendian; | ||
44 | static int long_size; | ||
45 | |||
46 | static ssize_t trace_data_size; | 42 | static ssize_t trace_data_size; |
47 | static bool repipe; | 43 | static bool repipe; |
48 | 44 | ||
@@ -216,7 +212,7 @@ static int read_ftrace_printk(struct pevent *pevent) | |||
216 | static int read_header_files(struct pevent *pevent) | 212 | static int read_header_files(struct pevent *pevent) |
217 | { | 213 | { |
218 | unsigned long long size; | 214 | unsigned long long size; |
219 | char *header_event; | 215 | char *header_page; |
220 | char buf[BUFSIZ]; | 216 | char buf[BUFSIZ]; |
221 | int ret = 0; | 217 | int ret = 0; |
222 | 218 | ||
@@ -229,13 +225,26 @@ static int read_header_files(struct pevent *pevent) | |||
229 | } | 225 | } |
230 | 226 | ||
231 | size = read8(pevent); | 227 | size = read8(pevent); |
232 | skip(size); | ||
233 | 228 | ||
234 | /* | 229 | header_page = malloc(size); |
235 | * The size field in the page is of type long, | 230 | if (header_page == NULL) |
236 | * use that instead, since it represents the kernel. | 231 | return -1; |
237 | */ | 232 | |
238 | long_size = header_page_size_size; | 233 | if (do_read(header_page, size) < 0) { |
234 | pr_debug("did not read header page"); | ||
235 | free(header_page); | ||
236 | return -1; | ||
237 | } | ||
238 | |||
239 | if (!pevent_parse_header_page(pevent, header_page, size, | ||
240 | pevent_get_long_size(pevent))) { | ||
241 | /* | ||
242 | * The commit field in the page is of type long, | ||
243 | * use that instead, since it represents the kernel. | ||
244 | */ | ||
245 | pevent_set_long_size(pevent, pevent->header_page_size_size); | ||
246 | } | ||
247 | free(header_page); | ||
239 | 248 | ||
240 | if (do_read(buf, 13) < 0) | 249 | if (do_read(buf, 13) < 0) |
241 | return -1; | 250 | return -1; |
@@ -246,14 +255,8 @@ static int read_header_files(struct pevent *pevent) | |||
246 | } | 255 | } |
247 | 256 | ||
248 | size = read8(pevent); | 257 | size = read8(pevent); |
249 | header_event = malloc(size); | 258 | skip(size); |
250 | if (header_event == NULL) | ||
251 | return -1; | ||
252 | |||
253 | if (do_read(header_event, size) < 0) | ||
254 | ret = -1; | ||
255 | 259 | ||
256 | free(header_event); | ||
257 | return ret; | 260 | return ret; |
258 | } | 261 | } |
259 | 262 | ||
@@ -349,6 +352,10 @@ ssize_t trace_report(int fd, struct pevent **ppevent, bool __repipe) | |||
349 | int show_funcs = 0; | 352 | int show_funcs = 0; |
350 | int show_printk = 0; | 353 | int show_printk = 0; |
351 | ssize_t size = -1; | 354 | ssize_t size = -1; |
355 | int file_bigendian; | ||
356 | int host_bigendian; | ||
357 | int file_long_size; | ||
358 | int file_page_size; | ||
352 | struct pevent *pevent; | 359 | struct pevent *pevent; |
353 | int err; | 360 | int err; |
354 | 361 | ||
@@ -391,12 +398,15 @@ ssize_t trace_report(int fd, struct pevent **ppevent, bool __repipe) | |||
391 | 398 | ||
392 | if (do_read(buf, 1) < 0) | 399 | if (do_read(buf, 1) < 0) |
393 | goto out; | 400 | goto out; |
394 | long_size = buf[0]; | 401 | file_long_size = buf[0]; |
395 | 402 | ||
396 | page_size = read4(pevent); | 403 | file_page_size = read4(pevent); |
397 | if (!page_size) | 404 | if (!file_page_size) |
398 | goto out; | 405 | goto out; |
399 | 406 | ||
407 | pevent_set_long_size(pevent, file_long_size); | ||
408 | pevent_set_page_size(pevent, file_page_size); | ||
409 | |||
400 | err = read_header_files(pevent); | 410 | err = read_header_files(pevent); |
401 | if (err) | 411 | if (err) |
402 | goto out; | 412 | goto out; |
diff --git a/tools/perf/util/trace-event.h b/tools/perf/util/trace-event.h index 1978c398ad87..669a64a660d7 100644 --- a/tools/perf/util/trace-event.h +++ b/tools/perf/util/trace-event.h | |||
@@ -1,8 +1,8 @@ | |||
1 | #ifndef _PERF_UTIL_TRACE_EVENT_H | 1 | #ifndef _PERF_UTIL_TRACE_EVENT_H |
2 | #define _PERF_UTIL_TRACE_EVENT_H | 2 | #define _PERF_UTIL_TRACE_EVENT_H |
3 | 3 | ||
4 | #include <traceevent/event-parse.h> | ||
4 | #include "parse-events.h" | 5 | #include "parse-events.h" |
5 | #include "event-parse.h" | ||
6 | #include "session.h" | 6 | #include "session.h" |
7 | 7 | ||
8 | struct machine; | 8 | struct machine; |
@@ -10,23 +10,8 @@ struct perf_sample; | |||
10 | union perf_event; | 10 | union perf_event; |
11 | struct perf_tool; | 11 | struct perf_tool; |
12 | 12 | ||
13 | extern int header_page_size_size; | ||
14 | extern int header_page_ts_size; | ||
15 | extern int header_page_data_offset; | ||
16 | |||
17 | extern bool latency_format; | ||
18 | extern struct pevent *perf_pevent; | 13 | extern struct pevent *perf_pevent; |
19 | 14 | ||
20 | enum { | ||
21 | RINGBUF_TYPE_PADDING = 29, | ||
22 | RINGBUF_TYPE_TIME_EXTEND = 30, | ||
23 | RINGBUF_TYPE_TIME_STAMP = 31, | ||
24 | }; | ||
25 | |||
26 | #ifndef TS_SHIFT | ||
27 | #define TS_SHIFT 27 | ||
28 | #endif | ||
29 | |||
30 | int bigendian(void); | 15 | int bigendian(void); |
31 | 16 | ||
32 | struct pevent *read_trace_init(int file_bigendian, int host_bigendian); | 17 | struct pevent *read_trace_init(int file_bigendian, int host_bigendian); |
diff --git a/tools/perf/util/util.c b/tools/perf/util/util.c index 59d868add275..9a0658405760 100644 --- a/tools/perf/util/util.c +++ b/tools/perf/util/util.c | |||
@@ -269,3 +269,62 @@ void perf_debugfs_set_path(const char *mntpt) | |||
269 | snprintf(debugfs_mountpoint, strlen(debugfs_mountpoint), "%s", mntpt); | 269 | snprintf(debugfs_mountpoint, strlen(debugfs_mountpoint), "%s", mntpt); |
270 | set_tracing_events_path(mntpt); | 270 | set_tracing_events_path(mntpt); |
271 | } | 271 | } |
272 | |||
273 | static const char *find_debugfs(void) | ||
274 | { | ||
275 | const char *path = perf_debugfs_mount(NULL); | ||
276 | |||
277 | if (!path) | ||
278 | fprintf(stderr, "Your kernel does not support the debugfs filesystem"); | ||
279 | |||
280 | return path; | ||
281 | } | ||
282 | |||
283 | /* | ||
284 | * Finds the path to the debugfs/tracing | ||
285 | * Allocates the string and stores it. | ||
286 | */ | ||
287 | const char *find_tracing_dir(void) | ||
288 | { | ||
289 | static char *tracing; | ||
290 | static int tracing_found; | ||
291 | const char *debugfs; | ||
292 | |||
293 | if (tracing_found) | ||
294 | return tracing; | ||
295 | |||
296 | debugfs = find_debugfs(); | ||
297 | if (!debugfs) | ||
298 | return NULL; | ||
299 | |||
300 | tracing = malloc(strlen(debugfs) + 9); | ||
301 | if (!tracing) | ||
302 | return NULL; | ||
303 | |||
304 | sprintf(tracing, "%s/tracing", debugfs); | ||
305 | |||
306 | tracing_found = 1; | ||
307 | return tracing; | ||
308 | } | ||
309 | |||
310 | char *get_tracing_file(const char *name) | ||
311 | { | ||
312 | const char *tracing; | ||
313 | char *file; | ||
314 | |||
315 | tracing = find_tracing_dir(); | ||
316 | if (!tracing) | ||
317 | return NULL; | ||
318 | |||
319 | file = malloc(strlen(tracing) + strlen(name) + 2); | ||
320 | if (!file) | ||
321 | return NULL; | ||
322 | |||
323 | sprintf(file, "%s/%s", tracing, name); | ||
324 | return file; | ||
325 | } | ||
326 | |||
327 | void put_tracing_file(char *file) | ||
328 | { | ||
329 | free(file); | ||
330 | } | ||
diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h index 2732fad03908..cc1574edcd9a 100644 --- a/tools/perf/util/util.h +++ b/tools/perf/util/util.h | |||
@@ -80,6 +80,9 @@ extern char buildid_dir[]; | |||
80 | extern char tracing_events_path[]; | 80 | extern char tracing_events_path[]; |
81 | extern void perf_debugfs_set_path(const char *mountpoint); | 81 | extern void perf_debugfs_set_path(const char *mountpoint); |
82 | const char *perf_debugfs_mount(const char *mountpoint); | 82 | const char *perf_debugfs_mount(const char *mountpoint); |
83 | const char *find_tracing_dir(void); | ||
84 | char *get_tracing_file(const char *name); | ||
85 | void put_tracing_file(char *file); | ||
83 | 86 | ||
84 | /* On most systems <limits.h> would have given us this, but | 87 | /* On most systems <limits.h> would have given us this, but |
85 | * not on some systems (e.g. GNU/Hurd). | 88 | * not on some systems (e.g. GNU/Hurd). |