aboutsummaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
authorIngo Molnar <mingo@kernel.org>2013-07-19 03:35:30 -0400
committerIngo Molnar <mingo@kernel.org>2013-07-19 03:35:30 -0400
commit5a9821321e0a61674fd5c4b5a9e95007d0e7e052 (patch)
tree6138bbc657a866f4373f774501c7698338f9354b /tools
parente43fff2b98b4e99b189c086a9cf740b19eaf3538 (diff)
parent2a08c3ec4f7d6058a450d2d4bc6e366955872707 (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')
-rw-r--r--tools/lib/traceevent/Makefile18
-rw-r--r--tools/lib/traceevent/event-parse.c7
-rw-r--r--tools/lib/traceevent/event-parse.h15
-rw-r--r--tools/lib/traceevent/kbuffer-parse.c732
-rw-r--r--tools/lib/traceevent/kbuffer.h67
-rw-r--r--tools/lib/traceevent/trace-seq.c13
-rw-r--r--tools/perf/Documentation/perf-diff.txt79
-rw-r--r--tools/perf/Documentation/perf-list.txt4
-rw-r--r--tools/perf/Documentation/perf-report.txt5
-rw-r--r--tools/perf/Documentation/perf-top.txt5
-rw-r--r--tools/perf/Makefile4
-rw-r--r--tools/perf/builtin-diff.c662
-rw-r--r--tools/perf/builtin-inject.c45
-rw-r--r--tools/perf/builtin-kmem.c2
-rw-r--r--tools/perf/builtin-list.c3
-rw-r--r--tools/perf/builtin-record.c13
-rw-r--r--tools/perf/builtin-report.c60
-rw-r--r--tools/perf/builtin-sched.c53
-rw-r--r--tools/perf/builtin-script.c2
-rw-r--r--tools/perf/builtin-timechart.c176
-rw-r--r--tools/perf/builtin-top.c15
-rw-r--r--tools/perf/builtin-trace.c6
-rw-r--r--tools/perf/config/Makefile5
-rw-r--r--tools/perf/tests/dso-data.c8
-rw-r--r--tools/perf/tests/evsel-tp-sched.c4
-rw-r--r--tools/perf/tests/parse-events.c22
-rw-r--r--tools/perf/tests/tests.h8
-rw-r--r--tools/perf/tests/vmlinux-kallsyms.c15
-rw-r--r--tools/perf/ui/browsers/hists.c18
-rw-r--r--tools/perf/ui/gtk/hists.c126
-rw-r--r--tools/perf/ui/hist.c258
-rw-r--r--tools/perf/ui/setup.c1
-rw-r--r--tools/perf/ui/stdio/hist.c45
-rw-r--r--tools/perf/util/cpumap.h2
-rw-r--r--tools/perf/util/event.c2
-rw-r--r--tools/perf/util/event.h2
-rw-r--r--tools/perf/util/evlist.c38
-rw-r--r--tools/perf/util/evsel.c8
-rw-r--r--tools/perf/util/header.c150
-rw-r--r--tools/perf/util/header.h40
-rw-r--r--tools/perf/util/hist.c1
-rw-r--r--tools/perf/util/hist.h26
-rw-r--r--tools/perf/util/include/linux/string.h1
-rw-r--r--tools/perf/util/machine.c46
-rw-r--r--tools/perf/util/machine.h8
-rw-r--r--tools/perf/util/parse-events.c112
-rw-r--r--tools/perf/util/parse-events.h11
-rw-r--r--tools/perf/util/parse-events.y62
-rw-r--r--tools/perf/util/pmu.c87
-rw-r--r--tools/perf/util/pmu.h5
-rw-r--r--tools/perf/util/session.c45
-rw-r--r--tools/perf/util/session.h1
-rw-r--r--tools/perf/util/sort.c8
-rw-r--r--tools/perf/util/sort.h7
-rw-r--r--tools/perf/util/string.c24
-rw-r--r--tools/perf/util/symbol.c7
-rw-r--r--tools/perf/util/thread.c10
-rw-r--r--tools/perf/util/thread.h14
-rw-r--r--tools/perf/util/tool.h10
-rw-r--r--tools/perf/util/trace-event-info.c96
-rw-r--r--tools/perf/util/trace-event-parse.c6
-rw-r--r--tools/perf/util/trace-event-read.c52
-rw-r--r--tools/perf/util/trace-event.h17
-rw-r--r--tools/perf/util/util.c59
-rw-r--r--tools/perf/util/util.h3
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
39bindir = $(prefix)/$(bindir_relative) 39bindir = $(prefix)/$(bindir_relative)
40man_dir = $(prefix)/share/man 40man_dir = $(prefix)/share/man
41man_dir_SQ = '$(subst ','\'',$(man_dir))' 41man_dir_SQ = '$(subst ','\'',$(man_dir))'
42html_install = $(prefix)/share/kernelshark/html
43html_install_SQ = '$(subst ','\'',$(html_install))'
44img_install = $(prefix)/share/kernelshark/html/images
45img_install_SQ = '$(subst ','\'',$(img_install))'
46 42
47export man_dir man_dir_SQ html_install html_install_SQ INSTALL 43export man_dir man_dir_SQ INSTALL
48export img_install img_install_SQ
49export DESTDIR DESTDIR_SQ 44export 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
77all: sub-make 72all: sub-make
78 73
79gui: force 74$(MAKECMDGOALS): sub-make
80 $(call build_output, all_cmd)
81
82$(filter-out gui,$(MAKECMDGOALS)): sub-make
83 75
84sub-make: force 76sub-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
191PEVENT_LIB_OBJS = event-parse.o trace-seq.o parse-filter.o parse-utils.o 183PEVENT_LIB_OBJS = event-parse.o trace-seq.o parse-filter.o parse-utils.o
184PEVENT_LIB_OBJS += kbuffer-parse.o
192 185
193ALL_OBJS = $(PEVENT_LIB_OBJS) 186ALL_OBJS = $(PEVENT_LIB_OBJS)
194 187
@@ -258,9 +251,6 @@ define check_deps
258 $(RM) $@.$$$$ 251 $(RM) $@.$$$$
259endef 252endef
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'
301endef 291endef
302 292
303install_lib: all_cmd install_plugins install_python 293install_lib: all_cmd
304 $(Q)$(call do_install,$(LIB_FILE),$(bindir_SQ)) 294 $(Q)$(call do_install,$(LIB_FILE),$(bindir_SQ))
305 295
306install: install_lib 296install: 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 */
5453int pevent_register_event_handler(struct pevent *pevent, 5453int 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
71void trace_seq_init(struct trace_seq *s); 71void trace_seq_init(struct trace_seq *s);
72void trace_seq_reset(struct trace_seq *s);
72void trace_seq_destroy(struct trace_seq *s); 73void trace_seq_destroy(struct trace_seq *s);
73 74
74extern int trace_seq_printf(struct trace_seq *s, const char *fmt, ...) 75extern 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
564int pevent_register_event_handler(struct pevent *pevent, int id, char *sys_name, char *event_name, 566int 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);
566int pevent_register_print_function(struct pevent *pevent, 569int 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
625static inline int pevent_get_page_size(struct pevent *pevent)
626{
627 return pevent->page_size;
628}
629
630static inline void pevent_set_page_size(struct pevent *pevent, int _page_size)
631{
632 pevent->page_size = _page_size;
633}
634
622static inline int pevent_is_file_bigendian(struct pevent *pevent) 635static 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
32enum {
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 */
58struct 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
76static void *zmalloc(size_t size)
77{
78 return calloc(1, size);
79}
80
81static 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
90static int do_swap(struct kbuffer *kbuf)
91{
92 return ((kbuf->flags & KBUFFER_FL_HOST_BIG_ENDIAN) + kbuf->flags) &
93 ENDIAN_MASK;
94}
95
96static unsigned long long __read_8(void *ptr)
97{
98 unsigned long long data = *(unsigned long long *)ptr;
99
100 return data;
101}
102
103static 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
120static unsigned int __read_4(void *ptr)
121{
122 unsigned int data = *(unsigned int *)ptr;
123
124 return data;
125}
126
127static 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
140static unsigned long long read_8(struct kbuffer *kbuf, void *ptr)
141{
142 return kbuf->read_8(ptr);
143}
144
145static unsigned int read_4(struct kbuffer *kbuf, void *ptr)
146{
147 return kbuf->read_4(ptr);
148}
149
150static unsigned long long __read_long_8(struct kbuffer *kbuf, void *ptr)
151{
152 return kbuf->read_8(ptr);
153}
154
155static unsigned long long __read_long_4(struct kbuffer *kbuf, void *ptr)
156{
157 return kbuf->read_4(ptr);
158}
159
160static unsigned long long read_long(struct kbuffer *kbuf, void *ptr)
161{
162 return kbuf->read_long(kbuf, ptr);
163}
164
165static int calc_index(struct kbuffer *kbuf, void *ptr)
166{
167 return (unsigned long)ptr - (unsigned long)kbuf->data;
168}
169
170static 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 */
179struct kbuffer *
180kbuffer_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 */
238void kbuffer_free(struct kbuffer *kbuf)
239{
240 free(kbuf);
241}
242
243static 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
252static 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
261static 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
270static 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 */
283enum 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
290static 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
344static 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
358static unsigned int
359translate_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
406static 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 */
432void *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
463static 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
477static 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 */
494void *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 */
522int 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 */
572void *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 */
591unsigned 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 */
614void *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 */
644int 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 */
659int 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 */
671int 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 */
683int 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 */
695int 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 */
709int 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 */
727void 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
28enum kbuffer_endian {
29 KBUFFER_ENDIAN_BIG,
30 KBUFFER_ENDIAN_LITTLE,
31};
32
33enum kbuffer_long_size {
34 KBUFFER_LSIZE_4,
35 KBUFFER_LSIZE_8,
36};
37
38enum {
39 KBUFFER_TYPE_PADDING = 29,
40 KBUFFER_TYPE_TIME_EXTEND = 30,
41 KBUFFER_TYPE_TIME_STAMP = 31,
42};
43
44struct kbuffer;
45
46struct kbuffer *kbuffer_alloc(enum kbuffer_long_size size, enum kbuffer_endian endian);
47void kbuffer_free(struct kbuffer *kbuf);
48int kbuffer_load_subbuffer(struct kbuffer *kbuf, void *subbuffer);
49void *kbuffer_read_event(struct kbuffer *kbuf, unsigned long long *ts);
50void *kbuffer_next_event(struct kbuffer *kbuf, unsigned long long *ts);
51unsigned long long kbuffer_timestamp(struct kbuffer *kbuf);
52
53void *kbuffer_translate_data(int swap, void *data, unsigned int *size);
54
55void *kbuffer_read_at_offset(struct kbuffer *kbuf, int offset, unsigned long long *ts);
56
57int kbuffer_curr_index(struct kbuffer *kbuf);
58
59int kbuffer_curr_offset(struct kbuffer *kbuf);
60int kbuffer_curr_size(struct kbuffer *kbuf);
61int kbuffer_event_size(struct kbuffer *kbuf);
62int kbuffer_missed_events(struct kbuffer *kbuf);
63int kbuffer_subbuffer_size(struct kbuffer *kbuf);
64
65void 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 */
55void 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
4NAME 4NAME
5---- 5----
6perf-diff - Read two perf.data files and display the differential profile 6perf-diff - Read perf.data files and display the differential profile
7 7
8SYNOPSIS 8SYNOPSIS
9-------- 9--------
10[verse] 10[verse]
11'perf diff' [oldfile] [newfile] 11'perf diff' [baseline file] [data file1] [[data file2] ... ]
12 12
13DESCRIPTION 13DESCRIPTION
14----------- 14-----------
15This command displays the performance difference amongst two perf.data files 15This command displays the performance difference amongst two or more perf.data
16captured via perf record. 16files captured via perf record.
17 17
18If no parameters are passed it will assume perf.data.old and perf.data. 18If 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
92COMPARISON
93----------
94The comparison is governed by the baseline file. The baseline perf.data
95file is iterated for samples. All other perf.data files specified on
96the command line are searched for the baseline sample pair. If the pair
97is found, specified computation is made and result is displayed.
98
99All samples from non-baseline perf.data files, that do not match any
100baseline entry, are displayed with empty space within baseline column
101and possible computation results (delta) in their related column.
102
103Example 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
108Example 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
90COMPARISON METHODS 145COMPARISON METHODS
91------------------ 146------------------
92delta 147delta
@@ -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
98with: 153with:
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
111with: 166with:
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
117wdiff 172wdiff:WEIGHT-B,WEIGHT-A
118~~~~~ 173~~~~~~~~~~~~~~~~~~~~~~~
119If specified the 'Weighted diff' column is displayed with value 'd' computed as: 174If 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
131SEE ALSO 188SEE 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
8SYNOPSIS 8SYNOPSIS
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
13DESCRIPTION 13DESCRIPTION
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))
124ifneq ($(OUTPUT),) 124ifneq ($(OUTPUT),)
125 TE_PATH=$(OUTPUT) 125 TE_PATH=$(OUTPUT)
126ifneq ($(subdir),) 126ifneq ($(subdir),)
127 LK_PATH=$(objtree)/lib/lk/ 127 LK_PATH=$(OUTPUT)/../lib/lk/
128else 128else
129 LK_PATH=$(OUTPUT) 129 LK_PATH=$(OUTPUT)
130endif 130endif
@@ -281,7 +281,7 @@ LIB_H += util/cpumap.h
281LIB_H += util/top.h 281LIB_H += util/top.h
282LIB_H += $(ARCH_INCLUDE) 282LIB_H += $(ARCH_INCLUDE)
283LIB_H += util/cgroup.h 283LIB_H += util/cgroup.h
284LIB_H += $(TRACE_EVENT_DIR)event-parse.h 284LIB_H += $(LIB_INCLUDE)traceevent/event-parse.h
285LIB_H += util/target.h 285LIB_H += util/target.h
286LIB_H += util/rblist.h 286LIB_H += util/rblist.h
287LIB_H += util/intlist.h 287LIB_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
22static char const *input_old = "perf.data.old", 23/* Diff command specific HPP columns. */
23 *input_new = "perf.data"; 24enum {
24static char diff__default_sort_order[] = "dso,symbol"; 25 PERF_HPP_DIFF__BASELINE,
25static 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
36struct diff_hpp_fmt {
37 struct perf_hpp_fmt fmt;
38 int idx;
39 char *header;
40 int header_width;
41};
42
43struct 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
51static struct data__file *data__files;
52static 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
62static char diff__default_sort_order[] = "dso,symbol";
63static bool force;
26static bool show_period; 64static bool show_period;
27static bool show_formula; 65static bool show_formula;
28static bool show_baseline_only; 66static bool show_baseline_only;
29static bool sort_compute; 67static unsigned int sort_compute;
30 68
31static s64 compute_wdiff_w1; 69static s64 compute_wdiff_w1;
32static s64 compute_wdiff_w2; 70static s64 compute_wdiff_w2;
@@ -46,6 +84,47 @@ const char *compute_names[COMPUTE_MAX] = {
46 84
47static int compute; 85static int compute;
48 86
87static 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
95static 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
49static int setup_compute_opt_wdiff(char *opt) 128static 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
148double perf_diff__period_percent(struct hist_entry *he, u64 period) 220static 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
154double perf_diff__compute_delta(struct hist_entry *he, struct hist_entry *pair) 226static 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
164double perf_diff__compute_ratio(struct hist_entry *he, struct hist_entry *pair) 236static 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
174s64 perf_diff__compute_wdiff(struct hist_entry *he, struct hist_entry *pair) 246static 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
186static int formula_delta(struct hist_entry *he, struct hist_entry *pair, 258static 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
196static int formula_ratio(struct hist_entry *he, struct hist_entry *pair, 268static 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,
205static int formula_wdiff(struct hist_entry *he, struct hist_entry *pair, 277static 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
216int perf_diff__formula(struct hist_entry *he, struct hist_entry *pair, 288static 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
374static struct hist_entry*
375get_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
388static struct hist_entry*
389get_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
302static void hists__baseline_only(struct hists *hists) 397static 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
369static int64_t 466static int64_t
370hist_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
499static int64_t
500hist_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
402static void insert_hist_entry_by_compute(struct rb_root *root, 529static 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
451static void hists__process(struct hists *old, struct hists *new) 578static 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
470static int __cmd_diff(void) 593static 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
608static 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
647static 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
514out_delete: 658static 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
522static const char * const diff_usage[] = { 695static 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
561static void ui_init(void) 735static 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) { 741static 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
758static 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
770static void
771hpp__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
783static void
784hpp__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
843static 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
861static 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
877static 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) { 887static 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
897static 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
929static 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
948static 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
592int cmd_diff(int argc, const char **argv, const char *prefix __maybe_unused) 982static 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
1024int 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
40static int perf_event__repipe_synth(struct perf_tool *tool, 40static 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
71static int perf_event__repipe_event_type_synth(struct perf_tool *tool, 70static 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
77static 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
84static 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
95static int perf_event__repipe(struct perf_tool *tool, 83static 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
103typedef int (*inject_handler)(struct perf_tool *tool, 91typedef 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
125static int perf_event__repipe_mmap(struct perf_tool *tool, 113static 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
151static int perf_event__repipe_tracing_data(union perf_event *event, 139static 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
17int cmd_list(int argc, const char **argv, const char *prefix __maybe_unused) 18int 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[] = {
904int cmd_record(int argc, const char **argv, const char *prefix __maybe_unused) 897int 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
601out_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
684int
685report_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
697static int 702static int
698parse_branch_mode(const struct option *opt __maybe_unused, 703parse_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
1132static int pid_cmp(struct work_atoms *l, struct work_atoms *r) 1132static 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
1665static const char default_sort_order[] = "avg, max, switch, runtime";
1666static 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
1665int cmd_sched(int argc, const char **argv, const char *prefix __maybe_unused) 1686int 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;
24static u64 nr_unordered; 24static u64 nr_unordered;
25extern const struct option record_options[]; 25extern const struct option record_options[];
26static bool no_callchain; 26static bool no_callchain;
27static bool latency_format;
27static bool system_wide; 28static bool system_wide;
28static const char *cpu_list; 29static const char *cpu_list;
29static DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS); 30static 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 */
340enum 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
350struct sched_switch { 334struct 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
466typedef int (*tracepoint_handler)(struct perf_evsel *evsel,
467 struct perf_sample *sample);
482 468
483static int process_sample_event(struct perf_tool *tool __maybe_unused, 469static 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. 493static int
510 * 494process_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 506static int
523 if (strcmp(event_str, "power:cpu_idle") == 0) { 507process_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; 516static int
533 p_state_change(ppe->cpu_id, sample->time, ppe->state); 517process_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) 526static int
537 sched_wakeup(sample->cpu, sample->time, sample->pid, te); 527process_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) { 537static int
544 if (strcmp(event_str, "power:power_start") == 0) 538process_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
547static int
548process_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
555static int
556process_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),)
46obj-perf := $(abspath $(obj-perf))/ 46obj-perf := $(abspath $(obj-perf))/
47endif 47endif
48 48
49LIB_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
122CFLAGS += -I$(src-perf)/util 124CFLAGS += -I$(src-perf)/util
123CFLAGS += -I$(src-perf) 125CFLAGS += -I$(src-perf)
124CFLAGS += -I$(TRACE_EVENT_DIR) 126CFLAGS += -I$(LIB_INCLUDE)
125CFLAGS += -I$(srctree)/tools/lib/
126 127
127CFLAGS += -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE 128CFLAGS += -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) \
14do { \
15 if (!(cond)) { \
16 pr_debug("FAILED %s:%d %s\n", __FILE__, __LINE__, text); \
17 return -1; \
18 } \
19} while (0)
20
21static char *test_file(int size) 13static 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
5static int perf_evsel__test_field(struct perf_evsel *evsel, const char *name, 5static 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) \
11do { \
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
1255static int test_term(struct terms_test *t) 1247static 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) \
5do { \
6 if (!(cond)) { \
7 pr_debug("FAILED %s:%d %s\n", __FILE__, __LINE__, text); \
8 return -1; \
9 } \
10} while (0)
11
4enum { 12enum {
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;
149detour: 156detour:
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 \
688static int hist_browser__hpp_color_##_type(struct perf_hpp *hpp, \ 688static int \
689 struct hist_entry *he) \ 689hist_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
702void hist_browser__init_hpp(void) 704void 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 \
94static int perf_gtk__hpp_color_##_type(struct perf_hpp *hpp, \ 94static 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
128static 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
137static 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
191static 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
127static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists, 203static 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) \
82static int hpp__header_##_type(struct perf_hpp *hpp) \ 83static 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) \
95static int hpp__width_##_type(struct perf_hpp *hpp __maybe_unused) \ 97static 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 \
113static int hpp__color_##_type(struct perf_hpp *hpp, struct hist_entry *he) \ 116static 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) \
120static int hpp__entry_##_type(struct perf_hpp *hpp, struct hist_entry *he) \ 124static 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 \
133static int hpp__entry_##_type(struct perf_hpp *hpp, struct hist_entry *he) \ 138static 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)
157HPP_RAW_FNS(samples, "Samples", nr_events, 12, 12) 163HPP_RAW_FNS(samples, "Samples", nr_events, 12, 12)
158HPP_RAW_FNS(period, "Period", period, 12, 12) 164HPP_RAW_FNS(period, "Period", period, 12, 12)
159 165
160
161static int hpp__header_baseline(struct perf_hpp *hpp)
162{
163 return scnprintf(hpp->buf, hpp->size, "Baseline");
164}
165
166static int hpp__width_baseline(struct perf_hpp *hpp __maybe_unused)
167{
168 return 8;
169}
170
171static 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
187static 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
197static 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
208static 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
215static int hpp__width_period_baseline(struct perf_hpp *hpp __maybe_unused)
216{
217 return 12;
218}
219
220static 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
229static 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
236static int hpp__width_delta(struct perf_hpp *hpp __maybe_unused)
237{
238 return 7;
239}
240
241static 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
262static 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
269static int hpp__width_ratio(struct perf_hpp *hpp __maybe_unused)
270{
271 return 14;
272}
273
274static 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
294static 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
301static int hpp__width_wdiff(struct perf_hpp *hpp __maybe_unused)
302{
303 return 14;
304}
305
306static 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
326static 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
333static int hpp__width_formula(struct perf_hpp *hpp __maybe_unused)
334{
335 return 70;
336}
337
338static 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
365struct perf_hpp_fmt perf_hpp__format[] = { 181struct 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
381LIST_HEAD(perf_hpp__list); 191LIST_HEAD(perf_hpp__list);
@@ -396,6 +206,8 @@ LIST_HEAD(perf_hpp__list);
396 206
397void perf_hpp__init(void) 207void 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
427static inline void advance_hpp(struct perf_hpp *hpp, int inc)
428{
429 hpp->buf += inc;
430 hpp->size -= inc;
431}
432
433int 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
467int hist_entry__sort_snprintf(struct hist_entry *he, char *s, size_t size, 239int 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
311static inline void advance_hpp(struct perf_hpp *hpp, int inc)
312{
313 hpp->buf += inc;
314 hpp->size -= inc;
315}
316
317static 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
311static int hist_entry__fprintf(struct hist_entry *he, size_t size, 352static 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
44static inline bool cpu_map__all(const struct cpu_map *map) 44static 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 {
116enum perf_user_event_type { /* above any possible kernel type */ 116enum 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
406static 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
406void perf_evlist__munmap(struct perf_evlist *evlist) 414void 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)
421static int perf_evlist__alloc_mmap(struct perf_evlist *evlist) 425static 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
479out_unmap: 483out_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
519out_unmap: 519out_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:
838int perf_evlist__start_workload(struct perf_evlist *evlist) 834int 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
25static struct { 25static 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
26static bool no_buildid_cache = false; 26static bool no_buildid_cache = false;
27 27
28static int trace_event_count;
29static struct perf_trace_event_type *trace_events;
30
31static u32 header_argc; 28static u32 header_argc;
32static const char **header_argv; 29static const char **header_argv;
33 30
34int 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
53char *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
2669static int perf_header__read_pipe(struct perf_session *session, int fd) 2627static 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
2775int perf_session__read_header(struct perf_session *session, int fd) 2731int 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
2925int perf_event__process_attr(union perf_event *event, 2869int 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
2964int 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
2990int 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
3012int 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
3022int perf_event__synthesize_tracing_data(struct perf_tool *tool, int fd, 2909int 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
3068int perf_event__process_tracing_data(union perf_event *event, 2955int 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
37enum perf_header_version {
38 PERF_HEADER_VERSION_1,
39 PERF_HEADER_VERSION_2,
40};
41
37struct perf_file_section { 42struct 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
86struct perf_header { 92struct 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
97struct perf_evlist; 102struct perf_evlist;
98struct perf_session; 103struct perf_session;
99 104
100int perf_session__read_header(struct perf_session *session, int fd); 105int perf_session__read_header(struct perf_session *session);
101int perf_session__write_header(struct perf_session *session, 106int 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);
104int perf_header__write_pipe(int fd); 109int perf_header__write_pipe(int fd);
105 110
106int perf_header__push_event(u64 id, const char *name);
107char *perf_header__find_event(u64 id);
108
109void perf_header__set_feat(struct perf_header *header, int feat); 111void perf_header__set_feat(struct perf_header *header, int feat);
110void perf_header__clear_feat(struct perf_header *header, int feat); 112void perf_header__clear_feat(struct perf_header *header, int feat);
111bool perf_header__has_feat(const struct perf_header *header, int feat); 113bool perf_header__has_feat(const struct perf_header *header, int feat);
@@ -130,22 +132,14 @@ int perf_event__synthesize_attr(struct perf_tool *tool,
130int perf_event__synthesize_attrs(struct perf_tool *tool, 132int 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);
133int perf_event__process_attr(union perf_event *event, struct perf_evlist **pevlist); 135int perf_event__process_attr(struct perf_tool *tool, union perf_event *event,
134 136 struct perf_evlist **pevlist);
135int 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);
139int perf_event__synthesize_event_types(struct perf_tool *tool,
140 perf_event__handler_t process,
141 struct machine *machine);
142int perf_event__process_event_type(struct perf_tool *tool,
143 union perf_event *event);
144 137
145int perf_event__synthesize_tracing_data(struct perf_tool *tool, 138int 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);
148int perf_event__process_tracing_data(union perf_event *event, 141int 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
151int perf_event__synthesize_build_id(struct perf_tool *tool, 145int 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 }
916out: 917out:
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
143struct perf_hpp_fmt { 143struct 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;
157extern struct perf_hpp_fmt perf_hpp__format[]; 159extern struct perf_hpp_fmt perf_hpp__format[];
158 160
159enum { 161enum {
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 {
177void perf_hpp__init(void); 174void perf_hpp__init(void);
178void perf_hpp__column_register(struct perf_hpp_fmt *format); 175void perf_hpp__column_register(struct perf_hpp_fmt *format);
179void perf_hpp__column_enable(unsigned col); 176void perf_hpp__column_enable(unsigned col);
180int hist_entry__period_snprintf(struct perf_hpp *hpp, struct hist_entry *he,
181 bool color);
182 177
183struct perf_evlist; 178struct 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
247unsigned int hists__sort_list_width(struct hists *self); 242unsigned int hists__sort_list_width(struct hists *self);
248
249double perf_diff__compute_delta(struct hist_entry *he, struct hist_entry *pair);
250double perf_diff__compute_ratio(struct hist_entry *he, struct hist_entry *pair);
251s64 perf_diff__compute_wdiff(struct hist_entry *he, struct hist_entry *pair);
252int perf_diff__formula(struct hist_entry *he, struct hist_entry *pair,
253 char *buf, size_t size);
254double 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
3void *memdup(const void *src, size_t len); 3void *memdup(const void *src, size_t len);
4int 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
236static struct thread *__machine__findnew_thread(struct machine *machine, pid_t pid, 236static 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
279struct thread *machine__findnew_thread(struct machine *machine, pid_t pid) 279struct 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
284struct thread *machine__find_thread(struct machine *machine, pid_t pid) 284struct 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
289int machine__process_comm_event(struct machine *machine, union perf_event *event) 289int 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
1061static bool symbol__match_parent_regex(struct symbol *sym) 1061static 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,
1159static int machine__resolve_callchain_sample(struct machine *machine, 1158static 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
8struct addr_location;
8struct branch_stack; 9struct branch_stack;
9struct perf_evsel; 10struct perf_evsel;
10struct perf_sample; 11struct 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
39struct thread *machine__find_thread(struct machine *machine, pid_t pid); 40struct thread *machine__find_thread(struct machine *machine, pid_t tid);
40 41
41int machine__process_comm_event(struct machine *machine, union perf_event *event); 42int machine__process_comm_event(struct machine *machine, union perf_event *event);
42int machine__process_exit_event(struct machine *machine, union perf_event *event); 43int 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
102struct thread *machine__findnew_thread(struct machine *machine, pid_t pid); 104struct thread *machine__findnew_thread(struct machine *machine, pid_t tid);
103 105
104size_t machine__fprintf(struct machine *machine, FILE *fp); 106size_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
220struct 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
220const char *event_type(int type) 243const 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
244static int __add_event(struct list_head **_list, int *idx, 267static 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
274static int add_event(struct list_head **_list, int *idx, 286static 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
280static int parse_aliases(char *str, const char *names[][PERF_EVSEL__MAX_ALIASES], int size) 292static 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
298int parse_events_add_cache(struct list_head **list, int *idx, 310int 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
359static int add_tracepoint(struct list_head **listp, int *idx, 371static 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
383static int add_tracepoint_multi_event(struct list_head **list, int *idx, 385static 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
415static int add_tracepoint_event(struct list_head **list, int *idx, 417static 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
423static int add_tracepoint_multi_sys(struct list_head **list, int *idx, 425static 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
455int parse_events_add_tracepoint(struct list_head **list, int *idx, 457int 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
510int parse_events_add_breakpoint(struct list_head **list, int *idx, 512int 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
591int parse_events_add_numeric(struct list_head **list, int *idx, 593int 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
624int parse_events_add_pmu(struct list_head **list, int *idx, 626int 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 */
667void parse_events_update_lists(struct list_head *list_event, 670void 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
826static int parse_events__scanner(const char *str, void *data, int start_token);
827
828static 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
823static int parse_events__scanner(const char *str, void *data, int start_token) 852static 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
25extern struct tracepoint_path *tracepoint_id_to_path(u64 config); 25extern struct tracepoint_path *tracepoint_id_to_path(u64 config);
26extern struct tracepoint_path *tracepoint_name_to_path(const char *name);
26extern bool have_tracepoints(struct list_head *evlist); 27extern bool have_tracepoints(struct list_head *evlist);
27 28
28const char *event_type(int type); 29const char *event_type(int type);
@@ -84,16 +85,16 @@ void parse_events__free_terms(struct list_head *terms);
84int parse_events__modifier_event(struct list_head *list, char *str, bool add); 85int parse_events__modifier_event(struct list_head *list, char *str, bool add);
85int parse_events__modifier_group(struct list_head *list, char *event_mod); 86int parse_events__modifier_group(struct list_head *list, char *event_mod);
86int parse_events_name(struct list_head *list, char *name); 87int parse_events_name(struct list_head *list, char *name);
87int parse_events_add_tracepoint(struct list_head **list, int *idx, 88int parse_events_add_tracepoint(struct list_head *list, int *idx,
88 char *sys, char *event); 89 char *sys, char *event);
89int parse_events_add_numeric(struct list_head **list, int *idx, 90int 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);
92int parse_events_add_cache(struct list_head **list, int *idx, 93int 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);
94int parse_events_add_breakpoint(struct list_head **list, int *idx, 95int parse_events_add_breakpoint(struct list_head *list, int *idx,
95 void *ptr, char *type); 96 void *ptr, char *type);
96int parse_events_add_pmu(struct list_head **list, int *idx, 97int 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);
98void parse_events__set_leader(char *name, struct list_head *list); 99void parse_events__set_leader(char *name, struct list_head *list);
99void parse_events_update_lists(struct list_head *list_event, 100void 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) \
26do { \
27 list = malloc(sizeof(*list)); \
28 ABORT_ON(!list); \
29 INIT_LIST_HEAD(list); \
30} while (0)
31
25static inc_group_count(struct list_head *list, 32static 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:
196PE_NAME '/' event_config '/' 203PE_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:
212value_sym '/' event_config '/' 220value_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 '/'
225value_sym sep_slash_dc 234value_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:
238PE_NAME_CACHE_TYPE '-' PE_NAME_CACHE_OP_RESULT '-' PE_NAME_CACHE_OP_RESULT 248PE_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|
247PE_NAME_CACHE_TYPE '-' PE_NAME_CACHE_OP_RESULT 258PE_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|
256PE_NAME_CACHE_TYPE 268PE_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:
266PE_PREFIX_MEM PE_VALUE ':' PE_MODIFIER_BP sep_dc 279PE_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
276PE_PREFIX_MEM PE_VALUE sep_dc 290PE_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:
287PE_NAME ':' PE_NAME 302PE_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:
297PE_VALUE ':' PE_VALUE 313PE_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:
307PE_RAW 324PE_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 */
76static int pmu_format(char *name, struct list_head *format) 76static 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 */
165static int pmu_aliases(char *name, struct list_head *head) 165static 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 */
211static int pmu_type(char *name, __u32 *type) 211static 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
269static struct cpu_map *pmu_cpumask(char *name) 269static 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
296static struct perf_pmu *pmu_lookup(char *name) 296static 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
333static struct perf_pmu *pmu_find(char *name) 333static 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
359struct perf_pmu *perf_pmu__find(char *name) 359struct 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
568static 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
575static 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
582static 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
589void 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
7enum { 8enum {
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
24struct perf_pmu *perf_pmu__find(char *name); 25struct perf_pmu *perf_pmu__find(const char *name);
25int perf_pmu__config(struct perf_pmu *pmu, struct perf_event_attr *attr, 26int perf_pmu__config(struct perf_pmu *pmu, struct perf_event_attr *attr,
26 struct list_head *head_terms); 27 struct list_head *head_terms);
27int perf_pmu__config_terms(struct list_head *formats, 28int 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
41struct perf_pmu *perf_pmu__scan(struct perf_pmu *pmu); 42struct perf_pmu *perf_pmu__scan(struct perf_pmu *pmu);
42 43
44void print_pmu_events(const char *event_glob, bool name_only);
45
43int perf_pmu__test(void); 46int 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
196static int process_event_synth_tracing_data_stub(union perf_event *event 196static 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
205static int process_event_synth_attr_stub(union perf_event *event __maybe_unused, 207static 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
241static 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
248static int process_finished_round(struct perf_tool *tool, 244static 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";
7const char *parent_pattern = default_parent_pattern; 7const char *parent_pattern = default_parent_pattern;
8const char default_sort_order[] = "comm,dso,symbol"; 8const char default_sort_order[] = "comm,dso,symbol";
9const char *sort_order = default_sort_order; 9const char *sort_order = default_sort_order;
10regex_t ignore_callees_regex;
11int have_ignore_callees = 0;
10int sort__need_collapse = 0; 12int sort__need_collapse = 0;
11int sort__has_parent = 0; 13int sort__has_parent = 0;
12int sort__has_sym = 0; 14int sort__has_sym = 0;
@@ -55,14 +57,14 @@ static int64_t cmp_null(void *l, void *r)
55static int64_t 57static int64_t
56sort__thread_cmp(struct hist_entry *left, struct hist_entry *right) 58sort__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
61static int hist_entry__thread_snprintf(struct hist_entry *self, char *bf, 63static 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
68struct sort_entry sort_thread = { 70struct sort_entry sort_thread = {
@@ -77,7 +79,7 @@ struct sort_entry sort_thread = {
77static int64_t 79static int64_t
78sort__comm_cmp(struct hist_entry *left, struct hist_entry *right) 80sort__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
83static int64_t 85static 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;
29extern const char default_parent_pattern[]; 29extern const char default_parent_pattern[];
30extern const char *parent_pattern; 30extern const char *parent_pattern;
31extern const char default_sort_order[]; 31extern const char default_sort_order[];
32extern regex_t ignore_callees_regex;
33extern int have_ignore_callees;
32extern int sort__need_collapse; 34extern int sort__need_collapse;
33extern int sort__has_parent; 35extern int sort__has_parent;
34extern int sort__has_sym; 36extern 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);
183extern int sort_dimension__add(const char *); 188extern int sort_dimension__add(const char *);
184void sort__setup_elide(FILE *fp); 189void sort__setup_elide(FILE *fp);
185 190
191int 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 */
397int 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
10struct thread *thread__new(pid_t pid) 10struct 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
58size_t thread__fprintf(struct thread *thread, FILE *fp) 58size_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
25struct machine; 25struct machine;
26 26
27struct thread *thread__new(pid_t pid); 27struct thread *thread__new(pid_t tid);
28void thread__delete(struct thread *self); 28void thread__delete(struct thread *self);
29 29
30int thread__set_comm(struct thread *self, const char *comm); 30int 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
51static inline void *thread__priv(struct thread *thread)
52{
53 return thread->priv;
54}
55
56static 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,
18typedef int (*event_op)(struct perf_tool *tool, union perf_event *event, 18typedef 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
21typedef int (*event_attr_op)(union perf_event *event, 21typedef int (*event_attr_op)(struct perf_tool *tool,
22 union perf_event *event,
22 struct perf_evlist **pevlist); 23 struct perf_evlist **pevlist);
23typedef int (*event_simple_op)(struct perf_tool *tool, union perf_event *event);
24
25typedef int (*event_synth_op)(union perf_event *event,
26 struct perf_session *session);
27 24
28typedef int (*event_op2)(struct perf_tool *tool, union perf_event *event, 25typedef 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 @@
46static int output_fd; 46static int output_fd;
47 47
48 48
49static 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 */
63static 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
86static 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
103static void put_tracing_file(char *file)
104{
105 free(file);
106}
107
108int bigendian(void) 49int 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
163static int read_header_files(void) 104static 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
302static int read_ftrace_files(struct tracepoint_path *tps) 243static 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
331static int read_event_files(struct tracepoint_path *tps) 272static 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
406static int read_proc_kallsyms(void) 347static 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
424static int read_ftrace_printk(void) 365static 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
429try_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) {
432error:
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 }
437next:
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
600out: 554out:
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
31int header_page_size_size;
32int header_page_ts_size;
33int header_page_data_offset;
34
35bool latency_format;
36
37struct pevent *read_trace_init(int file_bigendian, int host_bigendian) 31struct 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
40static int input_fd; 40static int input_fd;
41 41
42int file_bigendian;
43int host_bigendian;
44static int long_size;
45
46static ssize_t trace_data_size; 42static ssize_t trace_data_size;
47static bool repipe; 43static bool repipe;
48 44
@@ -216,7 +212,7 @@ static int read_ftrace_printk(struct pevent *pevent)
216static int read_header_files(struct pevent *pevent) 212static 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
8struct machine; 8struct machine;
@@ -10,23 +10,8 @@ struct perf_sample;
10union perf_event; 10union perf_event;
11struct perf_tool; 11struct perf_tool;
12 12
13extern int header_page_size_size;
14extern int header_page_ts_size;
15extern int header_page_data_offset;
16
17extern bool latency_format;
18extern struct pevent *perf_pevent; 13extern struct pevent *perf_pevent;
19 14
20enum {
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
30int bigendian(void); 15int bigendian(void);
31 16
32struct pevent *read_trace_init(int file_bigendian, int host_bigendian); 17struct 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
273static 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 */
287const 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
310char *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
327void 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[];
80extern char tracing_events_path[]; 80extern char tracing_events_path[];
81extern void perf_debugfs_set_path(const char *mountpoint); 81extern void perf_debugfs_set_path(const char *mountpoint);
82const char *perf_debugfs_mount(const char *mountpoint); 82const char *perf_debugfs_mount(const char *mountpoint);
83const char *find_tracing_dir(void);
84char *get_tracing_file(const char *name);
85void 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).