blob: 9783d1e493c44d3d5cfe887d6b79e7f4bf2a2ea2 [file] [log] [blame]
Ingo Molnarbf9e1872009-06-02 23:37:05 +02001/*
2 * builtin-report.c
3 *
4 * Builtin report command: Analyze the perf.data input file,
5 * look up and read DSOs and symbol information and display
6 * a histogram of results, along various sorting keys.
7 */
Ingo Molnar16f762a2009-05-27 09:10:38 +02008#include "builtin.h"
Ingo Molnar53cb8bc2009-05-26 09:17:18 +02009
Ingo Molnarbf9e1872009-06-02 23:37:05 +020010#include "util/util.h"
11
Ingo Molnar8fc03212009-06-04 15:19:47 +020012#include "util/color.h"
Arnaldo Carvalho de Melo35a50c82009-05-18 16:24:49 -030013#include "util/list.h"
Ingo Molnara930d2c2009-05-27 09:50:13 +020014#include "util/cache.h"
Arnaldo Carvalho de Melo35a50c82009-05-18 16:24:49 -030015#include "util/rbtree.h"
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -030016#include "util/symbol.h"
Arnaldo Carvalho de Meloa0055ae2009-06-01 17:50:19 -030017#include "util/string.h"
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -030018
Ingo Molnar53cb8bc2009-05-26 09:17:18 +020019#include "perf.h"
20
21#include "util/parse-options.h"
22#include "util/parse-events.h"
23
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -030024#define SHOW_KERNEL 1
25#define SHOW_USER 2
26#define SHOW_HV 4
27
Ingo Molnar23ac9cb2009-05-27 09:33:18 +020028static char const *input_name = "perf.data";
Peter Zijlstra450aaa22009-05-27 20:20:23 +020029static char *vmlinux = NULL;
Ingo Molnarbd741372009-06-04 14:13:04 +020030
31static char default_sort_order[] = "comm,dso";
32static char *sort_order = default_sort_order;
33
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -030034static int input;
35static int show_mask = SHOW_KERNEL | SHOW_USER | SHOW_HV;
36
Ingo Molnar97b07b62009-05-26 18:48:58 +020037static int dump_trace = 0;
Ingo Molnar35029732009-06-03 09:38:58 +020038#define dprintf(x...) do { if (dump_trace) printf(x); } while (0)
39
Ingo Molnar16f762a2009-05-27 09:10:38 +020040static int verbose;
Arnaldo Carvalho de Melob78c07d2009-05-29 13:48:59 -030041static int full_paths;
Ingo Molnar97b07b62009-05-26 18:48:58 +020042
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -030043static unsigned long page_size;
44static unsigned long mmap_window = 32;
45
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -030046struct ip_event {
47 struct perf_event_header header;
48 __u64 ip;
49 __u32 pid, tid;
50};
Ingo Molnar75051722009-06-03 23:14:49 +020051
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -030052struct mmap_event {
53 struct perf_event_header header;
54 __u32 pid, tid;
55 __u64 start;
56 __u64 len;
57 __u64 pgoff;
58 char filename[PATH_MAX];
59};
Ingo Molnar75051722009-06-03 23:14:49 +020060
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -030061struct comm_event {
62 struct perf_event_header header;
Ingo Molnar75051722009-06-03 23:14:49 +020063 __u32 pid, tid;
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -030064 char comm[16];
65};
66
Peter Zijlstra62fc4452009-06-04 16:53:49 +020067struct fork_event {
68 struct perf_event_header header;
69 __u32 pid, ppid;
70};
71
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -030072typedef union event_union {
73 struct perf_event_header header;
74 struct ip_event ip;
75 struct mmap_event mmap;
76 struct comm_event comm;
Peter Zijlstra62fc4452009-06-04 16:53:49 +020077 struct fork_event fork;
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -030078} event_t;
79
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -030080static LIST_HEAD(dsos);
81static struct dso *kernel_dso;
Peter Zijlstrafc54db52009-06-05 14:04:59 +020082static struct dso *vdso;
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -030083
84static void dsos__add(struct dso *dso)
85{
86 list_add_tail(&dso->node, &dsos);
87}
88
89static struct dso *dsos__find(const char *name)
90{
91 struct dso *pos;
92
93 list_for_each_entry(pos, &dsos, node)
94 if (strcmp(pos->name, name) == 0)
95 return pos;
96 return NULL;
97}
98
99static struct dso *dsos__findnew(const char *name)
100{
101 struct dso *dso = dsos__find(name);
Peter Zijlstrab7a16ea2009-05-27 13:35:35 +0200102 int nr;
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300103
Ingo Molnar4593bba2009-06-02 15:34:25 +0200104 if (dso)
105 return dso;
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300106
Ingo Molnar4593bba2009-06-02 15:34:25 +0200107 dso = dso__new(name, 0);
108 if (!dso)
109 goto out_delete_dso;
Peter Zijlstrab7a16ea2009-05-27 13:35:35 +0200110
Ingo Molnarbd741372009-06-04 14:13:04 +0200111 nr = dso__load(dso, NULL, verbose);
Ingo Molnar4593bba2009-06-02 15:34:25 +0200112 if (nr < 0) {
Ingo Molnarbd741372009-06-04 14:13:04 +0200113 if (verbose)
114 fprintf(stderr, "Failed to open: %s\n", name);
Ingo Molnar4593bba2009-06-02 15:34:25 +0200115 goto out_delete_dso;
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300116 }
Ingo Molnar4593bba2009-06-02 15:34:25 +0200117 if (!nr && verbose) {
118 fprintf(stderr,
119 "No symbols found in: %s, maybe install a debug package?\n",
120 name);
121 }
122
123 dsos__add(dso);
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300124
125 return dso;
126
127out_delete_dso:
128 dso__delete(dso);
129 return NULL;
130}
131
Ingo Molnar16f762a2009-05-27 09:10:38 +0200132static void dsos__fprintf(FILE *fp)
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300133{
134 struct dso *pos;
135
136 list_for_each_entry(pos, &dsos, node)
137 dso__fprintf(pos, fp);
138}
139
Peter Zijlstrafc54db52009-06-05 14:04:59 +0200140static struct symbol *vdso__find_symbol(struct dso *dso, uint64_t ip)
141{
142 return dso__find_symbol(kernel_dso, ip);
143}
144
Peter Zijlstra450aaa22009-05-27 20:20:23 +0200145static int load_kernel(void)
146{
Arnaldo Carvalho de Meloa827c872009-05-28 14:55:19 -0300147 int err;
Peter Zijlstra450aaa22009-05-27 20:20:23 +0200148
Arnaldo Carvalho de Melo0085c952009-05-28 14:55:13 -0300149 kernel_dso = dso__new("[kernel]", 0);
Peter Zijlstra450aaa22009-05-27 20:20:23 +0200150 if (!kernel_dso)
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300151 return -1;
Peter Zijlstra450aaa22009-05-27 20:20:23 +0200152
Ingo Molnarbd741372009-06-04 14:13:04 +0200153 err = dso__load_kernel(kernel_dso, vmlinux, NULL, verbose);
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300154 if (err) {
155 dso__delete(kernel_dso);
156 kernel_dso = NULL;
157 } else
158 dsos__add(kernel_dso);
Peter Zijlstra450aaa22009-05-27 20:20:23 +0200159
Peter Zijlstrafc54db52009-06-05 14:04:59 +0200160 vdso = dso__new("[vdso]", 0);
161 if (!vdso)
162 return -1;
163
164 vdso->find_symbol = vdso__find_symbol;
165
166 dsos__add(vdso);
167
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300168 return err;
Peter Zijlstra450aaa22009-05-27 20:20:23 +0200169}
170
Ingo Molnard80d3382009-06-03 23:14:49 +0200171static char __cwd[PATH_MAX];
172static char *cwd = __cwd;
173static int cwdlen;
174
175static int strcommon(const char *pathname)
Arnaldo Carvalho de Melob78c07d2009-05-29 13:48:59 -0300176{
177 int n = 0;
178
179 while (pathname[n] == cwd[n] && n < cwdlen)
180 ++n;
181
182 return n;
183}
184
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300185struct map {
186 struct list_head node;
187 uint64_t start;
188 uint64_t end;
189 uint64_t pgoff;
Peter Zijlstrafc54db52009-06-05 14:04:59 +0200190 uint64_t (*map_ip)(struct map *, uint64_t);
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300191 struct dso *dso;
192};
193
Peter Zijlstrafc54db52009-06-05 14:04:59 +0200194static uint64_t map__map_ip(struct map *map, uint64_t ip)
195{
196 return ip - map->start + map->pgoff;
197}
198
199static uint64_t vdso__map_ip(struct map *map, uint64_t ip)
200{
201 return ip;
202}
203
Ingo Molnard80d3382009-06-03 23:14:49 +0200204static struct map *map__new(struct mmap_event *event)
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300205{
206 struct map *self = malloc(sizeof(*self));
207
208 if (self != NULL) {
Arnaldo Carvalho de Melob78c07d2009-05-29 13:48:59 -0300209 const char *filename = event->filename;
210 char newfilename[PATH_MAX];
211
212 if (cwd) {
Ingo Molnard80d3382009-06-03 23:14:49 +0200213 int n = strcommon(filename);
214
Arnaldo Carvalho de Melob78c07d2009-05-29 13:48:59 -0300215 if (n == cwdlen) {
216 snprintf(newfilename, sizeof(newfilename),
217 ".%s", filename + n);
218 filename = newfilename;
219 }
220 }
221
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300222 self->start = event->start;
223 self->end = event->start + event->len;
224 self->pgoff = event->pgoff;
225
Arnaldo Carvalho de Melob78c07d2009-05-29 13:48:59 -0300226 self->dso = dsos__findnew(filename);
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300227 if (self->dso == NULL)
228 goto out_delete;
Peter Zijlstrafc54db52009-06-05 14:04:59 +0200229
230 if (self->dso == vdso)
231 self->map_ip = vdso__map_ip;
232 else
233 self->map_ip = map__map_ip;
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300234 }
235 return self;
236out_delete:
237 free(self);
238 return NULL;
239}
240
Peter Zijlstra62fc4452009-06-04 16:53:49 +0200241static struct map *map__clone(struct map *self)
242{
243 struct map *map = malloc(sizeof(*self));
244
245 if (!map)
246 return NULL;
247
248 memcpy(map, self, sizeof(*self));
249
250 return map;
251}
252
253static int map__overlap(struct map *l, struct map *r)
254{
255 if (l->start > r->start) {
256 struct map *t = l;
257 l = r;
258 r = t;
259 }
260
261 if (l->end > r->start)
262 return 1;
263
264 return 0;
265}
Arnaldo Carvalho de Melo3a4b8cc2009-05-26 16:19:04 -0300266
Arnaldo Carvalho de Melo9ac99542009-06-04 13:54:00 -0300267static size_t map__fprintf(struct map *self, FILE *fp)
268{
Yong Wangee7b31f2009-06-05 11:37:35 +0800269 return fprintf(fp, " %"PRIx64"-%"PRIx64" %"PRIx64" %s\n",
Arnaldo Carvalho de Melo9ac99542009-06-04 13:54:00 -0300270 self->start, self->end, self->pgoff, self->dso->name);
271}
272
273
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300274struct thread {
Arnaldo Carvalho de Meloce7e4362009-05-19 09:30:23 -0300275 struct rb_node rb_node;
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300276 struct list_head maps;
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300277 pid_t pid;
278 char *comm;
279};
280
281static struct thread *thread__new(pid_t pid)
282{
283 struct thread *self = malloc(sizeof(*self));
284
285 if (self != NULL) {
286 self->pid = pid;
Peter Zijlstra82292892009-06-03 12:37:36 +0200287 self->comm = malloc(32);
Ingo Molnar0a520c62009-06-02 23:24:45 +0200288 if (self->comm)
Peter Zijlstra82292892009-06-03 12:37:36 +0200289 snprintf(self->comm, 32, ":%d", self->pid);
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300290 INIT_LIST_HEAD(&self->maps);
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300291 }
292
293 return self;
294}
295
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300296static int thread__set_comm(struct thread *self, const char *comm)
297{
Peter Zijlstra82292892009-06-03 12:37:36 +0200298 if (self->comm)
299 free(self->comm);
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300300 self->comm = strdup(comm);
301 return self->comm ? 0 : -ENOMEM;
302}
303
Arnaldo Carvalho de Melo9ac99542009-06-04 13:54:00 -0300304static size_t thread__fprintf(struct thread *self, FILE *fp)
305{
306 struct map *pos;
307 size_t ret = fprintf(fp, "Thread %d %s\n", self->pid, self->comm);
308
309 list_for_each_entry(pos, &self->maps, node)
310 ret += map__fprintf(pos, fp);
311
312 return ret;
313}
314
315
Ingo Molnar16f762a2009-05-27 09:10:38 +0200316static struct rb_root threads;
Ingo Molnareed4dcd2009-06-03 19:59:24 +0200317static struct thread *last_match;
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300318
319static struct thread *threads__findnew(pid_t pid)
320{
Arnaldo Carvalho de Meloce7e4362009-05-19 09:30:23 -0300321 struct rb_node **p = &threads.rb_node;
322 struct rb_node *parent = NULL;
323 struct thread *th;
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300324
Ingo Molnareed4dcd2009-06-03 19:59:24 +0200325 /*
326 * Font-end cache - PID lookups come in blocks,
327 * so most of the time we dont have to look up
328 * the full rbtree:
329 */
330 if (last_match && last_match->pid == pid)
331 return last_match;
332
Arnaldo Carvalho de Meloce7e4362009-05-19 09:30:23 -0300333 while (*p != NULL) {
334 parent = *p;
335 th = rb_entry(parent, struct thread, rb_node);
336
Ingo Molnareed4dcd2009-06-03 19:59:24 +0200337 if (th->pid == pid) {
338 last_match = th;
Arnaldo Carvalho de Meloce7e4362009-05-19 09:30:23 -0300339 return th;
Ingo Molnareed4dcd2009-06-03 19:59:24 +0200340 }
Arnaldo Carvalho de Meloce7e4362009-05-19 09:30:23 -0300341
342 if (pid < th->pid)
343 p = &(*p)->rb_left;
344 else
345 p = &(*p)->rb_right;
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300346 }
347
Arnaldo Carvalho de Meloce7e4362009-05-19 09:30:23 -0300348 th = thread__new(pid);
349 if (th != NULL) {
350 rb_link_node(&th->rb_node, parent, p);
351 rb_insert_color(&th->rb_node, &threads);
Ingo Molnareed4dcd2009-06-03 19:59:24 +0200352 last_match = th;
Arnaldo Carvalho de Meloce7e4362009-05-19 09:30:23 -0300353 }
Ingo Molnareed4dcd2009-06-03 19:59:24 +0200354
Arnaldo Carvalho de Meloce7e4362009-05-19 09:30:23 -0300355 return th;
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300356}
357
358static void thread__insert_map(struct thread *self, struct map *map)
359{
Peter Zijlstra62fc4452009-06-04 16:53:49 +0200360 struct map *pos, *tmp;
361
362 list_for_each_entry_safe(pos, tmp, &self->maps, node) {
363 if (map__overlap(pos, map)) {
364 list_del_init(&pos->node);
365 /* XXX leaks dsos */
366 free(pos);
367 }
368 }
369
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300370 list_add_tail(&map->node, &self->maps);
371}
372
Peter Zijlstra62fc4452009-06-04 16:53:49 +0200373static int thread__fork(struct thread *self, struct thread *parent)
374{
375 struct map *map;
376
377 if (self->comm)
378 free(self->comm);
379 self->comm = strdup(parent->comm);
380 if (!self->comm)
381 return -ENOMEM;
382
383 list_for_each_entry(map, &parent->maps, node) {
384 struct map *new = map__clone(map);
385 if (!new)
386 return -ENOMEM;
387 thread__insert_map(self, new);
388 }
389
390 return 0;
391}
392
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300393static struct map *thread__find_map(struct thread *self, uint64_t ip)
394{
Ingo Molnar16f762a2009-05-27 09:10:38 +0200395 struct map *pos;
396
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300397 if (self == NULL)
398 return NULL;
399
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300400 list_for_each_entry(pos, &self->maps, node)
401 if (ip >= pos->start && ip <= pos->end)
402 return pos;
403
404 return NULL;
405}
406
Arnaldo Carvalho de Melo9ac99542009-06-04 13:54:00 -0300407static size_t threads__fprintf(FILE *fp)
408{
409 size_t ret = 0;
410 struct rb_node *nd;
411
412 for (nd = rb_first(&threads); nd; nd = rb_next(nd)) {
413 struct thread *pos = rb_entry(nd, struct thread, rb_node);
414
415 ret += thread__fprintf(pos, fp);
416 }
417
418 return ret;
419}
420
Peter Zijlstrae7fb08b2009-05-27 20:20:24 +0200421/*
422 * histogram, sorted on item, collects counts
423 */
424
425static struct rb_root hist;
426
427struct hist_entry {
428 struct rb_node rb_node;
429
430 struct thread *thread;
431 struct map *map;
432 struct dso *dso;
433 struct symbol *sym;
434 uint64_t ip;
435 char level;
436
437 uint32_t count;
438};
439
Peter Zijlstra1aa16732009-05-27 20:20:25 +0200440/*
441 * configurable sorting bits
442 */
443
444struct sort_entry {
445 struct list_head list;
446
Peter Zijlstraca8cdee2009-05-28 11:08:33 +0200447 char *header;
448
Peter Zijlstra1aa16732009-05-27 20:20:25 +0200449 int64_t (*cmp)(struct hist_entry *, struct hist_entry *);
Peter Zijlstra82292892009-06-03 12:37:36 +0200450 int64_t (*collapse)(struct hist_entry *, struct hist_entry *);
Peter Zijlstra1aa16732009-05-27 20:20:25 +0200451 size_t (*print)(FILE *fp, struct hist_entry *);
452};
453
Peter Zijlstra82292892009-06-03 12:37:36 +0200454/* --sort pid */
455
Peter Zijlstrae7fb08b2009-05-27 20:20:24 +0200456static int64_t
Peter Zijlstra1aa16732009-05-27 20:20:25 +0200457sort__thread_cmp(struct hist_entry *left, struct hist_entry *right)
458{
459 return right->thread->pid - left->thread->pid;
460}
461
462static size_t
463sort__thread_print(FILE *fp, struct hist_entry *self)
464{
Peter Zijlstra71dd8942009-06-04 15:16:56 +0200465 return fprintf(fp, "%16s:%5d", self->thread->comm ?: "", self->thread->pid);
Peter Zijlstra1aa16732009-05-27 20:20:25 +0200466}
467
468static struct sort_entry sort_thread = {
Peter Zijlstra71dd8942009-06-04 15:16:56 +0200469 .header = " Command: Pid",
Peter Zijlstra1aa16732009-05-27 20:20:25 +0200470 .cmp = sort__thread_cmp,
471 .print = sort__thread_print,
472};
473
Peter Zijlstra82292892009-06-03 12:37:36 +0200474/* --sort comm */
475
Peter Zijlstra1aa16732009-05-27 20:20:25 +0200476static int64_t
Peter Zijlstra992444b2009-05-27 20:20:27 +0200477sort__comm_cmp(struct hist_entry *left, struct hist_entry *right)
478{
Peter Zijlstra82292892009-06-03 12:37:36 +0200479 return right->thread->pid - left->thread->pid;
480}
481
482static int64_t
483sort__comm_collapse(struct hist_entry *left, struct hist_entry *right)
484{
Peter Zijlstra992444b2009-05-27 20:20:27 +0200485 char *comm_l = left->thread->comm;
486 char *comm_r = right->thread->comm;
487
488 if (!comm_l || !comm_r) {
489 if (!comm_l && !comm_r)
490 return 0;
491 else if (!comm_l)
492 return -1;
493 else
494 return 1;
495 }
496
497 return strcmp(comm_l, comm_r);
498}
499
500static size_t
501sort__comm_print(FILE *fp, struct hist_entry *self)
502{
Peter Zijlstra71dd8942009-06-04 15:16:56 +0200503 return fprintf(fp, "%16s", self->thread->comm);
Peter Zijlstra992444b2009-05-27 20:20:27 +0200504}
505
506static struct sort_entry sort_comm = {
Peter Zijlstra71dd8942009-06-04 15:16:56 +0200507 .header = " Command",
Peter Zijlstra82292892009-06-03 12:37:36 +0200508 .cmp = sort__comm_cmp,
509 .collapse = sort__comm_collapse,
510 .print = sort__comm_print,
Peter Zijlstra992444b2009-05-27 20:20:27 +0200511};
512
Peter Zijlstra82292892009-06-03 12:37:36 +0200513/* --sort dso */
514
Peter Zijlstra992444b2009-05-27 20:20:27 +0200515static int64_t
Peter Zijlstra55e5ec42009-05-27 20:20:28 +0200516sort__dso_cmp(struct hist_entry *left, struct hist_entry *right)
517{
518 struct dso *dso_l = left->dso;
519 struct dso *dso_r = right->dso;
520
521 if (!dso_l || !dso_r) {
522 if (!dso_l && !dso_r)
523 return 0;
524 else if (!dso_l)
525 return -1;
526 else
527 return 1;
528 }
529
530 return strcmp(dso_l->name, dso_r->name);
531}
532
533static size_t
534sort__dso_print(FILE *fp, struct hist_entry *self)
535{
Ingo Molnar0a520c62009-06-02 23:24:45 +0200536 if (self->dso)
Peter Zijlstra71dd8942009-06-04 15:16:56 +0200537 return fprintf(fp, "%-25s", self->dso->name);
Ingo Molnar0a520c62009-06-02 23:24:45 +0200538
Peter Zijlstra71dd8942009-06-04 15:16:56 +0200539 return fprintf(fp, "%016llx ", (__u64)self->ip);
Peter Zijlstra55e5ec42009-05-27 20:20:28 +0200540}
541
542static struct sort_entry sort_dso = {
Peter Zijlstra71dd8942009-06-04 15:16:56 +0200543 .header = "Shared Object ",
Peter Zijlstra55e5ec42009-05-27 20:20:28 +0200544 .cmp = sort__dso_cmp,
545 .print = sort__dso_print,
546};
547
Peter Zijlstra82292892009-06-03 12:37:36 +0200548/* --sort symbol */
549
Peter Zijlstra55e5ec42009-05-27 20:20:28 +0200550static int64_t
Peter Zijlstra1aa16732009-05-27 20:20:25 +0200551sort__sym_cmp(struct hist_entry *left, struct hist_entry *right)
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300552{
Peter Zijlstrae7fb08b2009-05-27 20:20:24 +0200553 uint64_t ip_l, ip_r;
Peter Zijlstrae7fb08b2009-05-27 20:20:24 +0200554
555 if (left->sym == right->sym)
556 return 0;
557
558 ip_l = left->sym ? left->sym->start : left->ip;
559 ip_r = right->sym ? right->sym->start : right->ip;
560
561 return (int64_t)(ip_r - ip_l);
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300562}
563
Peter Zijlstra1aa16732009-05-27 20:20:25 +0200564static size_t
565sort__sym_print(FILE *fp, struct hist_entry *self)
566{
567 size_t ret = 0;
568
Peter Zijlstra1aa16732009-05-27 20:20:25 +0200569 if (verbose)
Peter Zijlstra71dd8942009-06-04 15:16:56 +0200570 ret += fprintf(fp, "%#018llx ", (__u64)self->ip);
Peter Zijlstra1aa16732009-05-27 20:20:25 +0200571
Ingo Molnar0a520c62009-06-02 23:24:45 +0200572 if (self->sym)
Peter Zijlstra71dd8942009-06-04 15:16:56 +0200573 ret += fprintf(fp, "%s", self->sym->name);
Ingo Molnar0a520c62009-06-02 23:24:45 +0200574 else
Peter Zijlstra71dd8942009-06-04 15:16:56 +0200575 ret += fprintf(fp, "%#016llx", (__u64)self->ip);
Peter Zijlstra1aa16732009-05-27 20:20:25 +0200576
577 return ret;
578}
579
580static struct sort_entry sort_sym = {
Peter Zijlstra71dd8942009-06-04 15:16:56 +0200581 .header = "Symbol",
Peter Zijlstraca8cdee2009-05-28 11:08:33 +0200582 .cmp = sort__sym_cmp,
583 .print = sort__sym_print,
Peter Zijlstra1aa16732009-05-27 20:20:25 +0200584};
585
Peter Zijlstra82292892009-06-03 12:37:36 +0200586static int sort__need_collapse = 0;
587
Peter Zijlstra37f440c2009-05-27 20:20:26 +0200588struct sort_dimension {
589 char *name;
590 struct sort_entry *entry;
591 int taken;
592};
593
594static struct sort_dimension sort_dimensions[] = {
595 { .name = "pid", .entry = &sort_thread, },
Peter Zijlstra992444b2009-05-27 20:20:27 +0200596 { .name = "comm", .entry = &sort_comm, },
Peter Zijlstra55e5ec42009-05-27 20:20:28 +0200597 { .name = "dso", .entry = &sort_dso, },
Peter Zijlstra37f440c2009-05-27 20:20:26 +0200598 { .name = "symbol", .entry = &sort_sym, },
599};
600
Peter Zijlstra1aa16732009-05-27 20:20:25 +0200601static LIST_HEAD(hist_entry__sort_list);
602
Peter Zijlstra37f440c2009-05-27 20:20:26 +0200603static int sort_dimension__add(char *tok)
604{
605 int i;
606
607 for (i = 0; i < ARRAY_SIZE(sort_dimensions); i++) {
608 struct sort_dimension *sd = &sort_dimensions[i];
609
610 if (sd->taken)
611 continue;
612
Ingo Molnar5352f352009-06-03 10:07:39 +0200613 if (strncasecmp(tok, sd->name, strlen(tok)))
Peter Zijlstra37f440c2009-05-27 20:20:26 +0200614 continue;
615
Peter Zijlstra82292892009-06-03 12:37:36 +0200616 if (sd->entry->collapse)
617 sort__need_collapse = 1;
618
Peter Zijlstra37f440c2009-05-27 20:20:26 +0200619 list_add_tail(&sd->entry->list, &hist_entry__sort_list);
620 sd->taken = 1;
Ingo Molnar5352f352009-06-03 10:07:39 +0200621
Peter Zijlstra37f440c2009-05-27 20:20:26 +0200622 return 0;
623 }
624
625 return -ESRCH;
626}
627
Peter Zijlstra1aa16732009-05-27 20:20:25 +0200628static int64_t
629hist_entry__cmp(struct hist_entry *left, struct hist_entry *right)
630{
631 struct sort_entry *se;
632 int64_t cmp = 0;
633
634 list_for_each_entry(se, &hist_entry__sort_list, list) {
635 cmp = se->cmp(left, right);
636 if (cmp)
637 break;
638 }
639
640 return cmp;
641}
642
Peter Zijlstra82292892009-06-03 12:37:36 +0200643static int64_t
644hist_entry__collapse(struct hist_entry *left, struct hist_entry *right)
645{
646 struct sort_entry *se;
647 int64_t cmp = 0;
648
649 list_for_each_entry(se, &hist_entry__sort_list, list) {
650 int64_t (*f)(struct hist_entry *, struct hist_entry *);
651
652 f = se->collapse ?: se->cmp;
653
654 cmp = f(left, right);
655 if (cmp)
656 break;
657 }
658
659 return cmp;
660}
661
Peter Zijlstra1aa16732009-05-27 20:20:25 +0200662static size_t
663hist_entry__fprintf(FILE *fp, struct hist_entry *self, uint64_t total_samples)
664{
665 struct sort_entry *se;
666 size_t ret;
667
668 if (total_samples) {
Ingo Molnar8fc03212009-06-04 15:19:47 +0200669 double percent = self->count * 100.0 / total_samples;
670 char *color = PERF_COLOR_NORMAL;
671
672 /*
673 * We color high-overhead entries in red, low-overhead
674 * entries in green - and keep the middle ground normal:
675 */
676 if (percent >= 5.0)
677 color = PERF_COLOR_RED;
678 if (percent < 0.5)
679 color = PERF_COLOR_GREEN;
680
681 ret = color_fprintf(fp, color, " %6.2f%%",
Peter Zijlstra1aa16732009-05-27 20:20:25 +0200682 (self->count * 100.0) / total_samples);
683 } else
684 ret = fprintf(fp, "%12d ", self->count);
685
Peter Zijlstra71dd8942009-06-04 15:16:56 +0200686 list_for_each_entry(se, &hist_entry__sort_list, list) {
687 fprintf(fp, " ");
Peter Zijlstra1aa16732009-05-27 20:20:25 +0200688 ret += se->print(fp, self);
Peter Zijlstra71dd8942009-06-04 15:16:56 +0200689 }
Peter Zijlstra1aa16732009-05-27 20:20:25 +0200690
691 ret += fprintf(fp, "\n");
692
693 return ret;
694}
695
696/*
697 * collect histogram counts
698 */
699
Peter Zijlstrae7fb08b2009-05-27 20:20:24 +0200700static int
701hist_entry__add(struct thread *thread, struct map *map, struct dso *dso,
702 struct symbol *sym, uint64_t ip, char level)
Arnaldo Carvalho de Melo3a4b8cc2009-05-26 16:19:04 -0300703{
Peter Zijlstrae7fb08b2009-05-27 20:20:24 +0200704 struct rb_node **p = &hist.rb_node;
Arnaldo Carvalho de Melo3a4b8cc2009-05-26 16:19:04 -0300705 struct rb_node *parent = NULL;
Peter Zijlstrae7fb08b2009-05-27 20:20:24 +0200706 struct hist_entry *he;
707 struct hist_entry entry = {
708 .thread = thread,
709 .map = map,
710 .dso = dso,
711 .sym = sym,
712 .ip = ip,
713 .level = level,
714 .count = 1,
715 };
716 int cmp;
Arnaldo Carvalho de Melo3a4b8cc2009-05-26 16:19:04 -0300717
718 while (*p != NULL) {
719 parent = *p;
Peter Zijlstrae7fb08b2009-05-27 20:20:24 +0200720 he = rb_entry(parent, struct hist_entry, rb_node);
Arnaldo Carvalho de Melo3a4b8cc2009-05-26 16:19:04 -0300721
Peter Zijlstrae7fb08b2009-05-27 20:20:24 +0200722 cmp = hist_entry__cmp(&entry, he);
723
724 if (!cmp) {
725 he->count++;
726 return 0;
727 }
728
729 if (cmp < 0)
Arnaldo Carvalho de Melo3a4b8cc2009-05-26 16:19:04 -0300730 p = &(*p)->rb_left;
731 else
732 p = &(*p)->rb_right;
733 }
734
Peter Zijlstrae7fb08b2009-05-27 20:20:24 +0200735 he = malloc(sizeof(*he));
736 if (!he)
737 return -ENOMEM;
738 *he = entry;
739 rb_link_node(&he->rb_node, parent, p);
740 rb_insert_color(&he->rb_node, &hist);
741
742 return 0;
Arnaldo Carvalho de Melo3a4b8cc2009-05-26 16:19:04 -0300743}
744
Peter Zijlstra82292892009-06-03 12:37:36 +0200745static void hist_entry__free(struct hist_entry *he)
746{
747 free(he);
748}
749
750/*
751 * collapse the histogram
752 */
753
754static struct rb_root collapse_hists;
755
756static void collapse__insert_entry(struct hist_entry *he)
757{
758 struct rb_node **p = &collapse_hists.rb_node;
759 struct rb_node *parent = NULL;
760 struct hist_entry *iter;
761 int64_t cmp;
762
763 while (*p != NULL) {
764 parent = *p;
765 iter = rb_entry(parent, struct hist_entry, rb_node);
766
767 cmp = hist_entry__collapse(iter, he);
768
769 if (!cmp) {
770 iter->count += he->count;
771 hist_entry__free(he);
772 return;
773 }
774
775 if (cmp < 0)
776 p = &(*p)->rb_left;
777 else
778 p = &(*p)->rb_right;
779 }
780
781 rb_link_node(&he->rb_node, parent, p);
782 rb_insert_color(&he->rb_node, &collapse_hists);
783}
784
785static void collapse__resort(void)
786{
787 struct rb_node *next;
788 struct hist_entry *n;
789
790 if (!sort__need_collapse)
791 return;
792
793 next = rb_first(&hist);
794 while (next) {
795 n = rb_entry(next, struct hist_entry, rb_node);
796 next = rb_next(&n->rb_node);
797
798 rb_erase(&n->rb_node, &hist);
799 collapse__insert_entry(n);
800 }
801}
802
Peter Zijlstrae7fb08b2009-05-27 20:20:24 +0200803/*
804 * reverse the map, sort on count.
805 */
806
807static struct rb_root output_hists;
808
809static void output__insert_entry(struct hist_entry *he)
810{
811 struct rb_node **p = &output_hists.rb_node;
812 struct rb_node *parent = NULL;
813 struct hist_entry *iter;
814
815 while (*p != NULL) {
816 parent = *p;
817 iter = rb_entry(parent, struct hist_entry, rb_node);
818
819 if (he->count > iter->count)
820 p = &(*p)->rb_left;
821 else
822 p = &(*p)->rb_right;
823 }
824
825 rb_link_node(&he->rb_node, parent, p);
826 rb_insert_color(&he->rb_node, &output_hists);
827}
828
829static void output__resort(void)
830{
Peter Zijlstra82292892009-06-03 12:37:36 +0200831 struct rb_node *next;
Peter Zijlstrae7fb08b2009-05-27 20:20:24 +0200832 struct hist_entry *n;
Arnaldo Carvalho de Meloa4c43be2009-06-03 23:02:33 -0300833 struct rb_root *tree = &hist;
Peter Zijlstrae7fb08b2009-05-27 20:20:24 +0200834
Peter Zijlstra82292892009-06-03 12:37:36 +0200835 if (sort__need_collapse)
Arnaldo Carvalho de Meloa4c43be2009-06-03 23:02:33 -0300836 tree = &collapse_hists;
837
838 next = rb_first(tree);
Peter Zijlstra82292892009-06-03 12:37:36 +0200839
Peter Zijlstrae7fb08b2009-05-27 20:20:24 +0200840 while (next) {
841 n = rb_entry(next, struct hist_entry, rb_node);
842 next = rb_next(&n->rb_node);
843
Arnaldo Carvalho de Meloa4c43be2009-06-03 23:02:33 -0300844 rb_erase(&n->rb_node, tree);
Peter Zijlstrae7fb08b2009-05-27 20:20:24 +0200845 output__insert_entry(n);
Arnaldo Carvalho de Melo3a4b8cc2009-05-26 16:19:04 -0300846 }
847}
848
Peter Zijlstrae7fb08b2009-05-27 20:20:24 +0200849static size_t output__fprintf(FILE *fp, uint64_t total_samples)
Arnaldo Carvalho de Melo3a4b8cc2009-05-26 16:19:04 -0300850{
Peter Zijlstrae7fb08b2009-05-27 20:20:24 +0200851 struct hist_entry *pos;
Ingo Molnar2d655372009-05-27 21:36:22 +0200852 struct sort_entry *se;
Arnaldo Carvalho de Melo3a4b8cc2009-05-26 16:19:04 -0300853 struct rb_node *nd;
854 size_t ret = 0;
855
Peter Zijlstra71dd8942009-06-04 15:16:56 +0200856 fprintf(fp, "\n");
Peter Zijlstraca8cdee2009-05-28 11:08:33 +0200857 fprintf(fp, "#\n");
Ingo Molnar05ca0612009-06-04 14:21:16 +0200858 fprintf(fp, "# (%Ld profiler events)\n", (__u64)total_samples);
859 fprintf(fp, "#\n");
Peter Zijlstraca8cdee2009-05-28 11:08:33 +0200860
861 fprintf(fp, "# Overhead");
862 list_for_each_entry(se, &hist_entry__sort_list, list)
Peter Zijlstra71dd8942009-06-04 15:16:56 +0200863 fprintf(fp, " %s", se->header);
Peter Zijlstraca8cdee2009-05-28 11:08:33 +0200864 fprintf(fp, "\n");
865
866 fprintf(fp, "# ........");
Ingo Molnar2d655372009-05-27 21:36:22 +0200867 list_for_each_entry(se, &hist_entry__sort_list, list) {
Peter Zijlstraca8cdee2009-05-28 11:08:33 +0200868 int i;
869
Ingo Molnar4593bba2009-06-02 15:34:25 +0200870 fprintf(fp, " ");
Peter Zijlstra71dd8942009-06-04 15:16:56 +0200871 for (i = 0; i < strlen(se->header); i++)
Peter Zijlstraca8cdee2009-05-28 11:08:33 +0200872 fprintf(fp, ".");
Ingo Molnar2d655372009-05-27 21:36:22 +0200873 }
Peter Zijlstraca8cdee2009-05-28 11:08:33 +0200874 fprintf(fp, "\n");
875
876 fprintf(fp, "#\n");
Ingo Molnar2d655372009-05-27 21:36:22 +0200877
Peter Zijlstrae7fb08b2009-05-27 20:20:24 +0200878 for (nd = rb_first(&output_hists); nd; nd = rb_next(nd)) {
879 pos = rb_entry(nd, struct hist_entry, rb_node);
880 ret += hist_entry__fprintf(fp, pos, total_samples);
Arnaldo Carvalho de Melo3a4b8cc2009-05-26 16:19:04 -0300881 }
882
Ingo Molnarbd741372009-06-04 14:13:04 +0200883 if (!strcmp(sort_order, default_sort_order)) {
884 fprintf(fp, "#\n");
Peter Zijlstra71dd8942009-06-04 15:16:56 +0200885 fprintf(fp, "# (For more details, try: perf report --sort comm,dso,symbol)\n");
Ingo Molnarbd741372009-06-04 14:13:04 +0200886 fprintf(fp, "#\n");
887 }
Peter Zijlstra71dd8942009-06-04 15:16:56 +0200888 fprintf(fp, "\n");
Ingo Molnarbd741372009-06-04 14:13:04 +0200889
Arnaldo Carvalho de Melo3a4b8cc2009-05-26 16:19:04 -0300890 return ret;
891}
892
Peter Zijlstra436224a2009-06-02 21:02:36 +0200893static void register_idle_thread(void)
894{
895 struct thread *thread = threads__findnew(0);
896
897 if (thread == NULL ||
898 thread__set_comm(thread, "[idle]")) {
899 fprintf(stderr, "problem inserting idle task.\n");
900 exit(-1);
901 }
902}
903
Peter Zijlstra62fc4452009-06-04 16:53:49 +0200904static unsigned long total = 0,
905 total_mmap = 0,
906 total_comm = 0,
907 total_fork = 0,
908 total_unknown = 0;
Peter Zijlstrae7fb08b2009-05-27 20:20:24 +0200909
Ingo Molnard80d3382009-06-03 23:14:49 +0200910static int
Ingo Molnar75051722009-06-03 23:14:49 +0200911process_overflow_event(event_t *event, unsigned long offset, unsigned long head)
912{
913 char level;
914 int show = 0;
915 struct dso *dso = NULL;
916 struct thread *thread = threads__findnew(event->ip.pid);
917 uint64_t ip = event->ip.ip;
918 struct map *map = NULL;
919
920 dprintf("%p [%p]: PERF_EVENT (IP, %d): %d: %p\n",
921 (void *)(offset + head),
922 (void *)(long)(event->header.size),
923 event->header.misc,
924 event->ip.pid,
925 (void *)(long)ip);
926
927 dprintf(" ... thread: %s:%d\n", thread->comm, thread->pid);
928
929 if (thread == NULL) {
930 fprintf(stderr, "problem processing %d event, skipping it.\n",
931 event->header.type);
932 return -1;
933 }
934
935 if (event->header.misc & PERF_EVENT_MISC_KERNEL) {
936 show = SHOW_KERNEL;
937 level = 'k';
938
939 dso = kernel_dso;
940
941 dprintf(" ...... dso: %s\n", dso->name);
942
943 } else if (event->header.misc & PERF_EVENT_MISC_USER) {
944
945 show = SHOW_USER;
946 level = '.';
947
948 map = thread__find_map(thread, ip);
949 if (map != NULL) {
Peter Zijlstrafc54db52009-06-05 14:04:59 +0200950 ip = map->map_ip(map, ip);
Ingo Molnar75051722009-06-03 23:14:49 +0200951 dso = map->dso;
Ingo Molnar75051722009-06-03 23:14:49 +0200952 } else {
953 /*
954 * If this is outside of all known maps,
955 * and is a negative address, try to look it
956 * up in the kernel dso, as it might be a
957 * vsyscall (which executes in user-mode):
958 */
959 if ((long long)ip < 0)
960 dso = kernel_dso;
961 }
962 dprintf(" ...... dso: %s\n", dso ? dso->name : "<not found>");
963
964 } else {
965 show = SHOW_HV;
966 level = 'H';
967 dprintf(" ...... dso: [hypervisor]\n");
968 }
969
970 if (show & show_mask) {
Peter Zijlstrafc54db52009-06-05 14:04:59 +0200971 struct symbol *sym = NULL;
972
973 if (dso)
974 sym = dso->find_symbol(dso, ip);
Ingo Molnar75051722009-06-03 23:14:49 +0200975
976 if (hist_entry__add(thread, map, dso, sym, ip, level)) {
977 fprintf(stderr,
978 "problem incrementing symbol count, skipping event\n");
979 return -1;
980 }
981 }
982 total++;
983
984 return 0;
985}
986
987static int
988process_mmap_event(event_t *event, unsigned long offset, unsigned long head)
989{
990 struct thread *thread = threads__findnew(event->mmap.pid);
991 struct map *map = map__new(&event->mmap);
992
Peter Zijlstra62fc4452009-06-04 16:53:49 +0200993 dprintf("%p [%p]: PERF_EVENT_MMAP %d: [%p(%p) @ %p]: %s\n",
Ingo Molnar75051722009-06-03 23:14:49 +0200994 (void *)(offset + head),
995 (void *)(long)(event->header.size),
Peter Zijlstra62fc4452009-06-04 16:53:49 +0200996 event->mmap.pid,
Ingo Molnar75051722009-06-03 23:14:49 +0200997 (void *)(long)event->mmap.start,
998 (void *)(long)event->mmap.len,
999 (void *)(long)event->mmap.pgoff,
1000 event->mmap.filename);
1001
1002 if (thread == NULL || map == NULL) {
1003 dprintf("problem processing PERF_EVENT_MMAP, skipping event.\n");
Ingo Molnardf979922009-06-04 13:41:22 +02001004 return 0;
Ingo Molnar75051722009-06-03 23:14:49 +02001005 }
1006
1007 thread__insert_map(thread, map);
1008 total_mmap++;
1009
1010 return 0;
1011}
1012
1013static int
1014process_comm_event(event_t *event, unsigned long offset, unsigned long head)
1015{
1016 struct thread *thread = threads__findnew(event->comm.pid);
1017
1018 dprintf("%p [%p]: PERF_EVENT_COMM: %s:%d\n",
1019 (void *)(offset + head),
1020 (void *)(long)(event->header.size),
1021 event->comm.comm, event->comm.pid);
1022
1023 if (thread == NULL ||
1024 thread__set_comm(thread, event->comm.comm)) {
1025 dprintf("problem processing PERF_EVENT_COMM, skipping event.\n");
1026 return -1;
1027 }
1028 total_comm++;
1029
1030 return 0;
1031}
1032
1033static int
Peter Zijlstra62fc4452009-06-04 16:53:49 +02001034process_fork_event(event_t *event, unsigned long offset, unsigned long head)
1035{
1036 struct thread *thread = threads__findnew(event->fork.pid);
1037 struct thread *parent = threads__findnew(event->fork.ppid);
1038
1039 dprintf("%p [%p]: PERF_EVENT_FORK: %d:%d\n",
1040 (void *)(offset + head),
1041 (void *)(long)(event->header.size),
1042 event->fork.pid, event->fork.ppid);
1043
1044 if (!thread || !parent || thread__fork(thread, parent)) {
1045 dprintf("problem processing PERF_EVENT_FORK, skipping event.\n");
1046 return -1;
1047 }
1048 total_fork++;
1049
1050 return 0;
1051}
1052
1053static int
Ingo Molnard80d3382009-06-03 23:14:49 +02001054process_event(event_t *event, unsigned long offset, unsigned long head)
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -03001055{
Ingo Molnar75051722009-06-03 23:14:49 +02001056 if (event->header.misc & PERF_EVENT_MISC_OVERFLOW)
1057 return process_overflow_event(event, offset, head);
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -03001058
Ingo Molnar75051722009-06-03 23:14:49 +02001059 switch (event->header.type) {
1060 case PERF_EVENT_MMAP:
1061 return process_mmap_event(event, offset, head);
Ingo Molnar97b07b62009-05-26 18:48:58 +02001062
Ingo Molnar75051722009-06-03 23:14:49 +02001063 case PERF_EVENT_COMM:
1064 return process_comm_event(event, offset, head);
Ingo Molnared966aa2009-06-03 10:39:26 +02001065
Peter Zijlstra62fc4452009-06-04 16:53:49 +02001066 case PERF_EVENT_FORK:
1067 return process_fork_event(event, offset, head);
1068
Ingo Molnard11444d2009-06-03 23:29:14 +02001069 /*
1070 * We dont process them right now but they are fine:
1071 */
Peter Zijlstra62fc4452009-06-04 16:53:49 +02001072
Ingo Molnard11444d2009-06-03 23:29:14 +02001073 case PERF_EVENT_PERIOD:
1074 case PERF_EVENT_THROTTLE:
1075 case PERF_EVENT_UNTHROTTLE:
1076 return 0;
1077
Ingo Molnard80d3382009-06-03 23:14:49 +02001078 default:
1079 return -1;
1080 }
1081
1082 return 0;
1083}
1084
1085static int __cmd_report(void)
1086{
Ingo Molnar75051722009-06-03 23:14:49 +02001087 int ret, rc = EXIT_FAILURE;
Ingo Molnard80d3382009-06-03 23:14:49 +02001088 unsigned long offset = 0;
1089 unsigned long head = 0;
1090 struct stat stat;
Ingo Molnard80d3382009-06-03 23:14:49 +02001091 event_t *event;
Ingo Molnard80d3382009-06-03 23:14:49 +02001092 uint32_t size;
Ingo Molnar75051722009-06-03 23:14:49 +02001093 char *buf;
Ingo Molnard80d3382009-06-03 23:14:49 +02001094
1095 register_idle_thread();
1096
1097 input = open(input_name, O_RDONLY);
1098 if (input < 0) {
1099 perror("failed to open file");
1100 exit(-1);
1101 }
1102
1103 ret = fstat(input, &stat);
1104 if (ret < 0) {
1105 perror("failed to stat file");
1106 exit(-1);
1107 }
1108
1109 if (!stat.st_size) {
1110 fprintf(stderr, "zero-sized file, nothing to do!\n");
1111 exit(0);
1112 }
1113
1114 if (load_kernel() < 0) {
1115 perror("failed to load kernel symbols");
1116 return EXIT_FAILURE;
1117 }
1118
1119 if (!full_paths) {
1120 if (getcwd(__cwd, sizeof(__cwd)) == NULL) {
1121 perror("failed to get the current directory");
1122 return EXIT_FAILURE;
1123 }
1124 cwdlen = strlen(cwd);
1125 } else {
1126 cwd = NULL;
1127 cwdlen = 0;
1128 }
1129remap:
1130 buf = (char *)mmap(NULL, page_size * mmap_window, PROT_READ,
1131 MAP_SHARED, input, offset);
1132 if (buf == MAP_FAILED) {
1133 perror("failed to mmap file");
1134 exit(-1);
1135 }
1136
1137more:
1138 event = (event_t *)(buf + head);
1139
1140 size = event->header.size;
1141 if (!size)
1142 size = 8;
1143
1144 if (head + event->header.size >= page_size * mmap_window) {
1145 unsigned long shift = page_size * (head / page_size);
1146 int ret;
1147
1148 ret = munmap(buf, page_size * mmap_window);
1149 assert(ret == 0);
1150
1151 offset += shift;
1152 head -= shift;
1153 goto remap;
1154 }
1155
1156 size = event->header.size;
1157
1158 if (!size || process_event(event, offset, head) < 0) {
1159
Ingo Molnar35029732009-06-03 09:38:58 +02001160 dprintf("%p [%p]: skipping unknown header type: %d\n",
1161 (void *)(offset + head),
1162 (void *)(long)(event->header.size),
1163 event->header.type);
Peter Zijlstrab7a16ea2009-05-27 13:35:35 +02001164
Ingo Molnar3e706112009-05-26 18:53:17 +02001165 total_unknown++;
Peter Zijlstra6142f9e2009-05-26 20:51:47 +02001166
1167 /*
1168 * assume we lost track of the stream, check alignment, and
1169 * increment a single u64 in the hope to catch on again 'soon'.
1170 */
1171
1172 if (unlikely(head & 7))
1173 head &= ~7ULL;
1174
1175 size = 8;
Ingo Molnar97b07b62009-05-26 18:48:58 +02001176 }
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -03001177
Peter Zijlstra6142f9e2009-05-26 20:51:47 +02001178 head += size;
Ingo Molnarf49515b2009-05-26 19:03:36 +02001179
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -03001180 if (offset + head < stat.st_size)
1181 goto more;
1182
1183 rc = EXIT_SUCCESS;
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -03001184 close(input);
Ingo Molnar97b07b62009-05-26 18:48:58 +02001185
Ingo Molnar35029732009-06-03 09:38:58 +02001186 dprintf(" IP events: %10ld\n", total);
1187 dprintf(" mmap events: %10ld\n", total_mmap);
1188 dprintf(" comm events: %10ld\n", total_comm);
Peter Zijlstra62fc4452009-06-04 16:53:49 +02001189 dprintf(" fork events: %10ld\n", total_fork);
Ingo Molnar35029732009-06-03 09:38:58 +02001190 dprintf(" unknown events: %10ld\n", total_unknown);
Ingo Molnar97b07b62009-05-26 18:48:58 +02001191
Ingo Molnar35029732009-06-03 09:38:58 +02001192 if (dump_trace)
Ingo Molnar97b07b62009-05-26 18:48:58 +02001193 return 0;
Ingo Molnar97b07b62009-05-26 18:48:58 +02001194
Arnaldo Carvalho de Melo9ac99542009-06-04 13:54:00 -03001195 if (verbose >= 3)
1196 threads__fprintf(stdout);
1197
Peter Zijlstrae7fb08b2009-05-27 20:20:24 +02001198 if (verbose >= 2)
Ingo Molnar16f762a2009-05-27 09:10:38 +02001199 dsos__fprintf(stdout);
Ingo Molnar16f762a2009-05-27 09:10:38 +02001200
Peter Zijlstra82292892009-06-03 12:37:36 +02001201 collapse__resort();
Peter Zijlstrae7fb08b2009-05-27 20:20:24 +02001202 output__resort();
1203 output__fprintf(stdout, total);
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -03001204
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -03001205 return rc;
1206}
1207
Ingo Molnar53cb8bc2009-05-26 09:17:18 +02001208static const char * const report_usage[] = {
1209 "perf report [<options>] <command>",
1210 NULL
1211};
1212
1213static const struct option options[] = {
1214 OPT_STRING('i', "input", &input_name, "file",
1215 "input file name"),
Arnaldo Carvalho de Melo815e7772009-05-26 19:46:14 -03001216 OPT_BOOLEAN('v', "verbose", &verbose,
1217 "be more verbose (show symbol address, etc)"),
Ingo Molnar97b07b62009-05-26 18:48:58 +02001218 OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace,
1219 "dump raw trace in ASCII"),
Peter Zijlstra450aaa22009-05-27 20:20:23 +02001220 OPT_STRING('k', "vmlinux", &vmlinux, "file", "vmlinux pathname"),
Ingo Molnar63299f02009-05-28 10:52:00 +02001221 OPT_STRING('s', "sort", &sort_order, "key[,key2...]",
1222 "sort by key(s): pid, comm, dso, symbol. Default: pid,symbol"),
Arnaldo Carvalho de Melob78c07d2009-05-29 13:48:59 -03001223 OPT_BOOLEAN('P', "full-paths", &full_paths,
1224 "Don't shorten the pathnames taking into account the cwd"),
Ingo Molnar53cb8bc2009-05-26 09:17:18 +02001225 OPT_END()
1226};
1227
Ingo Molnar5352f352009-06-03 10:07:39 +02001228static void setup_sorting(void)
1229{
1230 char *tmp, *tok, *str = strdup(sort_order);
1231
1232 for (tok = strtok_r(str, ", ", &tmp);
1233 tok; tok = strtok_r(NULL, ", ", &tmp)) {
1234 if (sort_dimension__add(tok) < 0) {
1235 error("Unknown --sort key: `%s'", tok);
1236 usage_with_options(report_usage, options);
1237 }
1238 }
1239
1240 free(str);
1241}
1242
Ingo Molnar53cb8bc2009-05-26 09:17:18 +02001243int cmd_report(int argc, const char **argv, const char *prefix)
1244{
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -03001245 symbol__init();
Ingo Molnar53cb8bc2009-05-26 09:17:18 +02001246
1247 page_size = getpagesize();
1248
Ingo Molnaredc52de2009-06-04 16:24:37 +02001249 argc = parse_options(argc, argv, options, report_usage, 0);
Ingo Molnar53cb8bc2009-05-26 09:17:18 +02001250
Peter Zijlstra1aa16732009-05-27 20:20:25 +02001251 setup_sorting();
1252
Ingo Molnaredc52de2009-06-04 16:24:37 +02001253 /*
1254 * Any (unrecognized) arguments left?
1255 */
1256 if (argc)
1257 usage_with_options(report_usage, options);
1258
Ingo Molnara930d2c2009-05-27 09:50:13 +02001259 setup_pager();
1260
Ingo Molnar53cb8bc2009-05-26 09:17:18 +02001261 return __cmd_report();
1262}