aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf
diff options
context:
space:
mode:
authorHaavard Skinnemoen <haavard.skinnemoen@atmel.com>2009-10-06 11:36:55 -0400
committerHaavard Skinnemoen <haavard.skinnemoen@atmel.com>2009-10-06 11:36:55 -0400
commitd94e5fcbf1420366dcb4102bafe04dbcfc0d0d4b (patch)
treea9b7de7df6da5c3132cc68169b9c47ba288ccd42 /tools/perf
parentd55651168a20078a94597a297d5cdfd807bf07b6 (diff)
parent374576a8b6f865022c0fd1ca62396889b23d66dd (diff)
Merge commit 'v2.6.32-rc3'
Diffstat (limited to 'tools/perf')
-rw-r--r--tools/perf/.gitignore1
-rw-r--r--tools/perf/Documentation/perf-record.txt4
-rw-r--r--tools/perf/Documentation/perf-report.txt13
-rw-r--r--tools/perf/Documentation/perf-sched.txt41
-rw-r--r--tools/perf/Documentation/perf-timechart.txt38
-rw-r--r--tools/perf/Documentation/perf-trace.txt25
-rw-r--r--tools/perf/Makefile50
-rw-r--r--tools/perf/builtin-annotate.c488
-rw-r--r--tools/perf/builtin-help.c1
-rw-r--r--tools/perf/builtin-record.c112
-rw-r--r--tools/perf/builtin-report.c747
-rw-r--r--tools/perf/builtin-sched.c2004
-rw-r--r--tools/perf/builtin-stat.c261
-rw-r--r--tools/perf/builtin-timechart.c1158
-rw-r--r--tools/perf/builtin-top.c78
-rw-r--r--tools/perf/builtin-trace.c297
-rw-r--r--tools/perf/builtin.h5
-rw-r--r--tools/perf/command-list.txt3
-rw-r--r--tools/perf/design.txt58
-rw-r--r--tools/perf/perf.c3
-rw-r--r--tools/perf/perf.h18
-rw-r--r--tools/perf/util/abspath.c3
-rw-r--r--tools/perf/util/cache.h1
-rw-r--r--tools/perf/util/callchain.c2
-rw-r--r--tools/perf/util/callchain.h1
-rw-r--r--tools/perf/util/color.c16
-rw-r--r--tools/perf/util/color.h3
-rw-r--r--tools/perf/util/config.c22
-rw-r--r--tools/perf/util/debug.c95
-rw-r--r--tools/perf/util/debug.h8
-rw-r--r--tools/perf/util/event.h104
-rw-r--r--tools/perf/util/exec_cmd.c1
-rw-r--r--tools/perf/util/header.c108
-rw-r--r--tools/perf/util/header.h16
-rw-r--r--tools/perf/util/map.c97
-rw-r--r--tools/perf/util/module.c98
-rw-r--r--tools/perf/util/parse-events.c401
-rw-r--r--tools/perf/util/parse-events.h19
-rw-r--r--tools/perf/util/parse-options.c22
-rw-r--r--tools/perf/util/parse-options.h2
-rw-r--r--tools/perf/util/path.c25
-rw-r--r--tools/perf/util/run-command.c6
-rw-r--r--tools/perf/util/svghelper.c488
-rw-r--r--tools/perf/util/svghelper.h28
-rw-r--r--tools/perf/util/symbol.c212
-rw-r--r--tools/perf/util/symbol.h14
-rw-r--r--tools/perf/util/thread.c175
-rw-r--r--tools/perf/util/thread.h22
-rw-r--r--tools/perf/util/trace-event-info.c540
-rw-r--r--tools/perf/util/trace-event-parse.c2967
-rw-r--r--tools/perf/util/trace-event-read.c514
-rw-r--r--tools/perf/util/trace-event.h245
-rw-r--r--tools/perf/util/util.h6
-rw-r--r--tools/perf/util/values.c230
-rw-r--r--tools/perf/util/values.h27
55 files changed, 10371 insertions, 1552 deletions
diff --git a/tools/perf/.gitignore b/tools/perf/.gitignore
index d69a759a1046..0854f110bf7f 100644
--- a/tools/perf/.gitignore
+++ b/tools/perf/.gitignore
@@ -10,6 +10,7 @@ perf-stat
10perf-top 10perf-top
11perf*.1 11perf*.1
12perf*.xml 12perf*.xml
13perf*.html
13common-cmds.h 14common-cmds.h
14tags 15tags
15TAGS 16TAGS
diff --git a/tools/perf/Documentation/perf-record.txt b/tools/perf/Documentation/perf-record.txt
index 6be696b0a2bb..0ff23de9e453 100644
--- a/tools/perf/Documentation/perf-record.txt
+++ b/tools/perf/Documentation/perf-record.txt
@@ -91,6 +91,10 @@ OPTIONS
91--no-samples:: 91--no-samples::
92 Don't sample. 92 Don't sample.
93 93
94-R::
95--raw-samples::
96Collect raw sample records from all opened counters (typically for tracepoint counters).
97
94SEE ALSO 98SEE ALSO
95-------- 99--------
96linkperf:perf-stat[1], linkperf:perf-list[1] 100linkperf:perf-stat[1], linkperf:perf-list[1]
diff --git a/tools/perf/Documentation/perf-report.txt b/tools/perf/Documentation/perf-report.txt
index e72e93110782..59f0b846cd71 100644
--- a/tools/perf/Documentation/perf-report.txt
+++ b/tools/perf/Documentation/perf-report.txt
@@ -27,6 +27,9 @@ OPTIONS
27-n 27-n
28--show-nr-samples 28--show-nr-samples
29 Show the number of samples for each symbol 29 Show the number of samples for each symbol
30-T
31--threads
32 Show per-thread event counters
30-C:: 33-C::
31--comms=:: 34--comms=::
32 Only consider symbols in these comms. CSV that understands 35 Only consider symbols in these comms. CSV that understands
@@ -48,6 +51,16 @@ OPTIONS
48 all occurances of this separator in symbol names (and other output) 51 all occurances of this separator in symbol names (and other output)
49 with a '.' character, that thus it's the only non valid separator. 52 with a '.' character, that thus it's the only non valid separator.
50 53
54-g [type,min]::
55--call-graph::
56 Display callchains using type and min percent threshold.
57 type can be either:
58 - flat: single column, linear exposure of callchains.
59 - graph: use a graph tree, displaying absolute overhead rates.
60 - fractal: like graph, but displays relative rates. Each branch of
61 the tree is considered as a new profiled object. +
62 Default: fractal,0.5.
63
51SEE ALSO 64SEE ALSO
52-------- 65--------
53linkperf:perf-stat[1] 66linkperf:perf-stat[1]
diff --git a/tools/perf/Documentation/perf-sched.txt b/tools/perf/Documentation/perf-sched.txt
new file mode 100644
index 000000000000..1ce79198997b
--- /dev/null
+++ b/tools/perf/Documentation/perf-sched.txt
@@ -0,0 +1,41 @@
1perf-sched(1)
2==============
3
4NAME
5----
6perf-sched - Tool to trace/measure scheduler properties (latencies)
7
8SYNOPSIS
9--------
10[verse]
11'perf sched' {record|latency|replay|trace}
12
13DESCRIPTION
14-----------
15There's four variants of perf sched:
16
17 'perf sched record <command>' to record the scheduling events
18 of an arbitrary workload.
19
20 'perf sched latency' to report the per task scheduling latencies
21 and other scheduling properties of the workload.
22
23 'perf sched trace' to see a detailed trace of the workload that
24 was recorded.
25
26 'perf sched replay' to simulate the workload that was recorded
27 via perf sched record. (this is done by starting up mockup threads
28 that mimic the workload based on the events in the trace. These
29 threads can then replay the timings (CPU runtime and sleep patterns)
30 of the workload as it occured when it was recorded - and can repeat
31 it a number of times, measuring its performance.)
32
33OPTIONS
34-------
35-D::
36--dump-raw-trace=::
37 Display verbose dump of the sched data.
38
39SEE ALSO
40--------
41linkperf:perf-record[1]
diff --git a/tools/perf/Documentation/perf-timechart.txt b/tools/perf/Documentation/perf-timechart.txt
new file mode 100644
index 000000000000..1c2ed3090cce
--- /dev/null
+++ b/tools/perf/Documentation/perf-timechart.txt
@@ -0,0 +1,38 @@
1perf-timechart(1)
2=================
3
4NAME
5----
6perf-timechart - Tool to visualize total system behavior during a workload
7
8SYNOPSIS
9--------
10[verse]
11'perf timechart' {record}
12
13DESCRIPTION
14-----------
15There are two variants of perf timechart:
16
17 'perf timechart record <command>' to record the system level events
18 of an arbitrary workload.
19
20 'perf timechart' to turn a trace into a Scalable Vector Graphics file,
21 that can be viewed with popular SVG viewers such as 'Inkscape'.
22
23OPTIONS
24-------
25-o::
26--output=::
27 Select the output file (default: output.svg)
28-i::
29--input=::
30 Select the input file (default: perf.data)
31-w::
32--width=::
33 Select the width of the SVG file (default: 1000)
34
35
36SEE ALSO
37--------
38linkperf:perf-record[1]
diff --git a/tools/perf/Documentation/perf-trace.txt b/tools/perf/Documentation/perf-trace.txt
new file mode 100644
index 000000000000..41ed75398ca9
--- /dev/null
+++ b/tools/perf/Documentation/perf-trace.txt
@@ -0,0 +1,25 @@
1perf-trace(1)
2==============
3
4NAME
5----
6perf-trace - Read perf.data (created by perf record) and display trace output
7
8SYNOPSIS
9--------
10[verse]
11'perf trace' [-i <file> | --input=file] symbol_name
12
13DESCRIPTION
14-----------
15This command reads the input file and displays the trace recorded.
16
17OPTIONS
18-------
19-D::
20--dump-raw-trace=::
21 Display verbose dump of the trace data.
22
23SEE ALSO
24--------
25linkperf:perf-record[1]
diff --git a/tools/perf/Makefile b/tools/perf/Makefile
index c045b4271e57..b5f1953b6144 100644
--- a/tools/perf/Makefile
+++ b/tools/perf/Makefile
@@ -166,7 +166,35 @@ endif
166 166
167# CFLAGS and LDFLAGS are for the users to override from the command line. 167# CFLAGS and LDFLAGS are for the users to override from the command line.
168 168
169CFLAGS = $(M64) -ggdb3 -Wall -Wextra -Wstrict-prototypes -Wmissing-declarations -Wmissing-prototypes -std=gnu99 -Wdeclaration-after-statement -Werror -O6 169#
170# Include saner warnings here, which can catch bugs:
171#
172
173EXTRA_WARNINGS := -Wcast-align
174EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wformat
175EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wformat-security
176EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wformat-y2k
177EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wshadow
178EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Winit-self
179EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wpacked
180EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wredundant-decls
181EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wstack-protector
182EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wstrict-aliasing=3
183EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wswitch-default
184EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wswitch-enum
185EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wno-system-headers
186EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wundef
187EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wvolatile-register-var
188EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wwrite-strings
189EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wbad-function-cast
190EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wmissing-declarations
191EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wmissing-prototypes
192EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wnested-externs
193EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wold-style-definition
194EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wstrict-prototypes
195EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wdeclaration-after-statement
196
197CFLAGS = $(M64) -ggdb3 -Wall -Wextra -std=gnu99 -Werror -O6 -fstack-protector-all -D_FORTIFY_SOURCE=2 $(EXTRA_WARNINGS)
170LDFLAGS = -lpthread -lrt -lelf -lm 198LDFLAGS = -lpthread -lrt -lelf -lm
171ALL_CFLAGS = $(CFLAGS) 199ALL_CFLAGS = $(CFLAGS)
172ALL_LDFLAGS = $(LDFLAGS) 200ALL_LDFLAGS = $(LDFLAGS)
@@ -290,7 +318,7 @@ export PERL_PATH
290 318
291LIB_FILE=libperf.a 319LIB_FILE=libperf.a
292 320
293LIB_H += ../../include/linux/perf_counter.h 321LIB_H += ../../include/linux/perf_event.h
294LIB_H += ../../include/linux/rbtree.h 322LIB_H += ../../include/linux/rbtree.h
295LIB_H += ../../include/linux/list.h 323LIB_H += ../../include/linux/list.h
296LIB_H += util/include/linux/list.h 324LIB_H += util/include/linux/list.h
@@ -310,6 +338,7 @@ LIB_H += util/sigchain.h
310LIB_H += util/symbol.h 338LIB_H += util/symbol.h
311LIB_H += util/module.h 339LIB_H += util/module.h
312LIB_H += util/color.h 340LIB_H += util/color.h
341LIB_H += util/values.h
313 342
314LIB_OBJS += util/abspath.o 343LIB_OBJS += util/abspath.o
315LIB_OBJS += util/alias.o 344LIB_OBJS += util/alias.o
@@ -337,14 +366,25 @@ LIB_OBJS += util/color.o
337LIB_OBJS += util/pager.o 366LIB_OBJS += util/pager.o
338LIB_OBJS += util/header.o 367LIB_OBJS += util/header.o
339LIB_OBJS += util/callchain.o 368LIB_OBJS += util/callchain.o
369LIB_OBJS += util/values.o
370LIB_OBJS += util/debug.o
371LIB_OBJS += util/map.o
372LIB_OBJS += util/thread.o
373LIB_OBJS += util/trace-event-parse.o
374LIB_OBJS += util/trace-event-read.o
375LIB_OBJS += util/trace-event-info.o
376LIB_OBJS += util/svghelper.o
340 377
341BUILTIN_OBJS += builtin-annotate.o 378BUILTIN_OBJS += builtin-annotate.o
342BUILTIN_OBJS += builtin-help.o 379BUILTIN_OBJS += builtin-help.o
380BUILTIN_OBJS += builtin-sched.o
343BUILTIN_OBJS += builtin-list.o 381BUILTIN_OBJS += builtin-list.o
344BUILTIN_OBJS += builtin-record.o 382BUILTIN_OBJS += builtin-record.o
345BUILTIN_OBJS += builtin-report.o 383BUILTIN_OBJS += builtin-report.o
346BUILTIN_OBJS += builtin-stat.o 384BUILTIN_OBJS += builtin-stat.o
385BUILTIN_OBJS += builtin-timechart.o
347BUILTIN_OBJS += builtin-top.o 386BUILTIN_OBJS += builtin-top.o
387BUILTIN_OBJS += builtin-trace.o
348 388
349PERFLIBS = $(LIB_FILE) 389PERFLIBS = $(LIB_FILE)
350 390
@@ -673,6 +713,12 @@ builtin-help.o: builtin-help.c common-cmds.h PERF-CFLAGS
673 '-DPERF_MAN_PATH="$(mandir_SQ)"' \ 713 '-DPERF_MAN_PATH="$(mandir_SQ)"' \
674 '-DPERF_INFO_PATH="$(infodir_SQ)"' $< 714 '-DPERF_INFO_PATH="$(infodir_SQ)"' $<
675 715
716builtin-timechart.o: builtin-timechart.c common-cmds.h PERF-CFLAGS
717 $(QUIET_CC)$(CC) -o $*.o -c $(ALL_CFLAGS) \
718 '-DPERF_HTML_PATH="$(htmldir_SQ)"' \
719 '-DPERF_MAN_PATH="$(mandir_SQ)"' \
720 '-DPERF_INFO_PATH="$(infodir_SQ)"' $<
721
676$(BUILT_INS): perf$X 722$(BUILT_INS): perf$X
677 $(QUIET_BUILT_IN)$(RM) $@ && \ 723 $(QUIET_BUILT_IN)$(RM) $@ && \
678 ln perf$X $@ 2>/dev/null || \ 724 ln perf$X $@ 2>/dev/null || \
diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c
index 5e17de984dc8..1ec741615814 100644
--- a/tools/perf/builtin-annotate.c
+++ b/tools/perf/builtin-annotate.c
@@ -17,16 +17,13 @@
17#include "util/string.h" 17#include "util/string.h"
18 18
19#include "perf.h" 19#include "perf.h"
20#include "util/debug.h"
20 21
21#include "util/parse-options.h" 22#include "util/parse-options.h"
22#include "util/parse-events.h" 23#include "util/parse-events.h"
23 24#include "util/thread.h"
24#define SHOW_KERNEL 1
25#define SHOW_USER 2
26#define SHOW_HV 4
27 25
28static char const *input_name = "perf.data"; 26static char const *input_name = "perf.data";
29static char *vmlinux = "vmlinux";
30 27
31static char default_sort_order[] = "comm,symbol"; 28static char default_sort_order[] = "comm,symbol";
32static char *sort_order = default_sort_order; 29static char *sort_order = default_sort_order;
@@ -35,13 +32,6 @@ static int force;
35static int input; 32static int input;
36static int show_mask = SHOW_KERNEL | SHOW_USER | SHOW_HV; 33static int show_mask = SHOW_KERNEL | SHOW_USER | SHOW_HV;
37 34
38static int dump_trace = 0;
39#define dprintf(x...) do { if (dump_trace) printf(x); } while (0)
40
41static int verbose;
42
43static int modules;
44
45static int full_paths; 35static int full_paths;
46 36
47static int print_line; 37static int print_line;
@@ -49,39 +39,8 @@ static int print_line;
49static unsigned long page_size; 39static unsigned long page_size;
50static unsigned long mmap_window = 32; 40static unsigned long mmap_window = 32;
51 41
52struct ip_event { 42static struct rb_root threads;
53 struct perf_event_header header; 43static struct thread *last_match;
54 u64 ip;
55 u32 pid, tid;
56};
57
58struct mmap_event {
59 struct perf_event_header header;
60 u32 pid, tid;
61 u64 start;
62 u64 len;
63 u64 pgoff;
64 char filename[PATH_MAX];
65};
66
67struct comm_event {
68 struct perf_event_header header;
69 u32 pid, tid;
70 char comm[16];
71};
72
73struct fork_event {
74 struct perf_event_header header;
75 u32 pid, ppid;
76};
77
78typedef union event_union {
79 struct perf_event_header header;
80 struct ip_event ip;
81 struct mmap_event mmap;
82 struct comm_event comm;
83 struct fork_event fork;
84} event_t;
85 44
86 45
87struct sym_ext { 46struct sym_ext {
@@ -90,323 +49,6 @@ struct sym_ext {
90 char *path; 49 char *path;
91}; 50};
92 51
93static LIST_HEAD(dsos);
94static struct dso *kernel_dso;
95static struct dso *vdso;
96
97
98static void dsos__add(struct dso *dso)
99{
100 list_add_tail(&dso->node, &dsos);
101}
102
103static struct dso *dsos__find(const char *name)
104{
105 struct dso *pos;
106
107 list_for_each_entry(pos, &dsos, node)
108 if (strcmp(pos->name, name) == 0)
109 return pos;
110 return NULL;
111}
112
113static struct dso *dsos__findnew(const char *name)
114{
115 struct dso *dso = dsos__find(name);
116 int nr;
117
118 if (dso)
119 return dso;
120
121 dso = dso__new(name, 0);
122 if (!dso)
123 goto out_delete_dso;
124
125 nr = dso__load(dso, NULL, verbose);
126 if (nr < 0) {
127 if (verbose)
128 fprintf(stderr, "Failed to open: %s\n", name);
129 goto out_delete_dso;
130 }
131 if (!nr && verbose) {
132 fprintf(stderr,
133 "No symbols found in: %s, maybe install a debug package?\n",
134 name);
135 }
136
137 dsos__add(dso);
138
139 return dso;
140
141out_delete_dso:
142 dso__delete(dso);
143 return NULL;
144}
145
146static void dsos__fprintf(FILE *fp)
147{
148 struct dso *pos;
149
150 list_for_each_entry(pos, &dsos, node)
151 dso__fprintf(pos, fp);
152}
153
154static struct symbol *vdso__find_symbol(struct dso *dso, u64 ip)
155{
156 return dso__find_symbol(dso, ip);
157}
158
159static int load_kernel(void)
160{
161 int err;
162
163 kernel_dso = dso__new("[kernel]", 0);
164 if (!kernel_dso)
165 return -1;
166
167 err = dso__load_kernel(kernel_dso, vmlinux, NULL, verbose, modules);
168 if (err <= 0) {
169 dso__delete(kernel_dso);
170 kernel_dso = NULL;
171 } else
172 dsos__add(kernel_dso);
173
174 vdso = dso__new("[vdso]", 0);
175 if (!vdso)
176 return -1;
177
178 vdso->find_symbol = vdso__find_symbol;
179
180 dsos__add(vdso);
181
182 return err;
183}
184
185struct map {
186 struct list_head node;
187 u64 start;
188 u64 end;
189 u64 pgoff;
190 u64 (*map_ip)(struct map *, u64);
191 struct dso *dso;
192};
193
194static u64 map__map_ip(struct map *map, u64 ip)
195{
196 return ip - map->start + map->pgoff;
197}
198
199static u64 vdso__map_ip(struct map *map __used, u64 ip)
200{
201 return ip;
202}
203
204static struct map *map__new(struct mmap_event *event)
205{
206 struct map *self = malloc(sizeof(*self));
207
208 if (self != NULL) {
209 const char *filename = event->filename;
210
211 self->start = event->start;
212 self->end = event->start + event->len;
213 self->pgoff = event->pgoff;
214
215 self->dso = dsos__findnew(filename);
216 if (self->dso == NULL)
217 goto out_delete;
218
219 if (self->dso == vdso)
220 self->map_ip = vdso__map_ip;
221 else
222 self->map_ip = map__map_ip;
223 }
224 return self;
225out_delete:
226 free(self);
227 return NULL;
228}
229
230static struct map *map__clone(struct map *self)
231{
232 struct map *map = malloc(sizeof(*self));
233
234 if (!map)
235 return NULL;
236
237 memcpy(map, self, sizeof(*self));
238
239 return map;
240}
241
242static int map__overlap(struct map *l, struct map *r)
243{
244 if (l->start > r->start) {
245 struct map *t = l;
246 l = r;
247 r = t;
248 }
249
250 if (l->end > r->start)
251 return 1;
252
253 return 0;
254}
255
256static size_t map__fprintf(struct map *self, FILE *fp)
257{
258 return fprintf(fp, " %Lx-%Lx %Lx %s\n",
259 self->start, self->end, self->pgoff, self->dso->name);
260}
261
262
263struct thread {
264 struct rb_node rb_node;
265 struct list_head maps;
266 pid_t pid;
267 char *comm;
268};
269
270static struct thread *thread__new(pid_t pid)
271{
272 struct thread *self = malloc(sizeof(*self));
273
274 if (self != NULL) {
275 self->pid = pid;
276 self->comm = malloc(32);
277 if (self->comm)
278 snprintf(self->comm, 32, ":%d", self->pid);
279 INIT_LIST_HEAD(&self->maps);
280 }
281
282 return self;
283}
284
285static int thread__set_comm(struct thread *self, const char *comm)
286{
287 if (self->comm)
288 free(self->comm);
289 self->comm = strdup(comm);
290 return self->comm ? 0 : -ENOMEM;
291}
292
293static size_t thread__fprintf(struct thread *self, FILE *fp)
294{
295 struct map *pos;
296 size_t ret = fprintf(fp, "Thread %d %s\n", self->pid, self->comm);
297
298 list_for_each_entry(pos, &self->maps, node)
299 ret += map__fprintf(pos, fp);
300
301 return ret;
302}
303
304
305static struct rb_root threads;
306static struct thread *last_match;
307
308static struct thread *threads__findnew(pid_t pid)
309{
310 struct rb_node **p = &threads.rb_node;
311 struct rb_node *parent = NULL;
312 struct thread *th;
313
314 /*
315 * Font-end cache - PID lookups come in blocks,
316 * so most of the time we dont have to look up
317 * the full rbtree:
318 */
319 if (last_match && last_match->pid == pid)
320 return last_match;
321
322 while (*p != NULL) {
323 parent = *p;
324 th = rb_entry(parent, struct thread, rb_node);
325
326 if (th->pid == pid) {
327 last_match = th;
328 return th;
329 }
330
331 if (pid < th->pid)
332 p = &(*p)->rb_left;
333 else
334 p = &(*p)->rb_right;
335 }
336
337 th = thread__new(pid);
338 if (th != NULL) {
339 rb_link_node(&th->rb_node, parent, p);
340 rb_insert_color(&th->rb_node, &threads);
341 last_match = th;
342 }
343
344 return th;
345}
346
347static void thread__insert_map(struct thread *self, struct map *map)
348{
349 struct map *pos, *tmp;
350
351 list_for_each_entry_safe(pos, tmp, &self->maps, node) {
352 if (map__overlap(pos, map)) {
353 list_del_init(&pos->node);
354 /* XXX leaks dsos */
355 free(pos);
356 }
357 }
358
359 list_add_tail(&map->node, &self->maps);
360}
361
362static int thread__fork(struct thread *self, struct thread *parent)
363{
364 struct map *map;
365
366 if (self->comm)
367 free(self->comm);
368 self->comm = strdup(parent->comm);
369 if (!self->comm)
370 return -ENOMEM;
371
372 list_for_each_entry(map, &parent->maps, node) {
373 struct map *new = map__clone(map);
374 if (!new)
375 return -ENOMEM;
376 thread__insert_map(self, new);
377 }
378
379 return 0;
380}
381
382static struct map *thread__find_map(struct thread *self, u64 ip)
383{
384 struct map *pos;
385
386 if (self == NULL)
387 return NULL;
388
389 list_for_each_entry(pos, &self->maps, node)
390 if (ip >= pos->start && ip <= pos->end)
391 return pos;
392
393 return NULL;
394}
395
396static size_t threads__fprintf(FILE *fp)
397{
398 size_t ret = 0;
399 struct rb_node *nd;
400
401 for (nd = rb_first(&threads); nd; nd = rb_next(nd)) {
402 struct thread *pos = rb_entry(nd, struct thread, rb_node);
403
404 ret += thread__fprintf(pos, fp);
405 }
406
407 return ret;
408}
409
410/* 52/*
411 * histogram, sorted on item, collects counts 53 * histogram, sorted on item, collects counts
412 */ 54 */
@@ -433,7 +75,7 @@ struct hist_entry {
433struct sort_entry { 75struct sort_entry {
434 struct list_head list; 76 struct list_head list;
435 77
436 char *header; 78 const char *header;
437 79
438 int64_t (*cmp)(struct hist_entry *, struct hist_entry *); 80 int64_t (*cmp)(struct hist_entry *, struct hist_entry *);
439 int64_t (*collapse)(struct hist_entry *, struct hist_entry *); 81 int64_t (*collapse)(struct hist_entry *, struct hist_entry *);
@@ -577,7 +219,7 @@ static struct sort_entry sort_sym = {
577static int sort__need_collapse = 0; 219static int sort__need_collapse = 0;
578 220
579struct sort_dimension { 221struct sort_dimension {
580 char *name; 222 const char *name;
581 struct sort_entry *entry; 223 struct sort_entry *entry;
582 int taken; 224 int taken;
583}; 225};
@@ -830,17 +472,6 @@ static void output__resort(void)
830 } 472 }
831} 473}
832 474
833static void register_idle_thread(void)
834{
835 struct thread *thread = threads__findnew(0);
836
837 if (thread == NULL ||
838 thread__set_comm(thread, "[idle]")) {
839 fprintf(stderr, "problem inserting idle task.\n");
840 exit(-1);
841 }
842}
843
844static unsigned long total = 0, 475static unsigned long total = 0,
845 total_mmap = 0, 476 total_mmap = 0,
846 total_comm = 0, 477 total_comm = 0,
@@ -853,18 +484,20 @@ process_sample_event(event_t *event, unsigned long offset, unsigned long head)
853 char level; 484 char level;
854 int show = 0; 485 int show = 0;
855 struct dso *dso = NULL; 486 struct dso *dso = NULL;
856 struct thread *thread = threads__findnew(event->ip.pid); 487 struct thread *thread;
857 u64 ip = event->ip.ip; 488 u64 ip = event->ip.ip;
858 struct map *map = NULL; 489 struct map *map = NULL;
859 490
860 dprintf("%p [%p]: PERF_EVENT (IP, %d): %d: %p\n", 491 thread = threads__findnew(event->ip.pid, &threads, &last_match);
492
493 dump_printf("%p [%p]: PERF_EVENT (IP, %d): %d: %p\n",
861 (void *)(offset + head), 494 (void *)(offset + head),
862 (void *)(long)(event->header.size), 495 (void *)(long)(event->header.size),
863 event->header.misc, 496 event->header.misc,
864 event->ip.pid, 497 event->ip.pid,
865 (void *)(long)ip); 498 (void *)(long)ip);
866 499
867 dprintf(" ... thread: %s:%d\n", thread->comm, thread->pid); 500 dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid);
868 501
869 if (thread == NULL) { 502 if (thread == NULL) {
870 fprintf(stderr, "problem processing %d event, skipping it.\n", 503 fprintf(stderr, "problem processing %d event, skipping it.\n",
@@ -872,15 +505,15 @@ process_sample_event(event_t *event, unsigned long offset, unsigned long head)
872 return -1; 505 return -1;
873 } 506 }
874 507
875 if (event->header.misc & PERF_EVENT_MISC_KERNEL) { 508 if (event->header.misc & PERF_RECORD_MISC_KERNEL) {
876 show = SHOW_KERNEL; 509 show = SHOW_KERNEL;
877 level = 'k'; 510 level = 'k';
878 511
879 dso = kernel_dso; 512 dso = kernel_dso;
880 513
881 dprintf(" ...... dso: %s\n", dso->name); 514 dump_printf(" ...... dso: %s\n", dso->name);
882 515
883 } else if (event->header.misc & PERF_EVENT_MISC_USER) { 516 } else if (event->header.misc & PERF_RECORD_MISC_USER) {
884 517
885 show = SHOW_USER; 518 show = SHOW_USER;
886 level = '.'; 519 level = '.';
@@ -899,12 +532,12 @@ process_sample_event(event_t *event, unsigned long offset, unsigned long head)
899 if ((long long)ip < 0) 532 if ((long long)ip < 0)
900 dso = kernel_dso; 533 dso = kernel_dso;
901 } 534 }
902 dprintf(" ...... dso: %s\n", dso ? dso->name : "<not found>"); 535 dump_printf(" ...... dso: %s\n", dso ? dso->name : "<not found>");
903 536
904 } else { 537 } else {
905 show = SHOW_HV; 538 show = SHOW_HV;
906 level = 'H'; 539 level = 'H';
907 dprintf(" ...... dso: [hypervisor]\n"); 540 dump_printf(" ...... dso: [hypervisor]\n");
908 } 541 }
909 542
910 if (show & show_mask) { 543 if (show & show_mask) {
@@ -927,10 +560,12 @@ process_sample_event(event_t *event, unsigned long offset, unsigned long head)
927static int 560static int
928process_mmap_event(event_t *event, unsigned long offset, unsigned long head) 561process_mmap_event(event_t *event, unsigned long offset, unsigned long head)
929{ 562{
930 struct thread *thread = threads__findnew(event->mmap.pid); 563 struct thread *thread;
931 struct map *map = map__new(&event->mmap); 564 struct map *map = map__new(&event->mmap, NULL, 0);
565
566 thread = threads__findnew(event->mmap.pid, &threads, &last_match);
932 567
933 dprintf("%p [%p]: PERF_EVENT_MMAP %d: [%p(%p) @ %p]: %s\n", 568 dump_printf("%p [%p]: PERF_RECORD_MMAP %d: [%p(%p) @ %p]: %s\n",
934 (void *)(offset + head), 569 (void *)(offset + head),
935 (void *)(long)(event->header.size), 570 (void *)(long)(event->header.size),
936 event->mmap.pid, 571 event->mmap.pid,
@@ -940,7 +575,7 @@ process_mmap_event(event_t *event, unsigned long offset, unsigned long head)
940 event->mmap.filename); 575 event->mmap.filename);
941 576
942 if (thread == NULL || map == NULL) { 577 if (thread == NULL || map == NULL) {
943 dprintf("problem processing PERF_EVENT_MMAP, skipping event.\n"); 578 dump_printf("problem processing PERF_RECORD_MMAP, skipping event.\n");
944 return 0; 579 return 0;
945 } 580 }
946 581
@@ -953,16 +588,17 @@ process_mmap_event(event_t *event, unsigned long offset, unsigned long head)
953static int 588static int
954process_comm_event(event_t *event, unsigned long offset, unsigned long head) 589process_comm_event(event_t *event, unsigned long offset, unsigned long head)
955{ 590{
956 struct thread *thread = threads__findnew(event->comm.pid); 591 struct thread *thread;
957 592
958 dprintf("%p [%p]: PERF_EVENT_COMM: %s:%d\n", 593 thread = threads__findnew(event->comm.pid, &threads, &last_match);
594 dump_printf("%p [%p]: PERF_RECORD_COMM: %s:%d\n",
959 (void *)(offset + head), 595 (void *)(offset + head),
960 (void *)(long)(event->header.size), 596 (void *)(long)(event->header.size),
961 event->comm.comm, event->comm.pid); 597 event->comm.comm, event->comm.pid);
962 598
963 if (thread == NULL || 599 if (thread == NULL ||
964 thread__set_comm(thread, event->comm.comm)) { 600 thread__set_comm(thread, event->comm.comm)) {
965 dprintf("problem processing PERF_EVENT_COMM, skipping event.\n"); 601 dump_printf("problem processing PERF_RECORD_COMM, skipping event.\n");
966 return -1; 602 return -1;
967 } 603 }
968 total_comm++; 604 total_comm++;
@@ -973,10 +609,12 @@ process_comm_event(event_t *event, unsigned long offset, unsigned long head)
973static int 609static int
974process_fork_event(event_t *event, unsigned long offset, unsigned long head) 610process_fork_event(event_t *event, unsigned long offset, unsigned long head)
975{ 611{
976 struct thread *thread = threads__findnew(event->fork.pid); 612 struct thread *thread;
977 struct thread *parent = threads__findnew(event->fork.ppid); 613 struct thread *parent;
978 614
979 dprintf("%p [%p]: PERF_EVENT_FORK: %d:%d\n", 615 thread = threads__findnew(event->fork.pid, &threads, &last_match);
616 parent = threads__findnew(event->fork.ppid, &threads, &last_match);
617 dump_printf("%p [%p]: PERF_RECORD_FORK: %d:%d\n",
980 (void *)(offset + head), 618 (void *)(offset + head),
981 (void *)(long)(event->header.size), 619 (void *)(long)(event->header.size),
982 event->fork.pid, event->fork.ppid); 620 event->fork.pid, event->fork.ppid);
@@ -989,7 +627,7 @@ process_fork_event(event_t *event, unsigned long offset, unsigned long head)
989 return 0; 627 return 0;
990 628
991 if (!thread || !parent || thread__fork(thread, parent)) { 629 if (!thread || !parent || thread__fork(thread, parent)) {
992 dprintf("problem processing PERF_EVENT_FORK, skipping event.\n"); 630 dump_printf("problem processing PERF_RECORD_FORK, skipping event.\n");
993 return -1; 631 return -1;
994 } 632 }
995 total_fork++; 633 total_fork++;
@@ -1001,23 +639,23 @@ static int
1001process_event(event_t *event, unsigned long offset, unsigned long head) 639process_event(event_t *event, unsigned long offset, unsigned long head)
1002{ 640{
1003 switch (event->header.type) { 641 switch (event->header.type) {
1004 case PERF_EVENT_SAMPLE: 642 case PERF_RECORD_SAMPLE:
1005 return process_sample_event(event, offset, head); 643 return process_sample_event(event, offset, head);
1006 644
1007 case PERF_EVENT_MMAP: 645 case PERF_RECORD_MMAP:
1008 return process_mmap_event(event, offset, head); 646 return process_mmap_event(event, offset, head);
1009 647
1010 case PERF_EVENT_COMM: 648 case PERF_RECORD_COMM:
1011 return process_comm_event(event, offset, head); 649 return process_comm_event(event, offset, head);
1012 650
1013 case PERF_EVENT_FORK: 651 case PERF_RECORD_FORK:
1014 return process_fork_event(event, offset, head); 652 return process_fork_event(event, offset, head);
1015 /* 653 /*
1016 * We dont process them right now but they are fine: 654 * We dont process them right now but they are fine:
1017 */ 655 */
1018 656
1019 case PERF_EVENT_THROTTLE: 657 case PERF_RECORD_THROTTLE:
1020 case PERF_EVENT_UNTHROTTLE: 658 case PERF_RECORD_UNTHROTTLE:
1021 return 0; 659 return 0;
1022 660
1023 default: 661 default:
@@ -1075,7 +713,7 @@ parse_line(FILE *file, struct symbol *sym, u64 start, u64 len)
1075 const char *path = NULL; 713 const char *path = NULL;
1076 unsigned int hits = 0; 714 unsigned int hits = 0;
1077 double percent = 0.0; 715 double percent = 0.0;
1078 char *color; 716 const char *color;
1079 struct sym_ext *sym_ext = sym->priv; 717 struct sym_ext *sym_ext = sym->priv;
1080 718
1081 offset = line_ip - start; 719 offset = line_ip - start;
@@ -1157,7 +795,7 @@ static void free_source_line(struct symbol *sym, int len)
1157 795
1158/* Get the filename:line for the colored entries */ 796/* Get the filename:line for the colored entries */
1159static void 797static void
1160get_source_line(struct symbol *sym, u64 start, int len, char *filename) 798get_source_line(struct symbol *sym, u64 start, int len, const char *filename)
1161{ 799{
1162 int i; 800 int i;
1163 char cmd[PATH_MAX * 2]; 801 char cmd[PATH_MAX * 2];
@@ -1203,7 +841,7 @@ get_source_line(struct symbol *sym, u64 start, int len, char *filename)
1203 } 841 }
1204} 842}
1205 843
1206static void print_summary(char *filename) 844static void print_summary(const char *filename)
1207{ 845{
1208 struct sym_ext *sym_ext; 846 struct sym_ext *sym_ext;
1209 struct rb_node *node; 847 struct rb_node *node;
@@ -1219,7 +857,7 @@ static void print_summary(char *filename)
1219 node = rb_first(&root_sym_ext); 857 node = rb_first(&root_sym_ext);
1220 while (node) { 858 while (node) {
1221 double percent; 859 double percent;
1222 char *color; 860 const char *color;
1223 char *path; 861 char *path;
1224 862
1225 sym_ext = rb_entry(node, struct sym_ext, node); 863 sym_ext = rb_entry(node, struct sym_ext, node);
@@ -1234,7 +872,7 @@ static void print_summary(char *filename)
1234 872
1235static void annotate_sym(struct dso *dso, struct symbol *sym) 873static void annotate_sym(struct dso *dso, struct symbol *sym)
1236{ 874{
1237 char *filename = dso->name, *d_filename; 875 const char *filename = dso->name, *d_filename;
1238 u64 start, end, len; 876 u64 start, end, len;
1239 char command[PATH_MAX*2]; 877 char command[PATH_MAX*2];
1240 FILE *file; 878 FILE *file;
@@ -1244,7 +882,7 @@ static void annotate_sym(struct dso *dso, struct symbol *sym)
1244 if (sym->module) 882 if (sym->module)
1245 filename = sym->module->path; 883 filename = sym->module->path;
1246 else if (dso == kernel_dso) 884 else if (dso == kernel_dso)
1247 filename = vmlinux; 885 filename = vmlinux_name;
1248 886
1249 start = sym->obj_start; 887 start = sym->obj_start;
1250 if (!start) 888 if (!start)
@@ -1316,12 +954,12 @@ static int __cmd_annotate(void)
1316 int ret, rc = EXIT_FAILURE; 954 int ret, rc = EXIT_FAILURE;
1317 unsigned long offset = 0; 955 unsigned long offset = 0;
1318 unsigned long head = 0; 956 unsigned long head = 0;
1319 struct stat stat; 957 struct stat input_stat;
1320 event_t *event; 958 event_t *event;
1321 uint32_t size; 959 uint32_t size;
1322 char *buf; 960 char *buf;
1323 961
1324 register_idle_thread(); 962 register_idle_thread(&threads, &last_match);
1325 963
1326 input = open(input_name, O_RDONLY); 964 input = open(input_name, O_RDONLY);
1327 if (input < 0) { 965 if (input < 0) {
@@ -1329,18 +967,18 @@ static int __cmd_annotate(void)
1329 exit(-1); 967 exit(-1);
1330 } 968 }
1331 969
1332 ret = fstat(input, &stat); 970 ret = fstat(input, &input_stat);
1333 if (ret < 0) { 971 if (ret < 0) {
1334 perror("failed to stat file"); 972 perror("failed to stat file");
1335 exit(-1); 973 exit(-1);
1336 } 974 }
1337 975
1338 if (!force && (stat.st_uid != geteuid())) { 976 if (!force && input_stat.st_uid && (input_stat.st_uid != geteuid())) {
1339 fprintf(stderr, "file: %s not owned by current user\n", input_name); 977 fprintf(stderr, "file: %s not owned by current user or root\n", input_name);
1340 exit(-1); 978 exit(-1);
1341 } 979 }
1342 980
1343 if (!stat.st_size) { 981 if (!input_stat.st_size) {
1344 fprintf(stderr, "zero-sized file, nothing to do!\n"); 982 fprintf(stderr, "zero-sized file, nothing to do!\n");
1345 exit(0); 983 exit(0);
1346 } 984 }
@@ -1367,10 +1005,10 @@ more:
1367 1005
1368 if (head + event->header.size >= page_size * mmap_window) { 1006 if (head + event->header.size >= page_size * mmap_window) {
1369 unsigned long shift = page_size * (head / page_size); 1007 unsigned long shift = page_size * (head / page_size);
1370 int ret; 1008 int munmap_ret;
1371 1009
1372 ret = munmap(buf, page_size * mmap_window); 1010 munmap_ret = munmap(buf, page_size * mmap_window);
1373 assert(ret == 0); 1011 assert(munmap_ret == 0);
1374 1012
1375 offset += shift; 1013 offset += shift;
1376 head -= shift; 1014 head -= shift;
@@ -1379,14 +1017,14 @@ more:
1379 1017
1380 size = event->header.size; 1018 size = event->header.size;
1381 1019
1382 dprintf("%p [%p]: event: %d\n", 1020 dump_printf("%p [%p]: event: %d\n",
1383 (void *)(offset + head), 1021 (void *)(offset + head),
1384 (void *)(long)event->header.size, 1022 (void *)(long)event->header.size,
1385 event->header.type); 1023 event->header.type);
1386 1024
1387 if (!size || process_event(event, offset, head) < 0) { 1025 if (!size || process_event(event, offset, head) < 0) {
1388 1026
1389 dprintf("%p [%p]: skipping unknown header type: %d\n", 1027 dump_printf("%p [%p]: skipping unknown header type: %d\n",
1390 (void *)(offset + head), 1028 (void *)(offset + head),
1391 (void *)(long)(event->header.size), 1029 (void *)(long)(event->header.size),
1392 event->header.type); 1030 event->header.type);
@@ -1406,23 +1044,23 @@ more:
1406 1044
1407 head += size; 1045 head += size;
1408 1046
1409 if (offset + head < (unsigned long)stat.st_size) 1047 if (offset + head < (unsigned long)input_stat.st_size)
1410 goto more; 1048 goto more;
1411 1049
1412 rc = EXIT_SUCCESS; 1050 rc = EXIT_SUCCESS;
1413 close(input); 1051 close(input);
1414 1052
1415 dprintf(" IP events: %10ld\n", total); 1053 dump_printf(" IP events: %10ld\n", total);
1416 dprintf(" mmap events: %10ld\n", total_mmap); 1054 dump_printf(" mmap events: %10ld\n", total_mmap);
1417 dprintf(" comm events: %10ld\n", total_comm); 1055 dump_printf(" comm events: %10ld\n", total_comm);
1418 dprintf(" fork events: %10ld\n", total_fork); 1056 dump_printf(" fork events: %10ld\n", total_fork);
1419 dprintf(" unknown events: %10ld\n", total_unknown); 1057 dump_printf(" unknown events: %10ld\n", total_unknown);
1420 1058
1421 if (dump_trace) 1059 if (dump_trace)
1422 return 0; 1060 return 0;
1423 1061
1424 if (verbose >= 3) 1062 if (verbose >= 3)
1425 threads__fprintf(stdout); 1063 threads__fprintf(stdout, &threads);
1426 1064
1427 if (verbose >= 2) 1065 if (verbose >= 2)
1428 dsos__fprintf(stdout); 1066 dsos__fprintf(stdout);
@@ -1450,7 +1088,7 @@ static const struct option options[] = {
1450 "be more verbose (show symbol address, etc)"), 1088 "be more verbose (show symbol address, etc)"),
1451 OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace, 1089 OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace,
1452 "dump raw trace in ASCII"), 1090 "dump raw trace in ASCII"),
1453 OPT_STRING('k', "vmlinux", &vmlinux, "file", "vmlinux pathname"), 1091 OPT_STRING('k', "vmlinux", &vmlinux_name, "file", "vmlinux pathname"),
1454 OPT_BOOLEAN('m', "modules", &modules, 1092 OPT_BOOLEAN('m', "modules", &modules,
1455 "load module symbols - WARNING: use only with -k and LIVE kernel"), 1093 "load module symbols - WARNING: use only with -k and LIVE kernel"),
1456 OPT_BOOLEAN('l', "print-line", &print_line, 1094 OPT_BOOLEAN('l', "print-line", &print_line,
diff --git a/tools/perf/builtin-help.c b/tools/perf/builtin-help.c
index 2599d86a733b..4fb8734a796e 100644
--- a/tools/perf/builtin-help.c
+++ b/tools/perf/builtin-help.c
@@ -456,6 +456,7 @@ int cmd_help(int argc, const char **argv, const char *prefix __used)
456 break; 456 break;
457 case HELP_FORMAT_WEB: 457 case HELP_FORMAT_WEB:
458 show_html_page(argv[0]); 458 show_html_page(argv[0]);
459 default:
459 break; 460 break;
460 } 461 }
461 462
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index 89a5ddcd1ded..a5a050af8e7d 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -15,6 +15,9 @@
15#include "util/string.h" 15#include "util/string.h"
16 16
17#include "util/header.h" 17#include "util/header.h"
18#include "util/event.h"
19#include "util/debug.h"
20#include "util/trace-event.h"
18 21
19#include <unistd.h> 22#include <unistd.h>
20#include <sched.h> 23#include <sched.h>
@@ -42,10 +45,11 @@ static int inherit = 1;
42static int force = 0; 45static int force = 0;
43static int append_file = 0; 46static int append_file = 0;
44static int call_graph = 0; 47static int call_graph = 0;
45static int verbose = 0;
46static int inherit_stat = 0; 48static int inherit_stat = 0;
47static int no_samples = 0; 49static int no_samples = 0;
48static int sample_address = 0; 50static int sample_address = 0;
51static int multiplex = 0;
52static int multiplex_fd = -1;
49 53
50static long samples; 54static long samples;
51static struct timeval last_read; 55static struct timeval last_read;
@@ -62,24 +66,6 @@ static int file_new = 1;
62 66
63struct perf_header *header; 67struct perf_header *header;
64 68
65struct mmap_event {
66 struct perf_event_header header;
67 u32 pid;
68 u32 tid;
69 u64 start;
70 u64 len;
71 u64 pgoff;
72 char filename[PATH_MAX];
73};
74
75struct comm_event {
76 struct perf_event_header header;
77 u32 pid;
78 u32 tid;
79 char comm[16];
80};
81
82
83struct mmap_data { 69struct mmap_data {
84 int counter; 70 int counter;
85 void *base; 71 void *base;
@@ -91,7 +77,7 @@ static struct mmap_data mmap_array[MAX_NR_CPUS][MAX_COUNTERS];
91 77
92static unsigned long mmap_read_head(struct mmap_data *md) 78static unsigned long mmap_read_head(struct mmap_data *md)
93{ 79{
94 struct perf_counter_mmap_page *pc = md->base; 80 struct perf_event_mmap_page *pc = md->base;
95 long head; 81 long head;
96 82
97 head = pc->data_head; 83 head = pc->data_head;
@@ -102,7 +88,7 @@ static unsigned long mmap_read_head(struct mmap_data *md)
102 88
103static void mmap_write_tail(struct mmap_data *md, unsigned long tail) 89static void mmap_write_tail(struct mmap_data *md, unsigned long tail)
104{ 90{
105 struct perf_counter_mmap_page *pc = md->base; 91 struct perf_event_mmap_page *pc = md->base;
106 92
107 /* 93 /*
108 * ensure all reads are done before we write the tail out. 94 * ensure all reads are done before we write the tail out.
@@ -247,7 +233,7 @@ static pid_t pid_synthesize_comm_event(pid_t pid, int full)
247 } 233 }
248 } 234 }
249 235
250 comm_ev.header.type = PERF_EVENT_COMM; 236 comm_ev.header.type = PERF_RECORD_COMM;
251 size = ALIGN(size, sizeof(u64)); 237 size = ALIGN(size, sizeof(u64));
252 comm_ev.header.size = sizeof(comm_ev) - (sizeof(comm_ev.comm) - size); 238 comm_ev.header.size = sizeof(comm_ev) - (sizeof(comm_ev.comm) - size);
253 239
@@ -302,7 +288,7 @@ static void pid_synthesize_mmap_samples(pid_t pid, pid_t tgid)
302 while (1) { 288 while (1) {
303 char bf[BUFSIZ], *pbf = bf; 289 char bf[BUFSIZ], *pbf = bf;
304 struct mmap_event mmap_ev = { 290 struct mmap_event mmap_ev = {
305 .header = { .type = PERF_EVENT_MMAP }, 291 .header = { .type = PERF_RECORD_MMAP },
306 }; 292 };
307 int n; 293 int n;
308 size_t size; 294 size_t size;
@@ -369,7 +355,7 @@ static void synthesize_all(void)
369 355
370static int group_fd; 356static int group_fd;
371 357
372static struct perf_header_attr *get_header_attr(struct perf_counter_attr *a, int nr) 358static struct perf_header_attr *get_header_attr(struct perf_event_attr *a, int nr)
373{ 359{
374 struct perf_header_attr *h_attr; 360 struct perf_header_attr *h_attr;
375 361
@@ -385,7 +371,7 @@ static struct perf_header_attr *get_header_attr(struct perf_counter_attr *a, int
385 371
386static void create_counter(int counter, int cpu, pid_t pid) 372static void create_counter(int counter, int cpu, pid_t pid)
387{ 373{
388 struct perf_counter_attr *attr = attrs + counter; 374 struct perf_event_attr *attr = attrs + counter;
389 struct perf_header_attr *h_attr; 375 struct perf_header_attr *h_attr;
390 int track = !counter; /* only the first counter needs these */ 376 int track = !counter; /* only the first counter needs these */
391 struct { 377 struct {
@@ -419,8 +405,11 @@ static void create_counter(int counter, int cpu, pid_t pid)
419 if (call_graph) 405 if (call_graph)
420 attr->sample_type |= PERF_SAMPLE_CALLCHAIN; 406 attr->sample_type |= PERF_SAMPLE_CALLCHAIN;
421 407
422 if (raw_samples) 408 if (raw_samples) {
409 attr->sample_type |= PERF_SAMPLE_TIME;
423 attr->sample_type |= PERF_SAMPLE_RAW; 410 attr->sample_type |= PERF_SAMPLE_RAW;
411 attr->sample_type |= PERF_SAMPLE_CPU;
412 }
424 413
425 attr->mmap = track; 414 attr->mmap = track;
426 attr->comm = track; 415 attr->comm = track;
@@ -428,7 +417,7 @@ static void create_counter(int counter, int cpu, pid_t pid)
428 attr->disabled = 1; 417 attr->disabled = 1;
429 418
430try_again: 419try_again:
431 fd[nr_cpu][counter] = sys_perf_counter_open(attr, pid, cpu, group_fd, 0); 420 fd[nr_cpu][counter] = sys_perf_event_open(attr, pid, cpu, group_fd, 0);
432 421
433 if (fd[nr_cpu][counter] < 0) { 422 if (fd[nr_cpu][counter] < 0) {
434 int err = errno; 423 int err = errno;
@@ -455,7 +444,7 @@ try_again:
455 printf("\n"); 444 printf("\n");
456 error("perfcounter syscall returned with %d (%s)\n", 445 error("perfcounter syscall returned with %d (%s)\n",
457 fd[nr_cpu][counter], strerror(err)); 446 fd[nr_cpu][counter], strerror(err));
458 die("No CONFIG_PERF_COUNTERS=y kernel support configured?\n"); 447 die("No CONFIG_PERF_EVENTS=y kernel support configured?\n");
459 exit(-1); 448 exit(-1);
460 } 449 }
461 450
@@ -483,22 +472,31 @@ try_again:
483 */ 472 */
484 if (group && group_fd == -1) 473 if (group && group_fd == -1)
485 group_fd = fd[nr_cpu][counter]; 474 group_fd = fd[nr_cpu][counter];
475 if (multiplex && multiplex_fd == -1)
476 multiplex_fd = fd[nr_cpu][counter];
486 477
487 event_array[nr_poll].fd = fd[nr_cpu][counter]; 478 if (multiplex && fd[nr_cpu][counter] != multiplex_fd) {
488 event_array[nr_poll].events = POLLIN; 479 int ret;
489 nr_poll++; 480
490 481 ret = ioctl(fd[nr_cpu][counter], PERF_EVENT_IOC_SET_OUTPUT, multiplex_fd);
491 mmap_array[nr_cpu][counter].counter = counter; 482 assert(ret != -1);
492 mmap_array[nr_cpu][counter].prev = 0; 483 } else {
493 mmap_array[nr_cpu][counter].mask = mmap_pages*page_size - 1; 484 event_array[nr_poll].fd = fd[nr_cpu][counter];
494 mmap_array[nr_cpu][counter].base = mmap(NULL, (mmap_pages+1)*page_size, 485 event_array[nr_poll].events = POLLIN;
495 PROT_READ|PROT_WRITE, MAP_SHARED, fd[nr_cpu][counter], 0); 486 nr_poll++;
496 if (mmap_array[nr_cpu][counter].base == MAP_FAILED) { 487
497 error("failed to mmap with %d (%s)\n", errno, strerror(errno)); 488 mmap_array[nr_cpu][counter].counter = counter;
498 exit(-1); 489 mmap_array[nr_cpu][counter].prev = 0;
490 mmap_array[nr_cpu][counter].mask = mmap_pages*page_size - 1;
491 mmap_array[nr_cpu][counter].base = mmap(NULL, (mmap_pages+1)*page_size,
492 PROT_READ|PROT_WRITE, MAP_SHARED, fd[nr_cpu][counter], 0);
493 if (mmap_array[nr_cpu][counter].base == MAP_FAILED) {
494 error("failed to mmap with %d (%s)\n", errno, strerror(errno));
495 exit(-1);
496 }
499 } 497 }
500 498
501 ioctl(fd[nr_cpu][counter], PERF_COUNTER_IOC_ENABLE); 499 ioctl(fd[nr_cpu][counter], PERF_EVENT_IOC_ENABLE);
502} 500}
503 501
504static void open_counters(int cpu, pid_t pid) 502static void open_counters(int cpu, pid_t pid)
@@ -526,6 +524,7 @@ static int __cmd_record(int argc, const char **argv)
526 pid_t pid = 0; 524 pid_t pid = 0;
527 int flags; 525 int flags;
528 int ret; 526 int ret;
527 unsigned long waking = 0;
529 528
530 page_size = sysconf(_SC_PAGE_SIZE); 529 page_size = sysconf(_SC_PAGE_SIZE);
531 nr_cpus = sysconf(_SC_NPROCESSORS_ONLN); 530 nr_cpus = sysconf(_SC_NPROCESSORS_ONLN);
@@ -563,6 +562,17 @@ static int __cmd_record(int argc, const char **argv)
563 else 562 else
564 header = perf_header__new(); 563 header = perf_header__new();
565 564
565
566 if (raw_samples) {
567 read_tracing_data(attrs, nr_counters);
568 } else {
569 for (i = 0; i < nr_counters; i++) {
570 if (attrs[i].sample_type & PERF_SAMPLE_RAW) {
571 read_tracing_data(attrs, nr_counters);
572 break;
573 }
574 }
575 }
566 atexit(atexit_header); 576 atexit(atexit_header);
567 577
568 if (!system_wide) { 578 if (!system_wide) {
@@ -616,17 +626,29 @@ static int __cmd_record(int argc, const char **argv)
616 int hits = samples; 626 int hits = samples;
617 627
618 for (i = 0; i < nr_cpu; i++) { 628 for (i = 0; i < nr_cpu; i++) {
619 for (counter = 0; counter < nr_counters; counter++) 629 for (counter = 0; counter < nr_counters; counter++) {
620 mmap_read(&mmap_array[i][counter]); 630 if (mmap_array[i][counter].base)
631 mmap_read(&mmap_array[i][counter]);
632 }
621 } 633 }
622 634
623 if (hits == samples) { 635 if (hits == samples) {
624 if (done) 636 if (done)
625 break; 637 break;
626 ret = poll(event_array, nr_poll, 100); 638 ret = poll(event_array, nr_poll, -1);
639 waking++;
640 }
641
642 if (done) {
643 for (i = 0; i < nr_cpu; i++) {
644 for (counter = 0; counter < nr_counters; counter++)
645 ioctl(fd[i][counter], PERF_EVENT_IOC_DISABLE);
646 }
627 } 647 }
628 } 648 }
629 649
650 fprintf(stderr, "[ perf record: Woken up %ld times to write data ]\n", waking);
651
630 /* 652 /*
631 * Approximate RIP event size: 24 bytes. 653 * Approximate RIP event size: 24 bytes.
632 */ 654 */
@@ -683,6 +705,8 @@ static const struct option options[] = {
683 "Sample addresses"), 705 "Sample addresses"),
684 OPT_BOOLEAN('n', "no-samples", &no_samples, 706 OPT_BOOLEAN('n', "no-samples", &no_samples,
685 "don't sample"), 707 "don't sample"),
708 OPT_BOOLEAN('M', "multiplex", &multiplex,
709 "multiplex counter output in a single channel"),
686 OPT_END() 710 OPT_END()
687}; 711};
688 712
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
index 8b2ec882e6e0..19669c20088e 100644
--- a/tools/perf/builtin-report.c
+++ b/tools/perf/builtin-report.c
@@ -17,19 +17,18 @@
17#include "util/string.h" 17#include "util/string.h"
18#include "util/callchain.h" 18#include "util/callchain.h"
19#include "util/strlist.h" 19#include "util/strlist.h"
20#include "util/values.h"
20 21
21#include "perf.h" 22#include "perf.h"
23#include "util/debug.h"
22#include "util/header.h" 24#include "util/header.h"
23 25
24#include "util/parse-options.h" 26#include "util/parse-options.h"
25#include "util/parse-events.h" 27#include "util/parse-events.h"
26 28
27#define SHOW_KERNEL 1 29#include "util/thread.h"
28#define SHOW_USER 2
29#define SHOW_HV 4
30 30
31static char const *input_name = "perf.data"; 31static char const *input_name = "perf.data";
32static char *vmlinux = NULL;
33 32
34static char default_sort_order[] = "comm,dso,symbol"; 33static char default_sort_order[] = "comm,dso,symbol";
35static char *sort_order = default_sort_order; 34static char *sort_order = default_sort_order;
@@ -42,18 +41,15 @@ static int force;
42static int input; 41static int input;
43static int show_mask = SHOW_KERNEL | SHOW_USER | SHOW_HV; 42static int show_mask = SHOW_KERNEL | SHOW_USER | SHOW_HV;
44 43
45static int dump_trace = 0;
46#define dprintf(x...) do { if (dump_trace) printf(x); } while (0)
47#define cdprintf(x...) do { if (dump_trace) color_fprintf(stdout, color, x); } while (0)
48
49static int verbose;
50#define eprintf(x...) do { if (verbose) fprintf(stderr, x); } while (0)
51
52static int modules;
53
54static int full_paths; 44static int full_paths;
55static int show_nr_samples; 45static int show_nr_samples;
56 46
47static int show_threads;
48static struct perf_read_values show_threads_values;
49
50static char default_pretty_printing_style[] = "normal";
51static char *pretty_printing_style = default_pretty_printing_style;
52
57static unsigned long page_size; 53static unsigned long page_size;
58static unsigned long mmap_window = 32; 54static unsigned long mmap_window = 32;
59 55
@@ -67,6 +63,15 @@ static char callchain_default_opt[] = "fractal,0.5";
67 63
68static int callchain; 64static int callchain;
69 65
66static char __cwd[PATH_MAX];
67static char *cwd = __cwd;
68static int cwdlen;
69
70static struct rb_root threads;
71static struct thread *last_match;
72
73static struct perf_header *header;
74
70static 75static
71struct callchain_param callchain_param = { 76struct callchain_param callchain_param = {
72 .mode = CHAIN_GRAPH_REL, 77 .mode = CHAIN_GRAPH_REL,
@@ -75,59 +80,6 @@ struct callchain_param callchain_param = {
75 80
76static u64 sample_type; 81static u64 sample_type;
77 82
78struct ip_event {
79 struct perf_event_header header;
80 u64 ip;
81 u32 pid, tid;
82 unsigned char __more_data[];
83};
84
85struct mmap_event {
86 struct perf_event_header header;
87 u32 pid, tid;
88 u64 start;
89 u64 len;
90 u64 pgoff;
91 char filename[PATH_MAX];
92};
93
94struct comm_event {
95 struct perf_event_header header;
96 u32 pid, tid;
97 char comm[16];
98};
99
100struct fork_event {
101 struct perf_event_header header;
102 u32 pid, ppid;
103 u32 tid, ptid;
104};
105
106struct lost_event {
107 struct perf_event_header header;
108 u64 id;
109 u64 lost;
110};
111
112struct read_event {
113 struct perf_event_header header;
114 u32 pid,tid;
115 u64 value;
116 u64 time_enabled;
117 u64 time_running;
118 u64 id;
119};
120
121typedef union event_union {
122 struct perf_event_header header;
123 struct ip_event ip;
124 struct mmap_event mmap;
125 struct comm_event comm;
126 struct fork_event fork;
127 struct lost_event lost;
128 struct read_event read;
129} event_t;
130
131static int repsep_fprintf(FILE *fp, const char *fmt, ...) 83static int repsep_fprintf(FILE *fp, const char *fmt, ...)
132{ 84{
133 int n; 85 int n;
@@ -141,6 +93,7 @@ static int repsep_fprintf(FILE *fp, const char *fmt, ...)
141 n = vasprintf(&bf, fmt, ap); 93 n = vasprintf(&bf, fmt, ap);
142 if (n > 0) { 94 if (n > 0) {
143 char *sep = bf; 95 char *sep = bf;
96
144 while (1) { 97 while (1) {
145 sep = strchr(sep, *field_sep); 98 sep = strchr(sep, *field_sep);
146 if (sep == NULL) 99 if (sep == NULL)
@@ -155,396 +108,10 @@ static int repsep_fprintf(FILE *fp, const char *fmt, ...)
155 return n; 108 return n;
156} 109}
157 110
158static LIST_HEAD(dsos);
159static struct dso *kernel_dso;
160static struct dso *vdso;
161static struct dso *hypervisor_dso;
162
163static void dsos__add(struct dso *dso)
164{
165 list_add_tail(&dso->node, &dsos);
166}
167
168static struct dso *dsos__find(const char *name)
169{
170 struct dso *pos;
171
172 list_for_each_entry(pos, &dsos, node)
173 if (strcmp(pos->name, name) == 0)
174 return pos;
175 return NULL;
176}
177
178static struct dso *dsos__findnew(const char *name)
179{
180 struct dso *dso = dsos__find(name);
181 int nr;
182
183 if (dso)
184 return dso;
185
186 dso = dso__new(name, 0);
187 if (!dso)
188 goto out_delete_dso;
189
190 nr = dso__load(dso, NULL, verbose);
191 if (nr < 0) {
192 eprintf("Failed to open: %s\n", name);
193 goto out_delete_dso;
194 }
195 if (!nr)
196 eprintf("No symbols found in: %s, maybe install a debug package?\n", name);
197
198 dsos__add(dso);
199
200 return dso;
201
202out_delete_dso:
203 dso__delete(dso);
204 return NULL;
205}
206
207static void dsos__fprintf(FILE *fp)
208{
209 struct dso *pos;
210
211 list_for_each_entry(pos, &dsos, node)
212 dso__fprintf(pos, fp);
213}
214
215static struct symbol *vdso__find_symbol(struct dso *dso, u64 ip)
216{
217 return dso__find_symbol(dso, ip);
218}
219
220static int load_kernel(void)
221{
222 int err;
223
224 kernel_dso = dso__new("[kernel]", 0);
225 if (!kernel_dso)
226 return -1;
227
228 err = dso__load_kernel(kernel_dso, vmlinux, NULL, verbose, modules);
229 if (err <= 0) {
230 dso__delete(kernel_dso);
231 kernel_dso = NULL;
232 } else
233 dsos__add(kernel_dso);
234
235 vdso = dso__new("[vdso]", 0);
236 if (!vdso)
237 return -1;
238
239 vdso->find_symbol = vdso__find_symbol;
240
241 dsos__add(vdso);
242
243 hypervisor_dso = dso__new("[hypervisor]", 0);
244 if (!hypervisor_dso)
245 return -1;
246 dsos__add(hypervisor_dso);
247
248 return err;
249}
250
251static char __cwd[PATH_MAX];
252static char *cwd = __cwd;
253static int cwdlen;
254
255static int strcommon(const char *pathname)
256{
257 int n = 0;
258
259 while (n < cwdlen && pathname[n] == cwd[n])
260 ++n;
261
262 return n;
263}
264
265struct map {
266 struct list_head node;
267 u64 start;
268 u64 end;
269 u64 pgoff;
270 u64 (*map_ip)(struct map *, u64);
271 struct dso *dso;
272};
273
274static u64 map__map_ip(struct map *map, u64 ip)
275{
276 return ip - map->start + map->pgoff;
277}
278
279static u64 vdso__map_ip(struct map *map __used, u64 ip)
280{
281 return ip;
282}
283
284static inline int is_anon_memory(const char *filename)
285{
286 return strcmp(filename, "//anon") == 0;
287}
288
289static struct map *map__new(struct mmap_event *event)
290{
291 struct map *self = malloc(sizeof(*self));
292
293 if (self != NULL) {
294 const char *filename = event->filename;
295 char newfilename[PATH_MAX];
296 int anon;
297
298 if (cwd) {
299 int n = strcommon(filename);
300
301 if (n == cwdlen) {
302 snprintf(newfilename, sizeof(newfilename),
303 ".%s", filename + n);
304 filename = newfilename;
305 }
306 }
307
308 anon = is_anon_memory(filename);
309
310 if (anon) {
311 snprintf(newfilename, sizeof(newfilename), "/tmp/perf-%d.map", event->pid);
312 filename = newfilename;
313 }
314
315 self->start = event->start;
316 self->end = event->start + event->len;
317 self->pgoff = event->pgoff;
318
319 self->dso = dsos__findnew(filename);
320 if (self->dso == NULL)
321 goto out_delete;
322
323 if (self->dso == vdso || anon)
324 self->map_ip = vdso__map_ip;
325 else
326 self->map_ip = map__map_ip;
327 }
328 return self;
329out_delete:
330 free(self);
331 return NULL;
332}
333
334static struct map *map__clone(struct map *self)
335{
336 struct map *map = malloc(sizeof(*self));
337
338 if (!map)
339 return NULL;
340
341 memcpy(map, self, sizeof(*self));
342
343 return map;
344}
345
346static int map__overlap(struct map *l, struct map *r)
347{
348 if (l->start > r->start) {
349 struct map *t = l;
350 l = r;
351 r = t;
352 }
353
354 if (l->end > r->start)
355 return 1;
356
357 return 0;
358}
359
360static size_t map__fprintf(struct map *self, FILE *fp)
361{
362 return fprintf(fp, " %Lx-%Lx %Lx %s\n",
363 self->start, self->end, self->pgoff, self->dso->name);
364}
365
366
367struct thread {
368 struct rb_node rb_node;
369 struct list_head maps;
370 pid_t pid;
371 char *comm;
372};
373
374static struct thread *thread__new(pid_t pid)
375{
376 struct thread *self = malloc(sizeof(*self));
377
378 if (self != NULL) {
379 self->pid = pid;
380 self->comm = malloc(32);
381 if (self->comm)
382 snprintf(self->comm, 32, ":%d", self->pid);
383 INIT_LIST_HEAD(&self->maps);
384 }
385
386 return self;
387}
388
389static unsigned int dsos__col_width, 111static unsigned int dsos__col_width,
390 comms__col_width, 112 comms__col_width,
391 threads__col_width; 113 threads__col_width;
392 114
393static int thread__set_comm(struct thread *self, const char *comm)
394{
395 if (self->comm)
396 free(self->comm);
397 self->comm = strdup(comm);
398 if (!self->comm)
399 return -ENOMEM;
400
401 if (!col_width_list_str && !field_sep &&
402 (!comm_list || strlist__has_entry(comm_list, comm))) {
403 unsigned int slen = strlen(comm);
404 if (slen > comms__col_width) {
405 comms__col_width = slen;
406 threads__col_width = slen + 6;
407 }
408 }
409
410 return 0;
411}
412
413static size_t thread__fprintf(struct thread *self, FILE *fp)
414{
415 struct map *pos;
416 size_t ret = fprintf(fp, "Thread %d %s\n", self->pid, self->comm);
417
418 list_for_each_entry(pos, &self->maps, node)
419 ret += map__fprintf(pos, fp);
420
421 return ret;
422}
423
424
425static struct rb_root threads;
426static struct thread *last_match;
427
428static struct thread *threads__findnew(pid_t pid)
429{
430 struct rb_node **p = &threads.rb_node;
431 struct rb_node *parent = NULL;
432 struct thread *th;
433
434 /*
435 * Font-end cache - PID lookups come in blocks,
436 * so most of the time we dont have to look up
437 * the full rbtree:
438 */
439 if (last_match && last_match->pid == pid)
440 return last_match;
441
442 while (*p != NULL) {
443 parent = *p;
444 th = rb_entry(parent, struct thread, rb_node);
445
446 if (th->pid == pid) {
447 last_match = th;
448 return th;
449 }
450
451 if (pid < th->pid)
452 p = &(*p)->rb_left;
453 else
454 p = &(*p)->rb_right;
455 }
456
457 th = thread__new(pid);
458 if (th != NULL) {
459 rb_link_node(&th->rb_node, parent, p);
460 rb_insert_color(&th->rb_node, &threads);
461 last_match = th;
462 }
463
464 return th;
465}
466
467static void thread__insert_map(struct thread *self, struct map *map)
468{
469 struct map *pos, *tmp;
470
471 list_for_each_entry_safe(pos, tmp, &self->maps, node) {
472 if (map__overlap(pos, map)) {
473 if (verbose >= 2) {
474 printf("overlapping maps:\n");
475 map__fprintf(map, stdout);
476 map__fprintf(pos, stdout);
477 }
478
479 if (map->start <= pos->start && map->end > pos->start)
480 pos->start = map->end;
481
482 if (map->end >= pos->end && map->start < pos->end)
483 pos->end = map->start;
484
485 if (verbose >= 2) {
486 printf("after collision:\n");
487 map__fprintf(pos, stdout);
488 }
489
490 if (pos->start >= pos->end) {
491 list_del_init(&pos->node);
492 free(pos);
493 }
494 }
495 }
496
497 list_add_tail(&map->node, &self->maps);
498}
499
500static int thread__fork(struct thread *self, struct thread *parent)
501{
502 struct map *map;
503
504 if (self->comm)
505 free(self->comm);
506 self->comm = strdup(parent->comm);
507 if (!self->comm)
508 return -ENOMEM;
509
510 list_for_each_entry(map, &parent->maps, node) {
511 struct map *new = map__clone(map);
512 if (!new)
513 return -ENOMEM;
514 thread__insert_map(self, new);
515 }
516
517 return 0;
518}
519
520static struct map *thread__find_map(struct thread *self, u64 ip)
521{
522 struct map *pos;
523
524 if (self == NULL)
525 return NULL;
526
527 list_for_each_entry(pos, &self->maps, node)
528 if (ip >= pos->start && ip <= pos->end)
529 return pos;
530
531 return NULL;
532}
533
534static size_t threads__fprintf(FILE *fp)
535{
536 size_t ret = 0;
537 struct rb_node *nd;
538
539 for (nd = rb_first(&threads); nd; nd = rb_next(nd)) {
540 struct thread *pos = rb_entry(nd, struct thread, rb_node);
541
542 ret += thread__fprintf(pos, fp);
543 }
544
545 return ret;
546}
547
548/* 115/*
549 * histogram, sorted on item, collects counts 116 * histogram, sorted on item, collects counts
550 */ 117 */
@@ -574,7 +141,7 @@ struct hist_entry {
574struct sort_entry { 141struct sort_entry {
575 struct list_head list; 142 struct list_head list;
576 143
577 char *header; 144 const char *header;
578 145
579 int64_t (*cmp)(struct hist_entry *, struct hist_entry *); 146 int64_t (*cmp)(struct hist_entry *, struct hist_entry *);
580 int64_t (*collapse)(struct hist_entry *, struct hist_entry *); 147 int64_t (*collapse)(struct hist_entry *, struct hist_entry *);
@@ -758,7 +325,7 @@ static int sort__need_collapse = 0;
758static int sort__has_parent = 0; 325static int sort__has_parent = 0;
759 326
760struct sort_dimension { 327struct sort_dimension {
761 char *name; 328 const char *name;
762 struct sort_entry *entry; 329 struct sort_entry *entry;
763 int taken; 330 int taken;
764}; 331};
@@ -773,7 +340,7 @@ static struct sort_dimension sort_dimensions[] = {
773 340
774static LIST_HEAD(hist_entry__sort_list); 341static LIST_HEAD(hist_entry__sort_list);
775 342
776static int sort_dimension__add(char *tok) 343static int sort_dimension__add(const char *tok)
777{ 344{
778 unsigned int i; 345 unsigned int i;
779 346
@@ -1032,6 +599,7 @@ hist_entry_callchain__fprintf(FILE *fp, struct hist_entry *self,
1032 case CHAIN_GRAPH_REL: 599 case CHAIN_GRAPH_REL:
1033 ret += callchain__fprintf_graph(fp, chain, 600 ret += callchain__fprintf_graph(fp, chain,
1034 total_samples, 1, 1); 601 total_samples, 1, 1);
602 case CHAIN_NONE:
1035 default: 603 default:
1036 break; 604 break;
1037 } 605 }
@@ -1098,6 +666,34 @@ static void dso__calc_col_width(struct dso *self)
1098 self->slen_calculated = 1; 666 self->slen_calculated = 1;
1099} 667}
1100 668
669static void thread__comm_adjust(struct thread *self)
670{
671 char *comm = self->comm;
672
673 if (!col_width_list_str && !field_sep &&
674 (!comm_list || strlist__has_entry(comm_list, comm))) {
675 unsigned int slen = strlen(comm);
676
677 if (slen > comms__col_width) {
678 comms__col_width = slen;
679 threads__col_width = slen + 6;
680 }
681 }
682}
683
684static int thread__set_comm_adjust(struct thread *self, const char *comm)
685{
686 int ret = thread__set_comm(self, comm);
687
688 if (ret)
689 return ret;
690
691 thread__comm_adjust(self);
692
693 return 0;
694}
695
696
1101static struct symbol * 697static struct symbol *
1102resolve_symbol(struct thread *thread, struct map **mapp, 698resolve_symbol(struct thread *thread, struct map **mapp,
1103 struct dso **dsop, u64 *ipp) 699 struct dso **dsop, u64 *ipp)
@@ -1141,8 +737,8 @@ got_map:
1141 if ((long long)ip < 0) 737 if ((long long)ip < 0)
1142 dso = kernel_dso; 738 dso = kernel_dso;
1143 } 739 }
1144 dprintf(" ...... dso: %s\n", dso ? dso->name : "<not found>"); 740 dump_printf(" ...... dso: %s\n", dso ? dso->name : "<not found>");
1145 dprintf(" ...... map: %Lx -> %Lx\n", *ipp, ip); 741 dump_printf(" ...... map: %Lx -> %Lx\n", *ipp, ip);
1146 *ipp = ip; 742 *ipp = ip;
1147 743
1148 if (dsop) 744 if (dsop)
@@ -1398,6 +994,9 @@ static size_t output__fprintf(FILE *fp, u64 total_samples)
1398 size_t ret = 0; 994 size_t ret = 0;
1399 unsigned int width; 995 unsigned int width;
1400 char *col_width = col_width_list_str; 996 char *col_width = col_width_list_str;
997 int raw_printing_style;
998
999 raw_printing_style = !strcmp(pretty_printing_style, "raw");
1401 1000
1402 init_rem_hits(); 1001 init_rem_hits();
1403 1002
@@ -1474,18 +1073,11 @@ print_entries:
1474 1073
1475 free(rem_sq_bracket); 1074 free(rem_sq_bracket);
1476 1075
1477 return ret; 1076 if (show_threads)
1478} 1077 perf_read_values_display(fp, &show_threads_values,
1078 raw_printing_style);
1479 1079
1480static void register_idle_thread(void) 1080 return ret;
1481{
1482 struct thread *thread = threads__findnew(0);
1483
1484 if (thread == NULL ||
1485 thread__set_comm(thread, "[idle]")) {
1486 fprintf(stderr, "problem inserting idle task.\n");
1487 exit(-1);
1488 }
1489} 1081}
1490 1082
1491static unsigned long total = 0, 1083static unsigned long total = 0,
@@ -1514,7 +1106,7 @@ process_sample_event(event_t *event, unsigned long offset, unsigned long head)
1514 char level; 1106 char level;
1515 int show = 0; 1107 int show = 0;
1516 struct dso *dso = NULL; 1108 struct dso *dso = NULL;
1517 struct thread *thread = threads__findnew(event->ip.pid); 1109 struct thread *thread;
1518 u64 ip = event->ip.ip; 1110 u64 ip = event->ip.ip;
1519 u64 period = 1; 1111 u64 period = 1;
1520 struct map *map = NULL; 1112 struct map *map = NULL;
@@ -1522,12 +1114,14 @@ process_sample_event(event_t *event, unsigned long offset, unsigned long head)
1522 struct ip_callchain *chain = NULL; 1114 struct ip_callchain *chain = NULL;
1523 int cpumode; 1115 int cpumode;
1524 1116
1117 thread = threads__findnew(event->ip.pid, &threads, &last_match);
1118
1525 if (sample_type & PERF_SAMPLE_PERIOD) { 1119 if (sample_type & PERF_SAMPLE_PERIOD) {
1526 period = *(u64 *)more_data; 1120 period = *(u64 *)more_data;
1527 more_data += sizeof(u64); 1121 more_data += sizeof(u64);
1528 } 1122 }
1529 1123
1530 dprintf("%p [%p]: PERF_EVENT_SAMPLE (IP, %d): %d/%d: %p period: %Ld\n", 1124 dump_printf("%p [%p]: PERF_RECORD_SAMPLE (IP, %d): %d/%d: %p period: %Ld\n",
1531 (void *)(offset + head), 1125 (void *)(offset + head),
1532 (void *)(long)(event->header.size), 1126 (void *)(long)(event->header.size),
1533 event->header.misc, 1127 event->header.misc,
@@ -1540,7 +1134,7 @@ process_sample_event(event_t *event, unsigned long offset, unsigned long head)
1540 1134
1541 chain = (void *)more_data; 1135 chain = (void *)more_data;
1542 1136
1543 dprintf("... chain: nr:%Lu\n", chain->nr); 1137 dump_printf("... chain: nr:%Lu\n", chain->nr);
1544 1138
1545 if (validate_chain(chain, event) < 0) { 1139 if (validate_chain(chain, event) < 0) {
1546 eprintf("call-chain problem with event, skipping it.\n"); 1140 eprintf("call-chain problem with event, skipping it.\n");
@@ -1549,11 +1143,11 @@ process_sample_event(event_t *event, unsigned long offset, unsigned long head)
1549 1143
1550 if (dump_trace) { 1144 if (dump_trace) {
1551 for (i = 0; i < chain->nr; i++) 1145 for (i = 0; i < chain->nr; i++)
1552 dprintf("..... %2d: %016Lx\n", i, chain->ips[i]); 1146 dump_printf("..... %2d: %016Lx\n", i, chain->ips[i]);
1553 } 1147 }
1554 } 1148 }
1555 1149
1556 dprintf(" ... thread: %s:%d\n", thread->comm, thread->pid); 1150 dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid);
1557 1151
1558 if (thread == NULL) { 1152 if (thread == NULL) {
1559 eprintf("problem processing %d event, skipping it.\n", 1153 eprintf("problem processing %d event, skipping it.\n",
@@ -1564,17 +1158,17 @@ process_sample_event(event_t *event, unsigned long offset, unsigned long head)
1564 if (comm_list && !strlist__has_entry(comm_list, thread->comm)) 1158 if (comm_list && !strlist__has_entry(comm_list, thread->comm))
1565 return 0; 1159 return 0;
1566 1160
1567 cpumode = event->header.misc & PERF_EVENT_MISC_CPUMODE_MASK; 1161 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
1568 1162
1569 if (cpumode == PERF_EVENT_MISC_KERNEL) { 1163 if (cpumode == PERF_RECORD_MISC_KERNEL) {
1570 show = SHOW_KERNEL; 1164 show = SHOW_KERNEL;
1571 level = 'k'; 1165 level = 'k';
1572 1166
1573 dso = kernel_dso; 1167 dso = kernel_dso;
1574 1168
1575 dprintf(" ...... dso: %s\n", dso->name); 1169 dump_printf(" ...... dso: %s\n", dso->name);
1576 1170
1577 } else if (cpumode == PERF_EVENT_MISC_USER) { 1171 } else if (cpumode == PERF_RECORD_MISC_USER) {
1578 1172
1579 show = SHOW_USER; 1173 show = SHOW_USER;
1580 level = '.'; 1174 level = '.';
@@ -1585,7 +1179,7 @@ process_sample_event(event_t *event, unsigned long offset, unsigned long head)
1585 1179
1586 dso = hypervisor_dso; 1180 dso = hypervisor_dso;
1587 1181
1588 dprintf(" ...... dso: [hypervisor]\n"); 1182 dump_printf(" ...... dso: [hypervisor]\n");
1589 } 1183 }
1590 1184
1591 if (show & show_mask) { 1185 if (show & show_mask) {
@@ -1611,10 +1205,12 @@ process_sample_event(event_t *event, unsigned long offset, unsigned long head)
1611static int 1205static int
1612process_mmap_event(event_t *event, unsigned long offset, unsigned long head) 1206process_mmap_event(event_t *event, unsigned long offset, unsigned long head)
1613{ 1207{
1614 struct thread *thread = threads__findnew(event->mmap.pid); 1208 struct thread *thread;
1615 struct map *map = map__new(&event->mmap); 1209 struct map *map = map__new(&event->mmap, cwd, cwdlen);
1616 1210
1617 dprintf("%p [%p]: PERF_EVENT_MMAP %d/%d: [%p(%p) @ %p]: %s\n", 1211 thread = threads__findnew(event->mmap.pid, &threads, &last_match);
1212
1213 dump_printf("%p [%p]: PERF_RECORD_MMAP %d/%d: [%p(%p) @ %p]: %s\n",
1618 (void *)(offset + head), 1214 (void *)(offset + head),
1619 (void *)(long)(event->header.size), 1215 (void *)(long)(event->header.size),
1620 event->mmap.pid, 1216 event->mmap.pid,
@@ -1625,7 +1221,7 @@ process_mmap_event(event_t *event, unsigned long offset, unsigned long head)
1625 event->mmap.filename); 1221 event->mmap.filename);
1626 1222
1627 if (thread == NULL || map == NULL) { 1223 if (thread == NULL || map == NULL) {
1628 dprintf("problem processing PERF_EVENT_MMAP, skipping event.\n"); 1224 dump_printf("problem processing PERF_RECORD_MMAP, skipping event.\n");
1629 return 0; 1225 return 0;
1630 } 1226 }
1631 1227
@@ -1638,16 +1234,18 @@ process_mmap_event(event_t *event, unsigned long offset, unsigned long head)
1638static int 1234static int
1639process_comm_event(event_t *event, unsigned long offset, unsigned long head) 1235process_comm_event(event_t *event, unsigned long offset, unsigned long head)
1640{ 1236{
1641 struct thread *thread = threads__findnew(event->comm.pid); 1237 struct thread *thread;
1238
1239 thread = threads__findnew(event->comm.pid, &threads, &last_match);
1642 1240
1643 dprintf("%p [%p]: PERF_EVENT_COMM: %s:%d\n", 1241 dump_printf("%p [%p]: PERF_RECORD_COMM: %s:%d\n",
1644 (void *)(offset + head), 1242 (void *)(offset + head),
1645 (void *)(long)(event->header.size), 1243 (void *)(long)(event->header.size),
1646 event->comm.comm, event->comm.pid); 1244 event->comm.comm, event->comm.pid);
1647 1245
1648 if (thread == NULL || 1246 if (thread == NULL ||
1649 thread__set_comm(thread, event->comm.comm)) { 1247 thread__set_comm_adjust(thread, event->comm.comm)) {
1650 dprintf("problem processing PERF_EVENT_COMM, skipping event.\n"); 1248 dump_printf("problem processing PERF_RECORD_COMM, skipping event.\n");
1651 return -1; 1249 return -1;
1652 } 1250 }
1653 total_comm++; 1251 total_comm++;
@@ -1658,13 +1256,16 @@ process_comm_event(event_t *event, unsigned long offset, unsigned long head)
1658static int 1256static int
1659process_task_event(event_t *event, unsigned long offset, unsigned long head) 1257process_task_event(event_t *event, unsigned long offset, unsigned long head)
1660{ 1258{
1661 struct thread *thread = threads__findnew(event->fork.pid); 1259 struct thread *thread;
1662 struct thread *parent = threads__findnew(event->fork.ppid); 1260 struct thread *parent;
1663 1261
1664 dprintf("%p [%p]: PERF_EVENT_%s: (%d:%d):(%d:%d)\n", 1262 thread = threads__findnew(event->fork.pid, &threads, &last_match);
1263 parent = threads__findnew(event->fork.ppid, &threads, &last_match);
1264
1265 dump_printf("%p [%p]: PERF_RECORD_%s: (%d:%d):(%d:%d)\n",
1665 (void *)(offset + head), 1266 (void *)(offset + head),
1666 (void *)(long)(event->header.size), 1267 (void *)(long)(event->header.size),
1667 event->header.type == PERF_EVENT_FORK ? "FORK" : "EXIT", 1268 event->header.type == PERF_RECORD_FORK ? "FORK" : "EXIT",
1668 event->fork.pid, event->fork.tid, 1269 event->fork.pid, event->fork.tid,
1669 event->fork.ppid, event->fork.ptid); 1270 event->fork.ppid, event->fork.ptid);
1670 1271
@@ -1675,11 +1276,11 @@ process_task_event(event_t *event, unsigned long offset, unsigned long head)
1675 if (thread == parent) 1276 if (thread == parent)
1676 return 0; 1277 return 0;
1677 1278
1678 if (event->header.type == PERF_EVENT_EXIT) 1279 if (event->header.type == PERF_RECORD_EXIT)
1679 return 0; 1280 return 0;
1680 1281
1681 if (!thread || !parent || thread__fork(thread, parent)) { 1282 if (!thread || !parent || thread__fork(thread, parent)) {
1682 dprintf("problem processing PERF_EVENT_FORK, skipping event.\n"); 1283 dump_printf("problem processing PERF_RECORD_FORK, skipping event.\n");
1683 return -1; 1284 return -1;
1684 } 1285 }
1685 total_fork++; 1286 total_fork++;
@@ -1690,7 +1291,7 @@ process_task_event(event_t *event, unsigned long offset, unsigned long head)
1690static int 1291static int
1691process_lost_event(event_t *event, unsigned long offset, unsigned long head) 1292process_lost_event(event_t *event, unsigned long offset, unsigned long head)
1692{ 1293{
1693 dprintf("%p [%p]: PERF_EVENT_LOST: id:%Ld: lost:%Ld\n", 1294 dump_printf("%p [%p]: PERF_RECORD_LOST: id:%Ld: lost:%Ld\n",
1694 (void *)(offset + head), 1295 (void *)(offset + head),
1695 (void *)(long)(event->header.size), 1296 (void *)(long)(event->header.size),
1696 event->lost.id, 1297 event->lost.id,
@@ -1701,67 +1302,24 @@ process_lost_event(event_t *event, unsigned long offset, unsigned long head)
1701 return 0; 1302 return 0;
1702} 1303}
1703 1304
1704static void trace_event(event_t *event) 1305static int
1705{ 1306process_read_event(event_t *event, unsigned long offset, unsigned long head)
1706 unsigned char *raw_event = (void *)event;
1707 char *color = PERF_COLOR_BLUE;
1708 int i, j;
1709
1710 if (!dump_trace)
1711 return;
1712
1713 dprintf(".");
1714 cdprintf("\n. ... raw event: size %d bytes\n", event->header.size);
1715
1716 for (i = 0; i < event->header.size; i++) {
1717 if ((i & 15) == 0) {
1718 dprintf(".");
1719 cdprintf(" %04x: ", i);
1720 }
1721
1722 cdprintf(" %02x", raw_event[i]);
1723
1724 if (((i & 15) == 15) || i == event->header.size-1) {
1725 cdprintf(" ");
1726 for (j = 0; j < 15-(i & 15); j++)
1727 cdprintf(" ");
1728 for (j = 0; j < (i & 15); j++) {
1729 if (isprint(raw_event[i-15+j]))
1730 cdprintf("%c", raw_event[i-15+j]);
1731 else
1732 cdprintf(".");
1733 }
1734 cdprintf("\n");
1735 }
1736 }
1737 dprintf(".\n");
1738}
1739
1740static struct perf_header *header;
1741
1742static struct perf_counter_attr *perf_header__find_attr(u64 id)
1743{ 1307{
1744 int i; 1308 struct perf_event_attr *attr;
1745 1309
1746 for (i = 0; i < header->attrs; i++) { 1310 attr = perf_header__find_attr(event->read.id, header);
1747 struct perf_header_attr *attr = header->attr[i];
1748 int j;
1749 1311
1750 for (j = 0; j < attr->ids; j++) { 1312 if (show_threads) {
1751 if (attr->id[j] == id) 1313 const char *name = attr ? __event_name(attr->type, attr->config)
1752 return &attr->attr; 1314 : "unknown";
1753 } 1315 perf_read_values_add_value(&show_threads_values,
1316 event->read.pid, event->read.tid,
1317 event->read.id,
1318 name,
1319 event->read.value);
1754 } 1320 }
1755 1321
1756 return NULL; 1322 dump_printf("%p [%p]: PERF_RECORD_READ: %d %d %s %Lu\n",
1757}
1758
1759static int
1760process_read_event(event_t *event, unsigned long offset, unsigned long head)
1761{
1762 struct perf_counter_attr *attr = perf_header__find_attr(event->read.id);
1763
1764 dprintf("%p [%p]: PERF_EVENT_READ: %d %d %s %Lu\n",
1765 (void *)(offset + head), 1323 (void *)(offset + head),
1766 (void *)(long)(event->header.size), 1324 (void *)(long)(event->header.size),
1767 event->read.pid, 1325 event->read.pid,
@@ -1779,31 +1337,31 @@ process_event(event_t *event, unsigned long offset, unsigned long head)
1779 trace_event(event); 1337 trace_event(event);
1780 1338
1781 switch (event->header.type) { 1339 switch (event->header.type) {
1782 case PERF_EVENT_SAMPLE: 1340 case PERF_RECORD_SAMPLE:
1783 return process_sample_event(event, offset, head); 1341 return process_sample_event(event, offset, head);
1784 1342
1785 case PERF_EVENT_MMAP: 1343 case PERF_RECORD_MMAP:
1786 return process_mmap_event(event, offset, head); 1344 return process_mmap_event(event, offset, head);
1787 1345
1788 case PERF_EVENT_COMM: 1346 case PERF_RECORD_COMM:
1789 return process_comm_event(event, offset, head); 1347 return process_comm_event(event, offset, head);
1790 1348
1791 case PERF_EVENT_FORK: 1349 case PERF_RECORD_FORK:
1792 case PERF_EVENT_EXIT: 1350 case PERF_RECORD_EXIT:
1793 return process_task_event(event, offset, head); 1351 return process_task_event(event, offset, head);
1794 1352
1795 case PERF_EVENT_LOST: 1353 case PERF_RECORD_LOST:
1796 return process_lost_event(event, offset, head); 1354 return process_lost_event(event, offset, head);
1797 1355
1798 case PERF_EVENT_READ: 1356 case PERF_RECORD_READ:
1799 return process_read_event(event, offset, head); 1357 return process_read_event(event, offset, head);
1800 1358
1801 /* 1359 /*
1802 * We dont process them right now but they are fine: 1360 * We dont process them right now but they are fine:
1803 */ 1361 */
1804 1362
1805 case PERF_EVENT_THROTTLE: 1363 case PERF_RECORD_THROTTLE:
1806 case PERF_EVENT_UNTHROTTLE: 1364 case PERF_RECORD_UNTHROTTLE:
1807 return 0; 1365 return 0;
1808 1366
1809 default: 1367 default:
@@ -1813,34 +1371,22 @@ process_event(event_t *event, unsigned long offset, unsigned long head)
1813 return 0; 1371 return 0;
1814} 1372}
1815 1373
1816static u64 perf_header__sample_type(void)
1817{
1818 u64 sample_type = 0;
1819 int i;
1820
1821 for (i = 0; i < header->attrs; i++) {
1822 struct perf_header_attr *attr = header->attr[i];
1823
1824 if (!sample_type)
1825 sample_type = attr->attr.sample_type;
1826 else if (sample_type != attr->attr.sample_type)
1827 die("non matching sample_type");
1828 }
1829
1830 return sample_type;
1831}
1832
1833static int __cmd_report(void) 1374static int __cmd_report(void)
1834{ 1375{
1835 int ret, rc = EXIT_FAILURE; 1376 int ret, rc = EXIT_FAILURE;
1836 unsigned long offset = 0; 1377 unsigned long offset = 0;
1837 unsigned long head, shift; 1378 unsigned long head, shift;
1838 struct stat stat; 1379 struct stat input_stat;
1380 struct thread *idle;
1839 event_t *event; 1381 event_t *event;
1840 uint32_t size; 1382 uint32_t size;
1841 char *buf; 1383 char *buf;
1842 1384
1843 register_idle_thread(); 1385 idle = register_idle_thread(&threads, &last_match);
1386 thread__comm_adjust(idle);
1387
1388 if (show_threads)
1389 perf_read_values_init(&show_threads_values);
1844 1390
1845 input = open(input_name, O_RDONLY); 1391 input = open(input_name, O_RDONLY);
1846 if (input < 0) { 1392 if (input < 0) {
@@ -1851,18 +1397,18 @@ static int __cmd_report(void)
1851 exit(-1); 1397 exit(-1);
1852 } 1398 }
1853 1399
1854 ret = fstat(input, &stat); 1400 ret = fstat(input, &input_stat);
1855 if (ret < 0) { 1401 if (ret < 0) {
1856 perror("failed to stat file"); 1402 perror("failed to stat file");
1857 exit(-1); 1403 exit(-1);
1858 } 1404 }
1859 1405
1860 if (!force && (stat.st_uid != geteuid())) { 1406 if (!force && input_stat.st_uid && (input_stat.st_uid != geteuid())) {
1861 fprintf(stderr, "file: %s not owned by current user\n", input_name); 1407 fprintf(stderr, "file: %s not owned by current user or root\n", input_name);
1862 exit(-1); 1408 exit(-1);
1863 } 1409 }
1864 1410
1865 if (!stat.st_size) { 1411 if (!input_stat.st_size) {
1866 fprintf(stderr, "zero-sized file, nothing to do!\n"); 1412 fprintf(stderr, "zero-sized file, nothing to do!\n");
1867 exit(0); 1413 exit(0);
1868 } 1414 }
@@ -1870,7 +1416,7 @@ static int __cmd_report(void)
1870 header = perf_header__read(input); 1416 header = perf_header__read(input);
1871 head = header->data_offset; 1417 head = header->data_offset;
1872 1418
1873 sample_type = perf_header__sample_type(); 1419 sample_type = perf_header__sample_type(header);
1874 1420
1875 if (!(sample_type & PERF_SAMPLE_CALLCHAIN)) { 1421 if (!(sample_type & PERF_SAMPLE_CALLCHAIN)) {
1876 if (sort__has_parent) { 1422 if (sort__has_parent) {
@@ -1880,7 +1426,7 @@ static int __cmd_report(void)
1880 exit(-1); 1426 exit(-1);
1881 } 1427 }
1882 if (callchain) { 1428 if (callchain) {
1883 fprintf(stderr, "selected -c but no callchain data." 1429 fprintf(stderr, "selected -g but no callchain data."
1884 " Did you call perf record without" 1430 " Did you call perf record without"
1885 " -g?\n"); 1431 " -g?\n");
1886 exit(-1); 1432 exit(-1);
@@ -1930,12 +1476,12 @@ more:
1930 size = 8; 1476 size = 8;
1931 1477
1932 if (head + event->header.size >= page_size * mmap_window) { 1478 if (head + event->header.size >= page_size * mmap_window) {
1933 int ret; 1479 int munmap_ret;
1934 1480
1935 shift = page_size * (head / page_size); 1481 shift = page_size * (head / page_size);
1936 1482
1937 ret = munmap(buf, page_size * mmap_window); 1483 munmap_ret = munmap(buf, page_size * mmap_window);
1938 assert(ret == 0); 1484 assert(munmap_ret == 0);
1939 1485
1940 offset += shift; 1486 offset += shift;
1941 head -= shift; 1487 head -= shift;
@@ -1944,14 +1490,14 @@ more:
1944 1490
1945 size = event->header.size; 1491 size = event->header.size;
1946 1492
1947 dprintf("\n%p [%p]: event: %d\n", 1493 dump_printf("\n%p [%p]: event: %d\n",
1948 (void *)(offset + head), 1494 (void *)(offset + head),
1949 (void *)(long)event->header.size, 1495 (void *)(long)event->header.size,
1950 event->header.type); 1496 event->header.type);
1951 1497
1952 if (!size || process_event(event, offset, head) < 0) { 1498 if (!size || process_event(event, offset, head) < 0) {
1953 1499
1954 dprintf("%p [%p]: skipping unknown header type: %d\n", 1500 dump_printf("%p [%p]: skipping unknown header type: %d\n",
1955 (void *)(offset + head), 1501 (void *)(offset + head),
1956 (void *)(long)(event->header.size), 1502 (void *)(long)(event->header.size),
1957 event->header.type); 1503 event->header.type);
@@ -1974,25 +1520,25 @@ more:
1974 if (offset + head >= header->data_offset + header->data_size) 1520 if (offset + head >= header->data_offset + header->data_size)
1975 goto done; 1521 goto done;
1976 1522
1977 if (offset + head < (unsigned long)stat.st_size) 1523 if (offset + head < (unsigned long)input_stat.st_size)
1978 goto more; 1524 goto more;
1979 1525
1980done: 1526done:
1981 rc = EXIT_SUCCESS; 1527 rc = EXIT_SUCCESS;
1982 close(input); 1528 close(input);
1983 1529
1984 dprintf(" IP events: %10ld\n", total); 1530 dump_printf(" IP events: %10ld\n", total);
1985 dprintf(" mmap events: %10ld\n", total_mmap); 1531 dump_printf(" mmap events: %10ld\n", total_mmap);
1986 dprintf(" comm events: %10ld\n", total_comm); 1532 dump_printf(" comm events: %10ld\n", total_comm);
1987 dprintf(" fork events: %10ld\n", total_fork); 1533 dump_printf(" fork events: %10ld\n", total_fork);
1988 dprintf(" lost events: %10ld\n", total_lost); 1534 dump_printf(" lost events: %10ld\n", total_lost);
1989 dprintf(" unknown events: %10ld\n", total_unknown); 1535 dump_printf(" unknown events: %10ld\n", total_unknown);
1990 1536
1991 if (dump_trace) 1537 if (dump_trace)
1992 return 0; 1538 return 0;
1993 1539
1994 if (verbose >= 3) 1540 if (verbose >= 3)
1995 threads__fprintf(stdout); 1541 threads__fprintf(stdout, &threads);
1996 1542
1997 if (verbose >= 2) 1543 if (verbose >= 2)
1998 dsos__fprintf(stdout); 1544 dsos__fprintf(stdout);
@@ -2001,6 +1547,9 @@ done:
2001 output__resort(total); 1547 output__resort(total);
2002 output__fprintf(stdout, total); 1548 output__fprintf(stdout, total);
2003 1549
1550 if (show_threads)
1551 perf_read_values_destroy(&show_threads_values);
1552
2004 return rc; 1553 return rc;
2005} 1554}
2006 1555
@@ -2069,12 +1618,16 @@ static const struct option options[] = {
2069 "be more verbose (show symbol address, etc)"), 1618 "be more verbose (show symbol address, etc)"),
2070 OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace, 1619 OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace,
2071 "dump raw trace in ASCII"), 1620 "dump raw trace in ASCII"),
2072 OPT_STRING('k', "vmlinux", &vmlinux, "file", "vmlinux pathname"), 1621 OPT_STRING('k', "vmlinux", &vmlinux_name, "file", "vmlinux pathname"),
2073 OPT_BOOLEAN('f', "force", &force, "don't complain, do it"), 1622 OPT_BOOLEAN('f', "force", &force, "don't complain, do it"),
2074 OPT_BOOLEAN('m', "modules", &modules, 1623 OPT_BOOLEAN('m', "modules", &modules,
2075 "load module symbols - WARNING: use only with -k and LIVE kernel"), 1624 "load module symbols - WARNING: use only with -k and LIVE kernel"),
2076 OPT_BOOLEAN('n', "show-nr-samples", &show_nr_samples, 1625 OPT_BOOLEAN('n', "show-nr-samples", &show_nr_samples,
2077 "Show a column with the number of samples"), 1626 "Show a column with the number of samples"),
1627 OPT_BOOLEAN('T', "threads", &show_threads,
1628 "Show per-thread event counters"),
1629 OPT_STRING(0, "pretty", &pretty_printing_style, "key",
1630 "pretty printing style key: normal raw"),
2078 OPT_STRING('s', "sort", &sort_order, "key[,key2...]", 1631 OPT_STRING('s', "sort", &sort_order, "key[,key2...]",
2079 "sort by key(s): pid, comm, dso, symbol, parent"), 1632 "sort by key(s): pid, comm, dso, symbol, parent"),
2080 OPT_BOOLEAN('P', "full-paths", &full_paths, 1633 OPT_BOOLEAN('P', "full-paths", &full_paths,
diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c
new file mode 100644
index 000000000000..ea9c15c0cdfe
--- /dev/null
+++ b/tools/perf/builtin-sched.c
@@ -0,0 +1,2004 @@
1#include "builtin.h"
2#include "perf.h"
3
4#include "util/util.h"
5#include "util/cache.h"
6#include "util/symbol.h"
7#include "util/thread.h"
8#include "util/header.h"
9
10#include "util/parse-options.h"
11#include "util/trace-event.h"
12
13#include "util/debug.h"
14
15#include <sys/types.h>
16#include <sys/prctl.h>
17
18#include <semaphore.h>
19#include <pthread.h>
20#include <math.h>
21
22static char const *input_name = "perf.data";
23static int input;
24static unsigned long page_size;
25static unsigned long mmap_window = 32;
26
27static unsigned long total_comm = 0;
28
29static struct rb_root threads;
30static struct thread *last_match;
31
32static struct perf_header *header;
33static u64 sample_type;
34
35static char default_sort_order[] = "avg, max, switch, runtime";
36static char *sort_order = default_sort_order;
37
38#define PR_SET_NAME 15 /* Set process name */
39#define MAX_CPUS 4096
40
41#define BUG_ON(x) assert(!(x))
42
43static u64 run_measurement_overhead;
44static u64 sleep_measurement_overhead;
45
46#define COMM_LEN 20
47#define SYM_LEN 129
48
49#define MAX_PID 65536
50
51static unsigned long nr_tasks;
52
53struct sched_atom;
54
55struct task_desc {
56 unsigned long nr;
57 unsigned long pid;
58 char comm[COMM_LEN];
59
60 unsigned long nr_events;
61 unsigned long curr_event;
62 struct sched_atom **atoms;
63
64 pthread_t thread;
65 sem_t sleep_sem;
66
67 sem_t ready_for_work;
68 sem_t work_done_sem;
69
70 u64 cpu_usage;
71};
72
73enum sched_event_type {
74 SCHED_EVENT_RUN,
75 SCHED_EVENT_SLEEP,
76 SCHED_EVENT_WAKEUP,
77};
78
79struct sched_atom {
80 enum sched_event_type type;
81 u64 timestamp;
82 u64 duration;
83 unsigned long nr;
84 int specific_wait;
85 sem_t *wait_sem;
86 struct task_desc *wakee;
87};
88
89static struct task_desc *pid_to_task[MAX_PID];
90
91static struct task_desc **tasks;
92
93static pthread_mutex_t start_work_mutex = PTHREAD_MUTEX_INITIALIZER;
94static u64 start_time;
95
96static pthread_mutex_t work_done_wait_mutex = PTHREAD_MUTEX_INITIALIZER;
97
98static unsigned long nr_run_events;
99static unsigned long nr_sleep_events;
100static unsigned long nr_wakeup_events;
101
102static unsigned long nr_sleep_corrections;
103static unsigned long nr_run_events_optimized;
104
105static unsigned long targetless_wakeups;
106static unsigned long multitarget_wakeups;
107
108static u64 cpu_usage;
109static u64 runavg_cpu_usage;
110static u64 parent_cpu_usage;
111static u64 runavg_parent_cpu_usage;
112
113static unsigned long nr_runs;
114static u64 sum_runtime;
115static u64 sum_fluct;
116static u64 run_avg;
117
118static unsigned long replay_repeat = 10;
119static unsigned long nr_timestamps;
120static unsigned long nr_unordered_timestamps;
121static unsigned long nr_state_machine_bugs;
122static unsigned long nr_context_switch_bugs;
123static unsigned long nr_events;
124static unsigned long nr_lost_chunks;
125static unsigned long nr_lost_events;
126
127#define TASK_STATE_TO_CHAR_STR "RSDTtZX"
128
129enum thread_state {
130 THREAD_SLEEPING = 0,
131 THREAD_WAIT_CPU,
132 THREAD_SCHED_IN,
133 THREAD_IGNORE
134};
135
136struct work_atom {
137 struct list_head list;
138 enum thread_state state;
139 u64 sched_out_time;
140 u64 wake_up_time;
141 u64 sched_in_time;
142 u64 runtime;
143};
144
145struct work_atoms {
146 struct list_head work_list;
147 struct thread *thread;
148 struct rb_node node;
149 u64 max_lat;
150 u64 total_lat;
151 u64 nb_atoms;
152 u64 total_runtime;
153};
154
155typedef int (*sort_fn_t)(struct work_atoms *, struct work_atoms *);
156
157static struct rb_root atom_root, sorted_atom_root;
158
159static u64 all_runtime;
160static u64 all_count;
161
162
163static u64 get_nsecs(void)
164{
165 struct timespec ts;
166
167 clock_gettime(CLOCK_MONOTONIC, &ts);
168
169 return ts.tv_sec * 1000000000ULL + ts.tv_nsec;
170}
171
172static void burn_nsecs(u64 nsecs)
173{
174 u64 T0 = get_nsecs(), T1;
175
176 do {
177 T1 = get_nsecs();
178 } while (T1 + run_measurement_overhead < T0 + nsecs);
179}
180
181static void sleep_nsecs(u64 nsecs)
182{
183 struct timespec ts;
184
185 ts.tv_nsec = nsecs % 999999999;
186 ts.tv_sec = nsecs / 999999999;
187
188 nanosleep(&ts, NULL);
189}
190
191static void calibrate_run_measurement_overhead(void)
192{
193 u64 T0, T1, delta, min_delta = 1000000000ULL;
194 int i;
195
196 for (i = 0; i < 10; i++) {
197 T0 = get_nsecs();
198 burn_nsecs(0);
199 T1 = get_nsecs();
200 delta = T1-T0;
201 min_delta = min(min_delta, delta);
202 }
203 run_measurement_overhead = min_delta;
204
205 printf("run measurement overhead: %Ld nsecs\n", min_delta);
206}
207
208static void calibrate_sleep_measurement_overhead(void)
209{
210 u64 T0, T1, delta, min_delta = 1000000000ULL;
211 int i;
212
213 for (i = 0; i < 10; i++) {
214 T0 = get_nsecs();
215 sleep_nsecs(10000);
216 T1 = get_nsecs();
217 delta = T1-T0;
218 min_delta = min(min_delta, delta);
219 }
220 min_delta -= 10000;
221 sleep_measurement_overhead = min_delta;
222
223 printf("sleep measurement overhead: %Ld nsecs\n", min_delta);
224}
225
226static struct sched_atom *
227get_new_event(struct task_desc *task, u64 timestamp)
228{
229 struct sched_atom *event = calloc(1, sizeof(*event));
230 unsigned long idx = task->nr_events;
231 size_t size;
232
233 event->timestamp = timestamp;
234 event->nr = idx;
235
236 task->nr_events++;
237 size = sizeof(struct sched_atom *) * task->nr_events;
238 task->atoms = realloc(task->atoms, size);
239 BUG_ON(!task->atoms);
240
241 task->atoms[idx] = event;
242
243 return event;
244}
245
246static struct sched_atom *last_event(struct task_desc *task)
247{
248 if (!task->nr_events)
249 return NULL;
250
251 return task->atoms[task->nr_events - 1];
252}
253
254static void
255add_sched_event_run(struct task_desc *task, u64 timestamp, u64 duration)
256{
257 struct sched_atom *event, *curr_event = last_event(task);
258
259 /*
260 * optimize an existing RUN event by merging this one
261 * to it:
262 */
263 if (curr_event && curr_event->type == SCHED_EVENT_RUN) {
264 nr_run_events_optimized++;
265 curr_event->duration += duration;
266 return;
267 }
268
269 event = get_new_event(task, timestamp);
270
271 event->type = SCHED_EVENT_RUN;
272 event->duration = duration;
273
274 nr_run_events++;
275}
276
277static void
278add_sched_event_wakeup(struct task_desc *task, u64 timestamp,
279 struct task_desc *wakee)
280{
281 struct sched_atom *event, *wakee_event;
282
283 event = get_new_event(task, timestamp);
284 event->type = SCHED_EVENT_WAKEUP;
285 event->wakee = wakee;
286
287 wakee_event = last_event(wakee);
288 if (!wakee_event || wakee_event->type != SCHED_EVENT_SLEEP) {
289 targetless_wakeups++;
290 return;
291 }
292 if (wakee_event->wait_sem) {
293 multitarget_wakeups++;
294 return;
295 }
296
297 wakee_event->wait_sem = calloc(1, sizeof(*wakee_event->wait_sem));
298 sem_init(wakee_event->wait_sem, 0, 0);
299 wakee_event->specific_wait = 1;
300 event->wait_sem = wakee_event->wait_sem;
301
302 nr_wakeup_events++;
303}
304
305static void
306add_sched_event_sleep(struct task_desc *task, u64 timestamp,
307 u64 task_state __used)
308{
309 struct sched_atom *event = get_new_event(task, timestamp);
310
311 event->type = SCHED_EVENT_SLEEP;
312
313 nr_sleep_events++;
314}
315
316static struct task_desc *register_pid(unsigned long pid, const char *comm)
317{
318 struct task_desc *task;
319
320 BUG_ON(pid >= MAX_PID);
321
322 task = pid_to_task[pid];
323
324 if (task)
325 return task;
326
327 task = calloc(1, sizeof(*task));
328 task->pid = pid;
329 task->nr = nr_tasks;
330 strcpy(task->comm, comm);
331 /*
332 * every task starts in sleeping state - this gets ignored
333 * if there's no wakeup pointing to this sleep state:
334 */
335 add_sched_event_sleep(task, 0, 0);
336
337 pid_to_task[pid] = task;
338 nr_tasks++;
339 tasks = realloc(tasks, nr_tasks*sizeof(struct task_task *));
340 BUG_ON(!tasks);
341 tasks[task->nr] = task;
342
343 if (verbose)
344 printf("registered task #%ld, PID %ld (%s)\n", nr_tasks, pid, comm);
345
346 return task;
347}
348
349
350static void print_task_traces(void)
351{
352 struct task_desc *task;
353 unsigned long i;
354
355 for (i = 0; i < nr_tasks; i++) {
356 task = tasks[i];
357 printf("task %6ld (%20s:%10ld), nr_events: %ld\n",
358 task->nr, task->comm, task->pid, task->nr_events);
359 }
360}
361
362static void add_cross_task_wakeups(void)
363{
364 struct task_desc *task1, *task2;
365 unsigned long i, j;
366
367 for (i = 0; i < nr_tasks; i++) {
368 task1 = tasks[i];
369 j = i + 1;
370 if (j == nr_tasks)
371 j = 0;
372 task2 = tasks[j];
373 add_sched_event_wakeup(task1, 0, task2);
374 }
375}
376
377static void
378process_sched_event(struct task_desc *this_task __used, struct sched_atom *atom)
379{
380 int ret = 0;
381 u64 now;
382 long long delta;
383
384 now = get_nsecs();
385 delta = start_time + atom->timestamp - now;
386
387 switch (atom->type) {
388 case SCHED_EVENT_RUN:
389 burn_nsecs(atom->duration);
390 break;
391 case SCHED_EVENT_SLEEP:
392 if (atom->wait_sem)
393 ret = sem_wait(atom->wait_sem);
394 BUG_ON(ret);
395 break;
396 case SCHED_EVENT_WAKEUP:
397 if (atom->wait_sem)
398 ret = sem_post(atom->wait_sem);
399 BUG_ON(ret);
400 break;
401 default:
402 BUG_ON(1);
403 }
404}
405
406static u64 get_cpu_usage_nsec_parent(void)
407{
408 struct rusage ru;
409 u64 sum;
410 int err;
411
412 err = getrusage(RUSAGE_SELF, &ru);
413 BUG_ON(err);
414
415 sum = ru.ru_utime.tv_sec*1e9 + ru.ru_utime.tv_usec*1e3;
416 sum += ru.ru_stime.tv_sec*1e9 + ru.ru_stime.tv_usec*1e3;
417
418 return sum;
419}
420
421static u64 get_cpu_usage_nsec_self(void)
422{
423 char filename [] = "/proc/1234567890/sched";
424 unsigned long msecs, nsecs;
425 char *line = NULL;
426 u64 total = 0;
427 size_t len = 0;
428 ssize_t chars;
429 FILE *file;
430 int ret;
431
432 sprintf(filename, "/proc/%d/sched", getpid());
433 file = fopen(filename, "r");
434 BUG_ON(!file);
435
436 while ((chars = getline(&line, &len, file)) != -1) {
437 ret = sscanf(line, "se.sum_exec_runtime : %ld.%06ld\n",
438 &msecs, &nsecs);
439 if (ret == 2) {
440 total = msecs*1e6 + nsecs;
441 break;
442 }
443 }
444 if (line)
445 free(line);
446 fclose(file);
447
448 return total;
449}
450
451static void *thread_func(void *ctx)
452{
453 struct task_desc *this_task = ctx;
454 u64 cpu_usage_0, cpu_usage_1;
455 unsigned long i, ret;
456 char comm2[22];
457
458 sprintf(comm2, ":%s", this_task->comm);
459 prctl(PR_SET_NAME, comm2);
460
461again:
462 ret = sem_post(&this_task->ready_for_work);
463 BUG_ON(ret);
464 ret = pthread_mutex_lock(&start_work_mutex);
465 BUG_ON(ret);
466 ret = pthread_mutex_unlock(&start_work_mutex);
467 BUG_ON(ret);
468
469 cpu_usage_0 = get_cpu_usage_nsec_self();
470
471 for (i = 0; i < this_task->nr_events; i++) {
472 this_task->curr_event = i;
473 process_sched_event(this_task, this_task->atoms[i]);
474 }
475
476 cpu_usage_1 = get_cpu_usage_nsec_self();
477 this_task->cpu_usage = cpu_usage_1 - cpu_usage_0;
478
479 ret = sem_post(&this_task->work_done_sem);
480 BUG_ON(ret);
481
482 ret = pthread_mutex_lock(&work_done_wait_mutex);
483 BUG_ON(ret);
484 ret = pthread_mutex_unlock(&work_done_wait_mutex);
485 BUG_ON(ret);
486
487 goto again;
488}
489
490static void create_tasks(void)
491{
492 struct task_desc *task;
493 pthread_attr_t attr;
494 unsigned long i;
495 int err;
496
497 err = pthread_attr_init(&attr);
498 BUG_ON(err);
499 err = pthread_attr_setstacksize(&attr, (size_t)(16*1024));
500 BUG_ON(err);
501 err = pthread_mutex_lock(&start_work_mutex);
502 BUG_ON(err);
503 err = pthread_mutex_lock(&work_done_wait_mutex);
504 BUG_ON(err);
505 for (i = 0; i < nr_tasks; i++) {
506 task = tasks[i];
507 sem_init(&task->sleep_sem, 0, 0);
508 sem_init(&task->ready_for_work, 0, 0);
509 sem_init(&task->work_done_sem, 0, 0);
510 task->curr_event = 0;
511 err = pthread_create(&task->thread, &attr, thread_func, task);
512 BUG_ON(err);
513 }
514}
515
516static void wait_for_tasks(void)
517{
518 u64 cpu_usage_0, cpu_usage_1;
519 struct task_desc *task;
520 unsigned long i, ret;
521
522 start_time = get_nsecs();
523 cpu_usage = 0;
524 pthread_mutex_unlock(&work_done_wait_mutex);
525
526 for (i = 0; i < nr_tasks; i++) {
527 task = tasks[i];
528 ret = sem_wait(&task->ready_for_work);
529 BUG_ON(ret);
530 sem_init(&task->ready_for_work, 0, 0);
531 }
532 ret = pthread_mutex_lock(&work_done_wait_mutex);
533 BUG_ON(ret);
534
535 cpu_usage_0 = get_cpu_usage_nsec_parent();
536
537 pthread_mutex_unlock(&start_work_mutex);
538
539 for (i = 0; i < nr_tasks; i++) {
540 task = tasks[i];
541 ret = sem_wait(&task->work_done_sem);
542 BUG_ON(ret);
543 sem_init(&task->work_done_sem, 0, 0);
544 cpu_usage += task->cpu_usage;
545 task->cpu_usage = 0;
546 }
547
548 cpu_usage_1 = get_cpu_usage_nsec_parent();
549 if (!runavg_cpu_usage)
550 runavg_cpu_usage = cpu_usage;
551 runavg_cpu_usage = (runavg_cpu_usage*9 + cpu_usage)/10;
552
553 parent_cpu_usage = cpu_usage_1 - cpu_usage_0;
554 if (!runavg_parent_cpu_usage)
555 runavg_parent_cpu_usage = parent_cpu_usage;
556 runavg_parent_cpu_usage = (runavg_parent_cpu_usage*9 +
557 parent_cpu_usage)/10;
558
559 ret = pthread_mutex_lock(&start_work_mutex);
560 BUG_ON(ret);
561
562 for (i = 0; i < nr_tasks; i++) {
563 task = tasks[i];
564 sem_init(&task->sleep_sem, 0, 0);
565 task->curr_event = 0;
566 }
567}
568
569static void run_one_test(void)
570{
571 u64 T0, T1, delta, avg_delta, fluct, std_dev;
572
573 T0 = get_nsecs();
574 wait_for_tasks();
575 T1 = get_nsecs();
576
577 delta = T1 - T0;
578 sum_runtime += delta;
579 nr_runs++;
580
581 avg_delta = sum_runtime / nr_runs;
582 if (delta < avg_delta)
583 fluct = avg_delta - delta;
584 else
585 fluct = delta - avg_delta;
586 sum_fluct += fluct;
587 std_dev = sum_fluct / nr_runs / sqrt(nr_runs);
588 if (!run_avg)
589 run_avg = delta;
590 run_avg = (run_avg*9 + delta)/10;
591
592 printf("#%-3ld: %0.3f, ",
593 nr_runs, (double)delta/1000000.0);
594
595 printf("ravg: %0.2f, ",
596 (double)run_avg/1e6);
597
598 printf("cpu: %0.2f / %0.2f",
599 (double)cpu_usage/1e6, (double)runavg_cpu_usage/1e6);
600
601#if 0
602 /*
603 * rusage statistics done by the parent, these are less
604 * accurate than the sum_exec_runtime based statistics:
605 */
606 printf(" [%0.2f / %0.2f]",
607 (double)parent_cpu_usage/1e6,
608 (double)runavg_parent_cpu_usage/1e6);
609#endif
610
611 printf("\n");
612
613 if (nr_sleep_corrections)
614 printf(" (%ld sleep corrections)\n", nr_sleep_corrections);
615 nr_sleep_corrections = 0;
616}
617
618static void test_calibrations(void)
619{
620 u64 T0, T1;
621
622 T0 = get_nsecs();
623 burn_nsecs(1e6);
624 T1 = get_nsecs();
625
626 printf("the run test took %Ld nsecs\n", T1-T0);
627
628 T0 = get_nsecs();
629 sleep_nsecs(1e6);
630 T1 = get_nsecs();
631
632 printf("the sleep test took %Ld nsecs\n", T1-T0);
633}
634
635static int
636process_comm_event(event_t *event, unsigned long offset, unsigned long head)
637{
638 struct thread *thread;
639
640 thread = threads__findnew(event->comm.pid, &threads, &last_match);
641
642 dump_printf("%p [%p]: perf_event_comm: %s:%d\n",
643 (void *)(offset + head),
644 (void *)(long)(event->header.size),
645 event->comm.comm, event->comm.pid);
646
647 if (thread == NULL ||
648 thread__set_comm(thread, event->comm.comm)) {
649 dump_printf("problem processing perf_event_comm, skipping event.\n");
650 return -1;
651 }
652 total_comm++;
653
654 return 0;
655}
656
657
658struct raw_event_sample {
659 u32 size;
660 char data[0];
661};
662
663#define FILL_FIELD(ptr, field, event, data) \
664 ptr.field = (typeof(ptr.field)) raw_field_value(event, #field, data)
665
666#define FILL_ARRAY(ptr, array, event, data) \
667do { \
668 void *__array = raw_field_ptr(event, #array, data); \
669 memcpy(ptr.array, __array, sizeof(ptr.array)); \
670} while(0)
671
672#define FILL_COMMON_FIELDS(ptr, event, data) \
673do { \
674 FILL_FIELD(ptr, common_type, event, data); \
675 FILL_FIELD(ptr, common_flags, event, data); \
676 FILL_FIELD(ptr, common_preempt_count, event, data); \
677 FILL_FIELD(ptr, common_pid, event, data); \
678 FILL_FIELD(ptr, common_tgid, event, data); \
679} while (0)
680
681
682
683struct trace_switch_event {
684 u32 size;
685
686 u16 common_type;
687 u8 common_flags;
688 u8 common_preempt_count;
689 u32 common_pid;
690 u32 common_tgid;
691
692 char prev_comm[16];
693 u32 prev_pid;
694 u32 prev_prio;
695 u64 prev_state;
696 char next_comm[16];
697 u32 next_pid;
698 u32 next_prio;
699};
700
701struct trace_runtime_event {
702 u32 size;
703
704 u16 common_type;
705 u8 common_flags;
706 u8 common_preempt_count;
707 u32 common_pid;
708 u32 common_tgid;
709
710 char comm[16];
711 u32 pid;
712 u64 runtime;
713 u64 vruntime;
714};
715
716struct trace_wakeup_event {
717 u32 size;
718
719 u16 common_type;
720 u8 common_flags;
721 u8 common_preempt_count;
722 u32 common_pid;
723 u32 common_tgid;
724
725 char comm[16];
726 u32 pid;
727
728 u32 prio;
729 u32 success;
730 u32 cpu;
731};
732
733struct trace_fork_event {
734 u32 size;
735
736 u16 common_type;
737 u8 common_flags;
738 u8 common_preempt_count;
739 u32 common_pid;
740 u32 common_tgid;
741
742 char parent_comm[16];
743 u32 parent_pid;
744 char child_comm[16];
745 u32 child_pid;
746};
747
748struct trace_sched_handler {
749 void (*switch_event)(struct trace_switch_event *,
750 struct event *,
751 int cpu,
752 u64 timestamp,
753 struct thread *thread);
754
755 void (*runtime_event)(struct trace_runtime_event *,
756 struct event *,
757 int cpu,
758 u64 timestamp,
759 struct thread *thread);
760
761 void (*wakeup_event)(struct trace_wakeup_event *,
762 struct event *,
763 int cpu,
764 u64 timestamp,
765 struct thread *thread);
766
767 void (*fork_event)(struct trace_fork_event *,
768 struct event *,
769 int cpu,
770 u64 timestamp,
771 struct thread *thread);
772};
773
774
775static void
776replay_wakeup_event(struct trace_wakeup_event *wakeup_event,
777 struct event *event,
778 int cpu __used,
779 u64 timestamp __used,
780 struct thread *thread __used)
781{
782 struct task_desc *waker, *wakee;
783
784 if (verbose) {
785 printf("sched_wakeup event %p\n", event);
786
787 printf(" ... pid %d woke up %s/%d\n",
788 wakeup_event->common_pid,
789 wakeup_event->comm,
790 wakeup_event->pid);
791 }
792
793 waker = register_pid(wakeup_event->common_pid, "<unknown>");
794 wakee = register_pid(wakeup_event->pid, wakeup_event->comm);
795
796 add_sched_event_wakeup(waker, timestamp, wakee);
797}
798
799static u64 cpu_last_switched[MAX_CPUS];
800
801static void
802replay_switch_event(struct trace_switch_event *switch_event,
803 struct event *event,
804 int cpu,
805 u64 timestamp,
806 struct thread *thread __used)
807{
808 struct task_desc *prev, *next;
809 u64 timestamp0;
810 s64 delta;
811
812 if (verbose)
813 printf("sched_switch event %p\n", event);
814
815 if (cpu >= MAX_CPUS || cpu < 0)
816 return;
817
818 timestamp0 = cpu_last_switched[cpu];
819 if (timestamp0)
820 delta = timestamp - timestamp0;
821 else
822 delta = 0;
823
824 if (delta < 0)
825 die("hm, delta: %Ld < 0 ?\n", delta);
826
827 if (verbose) {
828 printf(" ... switch from %s/%d to %s/%d [ran %Ld nsecs]\n",
829 switch_event->prev_comm, switch_event->prev_pid,
830 switch_event->next_comm, switch_event->next_pid,
831 delta);
832 }
833
834 prev = register_pid(switch_event->prev_pid, switch_event->prev_comm);
835 next = register_pid(switch_event->next_pid, switch_event->next_comm);
836
837 cpu_last_switched[cpu] = timestamp;
838
839 add_sched_event_run(prev, timestamp, delta);
840 add_sched_event_sleep(prev, timestamp, switch_event->prev_state);
841}
842
843
844static void
845replay_fork_event(struct trace_fork_event *fork_event,
846 struct event *event,
847 int cpu __used,
848 u64 timestamp __used,
849 struct thread *thread __used)
850{
851 if (verbose) {
852 printf("sched_fork event %p\n", event);
853 printf("... parent: %s/%d\n", fork_event->parent_comm, fork_event->parent_pid);
854 printf("... child: %s/%d\n", fork_event->child_comm, fork_event->child_pid);
855 }
856 register_pid(fork_event->parent_pid, fork_event->parent_comm);
857 register_pid(fork_event->child_pid, fork_event->child_comm);
858}
859
860static struct trace_sched_handler replay_ops = {
861 .wakeup_event = replay_wakeup_event,
862 .switch_event = replay_switch_event,
863 .fork_event = replay_fork_event,
864};
865
866struct sort_dimension {
867 const char *name;
868 sort_fn_t cmp;
869 struct list_head list;
870};
871
872static LIST_HEAD(cmp_pid);
873
874static int
875thread_lat_cmp(struct list_head *list, struct work_atoms *l, struct work_atoms *r)
876{
877 struct sort_dimension *sort;
878 int ret = 0;
879
880 BUG_ON(list_empty(list));
881
882 list_for_each_entry(sort, list, list) {
883 ret = sort->cmp(l, r);
884 if (ret)
885 return ret;
886 }
887
888 return ret;
889}
890
891static struct work_atoms *
892thread_atoms_search(struct rb_root *root, struct thread *thread,
893 struct list_head *sort_list)
894{
895 struct rb_node *node = root->rb_node;
896 struct work_atoms key = { .thread = thread };
897
898 while (node) {
899 struct work_atoms *atoms;
900 int cmp;
901
902 atoms = container_of(node, struct work_atoms, node);
903
904 cmp = thread_lat_cmp(sort_list, &key, atoms);
905 if (cmp > 0)
906 node = node->rb_left;
907 else if (cmp < 0)
908 node = node->rb_right;
909 else {
910 BUG_ON(thread != atoms->thread);
911 return atoms;
912 }
913 }
914 return NULL;
915}
916
917static void
918__thread_latency_insert(struct rb_root *root, struct work_atoms *data,
919 struct list_head *sort_list)
920{
921 struct rb_node **new = &(root->rb_node), *parent = NULL;
922
923 while (*new) {
924 struct work_atoms *this;
925 int cmp;
926
927 this = container_of(*new, struct work_atoms, node);
928 parent = *new;
929
930 cmp = thread_lat_cmp(sort_list, data, this);
931
932 if (cmp > 0)
933 new = &((*new)->rb_left);
934 else
935 new = &((*new)->rb_right);
936 }
937
938 rb_link_node(&data->node, parent, new);
939 rb_insert_color(&data->node, root);
940}
941
942static void thread_atoms_insert(struct thread *thread)
943{
944 struct work_atoms *atoms;
945
946 atoms = calloc(sizeof(*atoms), 1);
947 if (!atoms)
948 die("No memory");
949
950 atoms->thread = thread;
951 INIT_LIST_HEAD(&atoms->work_list);
952 __thread_latency_insert(&atom_root, atoms, &cmp_pid);
953}
954
955static void
956latency_fork_event(struct trace_fork_event *fork_event __used,
957 struct event *event __used,
958 int cpu __used,
959 u64 timestamp __used,
960 struct thread *thread __used)
961{
962 /* should insert the newcomer */
963}
964
965__used
966static char sched_out_state(struct trace_switch_event *switch_event)
967{
968 const char *str = TASK_STATE_TO_CHAR_STR;
969
970 return str[switch_event->prev_state];
971}
972
973static void
974add_sched_out_event(struct work_atoms *atoms,
975 char run_state,
976 u64 timestamp)
977{
978 struct work_atom *atom;
979
980 atom = calloc(sizeof(*atom), 1);
981 if (!atom)
982 die("Non memory");
983
984 atom->sched_out_time = timestamp;
985
986 if (run_state == 'R') {
987 atom->state = THREAD_WAIT_CPU;
988 atom->wake_up_time = atom->sched_out_time;
989 }
990
991 list_add_tail(&atom->list, &atoms->work_list);
992}
993
994static void
995add_runtime_event(struct work_atoms *atoms, u64 delta, u64 timestamp __used)
996{
997 struct work_atom *atom;
998
999 BUG_ON(list_empty(&atoms->work_list));
1000
1001 atom = list_entry(atoms->work_list.prev, struct work_atom, list);
1002
1003 atom->runtime += delta;
1004 atoms->total_runtime += delta;
1005}
1006
1007static void
1008add_sched_in_event(struct work_atoms *atoms, u64 timestamp)
1009{
1010 struct work_atom *atom;
1011 u64 delta;
1012
1013 if (list_empty(&atoms->work_list))
1014 return;
1015
1016 atom = list_entry(atoms->work_list.prev, struct work_atom, list);
1017
1018 if (atom->state != THREAD_WAIT_CPU)
1019 return;
1020
1021 if (timestamp < atom->wake_up_time) {
1022 atom->state = THREAD_IGNORE;
1023 return;
1024 }
1025
1026 atom->state = THREAD_SCHED_IN;
1027 atom->sched_in_time = timestamp;
1028
1029 delta = atom->sched_in_time - atom->wake_up_time;
1030 atoms->total_lat += delta;
1031 if (delta > atoms->max_lat)
1032 atoms->max_lat = delta;
1033 atoms->nb_atoms++;
1034}
1035
1036static void
1037latency_switch_event(struct trace_switch_event *switch_event,
1038 struct event *event __used,
1039 int cpu,
1040 u64 timestamp,
1041 struct thread *thread __used)
1042{
1043 struct work_atoms *out_events, *in_events;
1044 struct thread *sched_out, *sched_in;
1045 u64 timestamp0;
1046 s64 delta;
1047
1048 BUG_ON(cpu >= MAX_CPUS || cpu < 0);
1049
1050 timestamp0 = cpu_last_switched[cpu];
1051 cpu_last_switched[cpu] = timestamp;
1052 if (timestamp0)
1053 delta = timestamp - timestamp0;
1054 else
1055 delta = 0;
1056
1057 if (delta < 0)
1058 die("hm, delta: %Ld < 0 ?\n", delta);
1059
1060
1061 sched_out = threads__findnew(switch_event->prev_pid, &threads, &last_match);
1062 sched_in = threads__findnew(switch_event->next_pid, &threads, &last_match);
1063
1064 out_events = thread_atoms_search(&atom_root, sched_out, &cmp_pid);
1065 if (!out_events) {
1066 thread_atoms_insert(sched_out);
1067 out_events = thread_atoms_search(&atom_root, sched_out, &cmp_pid);
1068 if (!out_events)
1069 die("out-event: Internal tree error");
1070 }
1071 add_sched_out_event(out_events, sched_out_state(switch_event), timestamp);
1072
1073 in_events = thread_atoms_search(&atom_root, sched_in, &cmp_pid);
1074 if (!in_events) {
1075 thread_atoms_insert(sched_in);
1076 in_events = thread_atoms_search(&atom_root, sched_in, &cmp_pid);
1077 if (!in_events)
1078 die("in-event: Internal tree error");
1079 /*
1080 * Take came in we have not heard about yet,
1081 * add in an initial atom in runnable state:
1082 */
1083 add_sched_out_event(in_events, 'R', timestamp);
1084 }
1085 add_sched_in_event(in_events, timestamp);
1086}
1087
1088static void
1089latency_runtime_event(struct trace_runtime_event *runtime_event,
1090 struct event *event __used,
1091 int cpu,
1092 u64 timestamp,
1093 struct thread *this_thread __used)
1094{
1095 struct work_atoms *atoms;
1096 struct thread *thread;
1097
1098 BUG_ON(cpu >= MAX_CPUS || cpu < 0);
1099
1100 thread = threads__findnew(runtime_event->pid, &threads, &last_match);
1101 atoms = thread_atoms_search(&atom_root, thread, &cmp_pid);
1102 if (!atoms) {
1103 thread_atoms_insert(thread);
1104 atoms = thread_atoms_search(&atom_root, thread, &cmp_pid);
1105 if (!atoms)
1106 die("in-event: Internal tree error");
1107 add_sched_out_event(atoms, 'R', timestamp);
1108 }
1109
1110 add_runtime_event(atoms, runtime_event->runtime, timestamp);
1111}
1112
1113static void
1114latency_wakeup_event(struct trace_wakeup_event *wakeup_event,
1115 struct event *__event __used,
1116 int cpu __used,
1117 u64 timestamp,
1118 struct thread *thread __used)
1119{
1120 struct work_atoms *atoms;
1121 struct work_atom *atom;
1122 struct thread *wakee;
1123
1124 /* Note for later, it may be interesting to observe the failing cases */
1125 if (!wakeup_event->success)
1126 return;
1127
1128 wakee = threads__findnew(wakeup_event->pid, &threads, &last_match);
1129 atoms = thread_atoms_search(&atom_root, wakee, &cmp_pid);
1130 if (!atoms) {
1131 thread_atoms_insert(wakee);
1132 atoms = thread_atoms_search(&atom_root, wakee, &cmp_pid);
1133 if (!atoms)
1134 die("wakeup-event: Internal tree error");
1135 add_sched_out_event(atoms, 'S', timestamp);
1136 }
1137
1138 BUG_ON(list_empty(&atoms->work_list));
1139
1140 atom = list_entry(atoms->work_list.prev, struct work_atom, list);
1141
1142 if (atom->state != THREAD_SLEEPING)
1143 nr_state_machine_bugs++;
1144
1145 nr_timestamps++;
1146 if (atom->sched_out_time > timestamp) {
1147 nr_unordered_timestamps++;
1148 return;
1149 }
1150
1151 atom->state = THREAD_WAIT_CPU;
1152 atom->wake_up_time = timestamp;
1153}
1154
1155static struct trace_sched_handler lat_ops = {
1156 .wakeup_event = latency_wakeup_event,
1157 .switch_event = latency_switch_event,
1158 .runtime_event = latency_runtime_event,
1159 .fork_event = latency_fork_event,
1160};
1161
1162static void output_lat_thread(struct work_atoms *work_list)
1163{
1164 int i;
1165 int ret;
1166 u64 avg;
1167
1168 if (!work_list->nb_atoms)
1169 return;
1170 /*
1171 * Ignore idle threads:
1172 */
1173 if (!strcmp(work_list->thread->comm, "swapper"))
1174 return;
1175
1176 all_runtime += work_list->total_runtime;
1177 all_count += work_list->nb_atoms;
1178
1179 ret = printf(" %s:%d ", work_list->thread->comm, work_list->thread->pid);
1180
1181 for (i = 0; i < 24 - ret; i++)
1182 printf(" ");
1183
1184 avg = work_list->total_lat / work_list->nb_atoms;
1185
1186 printf("|%11.3f ms |%9llu | avg:%9.3f ms | max:%9.3f ms |\n",
1187 (double)work_list->total_runtime / 1e6,
1188 work_list->nb_atoms, (double)avg / 1e6,
1189 (double)work_list->max_lat / 1e6);
1190}
1191
1192static int pid_cmp(struct work_atoms *l, struct work_atoms *r)
1193{
1194 if (l->thread->pid < r->thread->pid)
1195 return -1;
1196 if (l->thread->pid > r->thread->pid)
1197 return 1;
1198
1199 return 0;
1200}
1201
1202static struct sort_dimension pid_sort_dimension = {
1203 .name = "pid",
1204 .cmp = pid_cmp,
1205};
1206
1207static int avg_cmp(struct work_atoms *l, struct work_atoms *r)
1208{
1209 u64 avgl, avgr;
1210
1211 if (!l->nb_atoms)
1212 return -1;
1213
1214 if (!r->nb_atoms)
1215 return 1;
1216
1217 avgl = l->total_lat / l->nb_atoms;
1218 avgr = r->total_lat / r->nb_atoms;
1219
1220 if (avgl < avgr)
1221 return -1;
1222 if (avgl > avgr)
1223 return 1;
1224
1225 return 0;
1226}
1227
1228static struct sort_dimension avg_sort_dimension = {
1229 .name = "avg",
1230 .cmp = avg_cmp,
1231};
1232
1233static int max_cmp(struct work_atoms *l, struct work_atoms *r)
1234{
1235 if (l->max_lat < r->max_lat)
1236 return -1;
1237 if (l->max_lat > r->max_lat)
1238 return 1;
1239
1240 return 0;
1241}
1242
1243static struct sort_dimension max_sort_dimension = {
1244 .name = "max",
1245 .cmp = max_cmp,
1246};
1247
1248static int switch_cmp(struct work_atoms *l, struct work_atoms *r)
1249{
1250 if (l->nb_atoms < r->nb_atoms)
1251 return -1;
1252 if (l->nb_atoms > r->nb_atoms)
1253 return 1;
1254
1255 return 0;
1256}
1257
1258static struct sort_dimension switch_sort_dimension = {
1259 .name = "switch",
1260 .cmp = switch_cmp,
1261};
1262
1263static int runtime_cmp(struct work_atoms *l, struct work_atoms *r)
1264{
1265 if (l->total_runtime < r->total_runtime)
1266 return -1;
1267 if (l->total_runtime > r->total_runtime)
1268 return 1;
1269
1270 return 0;
1271}
1272
1273static struct sort_dimension runtime_sort_dimension = {
1274 .name = "runtime",
1275 .cmp = runtime_cmp,
1276};
1277
1278static struct sort_dimension *available_sorts[] = {
1279 &pid_sort_dimension,
1280 &avg_sort_dimension,
1281 &max_sort_dimension,
1282 &switch_sort_dimension,
1283 &runtime_sort_dimension,
1284};
1285
1286#define NB_AVAILABLE_SORTS (int)(sizeof(available_sorts) / sizeof(struct sort_dimension *))
1287
1288static LIST_HEAD(sort_list);
1289
1290static int sort_dimension__add(char *tok, struct list_head *list)
1291{
1292 int i;
1293
1294 for (i = 0; i < NB_AVAILABLE_SORTS; i++) {
1295 if (!strcmp(available_sorts[i]->name, tok)) {
1296 list_add_tail(&available_sorts[i]->list, list);
1297
1298 return 0;
1299 }
1300 }
1301
1302 return -1;
1303}
1304
1305static void setup_sorting(void);
1306
1307static void sort_lat(void)
1308{
1309 struct rb_node *node;
1310
1311 for (;;) {
1312 struct work_atoms *data;
1313 node = rb_first(&atom_root);
1314 if (!node)
1315 break;
1316
1317 rb_erase(node, &atom_root);
1318 data = rb_entry(node, struct work_atoms, node);
1319 __thread_latency_insert(&sorted_atom_root, data, &sort_list);
1320 }
1321}
1322
1323static struct trace_sched_handler *trace_handler;
1324
1325static void
1326process_sched_wakeup_event(struct raw_event_sample *raw,
1327 struct event *event,
1328 int cpu __used,
1329 u64 timestamp __used,
1330 struct thread *thread __used)
1331{
1332 struct trace_wakeup_event wakeup_event;
1333
1334 FILL_COMMON_FIELDS(wakeup_event, event, raw->data);
1335
1336 FILL_ARRAY(wakeup_event, comm, event, raw->data);
1337 FILL_FIELD(wakeup_event, pid, event, raw->data);
1338 FILL_FIELD(wakeup_event, prio, event, raw->data);
1339 FILL_FIELD(wakeup_event, success, event, raw->data);
1340 FILL_FIELD(wakeup_event, cpu, event, raw->data);
1341
1342 if (trace_handler->wakeup_event)
1343 trace_handler->wakeup_event(&wakeup_event, event, cpu, timestamp, thread);
1344}
1345
1346/*
1347 * Track the current task - that way we can know whether there's any
1348 * weird events, such as a task being switched away that is not current.
1349 */
1350static int max_cpu;
1351
1352static u32 curr_pid[MAX_CPUS] = { [0 ... MAX_CPUS-1] = -1 };
1353
1354static struct thread *curr_thread[MAX_CPUS];
1355
1356static char next_shortname1 = 'A';
1357static char next_shortname2 = '0';
1358
1359static void
1360map_switch_event(struct trace_switch_event *switch_event,
1361 struct event *event __used,
1362 int this_cpu,
1363 u64 timestamp,
1364 struct thread *thread __used)
1365{
1366 struct thread *sched_out, *sched_in;
1367 int new_shortname;
1368 u64 timestamp0;
1369 s64 delta;
1370 int cpu;
1371
1372 BUG_ON(this_cpu >= MAX_CPUS || this_cpu < 0);
1373
1374 if (this_cpu > max_cpu)
1375 max_cpu = this_cpu;
1376
1377 timestamp0 = cpu_last_switched[this_cpu];
1378 cpu_last_switched[this_cpu] = timestamp;
1379 if (timestamp0)
1380 delta = timestamp - timestamp0;
1381 else
1382 delta = 0;
1383
1384 if (delta < 0)
1385 die("hm, delta: %Ld < 0 ?\n", delta);
1386
1387
1388 sched_out = threads__findnew(switch_event->prev_pid, &threads, &last_match);
1389 sched_in = threads__findnew(switch_event->next_pid, &threads, &last_match);
1390
1391 curr_thread[this_cpu] = sched_in;
1392
1393 printf(" ");
1394
1395 new_shortname = 0;
1396 if (!sched_in->shortname[0]) {
1397 sched_in->shortname[0] = next_shortname1;
1398 sched_in->shortname[1] = next_shortname2;
1399
1400 if (next_shortname1 < 'Z') {
1401 next_shortname1++;
1402 } else {
1403 next_shortname1='A';
1404 if (next_shortname2 < '9') {
1405 next_shortname2++;
1406 } else {
1407 next_shortname2='0';
1408 }
1409 }
1410 new_shortname = 1;
1411 }
1412
1413 for (cpu = 0; cpu <= max_cpu; cpu++) {
1414 if (cpu != this_cpu)
1415 printf(" ");
1416 else
1417 printf("*");
1418
1419 if (curr_thread[cpu]) {
1420 if (curr_thread[cpu]->pid)
1421 printf("%2s ", curr_thread[cpu]->shortname);
1422 else
1423 printf(". ");
1424 } else
1425 printf(" ");
1426 }
1427
1428 printf(" %12.6f secs ", (double)timestamp/1e9);
1429 if (new_shortname) {
1430 printf("%s => %s:%d\n",
1431 sched_in->shortname, sched_in->comm, sched_in->pid);
1432 } else {
1433 printf("\n");
1434 }
1435}
1436
1437
1438static void
1439process_sched_switch_event(struct raw_event_sample *raw,
1440 struct event *event,
1441 int this_cpu,
1442 u64 timestamp __used,
1443 struct thread *thread __used)
1444{
1445 struct trace_switch_event switch_event;
1446
1447 FILL_COMMON_FIELDS(switch_event, event, raw->data);
1448
1449 FILL_ARRAY(switch_event, prev_comm, event, raw->data);
1450 FILL_FIELD(switch_event, prev_pid, event, raw->data);
1451 FILL_FIELD(switch_event, prev_prio, event, raw->data);
1452 FILL_FIELD(switch_event, prev_state, event, raw->data);
1453 FILL_ARRAY(switch_event, next_comm, event, raw->data);
1454 FILL_FIELD(switch_event, next_pid, event, raw->data);
1455 FILL_FIELD(switch_event, next_prio, event, raw->data);
1456
1457 if (curr_pid[this_cpu] != (u32)-1) {
1458 /*
1459 * Are we trying to switch away a PID that is
1460 * not current?
1461 */
1462 if (curr_pid[this_cpu] != switch_event.prev_pid)
1463 nr_context_switch_bugs++;
1464 }
1465 if (trace_handler->switch_event)
1466 trace_handler->switch_event(&switch_event, event, this_cpu, timestamp, thread);
1467
1468 curr_pid[this_cpu] = switch_event.next_pid;
1469}
1470
1471static void
1472process_sched_runtime_event(struct raw_event_sample *raw,
1473 struct event *event,
1474 int cpu __used,
1475 u64 timestamp __used,
1476 struct thread *thread __used)
1477{
1478 struct trace_runtime_event runtime_event;
1479
1480 FILL_ARRAY(runtime_event, comm, event, raw->data);
1481 FILL_FIELD(runtime_event, pid, event, raw->data);
1482 FILL_FIELD(runtime_event, runtime, event, raw->data);
1483 FILL_FIELD(runtime_event, vruntime, event, raw->data);
1484
1485 if (trace_handler->runtime_event)
1486 trace_handler->runtime_event(&runtime_event, event, cpu, timestamp, thread);
1487}
1488
1489static void
1490process_sched_fork_event(struct raw_event_sample *raw,
1491 struct event *event,
1492 int cpu __used,
1493 u64 timestamp __used,
1494 struct thread *thread __used)
1495{
1496 struct trace_fork_event fork_event;
1497
1498 FILL_COMMON_FIELDS(fork_event, event, raw->data);
1499
1500 FILL_ARRAY(fork_event, parent_comm, event, raw->data);
1501 FILL_FIELD(fork_event, parent_pid, event, raw->data);
1502 FILL_ARRAY(fork_event, child_comm, event, raw->data);
1503 FILL_FIELD(fork_event, child_pid, event, raw->data);
1504
1505 if (trace_handler->fork_event)
1506 trace_handler->fork_event(&fork_event, event, cpu, timestamp, thread);
1507}
1508
1509static void
1510process_sched_exit_event(struct event *event,
1511 int cpu __used,
1512 u64 timestamp __used,
1513 struct thread *thread __used)
1514{
1515 if (verbose)
1516 printf("sched_exit event %p\n", event);
1517}
1518
1519static void
1520process_raw_event(event_t *raw_event __used, void *more_data,
1521 int cpu, u64 timestamp, struct thread *thread)
1522{
1523 struct raw_event_sample *raw = more_data;
1524 struct event *event;
1525 int type;
1526
1527 type = trace_parse_common_type(raw->data);
1528 event = trace_find_event(type);
1529
1530 if (!strcmp(event->name, "sched_switch"))
1531 process_sched_switch_event(raw, event, cpu, timestamp, thread);
1532 if (!strcmp(event->name, "sched_stat_runtime"))
1533 process_sched_runtime_event(raw, event, cpu, timestamp, thread);
1534 if (!strcmp(event->name, "sched_wakeup"))
1535 process_sched_wakeup_event(raw, event, cpu, timestamp, thread);
1536 if (!strcmp(event->name, "sched_wakeup_new"))
1537 process_sched_wakeup_event(raw, event, cpu, timestamp, thread);
1538 if (!strcmp(event->name, "sched_process_fork"))
1539 process_sched_fork_event(raw, event, cpu, timestamp, thread);
1540 if (!strcmp(event->name, "sched_process_exit"))
1541 process_sched_exit_event(event, cpu, timestamp, thread);
1542}
1543
1544static int
1545process_sample_event(event_t *event, unsigned long offset, unsigned long head)
1546{
1547 char level;
1548 int show = 0;
1549 struct dso *dso = NULL;
1550 struct thread *thread;
1551 u64 ip = event->ip.ip;
1552 u64 timestamp = -1;
1553 u32 cpu = -1;
1554 u64 period = 1;
1555 void *more_data = event->ip.__more_data;
1556 int cpumode;
1557
1558 thread = threads__findnew(event->ip.pid, &threads, &last_match);
1559
1560 if (sample_type & PERF_SAMPLE_TIME) {
1561 timestamp = *(u64 *)more_data;
1562 more_data += sizeof(u64);
1563 }
1564
1565 if (sample_type & PERF_SAMPLE_CPU) {
1566 cpu = *(u32 *)more_data;
1567 more_data += sizeof(u32);
1568 more_data += sizeof(u32); /* reserved */
1569 }
1570
1571 if (sample_type & PERF_SAMPLE_PERIOD) {
1572 period = *(u64 *)more_data;
1573 more_data += sizeof(u64);
1574 }
1575
1576 dump_printf("%p [%p]: PERF_RECORD_SAMPLE (IP, %d): %d/%d: %p period: %Ld\n",
1577 (void *)(offset + head),
1578 (void *)(long)(event->header.size),
1579 event->header.misc,
1580 event->ip.pid, event->ip.tid,
1581 (void *)(long)ip,
1582 (long long)period);
1583
1584 dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid);
1585
1586 if (thread == NULL) {
1587 eprintf("problem processing %d event, skipping it.\n",
1588 event->header.type);
1589 return -1;
1590 }
1591
1592 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
1593
1594 if (cpumode == PERF_RECORD_MISC_KERNEL) {
1595 show = SHOW_KERNEL;
1596 level = 'k';
1597
1598 dso = kernel_dso;
1599
1600 dump_printf(" ...... dso: %s\n", dso->name);
1601
1602 } else if (cpumode == PERF_RECORD_MISC_USER) {
1603
1604 show = SHOW_USER;
1605 level = '.';
1606
1607 } else {
1608 show = SHOW_HV;
1609 level = 'H';
1610
1611 dso = hypervisor_dso;
1612
1613 dump_printf(" ...... dso: [hypervisor]\n");
1614 }
1615
1616 if (sample_type & PERF_SAMPLE_RAW)
1617 process_raw_event(event, more_data, cpu, timestamp, thread);
1618
1619 return 0;
1620}
1621
1622static int
1623process_event(event_t *event, unsigned long offset, unsigned long head)
1624{
1625 trace_event(event);
1626
1627 nr_events++;
1628 switch (event->header.type) {
1629 case PERF_RECORD_MMAP:
1630 return 0;
1631 case PERF_RECORD_LOST:
1632 nr_lost_chunks++;
1633 nr_lost_events += event->lost.lost;
1634 return 0;
1635
1636 case PERF_RECORD_COMM:
1637 return process_comm_event(event, offset, head);
1638
1639 case PERF_RECORD_EXIT ... PERF_RECORD_READ:
1640 return 0;
1641
1642 case PERF_RECORD_SAMPLE:
1643 return process_sample_event(event, offset, head);
1644
1645 case PERF_RECORD_MAX:
1646 default:
1647 return -1;
1648 }
1649
1650 return 0;
1651}
1652
1653static int read_events(void)
1654{
1655 int ret, rc = EXIT_FAILURE;
1656 unsigned long offset = 0;
1657 unsigned long head = 0;
1658 struct stat perf_stat;
1659 event_t *event;
1660 uint32_t size;
1661 char *buf;
1662
1663 trace_report();
1664 register_idle_thread(&threads, &last_match);
1665
1666 input = open(input_name, O_RDONLY);
1667 if (input < 0) {
1668 perror("failed to open file");
1669 exit(-1);
1670 }
1671
1672 ret = fstat(input, &perf_stat);
1673 if (ret < 0) {
1674 perror("failed to stat file");
1675 exit(-1);
1676 }
1677
1678 if (!perf_stat.st_size) {
1679 fprintf(stderr, "zero-sized file, nothing to do!\n");
1680 exit(0);
1681 }
1682 header = perf_header__read(input);
1683 head = header->data_offset;
1684 sample_type = perf_header__sample_type(header);
1685
1686 if (!(sample_type & PERF_SAMPLE_RAW))
1687 die("No trace sample to read. Did you call perf record "
1688 "without -R?");
1689
1690 if (load_kernel() < 0) {
1691 perror("failed to load kernel symbols");
1692 return EXIT_FAILURE;
1693 }
1694
1695remap:
1696 buf = (char *)mmap(NULL, page_size * mmap_window, PROT_READ,
1697 MAP_SHARED, input, offset);
1698 if (buf == MAP_FAILED) {
1699 perror("failed to mmap file");
1700 exit(-1);
1701 }
1702
1703more:
1704 event = (event_t *)(buf + head);
1705
1706 size = event->header.size;
1707 if (!size)
1708 size = 8;
1709
1710 if (head + event->header.size >= page_size * mmap_window) {
1711 unsigned long shift = page_size * (head / page_size);
1712 int res;
1713
1714 res = munmap(buf, page_size * mmap_window);
1715 assert(res == 0);
1716
1717 offset += shift;
1718 head -= shift;
1719 goto remap;
1720 }
1721
1722 size = event->header.size;
1723
1724
1725 if (!size || process_event(event, offset, head) < 0) {
1726
1727 /*
1728 * assume we lost track of the stream, check alignment, and
1729 * increment a single u64 in the hope to catch on again 'soon'.
1730 */
1731
1732 if (unlikely(head & 7))
1733 head &= ~7ULL;
1734
1735 size = 8;
1736 }
1737
1738 head += size;
1739
1740 if (offset + head < (unsigned long)perf_stat.st_size)
1741 goto more;
1742
1743 rc = EXIT_SUCCESS;
1744 close(input);
1745
1746 return rc;
1747}
1748
1749static void print_bad_events(void)
1750{
1751 if (nr_unordered_timestamps && nr_timestamps) {
1752 printf(" INFO: %.3f%% unordered timestamps (%ld out of %ld)\n",
1753 (double)nr_unordered_timestamps/(double)nr_timestamps*100.0,
1754 nr_unordered_timestamps, nr_timestamps);
1755 }
1756 if (nr_lost_events && nr_events) {
1757 printf(" INFO: %.3f%% lost events (%ld out of %ld, in %ld chunks)\n",
1758 (double)nr_lost_events/(double)nr_events*100.0,
1759 nr_lost_events, nr_events, nr_lost_chunks);
1760 }
1761 if (nr_state_machine_bugs && nr_timestamps) {
1762 printf(" INFO: %.3f%% state machine bugs (%ld out of %ld)",
1763 (double)nr_state_machine_bugs/(double)nr_timestamps*100.0,
1764 nr_state_machine_bugs, nr_timestamps);
1765 if (nr_lost_events)
1766 printf(" (due to lost events?)");
1767 printf("\n");
1768 }
1769 if (nr_context_switch_bugs && nr_timestamps) {
1770 printf(" INFO: %.3f%% context switch bugs (%ld out of %ld)",
1771 (double)nr_context_switch_bugs/(double)nr_timestamps*100.0,
1772 nr_context_switch_bugs, nr_timestamps);
1773 if (nr_lost_events)
1774 printf(" (due to lost events?)");
1775 printf("\n");
1776 }
1777}
1778
1779static void __cmd_lat(void)
1780{
1781 struct rb_node *next;
1782
1783 setup_pager();
1784 read_events();
1785 sort_lat();
1786
1787 printf("\n -----------------------------------------------------------------------------------------\n");
1788 printf(" Task | Runtime ms | Switches | Average delay ms | Maximum delay ms |\n");
1789 printf(" -----------------------------------------------------------------------------------------\n");
1790
1791 next = rb_first(&sorted_atom_root);
1792
1793 while (next) {
1794 struct work_atoms *work_list;
1795
1796 work_list = rb_entry(next, struct work_atoms, node);
1797 output_lat_thread(work_list);
1798 next = rb_next(next);
1799 }
1800
1801 printf(" -----------------------------------------------------------------------------------------\n");
1802 printf(" TOTAL: |%11.3f ms |%9Ld |\n",
1803 (double)all_runtime/1e6, all_count);
1804
1805 printf(" ---------------------------------------------------\n");
1806
1807 print_bad_events();
1808 printf("\n");
1809
1810}
1811
1812static struct trace_sched_handler map_ops = {
1813 .wakeup_event = NULL,
1814 .switch_event = map_switch_event,
1815 .runtime_event = NULL,
1816 .fork_event = NULL,
1817};
1818
1819static void __cmd_map(void)
1820{
1821 max_cpu = sysconf(_SC_NPROCESSORS_CONF);
1822
1823 setup_pager();
1824 read_events();
1825 print_bad_events();
1826}
1827
1828static void __cmd_replay(void)
1829{
1830 unsigned long i;
1831
1832 calibrate_run_measurement_overhead();
1833 calibrate_sleep_measurement_overhead();
1834
1835 test_calibrations();
1836
1837 read_events();
1838
1839 printf("nr_run_events: %ld\n", nr_run_events);
1840 printf("nr_sleep_events: %ld\n", nr_sleep_events);
1841 printf("nr_wakeup_events: %ld\n", nr_wakeup_events);
1842
1843 if (targetless_wakeups)
1844 printf("target-less wakeups: %ld\n", targetless_wakeups);
1845 if (multitarget_wakeups)
1846 printf("multi-target wakeups: %ld\n", multitarget_wakeups);
1847 if (nr_run_events_optimized)
1848 printf("run atoms optimized: %ld\n",
1849 nr_run_events_optimized);
1850
1851 print_task_traces();
1852 add_cross_task_wakeups();
1853
1854 create_tasks();
1855 printf("------------------------------------------------------------\n");
1856 for (i = 0; i < replay_repeat; i++)
1857 run_one_test();
1858}
1859
1860
1861static const char * const sched_usage[] = {
1862 "perf sched [<options>] {record|latency|map|replay|trace}",
1863 NULL
1864};
1865
1866static const struct option sched_options[] = {
1867 OPT_STRING('i', "input", &input_name, "file",
1868 "input file name"),
1869 OPT_BOOLEAN('v', "verbose", &verbose,
1870 "be more verbose (show symbol address, etc)"),
1871 OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace,
1872 "dump raw trace in ASCII"),
1873 OPT_END()
1874};
1875
1876static const char * const latency_usage[] = {
1877 "perf sched latency [<options>]",
1878 NULL
1879};
1880
1881static const struct option latency_options[] = {
1882 OPT_STRING('s', "sort", &sort_order, "key[,key2...]",
1883 "sort by key(s): runtime, switch, avg, max"),
1884 OPT_BOOLEAN('v', "verbose", &verbose,
1885 "be more verbose (show symbol address, etc)"),
1886 OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace,
1887 "dump raw trace in ASCII"),
1888 OPT_END()
1889};
1890
1891static const char * const replay_usage[] = {
1892 "perf sched replay [<options>]",
1893 NULL
1894};
1895
1896static const struct option replay_options[] = {
1897 OPT_INTEGER('r', "repeat", &replay_repeat,
1898 "repeat the workload replay N times (-1: infinite)"),
1899 OPT_BOOLEAN('v', "verbose", &verbose,
1900 "be more verbose (show symbol address, etc)"),
1901 OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace,
1902 "dump raw trace in ASCII"),
1903 OPT_END()
1904};
1905
1906static void setup_sorting(void)
1907{
1908 char *tmp, *tok, *str = strdup(sort_order);
1909
1910 for (tok = strtok_r(str, ", ", &tmp);
1911 tok; tok = strtok_r(NULL, ", ", &tmp)) {
1912 if (sort_dimension__add(tok, &sort_list) < 0) {
1913 error("Unknown --sort key: `%s'", tok);
1914 usage_with_options(latency_usage, latency_options);
1915 }
1916 }
1917
1918 free(str);
1919
1920 sort_dimension__add((char *)"pid", &cmp_pid);
1921}
1922
1923static const char *record_args[] = {
1924 "record",
1925 "-a",
1926 "-R",
1927 "-M",
1928 "-f",
1929 "-m", "1024",
1930 "-c", "1",
1931 "-e", "sched:sched_switch:r",
1932 "-e", "sched:sched_stat_wait:r",
1933 "-e", "sched:sched_stat_sleep:r",
1934 "-e", "sched:sched_stat_iowait:r",
1935 "-e", "sched:sched_stat_runtime:r",
1936 "-e", "sched:sched_process_exit:r",
1937 "-e", "sched:sched_process_fork:r",
1938 "-e", "sched:sched_wakeup:r",
1939 "-e", "sched:sched_migrate_task:r",
1940};
1941
1942static int __cmd_record(int argc, const char **argv)
1943{
1944 unsigned int rec_argc, i, j;
1945 const char **rec_argv;
1946
1947 rec_argc = ARRAY_SIZE(record_args) + argc - 1;
1948 rec_argv = calloc(rec_argc + 1, sizeof(char *));
1949
1950 for (i = 0; i < ARRAY_SIZE(record_args); i++)
1951 rec_argv[i] = strdup(record_args[i]);
1952
1953 for (j = 1; j < (unsigned int)argc; j++, i++)
1954 rec_argv[i] = argv[j];
1955
1956 BUG_ON(i != rec_argc);
1957
1958 return cmd_record(i, rec_argv, NULL);
1959}
1960
1961int cmd_sched(int argc, const char **argv, const char *prefix __used)
1962{
1963 symbol__init();
1964 page_size = getpagesize();
1965
1966 argc = parse_options(argc, argv, sched_options, sched_usage,
1967 PARSE_OPT_STOP_AT_NON_OPTION);
1968 if (!argc)
1969 usage_with_options(sched_usage, sched_options);
1970
1971 if (!strncmp(argv[0], "rec", 3)) {
1972 return __cmd_record(argc, argv);
1973 } else if (!strncmp(argv[0], "lat", 3)) {
1974 trace_handler = &lat_ops;
1975 if (argc > 1) {
1976 argc = parse_options(argc, argv, latency_options, latency_usage, 0);
1977 if (argc)
1978 usage_with_options(latency_usage, latency_options);
1979 }
1980 setup_sorting();
1981 __cmd_lat();
1982 } else if (!strcmp(argv[0], "map")) {
1983 trace_handler = &map_ops;
1984 setup_sorting();
1985 __cmd_map();
1986 } else if (!strncmp(argv[0], "rep", 3)) {
1987 trace_handler = &replay_ops;
1988 if (argc) {
1989 argc = parse_options(argc, argv, replay_options, replay_usage, 0);
1990 if (argc)
1991 usage_with_options(replay_usage, replay_options);
1992 }
1993 __cmd_replay();
1994 } else if (!strcmp(argv[0], "trace")) {
1995 /*
1996 * Aliased to 'perf trace' for now:
1997 */
1998 return cmd_trace(argc, argv, prefix);
1999 } else {
2000 usage_with_options(sched_usage, sched_options);
2001 }
2002
2003 return 0;
2004}
diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c
index b4b06c7903e1..e5f6ece65a13 100644
--- a/tools/perf/builtin-stat.c
+++ b/tools/perf/builtin-stat.c
@@ -42,11 +42,13 @@
42#include "util/util.h" 42#include "util/util.h"
43#include "util/parse-options.h" 43#include "util/parse-options.h"
44#include "util/parse-events.h" 44#include "util/parse-events.h"
45#include "util/event.h"
46#include "util/debug.h"
45 47
46#include <sys/prctl.h> 48#include <sys/prctl.h>
47#include <math.h> 49#include <math.h>
48 50
49static struct perf_counter_attr default_attrs[] = { 51static struct perf_event_attr default_attrs[] = {
50 52
51 { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_TASK_CLOCK }, 53 { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_TASK_CLOCK },
52 { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_CONTEXT_SWITCHES}, 54 { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_CONTEXT_SWITCHES},
@@ -60,10 +62,7 @@ static struct perf_counter_attr default_attrs[] = {
60 62
61}; 63};
62 64
63#define MAX_RUN 100
64
65static int system_wide = 0; 65static int system_wide = 0;
66static int verbose = 0;
67static unsigned int nr_cpus = 0; 66static unsigned int nr_cpus = 0;
68static int run_idx = 0; 67static int run_idx = 0;
69 68
@@ -75,37 +74,67 @@ static int null_run = 0;
75 74
76static int fd[MAX_NR_CPUS][MAX_COUNTERS]; 75static int fd[MAX_NR_CPUS][MAX_COUNTERS];
77 76
78static u64 runtime_nsecs[MAX_RUN]; 77static int event_scaled[MAX_COUNTERS];
79static u64 walltime_nsecs[MAX_RUN]; 78
80static u64 runtime_cycles[MAX_RUN]; 79struct stats
80{
81 double n, mean, M2;
82};
81 83
82static u64 event_res[MAX_RUN][MAX_COUNTERS][3]; 84static void update_stats(struct stats *stats, u64 val)
83static u64 event_scaled[MAX_RUN][MAX_COUNTERS]; 85{
86 double delta;
84 87
85static u64 event_res_avg[MAX_COUNTERS][3]; 88 stats->n++;
86static u64 event_res_noise[MAX_COUNTERS][3]; 89 delta = val - stats->mean;
90 stats->mean += delta / stats->n;
91 stats->M2 += delta*(val - stats->mean);
92}
87 93
88static u64 event_scaled_avg[MAX_COUNTERS]; 94static double avg_stats(struct stats *stats)
95{
96 return stats->mean;
97}
89 98
90static u64 runtime_nsecs_avg; 99/*
91static u64 runtime_nsecs_noise; 100 * http://en.wikipedia.org/wiki/Algorithms_for_calculating_variance
101 *
102 * (\Sum n_i^2) - ((\Sum n_i)^2)/n
103 * s^2 = -------------------------------
104 * n - 1
105 *
106 * http://en.wikipedia.org/wiki/Stddev
107 *
108 * The std dev of the mean is related to the std dev by:
109 *
110 * s
111 * s_mean = -------
112 * sqrt(n)
113 *
114 */
115static double stddev_stats(struct stats *stats)
116{
117 double variance = stats->M2 / (stats->n - 1);
118 double variance_mean = variance / stats->n;
92 119
93static u64 walltime_nsecs_avg; 120 return sqrt(variance_mean);
94static u64 walltime_nsecs_noise; 121}
95 122
96static u64 runtime_cycles_avg; 123struct stats event_res_stats[MAX_COUNTERS][3];
97static u64 runtime_cycles_noise; 124struct stats runtime_nsecs_stats;
125struct stats walltime_nsecs_stats;
126struct stats runtime_cycles_stats;
98 127
99#define MATCH_EVENT(t, c, counter) \ 128#define MATCH_EVENT(t, c, counter) \
100 (attrs[counter].type == PERF_TYPE_##t && \ 129 (attrs[counter].type == PERF_TYPE_##t && \
101 attrs[counter].config == PERF_COUNT_##c) 130 attrs[counter].config == PERF_COUNT_##c)
102 131
103#define ERR_PERF_OPEN \ 132#define ERR_PERF_OPEN \
104"Error: counter %d, sys_perf_counter_open() syscall returned with %d (%s)\n" 133"Error: counter %d, sys_perf_event_open() syscall returned with %d (%s)\n"
105 134
106static void create_perf_stat_counter(int counter, int pid) 135static void create_perf_stat_counter(int counter, int pid)
107{ 136{
108 struct perf_counter_attr *attr = attrs + counter; 137 struct perf_event_attr *attr = attrs + counter;
109 138
110 if (scale) 139 if (scale)
111 attr->read_format = PERF_FORMAT_TOTAL_TIME_ENABLED | 140 attr->read_format = PERF_FORMAT_TOTAL_TIME_ENABLED |
@@ -115,7 +144,7 @@ static void create_perf_stat_counter(int counter, int pid)
115 unsigned int cpu; 144 unsigned int cpu;
116 145
117 for (cpu = 0; cpu < nr_cpus; cpu++) { 146 for (cpu = 0; cpu < nr_cpus; cpu++) {
118 fd[cpu][counter] = sys_perf_counter_open(attr, -1, cpu, -1, 0); 147 fd[cpu][counter] = sys_perf_event_open(attr, -1, cpu, -1, 0);
119 if (fd[cpu][counter] < 0 && verbose) 148 if (fd[cpu][counter] < 0 && verbose)
120 fprintf(stderr, ERR_PERF_OPEN, counter, 149 fprintf(stderr, ERR_PERF_OPEN, counter,
121 fd[cpu][counter], strerror(errno)); 150 fd[cpu][counter], strerror(errno));
@@ -125,7 +154,7 @@ static void create_perf_stat_counter(int counter, int pid)
125 attr->disabled = 1; 154 attr->disabled = 1;
126 attr->enable_on_exec = 1; 155 attr->enable_on_exec = 1;
127 156
128 fd[0][counter] = sys_perf_counter_open(attr, pid, -1, -1, 0); 157 fd[0][counter] = sys_perf_event_open(attr, pid, -1, -1, 0);
129 if (fd[0][counter] < 0 && verbose) 158 if (fd[0][counter] < 0 && verbose)
130 fprintf(stderr, ERR_PERF_OPEN, counter, 159 fprintf(stderr, ERR_PERF_OPEN, counter,
131 fd[0][counter], strerror(errno)); 160 fd[0][counter], strerror(errno));
@@ -149,12 +178,11 @@ static inline int nsec_counter(int counter)
149 */ 178 */
150static void read_counter(int counter) 179static void read_counter(int counter)
151{ 180{
152 u64 *count, single_count[3]; 181 u64 count[3], single_count[3];
153 unsigned int cpu; 182 unsigned int cpu;
154 size_t res, nv; 183 size_t res, nv;
155 int scaled; 184 int scaled;
156 185 int i;
157 count = event_res[run_idx][counter];
158 186
159 count[0] = count[1] = count[2] = 0; 187 count[0] = count[1] = count[2] = 0;
160 188
@@ -179,24 +207,33 @@ static void read_counter(int counter)
179 scaled = 0; 207 scaled = 0;
180 if (scale) { 208 if (scale) {
181 if (count[2] == 0) { 209 if (count[2] == 0) {
182 event_scaled[run_idx][counter] = -1; 210 event_scaled[counter] = -1;
183 count[0] = 0; 211 count[0] = 0;
184 return; 212 return;
185 } 213 }
186 214
187 if (count[2] < count[1]) { 215 if (count[2] < count[1]) {
188 event_scaled[run_idx][counter] = 1; 216 event_scaled[counter] = 1;
189 count[0] = (unsigned long long) 217 count[0] = (unsigned long long)
190 ((double)count[0] * count[1] / count[2] + 0.5); 218 ((double)count[0] * count[1] / count[2] + 0.5);
191 } 219 }
192 } 220 }
221
222 for (i = 0; i < 3; i++)
223 update_stats(&event_res_stats[counter][i], count[i]);
224
225 if (verbose) {
226 fprintf(stderr, "%s: %Ld %Ld %Ld\n", event_name(counter),
227 count[0], count[1], count[2]);
228 }
229
193 /* 230 /*
194 * Save the full runtime - to allow normalization during printout: 231 * Save the full runtime - to allow normalization during printout:
195 */ 232 */
196 if (MATCH_EVENT(SOFTWARE, SW_TASK_CLOCK, counter)) 233 if (MATCH_EVENT(SOFTWARE, SW_TASK_CLOCK, counter))
197 runtime_nsecs[run_idx] = count[0]; 234 update_stats(&runtime_nsecs_stats, count[0]);
198 if (MATCH_EVENT(HARDWARE, HW_CPU_CYCLES, counter)) 235 if (MATCH_EVENT(HARDWARE, HW_CPU_CYCLES, counter))
199 runtime_cycles[run_idx] = count[0]; 236 update_stats(&runtime_cycles_stats, count[0]);
200} 237}
201 238
202static int run_perf_stat(int argc __used, const char **argv) 239static int run_perf_stat(int argc __used, const char **argv)
@@ -270,7 +307,7 @@ static int run_perf_stat(int argc __used, const char **argv)
270 307
271 t1 = rdclock(); 308 t1 = rdclock();
272 309
273 walltime_nsecs[run_idx] = t1 - t0; 310 update_stats(&walltime_nsecs_stats, t1 - t0);
274 311
275 for (counter = 0; counter < nr_counters; counter++) 312 for (counter = 0; counter < nr_counters; counter++)
276 read_counter(counter); 313 read_counter(counter);
@@ -278,42 +315,48 @@ static int run_perf_stat(int argc __used, const char **argv)
278 return WEXITSTATUS(status); 315 return WEXITSTATUS(status);
279} 316}
280 317
281static void print_noise(u64 *count, u64 *noise) 318static void print_noise(int counter, double avg)
282{ 319{
283 if (run_count > 1) 320 if (run_count == 1)
284 fprintf(stderr, " ( +- %7.3f%% )", 321 return;
285 (double)noise[0]/(count[0]+1)*100.0); 322
323 fprintf(stderr, " ( +- %7.3f%% )",
324 100 * stddev_stats(&event_res_stats[counter][0]) / avg);
286} 325}
287 326
288static void nsec_printout(int counter, u64 *count, u64 *noise) 327static void nsec_printout(int counter, double avg)
289{ 328{
290 double msecs = (double)count[0] / 1000000; 329 double msecs = avg / 1e6;
291 330
292 fprintf(stderr, " %14.6f %-24s", msecs, event_name(counter)); 331 fprintf(stderr, " %14.6f %-24s", msecs, event_name(counter));
293 332
294 if (MATCH_EVENT(SOFTWARE, SW_TASK_CLOCK, counter)) { 333 if (MATCH_EVENT(SOFTWARE, SW_TASK_CLOCK, counter)) {
295 if (walltime_nsecs_avg) 334 fprintf(stderr, " # %10.3f CPUs ",
296 fprintf(stderr, " # %10.3f CPUs ", 335 avg / avg_stats(&walltime_nsecs_stats));
297 (double)count[0] / (double)walltime_nsecs_avg);
298 } 336 }
299 print_noise(count, noise);
300} 337}
301 338
302static void abs_printout(int counter, u64 *count, u64 *noise) 339static void abs_printout(int counter, double avg)
303{ 340{
304 fprintf(stderr, " %14Ld %-24s", count[0], event_name(counter)); 341 double total, ratio = 0.0;
342
343 fprintf(stderr, " %14.0f %-24s", avg, event_name(counter));
305 344
306 if (runtime_cycles_avg && 345 if (MATCH_EVENT(HARDWARE, HW_INSTRUCTIONS, counter)) {
307 MATCH_EVENT(HARDWARE, HW_INSTRUCTIONS, counter)) { 346 total = avg_stats(&runtime_cycles_stats);
308 fprintf(stderr, " # %10.3f IPC ", 347
309 (double)count[0] / (double)runtime_cycles_avg); 348 if (total)
349 ratio = avg / total;
350
351 fprintf(stderr, " # %10.3f IPC ", ratio);
310 } else { 352 } else {
311 if (runtime_nsecs_avg) { 353 total = avg_stats(&runtime_nsecs_stats);
312 fprintf(stderr, " # %10.3f M/sec", 354
313 (double)count[0]/runtime_nsecs_avg*1000.0); 355 if (total)
314 } 356 ratio = 1000.0 * avg / total;
357
358 fprintf(stderr, " # %10.3f M/sec", ratio);
315 } 359 }
316 print_noise(count, noise);
317} 360}
318 361
319/* 362/*
@@ -321,12 +364,8 @@ static void abs_printout(int counter, u64 *count, u64 *noise)
321 */ 364 */
322static void print_counter(int counter) 365static void print_counter(int counter)
323{ 366{
324 u64 *count, *noise; 367 double avg = avg_stats(&event_res_stats[counter][0]);
325 int scaled; 368 int scaled = event_scaled[counter];
326
327 count = event_res_avg[counter];
328 noise = event_res_noise[counter];
329 scaled = event_scaled_avg[counter];
330 369
331 if (scaled == -1) { 370 if (scaled == -1) {
332 fprintf(stderr, " %14s %-24s\n", 371 fprintf(stderr, " %14s %-24s\n",
@@ -335,110 +374,29 @@ static void print_counter(int counter)
335 } 374 }
336 375
337 if (nsec_counter(counter)) 376 if (nsec_counter(counter))
338 nsec_printout(counter, count, noise); 377 nsec_printout(counter, avg);
339 else 378 else
340 abs_printout(counter, count, noise); 379 abs_printout(counter, avg);
341 380
342 if (scaled) 381 print_noise(counter, avg);
343 fprintf(stderr, " (scaled from %.2f%%)",
344 (double) count[2] / count[1] * 100);
345 382
346 fprintf(stderr, "\n"); 383 if (scaled) {
347} 384 double avg_enabled, avg_running;
348 385
349/* 386 avg_enabled = avg_stats(&event_res_stats[counter][1]);
350 * normalize_noise noise values down to stddev: 387 avg_running = avg_stats(&event_res_stats[counter][2]);
351 */
352static void normalize_noise(u64 *val)
353{
354 double res;
355
356 res = (double)*val / (run_count * sqrt((double)run_count));
357
358 *val = (u64)res;
359}
360
361static void update_avg(const char *name, int idx, u64 *avg, u64 *val)
362{
363 *avg += *val;
364 388
365 if (verbose > 1) 389 fprintf(stderr, " (scaled from %.2f%%)",
366 fprintf(stderr, "debug: %20s[%d]: %Ld\n", name, idx, *val); 390 100 * avg_running / avg_enabled);
367}
368/*
369 * Calculate the averages and noises:
370 */
371static void calc_avg(void)
372{
373 int i, j;
374
375 if (verbose > 1)
376 fprintf(stderr, "\n");
377
378 for (i = 0; i < run_count; i++) {
379 update_avg("runtime", 0, &runtime_nsecs_avg, runtime_nsecs + i);
380 update_avg("walltime", 0, &walltime_nsecs_avg, walltime_nsecs + i);
381 update_avg("runtime_cycles", 0, &runtime_cycles_avg, runtime_cycles + i);
382
383 for (j = 0; j < nr_counters; j++) {
384 update_avg("counter/0", j,
385 event_res_avg[j]+0, event_res[i][j]+0);
386 update_avg("counter/1", j,
387 event_res_avg[j]+1, event_res[i][j]+1);
388 update_avg("counter/2", j,
389 event_res_avg[j]+2, event_res[i][j]+2);
390 if (event_scaled[i][j] != (u64)-1)
391 update_avg("scaled", j,
392 event_scaled_avg + j, event_scaled[i]+j);
393 else
394 event_scaled_avg[j] = -1;
395 }
396 }
397 runtime_nsecs_avg /= run_count;
398 walltime_nsecs_avg /= run_count;
399 runtime_cycles_avg /= run_count;
400
401 for (j = 0; j < nr_counters; j++) {
402 event_res_avg[j][0] /= run_count;
403 event_res_avg[j][1] /= run_count;
404 event_res_avg[j][2] /= run_count;
405 }
406
407 for (i = 0; i < run_count; i++) {
408 runtime_nsecs_noise +=
409 abs((s64)(runtime_nsecs[i] - runtime_nsecs_avg));
410 walltime_nsecs_noise +=
411 abs((s64)(walltime_nsecs[i] - walltime_nsecs_avg));
412 runtime_cycles_noise +=
413 abs((s64)(runtime_cycles[i] - runtime_cycles_avg));
414
415 for (j = 0; j < nr_counters; j++) {
416 event_res_noise[j][0] +=
417 abs((s64)(event_res[i][j][0] - event_res_avg[j][0]));
418 event_res_noise[j][1] +=
419 abs((s64)(event_res[i][j][1] - event_res_avg[j][1]));
420 event_res_noise[j][2] +=
421 abs((s64)(event_res[i][j][2] - event_res_avg[j][2]));
422 }
423 } 391 }
424 392
425 normalize_noise(&runtime_nsecs_noise); 393 fprintf(stderr, "\n");
426 normalize_noise(&walltime_nsecs_noise);
427 normalize_noise(&runtime_cycles_noise);
428
429 for (j = 0; j < nr_counters; j++) {
430 normalize_noise(&event_res_noise[j][0]);
431 normalize_noise(&event_res_noise[j][1]);
432 normalize_noise(&event_res_noise[j][2]);
433 }
434} 394}
435 395
436static void print_stat(int argc, const char **argv) 396static void print_stat(int argc, const char **argv)
437{ 397{
438 int i, counter; 398 int i, counter;
439 399
440 calc_avg();
441
442 fflush(stdout); 400 fflush(stdout);
443 401
444 fprintf(stderr, "\n"); 402 fprintf(stderr, "\n");
@@ -457,10 +415,11 @@ static void print_stat(int argc, const char **argv)
457 415
458 fprintf(stderr, "\n"); 416 fprintf(stderr, "\n");
459 fprintf(stderr, " %14.9f seconds time elapsed", 417 fprintf(stderr, " %14.9f seconds time elapsed",
460 (double)walltime_nsecs_avg/1e9); 418 avg_stats(&walltime_nsecs_stats)/1e9);
461 if (run_count > 1) { 419 if (run_count > 1) {
462 fprintf(stderr, " ( +- %7.3f%% )", 420 fprintf(stderr, " ( +- %7.3f%% )",
463 100.0*(double)walltime_nsecs_noise/(double)walltime_nsecs_avg); 421 100*stddev_stats(&walltime_nsecs_stats) /
422 avg_stats(&walltime_nsecs_stats));
464 } 423 }
465 fprintf(stderr, "\n\n"); 424 fprintf(stderr, "\n\n");
466} 425}
@@ -515,7 +474,7 @@ int cmd_stat(int argc, const char **argv, const char *prefix __used)
515 PARSE_OPT_STOP_AT_NON_OPTION); 474 PARSE_OPT_STOP_AT_NON_OPTION);
516 if (!argc) 475 if (!argc)
517 usage_with_options(stat_usage, options); 476 usage_with_options(stat_usage, options);
518 if (run_count <= 0 || run_count > MAX_RUN) 477 if (run_count <= 0)
519 usage_with_options(stat_usage, options); 478 usage_with_options(stat_usage, options);
520 479
521 /* Set attrs and nr_counters if no event is selected and !null_run */ 480 /* Set attrs and nr_counters if no event is selected and !null_run */
diff --git a/tools/perf/builtin-timechart.c b/tools/perf/builtin-timechart.c
new file mode 100644
index 000000000000..4405681b3134
--- /dev/null
+++ b/tools/perf/builtin-timechart.c
@@ -0,0 +1,1158 @@
1/*
2 * builtin-timechart.c - make an svg timechart of system activity
3 *
4 * (C) Copyright 2009 Intel Corporation
5 *
6 * Authors:
7 * Arjan van de Ven <arjan@linux.intel.com>
8 *
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License
11 * as published by the Free Software Foundation; version 2
12 * of the License.
13 */
14
15#include "builtin.h"
16
17#include "util/util.h"
18
19#include "util/color.h"
20#include <linux/list.h>
21#include "util/cache.h"
22#include <linux/rbtree.h>
23#include "util/symbol.h"
24#include "util/string.h"
25#include "util/callchain.h"
26#include "util/strlist.h"
27
28#include "perf.h"
29#include "util/header.h"
30#include "util/parse-options.h"
31#include "util/parse-events.h"
32#include "util/svghelper.h"
33
34static char const *input_name = "perf.data";
35static char const *output_name = "output.svg";
36
37
38static unsigned long page_size;
39static unsigned long mmap_window = 32;
40static u64 sample_type;
41
42static unsigned int numcpus;
43static u64 min_freq; /* Lowest CPU frequency seen */
44static u64 max_freq; /* Highest CPU frequency seen */
45static u64 turbo_frequency;
46
47static u64 first_time, last_time;
48
49
50static struct perf_header *header;
51
52struct per_pid;
53struct per_pidcomm;
54
55struct cpu_sample;
56struct power_event;
57struct wake_event;
58
59struct sample_wrapper;
60
61/*
62 * Datastructure layout:
63 * We keep an list of "pid"s, matching the kernels notion of a task struct.
64 * Each "pid" entry, has a list of "comm"s.
65 * this is because we want to track different programs different, while
66 * exec will reuse the original pid (by design).
67 * Each comm has a list of samples that will be used to draw
68 * final graph.
69 */
70
71struct per_pid {
72 struct per_pid *next;
73
74 int pid;
75 int ppid;
76
77 u64 start_time;
78 u64 end_time;
79 u64 total_time;
80 int display;
81
82 struct per_pidcomm *all;
83 struct per_pidcomm *current;
84
85 int painted;
86};
87
88
89struct per_pidcomm {
90 struct per_pidcomm *next;
91
92 u64 start_time;
93 u64 end_time;
94 u64 total_time;
95
96 int Y;
97 int display;
98
99 long state;
100 u64 state_since;
101
102 char *comm;
103
104 struct cpu_sample *samples;
105};
106
107struct sample_wrapper {
108 struct sample_wrapper *next;
109
110 u64 timestamp;
111 unsigned char data[0];
112};
113
114#define TYPE_NONE 0
115#define TYPE_RUNNING 1
116#define TYPE_WAITING 2
117#define TYPE_BLOCKED 3
118
119struct cpu_sample {
120 struct cpu_sample *next;
121
122 u64 start_time;
123 u64 end_time;
124 int type;
125 int cpu;
126};
127
128static struct per_pid *all_data;
129
130#define CSTATE 1
131#define PSTATE 2
132
133struct power_event {
134 struct power_event *next;
135 int type;
136 int state;
137 u64 start_time;
138 u64 end_time;
139 int cpu;
140};
141
142struct wake_event {
143 struct wake_event *next;
144 int waker;
145 int wakee;
146 u64 time;
147};
148
149static struct power_event *power_events;
150static struct wake_event *wake_events;
151
152struct sample_wrapper *all_samples;
153
154static struct per_pid *find_create_pid(int pid)
155{
156 struct per_pid *cursor = all_data;
157
158 while (cursor) {
159 if (cursor->pid == pid)
160 return cursor;
161 cursor = cursor->next;
162 }
163 cursor = malloc(sizeof(struct per_pid));
164 assert(cursor != NULL);
165 memset(cursor, 0, sizeof(struct per_pid));
166 cursor->pid = pid;
167 cursor->next = all_data;
168 all_data = cursor;
169 return cursor;
170}
171
172static void pid_set_comm(int pid, char *comm)
173{
174 struct per_pid *p;
175 struct per_pidcomm *c;
176 p = find_create_pid(pid);
177 c = p->all;
178 while (c) {
179 if (c->comm && strcmp(c->comm, comm) == 0) {
180 p->current = c;
181 return;
182 }
183 if (!c->comm) {
184 c->comm = strdup(comm);
185 p->current = c;
186 return;
187 }
188 c = c->next;
189 }
190 c = malloc(sizeof(struct per_pidcomm));
191 assert(c != NULL);
192 memset(c, 0, sizeof(struct per_pidcomm));
193 c->comm = strdup(comm);
194 p->current = c;
195 c->next = p->all;
196 p->all = c;
197}
198
199static void pid_fork(int pid, int ppid, u64 timestamp)
200{
201 struct per_pid *p, *pp;
202 p = find_create_pid(pid);
203 pp = find_create_pid(ppid);
204 p->ppid = ppid;
205 if (pp->current && pp->current->comm && !p->current)
206 pid_set_comm(pid, pp->current->comm);
207
208 p->start_time = timestamp;
209 if (p->current) {
210 p->current->start_time = timestamp;
211 p->current->state_since = timestamp;
212 }
213}
214
215static void pid_exit(int pid, u64 timestamp)
216{
217 struct per_pid *p;
218 p = find_create_pid(pid);
219 p->end_time = timestamp;
220 if (p->current)
221 p->current->end_time = timestamp;
222}
223
224static void
225pid_put_sample(int pid, int type, unsigned int cpu, u64 start, u64 end)
226{
227 struct per_pid *p;
228 struct per_pidcomm *c;
229 struct cpu_sample *sample;
230
231 p = find_create_pid(pid);
232 c = p->current;
233 if (!c) {
234 c = malloc(sizeof(struct per_pidcomm));
235 assert(c != NULL);
236 memset(c, 0, sizeof(struct per_pidcomm));
237 p->current = c;
238 c->next = p->all;
239 p->all = c;
240 }
241
242 sample = malloc(sizeof(struct cpu_sample));
243 assert(sample != NULL);
244 memset(sample, 0, sizeof(struct cpu_sample));
245 sample->start_time = start;
246 sample->end_time = end;
247 sample->type = type;
248 sample->next = c->samples;
249 sample->cpu = cpu;
250 c->samples = sample;
251
252 if (sample->type == TYPE_RUNNING && end > start && start > 0) {
253 c->total_time += (end-start);
254 p->total_time += (end-start);
255 }
256
257 if (c->start_time == 0 || c->start_time > start)
258 c->start_time = start;
259 if (p->start_time == 0 || p->start_time > start)
260 p->start_time = start;
261
262 if (cpu > numcpus)
263 numcpus = cpu;
264}
265
266#define MAX_CPUS 4096
267
268static u64 cpus_cstate_start_times[MAX_CPUS];
269static int cpus_cstate_state[MAX_CPUS];
270static u64 cpus_pstate_start_times[MAX_CPUS];
271static u64 cpus_pstate_state[MAX_CPUS];
272
273static int
274process_comm_event(event_t *event)
275{
276 pid_set_comm(event->comm.pid, event->comm.comm);
277 return 0;
278}
279static int
280process_fork_event(event_t *event)
281{
282 pid_fork(event->fork.pid, event->fork.ppid, event->fork.time);
283 return 0;
284}
285
286static int
287process_exit_event(event_t *event)
288{
289 pid_exit(event->fork.pid, event->fork.time);
290 return 0;
291}
292
293struct trace_entry {
294 u32 size;
295 unsigned short type;
296 unsigned char flags;
297 unsigned char preempt_count;
298 int pid;
299 int tgid;
300};
301
302struct power_entry {
303 struct trace_entry te;
304 s64 type;
305 s64 value;
306};
307
308#define TASK_COMM_LEN 16
309struct wakeup_entry {
310 struct trace_entry te;
311 char comm[TASK_COMM_LEN];
312 int pid;
313 int prio;
314 int success;
315};
316
317/*
318 * trace_flag_type is an enumeration that holds different
319 * states when a trace occurs. These are:
320 * IRQS_OFF - interrupts were disabled
321 * IRQS_NOSUPPORT - arch does not support irqs_disabled_flags
322 * NEED_RESCED - reschedule is requested
323 * HARDIRQ - inside an interrupt handler
324 * SOFTIRQ - inside a softirq handler
325 */
326enum trace_flag_type {
327 TRACE_FLAG_IRQS_OFF = 0x01,
328 TRACE_FLAG_IRQS_NOSUPPORT = 0x02,
329 TRACE_FLAG_NEED_RESCHED = 0x04,
330 TRACE_FLAG_HARDIRQ = 0x08,
331 TRACE_FLAG_SOFTIRQ = 0x10,
332};
333
334
335
336struct sched_switch {
337 struct trace_entry te;
338 char prev_comm[TASK_COMM_LEN];
339 int prev_pid;
340 int prev_prio;
341 long prev_state; /* Arjan weeps. */
342 char next_comm[TASK_COMM_LEN];
343 int next_pid;
344 int next_prio;
345};
346
347static void c_state_start(int cpu, u64 timestamp, int state)
348{
349 cpus_cstate_start_times[cpu] = timestamp;
350 cpus_cstate_state[cpu] = state;
351}
352
353static void c_state_end(int cpu, u64 timestamp)
354{
355 struct power_event *pwr;
356 pwr = malloc(sizeof(struct power_event));
357 if (!pwr)
358 return;
359 memset(pwr, 0, sizeof(struct power_event));
360
361 pwr->state = cpus_cstate_state[cpu];
362 pwr->start_time = cpus_cstate_start_times[cpu];
363 pwr->end_time = timestamp;
364 pwr->cpu = cpu;
365 pwr->type = CSTATE;
366 pwr->next = power_events;
367
368 power_events = pwr;
369}
370
371static void p_state_change(int cpu, u64 timestamp, u64 new_freq)
372{
373 struct power_event *pwr;
374 pwr = malloc(sizeof(struct power_event));
375
376 if (new_freq > 8000000) /* detect invalid data */
377 return;
378
379 if (!pwr)
380 return;
381 memset(pwr, 0, sizeof(struct power_event));
382
383 pwr->state = cpus_pstate_state[cpu];
384 pwr->start_time = cpus_pstate_start_times[cpu];
385 pwr->end_time = timestamp;
386 pwr->cpu = cpu;
387 pwr->type = PSTATE;
388 pwr->next = power_events;
389
390 if (!pwr->start_time)
391 pwr->start_time = first_time;
392
393 power_events = pwr;
394
395 cpus_pstate_state[cpu] = new_freq;
396 cpus_pstate_start_times[cpu] = timestamp;
397
398 if ((u64)new_freq > max_freq)
399 max_freq = new_freq;
400
401 if (new_freq < min_freq || min_freq == 0)
402 min_freq = new_freq;
403
404 if (new_freq == max_freq - 1000)
405 turbo_frequency = max_freq;
406}
407
408static void
409sched_wakeup(int cpu, u64 timestamp, int pid, struct trace_entry *te)
410{
411 struct wake_event *we;
412 struct per_pid *p;
413 struct wakeup_entry *wake = (void *)te;
414
415 we = malloc(sizeof(struct wake_event));
416 if (!we)
417 return;
418
419 memset(we, 0, sizeof(struct wake_event));
420 we->time = timestamp;
421 we->waker = pid;
422
423 if ((te->flags & TRACE_FLAG_HARDIRQ) || (te->flags & TRACE_FLAG_SOFTIRQ))
424 we->waker = -1;
425
426 we->wakee = wake->pid;
427 we->next = wake_events;
428 wake_events = we;
429 p = find_create_pid(we->wakee);
430
431 if (p && p->current && p->current->state == TYPE_NONE) {
432 p->current->state_since = timestamp;
433 p->current->state = TYPE_WAITING;
434 }
435 if (p && p->current && p->current->state == TYPE_BLOCKED) {
436 pid_put_sample(p->pid, p->current->state, cpu, p->current->state_since, timestamp);
437 p->current->state_since = timestamp;
438 p->current->state = TYPE_WAITING;
439 }
440}
441
442static void sched_switch(int cpu, u64 timestamp, struct trace_entry *te)
443{
444 struct per_pid *p = NULL, *prev_p;
445 struct sched_switch *sw = (void *)te;
446
447
448 prev_p = find_create_pid(sw->prev_pid);
449
450 p = find_create_pid(sw->next_pid);
451
452 if (prev_p->current && prev_p->current->state != TYPE_NONE)
453 pid_put_sample(sw->prev_pid, TYPE_RUNNING, cpu, prev_p->current->state_since, timestamp);
454 if (p && p->current) {
455 if (p->current->state != TYPE_NONE)
456 pid_put_sample(sw->next_pid, p->current->state, cpu, p->current->state_since, timestamp);
457
458 p->current->state_since = timestamp;
459 p->current->state = TYPE_RUNNING;
460 }
461
462 if (prev_p->current) {
463 prev_p->current->state = TYPE_NONE;
464 prev_p->current->state_since = timestamp;
465 if (sw->prev_state & 2)
466 prev_p->current->state = TYPE_BLOCKED;
467 if (sw->prev_state == 0)
468 prev_p->current->state = TYPE_WAITING;
469 }
470}
471
472
473static int
474process_sample_event(event_t *event)
475{
476 int cursor = 0;
477 u64 addr = 0;
478 u64 stamp = 0;
479 u32 cpu = 0;
480 u32 pid = 0;
481 struct trace_entry *te;
482
483 if (sample_type & PERF_SAMPLE_IP)
484 cursor++;
485
486 if (sample_type & PERF_SAMPLE_TID) {
487 pid = event->sample.array[cursor]>>32;
488 cursor++;
489 }
490 if (sample_type & PERF_SAMPLE_TIME) {
491 stamp = event->sample.array[cursor++];
492
493 if (!first_time || first_time > stamp)
494 first_time = stamp;
495 if (last_time < stamp)
496 last_time = stamp;
497
498 }
499 if (sample_type & PERF_SAMPLE_ADDR)
500 addr = event->sample.array[cursor++];
501 if (sample_type & PERF_SAMPLE_ID)
502 cursor++;
503 if (sample_type & PERF_SAMPLE_STREAM_ID)
504 cursor++;
505 if (sample_type & PERF_SAMPLE_CPU)
506 cpu = event->sample.array[cursor++] & 0xFFFFFFFF;
507 if (sample_type & PERF_SAMPLE_PERIOD)
508 cursor++;
509
510 te = (void *)&event->sample.array[cursor];
511
512 if (sample_type & PERF_SAMPLE_RAW && te->size > 0) {
513 char *event_str;
514 struct power_entry *pe;
515
516 pe = (void *)te;
517
518 event_str = perf_header__find_event(te->type);
519
520 if (!event_str)
521 return 0;
522
523 if (strcmp(event_str, "power:power_start") == 0)
524 c_state_start(cpu, stamp, pe->value);
525
526 if (strcmp(event_str, "power:power_end") == 0)
527 c_state_end(cpu, stamp);
528
529 if (strcmp(event_str, "power:power_frequency") == 0)
530 p_state_change(cpu, stamp, pe->value);
531
532 if (strcmp(event_str, "sched:sched_wakeup") == 0)
533 sched_wakeup(cpu, stamp, pid, te);
534
535 if (strcmp(event_str, "sched:sched_switch") == 0)
536 sched_switch(cpu, stamp, te);
537 }
538 return 0;
539}
540
541/*
542 * After the last sample we need to wrap up the current C/P state
543 * and close out each CPU for these.
544 */
545static void end_sample_processing(void)
546{
547 u64 cpu;
548 struct power_event *pwr;
549
550 for (cpu = 0; cpu < numcpus; cpu++) {
551 pwr = malloc(sizeof(struct power_event));
552 if (!pwr)
553 return;
554 memset(pwr, 0, sizeof(struct power_event));
555
556 /* C state */
557#if 0
558 pwr->state = cpus_cstate_state[cpu];
559 pwr->start_time = cpus_cstate_start_times[cpu];
560 pwr->end_time = last_time;
561 pwr->cpu = cpu;
562 pwr->type = CSTATE;
563 pwr->next = power_events;
564
565 power_events = pwr;
566#endif
567 /* P state */
568
569 pwr = malloc(sizeof(struct power_event));
570 if (!pwr)
571 return;
572 memset(pwr, 0, sizeof(struct power_event));
573
574 pwr->state = cpus_pstate_state[cpu];
575 pwr->start_time = cpus_pstate_start_times[cpu];
576 pwr->end_time = last_time;
577 pwr->cpu = cpu;
578 pwr->type = PSTATE;
579 pwr->next = power_events;
580
581 if (!pwr->start_time)
582 pwr->start_time = first_time;
583 if (!pwr->state)
584 pwr->state = min_freq;
585 power_events = pwr;
586 }
587}
588
589static u64 sample_time(event_t *event)
590{
591 int cursor;
592
593 cursor = 0;
594 if (sample_type & PERF_SAMPLE_IP)
595 cursor++;
596 if (sample_type & PERF_SAMPLE_TID)
597 cursor++;
598 if (sample_type & PERF_SAMPLE_TIME)
599 return event->sample.array[cursor];
600 return 0;
601}
602
603
604/*
605 * We first queue all events, sorted backwards by insertion.
606 * The order will get flipped later.
607 */
608static int
609queue_sample_event(event_t *event)
610{
611 struct sample_wrapper *copy, *prev;
612 int size;
613
614 size = event->sample.header.size + sizeof(struct sample_wrapper) + 8;
615
616 copy = malloc(size);
617 if (!copy)
618 return 1;
619
620 memset(copy, 0, size);
621
622 copy->next = NULL;
623 copy->timestamp = sample_time(event);
624
625 memcpy(&copy->data, event, event->sample.header.size);
626
627 /* insert in the right place in the list */
628
629 if (!all_samples) {
630 /* first sample ever */
631 all_samples = copy;
632 return 0;
633 }
634
635 if (all_samples->timestamp < copy->timestamp) {
636 /* insert at the head of the list */
637 copy->next = all_samples;
638 all_samples = copy;
639 return 0;
640 }
641
642 prev = all_samples;
643 while (prev->next) {
644 if (prev->next->timestamp < copy->timestamp) {
645 copy->next = prev->next;
646 prev->next = copy;
647 return 0;
648 }
649 prev = prev->next;
650 }
651 /* insert at the end of the list */
652 prev->next = copy;
653
654 return 0;
655}
656
657static void sort_queued_samples(void)
658{
659 struct sample_wrapper *cursor, *next;
660
661 cursor = all_samples;
662 all_samples = NULL;
663
664 while (cursor) {
665 next = cursor->next;
666 cursor->next = all_samples;
667 all_samples = cursor;
668 cursor = next;
669 }
670}
671
672/*
673 * Sort the pid datastructure
674 */
675static void sort_pids(void)
676{
677 struct per_pid *new_list, *p, *cursor, *prev;
678 /* sort by ppid first, then by pid, lowest to highest */
679
680 new_list = NULL;
681
682 while (all_data) {
683 p = all_data;
684 all_data = p->next;
685 p->next = NULL;
686
687 if (new_list == NULL) {
688 new_list = p;
689 p->next = NULL;
690 continue;
691 }
692 prev = NULL;
693 cursor = new_list;
694 while (cursor) {
695 if (cursor->ppid > p->ppid ||
696 (cursor->ppid == p->ppid && cursor->pid > p->pid)) {
697 /* must insert before */
698 if (prev) {
699 p->next = prev->next;
700 prev->next = p;
701 cursor = NULL;
702 continue;
703 } else {
704 p->next = new_list;
705 new_list = p;
706 cursor = NULL;
707 continue;
708 }
709 }
710
711 prev = cursor;
712 cursor = cursor->next;
713 if (!cursor)
714 prev->next = p;
715 }
716 }
717 all_data = new_list;
718}
719
720
721static void draw_c_p_states(void)
722{
723 struct power_event *pwr;
724 pwr = power_events;
725
726 /*
727 * two pass drawing so that the P state bars are on top of the C state blocks
728 */
729 while (pwr) {
730 if (pwr->type == CSTATE)
731 svg_cstate(pwr->cpu, pwr->start_time, pwr->end_time, pwr->state);
732 pwr = pwr->next;
733 }
734
735 pwr = power_events;
736 while (pwr) {
737 if (pwr->type == PSTATE) {
738 if (!pwr->state)
739 pwr->state = min_freq;
740 svg_pstate(pwr->cpu, pwr->start_time, pwr->end_time, pwr->state);
741 }
742 pwr = pwr->next;
743 }
744}
745
746static void draw_wakeups(void)
747{
748 struct wake_event *we;
749 struct per_pid *p;
750 struct per_pidcomm *c;
751
752 we = wake_events;
753 while (we) {
754 int from = 0, to = 0;
755 char *task_from = NULL, *task_to = NULL;
756
757 /* locate the column of the waker and wakee */
758 p = all_data;
759 while (p) {
760 if (p->pid == we->waker || p->pid == we->wakee) {
761 c = p->all;
762 while (c) {
763 if (c->Y && c->start_time <= we->time && c->end_time >= we->time) {
764 if (p->pid == we->waker) {
765 from = c->Y;
766 task_from = c->comm;
767 }
768 if (p->pid == we->wakee) {
769 to = c->Y;
770 task_to = c->comm;
771 }
772 }
773 c = c->next;
774 }
775 }
776 p = p->next;
777 }
778
779 if (we->waker == -1)
780 svg_interrupt(we->time, to);
781 else if (from && to && abs(from - to) == 1)
782 svg_wakeline(we->time, from, to);
783 else
784 svg_partial_wakeline(we->time, from, task_from, to, task_to);
785 we = we->next;
786 }
787}
788
789static void draw_cpu_usage(void)
790{
791 struct per_pid *p;
792 struct per_pidcomm *c;
793 struct cpu_sample *sample;
794 p = all_data;
795 while (p) {
796 c = p->all;
797 while (c) {
798 sample = c->samples;
799 while (sample) {
800 if (sample->type == TYPE_RUNNING)
801 svg_process(sample->cpu, sample->start_time, sample->end_time, "sample", c->comm);
802
803 sample = sample->next;
804 }
805 c = c->next;
806 }
807 p = p->next;
808 }
809}
810
811static void draw_process_bars(void)
812{
813 struct per_pid *p;
814 struct per_pidcomm *c;
815 struct cpu_sample *sample;
816 int Y = 0;
817
818 Y = 2 * numcpus + 2;
819
820 p = all_data;
821 while (p) {
822 c = p->all;
823 while (c) {
824 if (!c->display) {
825 c->Y = 0;
826 c = c->next;
827 continue;
828 }
829
830 svg_box(Y, c->start_time, c->end_time, "process");
831 sample = c->samples;
832 while (sample) {
833 if (sample->type == TYPE_RUNNING)
834 svg_sample(Y, sample->cpu, sample->start_time, sample->end_time);
835 if (sample->type == TYPE_BLOCKED)
836 svg_box(Y, sample->start_time, sample->end_time, "blocked");
837 if (sample->type == TYPE_WAITING)
838 svg_waiting(Y, sample->start_time, sample->end_time);
839 sample = sample->next;
840 }
841
842 if (c->comm) {
843 char comm[256];
844 if (c->total_time > 5000000000) /* 5 seconds */
845 sprintf(comm, "%s:%i (%2.2fs)", c->comm, p->pid, c->total_time / 1000000000.0);
846 else
847 sprintf(comm, "%s:%i (%3.1fms)", c->comm, p->pid, c->total_time / 1000000.0);
848
849 svg_text(Y, c->start_time, comm);
850 }
851 c->Y = Y;
852 Y++;
853 c = c->next;
854 }
855 p = p->next;
856 }
857}
858
859static int determine_display_tasks(u64 threshold)
860{
861 struct per_pid *p;
862 struct per_pidcomm *c;
863 int count = 0;
864
865 p = all_data;
866 while (p) {
867 p->display = 0;
868 if (p->start_time == 1)
869 p->start_time = first_time;
870
871 /* no exit marker, task kept running to the end */
872 if (p->end_time == 0)
873 p->end_time = last_time;
874 if (p->total_time >= threshold)
875 p->display = 1;
876
877 c = p->all;
878
879 while (c) {
880 c->display = 0;
881
882 if (c->start_time == 1)
883 c->start_time = first_time;
884
885 if (c->total_time >= threshold) {
886 c->display = 1;
887 count++;
888 }
889
890 if (c->end_time == 0)
891 c->end_time = last_time;
892
893 c = c->next;
894 }
895 p = p->next;
896 }
897 return count;
898}
899
900
901
902#define TIME_THRESH 10000000
903
904static void write_svg_file(const char *filename)
905{
906 u64 i;
907 int count;
908
909 numcpus++;
910
911
912 count = determine_display_tasks(TIME_THRESH);
913
914 /* We'd like to show at least 15 tasks; be less picky if we have fewer */
915 if (count < 15)
916 count = determine_display_tasks(TIME_THRESH / 10);
917
918 open_svg(filename, numcpus, count, first_time, last_time);
919
920 svg_time_grid();
921 svg_legenda();
922
923 for (i = 0; i < numcpus; i++)
924 svg_cpu_box(i, max_freq, turbo_frequency);
925
926 draw_cpu_usage();
927 draw_process_bars();
928 draw_c_p_states();
929 draw_wakeups();
930
931 svg_close();
932}
933
934static int
935process_event(event_t *event)
936{
937
938 switch (event->header.type) {
939
940 case PERF_RECORD_COMM:
941 return process_comm_event(event);
942 case PERF_RECORD_FORK:
943 return process_fork_event(event);
944 case PERF_RECORD_EXIT:
945 return process_exit_event(event);
946 case PERF_RECORD_SAMPLE:
947 return queue_sample_event(event);
948
949 /*
950 * We dont process them right now but they are fine:
951 */
952 case PERF_RECORD_MMAP:
953 case PERF_RECORD_THROTTLE:
954 case PERF_RECORD_UNTHROTTLE:
955 return 0;
956
957 default:
958 return -1;
959 }
960
961 return 0;
962}
963
964static void process_samples(void)
965{
966 struct sample_wrapper *cursor;
967 event_t *event;
968
969 sort_queued_samples();
970
971 cursor = all_samples;
972 while (cursor) {
973 event = (void *)&cursor->data;
974 cursor = cursor->next;
975 process_sample_event(event);
976 }
977}
978
979
980static int __cmd_timechart(void)
981{
982 int ret, rc = EXIT_FAILURE;
983 unsigned long offset = 0;
984 unsigned long head, shift;
985 struct stat statbuf;
986 event_t *event;
987 uint32_t size;
988 char *buf;
989 int input;
990
991 input = open(input_name, O_RDONLY);
992 if (input < 0) {
993 fprintf(stderr, " failed to open file: %s", input_name);
994 if (!strcmp(input_name, "perf.data"))
995 fprintf(stderr, " (try 'perf record' first)");
996 fprintf(stderr, "\n");
997 exit(-1);
998 }
999
1000 ret = fstat(input, &statbuf);
1001 if (ret < 0) {
1002 perror("failed to stat file");
1003 exit(-1);
1004 }
1005
1006 if (!statbuf.st_size) {
1007 fprintf(stderr, "zero-sized file, nothing to do!\n");
1008 exit(0);
1009 }
1010
1011 header = perf_header__read(input);
1012 head = header->data_offset;
1013
1014 sample_type = perf_header__sample_type(header);
1015
1016 shift = page_size * (head / page_size);
1017 offset += shift;
1018 head -= shift;
1019
1020remap:
1021 buf = (char *)mmap(NULL, page_size * mmap_window, PROT_READ,
1022 MAP_SHARED, input, offset);
1023 if (buf == MAP_FAILED) {
1024 perror("failed to mmap file");
1025 exit(-1);
1026 }
1027
1028more:
1029 event = (event_t *)(buf + head);
1030
1031 size = event->header.size;
1032 if (!size)
1033 size = 8;
1034
1035 if (head + event->header.size >= page_size * mmap_window) {
1036 int ret2;
1037
1038 shift = page_size * (head / page_size);
1039
1040 ret2 = munmap(buf, page_size * mmap_window);
1041 assert(ret2 == 0);
1042
1043 offset += shift;
1044 head -= shift;
1045 goto remap;
1046 }
1047
1048 size = event->header.size;
1049
1050 if (!size || process_event(event) < 0) {
1051
1052 printf("%p [%p]: skipping unknown header type: %d\n",
1053 (void *)(offset + head),
1054 (void *)(long)(event->header.size),
1055 event->header.type);
1056
1057 /*
1058 * assume we lost track of the stream, check alignment, and
1059 * increment a single u64 in the hope to catch on again 'soon'.
1060 */
1061
1062 if (unlikely(head & 7))
1063 head &= ~7ULL;
1064
1065 size = 8;
1066 }
1067
1068 head += size;
1069
1070 if (offset + head >= header->data_offset + header->data_size)
1071 goto done;
1072
1073 if (offset + head < (unsigned long)statbuf.st_size)
1074 goto more;
1075
1076done:
1077 rc = EXIT_SUCCESS;
1078 close(input);
1079
1080
1081 process_samples();
1082
1083 end_sample_processing();
1084
1085 sort_pids();
1086
1087 write_svg_file(output_name);
1088
1089 printf("Written %2.1f seconds of trace to %s.\n", (last_time - first_time) / 1000000000.0, output_name);
1090
1091 return rc;
1092}
1093
1094static const char * const timechart_usage[] = {
1095 "perf timechart [<options>] {record}",
1096 NULL
1097};
1098
1099static const char *record_args[] = {
1100 "record",
1101 "-a",
1102 "-R",
1103 "-M",
1104 "-f",
1105 "-c", "1",
1106 "-e", "power:power_start",
1107 "-e", "power:power_end",
1108 "-e", "power:power_frequency",
1109 "-e", "sched:sched_wakeup",
1110 "-e", "sched:sched_switch",
1111};
1112
1113static int __cmd_record(int argc, const char **argv)
1114{
1115 unsigned int rec_argc, i, j;
1116 const char **rec_argv;
1117
1118 rec_argc = ARRAY_SIZE(record_args) + argc - 1;
1119 rec_argv = calloc(rec_argc + 1, sizeof(char *));
1120
1121 for (i = 0; i < ARRAY_SIZE(record_args); i++)
1122 rec_argv[i] = strdup(record_args[i]);
1123
1124 for (j = 1; j < (unsigned int)argc; j++, i++)
1125 rec_argv[i] = argv[j];
1126
1127 return cmd_record(i, rec_argv, NULL);
1128}
1129
1130static const struct option options[] = {
1131 OPT_STRING('i', "input", &input_name, "file",
1132 "input file name"),
1133 OPT_STRING('o', "output", &output_name, "file",
1134 "output file name"),
1135 OPT_INTEGER('w', "width", &svg_page_width,
1136 "page width"),
1137 OPT_END()
1138};
1139
1140
1141int cmd_timechart(int argc, const char **argv, const char *prefix __used)
1142{
1143 symbol__init();
1144
1145 page_size = getpagesize();
1146
1147 argc = parse_options(argc, argv, options, timechart_usage,
1148 PARSE_OPT_STOP_AT_NON_OPTION);
1149
1150 if (argc && !strncmp(argv[0], "rec", 3))
1151 return __cmd_record(argc, argv);
1152 else if (argc)
1153 usage_with_options(timechart_usage, options);
1154
1155 setup_pager();
1156
1157 return __cmd_timechart();
1158}
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c
index 7de28ce9ca26..1ca88896eee4 100644
--- a/tools/perf/builtin-top.c
+++ b/tools/perf/builtin-top.c
@@ -27,6 +27,8 @@
27#include "util/parse-options.h" 27#include "util/parse-options.h"
28#include "util/parse-events.h" 28#include "util/parse-events.h"
29 29
30#include "util/debug.h"
31
30#include <assert.h> 32#include <assert.h>
31#include <fcntl.h> 33#include <fcntl.h>
32 34
@@ -68,8 +70,6 @@ static int group = 0;
68static unsigned int page_size; 70static unsigned int page_size;
69static unsigned int mmap_pages = 16; 71static unsigned int mmap_pages = 16;
70static int freq = 0; 72static int freq = 0;
71static int verbose = 0;
72static char *vmlinux = NULL;
73 73
74static int delay_secs = 2; 74static int delay_secs = 2;
75static int zero; 75static int zero;
@@ -122,7 +122,8 @@ static void parse_source(struct sym_entry *syme)
122 struct module *module; 122 struct module *module;
123 struct section *section = NULL; 123 struct section *section = NULL;
124 FILE *file; 124 FILE *file;
125 char command[PATH_MAX*2], *path = vmlinux; 125 char command[PATH_MAX*2];
126 const char *path = vmlinux_name;
126 u64 start, end, len; 127 u64 start, end, len;
127 128
128 if (!syme) 129 if (!syme)
@@ -338,8 +339,6 @@ static void show_details(struct sym_entry *syme)
338 printf("%d lines not displayed, maybe increase display entries [e]\n", more); 339 printf("%d lines not displayed, maybe increase display entries [e]\n", more);
339} 340}
340 341
341struct dso *kernel_dso;
342
343/* 342/*
344 * Symbols will be added here in record_ip and will get out 343 * Symbols will be added here in record_ip and will get out
345 * after decayed. 344 * after decayed.
@@ -484,17 +483,24 @@ static void print_sym_table(void)
484 if (nr_counters == 1) 483 if (nr_counters == 1)
485 printf(" samples pcnt"); 484 printf(" samples pcnt");
486 else 485 else
487 printf(" weight samples pcnt"); 486 printf(" weight samples pcnt");
488 487
489 printf(" RIP kernel function\n" 488 if (verbose)
490 " ______ _______ _____ ________________ _______________\n\n" 489 printf(" RIP ");
491 ); 490 printf(" kernel function\n");
491 printf(" %s _______ _____",
492 nr_counters == 1 ? " " : "______");
493 if (verbose)
494 printf(" ________________");
495 printf(" _______________\n\n");
492 496
493 for (nd = rb_first(&tmp); nd; nd = rb_next(nd)) { 497 for (nd = rb_first(&tmp); nd; nd = rb_next(nd)) {
494 struct sym_entry *syme = rb_entry(nd, struct sym_entry, rb_node); 498 struct symbol *sym;
495 struct symbol *sym = (struct symbol *)(syme + 1);
496 double pcnt; 499 double pcnt;
497 500
501 syme = rb_entry(nd, struct sym_entry, rb_node);
502 sym = (struct symbol *)(syme + 1);
503
498 if (++printed > print_entries || (int)syme->snap_count < count_filter) 504 if (++printed > print_entries || (int)syme->snap_count < count_filter)
499 continue; 505 continue;
500 506
@@ -507,7 +513,9 @@ static void print_sym_table(void)
507 printf("%9.1f %10ld - ", syme->weight, syme->snap_count); 513 printf("%9.1f %10ld - ", syme->weight, syme->snap_count);
508 514
509 percent_color_fprintf(stdout, "%4.1f%%", pcnt); 515 percent_color_fprintf(stdout, "%4.1f%%", pcnt);
510 printf(" - %016llx : %s", sym->start, sym->name); 516 if (verbose)
517 printf(" - %016llx", sym->start);
518 printf(" : %s", sym->name);
511 if (sym->module) 519 if (sym->module)
512 printf("\t[%s]", sym->module->name); 520 printf("\t[%s]", sym->module->name);
513 printf("\n"); 521 printf("\n");
@@ -613,7 +621,7 @@ static void print_mapped_keys(void)
613 621
614 fprintf(stdout, "\t[f] profile display filter (count). \t(%d)\n", count_filter); 622 fprintf(stdout, "\t[f] profile display filter (count). \t(%d)\n", count_filter);
615 623
616 if (vmlinux) { 624 if (vmlinux_name) {
617 fprintf(stdout, "\t[F] annotate display filter (percent). \t(%d%%)\n", sym_pcnt_filter); 625 fprintf(stdout, "\t[F] annotate display filter (percent). \t(%d%%)\n", sym_pcnt_filter);
618 fprintf(stdout, "\t[s] annotate symbol. \t(%s)\n", name?: "NULL"); 626 fprintf(stdout, "\t[s] annotate symbol. \t(%s)\n", name?: "NULL");
619 fprintf(stdout, "\t[S] stop annotation.\n"); 627 fprintf(stdout, "\t[S] stop annotation.\n");
@@ -642,7 +650,9 @@ static int key_mapped(int c)
642 case 'F': 650 case 'F':
643 case 's': 651 case 's':
644 case 'S': 652 case 'S':
645 return vmlinux ? 1 : 0; 653 return vmlinux_name ? 1 : 0;
654 default:
655 break;
646 } 656 }
647 657
648 return 0; 658 return 0;
@@ -728,6 +738,8 @@ static void handle_keypress(int c)
728 case 'z': 738 case 'z':
729 zero = ~zero; 739 zero = ~zero;
730 break; 740 break;
741 default:
742 break;
731 } 743 }
732} 744}
733 745
@@ -816,13 +828,13 @@ static int parse_symbols(void)
816{ 828{
817 struct rb_node *node; 829 struct rb_node *node;
818 struct symbol *sym; 830 struct symbol *sym;
819 int modules = vmlinux ? 1 : 0; 831 int use_modules = vmlinux_name ? 1 : 0;
820 832
821 kernel_dso = dso__new("[kernel]", sizeof(struct sym_entry)); 833 kernel_dso = dso__new("[kernel]", sizeof(struct sym_entry));
822 if (kernel_dso == NULL) 834 if (kernel_dso == NULL)
823 return -1; 835 return -1;
824 836
825 if (dso__load_kernel(kernel_dso, vmlinux, symbol_filter, verbose, modules) <= 0) 837 if (dso__load_kernel(kernel_dso, vmlinux_name, symbol_filter, verbose, use_modules) <= 0)
826 goto out_delete_dso; 838 goto out_delete_dso;
827 839
828 node = rb_first(&kernel_dso->syms); 840 node = rb_first(&kernel_dso->syms);
@@ -889,7 +901,7 @@ struct mmap_data {
889 901
890static unsigned int mmap_read_head(struct mmap_data *md) 902static unsigned int mmap_read_head(struct mmap_data *md)
891{ 903{
892 struct perf_counter_mmap_page *pc = md->base; 904 struct perf_event_mmap_page *pc = md->base;
893 int head; 905 int head;
894 906
895 head = pc->data_head; 907 head = pc->data_head;
@@ -937,26 +949,6 @@ static void mmap_read_counter(struct mmap_data *md)
937 last_read = this_read; 949 last_read = this_read;
938 950
939 for (; old != head;) { 951 for (; old != head;) {
940 struct ip_event {
941 struct perf_event_header header;
942 u64 ip;
943 u32 pid, target_pid;
944 };
945 struct mmap_event {
946 struct perf_event_header header;
947 u32 pid, target_pid;
948 u64 start;
949 u64 len;
950 u64 pgoff;
951 char filename[PATH_MAX];
952 };
953
954 typedef union event_union {
955 struct perf_event_header header;
956 struct ip_event ip;
957 struct mmap_event mmap;
958 } event_t;
959
960 event_t *event = (event_t *)&data[old & md->mask]; 952 event_t *event = (event_t *)&data[old & md->mask];
961 953
962 event_t event_copy; 954 event_t event_copy;
@@ -985,9 +977,9 @@ static void mmap_read_counter(struct mmap_data *md)
985 977
986 old += size; 978 old += size;
987 979
988 if (event->header.type == PERF_EVENT_SAMPLE) { 980 if (event->header.type == PERF_RECORD_SAMPLE) {
989 int user = 981 int user =
990 (event->header.misc & PERF_EVENT_MISC_CPUMODE_MASK) == PERF_EVENT_MISC_USER; 982 (event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK) == PERF_RECORD_MISC_USER;
991 process_event(event->ip.ip, md->counter, user); 983 process_event(event->ip.ip, md->counter, user);
992 } 984 }
993 } 985 }
@@ -1013,7 +1005,7 @@ int group_fd;
1013 1005
1014static void start_counter(int i, int counter) 1006static void start_counter(int i, int counter)
1015{ 1007{
1016 struct perf_counter_attr *attr; 1008 struct perf_event_attr *attr;
1017 int cpu; 1009 int cpu;
1018 1010
1019 cpu = profile_cpu; 1011 cpu = profile_cpu;
@@ -1027,7 +1019,7 @@ static void start_counter(int i, int counter)
1027 attr->inherit = (cpu < 0) && inherit; 1019 attr->inherit = (cpu < 0) && inherit;
1028 1020
1029try_again: 1021try_again:
1030 fd[i][counter] = sys_perf_counter_open(attr, target_pid, cpu, group_fd, 0); 1022 fd[i][counter] = sys_perf_event_open(attr, target_pid, cpu, group_fd, 0);
1031 1023
1032 if (fd[i][counter] < 0) { 1024 if (fd[i][counter] < 0) {
1033 int err = errno; 1025 int err = errno;
@@ -1052,7 +1044,7 @@ try_again:
1052 printf("\n"); 1044 printf("\n");
1053 error("perfcounter syscall returned with %d (%s)\n", 1045 error("perfcounter syscall returned with %d (%s)\n",
1054 fd[i][counter], strerror(err)); 1046 fd[i][counter], strerror(err));
1055 die("No CONFIG_PERF_COUNTERS=y kernel support configured?\n"); 1047 die("No CONFIG_PERF_EVENTS=y kernel support configured?\n");
1056 exit(-1); 1048 exit(-1);
1057 } 1049 }
1058 assert(fd[i][counter] >= 0); 1050 assert(fd[i][counter] >= 0);
@@ -1138,7 +1130,7 @@ static const struct option options[] = {
1138 "system-wide collection from all CPUs"), 1130 "system-wide collection from all CPUs"),
1139 OPT_INTEGER('C', "CPU", &profile_cpu, 1131 OPT_INTEGER('C', "CPU", &profile_cpu,
1140 "CPU to profile on"), 1132 "CPU to profile on"),
1141 OPT_STRING('k', "vmlinux", &vmlinux, "file", "vmlinux pathname"), 1133 OPT_STRING('k', "vmlinux", &vmlinux_name, "file", "vmlinux pathname"),
1142 OPT_INTEGER('m', "mmap-pages", &mmap_pages, 1134 OPT_INTEGER('m', "mmap-pages", &mmap_pages,
1143 "number of mmap data pages"), 1135 "number of mmap data pages"),
1144 OPT_INTEGER('r', "realtime", &realtime_prio, 1136 OPT_INTEGER('r', "realtime", &realtime_prio,
diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c
new file mode 100644
index 000000000000..e9d256e2f47d
--- /dev/null
+++ b/tools/perf/builtin-trace.c
@@ -0,0 +1,297 @@
1#include "builtin.h"
2
3#include "util/util.h"
4#include "util/cache.h"
5#include "util/symbol.h"
6#include "util/thread.h"
7#include "util/header.h"
8
9#include "util/parse-options.h"
10
11#include "perf.h"
12#include "util/debug.h"
13
14#include "util/trace-event.h"
15
16static char const *input_name = "perf.data";
17static int input;
18static unsigned long page_size;
19static unsigned long mmap_window = 32;
20
21static unsigned long total = 0;
22static unsigned long total_comm = 0;
23
24static struct rb_root threads;
25static struct thread *last_match;
26
27static struct perf_header *header;
28static u64 sample_type;
29
30
31static int
32process_comm_event(event_t *event, unsigned long offset, unsigned long head)
33{
34 struct thread *thread;
35
36 thread = threads__findnew(event->comm.pid, &threads, &last_match);
37
38 dump_printf("%p [%p]: PERF_RECORD_COMM: %s:%d\n",
39 (void *)(offset + head),
40 (void *)(long)(event->header.size),
41 event->comm.comm, event->comm.pid);
42
43 if (thread == NULL ||
44 thread__set_comm(thread, event->comm.comm)) {
45 dump_printf("problem processing PERF_RECORD_COMM, skipping event.\n");
46 return -1;
47 }
48 total_comm++;
49
50 return 0;
51}
52
53static int
54process_sample_event(event_t *event, unsigned long offset, unsigned long head)
55{
56 char level;
57 int show = 0;
58 struct dso *dso = NULL;
59 struct thread *thread;
60 u64 ip = event->ip.ip;
61 u64 timestamp = -1;
62 u32 cpu = -1;
63 u64 period = 1;
64 void *more_data = event->ip.__more_data;
65 int cpumode;
66
67 thread = threads__findnew(event->ip.pid, &threads, &last_match);
68
69 if (sample_type & PERF_SAMPLE_TIME) {
70 timestamp = *(u64 *)more_data;
71 more_data += sizeof(u64);
72 }
73
74 if (sample_type & PERF_SAMPLE_CPU) {
75 cpu = *(u32 *)more_data;
76 more_data += sizeof(u32);
77 more_data += sizeof(u32); /* reserved */
78 }
79
80 if (sample_type & PERF_SAMPLE_PERIOD) {
81 period = *(u64 *)more_data;
82 more_data += sizeof(u64);
83 }
84
85 dump_printf("%p [%p]: PERF_RECORD_SAMPLE (IP, %d): %d/%d: %p period: %Ld\n",
86 (void *)(offset + head),
87 (void *)(long)(event->header.size),
88 event->header.misc,
89 event->ip.pid, event->ip.tid,
90 (void *)(long)ip,
91 (long long)period);
92
93 dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid);
94
95 if (thread == NULL) {
96 eprintf("problem processing %d event, skipping it.\n",
97 event->header.type);
98 return -1;
99 }
100
101 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
102
103 if (cpumode == PERF_RECORD_MISC_KERNEL) {
104 show = SHOW_KERNEL;
105 level = 'k';
106
107 dso = kernel_dso;
108
109 dump_printf(" ...... dso: %s\n", dso->name);
110
111 } else if (cpumode == PERF_RECORD_MISC_USER) {
112
113 show = SHOW_USER;
114 level = '.';
115
116 } else {
117 show = SHOW_HV;
118 level = 'H';
119
120 dso = hypervisor_dso;
121
122 dump_printf(" ...... dso: [hypervisor]\n");
123 }
124
125 if (sample_type & PERF_SAMPLE_RAW) {
126 struct {
127 u32 size;
128 char data[0];
129 } *raw = more_data;
130
131 /*
132 * FIXME: better resolve from pid from the struct trace_entry
133 * field, although it should be the same than this perf
134 * event pid
135 */
136 print_event(cpu, raw->data, raw->size, timestamp, thread->comm);
137 }
138 total += period;
139
140 return 0;
141}
142
143static int
144process_event(event_t *event, unsigned long offset, unsigned long head)
145{
146 trace_event(event);
147
148 switch (event->header.type) {
149 case PERF_RECORD_MMAP ... PERF_RECORD_LOST:
150 return 0;
151
152 case PERF_RECORD_COMM:
153 return process_comm_event(event, offset, head);
154
155 case PERF_RECORD_EXIT ... PERF_RECORD_READ:
156 return 0;
157
158 case PERF_RECORD_SAMPLE:
159 return process_sample_event(event, offset, head);
160
161 case PERF_RECORD_MAX:
162 default:
163 return -1;
164 }
165
166 return 0;
167}
168
169static int __cmd_trace(void)
170{
171 int ret, rc = EXIT_FAILURE;
172 unsigned long offset = 0;
173 unsigned long head = 0;
174 struct stat perf_stat;
175 event_t *event;
176 uint32_t size;
177 char *buf;
178
179 trace_report();
180 register_idle_thread(&threads, &last_match);
181
182 input = open(input_name, O_RDONLY);
183 if (input < 0) {
184 perror("failed to open file");
185 exit(-1);
186 }
187
188 ret = fstat(input, &perf_stat);
189 if (ret < 0) {
190 perror("failed to stat file");
191 exit(-1);
192 }
193
194 if (!perf_stat.st_size) {
195 fprintf(stderr, "zero-sized file, nothing to do!\n");
196 exit(0);
197 }
198 header = perf_header__read(input);
199 head = header->data_offset;
200 sample_type = perf_header__sample_type(header);
201
202 if (!(sample_type & PERF_SAMPLE_RAW))
203 die("No trace sample to read. Did you call perf record "
204 "without -R?");
205
206 if (load_kernel() < 0) {
207 perror("failed to load kernel symbols");
208 return EXIT_FAILURE;
209 }
210
211remap:
212 buf = (char *)mmap(NULL, page_size * mmap_window, PROT_READ,
213 MAP_SHARED, input, offset);
214 if (buf == MAP_FAILED) {
215 perror("failed to mmap file");
216 exit(-1);
217 }
218
219more:
220 event = (event_t *)(buf + head);
221
222 size = event->header.size;
223 if (!size)
224 size = 8;
225
226 if (head + event->header.size >= page_size * mmap_window) {
227 unsigned long shift = page_size * (head / page_size);
228 int res;
229
230 res = munmap(buf, page_size * mmap_window);
231 assert(res == 0);
232
233 offset += shift;
234 head -= shift;
235 goto remap;
236 }
237
238 size = event->header.size;
239
240
241 if (!size || process_event(event, offset, head) < 0) {
242
243 /*
244 * assume we lost track of the stream, check alignment, and
245 * increment a single u64 in the hope to catch on again 'soon'.
246 */
247
248 if (unlikely(head & 7))
249 head &= ~7ULL;
250
251 size = 8;
252 }
253
254 head += size;
255
256 if (offset + head < (unsigned long)perf_stat.st_size)
257 goto more;
258
259 rc = EXIT_SUCCESS;
260 close(input);
261
262 return rc;
263}
264
265static const char * const annotate_usage[] = {
266 "perf trace [<options>] <command>",
267 NULL
268};
269
270static const struct option options[] = {
271 OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace,
272 "dump raw trace in ASCII"),
273 OPT_BOOLEAN('v', "verbose", &verbose,
274 "be more verbose (show symbol address, etc)"),
275 OPT_END()
276};
277
278int cmd_trace(int argc, const char **argv, const char *prefix __used)
279{
280 symbol__init();
281 page_size = getpagesize();
282
283 argc = parse_options(argc, argv, options, annotate_usage, 0);
284 if (argc) {
285 /*
286 * Special case: if there's an argument left then assume tha
287 * it's a symbol filter:
288 */
289 if (argc > 1)
290 usage_with_options(annotate_usage, options);
291 }
292
293
294 setup_pager();
295
296 return __cmd_trace();
297}
diff --git a/tools/perf/builtin.h b/tools/perf/builtin.h
index 51d168230ee7..e11d8d231c3b 100644
--- a/tools/perf/builtin.h
+++ b/tools/perf/builtin.h
@@ -16,11 +16,14 @@ extern int check_pager_config(const char *cmd);
16 16
17extern int cmd_annotate(int argc, const char **argv, const char *prefix); 17extern int cmd_annotate(int argc, const char **argv, const char *prefix);
18extern int cmd_help(int argc, const char **argv, const char *prefix); 18extern int cmd_help(int argc, const char **argv, const char *prefix);
19extern int cmd_sched(int argc, const char **argv, const char *prefix);
20extern int cmd_list(int argc, const char **argv, const char *prefix);
19extern int cmd_record(int argc, const char **argv, const char *prefix); 21extern int cmd_record(int argc, const char **argv, const char *prefix);
20extern int cmd_report(int argc, const char **argv, const char *prefix); 22extern int cmd_report(int argc, const char **argv, const char *prefix);
21extern int cmd_stat(int argc, const char **argv, const char *prefix); 23extern int cmd_stat(int argc, const char **argv, const char *prefix);
24extern int cmd_timechart(int argc, const char **argv, const char *prefix);
22extern int cmd_top(int argc, const char **argv, const char *prefix); 25extern int cmd_top(int argc, const char **argv, const char *prefix);
26extern int cmd_trace(int argc, const char **argv, const char *prefix);
23extern int cmd_version(int argc, const char **argv, const char *prefix); 27extern int cmd_version(int argc, const char **argv, const char *prefix);
24extern int cmd_list(int argc, const char **argv, const char *prefix);
25 28
26#endif 29#endif
diff --git a/tools/perf/command-list.txt b/tools/perf/command-list.txt
index eebce30afbc0..00326e230d87 100644
--- a/tools/perf/command-list.txt
+++ b/tools/perf/command-list.txt
@@ -4,7 +4,10 @@
4# 4#
5perf-annotate mainporcelain common 5perf-annotate mainporcelain common
6perf-list mainporcelain common 6perf-list mainporcelain common
7perf-sched mainporcelain common
7perf-record mainporcelain common 8perf-record mainporcelain common
8perf-report mainporcelain common 9perf-report mainporcelain common
9perf-stat mainporcelain common 10perf-stat mainporcelain common
11perf-timechart mainporcelain common
10perf-top mainporcelain common 12perf-top mainporcelain common
13perf-trace mainporcelain common
diff --git a/tools/perf/design.txt b/tools/perf/design.txt
index f71e0d245cba..f1946d107b10 100644
--- a/tools/perf/design.txt
+++ b/tools/perf/design.txt
@@ -18,10 +18,10 @@ underlying hardware counters.
18Performance counters are accessed via special file descriptors. 18Performance counters are accessed via special file descriptors.
19There's one file descriptor per virtual counter used. 19There's one file descriptor per virtual counter used.
20 20
21The special file descriptor is opened via the perf_counter_open() 21The special file descriptor is opened via the perf_event_open()
22system call: 22system call:
23 23
24 int sys_perf_counter_open(struct perf_counter_hw_event *hw_event_uptr, 24 int sys_perf_event_open(struct perf_event_hw_event *hw_event_uptr,
25 pid_t pid, int cpu, int group_fd, 25 pid_t pid, int cpu, int group_fd,
26 unsigned long flags); 26 unsigned long flags);
27 27
@@ -32,9 +32,9 @@ can be used to set the blocking mode, etc.
32Multiple counters can be kept open at a time, and the counters 32Multiple counters can be kept open at a time, and the counters
33can be poll()ed. 33can be poll()ed.
34 34
35When creating a new counter fd, 'perf_counter_hw_event' is: 35When creating a new counter fd, 'perf_event_hw_event' is:
36 36
37struct perf_counter_hw_event { 37struct perf_event_hw_event {
38 /* 38 /*
39 * The MSB of the config word signifies if the rest contains cpu 39 * The MSB of the config word signifies if the rest contains cpu
40 * specific (raw) counter configuration data, if unset, the next 40 * specific (raw) counter configuration data, if unset, the next
@@ -93,7 +93,7 @@ specified by 'event_id':
93 93
94/* 94/*
95 * Generalized performance counter event types, used by the hw_event.event_id 95 * Generalized performance counter event types, used by the hw_event.event_id
96 * parameter of the sys_perf_counter_open() syscall: 96 * parameter of the sys_perf_event_open() syscall:
97 */ 97 */
98enum hw_event_ids { 98enum hw_event_ids {
99 /* 99 /*
@@ -159,7 +159,7 @@ in size.
159 * reads on the counter should return the indicated quantities, 159 * reads on the counter should return the indicated quantities,
160 * in increasing order of bit value, after the counter value. 160 * in increasing order of bit value, after the counter value.
161 */ 161 */
162enum perf_counter_read_format { 162enum perf_event_read_format {
163 PERF_FORMAT_TOTAL_TIME_ENABLED = 1, 163 PERF_FORMAT_TOTAL_TIME_ENABLED = 1,
164 PERF_FORMAT_TOTAL_TIME_RUNNING = 2, 164 PERF_FORMAT_TOTAL_TIME_RUNNING = 2,
165}; 165};
@@ -178,7 +178,7 @@ interrupt:
178 * Bits that can be set in hw_event.record_type to request information 178 * Bits that can be set in hw_event.record_type to request information
179 * in the overflow packets. 179 * in the overflow packets.
180 */ 180 */
181enum perf_counter_record_format { 181enum perf_event_record_format {
182 PERF_RECORD_IP = 1U << 0, 182 PERF_RECORD_IP = 1U << 0,
183 PERF_RECORD_TID = 1U << 1, 183 PERF_RECORD_TID = 1U << 1,
184 PERF_RECORD_TIME = 1U << 2, 184 PERF_RECORD_TIME = 1U << 2,
@@ -228,7 +228,7 @@ these events are recorded in the ring-buffer (see below).
228The 'comm' bit allows tracking of process comm data on process creation. 228The 'comm' bit allows tracking of process comm data on process creation.
229This too is recorded in the ring-buffer (see below). 229This too is recorded in the ring-buffer (see below).
230 230
231The 'pid' parameter to the perf_counter_open() system call allows the 231The 'pid' parameter to the perf_event_open() system call allows the
232counter to be specific to a task: 232counter to be specific to a task:
233 233
234 pid == 0: if the pid parameter is zero, the counter is attached to the 234 pid == 0: if the pid parameter is zero, the counter is attached to the
@@ -258,7 +258,7 @@ The 'flags' parameter is currently unused and must be zero.
258 258
259The 'group_fd' parameter allows counter "groups" to be set up. A 259The 'group_fd' parameter allows counter "groups" to be set up. A
260counter group has one counter which is the group "leader". The leader 260counter group has one counter which is the group "leader". The leader
261is created first, with group_fd = -1 in the perf_counter_open call 261is created first, with group_fd = -1 in the perf_event_open call
262that creates it. The rest of the group members are created 262that creates it. The rest of the group members are created
263subsequently, with group_fd giving the fd of the group leader. 263subsequently, with group_fd giving the fd of the group leader.
264(A single counter on its own is created with group_fd = -1 and is 264(A single counter on its own is created with group_fd = -1 and is
@@ -277,13 +277,13 @@ tracking are logged into a ring-buffer. This ring-buffer is created and
277accessed through mmap(). 277accessed through mmap().
278 278
279The mmap size should be 1+2^n pages, where the first page is a meta-data page 279The mmap size should be 1+2^n pages, where the first page is a meta-data page
280(struct perf_counter_mmap_page) that contains various bits of information such 280(struct perf_event_mmap_page) that contains various bits of information such
281as where the ring-buffer head is. 281as where the ring-buffer head is.
282 282
283/* 283/*
284 * Structure of the page that can be mapped via mmap 284 * Structure of the page that can be mapped via mmap
285 */ 285 */
286struct perf_counter_mmap_page { 286struct perf_event_mmap_page {
287 __u32 version; /* version number of this structure */ 287 __u32 version; /* version number of this structure */
288 __u32 compat_version; /* lowest version this is compat with */ 288 __u32 compat_version; /* lowest version this is compat with */
289 289
@@ -317,7 +317,7 @@ struct perf_counter_mmap_page {
317 * Control data for the mmap() data buffer. 317 * Control data for the mmap() data buffer.
318 * 318 *
319 * User-space reading this value should issue an rmb(), on SMP capable 319 * User-space reading this value should issue an rmb(), on SMP capable
320 * platforms, after reading this value -- see perf_counter_wakeup(). 320 * platforms, after reading this value -- see perf_event_wakeup().
321 */ 321 */
322 __u32 data_head; /* head in the data section */ 322 __u32 data_head; /* head in the data section */
323}; 323};
@@ -327,9 +327,9 @@ NOTE: the hw-counter userspace bits are arch specific and are currently only
327 327
328The following 2^n pages are the ring-buffer which contains events of the form: 328The following 2^n pages are the ring-buffer which contains events of the form:
329 329
330#define PERF_EVENT_MISC_KERNEL (1 << 0) 330#define PERF_RECORD_MISC_KERNEL (1 << 0)
331#define PERF_EVENT_MISC_USER (1 << 1) 331#define PERF_RECORD_MISC_USER (1 << 1)
332#define PERF_EVENT_MISC_OVERFLOW (1 << 2) 332#define PERF_RECORD_MISC_OVERFLOW (1 << 2)
333 333
334struct perf_event_header { 334struct perf_event_header {
335 __u32 type; 335 __u32 type;
@@ -353,8 +353,8 @@ enum perf_event_type {
353 * char filename[]; 353 * char filename[];
354 * }; 354 * };
355 */ 355 */
356 PERF_EVENT_MMAP = 1, 356 PERF_RECORD_MMAP = 1,
357 PERF_EVENT_MUNMAP = 2, 357 PERF_RECORD_MUNMAP = 2,
358 358
359 /* 359 /*
360 * struct { 360 * struct {
@@ -364,10 +364,10 @@ enum perf_event_type {
364 * char comm[]; 364 * char comm[];
365 * }; 365 * };
366 */ 366 */
367 PERF_EVENT_COMM = 3, 367 PERF_RECORD_COMM = 3,
368 368
369 /* 369 /*
370 * When header.misc & PERF_EVENT_MISC_OVERFLOW the event_type field 370 * When header.misc & PERF_RECORD_MISC_OVERFLOW the event_type field
371 * will be PERF_RECORD_* 371 * will be PERF_RECORD_*
372 * 372 *
373 * struct { 373 * struct {
@@ -397,7 +397,7 @@ Notification of new events is possible through poll()/select()/epoll() and
397fcntl() managing signals. 397fcntl() managing signals.
398 398
399Normally a notification is generated for every page filled, however one can 399Normally a notification is generated for every page filled, however one can
400additionally set perf_counter_hw_event.wakeup_events to generate one every 400additionally set perf_event_hw_event.wakeup_events to generate one every
401so many counter overflow events. 401so many counter overflow events.
402 402
403Future work will include a splice() interface to the ring-buffer. 403Future work will include a splice() interface to the ring-buffer.
@@ -409,11 +409,11 @@ events but does continue to exist and maintain its count value.
409 409
410An individual counter or counter group can be enabled with 410An individual counter or counter group can be enabled with
411 411
412 ioctl(fd, PERF_COUNTER_IOC_ENABLE); 412 ioctl(fd, PERF_EVENT_IOC_ENABLE);
413 413
414or disabled with 414or disabled with
415 415
416 ioctl(fd, PERF_COUNTER_IOC_DISABLE); 416 ioctl(fd, PERF_EVENT_IOC_DISABLE);
417 417
418Enabling or disabling the leader of a group enables or disables the 418Enabling or disabling the leader of a group enables or disables the
419whole group; that is, while the group leader is disabled, none of the 419whole group; that is, while the group leader is disabled, none of the
@@ -424,16 +424,16 @@ other counter.
424 424
425Additionally, non-inherited overflow counters can use 425Additionally, non-inherited overflow counters can use
426 426
427 ioctl(fd, PERF_COUNTER_IOC_REFRESH, nr); 427 ioctl(fd, PERF_EVENT_IOC_REFRESH, nr);
428 428
429to enable a counter for 'nr' events, after which it gets disabled again. 429to enable a counter for 'nr' events, after which it gets disabled again.
430 430
431A process can enable or disable all the counter groups that are 431A process can enable or disable all the counter groups that are
432attached to it, using prctl: 432attached to it, using prctl:
433 433
434 prctl(PR_TASK_PERF_COUNTERS_ENABLE); 434 prctl(PR_TASK_PERF_EVENTS_ENABLE);
435 435
436 prctl(PR_TASK_PERF_COUNTERS_DISABLE); 436 prctl(PR_TASK_PERF_EVENTS_DISABLE);
437 437
438This applies to all counters on the current process, whether created 438This applies to all counters on the current process, whether created
439by this process or by another, and doesn't affect any counters that 439by this process or by another, and doesn't affect any counters that
@@ -447,11 +447,11 @@ Arch requirements
447If your architecture does not have hardware performance metrics, you can 447If your architecture does not have hardware performance metrics, you can
448still use the generic software counters based on hrtimers for sampling. 448still use the generic software counters based on hrtimers for sampling.
449 449
450So to start with, in order to add HAVE_PERF_COUNTERS to your Kconfig, you 450So to start with, in order to add HAVE_PERF_EVENTS to your Kconfig, you
451will need at least this: 451will need at least this:
452 - asm/perf_counter.h - a basic stub will suffice at first 452 - asm/perf_event.h - a basic stub will suffice at first
453 - support for atomic64 types (and associated helper functions) 453 - support for atomic64 types (and associated helper functions)
454 - set_perf_counter_pending() implemented 454 - set_perf_event_pending() implemented
455 455
456If your architecture does have hardware capabilities, you can override the 456If your architecture does have hardware capabilities, you can override the
457weak stub hw_perf_counter_init() to register hardware counters. 457weak stub hw_perf_event_init() to register hardware counters.
diff --git a/tools/perf/perf.c b/tools/perf/perf.c
index 31982ad064b4..19fc7feb9d59 100644
--- a/tools/perf/perf.c
+++ b/tools/perf/perf.c
@@ -289,9 +289,12 @@ static void handle_internal_command(int argc, const char **argv)
289 { "record", cmd_record, 0 }, 289 { "record", cmd_record, 0 },
290 { "report", cmd_report, 0 }, 290 { "report", cmd_report, 0 },
291 { "stat", cmd_stat, 0 }, 291 { "stat", cmd_stat, 0 },
292 { "timechart", cmd_timechart, 0 },
292 { "top", cmd_top, 0 }, 293 { "top", cmd_top, 0 },
293 { "annotate", cmd_annotate, 0 }, 294 { "annotate", cmd_annotate, 0 },
294 { "version", cmd_version, 0 }, 295 { "version", cmd_version, 0 },
296 { "trace", cmd_trace, 0 },
297 { "sched", cmd_sched, 0 },
295 }; 298 };
296 unsigned int i; 299 unsigned int i;
297 static const char ext[] = STRIP_EXTENSION; 300 static const char ext[] = STRIP_EXTENSION;
diff --git a/tools/perf/perf.h b/tools/perf/perf.h
index e5148e2b6134..8cc4623afd6f 100644
--- a/tools/perf/perf.h
+++ b/tools/perf/perf.h
@@ -41,20 +41,26 @@
41#define cpu_relax() asm volatile("" ::: "memory"); 41#define cpu_relax() asm volatile("" ::: "memory");
42#endif 42#endif
43 43
44#ifdef __sparc__
45#include "../../arch/sparc/include/asm/unistd.h"
46#define rmb() asm volatile("":::"memory")
47#define cpu_relax() asm volatile("":::"memory")
48#endif
49
44#include <time.h> 50#include <time.h>
45#include <unistd.h> 51#include <unistd.h>
46#include <sys/types.h> 52#include <sys/types.h>
47#include <sys/syscall.h> 53#include <sys/syscall.h>
48 54
49#include "../../include/linux/perf_counter.h" 55#include "../../include/linux/perf_event.h"
50#include "util/types.h" 56#include "util/types.h"
51 57
52/* 58/*
53 * prctl(PR_TASK_PERF_COUNTERS_DISABLE) will (cheaply) disable all 59 * prctl(PR_TASK_PERF_EVENTS_DISABLE) will (cheaply) disable all
54 * counters in the current task. 60 * counters in the current task.
55 */ 61 */
56#define PR_TASK_PERF_COUNTERS_DISABLE 31 62#define PR_TASK_PERF_EVENTS_DISABLE 31
57#define PR_TASK_PERF_COUNTERS_ENABLE 32 63#define PR_TASK_PERF_EVENTS_ENABLE 32
58 64
59#ifndef NSEC_PER_SEC 65#ifndef NSEC_PER_SEC
60# define NSEC_PER_SEC 1000000000ULL 66# define NSEC_PER_SEC 1000000000ULL
@@ -84,12 +90,12 @@ static inline unsigned long long rdclock(void)
84 _min1 < _min2 ? _min1 : _min2; }) 90 _min1 < _min2 ? _min1 : _min2; })
85 91
86static inline int 92static inline int
87sys_perf_counter_open(struct perf_counter_attr *attr, 93sys_perf_event_open(struct perf_event_attr *attr,
88 pid_t pid, int cpu, int group_fd, 94 pid_t pid, int cpu, int group_fd,
89 unsigned long flags) 95 unsigned long flags)
90{ 96{
91 attr->size = sizeof(*attr); 97 attr->size = sizeof(*attr);
92 return syscall(__NR_perf_counter_open, attr, pid, cpu, 98 return syscall(__NR_perf_event_open, attr, pid, cpu,
93 group_fd, flags); 99 group_fd, flags);
94} 100}
95 101
diff --git a/tools/perf/util/abspath.c b/tools/perf/util/abspath.c
index 61d33b81fc97..a791dd467261 100644
--- a/tools/perf/util/abspath.c
+++ b/tools/perf/util/abspath.c
@@ -50,7 +50,8 @@ const char *make_absolute_path(const char *path)
50 die ("Could not get current working directory"); 50 die ("Could not get current working directory");
51 51
52 if (last_elem) { 52 if (last_elem) {
53 int len = strlen(buf); 53 len = strlen(buf);
54
54 if (len + strlen(last_elem) + 2 > PATH_MAX) 55 if (len + strlen(last_elem) + 2 > PATH_MAX)
55 die ("Too long path name: '%s/%s'", 56 die ("Too long path name: '%s/%s'",
56 buf, last_elem); 57 buf, last_elem);
diff --git a/tools/perf/util/cache.h b/tools/perf/util/cache.h
index 4b50c412b9c5..6f8ea9d210b6 100644
--- a/tools/perf/util/cache.h
+++ b/tools/perf/util/cache.h
@@ -52,7 +52,6 @@ extern const char *perf_mailmap_file;
52extern void maybe_flush_or_die(FILE *, const char *); 52extern void maybe_flush_or_die(FILE *, const char *);
53extern int copy_fd(int ifd, int ofd); 53extern int copy_fd(int ifd, int ofd);
54extern int copy_file(const char *dst, const char *src, int mode); 54extern int copy_file(const char *dst, const char *src, int mode);
55extern ssize_t read_in_full(int fd, void *buf, size_t count);
56extern ssize_t write_in_full(int fd, const void *buf, size_t count); 55extern ssize_t write_in_full(int fd, const void *buf, size_t count);
57extern void write_or_die(int fd, const void *buf, size_t count); 56extern void write_or_die(int fd, const void *buf, size_t count);
58extern int write_or_whine(int fd, const void *buf, size_t count, const char *msg); 57extern int write_or_whine(int fd, const void *buf, size_t count, const char *msg);
diff --git a/tools/perf/util/callchain.c b/tools/perf/util/callchain.c
index 011473411642..3b8380f1b478 100644
--- a/tools/perf/util/callchain.c
+++ b/tools/perf/util/callchain.c
@@ -50,6 +50,7 @@ rb_insert_callchain(struct rb_root *root, struct callchain_node *chain,
50 else 50 else
51 p = &(*p)->rb_right; 51 p = &(*p)->rb_right;
52 break; 52 break;
53 case CHAIN_NONE:
53 default: 54 default:
54 break; 55 break;
55 } 56 }
@@ -143,6 +144,7 @@ int register_callchain_param(struct callchain_param *param)
143 case CHAIN_FLAT: 144 case CHAIN_FLAT:
144 param->sort = sort_chain_flat; 145 param->sort = sort_chain_flat;
145 break; 146 break;
147 case CHAIN_NONE:
146 default: 148 default:
147 return -1; 149 return -1;
148 } 150 }
diff --git a/tools/perf/util/callchain.h b/tools/perf/util/callchain.h
index a926ae4f5a16..43cf3ea9e088 100644
--- a/tools/perf/util/callchain.h
+++ b/tools/perf/util/callchain.h
@@ -4,6 +4,7 @@
4#include "../perf.h" 4#include "../perf.h"
5#include <linux/list.h> 5#include <linux/list.h>
6#include <linux/rbtree.h> 6#include <linux/rbtree.h>
7#include "util.h"
7#include "symbol.h" 8#include "symbol.h"
8 9
9enum chain_mode { 10enum chain_mode {
diff --git a/tools/perf/util/color.c b/tools/perf/util/color.c
index 90a044d1fe7d..e88bca55a599 100644
--- a/tools/perf/util/color.c
+++ b/tools/perf/util/color.c
@@ -166,7 +166,7 @@ int perf_color_default_config(const char *var, const char *value, void *cb)
166 return perf_default_config(var, value, cb); 166 return perf_default_config(var, value, cb);
167} 167}
168 168
169static int color_vfprintf(FILE *fp, const char *color, const char *fmt, 169static int __color_vfprintf(FILE *fp, const char *color, const char *fmt,
170 va_list args, const char *trail) 170 va_list args, const char *trail)
171{ 171{
172 int r = 0; 172 int r = 0;
@@ -191,6 +191,10 @@ static int color_vfprintf(FILE *fp, const char *color, const char *fmt,
191 return r; 191 return r;
192} 192}
193 193
194int color_vfprintf(FILE *fp, const char *color, const char *fmt, va_list args)
195{
196 return __color_vfprintf(fp, color, fmt, args, NULL);
197}
194 198
195 199
196int color_fprintf(FILE *fp, const char *color, const char *fmt, ...) 200int color_fprintf(FILE *fp, const char *color, const char *fmt, ...)
@@ -199,7 +203,7 @@ int color_fprintf(FILE *fp, const char *color, const char *fmt, ...)
199 int r; 203 int r;
200 204
201 va_start(args, fmt); 205 va_start(args, fmt);
202 r = color_vfprintf(fp, color, fmt, args, NULL); 206 r = color_vfprintf(fp, color, fmt, args);
203 va_end(args); 207 va_end(args);
204 return r; 208 return r;
205} 209}
@@ -209,7 +213,7 @@ int color_fprintf_ln(FILE *fp, const char *color, const char *fmt, ...)
209 va_list args; 213 va_list args;
210 int r; 214 int r;
211 va_start(args, fmt); 215 va_start(args, fmt);
212 r = color_vfprintf(fp, color, fmt, args, "\n"); 216 r = __color_vfprintf(fp, color, fmt, args, "\n");
213 va_end(args); 217 va_end(args);
214 return r; 218 return r;
215} 219}
@@ -242,9 +246,9 @@ int color_fwrite_lines(FILE *fp, const char *color,
242 return 0; 246 return 0;
243} 247}
244 248
245char *get_percent_color(double percent) 249const char *get_percent_color(double percent)
246{ 250{
247 char *color = PERF_COLOR_NORMAL; 251 const char *color = PERF_COLOR_NORMAL;
248 252
249 /* 253 /*
250 * We color high-overhead entries in red, mid-overhead 254 * We color high-overhead entries in red, mid-overhead
@@ -263,7 +267,7 @@ char *get_percent_color(double percent)
263int percent_color_fprintf(FILE *fp, const char *fmt, double percent) 267int percent_color_fprintf(FILE *fp, const char *fmt, double percent)
264{ 268{
265 int r; 269 int r;
266 char *color; 270 const char *color;
267 271
268 color = get_percent_color(percent); 272 color = get_percent_color(percent);
269 r = color_fprintf(fp, color, fmt, percent); 273 r = color_fprintf(fp, color, fmt, percent);
diff --git a/tools/perf/util/color.h b/tools/perf/util/color.h
index 706cec50bd25..58d597564b99 100644
--- a/tools/perf/util/color.h
+++ b/tools/perf/util/color.h
@@ -32,10 +32,11 @@ int perf_color_default_config(const char *var, const char *value, void *cb);
32int perf_config_colorbool(const char *var, const char *value, int stdout_is_tty); 32int perf_config_colorbool(const char *var, const char *value, int stdout_is_tty);
33void color_parse(const char *value, const char *var, char *dst); 33void color_parse(const char *value, const char *var, char *dst);
34void color_parse_mem(const char *value, int len, const char *var, char *dst); 34void color_parse_mem(const char *value, int len, const char *var, char *dst);
35int color_vfprintf(FILE *fp, const char *color, const char *fmt, va_list args);
35int color_fprintf(FILE *fp, const char *color, const char *fmt, ...); 36int color_fprintf(FILE *fp, const char *color, const char *fmt, ...);
36int color_fprintf_ln(FILE *fp, const char *color, const char *fmt, ...); 37int color_fprintf_ln(FILE *fp, const char *color, const char *fmt, ...);
37int color_fwrite_lines(FILE *fp, const char *color, size_t count, const char *buf); 38int color_fwrite_lines(FILE *fp, const char *color, size_t count, const char *buf);
38int percent_color_fprintf(FILE *fp, const char *fmt, double percent); 39int percent_color_fprintf(FILE *fp, const char *fmt, double percent);
39char *get_percent_color(double percent); 40const char *get_percent_color(double percent);
40 41
41#endif /* COLOR_H */ 42#endif /* COLOR_H */
diff --git a/tools/perf/util/config.c b/tools/perf/util/config.c
index 780df541006d..8784649109ce 100644
--- a/tools/perf/util/config.c
+++ b/tools/perf/util/config.c
@@ -160,17 +160,18 @@ static int get_extended_base_var(char *name, int baselen, int c)
160 name[baselen++] = '.'; 160 name[baselen++] = '.';
161 161
162 for (;;) { 162 for (;;) {
163 int c = get_next_char(); 163 int ch = get_next_char();
164 if (c == '\n') 164
165 if (ch == '\n')
165 return -1; 166 return -1;
166 if (c == '"') 167 if (ch == '"')
167 break; 168 break;
168 if (c == '\\') { 169 if (ch == '\\') {
169 c = get_next_char(); 170 ch = get_next_char();
170 if (c == '\n') 171 if (ch == '\n')
171 return -1; 172 return -1;
172 } 173 }
173 name[baselen++] = c; 174 name[baselen++] = ch;
174 if (baselen > MAXNAME / 2) 175 if (baselen > MAXNAME / 2)
175 return -1; 176 return -1;
176 } 177 }
@@ -530,6 +531,8 @@ static int store_aux(const char* key, const char* value, void *cb __used)
530 store.offset[store.seen] = ftell(config_file); 531 store.offset[store.seen] = ftell(config_file);
531 } 532 }
532 } 533 }
534 default:
535 break;
533 } 536 }
534 return 0; 537 return 0;
535} 538}
@@ -619,6 +622,7 @@ contline:
619 switch (contents[offset]) { 622 switch (contents[offset]) {
620 case '=': equal_offset = offset; break; 623 case '=': equal_offset = offset; break;
621 case ']': bracket_offset = offset; break; 624 case ']': bracket_offset = offset; break;
625 default: break;
622 } 626 }
623 if (offset > 0 && contents[offset-1] == '\\') { 627 if (offset > 0 && contents[offset-1] == '\\') {
624 offset_ = offset; 628 offset_ = offset;
@@ -742,9 +746,9 @@ int perf_config_set_multivar(const char* key, const char* value,
742 goto write_err_out; 746 goto write_err_out;
743 } else { 747 } else {
744 struct stat st; 748 struct stat st;
745 char* contents; 749 char *contents;
746 ssize_t contents_sz, copy_begin, copy_end; 750 ssize_t contents_sz, copy_begin, copy_end;
747 int i, new_line = 0; 751 int new_line = 0;
748 752
749 if (value_regex == NULL) 753 if (value_regex == NULL)
750 store.value_regex = NULL; 754 store.value_regex = NULL;
diff --git a/tools/perf/util/debug.c b/tools/perf/util/debug.c
new file mode 100644
index 000000000000..e8ca98fe0bd4
--- /dev/null
+++ b/tools/perf/util/debug.c
@@ -0,0 +1,95 @@
1/* For general debugging purposes */
2
3#include "../perf.h"
4
5#include <string.h>
6#include <stdarg.h>
7#include <stdio.h>
8
9#include "color.h"
10#include "event.h"
11#include "debug.h"
12
13int verbose = 0;
14int dump_trace = 0;
15
16int eprintf(const char *fmt, ...)
17{
18 va_list args;
19 int ret = 0;
20
21 if (verbose) {
22 va_start(args, fmt);
23 ret = vfprintf(stderr, fmt, args);
24 va_end(args);
25 }
26
27 return ret;
28}
29
30int dump_printf(const char *fmt, ...)
31{
32 va_list args;
33 int ret = 0;
34
35 if (dump_trace) {
36 va_start(args, fmt);
37 ret = vprintf(fmt, args);
38 va_end(args);
39 }
40
41 return ret;
42}
43
44static int dump_printf_color(const char *fmt, const char *color, ...)
45{
46 va_list args;
47 int ret = 0;
48
49 if (dump_trace) {
50 va_start(args, color);
51 ret = color_vfprintf(stdout, color, fmt, args);
52 va_end(args);
53 }
54
55 return ret;
56}
57
58
59void trace_event(event_t *event)
60{
61 unsigned char *raw_event = (void *)event;
62 const char *color = PERF_COLOR_BLUE;
63 int i, j;
64
65 if (!dump_trace)
66 return;
67
68 dump_printf(".");
69 dump_printf_color("\n. ... raw event: size %d bytes\n", color,
70 event->header.size);
71
72 for (i = 0; i < event->header.size; i++) {
73 if ((i & 15) == 0) {
74 dump_printf(".");
75 dump_printf_color(" %04x: ", color, i);
76 }
77
78 dump_printf_color(" %02x", color, raw_event[i]);
79
80 if (((i & 15) == 15) || i == event->header.size-1) {
81 dump_printf_color(" ", color);
82 for (j = 0; j < 15-(i & 15); j++)
83 dump_printf_color(" ", color);
84 for (j = 0; j < (i & 15); j++) {
85 if (isprint(raw_event[i-15+j]))
86 dump_printf_color("%c", color,
87 raw_event[i-15+j]);
88 else
89 dump_printf_color(".", color);
90 }
91 dump_printf_color("\n", color);
92 }
93 }
94 dump_printf(".\n");
95}
diff --git a/tools/perf/util/debug.h b/tools/perf/util/debug.h
new file mode 100644
index 000000000000..437eea58ce40
--- /dev/null
+++ b/tools/perf/util/debug.h
@@ -0,0 +1,8 @@
1/* For debugging general purposes */
2
3extern int verbose;
4extern int dump_trace;
5
6int eprintf(const char *fmt, ...) __attribute__((format(printf, 1, 2)));
7int dump_printf(const char *fmt, ...) __attribute__((format(printf, 1, 2)));
8void trace_event(event_t *event);
diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h
new file mode 100644
index 000000000000..2c9c26d6ded0
--- /dev/null
+++ b/tools/perf/util/event.h
@@ -0,0 +1,104 @@
1#ifndef __PERF_RECORD_H
2#define __PERF_RECORD_H
3#include "../perf.h"
4#include "util.h"
5#include <linux/list.h>
6
7enum {
8 SHOW_KERNEL = 1,
9 SHOW_USER = 2,
10 SHOW_HV = 4,
11};
12
13/*
14 * PERF_SAMPLE_IP | PERF_SAMPLE_TID | *
15 */
16struct ip_event {
17 struct perf_event_header header;
18 u64 ip;
19 u32 pid, tid;
20 unsigned char __more_data[];
21};
22
23struct mmap_event {
24 struct perf_event_header header;
25 u32 pid, tid;
26 u64 start;
27 u64 len;
28 u64 pgoff;
29 char filename[PATH_MAX];
30};
31
32struct comm_event {
33 struct perf_event_header header;
34 u32 pid, tid;
35 char comm[16];
36};
37
38struct fork_event {
39 struct perf_event_header header;
40 u32 pid, ppid;
41 u32 tid, ptid;
42 u64 time;
43};
44
45struct lost_event {
46 struct perf_event_header header;
47 u64 id;
48 u64 lost;
49};
50
51/*
52 * PERF_FORMAT_ENABLED | PERF_FORMAT_RUNNING | PERF_FORMAT_ID
53 */
54struct read_event {
55 struct perf_event_header header;
56 u32 pid, tid;
57 u64 value;
58 u64 time_enabled;
59 u64 time_running;
60 u64 id;
61};
62
63struct sample_event{
64 struct perf_event_header header;
65 u64 array[];
66};
67
68
69typedef union event_union {
70 struct perf_event_header header;
71 struct ip_event ip;
72 struct mmap_event mmap;
73 struct comm_event comm;
74 struct fork_event fork;
75 struct lost_event lost;
76 struct read_event read;
77 struct sample_event sample;
78} event_t;
79
80struct map {
81 struct list_head node;
82 u64 start;
83 u64 end;
84 u64 pgoff;
85 u64 (*map_ip)(struct map *, u64);
86 struct dso *dso;
87};
88
89static inline u64 map__map_ip(struct map *map, u64 ip)
90{
91 return ip - map->start + map->pgoff;
92}
93
94static inline u64 vdso__map_ip(struct map *map __used, u64 ip)
95{
96 return ip;
97}
98
99struct map *map__new(struct mmap_event *event, char *cwd, int cwdlen);
100struct map *map__clone(struct map *self);
101int map__overlap(struct map *l, struct map *r);
102size_t map__fprintf(struct map *self, FILE *fp);
103
104#endif
diff --git a/tools/perf/util/exec_cmd.c b/tools/perf/util/exec_cmd.c
index 34a352867382..2745605dba11 100644
--- a/tools/perf/util/exec_cmd.c
+++ b/tools/perf/util/exec_cmd.c
@@ -6,7 +6,6 @@
6 6
7#define MAX_ARGS 32 7#define MAX_ARGS 32
8 8
9extern char **environ;
10static const char *argv_exec_path; 9static const char *argv_exec_path;
11static const char *argv0_path; 10static const char *argv0_path;
12 11
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
index b92a457ca32e..e306857b2c2b 100644
--- a/tools/perf/util/header.c
+++ b/tools/perf/util/header.c
@@ -7,10 +7,9 @@
7#include "header.h" 7#include "header.h"
8 8
9/* 9/*
10 * 10 * Create new perf.data header attribute:
11 */ 11 */
12 12struct perf_header_attr *perf_header_attr__new(struct perf_event_attr *attr)
13struct perf_header_attr *perf_header_attr__new(struct perf_counter_attr *attr)
14{ 13{
15 struct perf_header_attr *self = malloc(sizeof(*self)); 14 struct perf_header_attr *self = malloc(sizeof(*self));
16 15
@@ -43,9 +42,8 @@ void perf_header_attr__add_id(struct perf_header_attr *self, u64 id)
43} 42}
44 43
45/* 44/*
46 * 45 * Create new perf.data header:
47 */ 46 */
48
49struct perf_header *perf_header__new(void) 47struct perf_header *perf_header__new(void)
50{ 48{
51 struct perf_header *self = malloc(sizeof(*self)); 49 struct perf_header *self = malloc(sizeof(*self));
@@ -86,6 +84,46 @@ void perf_header__add_attr(struct perf_header *self,
86 self->attr[pos] = attr; 84 self->attr[pos] = attr;
87} 85}
88 86
87#define MAX_EVENT_NAME 64
88
89struct perf_trace_event_type {
90 u64 event_id;
91 char name[MAX_EVENT_NAME];
92};
93
94static int event_count;
95static struct perf_trace_event_type *events;
96
97void perf_header__push_event(u64 id, const char *name)
98{
99 if (strlen(name) > MAX_EVENT_NAME)
100 printf("Event %s will be truncated\n", name);
101
102 if (!events) {
103 events = malloc(sizeof(struct perf_trace_event_type));
104 if (!events)
105 die("nomem");
106 } else {
107 events = realloc(events, (event_count + 1) * sizeof(struct perf_trace_event_type));
108 if (!events)
109 die("nomem");
110 }
111 memset(&events[event_count], 0, sizeof(struct perf_trace_event_type));
112 events[event_count].event_id = id;
113 strncpy(events[event_count].name, name, MAX_EVENT_NAME - 1);
114 event_count++;
115}
116
117char *perf_header__find_event(u64 id)
118{
119 int i;
120 for (i = 0 ; i < event_count; i++) {
121 if (events[i].event_id == id)
122 return events[i].name;
123 }
124 return NULL;
125}
126
89static const char *__perf_magic = "PERFFILE"; 127static const char *__perf_magic = "PERFFILE";
90 128
91#define PERF_MAGIC (*(u64 *)__perf_magic) 129#define PERF_MAGIC (*(u64 *)__perf_magic)
@@ -96,7 +134,7 @@ struct perf_file_section {
96}; 134};
97 135
98struct perf_file_attr { 136struct perf_file_attr {
99 struct perf_counter_attr attr; 137 struct perf_event_attr attr;
100 struct perf_file_section ids; 138 struct perf_file_section ids;
101}; 139};
102 140
@@ -106,6 +144,7 @@ struct perf_file_header {
106 u64 attr_size; 144 u64 attr_size;
107 struct perf_file_section attrs; 145 struct perf_file_section attrs;
108 struct perf_file_section data; 146 struct perf_file_section data;
147 struct perf_file_section event_types;
109}; 148};
110 149
111static void do_write(int fd, void *buf, size_t size) 150static void do_write(int fd, void *buf, size_t size)
@@ -154,6 +193,11 @@ void perf_header__write(struct perf_header *self, int fd)
154 do_write(fd, &f_attr, sizeof(f_attr)); 193 do_write(fd, &f_attr, sizeof(f_attr));
155 } 194 }
156 195
196 self->event_offset = lseek(fd, 0, SEEK_CUR);
197 self->event_size = event_count * sizeof(struct perf_trace_event_type);
198 if (events)
199 do_write(fd, events, self->event_size);
200
157 201
158 self->data_offset = lseek(fd, 0, SEEK_CUR); 202 self->data_offset = lseek(fd, 0, SEEK_CUR);
159 203
@@ -169,6 +213,10 @@ void perf_header__write(struct perf_header *self, int fd)
169 .offset = self->data_offset, 213 .offset = self->data_offset,
170 .size = self->data_size, 214 .size = self->data_size,
171 }, 215 },
216 .event_types = {
217 .offset = self->event_offset,
218 .size = self->event_size,
219 },
172 }; 220 };
173 221
174 lseek(fd, 0, SEEK_SET); 222 lseek(fd, 0, SEEK_SET);
@@ -234,12 +282,58 @@ struct perf_header *perf_header__read(int fd)
234 lseek(fd, tmp, SEEK_SET); 282 lseek(fd, tmp, SEEK_SET);
235 } 283 }
236 284
285 if (f_header.event_types.size) {
286 lseek(fd, f_header.event_types.offset, SEEK_SET);
287 events = malloc(f_header.event_types.size);
288 if (!events)
289 die("nomem");
290 do_read(fd, events, f_header.event_types.size);
291 event_count = f_header.event_types.size / sizeof(struct perf_trace_event_type);
292 }
293 self->event_offset = f_header.event_types.offset;
294 self->event_size = f_header.event_types.size;
295
237 self->data_offset = f_header.data.offset; 296 self->data_offset = f_header.data.offset;
238 self->data_size = f_header.data.size; 297 self->data_size = f_header.data.size;
239 298
240 lseek(fd, self->data_offset + self->data_size, SEEK_SET); 299 lseek(fd, self->data_offset, SEEK_SET);
241 300
242 self->frozen = 1; 301 self->frozen = 1;
243 302
244 return self; 303 return self;
245} 304}
305
306u64 perf_header__sample_type(struct perf_header *header)
307{
308 u64 type = 0;
309 int i;
310
311 for (i = 0; i < header->attrs; i++) {
312 struct perf_header_attr *attr = header->attr[i];
313
314 if (!type)
315 type = attr->attr.sample_type;
316 else if (type != attr->attr.sample_type)
317 die("non matching sample_type");
318 }
319
320 return type;
321}
322
323struct perf_event_attr *
324perf_header__find_attr(u64 id, struct perf_header *header)
325{
326 int i;
327
328 for (i = 0; i < header->attrs; i++) {
329 struct perf_header_attr *attr = header->attr[i];
330 int j;
331
332 for (j = 0; j < attr->ids; j++) {
333 if (attr->id[j] == id)
334 return &attr->attr;
335 }
336 }
337
338 return NULL;
339}
diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h
index bf280449fcfd..a0761bc7863c 100644
--- a/tools/perf/util/header.h
+++ b/tools/perf/util/header.h
@@ -1,12 +1,12 @@
1#ifndef _PERF_HEADER_H 1#ifndef _PERF_HEADER_H
2#define _PERF_HEADER_H 2#define _PERF_HEADER_H
3 3
4#include "../../../include/linux/perf_counter.h" 4#include "../../../include/linux/perf_event.h"
5#include <sys/types.h> 5#include <sys/types.h>
6#include "types.h" 6#include "types.h"
7 7
8struct perf_header_attr { 8struct perf_header_attr {
9 struct perf_counter_attr attr; 9 struct perf_event_attr attr;
10 int ids, size; 10 int ids, size;
11 u64 *id; 11 u64 *id;
12 off_t id_offset; 12 off_t id_offset;
@@ -19,6 +19,8 @@ struct perf_header {
19 s64 attr_offset; 19 s64 attr_offset;
20 u64 data_offset; 20 u64 data_offset;
21 u64 data_size; 21 u64 data_size;
22 u64 event_offset;
23 u64 event_size;
22}; 24};
23 25
24struct perf_header *perf_header__read(int fd); 26struct perf_header *perf_header__read(int fd);
@@ -27,10 +29,18 @@ void perf_header__write(struct perf_header *self, int fd);
27void perf_header__add_attr(struct perf_header *self, 29void perf_header__add_attr(struct perf_header *self,
28 struct perf_header_attr *attr); 30 struct perf_header_attr *attr);
29 31
32void perf_header__push_event(u64 id, const char *name);
33char *perf_header__find_event(u64 id);
34
35
30struct perf_header_attr * 36struct perf_header_attr *
31perf_header_attr__new(struct perf_counter_attr *attr); 37perf_header_attr__new(struct perf_event_attr *attr);
32void perf_header_attr__add_id(struct perf_header_attr *self, u64 id); 38void perf_header_attr__add_id(struct perf_header_attr *self, u64 id);
33 39
40u64 perf_header__sample_type(struct perf_header *header);
41struct perf_event_attr *
42perf_header__find_attr(u64 id, struct perf_header *header);
43
34 44
35struct perf_header *perf_header__new(void); 45struct perf_header *perf_header__new(void);
36 46
diff --git a/tools/perf/util/map.c b/tools/perf/util/map.c
new file mode 100644
index 000000000000..804e02382739
--- /dev/null
+++ b/tools/perf/util/map.c
@@ -0,0 +1,97 @@
1#include "event.h"
2#include "symbol.h"
3#include <stdlib.h>
4#include <string.h>
5#include <stdio.h>
6
7static inline int is_anon_memory(const char *filename)
8{
9 return strcmp(filename, "//anon") == 0;
10}
11
12static int strcommon(const char *pathname, char *cwd, int cwdlen)
13{
14 int n = 0;
15
16 while (n < cwdlen && pathname[n] == cwd[n])
17 ++n;
18
19 return n;
20}
21
22 struct map *map__new(struct mmap_event *event, char *cwd, int cwdlen)
23{
24 struct map *self = malloc(sizeof(*self));
25
26 if (self != NULL) {
27 const char *filename = event->filename;
28 char newfilename[PATH_MAX];
29 int anon;
30
31 if (cwd) {
32 int n = strcommon(filename, cwd, cwdlen);
33
34 if (n == cwdlen) {
35 snprintf(newfilename, sizeof(newfilename),
36 ".%s", filename + n);
37 filename = newfilename;
38 }
39 }
40
41 anon = is_anon_memory(filename);
42
43 if (anon) {
44 snprintf(newfilename, sizeof(newfilename), "/tmp/perf-%d.map", event->pid);
45 filename = newfilename;
46 }
47
48 self->start = event->start;
49 self->end = event->start + event->len;
50 self->pgoff = event->pgoff;
51
52 self->dso = dsos__findnew(filename);
53 if (self->dso == NULL)
54 goto out_delete;
55
56 if (self->dso == vdso || anon)
57 self->map_ip = vdso__map_ip;
58 else
59 self->map_ip = map__map_ip;
60 }
61 return self;
62out_delete:
63 free(self);
64 return NULL;
65}
66
67struct map *map__clone(struct map *self)
68{
69 struct map *map = malloc(sizeof(*self));
70
71 if (!map)
72 return NULL;
73
74 memcpy(map, self, sizeof(*self));
75
76 return map;
77}
78
79int map__overlap(struct map *l, struct map *r)
80{
81 if (l->start > r->start) {
82 struct map *t = l;
83 l = r;
84 r = t;
85 }
86
87 if (l->end > r->start)
88 return 1;
89
90 return 0;
91}
92
93size_t map__fprintf(struct map *self, FILE *fp)
94{
95 return fprintf(fp, " %Lx-%Lx %Lx %s\n",
96 self->start, self->end, self->pgoff, self->dso->name);
97}
diff --git a/tools/perf/util/module.c b/tools/perf/util/module.c
index ddabe925d65d..0d8c85defcd2 100644
--- a/tools/perf/util/module.c
+++ b/tools/perf/util/module.c
@@ -4,6 +4,7 @@
4#include "module.h" 4#include "module.h"
5 5
6#include <libelf.h> 6#include <libelf.h>
7#include <libgen.h>
7#include <gelf.h> 8#include <gelf.h>
8#include <elf.h> 9#include <elf.h>
9#include <dirent.h> 10#include <dirent.h>
@@ -409,53 +410,82 @@ out_failure:
409static int mod_dso__load_module_paths(struct mod_dso *self) 410static int mod_dso__load_module_paths(struct mod_dso *self)
410{ 411{
411 struct utsname uts; 412 struct utsname uts;
412 int count = 0, len; 413 int count = 0, len, err = -1;
413 char *line = NULL; 414 char *line = NULL;
414 FILE *file; 415 FILE *file;
415 char *path; 416 char *dpath, *dir;
416 size_t n; 417 size_t n;
417 418
418 if (uname(&uts) < 0) 419 if (uname(&uts) < 0)
419 goto out_failure; 420 return err;
420 421
421 len = strlen("/lib/modules/"); 422 len = strlen("/lib/modules/");
422 len += strlen(uts.release); 423 len += strlen(uts.release);
423 len += strlen("/modules.dep"); 424 len += strlen("/modules.dep");
424 425
425 path = calloc(1, len); 426 dpath = calloc(1, len + 1);
426 if (path == NULL) 427 if (dpath == NULL)
427 goto out_failure; 428 return err;
428 429
429 strcat(path, "/lib/modules/"); 430 strcat(dpath, "/lib/modules/");
430 strcat(path, uts.release); 431 strcat(dpath, uts.release);
431 strcat(path, "/modules.dep"); 432 strcat(dpath, "/modules.dep");
432 433
433 file = fopen(path, "r"); 434 file = fopen(dpath, "r");
434 free(path);
435 if (file == NULL) 435 if (file == NULL)
436 goto out_failure; 436 goto out_failure;
437 437
438 dir = dirname(dpath);
439 if (!dir)
440 goto out_failure;
441 strcat(dir, "/");
442
438 while (!feof(file)) { 443 while (!feof(file)) {
439 char *path, *name, *tmp;
440 struct module *module; 444 struct module *module;
441 int line_len, len; 445 char *name, *path, *tmp;
446 FILE *modfile;
447 int line_len;
442 448
443 line_len = getline(&line, &n, file); 449 line_len = getline(&line, &n, file);
444 if (line_len < 0) 450 if (line_len < 0)
445 break; 451 break;
446 452
447 if (!line) 453 if (!line)
448 goto out_failure; 454 break;
449 455
450 line[--line_len] = '\0'; /* \n */ 456 line[--line_len] = '\0'; /* \n */
451 457
452 path = strtok(line, ":"); 458 path = strchr(line, ':');
459 if (!path)
460 break;
461 *path = '\0';
462
463 path = strdup(line);
453 if (!path) 464 if (!path)
454 goto out_failure; 465 break;
466
467 if (!strstr(path, dir)) {
468 if (strncmp(path, "kernel/", 7))
469 break;
470
471 free(path);
472 path = calloc(1, strlen(dir) + strlen(line) + 1);
473 if (!path)
474 break;
475 strcat(path, dir);
476 strcat(path, line);
477 }
478
479 modfile = fopen(path, "r");
480 if (modfile == NULL)
481 break;
482 fclose(modfile);
455 483
456 name = strdup(path); 484 name = strdup(path);
457 name = strtok(name, "/"); 485 if (!name)
486 break;
458 487
488 name = strtok(name, "/");
459 tmp = name; 489 tmp = name;
460 490
461 while (tmp) { 491 while (tmp) {
@@ -463,26 +493,25 @@ static int mod_dso__load_module_paths(struct mod_dso *self)
463 if (tmp) 493 if (tmp)
464 name = tmp; 494 name = tmp;
465 } 495 }
496
466 name = strsep(&name, "."); 497 name = strsep(&name, ".");
498 if (!name)
499 break;
467 500
468 /* Quirk: replace '-' with '_' in sound modules */ 501 /* Quirk: replace '-' with '_' in all modules */
469 for (len = strlen(name); len; len--) { 502 for (len = strlen(name); len; len--) {
470 if (*(name+len) == '-') 503 if (*(name+len) == '-')
471 *(name+len) = '_'; 504 *(name+len) = '_';
472 } 505 }
473 506
474 module = module__new(name, path); 507 module = module__new(name, path);
475 if (!module) { 508 if (!module)
476 fprintf(stderr, "load_module_paths: allocation error\n"); 509 break;
477 goto out_failure;
478 }
479 mod_dso__insert_module(self, module); 510 mod_dso__insert_module(self, module);
480 511
481 module->sections = sec_dso__new_dso("sections"); 512 module->sections = sec_dso__new_dso("sections");
482 if (!module->sections) { 513 if (!module->sections)
483 fprintf(stderr, "load_module_paths: allocation error\n"); 514 break;
484 goto out_failure;
485 }
486 515
487 module->active = mod_dso__load_sections(module); 516 module->active = mod_dso__load_sections(module);
488 517
@@ -490,13 +519,20 @@ static int mod_dso__load_module_paths(struct mod_dso *self)
490 count++; 519 count++;
491 } 520 }
492 521
493 free(line); 522 if (feof(file))
494 fclose(file); 523 err = count;
495 524 else
496 return count; 525 fprintf(stderr, "load_module_paths: modules.dep parsing failure!\n");
497 526
498out_failure: 527out_failure:
499 return -1; 528 if (dpath)
529 free(dpath);
530 if (file)
531 fclose(file);
532 if (line)
533 free(line);
534
535 return err;
500} 536}
501 537
502int mod_dso__load_modules(struct mod_dso *dso) 538int mod_dso__load_modules(struct mod_dso *dso)
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index 044178408783..87c424de79ee 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -1,23 +1,28 @@
1 1
2#include "../perf.h"
3#include "util.h" 2#include "util.h"
3#include "../perf.h"
4#include "parse-options.h" 4#include "parse-options.h"
5#include "parse-events.h" 5#include "parse-events.h"
6#include "exec_cmd.h" 6#include "exec_cmd.h"
7#include "string.h" 7#include "string.h"
8#include "cache.h" 8#include "cache.h"
9 9#include "header.h"
10extern char *strcasestr(const char *haystack, const char *needle);
11 10
12int nr_counters; 11int nr_counters;
13 12
14struct perf_counter_attr attrs[MAX_COUNTERS]; 13struct perf_event_attr attrs[MAX_COUNTERS];
15 14
16struct event_symbol { 15struct event_symbol {
17 u8 type; 16 u8 type;
18 u64 config; 17 u64 config;
19 char *symbol; 18 const char *symbol;
20 char *alias; 19 const char *alias;
20};
21
22enum event_result {
23 EVT_FAILED,
24 EVT_HANDLED,
25 EVT_HANDLED_ALL
21}; 26};
22 27
23char debugfs_path[MAXPATHLEN]; 28char debugfs_path[MAXPATHLEN];
@@ -43,15 +48,15 @@ static struct event_symbol event_symbols[] = {
43 { CSW(CPU_MIGRATIONS), "cpu-migrations", "migrations" }, 48 { CSW(CPU_MIGRATIONS), "cpu-migrations", "migrations" },
44}; 49};
45 50
46#define __PERF_COUNTER_FIELD(config, name) \ 51#define __PERF_EVENT_FIELD(config, name) \
47 ((config & PERF_COUNTER_##name##_MASK) >> PERF_COUNTER_##name##_SHIFT) 52 ((config & PERF_EVENT_##name##_MASK) >> PERF_EVENT_##name##_SHIFT)
48 53
49#define PERF_COUNTER_RAW(config) __PERF_COUNTER_FIELD(config, RAW) 54#define PERF_EVENT_RAW(config) __PERF_EVENT_FIELD(config, RAW)
50#define PERF_COUNTER_CONFIG(config) __PERF_COUNTER_FIELD(config, CONFIG) 55#define PERF_EVENT_CONFIG(config) __PERF_EVENT_FIELD(config, CONFIG)
51#define PERF_COUNTER_TYPE(config) __PERF_COUNTER_FIELD(config, TYPE) 56#define PERF_EVENT_TYPE(config) __PERF_EVENT_FIELD(config, TYPE)
52#define PERF_COUNTER_ID(config) __PERF_COUNTER_FIELD(config, EVENT) 57#define PERF_EVENT_ID(config) __PERF_EVENT_FIELD(config, EVENT)
53 58
54static char *hw_event_names[] = { 59static const char *hw_event_names[] = {
55 "cycles", 60 "cycles",
56 "instructions", 61 "instructions",
57 "cache-references", 62 "cache-references",
@@ -61,7 +66,7 @@ static char *hw_event_names[] = {
61 "bus-cycles", 66 "bus-cycles",
62}; 67};
63 68
64static char *sw_event_names[] = { 69static const char *sw_event_names[] = {
65 "cpu-clock-msecs", 70 "cpu-clock-msecs",
66 "task-clock-msecs", 71 "task-clock-msecs",
67 "page-faults", 72 "page-faults",
@@ -73,7 +78,7 @@ static char *sw_event_names[] = {
73 78
74#define MAX_ALIASES 8 79#define MAX_ALIASES 8
75 80
76static char *hw_cache[][MAX_ALIASES] = { 81static const char *hw_cache[][MAX_ALIASES] = {
77 { "L1-dcache", "l1-d", "l1d", "L1-data", }, 82 { "L1-dcache", "l1-d", "l1d", "L1-data", },
78 { "L1-icache", "l1-i", "l1i", "L1-instruction", }, 83 { "L1-icache", "l1-i", "l1i", "L1-instruction", },
79 { "LLC", "L2" }, 84 { "LLC", "L2" },
@@ -82,13 +87,13 @@ static char *hw_cache[][MAX_ALIASES] = {
82 { "branch", "branches", "bpu", "btb", "bpc", }, 87 { "branch", "branches", "bpu", "btb", "bpc", },
83}; 88};
84 89
85static char *hw_cache_op[][MAX_ALIASES] = { 90static const char *hw_cache_op[][MAX_ALIASES] = {
86 { "load", "loads", "read", }, 91 { "load", "loads", "read", },
87 { "store", "stores", "write", }, 92 { "store", "stores", "write", },
88 { "prefetch", "prefetches", "speculative-read", "speculative-load", }, 93 { "prefetch", "prefetches", "speculative-read", "speculative-load", },
89}; 94};
90 95
91static char *hw_cache_result[][MAX_ALIASES] = { 96static const char *hw_cache_result[][MAX_ALIASES] = {
92 { "refs", "Reference", "ops", "access", }, 97 { "refs", "Reference", "ops", "access", },
93 { "misses", "miss", }, 98 { "misses", "miss", },
94}; 99};
@@ -113,11 +118,9 @@ static unsigned long hw_cache_stat[C(MAX)] = {
113 [C(BPU)] = (CACHE_READ), 118 [C(BPU)] = (CACHE_READ),
114}; 119};
115 120
116#define for_each_subsystem(sys_dir, sys_dirent, sys_next, file, st) \ 121#define for_each_subsystem(sys_dir, sys_dirent, sys_next) \
117 while (!readdir_r(sys_dir, &sys_dirent, &sys_next) && sys_next) \ 122 while (!readdir_r(sys_dir, &sys_dirent, &sys_next) && sys_next) \
118 if (snprintf(file, MAXPATHLEN, "%s/%s", debugfs_path, \ 123 if (sys_dirent.d_type == DT_DIR && \
119 sys_dirent.d_name) && \
120 (!stat(file, &st)) && (S_ISDIR(st.st_mode)) && \
121 (strcmp(sys_dirent.d_name, ".")) && \ 124 (strcmp(sys_dirent.d_name, ".")) && \
122 (strcmp(sys_dirent.d_name, ".."))) 125 (strcmp(sys_dirent.d_name, "..")))
123 126
@@ -136,16 +139,14 @@ static int tp_event_has_id(struct dirent *sys_dir, struct dirent *evt_dir)
136 return 0; 139 return 0;
137} 140}
138 141
139#define for_each_event(sys_dirent, evt_dir, evt_dirent, evt_next, file, st) \ 142#define for_each_event(sys_dirent, evt_dir, evt_dirent, evt_next) \
140 while (!readdir_r(evt_dir, &evt_dirent, &evt_next) && evt_next) \ 143 while (!readdir_r(evt_dir, &evt_dirent, &evt_next) && evt_next) \
141 if (snprintf(file, MAXPATHLEN, "%s/%s/%s", debugfs_path, \ 144 if (evt_dirent.d_type == DT_DIR && \
142 sys_dirent.d_name, evt_dirent.d_name) && \
143 (!stat(file, &st)) && (S_ISDIR(st.st_mode)) && \
144 (strcmp(evt_dirent.d_name, ".")) && \ 145 (strcmp(evt_dirent.d_name, ".")) && \
145 (strcmp(evt_dirent.d_name, "..")) && \ 146 (strcmp(evt_dirent.d_name, "..")) && \
146 (!tp_event_has_id(&sys_dirent, &evt_dirent))) 147 (!tp_event_has_id(&sys_dirent, &evt_dirent)))
147 148
148#define MAX_EVENT_LENGTH 30 149#define MAX_EVENT_LENGTH 512
149 150
150int valid_debugfs_mount(const char *debugfs) 151int valid_debugfs_mount(const char *debugfs)
151{ 152{
@@ -158,32 +159,35 @@ int valid_debugfs_mount(const char *debugfs)
158 return 0; 159 return 0;
159} 160}
160 161
161static char *tracepoint_id_to_name(u64 config) 162struct tracepoint_path *tracepoint_id_to_path(u64 config)
162{ 163{
163 static char tracepoint_name[2 * MAX_EVENT_LENGTH]; 164 struct tracepoint_path *path = NULL;
164 DIR *sys_dir, *evt_dir; 165 DIR *sys_dir, *evt_dir;
165 struct dirent *sys_next, *evt_next, sys_dirent, evt_dirent; 166 struct dirent *sys_next, *evt_next, sys_dirent, evt_dirent;
166 struct stat st;
167 char id_buf[4]; 167 char id_buf[4];
168 int fd; 168 int fd;
169 u64 id; 169 u64 id;
170 char evt_path[MAXPATHLEN]; 170 char evt_path[MAXPATHLEN];
171 char dir_path[MAXPATHLEN];
171 172
172 if (valid_debugfs_mount(debugfs_path)) 173 if (valid_debugfs_mount(debugfs_path))
173 return "unkown"; 174 return NULL;
174 175
175 sys_dir = opendir(debugfs_path); 176 sys_dir = opendir(debugfs_path);
176 if (!sys_dir) 177 if (!sys_dir)
177 goto cleanup; 178 return NULL;
179
180 for_each_subsystem(sys_dir, sys_dirent, sys_next) {
178 181
179 for_each_subsystem(sys_dir, sys_dirent, sys_next, evt_path, st) { 182 snprintf(dir_path, MAXPATHLEN, "%s/%s", debugfs_path,
180 evt_dir = opendir(evt_path); 183 sys_dirent.d_name);
184 evt_dir = opendir(dir_path);
181 if (!evt_dir) 185 if (!evt_dir)
182 goto cleanup; 186 continue;
183 for_each_event(sys_dirent, evt_dir, evt_dirent, evt_next, 187
184 evt_path, st) { 188 for_each_event(sys_dirent, evt_dir, evt_dirent, evt_next) {
185 snprintf(evt_path, MAXPATHLEN, "%s/%s/%s/id", 189
186 debugfs_path, sys_dirent.d_name, 190 snprintf(evt_path, MAXPATHLEN, "%s/%s/id", dir_path,
187 evt_dirent.d_name); 191 evt_dirent.d_name);
188 fd = open(evt_path, O_RDONLY); 192 fd = open(evt_path, O_RDONLY);
189 if (fd < 0) 193 if (fd < 0)
@@ -197,18 +201,48 @@ static char *tracepoint_id_to_name(u64 config)
197 if (id == config) { 201 if (id == config) {
198 closedir(evt_dir); 202 closedir(evt_dir);
199 closedir(sys_dir); 203 closedir(sys_dir);
200 snprintf(tracepoint_name, 2 * MAX_EVENT_LENGTH, 204 path = calloc(1, sizeof(path));
201 "%s:%s", sys_dirent.d_name, 205 path->system = malloc(MAX_EVENT_LENGTH);
202 evt_dirent.d_name); 206 if (!path->system) {
203 return tracepoint_name; 207 free(path);
208 return NULL;
209 }
210 path->name = malloc(MAX_EVENT_LENGTH);
211 if (!path->name) {
212 free(path->system);
213 free(path);
214 return NULL;
215 }
216 strncpy(path->system, sys_dirent.d_name,
217 MAX_EVENT_LENGTH);
218 strncpy(path->name, evt_dirent.d_name,
219 MAX_EVENT_LENGTH);
220 return path;
204 } 221 }
205 } 222 }
206 closedir(evt_dir); 223 closedir(evt_dir);
207 } 224 }
208 225
209cleanup:
210 closedir(sys_dir); 226 closedir(sys_dir);
211 return "unkown"; 227 return NULL;
228}
229
230#define TP_PATH_LEN (MAX_EVENT_LENGTH * 2 + 1)
231static const char *tracepoint_id_to_name(u64 config)
232{
233 static char buf[TP_PATH_LEN];
234 struct tracepoint_path *path;
235
236 path = tracepoint_id_to_path(config);
237 if (path) {
238 snprintf(buf, TP_PATH_LEN, "%s:%s", path->system, path->name);
239 free(path->name);
240 free(path->system);
241 free(path);
242 } else
243 snprintf(buf, TP_PATH_LEN, "%s:%s", "unknown", "unknown");
244
245 return buf;
212} 246}
213 247
214static int is_cache_op_valid(u8 cache_type, u8 cache_op) 248static int is_cache_op_valid(u8 cache_type, u8 cache_op)
@@ -235,7 +269,7 @@ static char *event_cache_name(u8 cache_type, u8 cache_op, u8 cache_result)
235 return name; 269 return name;
236} 270}
237 271
238char *event_name(int counter) 272const char *event_name(int counter)
239{ 273{
240 u64 config = attrs[counter].config; 274 u64 config = attrs[counter].config;
241 int type = attrs[counter].type; 275 int type = attrs[counter].type;
@@ -243,7 +277,7 @@ char *event_name(int counter)
243 return __event_name(type, config); 277 return __event_name(type, config);
244} 278}
245 279
246char *__event_name(int type, u64 config) 280const char *__event_name(int type, u64 config)
247{ 281{
248 static char buf[32]; 282 static char buf[32];
249 283
@@ -294,7 +328,7 @@ char *__event_name(int type, u64 config)
294 return "unknown"; 328 return "unknown";
295} 329}
296 330
297static int parse_aliases(const char **str, char *names[][MAX_ALIASES], int size) 331static int parse_aliases(const char **str, const char *names[][MAX_ALIASES], int size)
298{ 332{
299 int i, j; 333 int i, j;
300 int n, longest = -1; 334 int n, longest = -1;
@@ -314,8 +348,8 @@ static int parse_aliases(const char **str, char *names[][MAX_ALIASES], int size)
314 return -1; 348 return -1;
315} 349}
316 350
317static int 351static enum event_result
318parse_generic_hw_event(const char **str, struct perf_counter_attr *attr) 352parse_generic_hw_event(const char **str, struct perf_event_attr *attr)
319{ 353{
320 const char *s = *str; 354 const char *s = *str;
321 int cache_type = -1, cache_op = -1, cache_result = -1; 355 int cache_type = -1, cache_op = -1, cache_result = -1;
@@ -326,7 +360,7 @@ parse_generic_hw_event(const char **str, struct perf_counter_attr *attr)
326 * then bail out: 360 * then bail out:
327 */ 361 */
328 if (cache_type == -1) 362 if (cache_type == -1)
329 return 0; 363 return EVT_FAILED;
330 364
331 while ((cache_op == -1 || cache_result == -1) && *s == '-') { 365 while ((cache_op == -1 || cache_result == -1) && *s == '-') {
332 ++s; 366 ++s;
@@ -372,27 +406,115 @@ parse_generic_hw_event(const char **str, struct perf_counter_attr *attr)
372 attr->type = PERF_TYPE_HW_CACHE; 406 attr->type = PERF_TYPE_HW_CACHE;
373 407
374 *str = s; 408 *str = s;
375 return 1; 409 return EVT_HANDLED;
410}
411
412static enum event_result
413parse_single_tracepoint_event(char *sys_name,
414 const char *evt_name,
415 unsigned int evt_length,
416 char *flags,
417 struct perf_event_attr *attr,
418 const char **strp)
419{
420 char evt_path[MAXPATHLEN];
421 char id_buf[4];
422 u64 id;
423 int fd;
424
425 if (flags) {
426 if (!strncmp(flags, "record", strlen(flags))) {
427 attr->sample_type |= PERF_SAMPLE_RAW;
428 attr->sample_type |= PERF_SAMPLE_TIME;
429 attr->sample_type |= PERF_SAMPLE_CPU;
430 }
431 }
432
433 snprintf(evt_path, MAXPATHLEN, "%s/%s/%s/id", debugfs_path,
434 sys_name, evt_name);
435
436 fd = open(evt_path, O_RDONLY);
437 if (fd < 0)
438 return EVT_FAILED;
439
440 if (read(fd, id_buf, sizeof(id_buf)) < 0) {
441 close(fd);
442 return EVT_FAILED;
443 }
444
445 close(fd);
446 id = atoll(id_buf);
447 attr->config = id;
448 attr->type = PERF_TYPE_TRACEPOINT;
449 *strp = evt_name + evt_length;
450
451 return EVT_HANDLED;
452}
453
454/* sys + ':' + event + ':' + flags*/
455#define MAX_EVOPT_LEN (MAX_EVENT_LENGTH * 2 + 2 + 128)
456static enum event_result
457parse_subsystem_tracepoint_event(char *sys_name, char *flags)
458{
459 char evt_path[MAXPATHLEN];
460 struct dirent *evt_ent;
461 DIR *evt_dir;
462
463 snprintf(evt_path, MAXPATHLEN, "%s/%s", debugfs_path, sys_name);
464 evt_dir = opendir(evt_path);
465
466 if (!evt_dir) {
467 perror("Can't open event dir");
468 return EVT_FAILED;
469 }
470
471 while ((evt_ent = readdir(evt_dir))) {
472 char event_opt[MAX_EVOPT_LEN + 1];
473 int len;
474 unsigned int rem = MAX_EVOPT_LEN;
475
476 if (!strcmp(evt_ent->d_name, ".")
477 || !strcmp(evt_ent->d_name, "..")
478 || !strcmp(evt_ent->d_name, "enable")
479 || !strcmp(evt_ent->d_name, "filter"))
480 continue;
481
482 len = snprintf(event_opt, MAX_EVOPT_LEN, "%s:%s", sys_name,
483 evt_ent->d_name);
484 if (len < 0)
485 return EVT_FAILED;
486
487 rem -= len;
488 if (flags) {
489 if (rem < strlen(flags) + 1)
490 return EVT_FAILED;
491
492 strcat(event_opt, ":");
493 strcat(event_opt, flags);
494 }
495
496 if (parse_events(NULL, event_opt, 0))
497 return EVT_FAILED;
498 }
499
500 return EVT_HANDLED_ALL;
376} 501}
377 502
378static int parse_tracepoint_event(const char **strp, 503
379 struct perf_counter_attr *attr) 504static enum event_result parse_tracepoint_event(const char **strp,
505 struct perf_event_attr *attr)
380{ 506{
381 const char *evt_name; 507 const char *evt_name;
382 char *flags; 508 char *flags;
383 char sys_name[MAX_EVENT_LENGTH]; 509 char sys_name[MAX_EVENT_LENGTH];
384 char id_buf[4];
385 int fd;
386 unsigned int sys_length, evt_length; 510 unsigned int sys_length, evt_length;
387 u64 id;
388 char evt_path[MAXPATHLEN];
389 511
390 if (valid_debugfs_mount(debugfs_path)) 512 if (valid_debugfs_mount(debugfs_path))
391 return 0; 513 return 0;
392 514
393 evt_name = strchr(*strp, ':'); 515 evt_name = strchr(*strp, ':');
394 if (!evt_name) 516 if (!evt_name)
395 return 0; 517 return EVT_FAILED;
396 518
397 sys_length = evt_name - *strp; 519 sys_length = evt_name - *strp;
398 if (sys_length >= MAX_EVENT_LENGTH) 520 if (sys_length >= MAX_EVENT_LENGTH)
@@ -404,32 +526,22 @@ static int parse_tracepoint_event(const char **strp,
404 526
405 flags = strchr(evt_name, ':'); 527 flags = strchr(evt_name, ':');
406 if (flags) { 528 if (flags) {
407 *flags = '\0'; 529 /* split it out: */
530 evt_name = strndup(evt_name, flags - evt_name);
408 flags++; 531 flags++;
409 if (!strncmp(flags, "record", strlen(flags)))
410 attr->sample_type |= PERF_SAMPLE_RAW;
411 } 532 }
412 533
413 evt_length = strlen(evt_name); 534 evt_length = strlen(evt_name);
414 if (evt_length >= MAX_EVENT_LENGTH) 535 if (evt_length >= MAX_EVENT_LENGTH)
415 return 0; 536 return EVT_FAILED;
416 537
417 snprintf(evt_path, MAXPATHLEN, "%s/%s/%s/id", debugfs_path, 538 if (!strcmp(evt_name, "*")) {
418 sys_name, evt_name); 539 *strp = evt_name + evt_length;
419 fd = open(evt_path, O_RDONLY); 540 return parse_subsystem_tracepoint_event(sys_name, flags);
420 if (fd < 0) 541 } else
421 return 0; 542 return parse_single_tracepoint_event(sys_name, evt_name,
422 543 evt_length, flags,
423 if (read(fd, id_buf, sizeof(id_buf)) < 0) { 544 attr, strp);
424 close(fd);
425 return 0;
426 }
427 close(fd);
428 id = atoll(id_buf);
429 attr->config = id;
430 attr->type = PERF_TYPE_TRACEPOINT;
431 *strp = evt_name + evt_length;
432 return 1;
433} 545}
434 546
435static int check_events(const char *str, unsigned int i) 547static int check_events(const char *str, unsigned int i)
@@ -447,8 +559,8 @@ static int check_events(const char *str, unsigned int i)
447 return 0; 559 return 0;
448} 560}
449 561
450static int 562static enum event_result
451parse_symbolic_event(const char **strp, struct perf_counter_attr *attr) 563parse_symbolic_event(const char **strp, struct perf_event_attr *attr)
452{ 564{
453 const char *str = *strp; 565 const char *str = *strp;
454 unsigned int i; 566 unsigned int i;
@@ -460,32 +572,33 @@ parse_symbolic_event(const char **strp, struct perf_counter_attr *attr)
460 attr->type = event_symbols[i].type; 572 attr->type = event_symbols[i].type;
461 attr->config = event_symbols[i].config; 573 attr->config = event_symbols[i].config;
462 *strp = str + n; 574 *strp = str + n;
463 return 1; 575 return EVT_HANDLED;
464 } 576 }
465 } 577 }
466 return 0; 578 return EVT_FAILED;
467} 579}
468 580
469static int parse_raw_event(const char **strp, struct perf_counter_attr *attr) 581static enum event_result
582parse_raw_event(const char **strp, struct perf_event_attr *attr)
470{ 583{
471 const char *str = *strp; 584 const char *str = *strp;
472 u64 config; 585 u64 config;
473 int n; 586 int n;
474 587
475 if (*str != 'r') 588 if (*str != 'r')
476 return 0; 589 return EVT_FAILED;
477 n = hex2u64(str + 1, &config); 590 n = hex2u64(str + 1, &config);
478 if (n > 0) { 591 if (n > 0) {
479 *strp = str + n + 1; 592 *strp = str + n + 1;
480 attr->type = PERF_TYPE_RAW; 593 attr->type = PERF_TYPE_RAW;
481 attr->config = config; 594 attr->config = config;
482 return 1; 595 return EVT_HANDLED;
483 } 596 }
484 return 0; 597 return EVT_FAILED;
485} 598}
486 599
487static int 600static enum event_result
488parse_numeric_event(const char **strp, struct perf_counter_attr *attr) 601parse_numeric_event(const char **strp, struct perf_event_attr *attr)
489{ 602{
490 const char *str = *strp; 603 const char *str = *strp;
491 char *endp; 604 char *endp;
@@ -500,14 +613,14 @@ parse_numeric_event(const char **strp, struct perf_counter_attr *attr)
500 attr->type = type; 613 attr->type = type;
501 attr->config = config; 614 attr->config = config;
502 *strp = endp; 615 *strp = endp;
503 return 1; 616 return EVT_HANDLED;
504 } 617 }
505 } 618 }
506 return 0; 619 return EVT_FAILED;
507} 620}
508 621
509static int 622static enum event_result
510parse_event_modifier(const char **strp, struct perf_counter_attr *attr) 623parse_event_modifier(const char **strp, struct perf_event_attr *attr)
511{ 624{
512 const char *str = *strp; 625 const char *str = *strp;
513 int eu = 1, ek = 1, eh = 1; 626 int eu = 1, ek = 1, eh = 1;
@@ -539,37 +652,84 @@ parse_event_modifier(const char **strp, struct perf_counter_attr *attr)
539 * Each event can have multiple symbolic names. 652 * Each event can have multiple symbolic names.
540 * Symbolic names are (almost) exactly matched. 653 * Symbolic names are (almost) exactly matched.
541 */ 654 */
542static int parse_event_symbols(const char **str, struct perf_counter_attr *attr) 655static enum event_result
656parse_event_symbols(const char **str, struct perf_event_attr *attr)
543{ 657{
544 if (!(parse_tracepoint_event(str, attr) || 658 enum event_result ret;
545 parse_raw_event(str, attr) || 659
546 parse_numeric_event(str, attr) || 660 ret = parse_tracepoint_event(str, attr);
547 parse_symbolic_event(str, attr) || 661 if (ret != EVT_FAILED)
548 parse_generic_hw_event(str, attr))) 662 goto modifier;
549 return 0;
550 663
664 ret = parse_raw_event(str, attr);
665 if (ret != EVT_FAILED)
666 goto modifier;
667
668 ret = parse_numeric_event(str, attr);
669 if (ret != EVT_FAILED)
670 goto modifier;
671
672 ret = parse_symbolic_event(str, attr);
673 if (ret != EVT_FAILED)
674 goto modifier;
675
676 ret = parse_generic_hw_event(str, attr);
677 if (ret != EVT_FAILED)
678 goto modifier;
679
680 return EVT_FAILED;
681
682modifier:
551 parse_event_modifier(str, attr); 683 parse_event_modifier(str, attr);
552 684
553 return 1; 685 return ret;
554} 686}
555 687
688static void store_event_type(const char *orgname)
689{
690 char filename[PATH_MAX], *c;
691 FILE *file;
692 int id;
693
694 sprintf(filename, "/sys/kernel/debug/tracing/events/%s/id", orgname);
695 c = strchr(filename, ':');
696 if (c)
697 *c = '/';
698
699 file = fopen(filename, "r");
700 if (!file)
701 return;
702 if (fscanf(file, "%i", &id) < 1)
703 die("cannot store event ID");
704 fclose(file);
705 perf_header__push_event(id, orgname);
706}
707
708
556int parse_events(const struct option *opt __used, const char *str, int unset __used) 709int parse_events(const struct option *opt __used, const char *str, int unset __used)
557{ 710{
558 struct perf_counter_attr attr; 711 struct perf_event_attr attr;
712 enum event_result ret;
713
714 if (strchr(str, ':'))
715 store_event_type(str);
559 716
560 for (;;) { 717 for (;;) {
561 if (nr_counters == MAX_COUNTERS) 718 if (nr_counters == MAX_COUNTERS)
562 return -1; 719 return -1;
563 720
564 memset(&attr, 0, sizeof(attr)); 721 memset(&attr, 0, sizeof(attr));
565 if (!parse_event_symbols(&str, &attr)) 722 ret = parse_event_symbols(&str, &attr);
723 if (ret == EVT_FAILED)
566 return -1; 724 return -1;
567 725
568 if (!(*str == 0 || *str == ',' || isspace(*str))) 726 if (!(*str == 0 || *str == ',' || isspace(*str)))
569 return -1; 727 return -1;
570 728
571 attrs[nr_counters] = attr; 729 if (ret != EVT_HANDLED_ALL) {
572 nr_counters++; 730 attrs[nr_counters] = attr;
731 nr_counters++;
732 }
573 733
574 if (*str == 0) 734 if (*str == 0)
575 break; 735 break;
@@ -598,31 +758,32 @@ static void print_tracepoint_events(void)
598{ 758{
599 DIR *sys_dir, *evt_dir; 759 DIR *sys_dir, *evt_dir;
600 struct dirent *sys_next, *evt_next, sys_dirent, evt_dirent; 760 struct dirent *sys_next, *evt_next, sys_dirent, evt_dirent;
601 struct stat st;
602 char evt_path[MAXPATHLEN]; 761 char evt_path[MAXPATHLEN];
762 char dir_path[MAXPATHLEN];
603 763
604 if (valid_debugfs_mount(debugfs_path)) 764 if (valid_debugfs_mount(debugfs_path))
605 return; 765 return;
606 766
607 sys_dir = opendir(debugfs_path); 767 sys_dir = opendir(debugfs_path);
608 if (!sys_dir) 768 if (!sys_dir)
609 goto cleanup; 769 return;
610 770
611 for_each_subsystem(sys_dir, sys_dirent, sys_next, evt_path, st) { 771 for_each_subsystem(sys_dir, sys_dirent, sys_next) {
612 evt_dir = opendir(evt_path); 772
773 snprintf(dir_path, MAXPATHLEN, "%s/%s", debugfs_path,
774 sys_dirent.d_name);
775 evt_dir = opendir(dir_path);
613 if (!evt_dir) 776 if (!evt_dir)
614 goto cleanup; 777 continue;
615 for_each_event(sys_dirent, evt_dir, evt_dirent, evt_next, 778
616 evt_path, st) { 779 for_each_event(sys_dirent, evt_dir, evt_dirent, evt_next) {
617 snprintf(evt_path, MAXPATHLEN, "%s:%s", 780 snprintf(evt_path, MAXPATHLEN, "%s:%s",
618 sys_dirent.d_name, evt_dirent.d_name); 781 sys_dirent.d_name, evt_dirent.d_name);
619 fprintf(stderr, " %-40s [%s]\n", evt_path, 782 fprintf(stderr, " %-42s [%s]\n", evt_path,
620 event_type_descriptors[PERF_TYPE_TRACEPOINT+1]); 783 event_type_descriptors[PERF_TYPE_TRACEPOINT+1]);
621 } 784 }
622 closedir(evt_dir); 785 closedir(evt_dir);
623 } 786 }
624
625cleanup:
626 closedir(sys_dir); 787 closedir(sys_dir);
627} 788}
628 789
@@ -650,7 +811,7 @@ void print_events(void)
650 sprintf(name, "%s OR %s", syms->symbol, syms->alias); 811 sprintf(name, "%s OR %s", syms->symbol, syms->alias);
651 else 812 else
652 strcpy(name, syms->symbol); 813 strcpy(name, syms->symbol);
653 fprintf(stderr, " %-40s [%s]\n", name, 814 fprintf(stderr, " %-42s [%s]\n", name,
654 event_type_descriptors[type]); 815 event_type_descriptors[type]);
655 816
656 prev_type = type; 817 prev_type = type;
@@ -664,7 +825,7 @@ void print_events(void)
664 continue; 825 continue;
665 826
666 for (i = 0; i < PERF_COUNT_HW_CACHE_RESULT_MAX; i++) { 827 for (i = 0; i < PERF_COUNT_HW_CACHE_RESULT_MAX; i++) {
667 fprintf(stderr, " %-40s [%s]\n", 828 fprintf(stderr, " %-42s [%s]\n",
668 event_cache_name(type, op, i), 829 event_cache_name(type, op, i),
669 event_type_descriptors[4]); 830 event_type_descriptors[4]);
670 } 831 }
@@ -672,7 +833,7 @@ void print_events(void)
672 } 833 }
673 834
674 fprintf(stderr, "\n"); 835 fprintf(stderr, "\n");
675 fprintf(stderr, " %-40s [raw hardware event descriptor]\n", 836 fprintf(stderr, " %-42s [raw hardware event descriptor]\n",
676 "rNNN"); 837 "rNNN");
677 fprintf(stderr, "\n"); 838 fprintf(stderr, "\n");
678 839
diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h
index 192a962e3a0f..30c608112845 100644
--- a/tools/perf/util/parse-events.h
+++ b/tools/perf/util/parse-events.h
@@ -1,16 +1,25 @@
1 1#ifndef _PARSE_EVENTS_H
2#define _PARSE_EVENTS_H
2/* 3/*
3 * Parse symbolic events/counts passed in as options: 4 * Parse symbolic events/counts passed in as options:
4 */ 5 */
5 6
6struct option; 7struct option;
7 8
9struct tracepoint_path {
10 char *system;
11 char *name;
12 struct tracepoint_path *next;
13};
14
15extern struct tracepoint_path *tracepoint_id_to_path(u64 config);
16
8extern int nr_counters; 17extern int nr_counters;
9 18
10extern struct perf_counter_attr attrs[MAX_COUNTERS]; 19extern struct perf_event_attr attrs[MAX_COUNTERS];
11 20
12extern char *event_name(int ctr); 21extern const char *event_name(int ctr);
13extern char *__event_name(int type, u64 config); 22extern const char *__event_name(int type, u64 config);
14 23
15extern int parse_events(const struct option *opt, const char *str, int unset); 24extern int parse_events(const struct option *opt, const char *str, int unset);
16 25
@@ -21,3 +30,5 @@ extern void print_events(void);
21extern char debugfs_path[]; 30extern char debugfs_path[];
22extern int valid_debugfs_mount(const char *debugfs); 31extern int valid_debugfs_mount(const char *debugfs);
23 32
33
34#endif /* _PARSE_EVENTS_H */
diff --git a/tools/perf/util/parse-options.c b/tools/perf/util/parse-options.c
index 1bf67190c820..6d8af48c925e 100644
--- a/tools/perf/util/parse-options.c
+++ b/tools/perf/util/parse-options.c
@@ -53,6 +53,12 @@ static int get_value(struct parse_opt_ctx_t *p,
53 case OPTION_SET_INT: 53 case OPTION_SET_INT:
54 case OPTION_SET_PTR: 54 case OPTION_SET_PTR:
55 return opterror(opt, "takes no value", flags); 55 return opterror(opt, "takes no value", flags);
56 case OPTION_END:
57 case OPTION_ARGUMENT:
58 case OPTION_GROUP:
59 case OPTION_STRING:
60 case OPTION_INTEGER:
61 case OPTION_LONG:
56 default: 62 default:
57 break; 63 break;
58 } 64 }
@@ -130,6 +136,9 @@ static int get_value(struct parse_opt_ctx_t *p,
130 return opterror(opt, "expects a numerical value", flags); 136 return opterror(opt, "expects a numerical value", flags);
131 return 0; 137 return 0;
132 138
139 case OPTION_END:
140 case OPTION_ARGUMENT:
141 case OPTION_GROUP:
133 default: 142 default:
134 die("should not happen, someone must be hit on the forehead"); 143 die("should not happen, someone must be hit on the forehead");
135 } 144 }
@@ -296,6 +305,8 @@ int parse_options_step(struct parse_opt_ctx_t *ctx,
296 return parse_options_usage(usagestr, options); 305 return parse_options_usage(usagestr, options);
297 case -2: 306 case -2:
298 goto unknown; 307 goto unknown;
308 default:
309 break;
299 } 310 }
300 if (ctx->opt) 311 if (ctx->opt)
301 check_typos(arg + 1, options); 312 check_typos(arg + 1, options);
@@ -314,6 +325,8 @@ int parse_options_step(struct parse_opt_ctx_t *ctx,
314 ctx->argv[0] = strdup(ctx->opt - 1); 325 ctx->argv[0] = strdup(ctx->opt - 1);
315 *(char *)ctx->argv[0] = '-'; 326 *(char *)ctx->argv[0] = '-';
316 goto unknown; 327 goto unknown;
328 default:
329 break;
317 } 330 }
318 } 331 }
319 continue; 332 continue;
@@ -336,6 +349,8 @@ int parse_options_step(struct parse_opt_ctx_t *ctx,
336 return parse_options_usage(usagestr, options); 349 return parse_options_usage(usagestr, options);
337 case -2: 350 case -2:
338 goto unknown; 351 goto unknown;
352 default:
353 break;
339 } 354 }
340 continue; 355 continue;
341unknown: 356unknown:
@@ -456,6 +471,13 @@ int usage_with_options_internal(const char * const *usagestr,
456 } 471 }
457 break; 472 break;
458 default: /* OPTION_{BIT,BOOLEAN,SET_INT,SET_PTR} */ 473 default: /* OPTION_{BIT,BOOLEAN,SET_INT,SET_PTR} */
474 case OPTION_END:
475 case OPTION_GROUP:
476 case OPTION_BIT:
477 case OPTION_BOOLEAN:
478 case OPTION_SET_INT:
479 case OPTION_SET_PTR:
480 case OPTION_LONG:
459 break; 481 break;
460 } 482 }
461 483
diff --git a/tools/perf/util/parse-options.h b/tools/perf/util/parse-options.h
index 8aa3464c7090..2ee248ff27e5 100644
--- a/tools/perf/util/parse-options.h
+++ b/tools/perf/util/parse-options.h
@@ -104,6 +104,8 @@ struct option {
104 { .type = OPTION_CALLBACK, .short_name = (s), .long_name = (l), .value = (v), .argh = "time", .help = (h), .callback = parse_opt_approxidate_cb } 104 { .type = OPTION_CALLBACK, .short_name = (s), .long_name = (l), .value = (v), .argh = "time", .help = (h), .callback = parse_opt_approxidate_cb }
105#define OPT_CALLBACK(s, l, v, a, h, f) \ 105#define OPT_CALLBACK(s, l, v, a, h, f) \
106 { .type = OPTION_CALLBACK, .short_name = (s), .long_name = (l), .value = (v), (a), .help = (h), .callback = (f) } 106 { .type = OPTION_CALLBACK, .short_name = (s), .long_name = (l), .value = (v), (a), .help = (h), .callback = (f) }
107#define OPT_CALLBACK_NOOPT(s, l, v, a, h, f) \
108 { .type = OPTION_CALLBACK, .short_name = (s), .long_name = (l), .value = (v), (a), .help = (h), .callback = (f), .flags = PARSE_OPT_NOARG }
107#define OPT_CALLBACK_DEFAULT(s, l, v, a, h, f, d) \ 109#define OPT_CALLBACK_DEFAULT(s, l, v, a, h, f, d) \
108 { .type = OPTION_CALLBACK, .short_name = (s), .long_name = (l), .value = (v), (a), .help = (h), .callback = (f), .defval = (intptr_t)d, .flags = PARSE_OPT_LASTARG_DEFAULT } 110 { .type = OPTION_CALLBACK, .short_name = (s), .long_name = (l), .value = (v), (a), .help = (h), .callback = (f), .defval = (intptr_t)d, .flags = PARSE_OPT_LASTARG_DEFAULT }
109 111
diff --git a/tools/perf/util/path.c b/tools/perf/util/path.c
index a501a40dd2cb..fd1f2faaade4 100644
--- a/tools/perf/util/path.c
+++ b/tools/perf/util/path.c
@@ -17,7 +17,7 @@ static char bad_path[] = "/bad-path/";
17 * Two hacks: 17 * Two hacks:
18 */ 18 */
19 19
20static char *get_perf_dir(void) 20static const char *get_perf_dir(void)
21{ 21{
22 return "."; 22 return ".";
23} 23}
@@ -38,8 +38,9 @@ size_t strlcpy(char *dest, const char *src, size_t size)
38static char *get_pathname(void) 38static char *get_pathname(void)
39{ 39{
40 static char pathname_array[4][PATH_MAX]; 40 static char pathname_array[4][PATH_MAX];
41 static int index; 41 static int idx;
42 return pathname_array[3 & ++index]; 42
43 return pathname_array[3 & ++idx];
43} 44}
44 45
45static char *cleanup_path(char *path) 46static char *cleanup_path(char *path)
@@ -161,20 +162,24 @@ int perf_mkstemp(char *path, size_t len, const char *template)
161} 162}
162 163
163 164
164const char *make_relative_path(const char *abs, const char *base) 165const char *make_relative_path(const char *abs_path, const char *base)
165{ 166{
166 static char buf[PATH_MAX + 1]; 167 static char buf[PATH_MAX + 1];
167 int baselen; 168 int baselen;
169
168 if (!base) 170 if (!base)
169 return abs; 171 return abs_path;
172
170 baselen = strlen(base); 173 baselen = strlen(base);
171 if (prefixcmp(abs, base)) 174 if (prefixcmp(abs_path, base))
172 return abs; 175 return abs_path;
173 if (abs[baselen] == '/') 176 if (abs_path[baselen] == '/')
174 baselen++; 177 baselen++;
175 else if (base[baselen - 1] != '/') 178 else if (base[baselen - 1] != '/')
176 return abs; 179 return abs_path;
177 strcpy(buf, abs + baselen); 180
181 strcpy(buf, abs_path + baselen);
182
178 return buf; 183 return buf;
179} 184}
180 185
diff --git a/tools/perf/util/run-command.c b/tools/perf/util/run-command.c
index a3935343091a..2b615acf94d7 100644
--- a/tools/perf/util/run-command.c
+++ b/tools/perf/util/run-command.c
@@ -262,7 +262,7 @@ int run_hook(const char *index_file, const char *name, ...)
262{ 262{
263 struct child_process hook; 263 struct child_process hook;
264 const char **argv = NULL, *env[2]; 264 const char **argv = NULL, *env[2];
265 char index[PATH_MAX]; 265 char idx[PATH_MAX];
266 va_list args; 266 va_list args;
267 int ret; 267 int ret;
268 size_t i = 0, alloc = 0; 268 size_t i = 0, alloc = 0;
@@ -284,8 +284,8 @@ int run_hook(const char *index_file, const char *name, ...)
284 hook.no_stdin = 1; 284 hook.no_stdin = 1;
285 hook.stdout_to_stderr = 1; 285 hook.stdout_to_stderr = 1;
286 if (index_file) { 286 if (index_file) {
287 snprintf(index, sizeof(index), "PERF_INDEX_FILE=%s", index_file); 287 snprintf(idx, sizeof(idx), "PERF_INDEX_FILE=%s", index_file);
288 env[0] = index; 288 env[0] = idx;
289 env[1] = NULL; 289 env[1] = NULL;
290 hook.env = env; 290 hook.env = env;
291 } 291 }
diff --git a/tools/perf/util/svghelper.c b/tools/perf/util/svghelper.c
new file mode 100644
index 000000000000..a778fd0f4ae4
--- /dev/null
+++ b/tools/perf/util/svghelper.c
@@ -0,0 +1,488 @@
1/*
2 * svghelper.c - helper functions for outputting svg
3 *
4 * (C) Copyright 2009 Intel Corporation
5 *
6 * Authors:
7 * Arjan van de Ven <arjan@linux.intel.com>
8 *
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License
11 * as published by the Free Software Foundation; version 2
12 * of the License.
13 */
14
15#include <stdio.h>
16#include <stdlib.h>
17#include <unistd.h>
18#include <string.h>
19
20#include "svghelper.h"
21
22static u64 first_time, last_time;
23static u64 turbo_frequency, max_freq;
24
25
26#define SLOT_MULT 30.0
27#define SLOT_HEIGHT 25.0
28
29int svg_page_width = 1000;
30
31#define MIN_TEXT_SIZE 0.001
32
33static u64 total_height;
34static FILE *svgfile;
35
36static double cpu2slot(int cpu)
37{
38 return 2 * cpu + 1;
39}
40
41static double cpu2y(int cpu)
42{
43 return cpu2slot(cpu) * SLOT_MULT;
44}
45
46static double time2pixels(u64 time)
47{
48 double X;
49
50 X = 1.0 * svg_page_width * (time - first_time) / (last_time - first_time);
51 return X;
52}
53
54/*
55 * Round text sizes so that the svg viewer only needs a discrete
56 * number of renderings of the font
57 */
58static double round_text_size(double size)
59{
60 int loop = 100;
61 double target = 10.0;
62
63 if (size >= 10.0)
64 return size;
65 while (loop--) {
66 if (size >= target)
67 return target;
68 target = target / 2.0;
69 }
70 return size;
71}
72
73void open_svg(const char *filename, int cpus, int rows, u64 start, u64 end)
74{
75 int new_width;
76
77 svgfile = fopen(filename, "w");
78 if (!svgfile) {
79 fprintf(stderr, "Cannot open %s for output\n", filename);
80 return;
81 }
82 first_time = start;
83 first_time = first_time / 100000000 * 100000000;
84 last_time = end;
85
86 /*
87 * if the recording is short, we default to a width of 1000, but
88 * for longer recordings we want at least 200 units of width per second
89 */
90 new_width = (last_time - first_time) / 5000000;
91
92 if (new_width > svg_page_width)
93 svg_page_width = new_width;
94
95 total_height = (1 + rows + cpu2slot(cpus)) * SLOT_MULT;
96 fprintf(svgfile, "<?xml version=\"1.0\" standalone=\"no\"?> \n");
97 fprintf(svgfile, "<svg width=\"%i\" height=\"%llu\" version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\">\n", svg_page_width, total_height);
98
99 fprintf(svgfile, "<defs>\n <style type=\"text/css\">\n <![CDATA[\n");
100
101 fprintf(svgfile, " rect { stroke-width: 1; }\n");
102 fprintf(svgfile, " rect.process { fill:rgb(180,180,180); fill-opacity:0.9; stroke-width:1; stroke:rgb( 0, 0, 0); } \n");
103 fprintf(svgfile, " rect.process2 { fill:rgb(180,180,180); fill-opacity:0.9; stroke-width:0; stroke:rgb( 0, 0, 0); } \n");
104 fprintf(svgfile, " rect.sample { fill:rgb( 0, 0,255); fill-opacity:0.8; stroke-width:0; stroke:rgb( 0, 0, 0); } \n");
105 fprintf(svgfile, " rect.blocked { fill:rgb(255, 0, 0); fill-opacity:0.5; stroke-width:0; stroke:rgb( 0, 0, 0); } \n");
106 fprintf(svgfile, " rect.waiting { fill:rgb(214,214, 0); fill-opacity:0.3; stroke-width:0; stroke:rgb( 0, 0, 0); } \n");
107 fprintf(svgfile, " rect.WAITING { fill:rgb(255,214, 48); fill-opacity:0.6; stroke-width:0; stroke:rgb( 0, 0, 0); } \n");
108 fprintf(svgfile, " rect.cpu { fill:rgb(192,192,192); fill-opacity:0.2; stroke-width:0.5; stroke:rgb(128,128,128); } \n");
109 fprintf(svgfile, " rect.pstate { fill:rgb(128,128,128); fill-opacity:0.8; stroke-width:0; } \n");
110 fprintf(svgfile, " rect.c1 { fill:rgb(255,214,214); fill-opacity:0.5; stroke-width:0; } \n");
111 fprintf(svgfile, " rect.c2 { fill:rgb(255,172,172); fill-opacity:0.5; stroke-width:0; } \n");
112 fprintf(svgfile, " rect.c3 { fill:rgb(255,130,130); fill-opacity:0.5; stroke-width:0; } \n");
113 fprintf(svgfile, " rect.c4 { fill:rgb(255, 88, 88); fill-opacity:0.5; stroke-width:0; } \n");
114 fprintf(svgfile, " rect.c5 { fill:rgb(255, 44, 44); fill-opacity:0.5; stroke-width:0; } \n");
115 fprintf(svgfile, " rect.c6 { fill:rgb(255, 0, 0); fill-opacity:0.5; stroke-width:0; } \n");
116 fprintf(svgfile, " line.pstate { stroke:rgb(255,255, 0); stroke-opacity:0.8; stroke-width:2; } \n");
117
118 fprintf(svgfile, " ]]>\n </style>\n</defs>\n");
119}
120
121void svg_box(int Yslot, u64 start, u64 end, const char *type)
122{
123 if (!svgfile)
124 return;
125
126 fprintf(svgfile, "<rect x=\"%4.8f\" width=\"%4.8f\" y=\"%4.1f\" height=\"%4.1f\" class=\"%s\"/>\n",
127 time2pixels(start), time2pixels(end)-time2pixels(start), Yslot * SLOT_MULT, SLOT_HEIGHT, type);
128}
129
130void svg_sample(int Yslot, int cpu, u64 start, u64 end)
131{
132 double text_size;
133 if (!svgfile)
134 return;
135
136 fprintf(svgfile, "<rect x=\"%4.8f\" width=\"%4.8f\" y=\"%4.1f\" height=\"%4.1f\" class=\"sample\"/>\n",
137 time2pixels(start), time2pixels(end)-time2pixels(start), Yslot * SLOT_MULT, SLOT_HEIGHT);
138
139 text_size = (time2pixels(end)-time2pixels(start));
140 if (cpu > 9)
141 text_size = text_size/2;
142 if (text_size > 1.25)
143 text_size = 1.25;
144 text_size = round_text_size(text_size);
145
146 if (text_size > MIN_TEXT_SIZE)
147 fprintf(svgfile, "<text x=\"%1.8f\" y=\"%1.8f\" font-size=\"%1.8fpt\">%i</text>\n",
148 time2pixels(start), Yslot * SLOT_MULT + SLOT_HEIGHT - 1, text_size, cpu + 1);
149
150}
151
152static char *time_to_string(u64 duration)
153{
154 static char text[80];
155
156 text[0] = 0;
157
158 if (duration < 1000) /* less than 1 usec */
159 return text;
160
161 if (duration < 1000 * 1000) { /* less than 1 msec */
162 sprintf(text, "%4.1f us", duration / 1000.0);
163 return text;
164 }
165 sprintf(text, "%4.1f ms", duration / 1000.0 / 1000);
166
167 return text;
168}
169
170void svg_waiting(int Yslot, u64 start, u64 end)
171{
172 char *text;
173 const char *style;
174 double font_size;
175
176 if (!svgfile)
177 return;
178
179 style = "waiting";
180
181 if (end-start > 10 * 1000000) /* 10 msec */
182 style = "WAITING";
183
184 text = time_to_string(end-start);
185
186 font_size = 1.0 * (time2pixels(end)-time2pixels(start));
187
188 if (font_size > 3)
189 font_size = 3;
190
191 font_size = round_text_size(font_size);
192
193 fprintf(svgfile, "<g transform=\"translate(%4.8f,%4.8f)\">\n", time2pixels(start), Yslot * SLOT_MULT);
194 fprintf(svgfile, "<rect x=\"0\" width=\"%4.8f\" y=\"0\" height=\"%4.1f\" class=\"%s\"/>\n",
195 time2pixels(end)-time2pixels(start), SLOT_HEIGHT, style);
196 if (font_size > MIN_TEXT_SIZE)
197 fprintf(svgfile, "<text transform=\"rotate(90)\" font-size=\"%1.8fpt\"> %s</text>\n",
198 font_size, text);
199 fprintf(svgfile, "</g>\n");
200}
201
202static char *cpu_model(void)
203{
204 static char cpu_m[255];
205 char buf[256];
206 FILE *file;
207
208 cpu_m[0] = 0;
209 /* CPU type */
210 file = fopen("/proc/cpuinfo", "r");
211 if (file) {
212 while (fgets(buf, 255, file)) {
213 if (strstr(buf, "model name")) {
214 strncpy(cpu_m, &buf[13], 255);
215 break;
216 }
217 }
218 fclose(file);
219 }
220 return cpu_m;
221}
222
223void svg_cpu_box(int cpu, u64 __max_freq, u64 __turbo_freq)
224{
225 char cpu_string[80];
226 if (!svgfile)
227 return;
228
229 max_freq = __max_freq;
230 turbo_frequency = __turbo_freq;
231
232 fprintf(svgfile, "<rect x=\"%4.8f\" width=\"%4.8f\" y=\"%4.1f\" height=\"%4.1f\" class=\"cpu\"/>\n",
233 time2pixels(first_time),
234 time2pixels(last_time)-time2pixels(first_time),
235 cpu2y(cpu), SLOT_MULT+SLOT_HEIGHT);
236
237 sprintf(cpu_string, "CPU %i", (int)cpu+1);
238 fprintf(svgfile, "<text x=\"%4.8f\" y=\"%4.8f\">%s</text>\n",
239 10+time2pixels(first_time), cpu2y(cpu) + SLOT_HEIGHT/2, cpu_string);
240
241 fprintf(svgfile, "<text transform=\"translate(%4.8f,%4.8f)\" font-size=\"1.25pt\">%s</text>\n",
242 10+time2pixels(first_time), cpu2y(cpu) + SLOT_MULT + SLOT_HEIGHT - 4, cpu_model());
243}
244
245void svg_process(int cpu, u64 start, u64 end, const char *type, const char *name)
246{
247 double width;
248
249 if (!svgfile)
250 return;
251
252
253 fprintf(svgfile, "<g transform=\"translate(%4.8f,%4.8f)\">\n", time2pixels(start), cpu2y(cpu));
254 fprintf(svgfile, "<rect x=\"0\" width=\"%4.8f\" y=\"0\" height=\"%4.1f\" class=\"%s\"/>\n",
255 time2pixels(end)-time2pixels(start), SLOT_MULT+SLOT_HEIGHT, type);
256 width = time2pixels(end)-time2pixels(start);
257 if (width > 6)
258 width = 6;
259
260 width = round_text_size(width);
261
262 if (width > MIN_TEXT_SIZE)
263 fprintf(svgfile, "<text transform=\"rotate(90)\" font-size=\"%3.8fpt\">%s</text>\n",
264 width, name);
265
266 fprintf(svgfile, "</g>\n");
267}
268
269void svg_cstate(int cpu, u64 start, u64 end, int type)
270{
271 double width;
272 char style[128];
273
274 if (!svgfile)
275 return;
276
277
278 if (type > 6)
279 type = 6;
280 sprintf(style, "c%i", type);
281
282 fprintf(svgfile, "<rect class=\"%s\" x=\"%4.8f\" width=\"%4.8f\" y=\"%4.1f\" height=\"%4.1f\"/>\n",
283 style,
284 time2pixels(start), time2pixels(end)-time2pixels(start),
285 cpu2y(cpu), SLOT_MULT+SLOT_HEIGHT);
286
287 width = (time2pixels(end)-time2pixels(start))/2.0;
288 if (width > 6)
289 width = 6;
290
291 width = round_text_size(width);
292
293 if (width > MIN_TEXT_SIZE)
294 fprintf(svgfile, "<text x=\"%4.8f\" y=\"%4.8f\" font-size=\"%3.8fpt\">C%i</text>\n",
295 time2pixels(start), cpu2y(cpu)+width, width, type);
296}
297
298static char *HzToHuman(unsigned long hz)
299{
300 static char buffer[1024];
301 unsigned long long Hz;
302
303 memset(buffer, 0, 1024);
304
305 Hz = hz;
306
307 /* default: just put the Number in */
308 sprintf(buffer, "%9lli", Hz);
309
310 if (Hz > 1000)
311 sprintf(buffer, " %6lli Mhz", (Hz+500)/1000);
312
313 if (Hz > 1500000)
314 sprintf(buffer, " %6.2f Ghz", (Hz+5000.0)/1000000);
315
316 if (Hz == turbo_frequency)
317 sprintf(buffer, "Turbo");
318
319 return buffer;
320}
321
322void svg_pstate(int cpu, u64 start, u64 end, u64 freq)
323{
324 double height = 0;
325
326 if (!svgfile)
327 return;
328
329 if (max_freq)
330 height = freq * 1.0 / max_freq * (SLOT_HEIGHT + SLOT_MULT);
331 height = 1 + cpu2y(cpu) + SLOT_MULT + SLOT_HEIGHT - height;
332 fprintf(svgfile, "<line x1=\"%4.8f\" x2=\"%4.8f\" y1=\"%4.1f\" y2=\"%4.1f\" class=\"pstate\"/>\n",
333 time2pixels(start), time2pixels(end), height, height);
334 fprintf(svgfile, "<text x=\"%4.8f\" y=\"%4.8f\" font-size=\"0.25pt\">%s</text>\n",
335 time2pixels(start), height+0.9, HzToHuman(freq));
336
337}
338
339
340void svg_partial_wakeline(u64 start, int row1, char *desc1, int row2, char *desc2)
341{
342 double height;
343
344 if (!svgfile)
345 return;
346
347
348 if (row1 < row2) {
349 if (row1) {
350 fprintf(svgfile, "<line x1=\"%4.8f\" y1=\"%4.2f\" x2=\"%4.8f\" y2=\"%4.2f\" style=\"stroke:rgb(32,255,32);stroke-width:0.009\"/>\n",
351 time2pixels(start), row1 * SLOT_MULT + SLOT_HEIGHT, time2pixels(start), row1 * SLOT_MULT + SLOT_HEIGHT + SLOT_MULT/32);
352 if (desc2)
353 fprintf(svgfile, "<g transform=\"translate(%4.8f,%4.8f)\"><text transform=\"rotate(90)\" font-size=\"0.02pt\">%s &gt;</text></g>\n",
354 time2pixels(start), row1 * SLOT_MULT + SLOT_HEIGHT + SLOT_HEIGHT/48, desc2);
355 }
356 if (row2) {
357 fprintf(svgfile, "<line x1=\"%4.8f\" y1=\"%4.2f\" x2=\"%4.8f\" y2=\"%4.2f\" style=\"stroke:rgb(32,255,32);stroke-width:0.009\"/>\n",
358 time2pixels(start), row2 * SLOT_MULT - SLOT_MULT/32, time2pixels(start), row2 * SLOT_MULT);
359 if (desc1)
360 fprintf(svgfile, "<g transform=\"translate(%4.8f,%4.8f)\"><text transform=\"rotate(90)\" font-size=\"0.02pt\">%s &gt;</text></g>\n",
361 time2pixels(start), row2 * SLOT_MULT - SLOT_MULT/32, desc1);
362 }
363 } else {
364 if (row2) {
365 fprintf(svgfile, "<line x1=\"%4.8f\" y1=\"%4.2f\" x2=\"%4.8f\" y2=\"%4.2f\" style=\"stroke:rgb(32,255,32);stroke-width:0.009\"/>\n",
366 time2pixels(start), row2 * SLOT_MULT + SLOT_HEIGHT, time2pixels(start), row2 * SLOT_MULT + SLOT_HEIGHT + SLOT_MULT/32);
367 if (desc1)
368 fprintf(svgfile, "<g transform=\"translate(%4.8f,%4.8f)\"><text transform=\"rotate(90)\" font-size=\"0.02pt\">%s &lt;</text></g>\n",
369 time2pixels(start), row2 * SLOT_MULT + SLOT_HEIGHT + SLOT_MULT/48, desc1);
370 }
371 if (row1) {
372 fprintf(svgfile, "<line x1=\"%4.8f\" y1=\"%4.2f\" x2=\"%4.8f\" y2=\"%4.2f\" style=\"stroke:rgb(32,255,32);stroke-width:0.009\"/>\n",
373 time2pixels(start), row1 * SLOT_MULT - SLOT_MULT/32, time2pixels(start), row1 * SLOT_MULT);
374 if (desc2)
375 fprintf(svgfile, "<g transform=\"translate(%4.8f,%4.8f)\"><text transform=\"rotate(90)\" font-size=\"0.02pt\">%s &lt;</text></g>\n",
376 time2pixels(start), row1 * SLOT_MULT - SLOT_HEIGHT/32, desc2);
377 }
378 }
379 height = row1 * SLOT_MULT;
380 if (row2 > row1)
381 height += SLOT_HEIGHT;
382 if (row1)
383 fprintf(svgfile, "<circle cx=\"%4.8f\" cy=\"%4.2f\" r = \"0.01\" style=\"fill:rgb(32,255,32)\"/>\n",
384 time2pixels(start), height);
385}
386
387void svg_wakeline(u64 start, int row1, int row2)
388{
389 double height;
390
391 if (!svgfile)
392 return;
393
394
395 if (row1 < row2)
396 fprintf(svgfile, "<line x1=\"%4.8f\" y1=\"%4.2f\" x2=\"%4.8f\" y2=\"%4.2f\" style=\"stroke:rgb(32,255,32);stroke-width:0.009\"/>\n",
397 time2pixels(start), row1 * SLOT_MULT + SLOT_HEIGHT, time2pixels(start), row2 * SLOT_MULT);
398 else
399 fprintf(svgfile, "<line x1=\"%4.8f\" y1=\"%4.2f\" x2=\"%4.8f\" y2=\"%4.2f\" style=\"stroke:rgb(32,255,32);stroke-width:0.009\"/>\n",
400 time2pixels(start), row2 * SLOT_MULT + SLOT_HEIGHT, time2pixels(start), row1 * SLOT_MULT);
401
402 height = row1 * SLOT_MULT;
403 if (row2 > row1)
404 height += SLOT_HEIGHT;
405 fprintf(svgfile, "<circle cx=\"%4.8f\" cy=\"%4.2f\" r = \"0.01\" style=\"fill:rgb(32,255,32)\"/>\n",
406 time2pixels(start), height);
407}
408
409void svg_interrupt(u64 start, int row)
410{
411 if (!svgfile)
412 return;
413
414 fprintf(svgfile, "<circle cx=\"%4.8f\" cy=\"%4.2f\" r = \"0.01\" style=\"fill:rgb(255,128,128)\"/>\n",
415 time2pixels(start), row * SLOT_MULT);
416 fprintf(svgfile, "<circle cx=\"%4.8f\" cy=\"%4.2f\" r = \"0.01\" style=\"fill:rgb(255,128,128)\"/>\n",
417 time2pixels(start), row * SLOT_MULT + SLOT_HEIGHT);
418}
419
420void svg_text(int Yslot, u64 start, const char *text)
421{
422 if (!svgfile)
423 return;
424
425 fprintf(svgfile, "<text x=\"%4.8f\" y=\"%4.8f\">%s</text>\n",
426 time2pixels(start), Yslot * SLOT_MULT+SLOT_HEIGHT/2, text);
427}
428
429static void svg_legenda_box(int X, const char *text, const char *style)
430{
431 double boxsize;
432 boxsize = SLOT_HEIGHT / 2;
433
434 fprintf(svgfile, "<rect x=\"%i\" width=\"%4.8f\" y=\"0\" height=\"%4.1f\" class=\"%s\"/>\n",
435 X, boxsize, boxsize, style);
436 fprintf(svgfile, "<text transform=\"translate(%4.8f, %4.8f)\" font-size=\"%4.8fpt\">%s</text>\n",
437 X + boxsize + 5, boxsize, 0.8 * boxsize, text);
438}
439
440void svg_legenda(void)
441{
442 if (!svgfile)
443 return;
444
445 svg_legenda_box(0, "Running", "sample");
446 svg_legenda_box(100, "Idle","rect.c1");
447 svg_legenda_box(200, "Deeper Idle", "rect.c3");
448 svg_legenda_box(350, "Deepest Idle", "rect.c6");
449 svg_legenda_box(550, "Sleeping", "process2");
450 svg_legenda_box(650, "Waiting for cpu", "waiting");
451 svg_legenda_box(800, "Blocked on IO", "blocked");
452}
453
454void svg_time_grid(void)
455{
456 u64 i;
457
458 if (!svgfile)
459 return;
460
461 i = first_time;
462 while (i < last_time) {
463 int color = 220;
464 double thickness = 0.075;
465 if ((i % 100000000) == 0) {
466 thickness = 0.5;
467 color = 192;
468 }
469 if ((i % 1000000000) == 0) {
470 thickness = 2.0;
471 color = 128;
472 }
473
474 fprintf(svgfile, "<line x1=\"%4.8f\" y1=\"%4.2f\" x2=\"%4.8f\" y2=\"%llu\" style=\"stroke:rgb(%i,%i,%i);stroke-width:%1.3f\"/>\n",
475 time2pixels(i), SLOT_MULT/2, time2pixels(i), total_height, color, color, color, thickness);
476
477 i += 10000000;
478 }
479}
480
481void svg_close(void)
482{
483 if (svgfile) {
484 fprintf(svgfile, "</svg>\n");
485 fclose(svgfile);
486 svgfile = NULL;
487 }
488}
diff --git a/tools/perf/util/svghelper.h b/tools/perf/util/svghelper.h
new file mode 100644
index 000000000000..cd93195aedb3
--- /dev/null
+++ b/tools/perf/util/svghelper.h
@@ -0,0 +1,28 @@
1#ifndef _INCLUDE_GUARD_SVG_HELPER_
2#define _INCLUDE_GUARD_SVG_HELPER_
3
4#include "types.h"
5
6extern void open_svg(const char *filename, int cpus, int rows, u64 start, u64 end);
7extern void svg_box(int Yslot, u64 start, u64 end, const char *type);
8extern void svg_sample(int Yslot, int cpu, u64 start, u64 end);
9extern void svg_waiting(int Yslot, u64 start, u64 end);
10extern void svg_cpu_box(int cpu, u64 max_frequency, u64 turbo_frequency);
11
12
13extern void svg_process(int cpu, u64 start, u64 end, const char *type, const char *name);
14extern void svg_cstate(int cpu, u64 start, u64 end, int type);
15extern void svg_pstate(int cpu, u64 start, u64 end, u64 freq);
16
17
18extern void svg_time_grid(void);
19extern void svg_legenda(void);
20extern void svg_wakeline(u64 start, int row1, int row2);
21extern void svg_partial_wakeline(u64 start, int row1, char *desc1, int row2, char *desc2);
22extern void svg_interrupt(u64 start, int row);
23extern void svg_text(int Yslot, u64 start, const char *text);
24extern void svg_close(void);
25
26extern int svg_page_width;
27
28#endif
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
index 5c0f42e6b33b..559fb06210f5 100644
--- a/tools/perf/util/symbol.c
+++ b/tools/perf/util/symbol.c
@@ -3,6 +3,8 @@
3#include "string.h" 3#include "string.h"
4#include "symbol.h" 4#include "symbol.h"
5 5
6#include "debug.h"
7
6#include <libelf.h> 8#include <libelf.h>
7#include <gelf.h> 9#include <gelf.h>
8#include <elf.h> 10#include <elf.h>
@@ -21,7 +23,7 @@ enum dso_origin {
21 23
22static struct symbol *symbol__new(u64 start, u64 len, 24static struct symbol *symbol__new(u64 start, u64 len,
23 const char *name, unsigned int priv_size, 25 const char *name, unsigned int priv_size,
24 u64 obj_start, int verbose) 26 u64 obj_start, int v)
25{ 27{
26 size_t namelen = strlen(name) + 1; 28 size_t namelen = strlen(name) + 1;
27 struct symbol *self = calloc(1, priv_size + sizeof(*self) + namelen); 29 struct symbol *self = calloc(1, priv_size + sizeof(*self) + namelen);
@@ -29,7 +31,7 @@ static struct symbol *symbol__new(u64 start, u64 len,
29 if (!self) 31 if (!self)
30 return NULL; 32 return NULL;
31 33
32 if (verbose >= 2) 34 if (v >= 2)
33 printf("new symbol: %016Lx [%08lx]: %s, hist: %p, obj_start: %p\n", 35 printf("new symbol: %016Lx [%08lx]: %s, hist: %p, obj_start: %p\n",
34 (u64)start, (unsigned long)len, name, self->hist, (void *)(unsigned long)obj_start); 36 (u64)start, (unsigned long)len, name, self->hist, (void *)(unsigned long)obj_start);
35 37
@@ -156,7 +158,7 @@ size_t dso__fprintf(struct dso *self, FILE *fp)
156 return ret; 158 return ret;
157} 159}
158 160
159static int dso__load_kallsyms(struct dso *self, symbol_filter_t filter, int verbose) 161static int dso__load_kallsyms(struct dso *self, symbol_filter_t filter, int v)
160{ 162{
161 struct rb_node *nd, *prevnd; 163 struct rb_node *nd, *prevnd;
162 char *line = NULL; 164 char *line = NULL;
@@ -198,7 +200,7 @@ static int dso__load_kallsyms(struct dso *self, symbol_filter_t filter, int verb
198 * Well fix up the end later, when we have all sorted. 200 * Well fix up the end later, when we have all sorted.
199 */ 201 */
200 sym = symbol__new(start, 0xdead, line + len + 2, 202 sym = symbol__new(start, 0xdead, line + len + 2,
201 self->sym_priv_size, 0, verbose); 203 self->sym_priv_size, 0, v);
202 204
203 if (sym == NULL) 205 if (sym == NULL)
204 goto out_delete_line; 206 goto out_delete_line;
@@ -239,7 +241,7 @@ out_failure:
239 return -1; 241 return -1;
240} 242}
241 243
242static int dso__load_perf_map(struct dso *self, symbol_filter_t filter, int verbose) 244static int dso__load_perf_map(struct dso *self, symbol_filter_t filter, int v)
243{ 245{
244 char *line = NULL; 246 char *line = NULL;
245 size_t n; 247 size_t n;
@@ -277,7 +279,7 @@ static int dso__load_perf_map(struct dso *self, symbol_filter_t filter, int verb
277 continue; 279 continue;
278 280
279 sym = symbol__new(start, size, line + len, 281 sym = symbol__new(start, size, line + len,
280 self->sym_priv_size, start, verbose); 282 self->sym_priv_size, start, v);
281 283
282 if (sym == NULL) 284 if (sym == NULL)
283 goto out_delete_line; 285 goto out_delete_line;
@@ -305,13 +307,13 @@ out_failure:
305 * elf_symtab__for_each_symbol - iterate thru all the symbols 307 * elf_symtab__for_each_symbol - iterate thru all the symbols
306 * 308 *
307 * @self: struct elf_symtab instance to iterate 309 * @self: struct elf_symtab instance to iterate
308 * @index: uint32_t index 310 * @idx: uint32_t idx
309 * @sym: GElf_Sym iterator 311 * @sym: GElf_Sym iterator
310 */ 312 */
311#define elf_symtab__for_each_symbol(syms, nr_syms, index, sym) \ 313#define elf_symtab__for_each_symbol(syms, nr_syms, idx, sym) \
312 for (index = 0, gelf_getsym(syms, index, &sym);\ 314 for (idx = 0, gelf_getsym(syms, idx, &sym);\
313 index < nr_syms; \ 315 idx < nr_syms; \
314 index++, gelf_getsym(syms, index, &sym)) 316 idx++, gelf_getsym(syms, idx, &sym))
315 317
316static inline uint8_t elf_sym__type(const GElf_Sym *sym) 318static inline uint8_t elf_sym__type(const GElf_Sym *sym)
317{ 319{
@@ -354,7 +356,7 @@ static inline const char *elf_sym__name(const GElf_Sym *sym,
354 356
355static Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep, 357static Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep,
356 GElf_Shdr *shp, const char *name, 358 GElf_Shdr *shp, const char *name,
357 size_t *index) 359 size_t *idx)
358{ 360{
359 Elf_Scn *sec = NULL; 361 Elf_Scn *sec = NULL;
360 size_t cnt = 1; 362 size_t cnt = 1;
@@ -365,8 +367,8 @@ static Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep,
365 gelf_getshdr(sec, shp); 367 gelf_getshdr(sec, shp);
366 str = elf_strptr(elf, ep->e_shstrndx, shp->sh_name); 368 str = elf_strptr(elf, ep->e_shstrndx, shp->sh_name);
367 if (!strcmp(name, str)) { 369 if (!strcmp(name, str)) {
368 if (index) 370 if (idx)
369 *index = cnt; 371 *idx = cnt;
370 break; 372 break;
371 } 373 }
372 ++cnt; 374 ++cnt;
@@ -392,7 +394,7 @@ static Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep,
392 * And always look at the original dso, not at debuginfo packages, that 394 * And always look at the original dso, not at debuginfo packages, that
393 * have the PLT data stripped out (shdr_rel_plt.sh_type == SHT_NOBITS). 395 * have the PLT data stripped out (shdr_rel_plt.sh_type == SHT_NOBITS).
394 */ 396 */
395static int dso__synthesize_plt_symbols(struct dso *self, int verbose) 397static int dso__synthesize_plt_symbols(struct dso *self, int v)
396{ 398{
397 uint32_t nr_rel_entries, idx; 399 uint32_t nr_rel_entries, idx;
398 GElf_Sym sym; 400 GElf_Sym sym;
@@ -442,7 +444,7 @@ static int dso__synthesize_plt_symbols(struct dso *self, int verbose)
442 goto out_elf_end; 444 goto out_elf_end;
443 445
444 /* 446 /*
445 * Fetch the relocation section to find the indexes to the GOT 447 * Fetch the relocation section to find the idxes to the GOT
446 * and the symbols in the .dynsym they refer to. 448 * and the symbols in the .dynsym they refer to.
447 */ 449 */
448 reldata = elf_getdata(scn_plt_rel, NULL); 450 reldata = elf_getdata(scn_plt_rel, NULL);
@@ -476,7 +478,7 @@ static int dso__synthesize_plt_symbols(struct dso *self, int verbose)
476 "%s@plt", elf_sym__name(&sym, symstrs)); 478 "%s@plt", elf_sym__name(&sym, symstrs));
477 479
478 f = symbol__new(plt_offset, shdr_plt.sh_entsize, 480 f = symbol__new(plt_offset, shdr_plt.sh_entsize,
479 sympltname, self->sym_priv_size, 0, verbose); 481 sympltname, self->sym_priv_size, 0, v);
480 if (!f) 482 if (!f)
481 goto out_elf_end; 483 goto out_elf_end;
482 484
@@ -494,7 +496,7 @@ static int dso__synthesize_plt_symbols(struct dso *self, int verbose)
494 "%s@plt", elf_sym__name(&sym, symstrs)); 496 "%s@plt", elf_sym__name(&sym, symstrs));
495 497
496 f = symbol__new(plt_offset, shdr_plt.sh_entsize, 498 f = symbol__new(plt_offset, shdr_plt.sh_entsize,
497 sympltname, self->sym_priv_size, 0, verbose); 499 sympltname, self->sym_priv_size, 0, v);
498 if (!f) 500 if (!f)
499 goto out_elf_end; 501 goto out_elf_end;
500 502
@@ -518,12 +520,12 @@ out:
518} 520}
519 521
520static int dso__load_sym(struct dso *self, int fd, const char *name, 522static int dso__load_sym(struct dso *self, int fd, const char *name,
521 symbol_filter_t filter, int verbose, struct module *mod) 523 symbol_filter_t filter, int v, struct module *mod)
522{ 524{
523 Elf_Data *symstrs, *secstrs; 525 Elf_Data *symstrs, *secstrs;
524 uint32_t nr_syms; 526 uint32_t nr_syms;
525 int err = -1; 527 int err = -1;
526 uint32_t index; 528 uint32_t idx;
527 GElf_Ehdr ehdr; 529 GElf_Ehdr ehdr;
528 GElf_Shdr shdr; 530 GElf_Shdr shdr;
529 Elf_Data *syms; 531 Elf_Data *syms;
@@ -534,14 +536,14 @@ static int dso__load_sym(struct dso *self, int fd, const char *name,
534 536
535 elf = elf_begin(fd, ELF_C_READ_MMAP, NULL); 537 elf = elf_begin(fd, ELF_C_READ_MMAP, NULL);
536 if (elf == NULL) { 538 if (elf == NULL) {
537 if (verbose) 539 if (v)
538 fprintf(stderr, "%s: cannot read %s ELF file.\n", 540 fprintf(stderr, "%s: cannot read %s ELF file.\n",
539 __func__, name); 541 __func__, name);
540 goto out_close; 542 goto out_close;
541 } 543 }
542 544
543 if (gelf_getehdr(elf, &ehdr) == NULL) { 545 if (gelf_getehdr(elf, &ehdr) == NULL) {
544 if (verbose) 546 if (v)
545 fprintf(stderr, "%s: cannot get elf header.\n", __func__); 547 fprintf(stderr, "%s: cannot get elf header.\n", __func__);
546 goto out_elf_end; 548 goto out_elf_end;
547 } 549 }
@@ -583,9 +585,9 @@ static int dso__load_sym(struct dso *self, int fd, const char *name,
583 NULL) != NULL); 585 NULL) != NULL);
584 } else self->adjust_symbols = 0; 586 } else self->adjust_symbols = 0;
585 587
586 elf_symtab__for_each_symbol(syms, nr_syms, index, sym) { 588 elf_symtab__for_each_symbol(syms, nr_syms, idx, sym) {
587 struct symbol *f; 589 struct symbol *f;
588 const char *name; 590 const char *elf_name;
589 char *demangled; 591 char *demangled;
590 u64 obj_start; 592 u64 obj_start;
591 struct section *section = NULL; 593 struct section *section = NULL;
@@ -608,7 +610,7 @@ static int dso__load_sym(struct dso *self, int fd, const char *name,
608 obj_start = sym.st_value; 610 obj_start = sym.st_value;
609 611
610 if (self->adjust_symbols) { 612 if (self->adjust_symbols) {
611 if (verbose >= 2) 613 if (v >= 2)
612 printf("adjusting symbol: st_value: %Lx sh_addr: %Lx sh_offset: %Lx\n", 614 printf("adjusting symbol: st_value: %Lx sh_addr: %Lx sh_offset: %Lx\n",
613 (u64)sym.st_value, (u64)shdr.sh_addr, (u64)shdr.sh_offset); 615 (u64)sym.st_value, (u64)shdr.sh_addr, (u64)shdr.sh_offset);
614 616
@@ -630,13 +632,13 @@ static int dso__load_sym(struct dso *self, int fd, const char *name,
630 * DWARF DW_compile_unit has this, but we don't always have access 632 * DWARF DW_compile_unit has this, but we don't always have access
631 * to it... 633 * to it...
632 */ 634 */
633 name = elf_sym__name(&sym, symstrs); 635 elf_name = elf_sym__name(&sym, symstrs);
634 demangled = bfd_demangle(NULL, name, DMGL_PARAMS | DMGL_ANSI); 636 demangled = bfd_demangle(NULL, elf_name, DMGL_PARAMS | DMGL_ANSI);
635 if (demangled != NULL) 637 if (demangled != NULL)
636 name = demangled; 638 elf_name = demangled;
637 639
638 f = symbol__new(sym.st_value, sym.st_size, name, 640 f = symbol__new(sym.st_value, sym.st_size, elf_name,
639 self->sym_priv_size, obj_start, verbose); 641 self->sym_priv_size, obj_start, v);
640 free(demangled); 642 free(demangled);
641 if (!f) 643 if (!f)
642 goto out_elf_end; 644 goto out_elf_end;
@@ -659,7 +661,7 @@ out_close:
659 661
660#define BUILD_ID_SIZE 128 662#define BUILD_ID_SIZE 128
661 663
662static char *dso__read_build_id(struct dso *self, int verbose) 664static char *dso__read_build_id(struct dso *self, int v)
663{ 665{
664 int i; 666 int i;
665 GElf_Ehdr ehdr; 667 GElf_Ehdr ehdr;
@@ -676,14 +678,14 @@ static char *dso__read_build_id(struct dso *self, int verbose)
676 678
677 elf = elf_begin(fd, ELF_C_READ_MMAP, NULL); 679 elf = elf_begin(fd, ELF_C_READ_MMAP, NULL);
678 if (elf == NULL) { 680 if (elf == NULL) {
679 if (verbose) 681 if (v)
680 fprintf(stderr, "%s: cannot read %s ELF file.\n", 682 fprintf(stderr, "%s: cannot read %s ELF file.\n",
681 __func__, self->name); 683 __func__, self->name);
682 goto out_close; 684 goto out_close;
683 } 685 }
684 686
685 if (gelf_getehdr(elf, &ehdr) == NULL) { 687 if (gelf_getehdr(elf, &ehdr) == NULL) {
686 if (verbose) 688 if (v)
687 fprintf(stderr, "%s: cannot get elf header.\n", __func__); 689 fprintf(stderr, "%s: cannot get elf header.\n", __func__);
688 goto out_elf_end; 690 goto out_elf_end;
689 } 691 }
@@ -706,7 +708,7 @@ static char *dso__read_build_id(struct dso *self, int verbose)
706 ++raw; 708 ++raw;
707 bid += 2; 709 bid += 2;
708 } 710 }
709 if (verbose >= 2) 711 if (v >= 2)
710 printf("%s(%s): %s\n", __func__, self->name, build_id); 712 printf("%s(%s): %s\n", __func__, self->name, build_id);
711out_elf_end: 713out_elf_end:
712 elf_end(elf); 714 elf_end(elf);
@@ -732,7 +734,7 @@ char dso__symtab_origin(const struct dso *self)
732 return origin[self->origin]; 734 return origin[self->origin];
733} 735}
734 736
735int dso__load(struct dso *self, symbol_filter_t filter, int verbose) 737int dso__load(struct dso *self, symbol_filter_t filter, int v)
736{ 738{
737 int size = PATH_MAX; 739 int size = PATH_MAX;
738 char *name = malloc(size), *build_id = NULL; 740 char *name = malloc(size), *build_id = NULL;
@@ -745,7 +747,7 @@ int dso__load(struct dso *self, symbol_filter_t filter, int verbose)
745 self->adjust_symbols = 0; 747 self->adjust_symbols = 0;
746 748
747 if (strncmp(self->name, "/tmp/perf-", 10) == 0) { 749 if (strncmp(self->name, "/tmp/perf-", 10) == 0) {
748 ret = dso__load_perf_map(self, filter, verbose); 750 ret = dso__load_perf_map(self, filter, v);
749 self->origin = ret > 0 ? DSO__ORIG_JAVA_JIT : 751 self->origin = ret > 0 ? DSO__ORIG_JAVA_JIT :
750 DSO__ORIG_NOT_FOUND; 752 DSO__ORIG_NOT_FOUND;
751 return ret; 753 return ret;
@@ -764,7 +766,7 @@ more:
764 snprintf(name, size, "/usr/lib/debug%s", self->name); 766 snprintf(name, size, "/usr/lib/debug%s", self->name);
765 break; 767 break;
766 case DSO__ORIG_BUILDID: 768 case DSO__ORIG_BUILDID:
767 build_id = dso__read_build_id(self, verbose); 769 build_id = dso__read_build_id(self, v);
768 if (build_id != NULL) { 770 if (build_id != NULL) {
769 snprintf(name, size, 771 snprintf(name, size,
770 "/usr/lib/debug/.build-id/%.2s/%s.debug", 772 "/usr/lib/debug/.build-id/%.2s/%s.debug",
@@ -785,7 +787,7 @@ more:
785 fd = open(name, O_RDONLY); 787 fd = open(name, O_RDONLY);
786 } while (fd < 0); 788 } while (fd < 0);
787 789
788 ret = dso__load_sym(self, fd, name, filter, verbose, NULL); 790 ret = dso__load_sym(self, fd, name, filter, v, NULL);
789 close(fd); 791 close(fd);
790 792
791 /* 793 /*
@@ -795,7 +797,7 @@ more:
795 goto more; 797 goto more;
796 798
797 if (ret > 0) { 799 if (ret > 0) {
798 int nr_plt = dso__synthesize_plt_symbols(self, verbose); 800 int nr_plt = dso__synthesize_plt_symbols(self, v);
799 if (nr_plt > 0) 801 if (nr_plt > 0)
800 ret += nr_plt; 802 ret += nr_plt;
801 } 803 }
@@ -807,7 +809,7 @@ out:
807} 809}
808 810
809static int dso__load_module(struct dso *self, struct mod_dso *mods, const char *name, 811static int dso__load_module(struct dso *self, struct mod_dso *mods, const char *name,
810 symbol_filter_t filter, int verbose) 812 symbol_filter_t filter, int v)
811{ 813{
812 struct module *mod = mod_dso__find_module(mods, name); 814 struct module *mod = mod_dso__find_module(mods, name);
813 int err = 0, fd; 815 int err = 0, fd;
@@ -820,18 +822,18 @@ static int dso__load_module(struct dso *self, struct mod_dso *mods, const char *
820 if (fd < 0) 822 if (fd < 0)
821 return err; 823 return err;
822 824
823 err = dso__load_sym(self, fd, name, filter, verbose, mod); 825 err = dso__load_sym(self, fd, name, filter, v, mod);
824 close(fd); 826 close(fd);
825 827
826 return err; 828 return err;
827} 829}
828 830
829int dso__load_modules(struct dso *self, symbol_filter_t filter, int verbose) 831int dso__load_modules(struct dso *self, symbol_filter_t filter, int v)
830{ 832{
831 struct mod_dso *mods = mod_dso__new_dso("modules"); 833 struct mod_dso *mods = mod_dso__new_dso("modules");
832 struct module *pos; 834 struct module *pos;
833 struct rb_node *next; 835 struct rb_node *next;
834 int err; 836 int err, count = 0;
835 837
836 err = mod_dso__load_modules(mods); 838 err = mod_dso__load_modules(mods);
837 839
@@ -844,20 +846,22 @@ int dso__load_modules(struct dso *self, symbol_filter_t filter, int verbose)
844 next = rb_first(&mods->mods); 846 next = rb_first(&mods->mods);
845 while (next) { 847 while (next) {
846 pos = rb_entry(next, struct module, rb_node); 848 pos = rb_entry(next, struct module, rb_node);
847 err = dso__load_module(self, mods, pos->name, filter, verbose); 849 err = dso__load_module(self, mods, pos->name, filter, v);
848 850
849 if (err < 0) 851 if (err < 0)
850 break; 852 break;
851 853
852 next = rb_next(&pos->rb_node); 854 next = rb_next(&pos->rb_node);
855 count += err;
853 } 856 }
854 857
855 if (err < 0) { 858 if (err < 0) {
856 mod_dso__delete_modules(mods); 859 mod_dso__delete_modules(mods);
857 mod_dso__delete_self(mods); 860 mod_dso__delete_self(mods);
861 return err;
858 } 862 }
859 863
860 return err; 864 return count;
861} 865}
862 866
863static inline void dso__fill_symbol_holes(struct dso *self) 867static inline void dso__fill_symbol_holes(struct dso *self)
@@ -887,14 +891,14 @@ static inline void dso__fill_symbol_holes(struct dso *self)
887} 891}
888 892
889static int dso__load_vmlinux(struct dso *self, const char *vmlinux, 893static int dso__load_vmlinux(struct dso *self, const char *vmlinux,
890 symbol_filter_t filter, int verbose) 894 symbol_filter_t filter, int v)
891{ 895{
892 int err, fd = open(vmlinux, O_RDONLY); 896 int err, fd = open(vmlinux, O_RDONLY);
893 897
894 if (fd < 0) 898 if (fd < 0)
895 return -1; 899 return -1;
896 900
897 err = dso__load_sym(self, fd, vmlinux, filter, verbose, NULL); 901 err = dso__load_sym(self, fd, vmlinux, filter, v, NULL);
898 902
899 if (err > 0) 903 if (err > 0)
900 dso__fill_symbol_holes(self); 904 dso__fill_symbol_holes(self);
@@ -905,18 +909,25 @@ static int dso__load_vmlinux(struct dso *self, const char *vmlinux,
905} 909}
906 910
907int dso__load_kernel(struct dso *self, const char *vmlinux, 911int dso__load_kernel(struct dso *self, const char *vmlinux,
908 symbol_filter_t filter, int verbose, int modules) 912 symbol_filter_t filter, int v, int use_modules)
909{ 913{
910 int err = -1; 914 int err = -1;
911 915
912 if (vmlinux) { 916 if (vmlinux) {
913 err = dso__load_vmlinux(self, vmlinux, filter, verbose); 917 err = dso__load_vmlinux(self, vmlinux, filter, v);
914 if (err > 0 && modules) 918 if (err > 0 && use_modules) {
915 err = dso__load_modules(self, filter, verbose); 919 int syms = dso__load_modules(self, filter, v);
920
921 if (syms < 0) {
922 fprintf(stderr, "dso__load_modules failed!\n");
923 return syms;
924 }
925 err += syms;
926 }
916 } 927 }
917 928
918 if (err <= 0) 929 if (err <= 0)
919 err = dso__load_kallsyms(self, filter, verbose); 930 err = dso__load_kallsyms(self, filter, v);
920 931
921 if (err > 0) 932 if (err > 0)
922 self->origin = DSO__ORIG_KERNEL; 933 self->origin = DSO__ORIG_KERNEL;
@@ -924,6 +935,103 @@ int dso__load_kernel(struct dso *self, const char *vmlinux,
924 return err; 935 return err;
925} 936}
926 937
938LIST_HEAD(dsos);
939struct dso *kernel_dso;
940struct dso *vdso;
941struct dso *hypervisor_dso;
942
943const char *vmlinux_name = "vmlinux";
944int modules;
945
946static void dsos__add(struct dso *dso)
947{
948 list_add_tail(&dso->node, &dsos);
949}
950
951static struct dso *dsos__find(const char *name)
952{
953 struct dso *pos;
954
955 list_for_each_entry(pos, &dsos, node)
956 if (strcmp(pos->name, name) == 0)
957 return pos;
958 return NULL;
959}
960
961struct dso *dsos__findnew(const char *name)
962{
963 struct dso *dso = dsos__find(name);
964 int nr;
965
966 if (dso)
967 return dso;
968
969 dso = dso__new(name, 0);
970 if (!dso)
971 goto out_delete_dso;
972
973 nr = dso__load(dso, NULL, verbose);
974 if (nr < 0) {
975 eprintf("Failed to open: %s\n", name);
976 goto out_delete_dso;
977 }
978 if (!nr)
979 eprintf("No symbols found in: %s, maybe install a debug package?\n", name);
980
981 dsos__add(dso);
982
983 return dso;
984
985out_delete_dso:
986 dso__delete(dso);
987 return NULL;
988}
989
990void dsos__fprintf(FILE *fp)
991{
992 struct dso *pos;
993
994 list_for_each_entry(pos, &dsos, node)
995 dso__fprintf(pos, fp);
996}
997
998static struct symbol *vdso__find_symbol(struct dso *dso, u64 ip)
999{
1000 return dso__find_symbol(dso, ip);
1001}
1002
1003int load_kernel(void)
1004{
1005 int err;
1006
1007 kernel_dso = dso__new("[kernel]", 0);
1008 if (!kernel_dso)
1009 return -1;
1010
1011 err = dso__load_kernel(kernel_dso, vmlinux_name, NULL, verbose, modules);
1012 if (err <= 0) {
1013 dso__delete(kernel_dso);
1014 kernel_dso = NULL;
1015 } else
1016 dsos__add(kernel_dso);
1017
1018 vdso = dso__new("[vdso]", 0);
1019 if (!vdso)
1020 return -1;
1021
1022 vdso->find_symbol = vdso__find_symbol;
1023
1024 dsos__add(vdso);
1025
1026 hypervisor_dso = dso__new("[hypervisor]", 0);
1027 if (!hypervisor_dso)
1028 return -1;
1029 dsos__add(hypervisor_dso);
1030
1031 return err;
1032}
1033
1034
927void symbol__init(void) 1035void symbol__init(void)
928{ 1036{
929 elf_version(EV_CURRENT); 1037 elf_version(EV_CURRENT);
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h
index b53bf0125c1b..6e8490716408 100644
--- a/tools/perf/util/symbol.h
+++ b/tools/perf/util/symbol.h
@@ -6,6 +6,7 @@
6#include <linux/list.h> 6#include <linux/list.h>
7#include <linux/rbtree.h> 7#include <linux/rbtree.h>
8#include "module.h" 8#include "module.h"
9#include "event.h"
9 10
10#ifdef HAVE_CPLUS_DEMANGLE 11#ifdef HAVE_CPLUS_DEMANGLE
11extern char *cplus_demangle(const char *, int); 12extern char *cplus_demangle(const char *, int);
@@ -54,7 +55,7 @@ struct dso {
54 char name[0]; 55 char name[0];
55}; 56};
56 57
57const char *sym_hist_filter; 58extern const char *sym_hist_filter;
58 59
59typedef int (*symbol_filter_t)(struct dso *self, struct symbol *sym); 60typedef int (*symbol_filter_t)(struct dso *self, struct symbol *sym);
60 61
@@ -72,9 +73,20 @@ int dso__load_kernel(struct dso *self, const char *vmlinux,
72 symbol_filter_t filter, int verbose, int modules); 73 symbol_filter_t filter, int verbose, int modules);
73int dso__load_modules(struct dso *self, symbol_filter_t filter, int verbose); 74int dso__load_modules(struct dso *self, symbol_filter_t filter, int verbose);
74int dso__load(struct dso *self, symbol_filter_t filter, int verbose); 75int dso__load(struct dso *self, symbol_filter_t filter, int verbose);
76struct dso *dsos__findnew(const char *name);
77void dsos__fprintf(FILE *fp);
75 78
76size_t dso__fprintf(struct dso *self, FILE *fp); 79size_t dso__fprintf(struct dso *self, FILE *fp);
77char dso__symtab_origin(const struct dso *self); 80char dso__symtab_origin(const struct dso *self);
78 81
82int load_kernel(void);
83
79void symbol__init(void); 84void symbol__init(void);
85
86extern struct list_head dsos;
87extern struct dso *kernel_dso;
88extern struct dso *vdso;
89extern struct dso *hypervisor_dso;
90extern const char *vmlinux_name;
91extern int modules;
80#endif /* _PERF_SYMBOL_ */ 92#endif /* _PERF_SYMBOL_ */
diff --git a/tools/perf/util/thread.c b/tools/perf/util/thread.c
new file mode 100644
index 000000000000..45efb5db0d19
--- /dev/null
+++ b/tools/perf/util/thread.c
@@ -0,0 +1,175 @@
1#include "../perf.h"
2#include <stdlib.h>
3#include <stdio.h>
4#include <string.h>
5#include "thread.h"
6#include "util.h"
7#include "debug.h"
8
9static struct thread *thread__new(pid_t pid)
10{
11 struct thread *self = calloc(1, sizeof(*self));
12
13 if (self != NULL) {
14 self->pid = pid;
15 self->comm = malloc(32);
16 if (self->comm)
17 snprintf(self->comm, 32, ":%d", self->pid);
18 INIT_LIST_HEAD(&self->maps);
19 }
20
21 return self;
22}
23
24int thread__set_comm(struct thread *self, const char *comm)
25{
26 if (self->comm)
27 free(self->comm);
28 self->comm = strdup(comm);
29 return self->comm ? 0 : -ENOMEM;
30}
31
32static size_t thread__fprintf(struct thread *self, FILE *fp)
33{
34 struct map *pos;
35 size_t ret = fprintf(fp, "Thread %d %s\n", self->pid, self->comm);
36
37 list_for_each_entry(pos, &self->maps, node)
38 ret += map__fprintf(pos, fp);
39
40 return ret;
41}
42
43struct thread *
44threads__findnew(pid_t pid, struct rb_root *threads, struct thread **last_match)
45{
46 struct rb_node **p = &threads->rb_node;
47 struct rb_node *parent = NULL;
48 struct thread *th;
49
50 /*
51 * Font-end cache - PID lookups come in blocks,
52 * so most of the time we dont have to look up
53 * the full rbtree:
54 */
55 if (*last_match && (*last_match)->pid == pid)
56 return *last_match;
57
58 while (*p != NULL) {
59 parent = *p;
60 th = rb_entry(parent, struct thread, rb_node);
61
62 if (th->pid == pid) {
63 *last_match = th;
64 return th;
65 }
66
67 if (pid < th->pid)
68 p = &(*p)->rb_left;
69 else
70 p = &(*p)->rb_right;
71 }
72
73 th = thread__new(pid);
74 if (th != NULL) {
75 rb_link_node(&th->rb_node, parent, p);
76 rb_insert_color(&th->rb_node, threads);
77 *last_match = th;
78 }
79
80 return th;
81}
82
83struct thread *
84register_idle_thread(struct rb_root *threads, struct thread **last_match)
85{
86 struct thread *thread = threads__findnew(0, threads, last_match);
87
88 if (!thread || thread__set_comm(thread, "swapper")) {
89 fprintf(stderr, "problem inserting idle task.\n");
90 exit(-1);
91 }
92
93 return thread;
94}
95
96void thread__insert_map(struct thread *self, struct map *map)
97{
98 struct map *pos, *tmp;
99
100 list_for_each_entry_safe(pos, tmp, &self->maps, node) {
101 if (map__overlap(pos, map)) {
102 if (verbose >= 2) {
103 printf("overlapping maps:\n");
104 map__fprintf(map, stdout);
105 map__fprintf(pos, stdout);
106 }
107
108 if (map->start <= pos->start && map->end > pos->start)
109 pos->start = map->end;
110
111 if (map->end >= pos->end && map->start < pos->end)
112 pos->end = map->start;
113
114 if (verbose >= 2) {
115 printf("after collision:\n");
116 map__fprintf(pos, stdout);
117 }
118
119 if (pos->start >= pos->end) {
120 list_del_init(&pos->node);
121 free(pos);
122 }
123 }
124 }
125
126 list_add_tail(&map->node, &self->maps);
127}
128
129int thread__fork(struct thread *self, struct thread *parent)
130{
131 struct map *map;
132
133 if (self->comm)
134 free(self->comm);
135 self->comm = strdup(parent->comm);
136 if (!self->comm)
137 return -ENOMEM;
138
139 list_for_each_entry(map, &parent->maps, node) {
140 struct map *new = map__clone(map);
141 if (!new)
142 return -ENOMEM;
143 thread__insert_map(self, new);
144 }
145
146 return 0;
147}
148
149struct map *thread__find_map(struct thread *self, u64 ip)
150{
151 struct map *pos;
152
153 if (self == NULL)
154 return NULL;
155
156 list_for_each_entry(pos, &self->maps, node)
157 if (ip >= pos->start && ip <= pos->end)
158 return pos;
159
160 return NULL;
161}
162
163size_t threads__fprintf(FILE *fp, struct rb_root *threads)
164{
165 size_t ret = 0;
166 struct rb_node *nd;
167
168 for (nd = rb_first(threads); nd; nd = rb_next(nd)) {
169 struct thread *pos = rb_entry(nd, struct thread, rb_node);
170
171 ret += thread__fprintf(pos, fp);
172 }
173
174 return ret;
175}
diff --git a/tools/perf/util/thread.h b/tools/perf/util/thread.h
new file mode 100644
index 000000000000..32aea3c1c2ad
--- /dev/null
+++ b/tools/perf/util/thread.h
@@ -0,0 +1,22 @@
1#include <linux/rbtree.h>
2#include <linux/list.h>
3#include <unistd.h>
4#include "symbol.h"
5
6struct thread {
7 struct rb_node rb_node;
8 struct list_head maps;
9 pid_t pid;
10 char shortname[3];
11 char *comm;
12};
13
14int thread__set_comm(struct thread *self, const char *comm);
15struct thread *
16threads__findnew(pid_t pid, struct rb_root *threads, struct thread **last_match);
17struct thread *
18register_idle_thread(struct rb_root *threads, struct thread **last_match);
19void thread__insert_map(struct thread *self, struct map *map);
20int thread__fork(struct thread *self, struct thread *parent);
21struct map *thread__find_map(struct thread *self, u64 ip);
22size_t threads__fprintf(FILE *fp, struct rb_root *threads);
diff --git a/tools/perf/util/trace-event-info.c b/tools/perf/util/trace-event-info.c
new file mode 100644
index 000000000000..af4b0573b37f
--- /dev/null
+++ b/tools/perf/util/trace-event-info.c
@@ -0,0 +1,540 @@
1/*
2 * Copyright (C) 2008,2009, Steven Rostedt <srostedt@redhat.com>
3 *
4 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; version 2 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 General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 *
19 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
20 */
21#define _GNU_SOURCE
22#include <dirent.h>
23#include <stdio.h>
24#include <stdlib.h>
25#include <string.h>
26#include <stdarg.h>
27#include <sys/types.h>
28#include <sys/stat.h>
29#include <sys/wait.h>
30#include <pthread.h>
31#include <fcntl.h>
32#include <unistd.h>
33#include <ctype.h>
34#include <errno.h>
35#include <stdbool.h>
36
37#include "../perf.h"
38#include "trace-event.h"
39
40
41#define VERSION "0.5"
42
43#define _STR(x) #x
44#define STR(x) _STR(x)
45#define MAX_PATH 256
46
47#define TRACE_CTRL "tracing_on"
48#define TRACE "trace"
49#define AVAILABLE "available_tracers"
50#define CURRENT "current_tracer"
51#define ITER_CTRL "trace_options"
52#define MAX_LATENCY "tracing_max_latency"
53
54unsigned int page_size;
55
56static const char *output_file = "trace.info";
57static int output_fd;
58
59struct event_list {
60 struct event_list *next;
61 const char *event;
62};
63
64struct events {
65 struct events *sibling;
66 struct events *children;
67 struct events *next;
68 char *name;
69};
70
71
72
73static void die(const char *fmt, ...)
74{
75 va_list ap;
76 int ret = errno;
77
78 if (errno)
79 perror("trace-cmd");
80 else
81 ret = -1;
82
83 va_start(ap, fmt);
84 fprintf(stderr, " ");
85 vfprintf(stderr, fmt, ap);
86 va_end(ap);
87
88 fprintf(stderr, "\n");
89 exit(ret);
90}
91
92void *malloc_or_die(unsigned int size)
93{
94 void *data;
95
96 data = malloc(size);
97 if (!data)
98 die("malloc");
99 return data;
100}
101
102static const char *find_debugfs(void)
103{
104 static char debugfs[MAX_PATH+1];
105 static int debugfs_found;
106 char type[100];
107 FILE *fp;
108
109 if (debugfs_found)
110 return debugfs;
111
112 if ((fp = fopen("/proc/mounts","r")) == NULL)
113 die("Can't open /proc/mounts for read");
114
115 while (fscanf(fp, "%*s %"
116 STR(MAX_PATH)
117 "s %99s %*s %*d %*d\n",
118 debugfs, type) == 2) {
119 if (strcmp(type, "debugfs") == 0)
120 break;
121 }
122 fclose(fp);
123
124 if (strcmp(type, "debugfs") != 0)
125 die("debugfs not mounted, please mount");
126
127 debugfs_found = 1;
128
129 return debugfs;
130}
131
132/*
133 * Finds the path to the debugfs/tracing
134 * Allocates the string and stores it.
135 */
136static const char *find_tracing_dir(void)
137{
138 static char *tracing;
139 static int tracing_found;
140 const char *debugfs;
141
142 if (tracing_found)
143 return tracing;
144
145 debugfs = find_debugfs();
146
147 tracing = malloc_or_die(strlen(debugfs) + 9);
148
149 sprintf(tracing, "%s/tracing", debugfs);
150
151 tracing_found = 1;
152 return tracing;
153}
154
155static char *get_tracing_file(const char *name)
156{
157 const char *tracing;
158 char *file;
159
160 tracing = find_tracing_dir();
161 if (!tracing)
162 return NULL;
163
164 file = malloc_or_die(strlen(tracing) + strlen(name) + 2);
165
166 sprintf(file, "%s/%s", tracing, name);
167 return file;
168}
169
170static void put_tracing_file(char *file)
171{
172 free(file);
173}
174
175static ssize_t write_or_die(const void *buf, size_t len)
176{
177 int ret;
178
179 ret = write(output_fd, buf, len);
180 if (ret < 0)
181 die("writing to '%s'", output_file);
182
183 return ret;
184}
185
186int bigendian(void)
187{
188 unsigned char str[] = { 0x1, 0x2, 0x3, 0x4, 0x0, 0x0, 0x0, 0x0};
189 unsigned int *ptr;
190
191 ptr = (unsigned int *)(void *)str;
192 return *ptr == 0x01020304;
193}
194
195static unsigned long long copy_file_fd(int fd)
196{
197 unsigned long long size = 0;
198 char buf[BUFSIZ];
199 int r;
200
201 do {
202 r = read(fd, buf, BUFSIZ);
203 if (r > 0) {
204 size += r;
205 write_or_die(buf, r);
206 }
207 } while (r > 0);
208
209 return size;
210}
211
212static unsigned long long copy_file(const char *file)
213{
214 unsigned long long size = 0;
215 int fd;
216
217 fd = open(file, O_RDONLY);
218 if (fd < 0)
219 die("Can't read '%s'", file);
220 size = copy_file_fd(fd);
221 close(fd);
222
223 return size;
224}
225
226static unsigned long get_size_fd(int fd)
227{
228 unsigned long long size = 0;
229 char buf[BUFSIZ];
230 int r;
231
232 do {
233 r = read(fd, buf, BUFSIZ);
234 if (r > 0)
235 size += r;
236 } while (r > 0);
237
238 lseek(fd, 0, SEEK_SET);
239
240 return size;
241}
242
243static unsigned long get_size(const char *file)
244{
245 unsigned long long size = 0;
246 int fd;
247
248 fd = open(file, O_RDONLY);
249 if (fd < 0)
250 die("Can't read '%s'", file);
251 size = get_size_fd(fd);
252 close(fd);
253
254 return size;
255}
256
257static void read_header_files(void)
258{
259 unsigned long long size, check_size;
260 char *path;
261 int fd;
262
263 path = get_tracing_file("events/header_page");
264 fd = open(path, O_RDONLY);
265 if (fd < 0)
266 die("can't read '%s'", path);
267
268 /* unfortunately, you can not stat debugfs files for size */
269 size = get_size_fd(fd);
270
271 write_or_die("header_page", 12);
272 write_or_die(&size, 8);
273 check_size = copy_file_fd(fd);
274 if (size != check_size)
275 die("wrong size for '%s' size=%lld read=%lld",
276 path, size, check_size);
277 put_tracing_file(path);
278
279 path = get_tracing_file("events/header_event");
280 fd = open(path, O_RDONLY);
281 if (fd < 0)
282 die("can't read '%s'", path);
283
284 size = get_size_fd(fd);
285
286 write_or_die("header_event", 13);
287 write_or_die(&size, 8);
288 check_size = copy_file_fd(fd);
289 if (size != check_size)
290 die("wrong size for '%s'", path);
291 put_tracing_file(path);
292}
293
294static bool name_in_tp_list(char *sys, struct tracepoint_path *tps)
295{
296 while (tps) {
297 if (!strcmp(sys, tps->name))
298 return true;
299 tps = tps->next;
300 }
301
302 return false;
303}
304
305static void copy_event_system(const char *sys, struct tracepoint_path *tps)
306{
307 unsigned long long size, check_size;
308 struct dirent *dent;
309 struct stat st;
310 char *format;
311 DIR *dir;
312 int count = 0;
313 int ret;
314
315 dir = opendir(sys);
316 if (!dir)
317 die("can't read directory '%s'", sys);
318
319 while ((dent = readdir(dir))) {
320 if (strcmp(dent->d_name, ".") == 0 ||
321 strcmp(dent->d_name, "..") == 0 ||
322 !name_in_tp_list(dent->d_name, tps))
323 continue;
324 format = malloc_or_die(strlen(sys) + strlen(dent->d_name) + 10);
325 sprintf(format, "%s/%s/format", sys, dent->d_name);
326 ret = stat(format, &st);
327 free(format);
328 if (ret < 0)
329 continue;
330 count++;
331 }
332
333 write_or_die(&count, 4);
334
335 rewinddir(dir);
336 while ((dent = readdir(dir))) {
337 if (strcmp(dent->d_name, ".") == 0 ||
338 strcmp(dent->d_name, "..") == 0 ||
339 !name_in_tp_list(dent->d_name, tps))
340 continue;
341 format = malloc_or_die(strlen(sys) + strlen(dent->d_name) + 10);
342 sprintf(format, "%s/%s/format", sys, dent->d_name);
343 ret = stat(format, &st);
344
345 if (ret >= 0) {
346 /* unfortunately, you can not stat debugfs files for size */
347 size = get_size(format);
348 write_or_die(&size, 8);
349 check_size = copy_file(format);
350 if (size != check_size)
351 die("error in size of file '%s'", format);
352 }
353
354 free(format);
355 }
356}
357
358static void read_ftrace_files(struct tracepoint_path *tps)
359{
360 char *path;
361
362 path = get_tracing_file("events/ftrace");
363
364 copy_event_system(path, tps);
365
366 put_tracing_file(path);
367}
368
369static bool system_in_tp_list(char *sys, struct tracepoint_path *tps)
370{
371 while (tps) {
372 if (!strcmp(sys, tps->system))
373 return true;
374 tps = tps->next;
375 }
376
377 return false;
378}
379
380static void read_event_files(struct tracepoint_path *tps)
381{
382 struct dirent *dent;
383 struct stat st;
384 char *path;
385 char *sys;
386 DIR *dir;
387 int count = 0;
388 int ret;
389
390 path = get_tracing_file("events");
391
392 dir = opendir(path);
393 if (!dir)
394 die("can't read directory '%s'", path);
395
396 while ((dent = readdir(dir))) {
397 if (strcmp(dent->d_name, ".") == 0 ||
398 strcmp(dent->d_name, "..") == 0 ||
399 strcmp(dent->d_name, "ftrace") == 0 ||
400 !system_in_tp_list(dent->d_name, tps))
401 continue;
402 sys = malloc_or_die(strlen(path) + strlen(dent->d_name) + 2);
403 sprintf(sys, "%s/%s", path, dent->d_name);
404 ret = stat(sys, &st);
405 free(sys);
406 if (ret < 0)
407 continue;
408 if (S_ISDIR(st.st_mode))
409 count++;
410 }
411
412 write_or_die(&count, 4);
413
414 rewinddir(dir);
415 while ((dent = readdir(dir))) {
416 if (strcmp(dent->d_name, ".") == 0 ||
417 strcmp(dent->d_name, "..") == 0 ||
418 strcmp(dent->d_name, "ftrace") == 0 ||
419 !system_in_tp_list(dent->d_name, tps))
420 continue;
421 sys = malloc_or_die(strlen(path) + strlen(dent->d_name) + 2);
422 sprintf(sys, "%s/%s", path, dent->d_name);
423 ret = stat(sys, &st);
424 if (ret >= 0) {
425 if (S_ISDIR(st.st_mode)) {
426 write_or_die(dent->d_name, strlen(dent->d_name) + 1);
427 copy_event_system(sys, tps);
428 }
429 }
430 free(sys);
431 }
432
433 put_tracing_file(path);
434}
435
436static void read_proc_kallsyms(void)
437{
438 unsigned int size, check_size;
439 const char *path = "/proc/kallsyms";
440 struct stat st;
441 int ret;
442
443 ret = stat(path, &st);
444 if (ret < 0) {
445 /* not found */
446 size = 0;
447 write_or_die(&size, 4);
448 return;
449 }
450 size = get_size(path);
451 write_or_die(&size, 4);
452 check_size = copy_file(path);
453 if (size != check_size)
454 die("error in size of file '%s'", path);
455
456}
457
458static void read_ftrace_printk(void)
459{
460 unsigned int size, check_size;
461 char *path;
462 struct stat st;
463 int ret;
464
465 path = get_tracing_file("printk_formats");
466 ret = stat(path, &st);
467 if (ret < 0) {
468 /* not found */
469 size = 0;
470 write_or_die(&size, 4);
471 goto out;
472 }
473 size = get_size(path);
474 write_or_die(&size, 4);
475 check_size = copy_file(path);
476 if (size != check_size)
477 die("error in size of file '%s'", path);
478out:
479 put_tracing_file(path);
480}
481
482static struct tracepoint_path *
483get_tracepoints_path(struct perf_event_attr *pattrs, int nb_events)
484{
485 struct tracepoint_path path, *ppath = &path;
486 int i;
487
488 for (i = 0; i < nb_events; i++) {
489 if (pattrs[i].type != PERF_TYPE_TRACEPOINT)
490 continue;
491 ppath->next = tracepoint_id_to_path(pattrs[i].config);
492 if (!ppath->next)
493 die("%s\n", "No memory to alloc tracepoints list");
494 ppath = ppath->next;
495 }
496
497 return path.next;
498}
499void read_tracing_data(struct perf_event_attr *pattrs, int nb_events)
500{
501 char buf[BUFSIZ];
502 struct tracepoint_path *tps;
503
504 output_fd = open(output_file, O_WRONLY | O_CREAT | O_TRUNC | O_LARGEFILE, 0644);
505 if (output_fd < 0)
506 die("creating file '%s'", output_file);
507
508 buf[0] = 23;
509 buf[1] = 8;
510 buf[2] = 68;
511 memcpy(buf + 3, "tracing", 7);
512
513 write_or_die(buf, 10);
514
515 write_or_die(VERSION, strlen(VERSION) + 1);
516
517 /* save endian */
518 if (bigendian())
519 buf[0] = 1;
520 else
521 buf[0] = 0;
522
523 write_or_die(buf, 1);
524
525 /* save size of long */
526 buf[0] = sizeof(long);
527 write_or_die(buf, 1);
528
529 /* save page_size */
530 page_size = getpagesize();
531 write_or_die(&page_size, 4);
532
533 tps = get_tracepoints_path(pattrs, nb_events);
534
535 read_header_files();
536 read_ftrace_files(tps);
537 read_event_files(tps);
538 read_proc_kallsyms();
539 read_ftrace_printk();
540}
diff --git a/tools/perf/util/trace-event-parse.c b/tools/perf/util/trace-event-parse.c
new file mode 100644
index 000000000000..f6a8437141c8
--- /dev/null
+++ b/tools/perf/util/trace-event-parse.c
@@ -0,0 +1,2967 @@
1/*
2 * Copyright (C) 2009, Steven Rostedt <srostedt@redhat.com>
3 *
4 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; version 2 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 General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 *
19 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
20 *
21 * The parts for function graph printing was taken and modified from the
22 * Linux Kernel that were written by Frederic Weisbecker.
23 */
24#define _GNU_SOURCE
25#include <stdio.h>
26#include <stdlib.h>
27#include <string.h>
28#include <ctype.h>
29#include <errno.h>
30
31#undef _GNU_SOURCE
32#include "../perf.h"
33#include "util.h"
34#include "trace-event.h"
35
36int header_page_ts_offset;
37int header_page_ts_size;
38int header_page_size_offset;
39int header_page_size_size;
40int header_page_data_offset;
41int header_page_data_size;
42
43static char *input_buf;
44static unsigned long long input_buf_ptr;
45static unsigned long long input_buf_siz;
46
47static int cpus;
48static int long_size;
49
50static void init_input_buf(char *buf, unsigned long long size)
51{
52 input_buf = buf;
53 input_buf_siz = size;
54 input_buf_ptr = 0;
55}
56
57struct cmdline {
58 char *comm;
59 int pid;
60};
61
62static struct cmdline *cmdlines;
63static int cmdline_count;
64
65static int cmdline_cmp(const void *a, const void *b)
66{
67 const struct cmdline *ca = a;
68 const struct cmdline *cb = b;
69
70 if (ca->pid < cb->pid)
71 return -1;
72 if (ca->pid > cb->pid)
73 return 1;
74
75 return 0;
76}
77
78void parse_cmdlines(char *file, int size __unused)
79{
80 struct cmdline_list {
81 struct cmdline_list *next;
82 char *comm;
83 int pid;
84 } *list = NULL, *item;
85 char *line;
86 char *next = NULL;
87 int i;
88
89 line = strtok_r(file, "\n", &next);
90 while (line) {
91 item = malloc_or_die(sizeof(*item));
92 sscanf(line, "%d %as", &item->pid,
93 (float *)(void *)&item->comm); /* workaround gcc warning */
94 item->next = list;
95 list = item;
96 line = strtok_r(NULL, "\n", &next);
97 cmdline_count++;
98 }
99
100 cmdlines = malloc_or_die(sizeof(*cmdlines) * cmdline_count);
101
102 i = 0;
103 while (list) {
104 cmdlines[i].pid = list->pid;
105 cmdlines[i].comm = list->comm;
106 i++;
107 item = list;
108 list = list->next;
109 free(item);
110 }
111
112 qsort(cmdlines, cmdline_count, sizeof(*cmdlines), cmdline_cmp);
113}
114
115static struct func_map {
116 unsigned long long addr;
117 char *func;
118 char *mod;
119} *func_list;
120static unsigned int func_count;
121
122static int func_cmp(const void *a, const void *b)
123{
124 const struct func_map *fa = a;
125 const struct func_map *fb = b;
126
127 if (fa->addr < fb->addr)
128 return -1;
129 if (fa->addr > fb->addr)
130 return 1;
131
132 return 0;
133}
134
135void parse_proc_kallsyms(char *file, unsigned int size __unused)
136{
137 struct func_list {
138 struct func_list *next;
139 unsigned long long addr;
140 char *func;
141 char *mod;
142 } *list = NULL, *item;
143 char *line;
144 char *next = NULL;
145 char *addr_str;
146 char ch;
147 int ret;
148 int i;
149
150 line = strtok_r(file, "\n", &next);
151 while (line) {
152 item = malloc_or_die(sizeof(*item));
153 item->mod = NULL;
154 ret = sscanf(line, "%as %c %as\t[%as",
155 (float *)(void *)&addr_str, /* workaround gcc warning */
156 &ch,
157 (float *)(void *)&item->func,
158 (float *)(void *)&item->mod);
159 item->addr = strtoull(addr_str, NULL, 16);
160 free(addr_str);
161
162 /* truncate the extra ']' */
163 if (item->mod)
164 item->mod[strlen(item->mod) - 1] = 0;
165
166
167 item->next = list;
168 list = item;
169 line = strtok_r(NULL, "\n", &next);
170 func_count++;
171 }
172
173 func_list = malloc_or_die(sizeof(*func_list) * func_count + 1);
174
175 i = 0;
176 while (list) {
177 func_list[i].func = list->func;
178 func_list[i].addr = list->addr;
179 func_list[i].mod = list->mod;
180 i++;
181 item = list;
182 list = list->next;
183 free(item);
184 }
185
186 qsort(func_list, func_count, sizeof(*func_list), func_cmp);
187
188 /*
189 * Add a special record at the end.
190 */
191 func_list[func_count].func = NULL;
192 func_list[func_count].addr = 0;
193 func_list[func_count].mod = NULL;
194}
195
196/*
197 * We are searching for a record in between, not an exact
198 * match.
199 */
200static int func_bcmp(const void *a, const void *b)
201{
202 const struct func_map *fa = a;
203 const struct func_map *fb = b;
204
205 if ((fa->addr == fb->addr) ||
206
207 (fa->addr > fb->addr &&
208 fa->addr < (fb+1)->addr))
209 return 0;
210
211 if (fa->addr < fb->addr)
212 return -1;
213
214 return 1;
215}
216
217static struct func_map *find_func(unsigned long long addr)
218{
219 struct func_map *func;
220 struct func_map key;
221
222 key.addr = addr;
223
224 func = bsearch(&key, func_list, func_count, sizeof(*func_list),
225 func_bcmp);
226
227 return func;
228}
229
230void print_funcs(void)
231{
232 int i;
233
234 for (i = 0; i < (int)func_count; i++) {
235 printf("%016llx %s",
236 func_list[i].addr,
237 func_list[i].func);
238 if (func_list[i].mod)
239 printf(" [%s]\n", func_list[i].mod);
240 else
241 printf("\n");
242 }
243}
244
245static struct printk_map {
246 unsigned long long addr;
247 char *printk;
248} *printk_list;
249static unsigned int printk_count;
250
251static int printk_cmp(const void *a, const void *b)
252{
253 const struct func_map *fa = a;
254 const struct func_map *fb = b;
255
256 if (fa->addr < fb->addr)
257 return -1;
258 if (fa->addr > fb->addr)
259 return 1;
260
261 return 0;
262}
263
264static struct printk_map *find_printk(unsigned long long addr)
265{
266 struct printk_map *printk;
267 struct printk_map key;
268
269 key.addr = addr;
270
271 printk = bsearch(&key, printk_list, printk_count, sizeof(*printk_list),
272 printk_cmp);
273
274 return printk;
275}
276
277void parse_ftrace_printk(char *file, unsigned int size __unused)
278{
279 struct printk_list {
280 struct printk_list *next;
281 unsigned long long addr;
282 char *printk;
283 } *list = NULL, *item;
284 char *line;
285 char *next = NULL;
286 char *addr_str;
287 int ret;
288 int i;
289
290 line = strtok_r(file, "\n", &next);
291 while (line) {
292 item = malloc_or_die(sizeof(*item));
293 ret = sscanf(line, "%as : %as",
294 (float *)(void *)&addr_str, /* workaround gcc warning */
295 (float *)(void *)&item->printk);
296 item->addr = strtoull(addr_str, NULL, 16);
297 free(addr_str);
298
299 item->next = list;
300 list = item;
301 line = strtok_r(NULL, "\n", &next);
302 printk_count++;
303 }
304
305 printk_list = malloc_or_die(sizeof(*printk_list) * printk_count + 1);
306
307 i = 0;
308 while (list) {
309 printk_list[i].printk = list->printk;
310 printk_list[i].addr = list->addr;
311 i++;
312 item = list;
313 list = list->next;
314 free(item);
315 }
316
317 qsort(printk_list, printk_count, sizeof(*printk_list), printk_cmp);
318}
319
320void print_printk(void)
321{
322 int i;
323
324 for (i = 0; i < (int)printk_count; i++) {
325 printf("%016llx %s\n",
326 printk_list[i].addr,
327 printk_list[i].printk);
328 }
329}
330
331static struct event *alloc_event(void)
332{
333 struct event *event;
334
335 event = malloc_or_die(sizeof(*event));
336 memset(event, 0, sizeof(*event));
337
338 return event;
339}
340
341enum event_type {
342 EVENT_ERROR,
343 EVENT_NONE,
344 EVENT_SPACE,
345 EVENT_NEWLINE,
346 EVENT_OP,
347 EVENT_DELIM,
348 EVENT_ITEM,
349 EVENT_DQUOTE,
350 EVENT_SQUOTE,
351};
352
353static struct event *event_list;
354
355static void add_event(struct event *event)
356{
357 event->next = event_list;
358 event_list = event;
359}
360
361static int event_item_type(enum event_type type)
362{
363 switch (type) {
364 case EVENT_ITEM ... EVENT_SQUOTE:
365 return 1;
366 case EVENT_ERROR ... EVENT_DELIM:
367 default:
368 return 0;
369 }
370}
371
372static void free_arg(struct print_arg *arg)
373{
374 if (!arg)
375 return;
376
377 switch (arg->type) {
378 case PRINT_ATOM:
379 if (arg->atom.atom)
380 free(arg->atom.atom);
381 break;
382 case PRINT_NULL:
383 case PRINT_FIELD ... PRINT_OP:
384 default:
385 /* todo */
386 break;
387 }
388
389 free(arg);
390}
391
392static enum event_type get_type(int ch)
393{
394 if (ch == '\n')
395 return EVENT_NEWLINE;
396 if (isspace(ch))
397 return EVENT_SPACE;
398 if (isalnum(ch) || ch == '_')
399 return EVENT_ITEM;
400 if (ch == '\'')
401 return EVENT_SQUOTE;
402 if (ch == '"')
403 return EVENT_DQUOTE;
404 if (!isprint(ch))
405 return EVENT_NONE;
406 if (ch == '(' || ch == ')' || ch == ',')
407 return EVENT_DELIM;
408
409 return EVENT_OP;
410}
411
412static int __read_char(void)
413{
414 if (input_buf_ptr >= input_buf_siz)
415 return -1;
416
417 return input_buf[input_buf_ptr++];
418}
419
420static int __peek_char(void)
421{
422 if (input_buf_ptr >= input_buf_siz)
423 return -1;
424
425 return input_buf[input_buf_ptr];
426}
427
428static enum event_type __read_token(char **tok)
429{
430 char buf[BUFSIZ];
431 int ch, last_ch, quote_ch, next_ch;
432 int i = 0;
433 int tok_size = 0;
434 enum event_type type;
435
436 *tok = NULL;
437
438
439 ch = __read_char();
440 if (ch < 0)
441 return EVENT_NONE;
442
443 type = get_type(ch);
444 if (type == EVENT_NONE)
445 return type;
446
447 buf[i++] = ch;
448
449 switch (type) {
450 case EVENT_NEWLINE:
451 case EVENT_DELIM:
452 *tok = malloc_or_die(2);
453 (*tok)[0] = ch;
454 (*tok)[1] = 0;
455 return type;
456
457 case EVENT_OP:
458 switch (ch) {
459 case '-':
460 next_ch = __peek_char();
461 if (next_ch == '>') {
462 buf[i++] = __read_char();
463 break;
464 }
465 /* fall through */
466 case '+':
467 case '|':
468 case '&':
469 case '>':
470 case '<':
471 last_ch = ch;
472 ch = __peek_char();
473 if (ch != last_ch)
474 goto test_equal;
475 buf[i++] = __read_char();
476 switch (last_ch) {
477 case '>':
478 case '<':
479 goto test_equal;
480 default:
481 break;
482 }
483 break;
484 case '!':
485 case '=':
486 goto test_equal;
487 default: /* what should we do instead? */
488 break;
489 }
490 buf[i] = 0;
491 *tok = strdup(buf);
492 return type;
493
494 test_equal:
495 ch = __peek_char();
496 if (ch == '=')
497 buf[i++] = __read_char();
498 break;
499
500 case EVENT_DQUOTE:
501 case EVENT_SQUOTE:
502 /* don't keep quotes */
503 i--;
504 quote_ch = ch;
505 last_ch = 0;
506 do {
507 if (i == (BUFSIZ - 1)) {
508 buf[i] = 0;
509 if (*tok) {
510 *tok = realloc(*tok, tok_size + BUFSIZ);
511 if (!*tok)
512 return EVENT_NONE;
513 strcat(*tok, buf);
514 } else
515 *tok = strdup(buf);
516
517 if (!*tok)
518 return EVENT_NONE;
519 tok_size += BUFSIZ;
520 i = 0;
521 }
522 last_ch = ch;
523 ch = __read_char();
524 buf[i++] = ch;
525 } while (ch != quote_ch && last_ch != '\\');
526 /* remove the last quote */
527 i--;
528 goto out;
529
530 case EVENT_ERROR ... EVENT_SPACE:
531 case EVENT_ITEM:
532 default:
533 break;
534 }
535
536 while (get_type(__peek_char()) == type) {
537 if (i == (BUFSIZ - 1)) {
538 buf[i] = 0;
539 if (*tok) {
540 *tok = realloc(*tok, tok_size + BUFSIZ);
541 if (!*tok)
542 return EVENT_NONE;
543 strcat(*tok, buf);
544 } else
545 *tok = strdup(buf);
546
547 if (!*tok)
548 return EVENT_NONE;
549 tok_size += BUFSIZ;
550 i = 0;
551 }
552 ch = __read_char();
553 buf[i++] = ch;
554 }
555
556 out:
557 buf[i] = 0;
558 if (*tok) {
559 *tok = realloc(*tok, tok_size + i);
560 if (!*tok)
561 return EVENT_NONE;
562 strcat(*tok, buf);
563 } else
564 *tok = strdup(buf);
565 if (!*tok)
566 return EVENT_NONE;
567
568 return type;
569}
570
571static void free_token(char *tok)
572{
573 if (tok)
574 free(tok);
575}
576
577static enum event_type read_token(char **tok)
578{
579 enum event_type type;
580
581 for (;;) {
582 type = __read_token(tok);
583 if (type != EVENT_SPACE)
584 return type;
585
586 free_token(*tok);
587 }
588
589 /* not reached */
590 return EVENT_NONE;
591}
592
593/* no newline */
594static enum event_type read_token_item(char **tok)
595{
596 enum event_type type;
597
598 for (;;) {
599 type = __read_token(tok);
600 if (type != EVENT_SPACE && type != EVENT_NEWLINE)
601 return type;
602
603 free_token(*tok);
604 }
605
606 /* not reached */
607 return EVENT_NONE;
608}
609
610static int test_type(enum event_type type, enum event_type expect)
611{
612 if (type != expect) {
613 die("Error: expected type %d but read %d",
614 expect, type);
615 return -1;
616 }
617 return 0;
618}
619
620static int test_type_token(enum event_type type, char *token,
621 enum event_type expect, char *expect_tok)
622{
623 if (type != expect) {
624 die("Error: expected type %d but read %d",
625 expect, type);
626 return -1;
627 }
628
629 if (strcmp(token, expect_tok) != 0) {
630 die("Error: expected '%s' but read '%s'",
631 expect_tok, token);
632 return -1;
633 }
634 return 0;
635}
636
637static int __read_expect_type(enum event_type expect, char **tok, int newline_ok)
638{
639 enum event_type type;
640
641 if (newline_ok)
642 type = read_token(tok);
643 else
644 type = read_token_item(tok);
645 return test_type(type, expect);
646}
647
648static int read_expect_type(enum event_type expect, char **tok)
649{
650 return __read_expect_type(expect, tok, 1);
651}
652
653static int __read_expected(enum event_type expect, char *str, int newline_ok)
654{
655 enum event_type type;
656 char *token;
657 int ret;
658
659 if (newline_ok)
660 type = read_token(&token);
661 else
662 type = read_token_item(&token);
663
664 ret = test_type_token(type, token, expect, str);
665
666 free_token(token);
667
668 return 0;
669}
670
671static int read_expected(enum event_type expect, char *str)
672{
673 return __read_expected(expect, str, 1);
674}
675
676static int read_expected_item(enum event_type expect, char *str)
677{
678 return __read_expected(expect, str, 0);
679}
680
681static char *event_read_name(void)
682{
683 char *token;
684
685 if (read_expected(EVENT_ITEM, (char *)"name") < 0)
686 return NULL;
687
688 if (read_expected(EVENT_OP, (char *)":") < 0)
689 return NULL;
690
691 if (read_expect_type(EVENT_ITEM, &token) < 0)
692 goto fail;
693
694 return token;
695
696 fail:
697 free_token(token);
698 return NULL;
699}
700
701static int event_read_id(void)
702{
703 char *token;
704 int id;
705
706 if (read_expected_item(EVENT_ITEM, (char *)"ID") < 0)
707 return -1;
708
709 if (read_expected(EVENT_OP, (char *)":") < 0)
710 return -1;
711
712 if (read_expect_type(EVENT_ITEM, &token) < 0)
713 goto fail;
714
715 id = strtoul(token, NULL, 0);
716 free_token(token);
717 return id;
718
719 fail:
720 free_token(token);
721 return -1;
722}
723
724static int event_read_fields(struct event *event, struct format_field **fields)
725{
726 struct format_field *field = NULL;
727 enum event_type type;
728 char *token;
729 char *last_token;
730 int count = 0;
731
732 do {
733 type = read_token(&token);
734 if (type == EVENT_NEWLINE) {
735 free_token(token);
736 return count;
737 }
738
739 count++;
740
741 if (test_type_token(type, token, EVENT_ITEM, (char *)"field"))
742 goto fail;
743 free_token(token);
744
745 type = read_token(&token);
746 /*
747 * The ftrace fields may still use the "special" name.
748 * Just ignore it.
749 */
750 if (event->flags & EVENT_FL_ISFTRACE &&
751 type == EVENT_ITEM && strcmp(token, "special") == 0) {
752 free_token(token);
753 type = read_token(&token);
754 }
755
756 if (test_type_token(type, token, EVENT_OP, (char *)":") < 0)
757 return -1;
758
759 if (read_expect_type(EVENT_ITEM, &token) < 0)
760 goto fail;
761
762 last_token = token;
763
764 field = malloc_or_die(sizeof(*field));
765 memset(field, 0, sizeof(*field));
766
767 /* read the rest of the type */
768 for (;;) {
769 type = read_token(&token);
770 if (type == EVENT_ITEM ||
771 (type == EVENT_OP && strcmp(token, "*") == 0) ||
772 /*
773 * Some of the ftrace fields are broken and have
774 * an illegal "." in them.
775 */
776 (event->flags & EVENT_FL_ISFTRACE &&
777 type == EVENT_OP && strcmp(token, ".") == 0)) {
778
779 if (strcmp(token, "*") == 0)
780 field->flags |= FIELD_IS_POINTER;
781
782 if (field->type) {
783 field->type = realloc(field->type,
784 strlen(field->type) +
785 strlen(last_token) + 2);
786 strcat(field->type, " ");
787 strcat(field->type, last_token);
788 } else
789 field->type = last_token;
790 last_token = token;
791 continue;
792 }
793
794 break;
795 }
796
797 if (!field->type) {
798 die("no type found");
799 goto fail;
800 }
801 field->name = last_token;
802
803 if (test_type(type, EVENT_OP))
804 goto fail;
805
806 if (strcmp(token, "[") == 0) {
807 enum event_type last_type = type;
808 char *brackets = token;
809 int len;
810
811 field->flags |= FIELD_IS_ARRAY;
812
813 type = read_token(&token);
814 while (strcmp(token, "]") != 0) {
815 if (last_type == EVENT_ITEM &&
816 type == EVENT_ITEM)
817 len = 2;
818 else
819 len = 1;
820 last_type = type;
821
822 brackets = realloc(brackets,
823 strlen(brackets) +
824 strlen(token) + len);
825 if (len == 2)
826 strcat(brackets, " ");
827 strcat(brackets, token);
828 free_token(token);
829 type = read_token(&token);
830 if (type == EVENT_NONE) {
831 die("failed to find token");
832 goto fail;
833 }
834 }
835
836 free_token(token);
837
838 brackets = realloc(brackets, strlen(brackets) + 2);
839 strcat(brackets, "]");
840
841 /* add brackets to type */
842
843 type = read_token(&token);
844 /*
845 * If the next token is not an OP, then it is of
846 * the format: type [] item;
847 */
848 if (type == EVENT_ITEM) {
849 field->type = realloc(field->type,
850 strlen(field->type) +
851 strlen(field->name) +
852 strlen(brackets) + 2);
853 strcat(field->type, " ");
854 strcat(field->type, field->name);
855 free_token(field->name);
856 strcat(field->type, brackets);
857 field->name = token;
858 type = read_token(&token);
859 } else {
860 field->type = realloc(field->type,
861 strlen(field->type) +
862 strlen(brackets) + 1);
863 strcat(field->type, brackets);
864 }
865 free(brackets);
866 }
867
868 if (test_type_token(type, token, EVENT_OP, (char *)";"))
869 goto fail;
870 free_token(token);
871
872 if (read_expected(EVENT_ITEM, (char *)"offset") < 0)
873 goto fail_expect;
874
875 if (read_expected(EVENT_OP, (char *)":") < 0)
876 goto fail_expect;
877
878 if (read_expect_type(EVENT_ITEM, &token))
879 goto fail;
880 field->offset = strtoul(token, NULL, 0);
881 free_token(token);
882
883 if (read_expected(EVENT_OP, (char *)";") < 0)
884 goto fail_expect;
885
886 if (read_expected(EVENT_ITEM, (char *)"size") < 0)
887 goto fail_expect;
888
889 if (read_expected(EVENT_OP, (char *)":") < 0)
890 goto fail_expect;
891
892 if (read_expect_type(EVENT_ITEM, &token))
893 goto fail;
894 field->size = strtoul(token, NULL, 0);
895 free_token(token);
896
897 if (read_expected(EVENT_OP, (char *)";") < 0)
898 goto fail_expect;
899
900 if (read_expect_type(EVENT_NEWLINE, &token) < 0)
901 goto fail;
902 free_token(token);
903
904 *fields = field;
905 fields = &field->next;
906
907 } while (1);
908
909 return 0;
910
911fail:
912 free_token(token);
913fail_expect:
914 if (field)
915 free(field);
916 return -1;
917}
918
919static int event_read_format(struct event *event)
920{
921 char *token;
922 int ret;
923
924 if (read_expected_item(EVENT_ITEM, (char *)"format") < 0)
925 return -1;
926
927 if (read_expected(EVENT_OP, (char *)":") < 0)
928 return -1;
929
930 if (read_expect_type(EVENT_NEWLINE, &token))
931 goto fail;
932 free_token(token);
933
934 ret = event_read_fields(event, &event->format.common_fields);
935 if (ret < 0)
936 return ret;
937 event->format.nr_common = ret;
938
939 ret = event_read_fields(event, &event->format.fields);
940 if (ret < 0)
941 return ret;
942 event->format.nr_fields = ret;
943
944 return 0;
945
946 fail:
947 free_token(token);
948 return -1;
949}
950
951enum event_type
952process_arg_token(struct event *event, struct print_arg *arg,
953 char **tok, enum event_type type);
954
955static enum event_type
956process_arg(struct event *event, struct print_arg *arg, char **tok)
957{
958 enum event_type type;
959 char *token;
960
961 type = read_token(&token);
962 *tok = token;
963
964 return process_arg_token(event, arg, tok, type);
965}
966
967static enum event_type
968process_cond(struct event *event, struct print_arg *top, char **tok)
969{
970 struct print_arg *arg, *left, *right;
971 enum event_type type;
972 char *token = NULL;
973
974 arg = malloc_or_die(sizeof(*arg));
975 memset(arg, 0, sizeof(*arg));
976
977 left = malloc_or_die(sizeof(*left));
978
979 right = malloc_or_die(sizeof(*right));
980
981 arg->type = PRINT_OP;
982 arg->op.left = left;
983 arg->op.right = right;
984
985 *tok = NULL;
986 type = process_arg(event, left, &token);
987 if (test_type_token(type, token, EVENT_OP, (char *)":"))
988 goto out_free;
989
990 arg->op.op = token;
991
992 type = process_arg(event, right, &token);
993
994 top->op.right = arg;
995
996 *tok = token;
997 return type;
998
999out_free:
1000 free_token(*tok);
1001 free(right);
1002 free(left);
1003 free_arg(arg);
1004 return EVENT_ERROR;
1005}
1006
1007static int get_op_prio(char *op)
1008{
1009 if (!op[1]) {
1010 switch (op[0]) {
1011 case '*':
1012 case '/':
1013 case '%':
1014 return 6;
1015 case '+':
1016 case '-':
1017 return 7;
1018 /* '>>' and '<<' are 8 */
1019 case '<':
1020 case '>':
1021 return 9;
1022 /* '==' and '!=' are 10 */
1023 case '&':
1024 return 11;
1025 case '^':
1026 return 12;
1027 case '|':
1028 return 13;
1029 case '?':
1030 return 16;
1031 default:
1032 die("unknown op '%c'", op[0]);
1033 return -1;
1034 }
1035 } else {
1036 if (strcmp(op, "++") == 0 ||
1037 strcmp(op, "--") == 0) {
1038 return 3;
1039 } else if (strcmp(op, ">>") == 0 ||
1040 strcmp(op, "<<") == 0) {
1041 return 8;
1042 } else if (strcmp(op, ">=") == 0 ||
1043 strcmp(op, "<=") == 0) {
1044 return 9;
1045 } else if (strcmp(op, "==") == 0 ||
1046 strcmp(op, "!=") == 0) {
1047 return 10;
1048 } else if (strcmp(op, "&&") == 0) {
1049 return 14;
1050 } else if (strcmp(op, "||") == 0) {
1051 return 15;
1052 } else {
1053 die("unknown op '%s'", op);
1054 return -1;
1055 }
1056 }
1057}
1058
1059static void set_op_prio(struct print_arg *arg)
1060{
1061
1062 /* single ops are the greatest */
1063 if (!arg->op.left || arg->op.left->type == PRINT_NULL) {
1064 arg->op.prio = 0;
1065 return;
1066 }
1067
1068 arg->op.prio = get_op_prio(arg->op.op);
1069}
1070
1071static enum event_type
1072process_op(struct event *event, struct print_arg *arg, char **tok)
1073{
1074 struct print_arg *left, *right = NULL;
1075 enum event_type type;
1076 char *token;
1077
1078 /* the op is passed in via tok */
1079 token = *tok;
1080
1081 if (arg->type == PRINT_OP && !arg->op.left) {
1082 /* handle single op */
1083 if (token[1]) {
1084 die("bad op token %s", token);
1085 return EVENT_ERROR;
1086 }
1087 switch (token[0]) {
1088 case '!':
1089 case '+':
1090 case '-':
1091 break;
1092 default:
1093 die("bad op token %s", token);
1094 return EVENT_ERROR;
1095 }
1096
1097 /* make an empty left */
1098 left = malloc_or_die(sizeof(*left));
1099 left->type = PRINT_NULL;
1100 arg->op.left = left;
1101
1102 right = malloc_or_die(sizeof(*right));
1103 arg->op.right = right;
1104
1105 type = process_arg(event, right, tok);
1106
1107 } else if (strcmp(token, "?") == 0) {
1108
1109 left = malloc_or_die(sizeof(*left));
1110 /* copy the top arg to the left */
1111 *left = *arg;
1112
1113 arg->type = PRINT_OP;
1114 arg->op.op = token;
1115 arg->op.left = left;
1116 arg->op.prio = 0;
1117
1118 type = process_cond(event, arg, tok);
1119
1120 } else if (strcmp(token, ">>") == 0 ||
1121 strcmp(token, "<<") == 0 ||
1122 strcmp(token, "&") == 0 ||
1123 strcmp(token, "|") == 0 ||
1124 strcmp(token, "&&") == 0 ||
1125 strcmp(token, "||") == 0 ||
1126 strcmp(token, "-") == 0 ||
1127 strcmp(token, "+") == 0 ||
1128 strcmp(token, "*") == 0 ||
1129 strcmp(token, "^") == 0 ||
1130 strcmp(token, "/") == 0 ||
1131 strcmp(token, "==") == 0 ||
1132 strcmp(token, "!=") == 0) {
1133
1134 left = malloc_or_die(sizeof(*left));
1135
1136 /* copy the top arg to the left */
1137 *left = *arg;
1138
1139 arg->type = PRINT_OP;
1140 arg->op.op = token;
1141 arg->op.left = left;
1142
1143 set_op_prio(arg);
1144
1145 right = malloc_or_die(sizeof(*right));
1146
1147 type = process_arg(event, right, tok);
1148
1149 arg->op.right = right;
1150
1151 } else {
1152 die("unknown op '%s'", token);
1153 /* the arg is now the left side */
1154 return EVENT_NONE;
1155 }
1156
1157
1158 if (type == EVENT_OP) {
1159 int prio;
1160
1161 /* higher prios need to be closer to the root */
1162 prio = get_op_prio(*tok);
1163
1164 if (prio > arg->op.prio)
1165 return process_op(event, arg, tok);
1166
1167 return process_op(event, right, tok);
1168 }
1169
1170 return type;
1171}
1172
1173static enum event_type
1174process_entry(struct event *event __unused, struct print_arg *arg,
1175 char **tok)
1176{
1177 enum event_type type;
1178 char *field;
1179 char *token;
1180
1181 if (read_expected(EVENT_OP, (char *)"->") < 0)
1182 return EVENT_ERROR;
1183
1184 if (read_expect_type(EVENT_ITEM, &token) < 0)
1185 goto fail;
1186 field = token;
1187
1188 arg->type = PRINT_FIELD;
1189 arg->field.name = field;
1190
1191 type = read_token(&token);
1192 *tok = token;
1193
1194 return type;
1195
1196fail:
1197 free_token(token);
1198 return EVENT_ERROR;
1199}
1200
1201static char *arg_eval (struct print_arg *arg);
1202
1203static long long arg_num_eval(struct print_arg *arg)
1204{
1205 long long left, right;
1206 long long val = 0;
1207
1208 switch (arg->type) {
1209 case PRINT_ATOM:
1210 val = strtoll(arg->atom.atom, NULL, 0);
1211 break;
1212 case PRINT_TYPE:
1213 val = arg_num_eval(arg->typecast.item);
1214 break;
1215 case PRINT_OP:
1216 switch (arg->op.op[0]) {
1217 case '|':
1218 left = arg_num_eval(arg->op.left);
1219 right = arg_num_eval(arg->op.right);
1220 if (arg->op.op[1])
1221 val = left || right;
1222 else
1223 val = left | right;
1224 break;
1225 case '&':
1226 left = arg_num_eval(arg->op.left);
1227 right = arg_num_eval(arg->op.right);
1228 if (arg->op.op[1])
1229 val = left && right;
1230 else
1231 val = left & right;
1232 break;
1233 case '<':
1234 left = arg_num_eval(arg->op.left);
1235 right = arg_num_eval(arg->op.right);
1236 switch (arg->op.op[1]) {
1237 case 0:
1238 val = left < right;
1239 break;
1240 case '<':
1241 val = left << right;
1242 break;
1243 case '=':
1244 val = left <= right;
1245 break;
1246 default:
1247 die("unknown op '%s'", arg->op.op);
1248 }
1249 break;
1250 case '>':
1251 left = arg_num_eval(arg->op.left);
1252 right = arg_num_eval(arg->op.right);
1253 switch (arg->op.op[1]) {
1254 case 0:
1255 val = left > right;
1256 break;
1257 case '>':
1258 val = left >> right;
1259 break;
1260 case '=':
1261 val = left >= right;
1262 break;
1263 default:
1264 die("unknown op '%s'", arg->op.op);
1265 }
1266 break;
1267 case '=':
1268 left = arg_num_eval(arg->op.left);
1269 right = arg_num_eval(arg->op.right);
1270
1271 if (arg->op.op[1] != '=')
1272 die("unknown op '%s'", arg->op.op);
1273
1274 val = left == right;
1275 break;
1276 case '!':
1277 left = arg_num_eval(arg->op.left);
1278 right = arg_num_eval(arg->op.right);
1279
1280 switch (arg->op.op[1]) {
1281 case '=':
1282 val = left != right;
1283 break;
1284 default:
1285 die("unknown op '%s'", arg->op.op);
1286 }
1287 break;
1288 default:
1289 die("unknown op '%s'", arg->op.op);
1290 }
1291 break;
1292
1293 case PRINT_NULL:
1294 case PRINT_FIELD ... PRINT_SYMBOL:
1295 case PRINT_STRING:
1296 default:
1297 die("invalid eval type %d", arg->type);
1298
1299 }
1300 return val;
1301}
1302
1303static char *arg_eval (struct print_arg *arg)
1304{
1305 long long val;
1306 static char buf[20];
1307
1308 switch (arg->type) {
1309 case PRINT_ATOM:
1310 return arg->atom.atom;
1311 case PRINT_TYPE:
1312 return arg_eval(arg->typecast.item);
1313 case PRINT_OP:
1314 val = arg_num_eval(arg);
1315 sprintf(buf, "%lld", val);
1316 return buf;
1317
1318 case PRINT_NULL:
1319 case PRINT_FIELD ... PRINT_SYMBOL:
1320 case PRINT_STRING:
1321 default:
1322 die("invalid eval type %d", arg->type);
1323 break;
1324 }
1325
1326 return NULL;
1327}
1328
1329static enum event_type
1330process_fields(struct event *event, struct print_flag_sym **list, char **tok)
1331{
1332 enum event_type type;
1333 struct print_arg *arg = NULL;
1334 struct print_flag_sym *field;
1335 char *token = NULL;
1336 char *value;
1337
1338 do {
1339 free_token(token);
1340 type = read_token_item(&token);
1341 if (test_type_token(type, token, EVENT_OP, (char *)"{"))
1342 break;
1343
1344 arg = malloc_or_die(sizeof(*arg));
1345
1346 free_token(token);
1347 type = process_arg(event, arg, &token);
1348 if (test_type_token(type, token, EVENT_DELIM, (char *)","))
1349 goto out_free;
1350
1351 field = malloc_or_die(sizeof(*field));
1352 memset(field, 0, sizeof(field));
1353
1354 value = arg_eval(arg);
1355 field->value = strdup(value);
1356
1357 free_token(token);
1358 type = process_arg(event, arg, &token);
1359 if (test_type_token(type, token, EVENT_OP, (char *)"}"))
1360 goto out_free;
1361
1362 value = arg_eval(arg);
1363 field->str = strdup(value);
1364 free_arg(arg);
1365 arg = NULL;
1366
1367 *list = field;
1368 list = &field->next;
1369
1370 free_token(token);
1371 type = read_token_item(&token);
1372 } while (type == EVENT_DELIM && strcmp(token, ",") == 0);
1373
1374 *tok = token;
1375 return type;
1376
1377out_free:
1378 free_arg(arg);
1379 free_token(token);
1380
1381 return EVENT_ERROR;
1382}
1383
1384static enum event_type
1385process_flags(struct event *event, struct print_arg *arg, char **tok)
1386{
1387 struct print_arg *field;
1388 enum event_type type;
1389 char *token;
1390
1391 memset(arg, 0, sizeof(*arg));
1392 arg->type = PRINT_FLAGS;
1393
1394 if (read_expected_item(EVENT_DELIM, (char *)"(") < 0)
1395 return EVENT_ERROR;
1396
1397 field = malloc_or_die(sizeof(*field));
1398
1399 type = process_arg(event, field, &token);
1400 if (test_type_token(type, token, EVENT_DELIM, (char *)","))
1401 goto out_free;
1402
1403 arg->flags.field = field;
1404
1405 type = read_token_item(&token);
1406 if (event_item_type(type)) {
1407 arg->flags.delim = token;
1408 type = read_token_item(&token);
1409 }
1410
1411 if (test_type_token(type, token, EVENT_DELIM, (char *)","))
1412 goto out_free;
1413
1414 type = process_fields(event, &arg->flags.flags, &token);
1415 if (test_type_token(type, token, EVENT_DELIM, (char *)")"))
1416 goto out_free;
1417
1418 free_token(token);
1419 type = read_token_item(tok);
1420 return type;
1421
1422out_free:
1423 free_token(token);
1424 return EVENT_ERROR;
1425}
1426
1427static enum event_type
1428process_symbols(struct event *event, struct print_arg *arg, char **tok)
1429{
1430 struct print_arg *field;
1431 enum event_type type;
1432 char *token;
1433
1434 memset(arg, 0, sizeof(*arg));
1435 arg->type = PRINT_SYMBOL;
1436
1437 if (read_expected_item(EVENT_DELIM, (char *)"(") < 0)
1438 return EVENT_ERROR;
1439
1440 field = malloc_or_die(sizeof(*field));
1441
1442 type = process_arg(event, field, &token);
1443 if (test_type_token(type, token, EVENT_DELIM, (char *)","))
1444 goto out_free;
1445
1446 arg->symbol.field = field;
1447
1448 type = process_fields(event, &arg->symbol.symbols, &token);
1449 if (test_type_token(type, token, EVENT_DELIM, (char *)")"))
1450 goto out_free;
1451
1452 free_token(token);
1453 type = read_token_item(tok);
1454 return type;
1455
1456out_free:
1457 free_token(token);
1458 return EVENT_ERROR;
1459}
1460
1461static enum event_type
1462process_paren(struct event *event, struct print_arg *arg, char **tok)
1463{
1464 struct print_arg *item_arg;
1465 enum event_type type;
1466 int ptr_cast = 0;
1467 char *token;
1468
1469 type = process_arg(event, arg, &token);
1470
1471 if (type == EVENT_ERROR)
1472 return EVENT_ERROR;
1473
1474 if (type == EVENT_OP) {
1475 /* handle the ptr casts */
1476 if (!strcmp(token, "*")) {
1477 /*
1478 * FIXME: should we zapp whitespaces before ')' ?
1479 * (may require a peek_token_item())
1480 */
1481 if (__peek_char() == ')') {
1482 ptr_cast = 1;
1483 free_token(token);
1484 type = read_token_item(&token);
1485 }
1486 }
1487 if (!ptr_cast) {
1488 type = process_op(event, arg, &token);
1489
1490 if (type == EVENT_ERROR)
1491 return EVENT_ERROR;
1492 }
1493 }
1494
1495 if (test_type_token(type, token, EVENT_DELIM, (char *)")")) {
1496 free_token(token);
1497 return EVENT_ERROR;
1498 }
1499
1500 free_token(token);
1501 type = read_token_item(&token);
1502
1503 /*
1504 * If the next token is an item or another open paren, then
1505 * this was a typecast.
1506 */
1507 if (event_item_type(type) ||
1508 (type == EVENT_DELIM && strcmp(token, "(") == 0)) {
1509
1510 /* make this a typecast and contine */
1511
1512 /* prevous must be an atom */
1513 if (arg->type != PRINT_ATOM)
1514 die("previous needed to be PRINT_ATOM");
1515
1516 item_arg = malloc_or_die(sizeof(*item_arg));
1517
1518 arg->type = PRINT_TYPE;
1519 if (ptr_cast) {
1520 char *old = arg->atom.atom;
1521
1522 arg->atom.atom = malloc_or_die(strlen(old + 3));
1523 sprintf(arg->atom.atom, "%s *", old);
1524 free(old);
1525 }
1526 arg->typecast.type = arg->atom.atom;
1527 arg->typecast.item = item_arg;
1528 type = process_arg_token(event, item_arg, &token, type);
1529
1530 }
1531
1532 *tok = token;
1533 return type;
1534}
1535
1536
1537static enum event_type
1538process_str(struct event *event __unused, struct print_arg *arg, char **tok)
1539{
1540 enum event_type type;
1541 char *token;
1542
1543 if (read_expected(EVENT_DELIM, (char *)"(") < 0)
1544 return EVENT_ERROR;
1545
1546 if (read_expect_type(EVENT_ITEM, &token) < 0)
1547 goto fail;
1548
1549 arg->type = PRINT_STRING;
1550 arg->string.string = token;
1551 arg->string.offset = -1;
1552
1553 if (read_expected(EVENT_DELIM, (char *)")") < 0)
1554 return EVENT_ERROR;
1555
1556 type = read_token(&token);
1557 *tok = token;
1558
1559 return type;
1560fail:
1561 free_token(token);
1562 return EVENT_ERROR;
1563}
1564
1565enum event_type
1566process_arg_token(struct event *event, struct print_arg *arg,
1567 char **tok, enum event_type type)
1568{
1569 char *token;
1570 char *atom;
1571
1572 token = *tok;
1573
1574 switch (type) {
1575 case EVENT_ITEM:
1576 if (strcmp(token, "REC") == 0) {
1577 free_token(token);
1578 type = process_entry(event, arg, &token);
1579 } else if (strcmp(token, "__print_flags") == 0) {
1580 free_token(token);
1581 type = process_flags(event, arg, &token);
1582 } else if (strcmp(token, "__print_symbolic") == 0) {
1583 free_token(token);
1584 type = process_symbols(event, arg, &token);
1585 } else if (strcmp(token, "__get_str") == 0) {
1586 free_token(token);
1587 type = process_str(event, arg, &token);
1588 } else {
1589 atom = token;
1590 /* test the next token */
1591 type = read_token_item(&token);
1592
1593 /* atoms can be more than one token long */
1594 while (type == EVENT_ITEM) {
1595 atom = realloc(atom, strlen(atom) + strlen(token) + 2);
1596 strcat(atom, " ");
1597 strcat(atom, token);
1598 free_token(token);
1599 type = read_token_item(&token);
1600 }
1601
1602 /* todo, test for function */
1603
1604 arg->type = PRINT_ATOM;
1605 arg->atom.atom = atom;
1606 }
1607 break;
1608 case EVENT_DQUOTE:
1609 case EVENT_SQUOTE:
1610 arg->type = PRINT_ATOM;
1611 arg->atom.atom = token;
1612 type = read_token_item(&token);
1613 break;
1614 case EVENT_DELIM:
1615 if (strcmp(token, "(") == 0) {
1616 free_token(token);
1617 type = process_paren(event, arg, &token);
1618 break;
1619 }
1620 case EVENT_OP:
1621 /* handle single ops */
1622 arg->type = PRINT_OP;
1623 arg->op.op = token;
1624 arg->op.left = NULL;
1625 type = process_op(event, arg, &token);
1626
1627 break;
1628
1629 case EVENT_ERROR ... EVENT_NEWLINE:
1630 default:
1631 die("unexpected type %d", type);
1632 }
1633 *tok = token;
1634
1635 return type;
1636}
1637
1638static int event_read_print_args(struct event *event, struct print_arg **list)
1639{
1640 enum event_type type;
1641 struct print_arg *arg;
1642 char *token;
1643 int args = 0;
1644
1645 do {
1646 arg = malloc_or_die(sizeof(*arg));
1647 memset(arg, 0, sizeof(*arg));
1648
1649 type = process_arg(event, arg, &token);
1650
1651 if (type == EVENT_ERROR) {
1652 free_arg(arg);
1653 return -1;
1654 }
1655
1656 *list = arg;
1657 args++;
1658
1659 if (type == EVENT_OP) {
1660 type = process_op(event, arg, &token);
1661 list = &arg->next;
1662 continue;
1663 }
1664
1665 if (type == EVENT_DELIM && strcmp(token, ",") == 0) {
1666 free_token(token);
1667 *list = arg;
1668 list = &arg->next;
1669 continue;
1670 }
1671 break;
1672 } while (type != EVENT_NONE);
1673
1674 if (type != EVENT_NONE)
1675 free_token(token);
1676
1677 return args;
1678}
1679
1680static int event_read_print(struct event *event)
1681{
1682 enum event_type type;
1683 char *token;
1684 int ret;
1685
1686 if (read_expected_item(EVENT_ITEM, (char *)"print") < 0)
1687 return -1;
1688
1689 if (read_expected(EVENT_ITEM, (char *)"fmt") < 0)
1690 return -1;
1691
1692 if (read_expected(EVENT_OP, (char *)":") < 0)
1693 return -1;
1694
1695 if (read_expect_type(EVENT_DQUOTE, &token) < 0)
1696 goto fail;
1697
1698 event->print_fmt.format = token;
1699 event->print_fmt.args = NULL;
1700
1701 /* ok to have no arg */
1702 type = read_token_item(&token);
1703
1704 if (type == EVENT_NONE)
1705 return 0;
1706
1707 if (test_type_token(type, token, EVENT_DELIM, (char *)","))
1708 goto fail;
1709
1710 free_token(token);
1711
1712 ret = event_read_print_args(event, &event->print_fmt.args);
1713 if (ret < 0)
1714 return -1;
1715
1716 return 0;
1717
1718 fail:
1719 free_token(token);
1720 return -1;
1721}
1722
1723static struct format_field *
1724find_common_field(struct event *event, const char *name)
1725{
1726 struct format_field *format;
1727
1728 for (format = event->format.common_fields;
1729 format; format = format->next) {
1730 if (strcmp(format->name, name) == 0)
1731 break;
1732 }
1733
1734 return format;
1735}
1736
1737static struct format_field *
1738find_field(struct event *event, const char *name)
1739{
1740 struct format_field *format;
1741
1742 for (format = event->format.fields;
1743 format; format = format->next) {
1744 if (strcmp(format->name, name) == 0)
1745 break;
1746 }
1747
1748 return format;
1749}
1750
1751static struct format_field *
1752find_any_field(struct event *event, const char *name)
1753{
1754 struct format_field *format;
1755
1756 format = find_common_field(event, name);
1757 if (format)
1758 return format;
1759 return find_field(event, name);
1760}
1761
1762static unsigned long long read_size(void *ptr, int size)
1763{
1764 switch (size) {
1765 case 1:
1766 return *(unsigned char *)ptr;
1767 case 2:
1768 return data2host2(ptr);
1769 case 4:
1770 return data2host4(ptr);
1771 case 8:
1772 return data2host8(ptr);
1773 default:
1774 /* BUG! */
1775 return 0;
1776 }
1777}
1778
1779unsigned long long
1780raw_field_value(struct event *event, const char *name, void *data)
1781{
1782 struct format_field *field;
1783
1784 field = find_any_field(event, name);
1785 if (!field)
1786 return 0ULL;
1787
1788 return read_size(data + field->offset, field->size);
1789}
1790
1791void *raw_field_ptr(struct event *event, const char *name, void *data)
1792{
1793 struct format_field *field;
1794
1795 field = find_any_field(event, name);
1796 if (!field)
1797 return NULL;
1798
1799 return data + field->offset;
1800}
1801
1802static int get_common_info(const char *type, int *offset, int *size)
1803{
1804 struct event *event;
1805 struct format_field *field;
1806
1807 /*
1808 * All events should have the same common elements.
1809 * Pick any event to find where the type is;
1810 */
1811 if (!event_list)
1812 die("no event_list!");
1813
1814 event = event_list;
1815 field = find_common_field(event, type);
1816 if (!field)
1817 die("field '%s' not found", type);
1818
1819 *offset = field->offset;
1820 *size = field->size;
1821
1822 return 0;
1823}
1824
1825int trace_parse_common_type(void *data)
1826{
1827 static int type_offset;
1828 static int type_size;
1829 int ret;
1830
1831 if (!type_size) {
1832 ret = get_common_info("common_type",
1833 &type_offset,
1834 &type_size);
1835 if (ret < 0)
1836 return ret;
1837 }
1838 return read_size(data + type_offset, type_size);
1839}
1840
1841static int parse_common_pid(void *data)
1842{
1843 static int pid_offset;
1844 static int pid_size;
1845 int ret;
1846
1847 if (!pid_size) {
1848 ret = get_common_info("common_pid",
1849 &pid_offset,
1850 &pid_size);
1851 if (ret < 0)
1852 return ret;
1853 }
1854
1855 return read_size(data + pid_offset, pid_size);
1856}
1857
1858struct event *trace_find_event(int id)
1859{
1860 struct event *event;
1861
1862 for (event = event_list; event; event = event->next) {
1863 if (event->id == id)
1864 break;
1865 }
1866 return event;
1867}
1868
1869static unsigned long long eval_num_arg(void *data, int size,
1870 struct event *event, struct print_arg *arg)
1871{
1872 unsigned long long val = 0;
1873 unsigned long long left, right;
1874
1875 switch (arg->type) {
1876 case PRINT_NULL:
1877 /* ?? */
1878 return 0;
1879 case PRINT_ATOM:
1880 return strtoull(arg->atom.atom, NULL, 0);
1881 case PRINT_FIELD:
1882 if (!arg->field.field) {
1883 arg->field.field = find_any_field(event, arg->field.name);
1884 if (!arg->field.field)
1885 die("field %s not found", arg->field.name);
1886 }
1887 /* must be a number */
1888 val = read_size(data + arg->field.field->offset,
1889 arg->field.field->size);
1890 break;
1891 case PRINT_FLAGS:
1892 case PRINT_SYMBOL:
1893 break;
1894 case PRINT_TYPE:
1895 return eval_num_arg(data, size, event, arg->typecast.item);
1896 case PRINT_STRING:
1897 return 0;
1898 break;
1899 case PRINT_OP:
1900 left = eval_num_arg(data, size, event, arg->op.left);
1901 right = eval_num_arg(data, size, event, arg->op.right);
1902 switch (arg->op.op[0]) {
1903 case '|':
1904 if (arg->op.op[1])
1905 val = left || right;
1906 else
1907 val = left | right;
1908 break;
1909 case '&':
1910 if (arg->op.op[1])
1911 val = left && right;
1912 else
1913 val = left & right;
1914 break;
1915 case '<':
1916 switch (arg->op.op[1]) {
1917 case 0:
1918 val = left < right;
1919 break;
1920 case '<':
1921 val = left << right;
1922 break;
1923 case '=':
1924 val = left <= right;
1925 break;
1926 default:
1927 die("unknown op '%s'", arg->op.op);
1928 }
1929 break;
1930 case '>':
1931 switch (arg->op.op[1]) {
1932 case 0:
1933 val = left > right;
1934 break;
1935 case '>':
1936 val = left >> right;
1937 break;
1938 case '=':
1939 val = left >= right;
1940 break;
1941 default:
1942 die("unknown op '%s'", arg->op.op);
1943 }
1944 break;
1945 case '=':
1946 if (arg->op.op[1] != '=')
1947 die("unknown op '%s'", arg->op.op);
1948 val = left == right;
1949 break;
1950 default:
1951 die("unknown op '%s'", arg->op.op);
1952 }
1953 break;
1954 default: /* not sure what to do there */
1955 return 0;
1956 }
1957 return val;
1958}
1959
1960struct flag {
1961 const char *name;
1962 unsigned long long value;
1963};
1964
1965static const struct flag flags[] = {
1966 { "HI_SOFTIRQ", 0 },
1967 { "TIMER_SOFTIRQ", 1 },
1968 { "NET_TX_SOFTIRQ", 2 },
1969 { "NET_RX_SOFTIRQ", 3 },
1970 { "BLOCK_SOFTIRQ", 4 },
1971 { "TASKLET_SOFTIRQ", 5 },
1972 { "SCHED_SOFTIRQ", 6 },
1973 { "HRTIMER_SOFTIRQ", 7 },
1974 { "RCU_SOFTIRQ", 8 },
1975
1976 { "HRTIMER_NORESTART", 0 },
1977 { "HRTIMER_RESTART", 1 },
1978};
1979
1980static unsigned long long eval_flag(const char *flag)
1981{
1982 int i;
1983
1984 /*
1985 * Some flags in the format files do not get converted.
1986 * If the flag is not numeric, see if it is something that
1987 * we already know about.
1988 */
1989 if (isdigit(flag[0]))
1990 return strtoull(flag, NULL, 0);
1991
1992 for (i = 0; i < (int)(sizeof(flags)/sizeof(flags[0])); i++)
1993 if (strcmp(flags[i].name, flag) == 0)
1994 return flags[i].value;
1995
1996 return 0;
1997}
1998
1999static void print_str_arg(void *data, int size,
2000 struct event *event, struct print_arg *arg)
2001{
2002 struct print_flag_sym *flag;
2003 unsigned long long val, fval;
2004 char *str;
2005 int print;
2006
2007 switch (arg->type) {
2008 case PRINT_NULL:
2009 /* ?? */
2010 return;
2011 case PRINT_ATOM:
2012 printf("%s", arg->atom.atom);
2013 return;
2014 case PRINT_FIELD:
2015 if (!arg->field.field) {
2016 arg->field.field = find_any_field(event, arg->field.name);
2017 if (!arg->field.field)
2018 die("field %s not found", arg->field.name);
2019 }
2020 str = malloc_or_die(arg->field.field->size + 1);
2021 memcpy(str, data + arg->field.field->offset,
2022 arg->field.field->size);
2023 str[arg->field.field->size] = 0;
2024 printf("%s", str);
2025 free(str);
2026 break;
2027 case PRINT_FLAGS:
2028 val = eval_num_arg(data, size, event, arg->flags.field);
2029 print = 0;
2030 for (flag = arg->flags.flags; flag; flag = flag->next) {
2031 fval = eval_flag(flag->value);
2032 if (!val && !fval) {
2033 printf("%s", flag->str);
2034 break;
2035 }
2036 if (fval && (val & fval) == fval) {
2037 if (print && arg->flags.delim)
2038 printf("%s", arg->flags.delim);
2039 printf("%s", flag->str);
2040 print = 1;
2041 val &= ~fval;
2042 }
2043 }
2044 break;
2045 case PRINT_SYMBOL:
2046 val = eval_num_arg(data, size, event, arg->symbol.field);
2047 for (flag = arg->symbol.symbols; flag; flag = flag->next) {
2048 fval = eval_flag(flag->value);
2049 if (val == fval) {
2050 printf("%s", flag->str);
2051 break;
2052 }
2053 }
2054 break;
2055
2056 case PRINT_TYPE:
2057 break;
2058 case PRINT_STRING: {
2059 int str_offset;
2060
2061 if (arg->string.offset == -1) {
2062 struct format_field *f;
2063
2064 f = find_any_field(event, arg->string.string);
2065 arg->string.offset = f->offset;
2066 }
2067 str_offset = *(int *)(data + arg->string.offset);
2068 str_offset &= 0xffff;
2069 printf("%s", ((char *)data) + str_offset);
2070 break;
2071 }
2072 case PRINT_OP:
2073 /*
2074 * The only op for string should be ? :
2075 */
2076 if (arg->op.op[0] != '?')
2077 return;
2078 val = eval_num_arg(data, size, event, arg->op.left);
2079 if (val)
2080 print_str_arg(data, size, event, arg->op.right->op.left);
2081 else
2082 print_str_arg(data, size, event, arg->op.right->op.right);
2083 break;
2084 default:
2085 /* well... */
2086 break;
2087 }
2088}
2089
2090static struct print_arg *make_bprint_args(char *fmt, void *data, int size, struct event *event)
2091{
2092 static struct format_field *field, *ip_field;
2093 struct print_arg *args, *arg, **next;
2094 unsigned long long ip, val;
2095 char *ptr;
2096 void *bptr;
2097
2098 if (!field) {
2099 field = find_field(event, "buf");
2100 if (!field)
2101 die("can't find buffer field for binary printk");
2102 ip_field = find_field(event, "ip");
2103 if (!ip_field)
2104 die("can't find ip field for binary printk");
2105 }
2106
2107 ip = read_size(data + ip_field->offset, ip_field->size);
2108
2109 /*
2110 * The first arg is the IP pointer.
2111 */
2112 args = malloc_or_die(sizeof(*args));
2113 arg = args;
2114 arg->next = NULL;
2115 next = &arg->next;
2116
2117 arg->type = PRINT_ATOM;
2118 arg->atom.atom = malloc_or_die(32);
2119 sprintf(arg->atom.atom, "%lld", ip);
2120
2121 /* skip the first "%pf : " */
2122 for (ptr = fmt + 6, bptr = data + field->offset;
2123 bptr < data + size && *ptr; ptr++) {
2124 int ls = 0;
2125
2126 if (*ptr == '%') {
2127 process_again:
2128 ptr++;
2129 switch (*ptr) {
2130 case '%':
2131 break;
2132 case 'l':
2133 ls++;
2134 goto process_again;
2135 case 'L':
2136 ls = 2;
2137 goto process_again;
2138 case '0' ... '9':
2139 goto process_again;
2140 case 'p':
2141 ls = 1;
2142 /* fall through */
2143 case 'd':
2144 case 'u':
2145 case 'x':
2146 case 'i':
2147 bptr = (void *)(((unsigned long)bptr + (long_size - 1)) &
2148 ~(long_size - 1));
2149 switch (ls) {
2150 case 0:
2151 case 1:
2152 ls = long_size;
2153 break;
2154 case 2:
2155 ls = 8;
2156 default:
2157 break;
2158 }
2159 val = read_size(bptr, ls);
2160 bptr += ls;
2161 arg = malloc_or_die(sizeof(*arg));
2162 arg->next = NULL;
2163 arg->type = PRINT_ATOM;
2164 arg->atom.atom = malloc_or_die(32);
2165 sprintf(arg->atom.atom, "%lld", val);
2166 *next = arg;
2167 next = &arg->next;
2168 break;
2169 case 's':
2170 arg = malloc_or_die(sizeof(*arg));
2171 arg->next = NULL;
2172 arg->type = PRINT_STRING;
2173 arg->string.string = strdup(bptr);
2174 bptr += strlen(bptr) + 1;
2175 *next = arg;
2176 next = &arg->next;
2177 default:
2178 break;
2179 }
2180 }
2181 }
2182
2183 return args;
2184}
2185
2186static void free_args(struct print_arg *args)
2187{
2188 struct print_arg *next;
2189
2190 while (args) {
2191 next = args->next;
2192
2193 if (args->type == PRINT_ATOM)
2194 free(args->atom.atom);
2195 else
2196 free(args->string.string);
2197 free(args);
2198 args = next;
2199 }
2200}
2201
2202static char *get_bprint_format(void *data, int size __unused, struct event *event)
2203{
2204 unsigned long long addr;
2205 static struct format_field *field;
2206 struct printk_map *printk;
2207 char *format;
2208 char *p;
2209
2210 if (!field) {
2211 field = find_field(event, "fmt");
2212 if (!field)
2213 die("can't find format field for binary printk");
2214 printf("field->offset = %d size=%d\n", field->offset, field->size);
2215 }
2216
2217 addr = read_size(data + field->offset, field->size);
2218
2219 printk = find_printk(addr);
2220 if (!printk) {
2221 format = malloc_or_die(45);
2222 sprintf(format, "%%pf : (NO FORMAT FOUND at %llx)\n",
2223 addr);
2224 return format;
2225 }
2226
2227 p = printk->printk;
2228 /* Remove any quotes. */
2229 if (*p == '"')
2230 p++;
2231 format = malloc_or_die(strlen(p) + 10);
2232 sprintf(format, "%s : %s", "%pf", p);
2233 /* remove ending quotes and new line since we will add one too */
2234 p = format + strlen(format) - 1;
2235 if (*p == '"')
2236 *p = 0;
2237
2238 p -= 2;
2239 if (strcmp(p, "\\n") == 0)
2240 *p = 0;
2241
2242 return format;
2243}
2244
2245static void pretty_print(void *data, int size, struct event *event)
2246{
2247 struct print_fmt *print_fmt = &event->print_fmt;
2248 struct print_arg *arg = print_fmt->args;
2249 struct print_arg *args = NULL;
2250 const char *ptr = print_fmt->format;
2251 unsigned long long val;
2252 struct func_map *func;
2253 const char *saveptr;
2254 char *bprint_fmt = NULL;
2255 char format[32];
2256 int show_func;
2257 int len;
2258 int ls;
2259
2260 if (event->flags & EVENT_FL_ISFUNC)
2261 ptr = " %pF <-- %pF";
2262
2263 if (event->flags & EVENT_FL_ISBPRINT) {
2264 bprint_fmt = get_bprint_format(data, size, event);
2265 args = make_bprint_args(bprint_fmt, data, size, event);
2266 arg = args;
2267 ptr = bprint_fmt;
2268 }
2269
2270 for (; *ptr; ptr++) {
2271 ls = 0;
2272 if (*ptr == '%') {
2273 saveptr = ptr;
2274 show_func = 0;
2275 cont_process:
2276 ptr++;
2277 switch (*ptr) {
2278 case '%':
2279 printf("%%");
2280 break;
2281 case 'l':
2282 ls++;
2283 goto cont_process;
2284 case 'L':
2285 ls = 2;
2286 goto cont_process;
2287 case 'z':
2288 case 'Z':
2289 case '0' ... '9':
2290 goto cont_process;
2291 case 'p':
2292 if (long_size == 4)
2293 ls = 1;
2294 else
2295 ls = 2;
2296
2297 if (*(ptr+1) == 'F' ||
2298 *(ptr+1) == 'f') {
2299 ptr++;
2300 show_func = *ptr;
2301 }
2302
2303 /* fall through */
2304 case 'd':
2305 case 'i':
2306 case 'x':
2307 case 'X':
2308 case 'u':
2309 if (!arg)
2310 die("no argument match");
2311
2312 len = ((unsigned long)ptr + 1) -
2313 (unsigned long)saveptr;
2314
2315 /* should never happen */
2316 if (len > 32)
2317 die("bad format!");
2318
2319 memcpy(format, saveptr, len);
2320 format[len] = 0;
2321
2322 val = eval_num_arg(data, size, event, arg);
2323 arg = arg->next;
2324
2325 if (show_func) {
2326 func = find_func(val);
2327 if (func) {
2328 printf("%s", func->func);
2329 if (show_func == 'F')
2330 printf("+0x%llx",
2331 val - func->addr);
2332 break;
2333 }
2334 }
2335 switch (ls) {
2336 case 0:
2337 printf(format, (int)val);
2338 break;
2339 case 1:
2340 printf(format, (long)val);
2341 break;
2342 case 2:
2343 printf(format, (long long)val);
2344 break;
2345 default:
2346 die("bad count (%d)", ls);
2347 }
2348 break;
2349 case 's':
2350 if (!arg)
2351 die("no matching argument");
2352
2353 print_str_arg(data, size, event, arg);
2354 arg = arg->next;
2355 break;
2356 default:
2357 printf(">%c<", *ptr);
2358
2359 }
2360 } else
2361 printf("%c", *ptr);
2362 }
2363
2364 if (args) {
2365 free_args(args);
2366 free(bprint_fmt);
2367 }
2368}
2369
2370static inline int log10_cpu(int nb)
2371{
2372 if (nb / 100)
2373 return 3;
2374 if (nb / 10)
2375 return 2;
2376 return 1;
2377}
2378
2379/* taken from Linux, written by Frederic Weisbecker */
2380static void print_graph_cpu(int cpu)
2381{
2382 int i;
2383 int log10_this = log10_cpu(cpu);
2384 int log10_all = log10_cpu(cpus);
2385
2386
2387 /*
2388 * Start with a space character - to make it stand out
2389 * to the right a bit when trace output is pasted into
2390 * email:
2391 */
2392 printf(" ");
2393
2394 /*
2395 * Tricky - we space the CPU field according to the max
2396 * number of online CPUs. On a 2-cpu system it would take
2397 * a maximum of 1 digit - on a 128 cpu system it would
2398 * take up to 3 digits:
2399 */
2400 for (i = 0; i < log10_all - log10_this; i++)
2401 printf(" ");
2402
2403 printf("%d) ", cpu);
2404}
2405
2406#define TRACE_GRAPH_PROCINFO_LENGTH 14
2407#define TRACE_GRAPH_INDENT 2
2408
2409static void print_graph_proc(int pid, const char *comm)
2410{
2411 /* sign + log10(MAX_INT) + '\0' */
2412 char pid_str[11];
2413 int spaces = 0;
2414 int len;
2415 int i;
2416
2417 sprintf(pid_str, "%d", pid);
2418
2419 /* 1 stands for the "-" character */
2420 len = strlen(comm) + strlen(pid_str) + 1;
2421
2422 if (len < TRACE_GRAPH_PROCINFO_LENGTH)
2423 spaces = TRACE_GRAPH_PROCINFO_LENGTH - len;
2424
2425 /* First spaces to align center */
2426 for (i = 0; i < spaces / 2; i++)
2427 printf(" ");
2428
2429 printf("%s-%s", comm, pid_str);
2430
2431 /* Last spaces to align center */
2432 for (i = 0; i < spaces - (spaces / 2); i++)
2433 printf(" ");
2434}
2435
2436static struct record *
2437get_return_for_leaf(int cpu, int cur_pid, unsigned long long cur_func,
2438 struct record *next)
2439{
2440 struct format_field *field;
2441 struct event *event;
2442 unsigned long val;
2443 int type;
2444 int pid;
2445
2446 type = trace_parse_common_type(next->data);
2447 event = trace_find_event(type);
2448 if (!event)
2449 return NULL;
2450
2451 if (!(event->flags & EVENT_FL_ISFUNCRET))
2452 return NULL;
2453
2454 pid = parse_common_pid(next->data);
2455 field = find_field(event, "func");
2456 if (!field)
2457 die("function return does not have field func");
2458
2459 val = read_size(next->data + field->offset, field->size);
2460
2461 if (cur_pid != pid || cur_func != val)
2462 return NULL;
2463
2464 /* this is a leaf, now advance the iterator */
2465 return trace_read_data(cpu);
2466}
2467
2468/* Signal a overhead of time execution to the output */
2469static void print_graph_overhead(unsigned long long duration)
2470{
2471 /* Non nested entry or return */
2472 if (duration == ~0ULL)
2473 return (void)printf(" ");
2474
2475 /* Duration exceeded 100 msecs */
2476 if (duration > 100000ULL)
2477 return (void)printf("! ");
2478
2479 /* Duration exceeded 10 msecs */
2480 if (duration > 10000ULL)
2481 return (void)printf("+ ");
2482
2483 printf(" ");
2484}
2485
2486static void print_graph_duration(unsigned long long duration)
2487{
2488 unsigned long usecs = duration / 1000;
2489 unsigned long nsecs_rem = duration % 1000;
2490 /* log10(ULONG_MAX) + '\0' */
2491 char msecs_str[21];
2492 char nsecs_str[5];
2493 int len;
2494 int i;
2495
2496 sprintf(msecs_str, "%lu", usecs);
2497
2498 /* Print msecs */
2499 len = printf("%lu", usecs);
2500
2501 /* Print nsecs (we don't want to exceed 7 numbers) */
2502 if (len < 7) {
2503 snprintf(nsecs_str, 8 - len, "%03lu", nsecs_rem);
2504 len += printf(".%s", nsecs_str);
2505 }
2506
2507 printf(" us ");
2508
2509 /* Print remaining spaces to fit the row's width */
2510 for (i = len; i < 7; i++)
2511 printf(" ");
2512
2513 printf("| ");
2514}
2515
2516static void
2517print_graph_entry_leaf(struct event *event, void *data, struct record *ret_rec)
2518{
2519 unsigned long long rettime, calltime;
2520 unsigned long long duration, depth;
2521 unsigned long long val;
2522 struct format_field *field;
2523 struct func_map *func;
2524 struct event *ret_event;
2525 int type;
2526 int i;
2527
2528 type = trace_parse_common_type(ret_rec->data);
2529 ret_event = trace_find_event(type);
2530
2531 field = find_field(ret_event, "rettime");
2532 if (!field)
2533 die("can't find rettime in return graph");
2534 rettime = read_size(ret_rec->data + field->offset, field->size);
2535
2536 field = find_field(ret_event, "calltime");
2537 if (!field)
2538 die("can't find rettime in return graph");
2539 calltime = read_size(ret_rec->data + field->offset, field->size);
2540
2541 duration = rettime - calltime;
2542
2543 /* Overhead */
2544 print_graph_overhead(duration);
2545
2546 /* Duration */
2547 print_graph_duration(duration);
2548
2549 field = find_field(event, "depth");
2550 if (!field)
2551 die("can't find depth in entry graph");
2552 depth = read_size(data + field->offset, field->size);
2553
2554 /* Function */
2555 for (i = 0; i < (int)(depth * TRACE_GRAPH_INDENT); i++)
2556 printf(" ");
2557
2558 field = find_field(event, "func");
2559 if (!field)
2560 die("can't find func in entry graph");
2561 val = read_size(data + field->offset, field->size);
2562 func = find_func(val);
2563
2564 if (func)
2565 printf("%s();", func->func);
2566 else
2567 printf("%llx();", val);
2568}
2569
2570static void print_graph_nested(struct event *event, void *data)
2571{
2572 struct format_field *field;
2573 unsigned long long depth;
2574 unsigned long long val;
2575 struct func_map *func;
2576 int i;
2577
2578 /* No overhead */
2579 print_graph_overhead(-1);
2580
2581 /* No time */
2582 printf(" | ");
2583
2584 field = find_field(event, "depth");
2585 if (!field)
2586 die("can't find depth in entry graph");
2587 depth = read_size(data + field->offset, field->size);
2588
2589 /* Function */
2590 for (i = 0; i < (int)(depth * TRACE_GRAPH_INDENT); i++)
2591 printf(" ");
2592
2593 field = find_field(event, "func");
2594 if (!field)
2595 die("can't find func in entry graph");
2596 val = read_size(data + field->offset, field->size);
2597 func = find_func(val);
2598
2599 if (func)
2600 printf("%s() {", func->func);
2601 else
2602 printf("%llx() {", val);
2603}
2604
2605static void
2606pretty_print_func_ent(void *data, int size, struct event *event,
2607 int cpu, int pid, const char *comm,
2608 unsigned long secs, unsigned long usecs)
2609{
2610 struct format_field *field;
2611 struct record *rec;
2612 void *copy_data;
2613 unsigned long val;
2614
2615 printf("%5lu.%06lu | ", secs, usecs);
2616
2617 print_graph_cpu(cpu);
2618 print_graph_proc(pid, comm);
2619
2620 printf(" | ");
2621
2622 field = find_field(event, "func");
2623 if (!field)
2624 die("function entry does not have func field");
2625
2626 val = read_size(data + field->offset, field->size);
2627
2628 /*
2629 * peek_data may unmap the data pointer. Copy it first.
2630 */
2631 copy_data = malloc_or_die(size);
2632 memcpy(copy_data, data, size);
2633 data = copy_data;
2634
2635 rec = trace_peek_data(cpu);
2636 if (rec) {
2637 rec = get_return_for_leaf(cpu, pid, val, rec);
2638 if (rec) {
2639 print_graph_entry_leaf(event, data, rec);
2640 goto out_free;
2641 }
2642 }
2643 print_graph_nested(event, data);
2644out_free:
2645 free(data);
2646}
2647
2648static void
2649pretty_print_func_ret(void *data, int size __unused, struct event *event,
2650 int cpu, int pid, const char *comm,
2651 unsigned long secs, unsigned long usecs)
2652{
2653 unsigned long long rettime, calltime;
2654 unsigned long long duration, depth;
2655 struct format_field *field;
2656 int i;
2657
2658 printf("%5lu.%06lu | ", secs, usecs);
2659
2660 print_graph_cpu(cpu);
2661 print_graph_proc(pid, comm);
2662
2663 printf(" | ");
2664
2665 field = find_field(event, "rettime");
2666 if (!field)
2667 die("can't find rettime in return graph");
2668 rettime = read_size(data + field->offset, field->size);
2669
2670 field = find_field(event, "calltime");
2671 if (!field)
2672 die("can't find calltime in return graph");
2673 calltime = read_size(data + field->offset, field->size);
2674
2675 duration = rettime - calltime;
2676
2677 /* Overhead */
2678 print_graph_overhead(duration);
2679
2680 /* Duration */
2681 print_graph_duration(duration);
2682
2683 field = find_field(event, "depth");
2684 if (!field)
2685 die("can't find depth in entry graph");
2686 depth = read_size(data + field->offset, field->size);
2687
2688 /* Function */
2689 for (i = 0; i < (int)(depth * TRACE_GRAPH_INDENT); i++)
2690 printf(" ");
2691
2692 printf("}");
2693}
2694
2695static void
2696pretty_print_func_graph(void *data, int size, struct event *event,
2697 int cpu, int pid, const char *comm,
2698 unsigned long secs, unsigned long usecs)
2699{
2700 if (event->flags & EVENT_FL_ISFUNCENT)
2701 pretty_print_func_ent(data, size, event,
2702 cpu, pid, comm, secs, usecs);
2703 else if (event->flags & EVENT_FL_ISFUNCRET)
2704 pretty_print_func_ret(data, size, event,
2705 cpu, pid, comm, secs, usecs);
2706 printf("\n");
2707}
2708
2709void print_event(int cpu, void *data, int size, unsigned long long nsecs,
2710 char *comm)
2711{
2712 struct event *event;
2713 unsigned long secs;
2714 unsigned long usecs;
2715 int type;
2716 int pid;
2717
2718 secs = nsecs / NSECS_PER_SEC;
2719 nsecs -= secs * NSECS_PER_SEC;
2720 usecs = nsecs / NSECS_PER_USEC;
2721
2722 type = trace_parse_common_type(data);
2723
2724 event = trace_find_event(type);
2725 if (!event) {
2726 printf("ug! no event found for type %d\n", type);
2727 return;
2728 }
2729
2730 pid = parse_common_pid(data);
2731
2732 if (event->flags & (EVENT_FL_ISFUNCENT | EVENT_FL_ISFUNCRET))
2733 return pretty_print_func_graph(data, size, event, cpu,
2734 pid, comm, secs, usecs);
2735
2736 printf("%16s-%-5d [%03d] %5lu.%09Lu: %s: ",
2737 comm, pid, cpu,
2738 secs, nsecs, event->name);
2739
2740 pretty_print(data, size, event);
2741 printf("\n");
2742}
2743
2744static void print_fields(struct print_flag_sym *field)
2745{
2746 printf("{ %s, %s }", field->value, field->str);
2747 if (field->next) {
2748 printf(", ");
2749 print_fields(field->next);
2750 }
2751}
2752
2753static void print_args(struct print_arg *args)
2754{
2755 int print_paren = 1;
2756
2757 switch (args->type) {
2758 case PRINT_NULL:
2759 printf("null");
2760 break;
2761 case PRINT_ATOM:
2762 printf("%s", args->atom.atom);
2763 break;
2764 case PRINT_FIELD:
2765 printf("REC->%s", args->field.name);
2766 break;
2767 case PRINT_FLAGS:
2768 printf("__print_flags(");
2769 print_args(args->flags.field);
2770 printf(", %s, ", args->flags.delim);
2771 print_fields(args->flags.flags);
2772 printf(")");
2773 break;
2774 case PRINT_SYMBOL:
2775 printf("__print_symbolic(");
2776 print_args(args->symbol.field);
2777 printf(", ");
2778 print_fields(args->symbol.symbols);
2779 printf(")");
2780 break;
2781 case PRINT_STRING:
2782 printf("__get_str(%s)", args->string.string);
2783 break;
2784 case PRINT_TYPE:
2785 printf("(%s)", args->typecast.type);
2786 print_args(args->typecast.item);
2787 break;
2788 case PRINT_OP:
2789 if (strcmp(args->op.op, ":") == 0)
2790 print_paren = 0;
2791 if (print_paren)
2792 printf("(");
2793 print_args(args->op.left);
2794 printf(" %s ", args->op.op);
2795 print_args(args->op.right);
2796 if (print_paren)
2797 printf(")");
2798 break;
2799 default:
2800 /* we should warn... */
2801 return;
2802 }
2803 if (args->next) {
2804 printf("\n");
2805 print_args(args->next);
2806 }
2807}
2808
2809static void parse_header_field(char *type,
2810 int *offset, int *size)
2811{
2812 char *token;
2813
2814 if (read_expected(EVENT_ITEM, (char *)"field") < 0)
2815 return;
2816 if (read_expected(EVENT_OP, (char *)":") < 0)
2817 return;
2818 /* type */
2819 if (read_expect_type(EVENT_ITEM, &token) < 0)
2820 return;
2821 free_token(token);
2822
2823 if (read_expected(EVENT_ITEM, type) < 0)
2824 return;
2825 if (read_expected(EVENT_OP, (char *)";") < 0)
2826 return;
2827 if (read_expected(EVENT_ITEM, (char *)"offset") < 0)
2828 return;
2829 if (read_expected(EVENT_OP, (char *)":") < 0)
2830 return;
2831 if (read_expect_type(EVENT_ITEM, &token) < 0)
2832 return;
2833 *offset = atoi(token);
2834 free_token(token);
2835 if (read_expected(EVENT_OP, (char *)";") < 0)
2836 return;
2837 if (read_expected(EVENT_ITEM, (char *)"size") < 0)
2838 return;
2839 if (read_expected(EVENT_OP, (char *)":") < 0)
2840 return;
2841 if (read_expect_type(EVENT_ITEM, &token) < 0)
2842 return;
2843 *size = atoi(token);
2844 free_token(token);
2845 if (read_expected(EVENT_OP, (char *)";") < 0)
2846 return;
2847 if (read_expect_type(EVENT_NEWLINE, &token) < 0)
2848 return;
2849 free_token(token);
2850}
2851
2852int parse_header_page(char *buf, unsigned long size)
2853{
2854 init_input_buf(buf, size);
2855
2856 parse_header_field((char *)"timestamp", &header_page_ts_offset,
2857 &header_page_ts_size);
2858 parse_header_field((char *)"commit", &header_page_size_offset,
2859 &header_page_size_size);
2860 parse_header_field((char *)"data", &header_page_data_offset,
2861 &header_page_data_size);
2862
2863 return 0;
2864}
2865
2866int parse_ftrace_file(char *buf, unsigned long size)
2867{
2868 struct format_field *field;
2869 struct print_arg *arg, **list;
2870 struct event *event;
2871 int ret;
2872
2873 init_input_buf(buf, size);
2874
2875 event = alloc_event();
2876 if (!event)
2877 return -ENOMEM;
2878
2879 event->flags |= EVENT_FL_ISFTRACE;
2880
2881 event->name = event_read_name();
2882 if (!event->name)
2883 die("failed to read ftrace event name");
2884
2885 if (strcmp(event->name, "function") == 0)
2886 event->flags |= EVENT_FL_ISFUNC;
2887
2888 else if (strcmp(event->name, "funcgraph_entry") == 0)
2889 event->flags |= EVENT_FL_ISFUNCENT;
2890
2891 else if (strcmp(event->name, "funcgraph_exit") == 0)
2892 event->flags |= EVENT_FL_ISFUNCRET;
2893
2894 else if (strcmp(event->name, "bprint") == 0)
2895 event->flags |= EVENT_FL_ISBPRINT;
2896
2897 event->id = event_read_id();
2898 if (event->id < 0)
2899 die("failed to read ftrace event id");
2900
2901 add_event(event);
2902
2903 ret = event_read_format(event);
2904 if (ret < 0)
2905 die("failed to read ftrace event format");
2906
2907 ret = event_read_print(event);
2908 if (ret < 0)
2909 die("failed to read ftrace event print fmt");
2910
2911 /*
2912 * The arguments for ftrace files are parsed by the fields.
2913 * Set up the fields as their arguments.
2914 */
2915 list = &event->print_fmt.args;
2916 for (field = event->format.fields; field; field = field->next) {
2917 arg = malloc_or_die(sizeof(*arg));
2918 memset(arg, 0, sizeof(*arg));
2919 *list = arg;
2920 list = &arg->next;
2921 arg->type = PRINT_FIELD;
2922 arg->field.name = field->name;
2923 arg->field.field = field;
2924 }
2925 return 0;
2926}
2927
2928int parse_event_file(char *buf, unsigned long size, char *system__unused __unused)
2929{
2930 struct event *event;
2931 int ret;
2932
2933 init_input_buf(buf, size);
2934
2935 event = alloc_event();
2936 if (!event)
2937 return -ENOMEM;
2938
2939 event->name = event_read_name();
2940 if (!event->name)
2941 die("failed to read event name");
2942
2943 event->id = event_read_id();
2944 if (event->id < 0)
2945 die("failed to read event id");
2946
2947 ret = event_read_format(event);
2948 if (ret < 0)
2949 die("failed to read event format");
2950
2951 ret = event_read_print(event);
2952 if (ret < 0)
2953 die("failed to read event print fmt");
2954
2955#define PRINT_ARGS 0
2956 if (PRINT_ARGS && event->print_fmt.args)
2957 print_args(event->print_fmt.args);
2958
2959 add_event(event);
2960 return 0;
2961}
2962
2963void parse_set_info(int nr_cpus, int long_sz)
2964{
2965 cpus = nr_cpus;
2966 long_size = long_sz;
2967}
diff --git a/tools/perf/util/trace-event-read.c b/tools/perf/util/trace-event-read.c
new file mode 100644
index 000000000000..1b5c847d2c22
--- /dev/null
+++ b/tools/perf/util/trace-event-read.c
@@ -0,0 +1,514 @@
1/*
2 * Copyright (C) 2009, Steven Rostedt <srostedt@redhat.com>
3 *
4 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; version 2 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 General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 *
19 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
20 */
21#define _LARGEFILE64_SOURCE
22
23#include <dirent.h>
24#include <stdio.h>
25#include <stdlib.h>
26#include <string.h>
27#include <getopt.h>
28#include <stdarg.h>
29#include <sys/types.h>
30#include <sys/stat.h>
31#include <sys/wait.h>
32#include <sys/mman.h>
33#include <pthread.h>
34#include <fcntl.h>
35#include <unistd.h>
36#include <ctype.h>
37#include <errno.h>
38
39#include "../perf.h"
40#include "util.h"
41#include "trace-event.h"
42
43static int input_fd;
44
45static int read_page;
46
47int file_bigendian;
48int host_bigendian;
49static int long_size;
50
51static unsigned long page_size;
52
53static int read_or_die(void *data, int size)
54{
55 int r;
56
57 r = read(input_fd, data, size);
58 if (r != size)
59 die("reading input file (size expected=%d received=%d)",
60 size, r);
61 return r;
62}
63
64static unsigned int read4(void)
65{
66 unsigned int data;
67
68 read_or_die(&data, 4);
69 return __data2host4(data);
70}
71
72static unsigned long long read8(void)
73{
74 unsigned long long data;
75
76 read_or_die(&data, 8);
77 return __data2host8(data);
78}
79
80static char *read_string(void)
81{
82 char buf[BUFSIZ];
83 char *str = NULL;
84 int size = 0;
85 int i;
86 int r;
87
88 for (;;) {
89 r = read(input_fd, buf, BUFSIZ);
90 if (r < 0)
91 die("reading input file");
92
93 if (!r)
94 die("no data");
95
96 for (i = 0; i < r; i++) {
97 if (!buf[i])
98 break;
99 }
100 if (i < r)
101 break;
102
103 if (str) {
104 size += BUFSIZ;
105 str = realloc(str, size);
106 if (!str)
107 die("malloc of size %d", size);
108 memcpy(str + (size - BUFSIZ), buf, BUFSIZ);
109 } else {
110 size = BUFSIZ;
111 str = malloc_or_die(size);
112 memcpy(str, buf, size);
113 }
114 }
115
116 /* trailing \0: */
117 i++;
118
119 /* move the file descriptor to the end of the string */
120 r = lseek(input_fd, -(r - i), SEEK_CUR);
121 if (r < 0)
122 die("lseek");
123
124 if (str) {
125 size += i;
126 str = realloc(str, size);
127 if (!str)
128 die("malloc of size %d", size);
129 memcpy(str + (size - i), buf, i);
130 } else {
131 size = i;
132 str = malloc_or_die(i);
133 memcpy(str, buf, i);
134 }
135
136 return str;
137}
138
139static void read_proc_kallsyms(void)
140{
141 unsigned int size;
142 char *buf;
143
144 size = read4();
145 if (!size)
146 return;
147
148 buf = malloc_or_die(size);
149 read_or_die(buf, size);
150
151 parse_proc_kallsyms(buf, size);
152
153 free(buf);
154}
155
156static void read_ftrace_printk(void)
157{
158 unsigned int size;
159 char *buf;
160
161 size = read4();
162 if (!size)
163 return;
164
165 buf = malloc_or_die(size);
166 read_or_die(buf, size);
167
168 parse_ftrace_printk(buf, size);
169
170 free(buf);
171}
172
173static void read_header_files(void)
174{
175 unsigned long long size;
176 char *header_page;
177 char *header_event;
178 char buf[BUFSIZ];
179
180 read_or_die(buf, 12);
181
182 if (memcmp(buf, "header_page", 12) != 0)
183 die("did not read header page");
184
185 size = read8();
186 header_page = malloc_or_die(size);
187 read_or_die(header_page, size);
188 parse_header_page(header_page, size);
189 free(header_page);
190
191 /*
192 * The size field in the page is of type long,
193 * use that instead, since it represents the kernel.
194 */
195 long_size = header_page_size_size;
196
197 read_or_die(buf, 13);
198 if (memcmp(buf, "header_event", 13) != 0)
199 die("did not read header event");
200
201 size = read8();
202 header_event = malloc_or_die(size);
203 read_or_die(header_event, size);
204 free(header_event);
205}
206
207static void read_ftrace_file(unsigned long long size)
208{
209 char *buf;
210
211 buf = malloc_or_die(size);
212 read_or_die(buf, size);
213 parse_ftrace_file(buf, size);
214 free(buf);
215}
216
217static void read_event_file(char *sys, unsigned long long size)
218{
219 char *buf;
220
221 buf = malloc_or_die(size);
222 read_or_die(buf, size);
223 parse_event_file(buf, size, sys);
224 free(buf);
225}
226
227static void read_ftrace_files(void)
228{
229 unsigned long long size;
230 int count;
231 int i;
232
233 count = read4();
234
235 for (i = 0; i < count; i++) {
236 size = read8();
237 read_ftrace_file(size);
238 }
239}
240
241static void read_event_files(void)
242{
243 unsigned long long size;
244 char *sys;
245 int systems;
246 int count;
247 int i,x;
248
249 systems = read4();
250
251 for (i = 0; i < systems; i++) {
252 sys = read_string();
253
254 count = read4();
255 for (x=0; x < count; x++) {
256 size = read8();
257 read_event_file(sys, size);
258 }
259 }
260}
261
262struct cpu_data {
263 unsigned long long offset;
264 unsigned long long size;
265 unsigned long long timestamp;
266 struct record *next;
267 char *page;
268 int cpu;
269 int index;
270 int page_size;
271};
272
273static struct cpu_data *cpu_data;
274
275static void update_cpu_data_index(int cpu)
276{
277 cpu_data[cpu].offset += page_size;
278 cpu_data[cpu].size -= page_size;
279 cpu_data[cpu].index = 0;
280}
281
282static void get_next_page(int cpu)
283{
284 off64_t save_seek;
285 off64_t ret;
286
287 if (!cpu_data[cpu].page)
288 return;
289
290 if (read_page) {
291 if (cpu_data[cpu].size <= page_size) {
292 free(cpu_data[cpu].page);
293 cpu_data[cpu].page = NULL;
294 return;
295 }
296
297 update_cpu_data_index(cpu);
298
299 /* other parts of the code may expect the pointer to not move */
300 save_seek = lseek64(input_fd, 0, SEEK_CUR);
301
302 ret = lseek64(input_fd, cpu_data[cpu].offset, SEEK_SET);
303 if (ret < 0)
304 die("failed to lseek");
305 ret = read(input_fd, cpu_data[cpu].page, page_size);
306 if (ret < 0)
307 die("failed to read page");
308
309 /* reset the file pointer back */
310 lseek64(input_fd, save_seek, SEEK_SET);
311
312 return;
313 }
314
315 munmap(cpu_data[cpu].page, page_size);
316 cpu_data[cpu].page = NULL;
317
318 if (cpu_data[cpu].size <= page_size)
319 return;
320
321 update_cpu_data_index(cpu);
322
323 cpu_data[cpu].page = mmap(NULL, page_size, PROT_READ, MAP_PRIVATE,
324 input_fd, cpu_data[cpu].offset);
325 if (cpu_data[cpu].page == MAP_FAILED)
326 die("failed to mmap cpu %d at offset 0x%llx",
327 cpu, cpu_data[cpu].offset);
328}
329
330static unsigned int type_len4host(unsigned int type_len_ts)
331{
332 if (file_bigendian)
333 return (type_len_ts >> 27) & ((1 << 5) - 1);
334 else
335 return type_len_ts & ((1 << 5) - 1);
336}
337
338static unsigned int ts4host(unsigned int type_len_ts)
339{
340 if (file_bigendian)
341 return type_len_ts & ((1 << 27) - 1);
342 else
343 return type_len_ts >> 5;
344}
345
346static int calc_index(void *ptr, int cpu)
347{
348 return (unsigned long)ptr - (unsigned long)cpu_data[cpu].page;
349}
350
351struct record *trace_peek_data(int cpu)
352{
353 struct record *data;
354 void *page = cpu_data[cpu].page;
355 int idx = cpu_data[cpu].index;
356 void *ptr = page + idx;
357 unsigned long long extend;
358 unsigned int type_len_ts;
359 unsigned int type_len;
360 unsigned int delta;
361 unsigned int length = 0;
362
363 if (cpu_data[cpu].next)
364 return cpu_data[cpu].next;
365
366 if (!page)
367 return NULL;
368
369 if (!idx) {
370 /* FIXME: handle header page */
371 if (header_page_ts_size != 8)
372 die("expected a long long type for timestamp");
373 cpu_data[cpu].timestamp = data2host8(ptr);
374 ptr += 8;
375 switch (header_page_size_size) {
376 case 4:
377 cpu_data[cpu].page_size = data2host4(ptr);
378 ptr += 4;
379 break;
380 case 8:
381 cpu_data[cpu].page_size = data2host8(ptr);
382 ptr += 8;
383 break;
384 default:
385 die("bad long size");
386 }
387 ptr = cpu_data[cpu].page + header_page_data_offset;
388 }
389
390read_again:
391 idx = calc_index(ptr, cpu);
392
393 if (idx >= cpu_data[cpu].page_size) {
394 get_next_page(cpu);
395 return trace_peek_data(cpu);
396 }
397
398 type_len_ts = data2host4(ptr);
399 ptr += 4;
400
401 type_len = type_len4host(type_len_ts);
402 delta = ts4host(type_len_ts);
403
404 switch (type_len) {
405 case RINGBUF_TYPE_PADDING:
406 if (!delta)
407 die("error, hit unexpected end of page");
408 length = data2host4(ptr);
409 ptr += 4;
410 length *= 4;
411 ptr += length;
412 goto read_again;
413
414 case RINGBUF_TYPE_TIME_EXTEND:
415 extend = data2host4(ptr);
416 ptr += 4;
417 extend <<= TS_SHIFT;
418 extend += delta;
419 cpu_data[cpu].timestamp += extend;
420 goto read_again;
421
422 case RINGBUF_TYPE_TIME_STAMP:
423 ptr += 12;
424 break;
425 case 0:
426 length = data2host4(ptr);
427 ptr += 4;
428 die("here! length=%d", length);
429 break;
430 default:
431 length = type_len * 4;
432 break;
433 }
434
435 cpu_data[cpu].timestamp += delta;
436
437 data = malloc_or_die(sizeof(*data));
438 memset(data, 0, sizeof(*data));
439
440 data->ts = cpu_data[cpu].timestamp;
441 data->size = length;
442 data->data = ptr;
443 ptr += length;
444
445 cpu_data[cpu].index = calc_index(ptr, cpu);
446 cpu_data[cpu].next = data;
447
448 return data;
449}
450
451struct record *trace_read_data(int cpu)
452{
453 struct record *data;
454
455 data = trace_peek_data(cpu);
456 cpu_data[cpu].next = NULL;
457
458 return data;
459}
460
461void trace_report(void)
462{
463 const char *input_file = "trace.info";
464 char buf[BUFSIZ];
465 char test[] = { 23, 8, 68 };
466 char *version;
467 int show_version = 0;
468 int show_funcs = 0;
469 int show_printk = 0;
470
471 input_fd = open(input_file, O_RDONLY);
472 if (input_fd < 0)
473 die("opening '%s'\n", input_file);
474
475 read_or_die(buf, 3);
476 if (memcmp(buf, test, 3) != 0)
477 die("not an trace data file");
478
479 read_or_die(buf, 7);
480 if (memcmp(buf, "tracing", 7) != 0)
481 die("not a trace file (missing tracing)");
482
483 version = read_string();
484 if (show_version)
485 printf("version = %s\n", version);
486 free(version);
487
488 read_or_die(buf, 1);
489 file_bigendian = buf[0];
490 host_bigendian = bigendian();
491
492 read_or_die(buf, 1);
493 long_size = buf[0];
494
495 page_size = read4();
496
497 read_header_files();
498
499 read_ftrace_files();
500 read_event_files();
501 read_proc_kallsyms();
502 read_ftrace_printk();
503
504 if (show_funcs) {
505 print_funcs();
506 return;
507 }
508 if (show_printk) {
509 print_printk();
510 return;
511 }
512
513 return;
514}
diff --git a/tools/perf/util/trace-event.h b/tools/perf/util/trace-event.h
new file mode 100644
index 000000000000..693f815c9429
--- /dev/null
+++ b/tools/perf/util/trace-event.h
@@ -0,0 +1,245 @@
1#ifndef _TRACE_EVENTS_H
2#define _TRACE_EVENTS_H
3
4#include "parse-events.h"
5
6#define __unused __attribute__((unused))
7
8
9#ifndef PAGE_MASK
10#define PAGE_MASK (page_size - 1)
11#endif
12
13enum {
14 RINGBUF_TYPE_PADDING = 29,
15 RINGBUF_TYPE_TIME_EXTEND = 30,
16 RINGBUF_TYPE_TIME_STAMP = 31,
17};
18
19#ifndef TS_SHIFT
20#define TS_SHIFT 27
21#endif
22
23#define NSECS_PER_SEC 1000000000ULL
24#define NSECS_PER_USEC 1000ULL
25
26enum format_flags {
27 FIELD_IS_ARRAY = 1,
28 FIELD_IS_POINTER = 2,
29};
30
31struct format_field {
32 struct format_field *next;
33 char *type;
34 char *name;
35 int offset;
36 int size;
37 unsigned long flags;
38};
39
40struct format {
41 int nr_common;
42 int nr_fields;
43 struct format_field *common_fields;
44 struct format_field *fields;
45};
46
47struct print_arg_atom {
48 char *atom;
49};
50
51struct print_arg_string {
52 char *string;
53 int offset;
54};
55
56struct print_arg_field {
57 char *name;
58 struct format_field *field;
59};
60
61struct print_flag_sym {
62 struct print_flag_sym *next;
63 char *value;
64 char *str;
65};
66
67struct print_arg_typecast {
68 char *type;
69 struct print_arg *item;
70};
71
72struct print_arg_flags {
73 struct print_arg *field;
74 char *delim;
75 struct print_flag_sym *flags;
76};
77
78struct print_arg_symbol {
79 struct print_arg *field;
80 struct print_flag_sym *symbols;
81};
82
83struct print_arg;
84
85struct print_arg_op {
86 char *op;
87 int prio;
88 struct print_arg *left;
89 struct print_arg *right;
90};
91
92struct print_arg_func {
93 char *name;
94 struct print_arg *args;
95};
96
97enum print_arg_type {
98 PRINT_NULL,
99 PRINT_ATOM,
100 PRINT_FIELD,
101 PRINT_FLAGS,
102 PRINT_SYMBOL,
103 PRINT_TYPE,
104 PRINT_STRING,
105 PRINT_OP,
106};
107
108struct print_arg {
109 struct print_arg *next;
110 enum print_arg_type type;
111 union {
112 struct print_arg_atom atom;
113 struct print_arg_field field;
114 struct print_arg_typecast typecast;
115 struct print_arg_flags flags;
116 struct print_arg_symbol symbol;
117 struct print_arg_func func;
118 struct print_arg_string string;
119 struct print_arg_op op;
120 };
121};
122
123struct print_fmt {
124 char *format;
125 struct print_arg *args;
126};
127
128struct event {
129 struct event *next;
130 char *name;
131 int id;
132 int flags;
133 struct format format;
134 struct print_fmt print_fmt;
135};
136
137enum {
138 EVENT_FL_ISFTRACE = 1,
139 EVENT_FL_ISPRINT = 2,
140 EVENT_FL_ISBPRINT = 4,
141 EVENT_FL_ISFUNC = 8,
142 EVENT_FL_ISFUNCENT = 16,
143 EVENT_FL_ISFUNCRET = 32,
144};
145
146struct record {
147 unsigned long long ts;
148 int size;
149 void *data;
150};
151
152struct record *trace_peek_data(int cpu);
153struct record *trace_read_data(int cpu);
154
155void parse_set_info(int nr_cpus, int long_sz);
156
157void trace_report(void);
158
159void *malloc_or_die(unsigned int size);
160
161void parse_cmdlines(char *file, int size);
162void parse_proc_kallsyms(char *file, unsigned int size);
163void parse_ftrace_printk(char *file, unsigned int size);
164
165void print_funcs(void);
166void print_printk(void);
167
168int parse_ftrace_file(char *buf, unsigned long size);
169int parse_event_file(char *buf, unsigned long size, char *system);
170void print_event(int cpu, void *data, int size, unsigned long long nsecs,
171 char *comm);
172
173extern int file_bigendian;
174extern int host_bigendian;
175
176int bigendian(void);
177
178static inline unsigned short __data2host2(unsigned short data)
179{
180 unsigned short swap;
181
182 if (host_bigendian == file_bigendian)
183 return data;
184
185 swap = ((data & 0xffULL) << 8) |
186 ((data & (0xffULL << 8)) >> 8);
187
188 return swap;
189}
190
191static inline unsigned int __data2host4(unsigned int data)
192{
193 unsigned int swap;
194
195 if (host_bigendian == file_bigendian)
196 return data;
197
198 swap = ((data & 0xffULL) << 24) |
199 ((data & (0xffULL << 8)) << 8) |
200 ((data & (0xffULL << 16)) >> 8) |
201 ((data & (0xffULL << 24)) >> 24);
202
203 return swap;
204}
205
206static inline unsigned long long __data2host8(unsigned long long data)
207{
208 unsigned long long swap;
209
210 if (host_bigendian == file_bigendian)
211 return data;
212
213 swap = ((data & 0xffULL) << 56) |
214 ((data & (0xffULL << 8)) << 40) |
215 ((data & (0xffULL << 16)) << 24) |
216 ((data & (0xffULL << 24)) << 8) |
217 ((data & (0xffULL << 32)) >> 8) |
218 ((data & (0xffULL << 40)) >> 24) |
219 ((data & (0xffULL << 48)) >> 40) |
220 ((data & (0xffULL << 56)) >> 56);
221
222 return swap;
223}
224
225#define data2host2(ptr) __data2host2(*(unsigned short *)ptr)
226#define data2host4(ptr) __data2host4(*(unsigned int *)ptr)
227#define data2host8(ptr) __data2host8(*(unsigned long long *)ptr)
228
229extern int header_page_ts_offset;
230extern int header_page_ts_size;
231extern int header_page_size_offset;
232extern int header_page_size_size;
233extern int header_page_data_offset;
234extern int header_page_data_size;
235
236int parse_header_page(char *buf, unsigned long size);
237int trace_parse_common_type(void *data);
238struct event *trace_find_event(int id);
239unsigned long long
240raw_field_value(struct event *event, const char *name, void *data);
241void *raw_field_ptr(struct event *event, const char *name, void *data);
242
243void read_tracing_data(struct perf_event_attr *pattrs, int nb_events);
244
245#endif /* _TRACE_EVENTS_H */
diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h
index 68fe157d72fb..9de2329dd44d 100644
--- a/tools/perf/util/util.h
+++ b/tools/perf/util/util.h
@@ -39,10 +39,6 @@
39/* Approximation of the length of the decimal representation of this type. */ 39/* Approximation of the length of the decimal representation of this type. */
40#define decimal_length(x) ((int)(sizeof(x) * 2.56 + 0.5) + 1) 40#define decimal_length(x) ((int)(sizeof(x) * 2.56 + 0.5) + 1)
41 41
42#if !defined(__APPLE__) && !defined(__FreeBSD__) && !defined(__USLC__) && !defined(_M_UNIX)
43#define _XOPEN_SOURCE 600 /* glibc2 and AIX 5.3L need 500, OpenBSD needs 600 for S_ISLNK() */
44#define _XOPEN_SOURCE_EXTENDED 1 /* AIX 5.3L needs this */
45#endif
46#define _ALL_SOURCE 1 42#define _ALL_SOURCE 1
47#define _GNU_SOURCE 1 43#define _GNU_SOURCE 1
48#define _BSD_SOURCE 1 44#define _BSD_SOURCE 1
@@ -83,6 +79,7 @@
83#include <inttypes.h> 79#include <inttypes.h>
84#include "../../../include/linux/magic.h" 80#include "../../../include/linux/magic.h"
85 81
82
86#ifndef NO_ICONV 83#ifndef NO_ICONV
87#include <iconv.h> 84#include <iconv.h>
88#endif 85#endif
@@ -310,6 +307,7 @@ static inline int has_extension(const char *filename, const char *ext)
310#undef isspace 307#undef isspace
311#undef isdigit 308#undef isdigit
312#undef isalpha 309#undef isalpha
310#undef isprint
313#undef isalnum 311#undef isalnum
314#undef tolower 312#undef tolower
315#undef toupper 313#undef toupper
diff --git a/tools/perf/util/values.c b/tools/perf/util/values.c
new file mode 100644
index 000000000000..1c15e39f99e3
--- /dev/null
+++ b/tools/perf/util/values.c
@@ -0,0 +1,230 @@
1#include <stdlib.h>
2
3#include "util.h"
4#include "values.h"
5
6void perf_read_values_init(struct perf_read_values *values)
7{
8 values->threads_max = 16;
9 values->pid = malloc(values->threads_max * sizeof(*values->pid));
10 values->tid = malloc(values->threads_max * sizeof(*values->tid));
11 values->value = malloc(values->threads_max * sizeof(*values->value));
12 if (!values->pid || !values->tid || !values->value)
13 die("failed to allocate read_values threads arrays");
14 values->threads = 0;
15
16 values->counters_max = 16;
17 values->counterrawid = malloc(values->counters_max
18 * sizeof(*values->counterrawid));
19 values->countername = malloc(values->counters_max
20 * sizeof(*values->countername));
21 if (!values->counterrawid || !values->countername)
22 die("failed to allocate read_values counters arrays");
23 values->counters = 0;
24}
25
26void perf_read_values_destroy(struct perf_read_values *values)
27{
28 int i;
29
30 if (!values->threads_max || !values->counters_max)
31 return;
32
33 for (i = 0; i < values->threads; i++)
34 free(values->value[i]);
35 free(values->pid);
36 free(values->tid);
37 free(values->counterrawid);
38 for (i = 0; i < values->counters; i++)
39 free(values->countername[i]);
40 free(values->countername);
41}
42
43static void perf_read_values__enlarge_threads(struct perf_read_values *values)
44{
45 values->threads_max *= 2;
46 values->pid = realloc(values->pid,
47 values->threads_max * sizeof(*values->pid));
48 values->tid = realloc(values->tid,
49 values->threads_max * sizeof(*values->tid));
50 values->value = realloc(values->value,
51 values->threads_max * sizeof(*values->value));
52 if (!values->pid || !values->tid || !values->value)
53 die("failed to enlarge read_values threads arrays");
54}
55
56static int perf_read_values__findnew_thread(struct perf_read_values *values,
57 u32 pid, u32 tid)
58{
59 int i;
60
61 for (i = 0; i < values->threads; i++)
62 if (values->pid[i] == pid && values->tid[i] == tid)
63 return i;
64
65 if (values->threads == values->threads_max)
66 perf_read_values__enlarge_threads(values);
67
68 i = values->threads++;
69 values->pid[i] = pid;
70 values->tid[i] = tid;
71 values->value[i] = malloc(values->counters_max * sizeof(**values->value));
72 if (!values->value[i])
73 die("failed to allocate read_values counters array");
74
75 return i;
76}
77
78static void perf_read_values__enlarge_counters(struct perf_read_values *values)
79{
80 int i;
81
82 values->counters_max *= 2;
83 values->counterrawid = realloc(values->counterrawid,
84 values->counters_max * sizeof(*values->counterrawid));
85 values->countername = realloc(values->countername,
86 values->counters_max * sizeof(*values->countername));
87 if (!values->counterrawid || !values->countername)
88 die("failed to enlarge read_values counters arrays");
89
90 for (i = 0; i < values->threads; i++) {
91 values->value[i] = realloc(values->value[i],
92 values->counters_max * sizeof(**values->value));
93 if (!values->value[i])
94 die("failed to enlarge read_values counters arrays");
95 }
96}
97
98static int perf_read_values__findnew_counter(struct perf_read_values *values,
99 u64 rawid, const char *name)
100{
101 int i;
102
103 for (i = 0; i < values->counters; i++)
104 if (values->counterrawid[i] == rawid)
105 return i;
106
107 if (values->counters == values->counters_max)
108 perf_read_values__enlarge_counters(values);
109
110 i = values->counters++;
111 values->counterrawid[i] = rawid;
112 values->countername[i] = strdup(name);
113
114 return i;
115}
116
117void perf_read_values_add_value(struct perf_read_values *values,
118 u32 pid, u32 tid,
119 u64 rawid, const char *name, u64 value)
120{
121 int tindex, cindex;
122
123 tindex = perf_read_values__findnew_thread(values, pid, tid);
124 cindex = perf_read_values__findnew_counter(values, rawid, name);
125
126 values->value[tindex][cindex] = value;
127}
128
129static void perf_read_values__display_pretty(FILE *fp,
130 struct perf_read_values *values)
131{
132 int i, j;
133 int pidwidth, tidwidth;
134 int *counterwidth;
135
136 counterwidth = malloc(values->counters * sizeof(*counterwidth));
137 if (!counterwidth)
138 die("failed to allocate counterwidth array");
139 tidwidth = 3;
140 pidwidth = 3;
141 for (j = 0; j < values->counters; j++)
142 counterwidth[j] = strlen(values->countername[j]);
143 for (i = 0; i < values->threads; i++) {
144 int width;
145
146 width = snprintf(NULL, 0, "%d", values->pid[i]);
147 if (width > pidwidth)
148 pidwidth = width;
149 width = snprintf(NULL, 0, "%d", values->tid[i]);
150 if (width > tidwidth)
151 tidwidth = width;
152 for (j = 0; j < values->counters; j++) {
153 width = snprintf(NULL, 0, "%Lu", values->value[i][j]);
154 if (width > counterwidth[j])
155 counterwidth[j] = width;
156 }
157 }
158
159 fprintf(fp, "# %*s %*s", pidwidth, "PID", tidwidth, "TID");
160 for (j = 0; j < values->counters; j++)
161 fprintf(fp, " %*s", counterwidth[j], values->countername[j]);
162 fprintf(fp, "\n");
163
164 for (i = 0; i < values->threads; i++) {
165 fprintf(fp, " %*d %*d", pidwidth, values->pid[i],
166 tidwidth, values->tid[i]);
167 for (j = 0; j < values->counters; j++)
168 fprintf(fp, " %*Lu",
169 counterwidth[j], values->value[i][j]);
170 fprintf(fp, "\n");
171 }
172}
173
174static void perf_read_values__display_raw(FILE *fp,
175 struct perf_read_values *values)
176{
177 int width, pidwidth, tidwidth, namewidth, rawwidth, countwidth;
178 int i, j;
179
180 tidwidth = 3; /* TID */
181 pidwidth = 3; /* PID */
182 namewidth = 4; /* "Name" */
183 rawwidth = 3; /* "Raw" */
184 countwidth = 5; /* "Count" */
185
186 for (i = 0; i < values->threads; i++) {
187 width = snprintf(NULL, 0, "%d", values->pid[i]);
188 if (width > pidwidth)
189 pidwidth = width;
190 width = snprintf(NULL, 0, "%d", values->tid[i]);
191 if (width > tidwidth)
192 tidwidth = width;
193 }
194 for (j = 0; j < values->counters; j++) {
195 width = strlen(values->countername[j]);
196 if (width > namewidth)
197 namewidth = width;
198 width = snprintf(NULL, 0, "%llx", values->counterrawid[j]);
199 if (width > rawwidth)
200 rawwidth = width;
201 }
202 for (i = 0; i < values->threads; i++) {
203 for (j = 0; j < values->counters; j++) {
204 width = snprintf(NULL, 0, "%Lu", values->value[i][j]);
205 if (width > countwidth)
206 countwidth = width;
207 }
208 }
209
210 fprintf(fp, "# %*s %*s %*s %*s %*s\n",
211 pidwidth, "PID", tidwidth, "TID",
212 namewidth, "Name", rawwidth, "Raw",
213 countwidth, "Count");
214 for (i = 0; i < values->threads; i++)
215 for (j = 0; j < values->counters; j++)
216 fprintf(fp, " %*d %*d %*s %*llx %*Lu\n",
217 pidwidth, values->pid[i],
218 tidwidth, values->tid[i],
219 namewidth, values->countername[j],
220 rawwidth, values->counterrawid[j],
221 countwidth, values->value[i][j]);
222}
223
224void perf_read_values_display(FILE *fp, struct perf_read_values *values, int raw)
225{
226 if (raw)
227 perf_read_values__display_raw(fp, values);
228 else
229 perf_read_values__display_pretty(fp, values);
230}
diff --git a/tools/perf/util/values.h b/tools/perf/util/values.h
new file mode 100644
index 000000000000..cadf8cf2a590
--- /dev/null
+++ b/tools/perf/util/values.h
@@ -0,0 +1,27 @@
1#ifndef _PERF_VALUES_H
2#define _PERF_VALUES_H
3
4#include "types.h"
5
6struct perf_read_values {
7 int threads;
8 int threads_max;
9 u32 *pid, *tid;
10 int counters;
11 int counters_max;
12 u64 *counterrawid;
13 char **countername;
14 u64 **value;
15};
16
17void perf_read_values_init(struct perf_read_values *values);
18void perf_read_values_destroy(struct perf_read_values *values);
19
20void perf_read_values_add_value(struct perf_read_values *values,
21 u32 pid, u32 tid,
22 u64 rawid, const char *name, u64 value);
23
24void perf_read_values_display(FILE *fp, struct perf_read_values *values,
25 int raw);
26
27#endif /* _PERF_VALUES_H */