aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2009-09-11 23:35:13 -0400
committerDavid S. Miller <davem@davemloft.net>2009-09-11 23:35:13 -0400
commitcabc5c0f7fa1342049042d6e147db5a73773955b (patch)
tree2be09ae1777d580c7dfe05d6d5b76e57281ec447 /tools/perf
parentb73d884756303316ead4cd7dad51236b2a515a1a (diff)
parent86d710146fb9975f04c505ec78caa43d227c1018 (diff)
Merge branch 'master' of /home/davem/src/GIT/linux-2.6/
Conflicts: arch/sparc/Kconfig
Diffstat (limited to 'tools/perf')
-rw-r--r--tools/perf/Documentation/perf-record.txt4
-rw-r--r--tools/perf/Documentation/perf-report.txt13
-rw-r--r--tools/perf/Makefile39
-rw-r--r--tools/perf/builtin-annotate.c472
-rw-r--r--tools/perf/builtin-help.c1
-rw-r--r--tools/perf/builtin-record.c38
-rw-r--r--tools/perf/builtin-report.c719
-rw-r--r--tools/perf/builtin-stat.c239
-rw-r--r--tools/perf/builtin-top.c66
-rw-r--r--tools/perf/builtin-trace.c297
-rw-r--r--tools/perf/builtin.h1
-rw-r--r--tools/perf/perf.c1
-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.h96
-rw-r--r--tools/perf/util/exec_cmd.c1
-rw-r--r--tools/perf/util/header.c37
-rw-r--r--tools/perf/util/header.h4
-rw-r--r--tools/perf/util/map.c97
-rw-r--r--tools/perf/util/module.c4
-rw-r--r--tools/perf/util/parse-events.c147
-rw-r--r--tools/perf/util/parse-events.h17
-rw-r--r--tools/perf/util/parse-options.c22
-rw-r--r--tools/perf/util/path.c25
-rw-r--r--tools/perf/util/run-command.c6
-rw-r--r--tools/perf/util/symbol.c199
-rw-r--r--tools/perf/util/symbol.h14
-rw-r--r--tools/perf/util/thread.c175
-rw-r--r--tools/perf/util/thread.h21
-rw-r--r--tools/perf/util/trace-event-info.c539
-rw-r--r--tools/perf/util/trace-event-parse.c2942
-rw-r--r--tools/perf/util/trace-event-read.c512
-rw-r--r--tools/perf/util/trace-event.h240
-rw-r--r--tools/perf/util/util.h6
-rw-r--r--tools/perf/util/values.c230
-rw-r--r--tools/perf/util/values.h27
43 files changed, 6051 insertions, 1351 deletions
diff --git a/tools/perf/Documentation/perf-record.txt b/tools/perf/Documentation/perf-record.txt
index 6be696b0a2b..0ff23de9e45 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 e72e9311078..59f0b846cd7 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/Makefile b/tools/perf/Makefile
index c045b4271e5..9f8d207a91b 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)
@@ -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,6 +366,13 @@ 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
340 376
341BUILTIN_OBJS += builtin-annotate.o 377BUILTIN_OBJS += builtin-annotate.o
342BUILTIN_OBJS += builtin-help.o 378BUILTIN_OBJS += builtin-help.o
@@ -345,6 +381,7 @@ BUILTIN_OBJS += builtin-record.o
345BUILTIN_OBJS += builtin-report.o 381BUILTIN_OBJS += builtin-report.o
346BUILTIN_OBJS += builtin-stat.o 382BUILTIN_OBJS += builtin-stat.o
347BUILTIN_OBJS += builtin-top.o 383BUILTIN_OBJS += builtin-top.o
384BUILTIN_OBJS += builtin-trace.o
348 385
349PERFLIBS = $(LIB_FILE) 386PERFLIBS = $(LIB_FILE)
350 387
diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c
index 5e17de984dc..043d85b7e25 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",
@@ -878,7 +511,7 @@ process_sample_event(event_t *event, unsigned long offset, unsigned long head)
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_EVENT_MISC_USER) {
884 517
@@ -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_EVENT_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_EVENT_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_EVENT_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_EVENT_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_EVENT_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_EVENT_FORK, skipping event.\n");
993 return -1; 631 return -1;
994 } 632 }
995 total_fork++; 633 total_fork++;
@@ -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 2599d86a733..4fb8734a796 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 89a5ddcd1de..99a12fe86e9 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,7 +45,6 @@ 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;
@@ -62,24 +64,6 @@ static int file_new = 1;
62 64
63struct perf_header *header; 65struct perf_header *header;
64 66
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 { 67struct mmap_data {
84 int counter; 68 int counter;
85 void *base; 69 void *base;
@@ -419,8 +403,11 @@ static void create_counter(int counter, int cpu, pid_t pid)
419 if (call_graph) 403 if (call_graph)
420 attr->sample_type |= PERF_SAMPLE_CALLCHAIN; 404 attr->sample_type |= PERF_SAMPLE_CALLCHAIN;
421 405
422 if (raw_samples) 406 if (raw_samples) {
407 attr->sample_type |= PERF_SAMPLE_TIME;
423 attr->sample_type |= PERF_SAMPLE_RAW; 408 attr->sample_type |= PERF_SAMPLE_RAW;
409 attr->sample_type |= PERF_SAMPLE_CPU;
410 }
424 411
425 attr->mmap = track; 412 attr->mmap = track;
426 attr->comm = track; 413 attr->comm = track;
@@ -563,6 +550,17 @@ static int __cmd_record(int argc, const char **argv)
563 else 550 else
564 header = perf_header__new(); 551 header = perf_header__new();
565 552
553
554 if (raw_samples) {
555 read_tracing_data(attrs, nr_counters);
556 } else {
557 for (i = 0; i < nr_counters; i++) {
558 if (attrs[i].sample_type & PERF_SAMPLE_RAW) {
559 read_tracing_data(attrs, nr_counters);
560 break;
561 }
562 }
563 }
566 atexit(atexit_header); 564 atexit(atexit_header);
567 565
568 if (!system_wide) { 566 if (!system_wide) {
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
index 8b2ec882e6e..cdf9a8d27bb 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_EVENT_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",
@@ -1572,7 +1166,7 @@ process_sample_event(event_t *event, unsigned long offset, unsigned long head)
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_EVENT_MISC_USER) {
1578 1172
@@ -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_EVENT_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_EVENT_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_EVENT_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_EVENT_COMM, skipping event.\n");
1651 return -1; 1249 return -1;
1652 } 1250 }
1653 total_comm++; 1251 total_comm++;
@@ -1658,10 +1256,13 @@ 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_EVENT_%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_EVENT_FORK ? "FORK" : "EXIT",
@@ -1679,7 +1280,7 @@ process_task_event(event_t *event, unsigned long offset, unsigned long head)
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_EVENT_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_EVENT_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_counter_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_EVENT_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,
@@ -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-stat.c b/tools/perf/builtin-stat.c
index b4b06c7903e..61b828236c1 100644
--- a/tools/perf/builtin-stat.c
+++ b/tools/perf/builtin-stat.c
@@ -42,6 +42,8 @@
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>
@@ -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,26 +74,56 @@ 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];
80static u64 runtime_cycles[MAX_RUN];
81 78
82static u64 event_res[MAX_RUN][MAX_COUNTERS][3]; 79struct stats
83static u64 event_scaled[MAX_RUN][MAX_COUNTERS]; 80{
81 double n, mean, M2;
82};
84 83
85static u64 event_res_avg[MAX_COUNTERS][3]; 84static void update_stats(struct stats *stats, u64 val)
86static u64 event_res_noise[MAX_COUNTERS][3]; 85{
86 double delta;
87 87
88static u64 event_scaled_avg[MAX_COUNTERS]; 88 stats->n++;
89 delta = val - stats->mean;
90 stats->mean += delta / stats->n;
91 stats->M2 += delta*(val - stats->mean);
92}
89 93
90static u64 runtime_nsecs_avg; 94static double avg_stats(struct stats *stats)
91static u64 runtime_nsecs_noise; 95{
96 return stats->mean;
97}
92 98
93static u64 walltime_nsecs_avg; 99/*
94static u64 walltime_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;
119
120 return sqrt(variance_mean);
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 && \
@@ -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,38 @@ 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 fprintf(stderr, " %14.0f %-24s", avg, event_name(counter));
305 342
306 if (runtime_cycles_avg && 343 if (MATCH_EVENT(HARDWARE, HW_INSTRUCTIONS, counter)) {
307 MATCH_EVENT(HARDWARE, HW_INSTRUCTIONS, counter)) {
308 fprintf(stderr, " # %10.3f IPC ", 344 fprintf(stderr, " # %10.3f IPC ",
309 (double)count[0] / (double)runtime_cycles_avg); 345 avg / avg_stats(&runtime_cycles_stats));
310 } else { 346 } else {
311 if (runtime_nsecs_avg) { 347 fprintf(stderr, " # %10.3f M/sec",
312 fprintf(stderr, " # %10.3f M/sec", 348 1000.0 * avg / avg_stats(&runtime_nsecs_stats));
313 (double)count[0]/runtime_nsecs_avg*1000.0);
314 }
315 } 349 }
316 print_noise(count, noise);
317} 350}
318 351
319/* 352/*
@@ -321,12 +354,8 @@ static void abs_printout(int counter, u64 *count, u64 *noise)
321 */ 354 */
322static void print_counter(int counter) 355static void print_counter(int counter)
323{ 356{
324 u64 *count, *noise; 357 double avg = avg_stats(&event_res_stats[counter][0]);
325 int scaled; 358 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 359
331 if (scaled == -1) { 360 if (scaled == -1) {
332 fprintf(stderr, " %14s %-24s\n", 361 fprintf(stderr, " %14s %-24s\n",
@@ -335,110 +364,29 @@ static void print_counter(int counter)
335 } 364 }
336 365
337 if (nsec_counter(counter)) 366 if (nsec_counter(counter))
338 nsec_printout(counter, count, noise); 367 nsec_printout(counter, avg);
339 else 368 else
340 abs_printout(counter, count, noise); 369 abs_printout(counter, avg);
341
342 if (scaled)
343 fprintf(stderr, " (scaled from %.2f%%)",
344 (double) count[2] / count[1] * 100);
345
346 fprintf(stderr, "\n");
347}
348 370
349/* 371 print_noise(counter, avg);
350 * normalize_noise noise values down to stddev:
351 */
352static void normalize_noise(u64 *val)
353{
354 double res;
355 372
356 res = (double)*val / (run_count * sqrt((double)run_count)); 373 if (scaled) {
374 double avg_enabled, avg_running;
357 375
358 *val = (u64)res; 376 avg_enabled = avg_stats(&event_res_stats[counter][1]);
359} 377 avg_running = avg_stats(&event_res_stats[counter][2]);
360 378
361static void update_avg(const char *name, int idx, u64 *avg, u64 *val) 379 fprintf(stderr, " (scaled from %.2f%%)",
362{ 380 100 * avg_running / avg_enabled);
363 *avg += *val;
364
365 if (verbose > 1)
366 fprintf(stderr, "debug: %20s[%d]: %Ld\n", name, idx, *val);
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 } 381 }
424 382
425 normalize_noise(&runtime_nsecs_noise); 383 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} 384}
435 385
436static void print_stat(int argc, const char **argv) 386static void print_stat(int argc, const char **argv)
437{ 387{
438 int i, counter; 388 int i, counter;
439 389
440 calc_avg();
441
442 fflush(stdout); 390 fflush(stdout);
443 391
444 fprintf(stderr, "\n"); 392 fprintf(stderr, "\n");
@@ -457,10 +405,11 @@ static void print_stat(int argc, const char **argv)
457 405
458 fprintf(stderr, "\n"); 406 fprintf(stderr, "\n");
459 fprintf(stderr, " %14.9f seconds time elapsed", 407 fprintf(stderr, " %14.9f seconds time elapsed",
460 (double)walltime_nsecs_avg/1e9); 408 avg_stats(&walltime_nsecs_stats)/1e9);
461 if (run_count > 1) { 409 if (run_count > 1) {
462 fprintf(stderr, " ( +- %7.3f%% )", 410 fprintf(stderr, " ( +- %7.3f%% )",
463 100.0*(double)walltime_nsecs_noise/(double)walltime_nsecs_avg); 411 100*stddev_stats(&walltime_nsecs_stats) /
412 avg_stats(&walltime_nsecs_stats));
464 } 413 }
465 fprintf(stderr, "\n\n"); 414 fprintf(stderr, "\n\n");
466} 415}
@@ -515,7 +464,7 @@ int cmd_stat(int argc, const char **argv, const char *prefix __used)
515 PARSE_OPT_STOP_AT_NON_OPTION); 464 PARSE_OPT_STOP_AT_NON_OPTION);
516 if (!argc) 465 if (!argc)
517 usage_with_options(stat_usage, options); 466 usage_with_options(stat_usage, options);
518 if (run_count <= 0 || run_count > MAX_RUN) 467 if (run_count <= 0)
519 usage_with_options(stat_usage, options); 468 usage_with_options(stat_usage, options);
520 469
521 /* Set attrs and nr_counters if no event is selected and !null_run */ 470 /* Set attrs and nr_counters if no event is selected and !null_run */
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c
index 7de28ce9ca2..4002ccb3675 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);
@@ -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;
@@ -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 00000000000..914ab366e36
--- /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_EVENT_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_EVENT_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_EVENT_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_EVENT_MISC_CPUMODE_MASK;
102
103 if (cpumode == PERF_EVENT_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_EVENT_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_EVENT_MMAP ... PERF_EVENT_LOST:
150 return 0;
151
152 case PERF_EVENT_COMM:
153 return process_comm_event(event, offset, head);
154
155 case PERF_EVENT_EXIT ... PERF_EVENT_READ:
156 return 0;
157
158 case PERF_EVENT_SAMPLE:
159 return process_sample_event(event, offset, head);
160
161 case PERF_EVENT_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 51d168230ee..3a63e41fb44 100644
--- a/tools/perf/builtin.h
+++ b/tools/perf/builtin.h
@@ -22,5 +22,6 @@ extern int cmd_stat(int argc, const char **argv, const char *prefix);
22extern int cmd_top(int argc, const char **argv, const char *prefix); 22extern int cmd_top(int argc, const char **argv, const char *prefix);
23extern int cmd_version(int argc, const char **argv, const char *prefix); 23extern int cmd_version(int argc, const char **argv, const char *prefix);
24extern int cmd_list(int argc, const char **argv, const char *prefix); 24extern int cmd_list(int argc, const char **argv, const char *prefix);
25extern int cmd_trace(int argc, const char **argv, const char *prefix);
25 26
26#endif 27#endif
diff --git a/tools/perf/perf.c b/tools/perf/perf.c
index 31982ad064b..fe4589dde95 100644
--- a/tools/perf/perf.c
+++ b/tools/perf/perf.c
@@ -292,6 +292,7 @@ static void handle_internal_command(int argc, const char **argv)
292 { "top", cmd_top, 0 }, 292 { "top", cmd_top, 0 },
293 { "annotate", cmd_annotate, 0 }, 293 { "annotate", cmd_annotate, 0 },
294 { "version", cmd_version, 0 }, 294 { "version", cmd_version, 0 },
295 { "trace", cmd_trace, 0 },
295 }; 296 };
296 unsigned int i; 297 unsigned int i;
297 static const char ext[] = STRIP_EXTENSION; 298 static const char ext[] = STRIP_EXTENSION;
diff --git a/tools/perf/util/abspath.c b/tools/perf/util/abspath.c
index 61d33b81fc9..a791dd46726 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 4b50c412b9c..6f8ea9d210b 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 01147341164..3b8380f1b47 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 a926ae4f5a1..43cf3ea9e08 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 90a044d1fe7..e88bca55a59 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 706cec50bd2..58d597564b9 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 780df541006..8784649109c 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 00000000000..e8ca98fe0bd
--- /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 00000000000..437eea58ce4
--- /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 00000000000..fa2d4e91d32
--- /dev/null
+++ b/tools/perf/util/event.h
@@ -0,0 +1,96 @@
1#ifndef __PERF_EVENT_H
2#define __PERF_EVENT_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};
43
44struct lost_event {
45 struct perf_event_header header;
46 u64 id;
47 u64 lost;
48};
49
50/*
51 * PERF_FORMAT_ENABLED | PERF_FORMAT_RUNNING | PERF_FORMAT_ID
52 */
53struct read_event {
54 struct perf_event_header header;
55 u32 pid,tid;
56 u64 value;
57 u64 time_enabled;
58 u64 time_running;
59 u64 id;
60};
61
62typedef union event_union {
63 struct perf_event_header header;
64 struct ip_event ip;
65 struct mmap_event mmap;
66 struct comm_event comm;
67 struct fork_event fork;
68 struct lost_event lost;
69 struct read_event read;
70} event_t;
71
72struct map {
73 struct list_head node;
74 u64 start;
75 u64 end;
76 u64 pgoff;
77 u64 (*map_ip)(struct map *, u64);
78 struct dso *dso;
79};
80
81static inline u64 map__map_ip(struct map *map, u64 ip)
82{
83 return ip - map->start + map->pgoff;
84}
85
86static inline u64 vdso__map_ip(struct map *map __used, u64 ip)
87{
88 return ip;
89}
90
91struct map *map__new(struct mmap_event *event, char *cwd, int cwdlen);
92struct map *map__clone(struct map *self);
93int map__overlap(struct map *l, struct map *r);
94size_t map__fprintf(struct map *self, FILE *fp);
95
96#endif
diff --git a/tools/perf/util/exec_cmd.c b/tools/perf/util/exec_cmd.c
index 34a35286738..2745605dba1 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 b92a457ca32..ec4d4c2f952 100644
--- a/tools/perf/util/header.c
+++ b/tools/perf/util/header.c
@@ -237,9 +237,44 @@ struct perf_header *perf_header__read(int fd)
237 self->data_offset = f_header.data.offset; 237 self->data_offset = f_header.data.offset;
238 self->data_size = f_header.data.size; 238 self->data_size = f_header.data.size;
239 239
240 lseek(fd, self->data_offset + self->data_size, SEEK_SET); 240 lseek(fd, self->data_offset, SEEK_SET);
241 241
242 self->frozen = 1; 242 self->frozen = 1;
243 243
244 return self; 244 return self;
245} 245}
246
247u64 perf_header__sample_type(struct perf_header *header)
248{
249 u64 type = 0;
250 int i;
251
252 for (i = 0; i < header->attrs; i++) {
253 struct perf_header_attr *attr = header->attr[i];
254
255 if (!type)
256 type = attr->attr.sample_type;
257 else if (type != attr->attr.sample_type)
258 die("non matching sample_type");
259 }
260
261 return type;
262}
263
264struct perf_counter_attr *
265perf_header__find_attr(u64 id, struct perf_header *header)
266{
267 int i;
268
269 for (i = 0; i < header->attrs; i++) {
270 struct perf_header_attr *attr = header->attr[i];
271 int j;
272
273 for (j = 0; j < attr->ids; j++) {
274 if (attr->id[j] == id)
275 return &attr->attr;
276 }
277 }
278
279 return NULL;
280}
diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h
index bf280449fcf..5d0a72ecc91 100644
--- a/tools/perf/util/header.h
+++ b/tools/perf/util/header.h
@@ -31,6 +31,10 @@ struct perf_header_attr *
31perf_header_attr__new(struct perf_counter_attr *attr); 31perf_header_attr__new(struct perf_counter_attr *attr);
32void perf_header_attr__add_id(struct perf_header_attr *self, u64 id); 32void perf_header_attr__add_id(struct perf_header_attr *self, u64 id);
33 33
34u64 perf_header__sample_type(struct perf_header *header);
35struct perf_counter_attr *
36perf_header__find_attr(u64 id, struct perf_header *header);
37
34 38
35struct perf_header *perf_header__new(void); 39struct perf_header *perf_header__new(void);
36 40
diff --git a/tools/perf/util/map.c b/tools/perf/util/map.c
new file mode 100644
index 00000000000..804e0238273
--- /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 ddabe925d65..3d567fe59c7 100644
--- a/tools/perf/util/module.c
+++ b/tools/perf/util/module.c
@@ -436,9 +436,9 @@ static int mod_dso__load_module_paths(struct mod_dso *self)
436 goto out_failure; 436 goto out_failure;
437 437
438 while (!feof(file)) { 438 while (!feof(file)) {
439 char *path, *name, *tmp; 439 char *name, *tmp;
440 struct module *module; 440 struct module *module;
441 int line_len, len; 441 int line_len;
442 442
443 line_len = getline(&line, &n, file); 443 line_len = getline(&line, &n, file);
444 if (line_len < 0) 444 if (line_len < 0)
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index 04417840878..a587d41ae3c 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -1,23 +1,21 @@
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
10extern char *strcasestr(const char *haystack, const char *needle);
11
12int nr_counters; 10int nr_counters;
13 11
14struct perf_counter_attr attrs[MAX_COUNTERS]; 12struct perf_counter_attr attrs[MAX_COUNTERS];
15 13
16struct event_symbol { 14struct event_symbol {
17 u8 type; 15 u8 type;
18 u64 config; 16 u64 config;
19 char *symbol; 17 const char *symbol;
20 char *alias; 18 const char *alias;
21}; 19};
22 20
23char debugfs_path[MAXPATHLEN]; 21char debugfs_path[MAXPATHLEN];
@@ -51,7 +49,7 @@ static struct event_symbol event_symbols[] = {
51#define PERF_COUNTER_TYPE(config) __PERF_COUNTER_FIELD(config, TYPE) 49#define PERF_COUNTER_TYPE(config) __PERF_COUNTER_FIELD(config, TYPE)
52#define PERF_COUNTER_ID(config) __PERF_COUNTER_FIELD(config, EVENT) 50#define PERF_COUNTER_ID(config) __PERF_COUNTER_FIELD(config, EVENT)
53 51
54static char *hw_event_names[] = { 52static const char *hw_event_names[] = {
55 "cycles", 53 "cycles",
56 "instructions", 54 "instructions",
57 "cache-references", 55 "cache-references",
@@ -61,7 +59,7 @@ static char *hw_event_names[] = {
61 "bus-cycles", 59 "bus-cycles",
62}; 60};
63 61
64static char *sw_event_names[] = { 62static const char *sw_event_names[] = {
65 "cpu-clock-msecs", 63 "cpu-clock-msecs",
66 "task-clock-msecs", 64 "task-clock-msecs",
67 "page-faults", 65 "page-faults",
@@ -73,7 +71,7 @@ static char *sw_event_names[] = {
73 71
74#define MAX_ALIASES 8 72#define MAX_ALIASES 8
75 73
76static char *hw_cache[][MAX_ALIASES] = { 74static const char *hw_cache[][MAX_ALIASES] = {
77 { "L1-dcache", "l1-d", "l1d", "L1-data", }, 75 { "L1-dcache", "l1-d", "l1d", "L1-data", },
78 { "L1-icache", "l1-i", "l1i", "L1-instruction", }, 76 { "L1-icache", "l1-i", "l1i", "L1-instruction", },
79 { "LLC", "L2" }, 77 { "LLC", "L2" },
@@ -82,13 +80,13 @@ static char *hw_cache[][MAX_ALIASES] = {
82 { "branch", "branches", "bpu", "btb", "bpc", }, 80 { "branch", "branches", "bpu", "btb", "bpc", },
83}; 81};
84 82
85static char *hw_cache_op[][MAX_ALIASES] = { 83static const char *hw_cache_op[][MAX_ALIASES] = {
86 { "load", "loads", "read", }, 84 { "load", "loads", "read", },
87 { "store", "stores", "write", }, 85 { "store", "stores", "write", },
88 { "prefetch", "prefetches", "speculative-read", "speculative-load", }, 86 { "prefetch", "prefetches", "speculative-read", "speculative-load", },
89}; 87};
90 88
91static char *hw_cache_result[][MAX_ALIASES] = { 89static const char *hw_cache_result[][MAX_ALIASES] = {
92 { "refs", "Reference", "ops", "access", }, 90 { "refs", "Reference", "ops", "access", },
93 { "misses", "miss", }, 91 { "misses", "miss", },
94}; 92};
@@ -113,11 +111,9 @@ static unsigned long hw_cache_stat[C(MAX)] = {
113 [C(BPU)] = (CACHE_READ), 111 [C(BPU)] = (CACHE_READ),
114}; 112};
115 113
116#define for_each_subsystem(sys_dir, sys_dirent, sys_next, file, st) \ 114#define for_each_subsystem(sys_dir, sys_dirent, sys_next) \
117 while (!readdir_r(sys_dir, &sys_dirent, &sys_next) && sys_next) \ 115 while (!readdir_r(sys_dir, &sys_dirent, &sys_next) && sys_next) \
118 if (snprintf(file, MAXPATHLEN, "%s/%s", debugfs_path, \ 116 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, ".")) && \ 117 (strcmp(sys_dirent.d_name, ".")) && \
122 (strcmp(sys_dirent.d_name, ".."))) 118 (strcmp(sys_dirent.d_name, "..")))
123 119
@@ -136,11 +132,9 @@ static int tp_event_has_id(struct dirent *sys_dir, struct dirent *evt_dir)
136 return 0; 132 return 0;
137} 133}
138 134
139#define for_each_event(sys_dirent, evt_dir, evt_dirent, evt_next, file, st) \ 135#define for_each_event(sys_dirent, evt_dir, evt_dirent, evt_next) \
140 while (!readdir_r(evt_dir, &evt_dirent, &evt_next) && evt_next) \ 136 while (!readdir_r(evt_dir, &evt_dirent, &evt_next) && evt_next) \
141 if (snprintf(file, MAXPATHLEN, "%s/%s/%s", debugfs_path, \ 137 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, ".")) && \ 138 (strcmp(evt_dirent.d_name, ".")) && \
145 (strcmp(evt_dirent.d_name, "..")) && \ 139 (strcmp(evt_dirent.d_name, "..")) && \
146 (!tp_event_has_id(&sys_dirent, &evt_dirent))) 140 (!tp_event_has_id(&sys_dirent, &evt_dirent)))
@@ -158,34 +152,39 @@ int valid_debugfs_mount(const char *debugfs)
158 return 0; 152 return 0;
159} 153}
160 154
161static char *tracepoint_id_to_name(u64 config) 155struct tracepoint_path *tracepoint_id_to_path(u64 config)
162{ 156{
163 static char tracepoint_name[2 * MAX_EVENT_LENGTH]; 157 struct tracepoint_path *path = NULL;
164 DIR *sys_dir, *evt_dir; 158 DIR *sys_dir, *evt_dir;
165 struct dirent *sys_next, *evt_next, sys_dirent, evt_dirent; 159 struct dirent *sys_next, *evt_next, sys_dirent, evt_dirent;
166 struct stat st;
167 char id_buf[4]; 160 char id_buf[4];
168 int fd; 161 int sys_dir_fd, fd;
169 u64 id; 162 u64 id;
170 char evt_path[MAXPATHLEN]; 163 char evt_path[MAXPATHLEN];
171 164
172 if (valid_debugfs_mount(debugfs_path)) 165 if (valid_debugfs_mount(debugfs_path))
173 return "unkown"; 166 return NULL;
174 167
175 sys_dir = opendir(debugfs_path); 168 sys_dir = opendir(debugfs_path);
176 if (!sys_dir) 169 if (!sys_dir)
177 goto cleanup; 170 goto cleanup;
178 171 sys_dir_fd = dirfd(sys_dir);
179 for_each_subsystem(sys_dir, sys_dirent, sys_next, evt_path, st) { 172
180 evt_dir = opendir(evt_path); 173 for_each_subsystem(sys_dir, sys_dirent, sys_next) {
181 if (!evt_dir) 174 int dfd = openat(sys_dir_fd, sys_dirent.d_name,
182 goto cleanup; 175 O_RDONLY|O_DIRECTORY), evt_dir_fd;
183 for_each_event(sys_dirent, evt_dir, evt_dirent, evt_next, 176 if (dfd == -1)
184 evt_path, st) { 177 continue;
185 snprintf(evt_path, MAXPATHLEN, "%s/%s/%s/id", 178 evt_dir = fdopendir(dfd);
186 debugfs_path, sys_dirent.d_name, 179 if (!evt_dir) {
180 close(dfd);
181 continue;
182 }
183 evt_dir_fd = dirfd(evt_dir);
184 for_each_event(sys_dirent, evt_dir, evt_dirent, evt_next) {
185 snprintf(evt_path, MAXPATHLEN, "%s/id",
187 evt_dirent.d_name); 186 evt_dirent.d_name);
188 fd = open(evt_path, O_RDONLY); 187 fd = openat(evt_dir_fd, evt_path, O_RDONLY);
189 if (fd < 0) 188 if (fd < 0)
190 continue; 189 continue;
191 if (read(fd, id_buf, sizeof(id_buf)) < 0) { 190 if (read(fd, id_buf, sizeof(id_buf)) < 0) {
@@ -197,10 +196,23 @@ static char *tracepoint_id_to_name(u64 config)
197 if (id == config) { 196 if (id == config) {
198 closedir(evt_dir); 197 closedir(evt_dir);
199 closedir(sys_dir); 198 closedir(sys_dir);
200 snprintf(tracepoint_name, 2 * MAX_EVENT_LENGTH, 199 path = calloc(1, sizeof(path));
201 "%s:%s", sys_dirent.d_name, 200 path->system = malloc(MAX_EVENT_LENGTH);
202 evt_dirent.d_name); 201 if (!path->system) {
203 return tracepoint_name; 202 free(path);
203 return NULL;
204 }
205 path->name = malloc(MAX_EVENT_LENGTH);
206 if (!path->name) {
207 free(path->system);
208 free(path);
209 return NULL;
210 }
211 strncpy(path->system, sys_dirent.d_name,
212 MAX_EVENT_LENGTH);
213 strncpy(path->name, evt_dirent.d_name,
214 MAX_EVENT_LENGTH);
215 return path;
204 } 216 }
205 } 217 }
206 closedir(evt_dir); 218 closedir(evt_dir);
@@ -208,7 +220,25 @@ static char *tracepoint_id_to_name(u64 config)
208 220
209cleanup: 221cleanup:
210 closedir(sys_dir); 222 closedir(sys_dir);
211 return "unkown"; 223 return NULL;
224}
225
226#define TP_PATH_LEN (MAX_EVENT_LENGTH * 2 + 1)
227static const char *tracepoint_id_to_name(u64 config)
228{
229 static char buf[TP_PATH_LEN];
230 struct tracepoint_path *path;
231
232 path = tracepoint_id_to_path(config);
233 if (path) {
234 snprintf(buf, TP_PATH_LEN, "%s:%s", path->system, path->name);
235 free(path->name);
236 free(path->system);
237 free(path);
238 } else
239 snprintf(buf, TP_PATH_LEN, "%s:%s", "unknown", "unknown");
240
241 return buf;
212} 242}
213 243
214static int is_cache_op_valid(u8 cache_type, u8 cache_op) 244static int is_cache_op_valid(u8 cache_type, u8 cache_op)
@@ -235,7 +265,7 @@ static char *event_cache_name(u8 cache_type, u8 cache_op, u8 cache_result)
235 return name; 265 return name;
236} 266}
237 267
238char *event_name(int counter) 268const char *event_name(int counter)
239{ 269{
240 u64 config = attrs[counter].config; 270 u64 config = attrs[counter].config;
241 int type = attrs[counter].type; 271 int type = attrs[counter].type;
@@ -243,7 +273,7 @@ char *event_name(int counter)
243 return __event_name(type, config); 273 return __event_name(type, config);
244} 274}
245 275
246char *__event_name(int type, u64 config) 276const char *__event_name(int type, u64 config)
247{ 277{
248 static char buf[32]; 278 static char buf[32];
249 279
@@ -294,7 +324,7 @@ char *__event_name(int type, u64 config)
294 return "unknown"; 324 return "unknown";
295} 325}
296 326
297static int parse_aliases(const char **str, char *names[][MAX_ALIASES], int size) 327static int parse_aliases(const char **str, const char *names[][MAX_ALIASES], int size)
298{ 328{
299 int i, j; 329 int i, j;
300 int n, longest = -1; 330 int n, longest = -1;
@@ -598,7 +628,7 @@ static void print_tracepoint_events(void)
598{ 628{
599 DIR *sys_dir, *evt_dir; 629 DIR *sys_dir, *evt_dir;
600 struct dirent *sys_next, *evt_next, sys_dirent, evt_dirent; 630 struct dirent *sys_next, *evt_next, sys_dirent, evt_dirent;
601 struct stat st; 631 int sys_dir_fd;
602 char evt_path[MAXPATHLEN]; 632 char evt_path[MAXPATHLEN];
603 633
604 if (valid_debugfs_mount(debugfs_path)) 634 if (valid_debugfs_mount(debugfs_path))
@@ -607,16 +637,23 @@ static void print_tracepoint_events(void)
607 sys_dir = opendir(debugfs_path); 637 sys_dir = opendir(debugfs_path);
608 if (!sys_dir) 638 if (!sys_dir)
609 goto cleanup; 639 goto cleanup;
610 640 sys_dir_fd = dirfd(sys_dir);
611 for_each_subsystem(sys_dir, sys_dirent, sys_next, evt_path, st) { 641
612 evt_dir = opendir(evt_path); 642 for_each_subsystem(sys_dir, sys_dirent, sys_next) {
613 if (!evt_dir) 643 int dfd = openat(sys_dir_fd, sys_dirent.d_name,
614 goto cleanup; 644 O_RDONLY|O_DIRECTORY), evt_dir_fd;
615 for_each_event(sys_dirent, evt_dir, evt_dirent, evt_next, 645 if (dfd == -1)
616 evt_path, st) { 646 continue;
647 evt_dir = fdopendir(dfd);
648 if (!evt_dir) {
649 close(dfd);
650 continue;
651 }
652 evt_dir_fd = dirfd(evt_dir);
653 for_each_event(sys_dirent, evt_dir, evt_dirent, evt_next) {
617 snprintf(evt_path, MAXPATHLEN, "%s:%s", 654 snprintf(evt_path, MAXPATHLEN, "%s:%s",
618 sys_dirent.d_name, evt_dirent.d_name); 655 sys_dirent.d_name, evt_dirent.d_name);
619 fprintf(stderr, " %-40s [%s]\n", evt_path, 656 fprintf(stderr, " %-42s [%s]\n", evt_path,
620 event_type_descriptors[PERF_TYPE_TRACEPOINT+1]); 657 event_type_descriptors[PERF_TYPE_TRACEPOINT+1]);
621 } 658 }
622 closedir(evt_dir); 659 closedir(evt_dir);
@@ -650,7 +687,7 @@ void print_events(void)
650 sprintf(name, "%s OR %s", syms->symbol, syms->alias); 687 sprintf(name, "%s OR %s", syms->symbol, syms->alias);
651 else 688 else
652 strcpy(name, syms->symbol); 689 strcpy(name, syms->symbol);
653 fprintf(stderr, " %-40s [%s]\n", name, 690 fprintf(stderr, " %-42s [%s]\n", name,
654 event_type_descriptors[type]); 691 event_type_descriptors[type]);
655 692
656 prev_type = type; 693 prev_type = type;
@@ -664,7 +701,7 @@ void print_events(void)
664 continue; 701 continue;
665 702
666 for (i = 0; i < PERF_COUNT_HW_CACHE_RESULT_MAX; i++) { 703 for (i = 0; i < PERF_COUNT_HW_CACHE_RESULT_MAX; i++) {
667 fprintf(stderr, " %-40s [%s]\n", 704 fprintf(stderr, " %-42s [%s]\n",
668 event_cache_name(type, op, i), 705 event_cache_name(type, op, i),
669 event_type_descriptors[4]); 706 event_type_descriptors[4]);
670 } 707 }
@@ -672,7 +709,7 @@ void print_events(void)
672 } 709 }
673 710
674 fprintf(stderr, "\n"); 711 fprintf(stderr, "\n");
675 fprintf(stderr, " %-40s [raw hardware event descriptor]\n", 712 fprintf(stderr, " %-42s [raw hardware event descriptor]\n",
676 "rNNN"); 713 "rNNN");
677 fprintf(stderr, "\n"); 714 fprintf(stderr, "\n");
678 715
diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h
index 192a962e3a0..60704c15961 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_counter_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 1bf67190c82..6d8af48c925 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/path.c b/tools/perf/util/path.c
index a501a40dd2c..fd1f2faaade 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 a3935343091..2b615acf94d 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/symbol.c b/tools/perf/util/symbol.c
index 5c0f42e6b33..fd3d9c8e90f 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,13 +822,13 @@ 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;
@@ -844,7 +846,7 @@ 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;
@@ -887,14 +889,14 @@ static inline void dso__fill_symbol_holes(struct dso *self)
887} 889}
888 890
889static int dso__load_vmlinux(struct dso *self, const char *vmlinux, 891static int dso__load_vmlinux(struct dso *self, const char *vmlinux,
890 symbol_filter_t filter, int verbose) 892 symbol_filter_t filter, int v)
891{ 893{
892 int err, fd = open(vmlinux, O_RDONLY); 894 int err, fd = open(vmlinux, O_RDONLY);
893 895
894 if (fd < 0) 896 if (fd < 0)
895 return -1; 897 return -1;
896 898
897 err = dso__load_sym(self, fd, vmlinux, filter, verbose, NULL); 899 err = dso__load_sym(self, fd, vmlinux, filter, v, NULL);
898 900
899 if (err > 0) 901 if (err > 0)
900 dso__fill_symbol_holes(self); 902 dso__fill_symbol_holes(self);
@@ -905,18 +907,18 @@ static int dso__load_vmlinux(struct dso *self, const char *vmlinux,
905} 907}
906 908
907int dso__load_kernel(struct dso *self, const char *vmlinux, 909int dso__load_kernel(struct dso *self, const char *vmlinux,
908 symbol_filter_t filter, int verbose, int modules) 910 symbol_filter_t filter, int v, int use_modules)
909{ 911{
910 int err = -1; 912 int err = -1;
911 913
912 if (vmlinux) { 914 if (vmlinux) {
913 err = dso__load_vmlinux(self, vmlinux, filter, verbose); 915 err = dso__load_vmlinux(self, vmlinux, filter, v);
914 if (err > 0 && modules) 916 if (err > 0 && use_modules)
915 err = dso__load_modules(self, filter, verbose); 917 err = dso__load_modules(self, filter, v);
916 } 918 }
917 919
918 if (err <= 0) 920 if (err <= 0)
919 err = dso__load_kallsyms(self, filter, verbose); 921 err = dso__load_kallsyms(self, filter, v);
920 922
921 if (err > 0) 923 if (err > 0)
922 self->origin = DSO__ORIG_KERNEL; 924 self->origin = DSO__ORIG_KERNEL;
@@ -924,6 +926,103 @@ int dso__load_kernel(struct dso *self, const char *vmlinux,
924 return err; 926 return err;
925} 927}
926 928
929LIST_HEAD(dsos);
930struct dso *kernel_dso;
931struct dso *vdso;
932struct dso *hypervisor_dso;
933
934const char *vmlinux_name = "vmlinux";
935int modules;
936
937static void dsos__add(struct dso *dso)
938{
939 list_add_tail(&dso->node, &dsos);
940}
941
942static struct dso *dsos__find(const char *name)
943{
944 struct dso *pos;
945
946 list_for_each_entry(pos, &dsos, node)
947 if (strcmp(pos->name, name) == 0)
948 return pos;
949 return NULL;
950}
951
952struct dso *dsos__findnew(const char *name)
953{
954 struct dso *dso = dsos__find(name);
955 int nr;
956
957 if (dso)
958 return dso;
959
960 dso = dso__new(name, 0);
961 if (!dso)
962 goto out_delete_dso;
963
964 nr = dso__load(dso, NULL, verbose);
965 if (nr < 0) {
966 eprintf("Failed to open: %s\n", name);
967 goto out_delete_dso;
968 }
969 if (!nr)
970 eprintf("No symbols found in: %s, maybe install a debug package?\n", name);
971
972 dsos__add(dso);
973
974 return dso;
975
976out_delete_dso:
977 dso__delete(dso);
978 return NULL;
979}
980
981void dsos__fprintf(FILE *fp)
982{
983 struct dso *pos;
984
985 list_for_each_entry(pos, &dsos, node)
986 dso__fprintf(pos, fp);
987}
988
989static struct symbol *vdso__find_symbol(struct dso *dso, u64 ip)
990{
991 return dso__find_symbol(dso, ip);
992}
993
994int load_kernel(void)
995{
996 int err;
997
998 kernel_dso = dso__new("[kernel]", 0);
999 if (!kernel_dso)
1000 return -1;
1001
1002 err = dso__load_kernel(kernel_dso, vmlinux_name, NULL, verbose, modules);
1003 if (err <= 0) {
1004 dso__delete(kernel_dso);
1005 kernel_dso = NULL;
1006 } else
1007 dsos__add(kernel_dso);
1008
1009 vdso = dso__new("[vdso]", 0);
1010 if (!vdso)
1011 return -1;
1012
1013 vdso->find_symbol = vdso__find_symbol;
1014
1015 dsos__add(vdso);
1016
1017 hypervisor_dso = dso__new("[hypervisor]", 0);
1018 if (!hypervisor_dso)
1019 return -1;
1020 dsos__add(hypervisor_dso);
1021
1022 return err;
1023}
1024
1025
927void symbol__init(void) 1026void symbol__init(void)
928{ 1027{
929 elf_version(EV_CURRENT); 1028 elf_version(EV_CURRENT);
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h
index b53bf0125c1..6e849071640 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 00000000000..7635928ca27
--- /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 = malloc(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, "[init]")) {
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 00000000000..634f2809a34
--- /dev/null
+++ b/tools/perf/util/thread.h
@@ -0,0 +1,21 @@
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 *comm;
11};
12
13int thread__set_comm(struct thread *self, const char *comm);
14struct thread *
15threads__findnew(pid_t pid, struct rb_root *threads, struct thread **last_match);
16struct thread *
17register_idle_thread(struct rb_root *threads, struct thread **last_match);
18void thread__insert_map(struct thread *self, struct map *map);
19int thread__fork(struct thread *self, struct thread *parent);
20struct map *thread__find_map(struct thread *self, u64 ip);
21size_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 00000000000..6c9302a7274
--- /dev/null
+++ b/tools/perf/util/trace-event-info.c
@@ -0,0 +1,539 @@
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 const 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 return;
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);
478
479}
480
481static struct tracepoint_path *
482get_tracepoints_path(struct perf_counter_attr *pattrs, int nb_counters)
483{
484 struct tracepoint_path path, *ppath = &path;
485 int i;
486
487 for (i = 0; i < nb_counters; i++) {
488 if (pattrs[i].type != PERF_TYPE_TRACEPOINT)
489 continue;
490 ppath->next = tracepoint_id_to_path(pattrs[i].config);
491 if (!ppath->next)
492 die("%s\n", "No memory to alloc tracepoints list");
493 ppath = ppath->next;
494 }
495
496 return path.next;
497}
498void read_tracing_data(struct perf_counter_attr *pattrs, int nb_counters)
499{
500 char buf[BUFSIZ];
501 struct tracepoint_path *tps;
502
503 output_fd = open(output_file, O_WRONLY | O_CREAT | O_TRUNC | O_LARGEFILE, 0644);
504 if (output_fd < 0)
505 die("creating file '%s'", output_file);
506
507 buf[0] = 23;
508 buf[1] = 8;
509 buf[2] = 68;
510 memcpy(buf + 3, "tracing", 7);
511
512 write_or_die(buf, 10);
513
514 write_or_die(VERSION, strlen(VERSION) + 1);
515
516 /* save endian */
517 if (bigendian())
518 buf[0] = 1;
519 else
520 buf[0] = 0;
521
522 write_or_die(buf, 1);
523
524 /* save size of long */
525 buf[0] = sizeof(long);
526 write_or_die(buf, 1);
527
528 /* save page_size */
529 page_size = getpagesize();
530 write_or_die(&page_size, 4);
531
532 tps = get_tracepoints_path(pattrs, nb_counters);
533
534 read_header_files();
535 read_ftrace_files(tps);
536 read_event_files(tps);
537 read_proc_kallsyms();
538 read_ftrace_printk();
539}
diff --git a/tools/perf/util/trace-event-parse.c b/tools/perf/util/trace-event-parse.c
new file mode 100644
index 00000000000..629e602d940
--- /dev/null
+++ b/tools/perf/util/trace-event-parse.c
@@ -0,0 +1,2942 @@
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
1779static int get_common_info(const char *type, int *offset, int *size)
1780{
1781 struct event *event;
1782 struct format_field *field;
1783
1784 /*
1785 * All events should have the same common elements.
1786 * Pick any event to find where the type is;
1787 */
1788 if (!event_list)
1789 die("no event_list!");
1790
1791 event = event_list;
1792 field = find_common_field(event, type);
1793 if (!field)
1794 die("field '%s' not found", type);
1795
1796 *offset = field->offset;
1797 *size = field->size;
1798
1799 return 0;
1800}
1801
1802static int parse_common_type(void *data)
1803{
1804 static int type_offset;
1805 static int type_size;
1806 int ret;
1807
1808 if (!type_size) {
1809 ret = get_common_info("common_type",
1810 &type_offset,
1811 &type_size);
1812 if (ret < 0)
1813 return ret;
1814 }
1815 return read_size(data + type_offset, type_size);
1816}
1817
1818static int parse_common_pid(void *data)
1819{
1820 static int pid_offset;
1821 static int pid_size;
1822 int ret;
1823
1824 if (!pid_size) {
1825 ret = get_common_info("common_pid",
1826 &pid_offset,
1827 &pid_size);
1828 if (ret < 0)
1829 return ret;
1830 }
1831
1832 return read_size(data + pid_offset, pid_size);
1833}
1834
1835static struct event *find_event(int id)
1836{
1837 struct event *event;
1838
1839 for (event = event_list; event; event = event->next) {
1840 if (event->id == id)
1841 break;
1842 }
1843 return event;
1844}
1845
1846static unsigned long long eval_num_arg(void *data, int size,
1847 struct event *event, struct print_arg *arg)
1848{
1849 unsigned long long val = 0;
1850 unsigned long long left, right;
1851
1852 switch (arg->type) {
1853 case PRINT_NULL:
1854 /* ?? */
1855 return 0;
1856 case PRINT_ATOM:
1857 return strtoull(arg->atom.atom, NULL, 0);
1858 case PRINT_FIELD:
1859 if (!arg->field.field) {
1860 arg->field.field = find_any_field(event, arg->field.name);
1861 if (!arg->field.field)
1862 die("field %s not found", arg->field.name);
1863 }
1864 /* must be a number */
1865 val = read_size(data + arg->field.field->offset,
1866 arg->field.field->size);
1867 break;
1868 case PRINT_FLAGS:
1869 case PRINT_SYMBOL:
1870 break;
1871 case PRINT_TYPE:
1872 return eval_num_arg(data, size, event, arg->typecast.item);
1873 case PRINT_STRING:
1874 return 0;
1875 break;
1876 case PRINT_OP:
1877 left = eval_num_arg(data, size, event, arg->op.left);
1878 right = eval_num_arg(data, size, event, arg->op.right);
1879 switch (arg->op.op[0]) {
1880 case '|':
1881 if (arg->op.op[1])
1882 val = left || right;
1883 else
1884 val = left | right;
1885 break;
1886 case '&':
1887 if (arg->op.op[1])
1888 val = left && right;
1889 else
1890 val = left & right;
1891 break;
1892 case '<':
1893 switch (arg->op.op[1]) {
1894 case 0:
1895 val = left < right;
1896 break;
1897 case '<':
1898 val = left << right;
1899 break;
1900 case '=':
1901 val = left <= right;
1902 break;
1903 default:
1904 die("unknown op '%s'", arg->op.op);
1905 }
1906 break;
1907 case '>':
1908 switch (arg->op.op[1]) {
1909 case 0:
1910 val = left > right;
1911 break;
1912 case '>':
1913 val = left >> right;
1914 break;
1915 case '=':
1916 val = left >= right;
1917 break;
1918 default:
1919 die("unknown op '%s'", arg->op.op);
1920 }
1921 break;
1922 case '=':
1923 if (arg->op.op[1] != '=')
1924 die("unknown op '%s'", arg->op.op);
1925 val = left == right;
1926 break;
1927 default:
1928 die("unknown op '%s'", arg->op.op);
1929 }
1930 break;
1931 default: /* not sure what to do there */
1932 return 0;
1933 }
1934 return val;
1935}
1936
1937struct flag {
1938 const char *name;
1939 unsigned long long value;
1940};
1941
1942static const struct flag flags[] = {
1943 { "HI_SOFTIRQ", 0 },
1944 { "TIMER_SOFTIRQ", 1 },
1945 { "NET_TX_SOFTIRQ", 2 },
1946 { "NET_RX_SOFTIRQ", 3 },
1947 { "BLOCK_SOFTIRQ", 4 },
1948 { "TASKLET_SOFTIRQ", 5 },
1949 { "SCHED_SOFTIRQ", 6 },
1950 { "HRTIMER_SOFTIRQ", 7 },
1951 { "RCU_SOFTIRQ", 8 },
1952
1953 { "HRTIMER_NORESTART", 0 },
1954 { "HRTIMER_RESTART", 1 },
1955};
1956
1957static unsigned long long eval_flag(const char *flag)
1958{
1959 int i;
1960
1961 /*
1962 * Some flags in the format files do not get converted.
1963 * If the flag is not numeric, see if it is something that
1964 * we already know about.
1965 */
1966 if (isdigit(flag[0]))
1967 return strtoull(flag, NULL, 0);
1968
1969 for (i = 0; i < (int)(sizeof(flags)/sizeof(flags[0])); i++)
1970 if (strcmp(flags[i].name, flag) == 0)
1971 return flags[i].value;
1972
1973 return 0;
1974}
1975
1976static void print_str_arg(void *data, int size,
1977 struct event *event, struct print_arg *arg)
1978{
1979 struct print_flag_sym *flag;
1980 unsigned long long val, fval;
1981 char *str;
1982 int print;
1983
1984 switch (arg->type) {
1985 case PRINT_NULL:
1986 /* ?? */
1987 return;
1988 case PRINT_ATOM:
1989 printf("%s", arg->atom.atom);
1990 return;
1991 case PRINT_FIELD:
1992 if (!arg->field.field) {
1993 arg->field.field = find_any_field(event, arg->field.name);
1994 if (!arg->field.field)
1995 die("field %s not found", arg->field.name);
1996 }
1997 str = malloc_or_die(arg->field.field->size + 1);
1998 memcpy(str, data + arg->field.field->offset,
1999 arg->field.field->size);
2000 str[arg->field.field->size] = 0;
2001 printf("%s", str);
2002 free(str);
2003 break;
2004 case PRINT_FLAGS:
2005 val = eval_num_arg(data, size, event, arg->flags.field);
2006 print = 0;
2007 for (flag = arg->flags.flags; flag; flag = flag->next) {
2008 fval = eval_flag(flag->value);
2009 if (!val && !fval) {
2010 printf("%s", flag->str);
2011 break;
2012 }
2013 if (fval && (val & fval) == fval) {
2014 if (print && arg->flags.delim)
2015 printf("%s", arg->flags.delim);
2016 printf("%s", flag->str);
2017 print = 1;
2018 val &= ~fval;
2019 }
2020 }
2021 break;
2022 case PRINT_SYMBOL:
2023 val = eval_num_arg(data, size, event, arg->symbol.field);
2024 for (flag = arg->symbol.symbols; flag; flag = flag->next) {
2025 fval = eval_flag(flag->value);
2026 if (val == fval) {
2027 printf("%s", flag->str);
2028 break;
2029 }
2030 }
2031 break;
2032
2033 case PRINT_TYPE:
2034 break;
2035 case PRINT_STRING: {
2036 int str_offset;
2037
2038 if (arg->string.offset == -1) {
2039 struct format_field *f;
2040
2041 f = find_any_field(event, arg->string.string);
2042 arg->string.offset = f->offset;
2043 }
2044 str_offset = *(int *)(data + arg->string.offset);
2045 str_offset &= 0xffff;
2046 printf("%s", ((char *)data) + str_offset);
2047 break;
2048 }
2049 case PRINT_OP:
2050 /*
2051 * The only op for string should be ? :
2052 */
2053 if (arg->op.op[0] != '?')
2054 return;
2055 val = eval_num_arg(data, size, event, arg->op.left);
2056 if (val)
2057 print_str_arg(data, size, event, arg->op.right->op.left);
2058 else
2059 print_str_arg(data, size, event, arg->op.right->op.right);
2060 break;
2061 default:
2062 /* well... */
2063 break;
2064 }
2065}
2066
2067static struct print_arg *make_bprint_args(char *fmt, void *data, int size, struct event *event)
2068{
2069 static struct format_field *field, *ip_field;
2070 struct print_arg *args, *arg, **next;
2071 unsigned long long ip, val;
2072 char *ptr;
2073 void *bptr;
2074
2075 if (!field) {
2076 field = find_field(event, "buf");
2077 if (!field)
2078 die("can't find buffer field for binary printk");
2079 ip_field = find_field(event, "ip");
2080 if (!ip_field)
2081 die("can't find ip field for binary printk");
2082 }
2083
2084 ip = read_size(data + ip_field->offset, ip_field->size);
2085
2086 /*
2087 * The first arg is the IP pointer.
2088 */
2089 args = malloc_or_die(sizeof(*args));
2090 arg = args;
2091 arg->next = NULL;
2092 next = &arg->next;
2093
2094 arg->type = PRINT_ATOM;
2095 arg->atom.atom = malloc_or_die(32);
2096 sprintf(arg->atom.atom, "%lld", ip);
2097
2098 /* skip the first "%pf : " */
2099 for (ptr = fmt + 6, bptr = data + field->offset;
2100 bptr < data + size && *ptr; ptr++) {
2101 int ls = 0;
2102
2103 if (*ptr == '%') {
2104 process_again:
2105 ptr++;
2106 switch (*ptr) {
2107 case '%':
2108 break;
2109 case 'l':
2110 ls++;
2111 goto process_again;
2112 case 'L':
2113 ls = 2;
2114 goto process_again;
2115 case '0' ... '9':
2116 goto process_again;
2117 case 'p':
2118 ls = 1;
2119 /* fall through */
2120 case 'd':
2121 case 'u':
2122 case 'x':
2123 case 'i':
2124 bptr = (void *)(((unsigned long)bptr + (long_size - 1)) &
2125 ~(long_size - 1));
2126 switch (ls) {
2127 case 0:
2128 case 1:
2129 ls = long_size;
2130 break;
2131 case 2:
2132 ls = 8;
2133 default:
2134 break;
2135 }
2136 val = read_size(bptr, ls);
2137 bptr += ls;
2138 arg = malloc_or_die(sizeof(*arg));
2139 arg->next = NULL;
2140 arg->type = PRINT_ATOM;
2141 arg->atom.atom = malloc_or_die(32);
2142 sprintf(arg->atom.atom, "%lld", val);
2143 *next = arg;
2144 next = &arg->next;
2145 break;
2146 case 's':
2147 arg = malloc_or_die(sizeof(*arg));
2148 arg->next = NULL;
2149 arg->type = PRINT_STRING;
2150 arg->string.string = strdup(bptr);
2151 bptr += strlen(bptr) + 1;
2152 *next = arg;
2153 next = &arg->next;
2154 default:
2155 break;
2156 }
2157 }
2158 }
2159
2160 return args;
2161}
2162
2163static void free_args(struct print_arg *args)
2164{
2165 struct print_arg *next;
2166
2167 while (args) {
2168 next = args->next;
2169
2170 if (args->type == PRINT_ATOM)
2171 free(args->atom.atom);
2172 else
2173 free(args->string.string);
2174 free(args);
2175 args = next;
2176 }
2177}
2178
2179static char *get_bprint_format(void *data, int size __unused, struct event *event)
2180{
2181 unsigned long long addr;
2182 static struct format_field *field;
2183 struct printk_map *printk;
2184 char *format;
2185 char *p;
2186
2187 if (!field) {
2188 field = find_field(event, "fmt");
2189 if (!field)
2190 die("can't find format field for binary printk");
2191 printf("field->offset = %d size=%d\n", field->offset, field->size);
2192 }
2193
2194 addr = read_size(data + field->offset, field->size);
2195
2196 printk = find_printk(addr);
2197 if (!printk) {
2198 format = malloc_or_die(45);
2199 sprintf(format, "%%pf : (NO FORMAT FOUND at %llx)\n",
2200 addr);
2201 return format;
2202 }
2203
2204 p = printk->printk;
2205 /* Remove any quotes. */
2206 if (*p == '"')
2207 p++;
2208 format = malloc_or_die(strlen(p) + 10);
2209 sprintf(format, "%s : %s", "%pf", p);
2210 /* remove ending quotes and new line since we will add one too */
2211 p = format + strlen(format) - 1;
2212 if (*p == '"')
2213 *p = 0;
2214
2215 p -= 2;
2216 if (strcmp(p, "\\n") == 0)
2217 *p = 0;
2218
2219 return format;
2220}
2221
2222static void pretty_print(void *data, int size, struct event *event)
2223{
2224 struct print_fmt *print_fmt = &event->print_fmt;
2225 struct print_arg *arg = print_fmt->args;
2226 struct print_arg *args = NULL;
2227 const char *ptr = print_fmt->format;
2228 unsigned long long val;
2229 struct func_map *func;
2230 const char *saveptr;
2231 char *bprint_fmt = NULL;
2232 char format[32];
2233 int show_func;
2234 int len;
2235 int ls;
2236
2237 if (event->flags & EVENT_FL_ISFUNC)
2238 ptr = " %pF <-- %pF";
2239
2240 if (event->flags & EVENT_FL_ISBPRINT) {
2241 bprint_fmt = get_bprint_format(data, size, event);
2242 args = make_bprint_args(bprint_fmt, data, size, event);
2243 arg = args;
2244 ptr = bprint_fmt;
2245 }
2246
2247 for (; *ptr; ptr++) {
2248 ls = 0;
2249 if (*ptr == '%') {
2250 saveptr = ptr;
2251 show_func = 0;
2252 cont_process:
2253 ptr++;
2254 switch (*ptr) {
2255 case '%':
2256 printf("%%");
2257 break;
2258 case 'l':
2259 ls++;
2260 goto cont_process;
2261 case 'L':
2262 ls = 2;
2263 goto cont_process;
2264 case 'z':
2265 case 'Z':
2266 case '0' ... '9':
2267 goto cont_process;
2268 case 'p':
2269 if (long_size == 4)
2270 ls = 1;
2271 else
2272 ls = 2;
2273
2274 if (*(ptr+1) == 'F' ||
2275 *(ptr+1) == 'f') {
2276 ptr++;
2277 show_func = *ptr;
2278 }
2279
2280 /* fall through */
2281 case 'd':
2282 case 'i':
2283 case 'x':
2284 case 'X':
2285 case 'u':
2286 if (!arg)
2287 die("no argument match");
2288
2289 len = ((unsigned long)ptr + 1) -
2290 (unsigned long)saveptr;
2291
2292 /* should never happen */
2293 if (len > 32)
2294 die("bad format!");
2295
2296 memcpy(format, saveptr, len);
2297 format[len] = 0;
2298
2299 val = eval_num_arg(data, size, event, arg);
2300 arg = arg->next;
2301
2302 if (show_func) {
2303 func = find_func(val);
2304 if (func) {
2305 printf("%s", func->func);
2306 if (show_func == 'F')
2307 printf("+0x%llx",
2308 val - func->addr);
2309 break;
2310 }
2311 }
2312 switch (ls) {
2313 case 0:
2314 printf(format, (int)val);
2315 break;
2316 case 1:
2317 printf(format, (long)val);
2318 break;
2319 case 2:
2320 printf(format, (long long)val);
2321 break;
2322 default:
2323 die("bad count (%d)", ls);
2324 }
2325 break;
2326 case 's':
2327 if (!arg)
2328 die("no matching argument");
2329
2330 print_str_arg(data, size, event, arg);
2331 arg = arg->next;
2332 break;
2333 default:
2334 printf(">%c<", *ptr);
2335
2336 }
2337 } else
2338 printf("%c", *ptr);
2339 }
2340
2341 if (args) {
2342 free_args(args);
2343 free(bprint_fmt);
2344 }
2345}
2346
2347static inline int log10_cpu(int nb)
2348{
2349 if (nb / 100)
2350 return 3;
2351 if (nb / 10)
2352 return 2;
2353 return 1;
2354}
2355
2356/* taken from Linux, written by Frederic Weisbecker */
2357static void print_graph_cpu(int cpu)
2358{
2359 int i;
2360 int log10_this = log10_cpu(cpu);
2361 int log10_all = log10_cpu(cpus);
2362
2363
2364 /*
2365 * Start with a space character - to make it stand out
2366 * to the right a bit when trace output is pasted into
2367 * email:
2368 */
2369 printf(" ");
2370
2371 /*
2372 * Tricky - we space the CPU field according to the max
2373 * number of online CPUs. On a 2-cpu system it would take
2374 * a maximum of 1 digit - on a 128 cpu system it would
2375 * take up to 3 digits:
2376 */
2377 for (i = 0; i < log10_all - log10_this; i++)
2378 printf(" ");
2379
2380 printf("%d) ", cpu);
2381}
2382
2383#define TRACE_GRAPH_PROCINFO_LENGTH 14
2384#define TRACE_GRAPH_INDENT 2
2385
2386static void print_graph_proc(int pid, const char *comm)
2387{
2388 /* sign + log10(MAX_INT) + '\0' */
2389 char pid_str[11];
2390 int spaces = 0;
2391 int len;
2392 int i;
2393
2394 sprintf(pid_str, "%d", pid);
2395
2396 /* 1 stands for the "-" character */
2397 len = strlen(comm) + strlen(pid_str) + 1;
2398
2399 if (len < TRACE_GRAPH_PROCINFO_LENGTH)
2400 spaces = TRACE_GRAPH_PROCINFO_LENGTH - len;
2401
2402 /* First spaces to align center */
2403 for (i = 0; i < spaces / 2; i++)
2404 printf(" ");
2405
2406 printf("%s-%s", comm, pid_str);
2407
2408 /* Last spaces to align center */
2409 for (i = 0; i < spaces - (spaces / 2); i++)
2410 printf(" ");
2411}
2412
2413static struct record *
2414get_return_for_leaf(int cpu, int cur_pid, unsigned long long cur_func,
2415 struct record *next)
2416{
2417 struct format_field *field;
2418 struct event *event;
2419 unsigned long val;
2420 int type;
2421 int pid;
2422
2423 type = parse_common_type(next->data);
2424 event = find_event(type);
2425 if (!event)
2426 return NULL;
2427
2428 if (!(event->flags & EVENT_FL_ISFUNCRET))
2429 return NULL;
2430
2431 pid = parse_common_pid(next->data);
2432 field = find_field(event, "func");
2433 if (!field)
2434 die("function return does not have field func");
2435
2436 val = read_size(next->data + field->offset, field->size);
2437
2438 if (cur_pid != pid || cur_func != val)
2439 return NULL;
2440
2441 /* this is a leaf, now advance the iterator */
2442 return trace_read_data(cpu);
2443}
2444
2445/* Signal a overhead of time execution to the output */
2446static void print_graph_overhead(unsigned long long duration)
2447{
2448 /* Non nested entry or return */
2449 if (duration == ~0ULL)
2450 return (void)printf(" ");
2451
2452 /* Duration exceeded 100 msecs */
2453 if (duration > 100000ULL)
2454 return (void)printf("! ");
2455
2456 /* Duration exceeded 10 msecs */
2457 if (duration > 10000ULL)
2458 return (void)printf("+ ");
2459
2460 printf(" ");
2461}
2462
2463static void print_graph_duration(unsigned long long duration)
2464{
2465 unsigned long usecs = duration / 1000;
2466 unsigned long nsecs_rem = duration % 1000;
2467 /* log10(ULONG_MAX) + '\0' */
2468 char msecs_str[21];
2469 char nsecs_str[5];
2470 int len;
2471 int i;
2472
2473 sprintf(msecs_str, "%lu", usecs);
2474
2475 /* Print msecs */
2476 len = printf("%lu", usecs);
2477
2478 /* Print nsecs (we don't want to exceed 7 numbers) */
2479 if (len < 7) {
2480 snprintf(nsecs_str, 8 - len, "%03lu", nsecs_rem);
2481 len += printf(".%s", nsecs_str);
2482 }
2483
2484 printf(" us ");
2485
2486 /* Print remaining spaces to fit the row's width */
2487 for (i = len; i < 7; i++)
2488 printf(" ");
2489
2490 printf("| ");
2491}
2492
2493static void
2494print_graph_entry_leaf(struct event *event, void *data, struct record *ret_rec)
2495{
2496 unsigned long long rettime, calltime;
2497 unsigned long long duration, depth;
2498 unsigned long long val;
2499 struct format_field *field;
2500 struct func_map *func;
2501 struct event *ret_event;
2502 int type;
2503 int i;
2504
2505 type = parse_common_type(ret_rec->data);
2506 ret_event = find_event(type);
2507
2508 field = find_field(ret_event, "rettime");
2509 if (!field)
2510 die("can't find rettime in return graph");
2511 rettime = read_size(ret_rec->data + field->offset, field->size);
2512
2513 field = find_field(ret_event, "calltime");
2514 if (!field)
2515 die("can't find rettime in return graph");
2516 calltime = read_size(ret_rec->data + field->offset, field->size);
2517
2518 duration = rettime - calltime;
2519
2520 /* Overhead */
2521 print_graph_overhead(duration);
2522
2523 /* Duration */
2524 print_graph_duration(duration);
2525
2526 field = find_field(event, "depth");
2527 if (!field)
2528 die("can't find depth in entry graph");
2529 depth = read_size(data + field->offset, field->size);
2530
2531 /* Function */
2532 for (i = 0; i < (int)(depth * TRACE_GRAPH_INDENT); i++)
2533 printf(" ");
2534
2535 field = find_field(event, "func");
2536 if (!field)
2537 die("can't find func in entry graph");
2538 val = read_size(data + field->offset, field->size);
2539 func = find_func(val);
2540
2541 if (func)
2542 printf("%s();", func->func);
2543 else
2544 printf("%llx();", val);
2545}
2546
2547static void print_graph_nested(struct event *event, void *data)
2548{
2549 struct format_field *field;
2550 unsigned long long depth;
2551 unsigned long long val;
2552 struct func_map *func;
2553 int i;
2554
2555 /* No overhead */
2556 print_graph_overhead(-1);
2557
2558 /* No time */
2559 printf(" | ");
2560
2561 field = find_field(event, "depth");
2562 if (!field)
2563 die("can't find depth in entry graph");
2564 depth = read_size(data + field->offset, field->size);
2565
2566 /* Function */
2567 for (i = 0; i < (int)(depth * TRACE_GRAPH_INDENT); i++)
2568 printf(" ");
2569
2570 field = find_field(event, "func");
2571 if (!field)
2572 die("can't find func in entry graph");
2573 val = read_size(data + field->offset, field->size);
2574 func = find_func(val);
2575
2576 if (func)
2577 printf("%s() {", func->func);
2578 else
2579 printf("%llx() {", val);
2580}
2581
2582static void
2583pretty_print_func_ent(void *data, int size, struct event *event,
2584 int cpu, int pid, const char *comm,
2585 unsigned long secs, unsigned long usecs)
2586{
2587 struct format_field *field;
2588 struct record *rec;
2589 void *copy_data;
2590 unsigned long val;
2591
2592 printf("%5lu.%06lu | ", secs, usecs);
2593
2594 print_graph_cpu(cpu);
2595 print_graph_proc(pid, comm);
2596
2597 printf(" | ");
2598
2599 field = find_field(event, "func");
2600 if (!field)
2601 die("function entry does not have func field");
2602
2603 val = read_size(data + field->offset, field->size);
2604
2605 /*
2606 * peek_data may unmap the data pointer. Copy it first.
2607 */
2608 copy_data = malloc_or_die(size);
2609 memcpy(copy_data, data, size);
2610 data = copy_data;
2611
2612 rec = trace_peek_data(cpu);
2613 if (rec) {
2614 rec = get_return_for_leaf(cpu, pid, val, rec);
2615 if (rec) {
2616 print_graph_entry_leaf(event, data, rec);
2617 goto out_free;
2618 }
2619 }
2620 print_graph_nested(event, data);
2621out_free:
2622 free(data);
2623}
2624
2625static void
2626pretty_print_func_ret(void *data, int size __unused, struct event *event,
2627 int cpu, int pid, const char *comm,
2628 unsigned long secs, unsigned long usecs)
2629{
2630 unsigned long long rettime, calltime;
2631 unsigned long long duration, depth;
2632 struct format_field *field;
2633 int i;
2634
2635 printf("%5lu.%06lu | ", secs, usecs);
2636
2637 print_graph_cpu(cpu);
2638 print_graph_proc(pid, comm);
2639
2640 printf(" | ");
2641
2642 field = find_field(event, "rettime");
2643 if (!field)
2644 die("can't find rettime in return graph");
2645 rettime = read_size(data + field->offset, field->size);
2646
2647 field = find_field(event, "calltime");
2648 if (!field)
2649 die("can't find calltime in return graph");
2650 calltime = read_size(data + field->offset, field->size);
2651
2652 duration = rettime - calltime;
2653
2654 /* Overhead */
2655 print_graph_overhead(duration);
2656
2657 /* Duration */
2658 print_graph_duration(duration);
2659
2660 field = find_field(event, "depth");
2661 if (!field)
2662 die("can't find depth in entry graph");
2663 depth = read_size(data + field->offset, field->size);
2664
2665 /* Function */
2666 for (i = 0; i < (int)(depth * TRACE_GRAPH_INDENT); i++)
2667 printf(" ");
2668
2669 printf("}");
2670}
2671
2672static void
2673pretty_print_func_graph(void *data, int size, struct event *event,
2674 int cpu, int pid, const char *comm,
2675 unsigned long secs, unsigned long usecs)
2676{
2677 if (event->flags & EVENT_FL_ISFUNCENT)
2678 pretty_print_func_ent(data, size, event,
2679 cpu, pid, comm, secs, usecs);
2680 else if (event->flags & EVENT_FL_ISFUNCRET)
2681 pretty_print_func_ret(data, size, event,
2682 cpu, pid, comm, secs, usecs);
2683 printf("\n");
2684}
2685
2686void print_event(int cpu, void *data, int size, unsigned long long nsecs,
2687 char *comm)
2688{
2689 struct event *event;
2690 unsigned long secs;
2691 unsigned long usecs;
2692 int type;
2693 int pid;
2694
2695 secs = nsecs / NSECS_PER_SEC;
2696 nsecs -= secs * NSECS_PER_SEC;
2697 usecs = nsecs / NSECS_PER_USEC;
2698
2699 type = parse_common_type(data);
2700
2701 event = find_event(type);
2702 if (!event)
2703 die("ug! no event found for type %d", type);
2704
2705 pid = parse_common_pid(data);
2706
2707 if (event->flags & (EVENT_FL_ISFUNCENT | EVENT_FL_ISFUNCRET))
2708 return pretty_print_func_graph(data, size, event, cpu,
2709 pid, comm, secs, usecs);
2710
2711 printf("%16s-%-5d [%03d] %5lu.%09Lu: %s: ",
2712 comm, pid, cpu,
2713 secs, nsecs, event->name);
2714
2715 pretty_print(data, size, event);
2716 printf("\n");
2717}
2718
2719static void print_fields(struct print_flag_sym *field)
2720{
2721 printf("{ %s, %s }", field->value, field->str);
2722 if (field->next) {
2723 printf(", ");
2724 print_fields(field->next);
2725 }
2726}
2727
2728static void print_args(struct print_arg *args)
2729{
2730 int print_paren = 1;
2731
2732 switch (args->type) {
2733 case PRINT_NULL:
2734 printf("null");
2735 break;
2736 case PRINT_ATOM:
2737 printf("%s", args->atom.atom);
2738 break;
2739 case PRINT_FIELD:
2740 printf("REC->%s", args->field.name);
2741 break;
2742 case PRINT_FLAGS:
2743 printf("__print_flags(");
2744 print_args(args->flags.field);
2745 printf(", %s, ", args->flags.delim);
2746 print_fields(args->flags.flags);
2747 printf(")");
2748 break;
2749 case PRINT_SYMBOL:
2750 printf("__print_symbolic(");
2751 print_args(args->symbol.field);
2752 printf(", ");
2753 print_fields(args->symbol.symbols);
2754 printf(")");
2755 break;
2756 case PRINT_STRING:
2757 printf("__get_str(%s)", args->string.string);
2758 break;
2759 case PRINT_TYPE:
2760 printf("(%s)", args->typecast.type);
2761 print_args(args->typecast.item);
2762 break;
2763 case PRINT_OP:
2764 if (strcmp(args->op.op, ":") == 0)
2765 print_paren = 0;
2766 if (print_paren)
2767 printf("(");
2768 print_args(args->op.left);
2769 printf(" %s ", args->op.op);
2770 print_args(args->op.right);
2771 if (print_paren)
2772 printf(")");
2773 break;
2774 default:
2775 /* we should warn... */
2776 return;
2777 }
2778 if (args->next) {
2779 printf("\n");
2780 print_args(args->next);
2781 }
2782}
2783
2784static void parse_header_field(char *type,
2785 int *offset, int *size)
2786{
2787 char *token;
2788
2789 if (read_expected(EVENT_ITEM, (char *)"field") < 0)
2790 return;
2791 if (read_expected(EVENT_OP, (char *)":") < 0)
2792 return;
2793 /* type */
2794 if (read_expect_type(EVENT_ITEM, &token) < 0)
2795 return;
2796 free_token(token);
2797
2798 if (read_expected(EVENT_ITEM, type) < 0)
2799 return;
2800 if (read_expected(EVENT_OP, (char *)";") < 0)
2801 return;
2802 if (read_expected(EVENT_ITEM, (char *)"offset") < 0)
2803 return;
2804 if (read_expected(EVENT_OP, (char *)":") < 0)
2805 return;
2806 if (read_expect_type(EVENT_ITEM, &token) < 0)
2807 return;
2808 *offset = atoi(token);
2809 free_token(token);
2810 if (read_expected(EVENT_OP, (char *)";") < 0)
2811 return;
2812 if (read_expected(EVENT_ITEM, (char *)"size") < 0)
2813 return;
2814 if (read_expected(EVENT_OP, (char *)":") < 0)
2815 return;
2816 if (read_expect_type(EVENT_ITEM, &token) < 0)
2817 return;
2818 *size = atoi(token);
2819 free_token(token);
2820 if (read_expected(EVENT_OP, (char *)";") < 0)
2821 return;
2822 if (read_expect_type(EVENT_NEWLINE, &token) < 0)
2823 return;
2824 free_token(token);
2825}
2826
2827int parse_header_page(char *buf, unsigned long size)
2828{
2829 init_input_buf(buf, size);
2830
2831 parse_header_field((char *)"timestamp", &header_page_ts_offset,
2832 &header_page_ts_size);
2833 parse_header_field((char *)"commit", &header_page_size_offset,
2834 &header_page_size_size);
2835 parse_header_field((char *)"data", &header_page_data_offset,
2836 &header_page_data_size);
2837
2838 return 0;
2839}
2840
2841int parse_ftrace_file(char *buf, unsigned long size)
2842{
2843 struct format_field *field;
2844 struct print_arg *arg, **list;
2845 struct event *event;
2846 int ret;
2847
2848 init_input_buf(buf, size);
2849
2850 event = alloc_event();
2851 if (!event)
2852 return -ENOMEM;
2853
2854 event->flags |= EVENT_FL_ISFTRACE;
2855
2856 event->name = event_read_name();
2857 if (!event->name)
2858 die("failed to read ftrace event name");
2859
2860 if (strcmp(event->name, "function") == 0)
2861 event->flags |= EVENT_FL_ISFUNC;
2862
2863 else if (strcmp(event->name, "funcgraph_entry") == 0)
2864 event->flags |= EVENT_FL_ISFUNCENT;
2865
2866 else if (strcmp(event->name, "funcgraph_exit") == 0)
2867 event->flags |= EVENT_FL_ISFUNCRET;
2868
2869 else if (strcmp(event->name, "bprint") == 0)
2870 event->flags |= EVENT_FL_ISBPRINT;
2871
2872 event->id = event_read_id();
2873 if (event->id < 0)
2874 die("failed to read ftrace event id");
2875
2876 add_event(event);
2877
2878 ret = event_read_format(event);
2879 if (ret < 0)
2880 die("failed to read ftrace event format");
2881
2882 ret = event_read_print(event);
2883 if (ret < 0)
2884 die("failed to read ftrace event print fmt");
2885
2886 /*
2887 * The arguments for ftrace files are parsed by the fields.
2888 * Set up the fields as their arguments.
2889 */
2890 list = &event->print_fmt.args;
2891 for (field = event->format.fields; field; field = field->next) {
2892 arg = malloc_or_die(sizeof(*arg));
2893 memset(arg, 0, sizeof(*arg));
2894 *list = arg;
2895 list = &arg->next;
2896 arg->type = PRINT_FIELD;
2897 arg->field.name = field->name;
2898 arg->field.field = field;
2899 }
2900 return 0;
2901}
2902
2903int parse_event_file(char *buf, unsigned long size, char *system__unused __unused)
2904{
2905 struct event *event;
2906 int ret;
2907
2908 init_input_buf(buf, size);
2909
2910 event = alloc_event();
2911 if (!event)
2912 return -ENOMEM;
2913
2914 event->name = event_read_name();
2915 if (!event->name)
2916 die("failed to read event name");
2917
2918 event->id = event_read_id();
2919 if (event->id < 0)
2920 die("failed to read event id");
2921
2922 ret = event_read_format(event);
2923 if (ret < 0)
2924 die("failed to read event format");
2925
2926 ret = event_read_print(event);
2927 if (ret < 0)
2928 die("failed to read event print fmt");
2929
2930#define PRINT_ARGS 0
2931 if (PRINT_ARGS && event->print_fmt.args)
2932 print_args(event->print_fmt.args);
2933
2934 add_event(event);
2935 return 0;
2936}
2937
2938void parse_set_info(int nr_cpus, int long_sz)
2939{
2940 cpus = nr_cpus;
2941 long_size = long_sz;
2942}
diff --git a/tools/perf/util/trace-event-read.c b/tools/perf/util/trace-event-read.c
new file mode 100644
index 00000000000..a1217a10632
--- /dev/null
+++ b/tools/perf/util/trace-event-read.c
@@ -0,0 +1,512 @@
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_funcs = 0;
468 int show_printk = 0;
469
470 input_fd = open(input_file, O_RDONLY);
471 if (input_fd < 0)
472 die("opening '%s'\n", input_file);
473
474 read_or_die(buf, 3);
475 if (memcmp(buf, test, 3) != 0)
476 die("not an trace data file");
477
478 read_or_die(buf, 7);
479 if (memcmp(buf, "tracing", 7) != 0)
480 die("not a trace file (missing tracing)");
481
482 version = read_string();
483 printf("version = %s\n", version);
484 free(version);
485
486 read_or_die(buf, 1);
487 file_bigendian = buf[0];
488 host_bigendian = bigendian();
489
490 read_or_die(buf, 1);
491 long_size = buf[0];
492
493 page_size = read4();
494
495 read_header_files();
496
497 read_ftrace_files();
498 read_event_files();
499 read_proc_kallsyms();
500 read_ftrace_printk();
501
502 if (show_funcs) {
503 print_funcs();
504 return;
505 }
506 if (show_printk) {
507 print_printk();
508 return;
509 }
510
511 return;
512}
diff --git a/tools/perf/util/trace-event.h b/tools/perf/util/trace-event.h
new file mode 100644
index 00000000000..420294a5773
--- /dev/null
+++ b/tools/perf/util/trace-event.h
@@ -0,0 +1,240 @@
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);
237
238void read_tracing_data(struct perf_counter_attr *pattrs, int nb_counters);
239
240#endif /* _TRACE_EVENTS_H */
diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h
index 68fe157d72f..9de2329dd44 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 00000000000..1c15e39f99e
--- /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 00000000000..cadf8cf2a59
--- /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 */