blob: 5af105c280b5e4c03bb3da2f8732363e4b3fce83 [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 = {
Ingo Molnar8edd4282009-06-05 14:13:18 +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 Molnar8edd4282009-06-05 14:13:18 +0200572 if (self->sym) {
573 ret += fprintf(fp, "[%c] %s",
574 self->dso == kernel_dso ? 'k' : '.', self->sym->name);
575 } else {
Peter Zijlstra71dd8942009-06-04 15:16:56 +0200576 ret += fprintf(fp, "%#016llx", (__u64)self->ip);
Ingo Molnar8edd4282009-06-05 14:13:18 +0200577 }
Peter Zijlstra1aa16732009-05-27 20:20:25 +0200578
579 return ret;
580}
581
582static struct sort_entry sort_sym = {
Peter Zijlstra71dd8942009-06-04 15:16:56 +0200583 .header = "Symbol",
Peter Zijlstraca8cdee2009-05-28 11:08:33 +0200584 .cmp = sort__sym_cmp,
585 .print = sort__sym_print,
Peter Zijlstra1aa16732009-05-27 20:20:25 +0200586};
587
Peter Zijlstra82292892009-06-03 12:37:36 +0200588static int sort__need_collapse = 0;
589
Peter Zijlstra37f440c2009-05-27 20:20:26 +0200590struct sort_dimension {
Ingo Molnar8edd4282009-06-05 14:13:18 +0200591 char *name;
592 struct sort_entry *entry;
593 int taken;
Peter Zijlstra37f440c2009-05-27 20:20:26 +0200594};
595
596static struct sort_dimension sort_dimensions[] = {
597 { .name = "pid", .entry = &sort_thread, },
Peter Zijlstra992444b2009-05-27 20:20:27 +0200598 { .name = "comm", .entry = &sort_comm, },
Peter Zijlstra55e5ec42009-05-27 20:20:28 +0200599 { .name = "dso", .entry = &sort_dso, },
Peter Zijlstra37f440c2009-05-27 20:20:26 +0200600 { .name = "symbol", .entry = &sort_sym, },
601};
602
Peter Zijlstra1aa16732009-05-27 20:20:25 +0200603static LIST_HEAD(hist_entry__sort_list);
604
Peter Zijlstra37f440c2009-05-27 20:20:26 +0200605static int sort_dimension__add(char *tok)
606{
607 int i;
608
609 for (i = 0; i < ARRAY_SIZE(sort_dimensions); i++) {
610 struct sort_dimension *sd = &sort_dimensions[i];
611
612 if (sd->taken)
613 continue;
614
Ingo Molnar5352f352009-06-03 10:07:39 +0200615 if (strncasecmp(tok, sd->name, strlen(tok)))
Peter Zijlstra37f440c2009-05-27 20:20:26 +0200616 continue;
617
Peter Zijlstra82292892009-06-03 12:37:36 +0200618 if (sd->entry->collapse)
619 sort__need_collapse = 1;
620
Peter Zijlstra37f440c2009-05-27 20:20:26 +0200621 list_add_tail(&sd->entry->list, &hist_entry__sort_list);
622 sd->taken = 1;
Ingo Molnar5352f352009-06-03 10:07:39 +0200623
Peter Zijlstra37f440c2009-05-27 20:20:26 +0200624 return 0;
625 }
626
627 return -ESRCH;
628}
629
Peter Zijlstra1aa16732009-05-27 20:20:25 +0200630static int64_t
631hist_entry__cmp(struct hist_entry *left, struct hist_entry *right)
632{
633 struct sort_entry *se;
634 int64_t cmp = 0;
635
636 list_for_each_entry(se, &hist_entry__sort_list, list) {
637 cmp = se->cmp(left, right);
638 if (cmp)
639 break;
640 }
641
642 return cmp;
643}
644
Peter Zijlstra82292892009-06-03 12:37:36 +0200645static int64_t
646hist_entry__collapse(struct hist_entry *left, struct hist_entry *right)
647{
648 struct sort_entry *se;
649 int64_t cmp = 0;
650
651 list_for_each_entry(se, &hist_entry__sort_list, list) {
652 int64_t (*f)(struct hist_entry *, struct hist_entry *);
653
654 f = se->collapse ?: se->cmp;
655
656 cmp = f(left, right);
657 if (cmp)
658 break;
659 }
660
661 return cmp;
662}
663
Peter Zijlstra1aa16732009-05-27 20:20:25 +0200664static size_t
665hist_entry__fprintf(FILE *fp, struct hist_entry *self, uint64_t total_samples)
666{
667 struct sort_entry *se;
668 size_t ret;
669
670 if (total_samples) {
Ingo Molnar8fc03212009-06-04 15:19:47 +0200671 double percent = self->count * 100.0 / total_samples;
672 char *color = PERF_COLOR_NORMAL;
673
674 /*
675 * We color high-overhead entries in red, low-overhead
676 * entries in green - and keep the middle ground normal:
677 */
678 if (percent >= 5.0)
679 color = PERF_COLOR_RED;
680 if (percent < 0.5)
681 color = PERF_COLOR_GREEN;
682
683 ret = color_fprintf(fp, color, " %6.2f%%",
Peter Zijlstra1aa16732009-05-27 20:20:25 +0200684 (self->count * 100.0) / total_samples);
685 } else
686 ret = fprintf(fp, "%12d ", self->count);
687
Peter Zijlstra71dd8942009-06-04 15:16:56 +0200688 list_for_each_entry(se, &hist_entry__sort_list, list) {
689 fprintf(fp, " ");
Peter Zijlstra1aa16732009-05-27 20:20:25 +0200690 ret += se->print(fp, self);
Peter Zijlstra71dd8942009-06-04 15:16:56 +0200691 }
Peter Zijlstra1aa16732009-05-27 20:20:25 +0200692
693 ret += fprintf(fp, "\n");
694
695 return ret;
696}
697
698/*
699 * collect histogram counts
700 */
701
Peter Zijlstrae7fb08b2009-05-27 20:20:24 +0200702static int
703hist_entry__add(struct thread *thread, struct map *map, struct dso *dso,
704 struct symbol *sym, uint64_t ip, char level)
Arnaldo Carvalho de Melo3a4b8cc2009-05-26 16:19:04 -0300705{
Peter Zijlstrae7fb08b2009-05-27 20:20:24 +0200706 struct rb_node **p = &hist.rb_node;
Arnaldo Carvalho de Melo3a4b8cc2009-05-26 16:19:04 -0300707 struct rb_node *parent = NULL;
Peter Zijlstrae7fb08b2009-05-27 20:20:24 +0200708 struct hist_entry *he;
709 struct hist_entry entry = {
710 .thread = thread,
711 .map = map,
712 .dso = dso,
713 .sym = sym,
714 .ip = ip,
715 .level = level,
716 .count = 1,
717 };
718 int cmp;
Arnaldo Carvalho de Melo3a4b8cc2009-05-26 16:19:04 -0300719
720 while (*p != NULL) {
721 parent = *p;
Peter Zijlstrae7fb08b2009-05-27 20:20:24 +0200722 he = rb_entry(parent, struct hist_entry, rb_node);
Arnaldo Carvalho de Melo3a4b8cc2009-05-26 16:19:04 -0300723
Peter Zijlstrae7fb08b2009-05-27 20:20:24 +0200724 cmp = hist_entry__cmp(&entry, he);
725
726 if (!cmp) {
727 he->count++;
728 return 0;
729 }
730
731 if (cmp < 0)
Arnaldo Carvalho de Melo3a4b8cc2009-05-26 16:19:04 -0300732 p = &(*p)->rb_left;
733 else
734 p = &(*p)->rb_right;
735 }
736
Peter Zijlstrae7fb08b2009-05-27 20:20:24 +0200737 he = malloc(sizeof(*he));
738 if (!he)
739 return -ENOMEM;
740 *he = entry;
741 rb_link_node(&he->rb_node, parent, p);
742 rb_insert_color(&he->rb_node, &hist);
743
744 return 0;
Arnaldo Carvalho de Melo3a4b8cc2009-05-26 16:19:04 -0300745}
746
Peter Zijlstra82292892009-06-03 12:37:36 +0200747static void hist_entry__free(struct hist_entry *he)
748{
749 free(he);
750}
751
752/*
753 * collapse the histogram
754 */
755
756static struct rb_root collapse_hists;
757
758static void collapse__insert_entry(struct hist_entry *he)
759{
760 struct rb_node **p = &collapse_hists.rb_node;
761 struct rb_node *parent = NULL;
762 struct hist_entry *iter;
763 int64_t cmp;
764
765 while (*p != NULL) {
766 parent = *p;
767 iter = rb_entry(parent, struct hist_entry, rb_node);
768
769 cmp = hist_entry__collapse(iter, he);
770
771 if (!cmp) {
772 iter->count += he->count;
773 hist_entry__free(he);
774 return;
775 }
776
777 if (cmp < 0)
778 p = &(*p)->rb_left;
779 else
780 p = &(*p)->rb_right;
781 }
782
783 rb_link_node(&he->rb_node, parent, p);
784 rb_insert_color(&he->rb_node, &collapse_hists);
785}
786
787static void collapse__resort(void)
788{
789 struct rb_node *next;
790 struct hist_entry *n;
791
792 if (!sort__need_collapse)
793 return;
794
795 next = rb_first(&hist);
796 while (next) {
797 n = rb_entry(next, struct hist_entry, rb_node);
798 next = rb_next(&n->rb_node);
799
800 rb_erase(&n->rb_node, &hist);
801 collapse__insert_entry(n);
802 }
803}
804
Peter Zijlstrae7fb08b2009-05-27 20:20:24 +0200805/*
806 * reverse the map, sort on count.
807 */
808
809static struct rb_root output_hists;
810
811static void output__insert_entry(struct hist_entry *he)
812{
813 struct rb_node **p = &output_hists.rb_node;
814 struct rb_node *parent = NULL;
815 struct hist_entry *iter;
816
817 while (*p != NULL) {
818 parent = *p;
819 iter = rb_entry(parent, struct hist_entry, rb_node);
820
821 if (he->count > iter->count)
822 p = &(*p)->rb_left;
823 else
824 p = &(*p)->rb_right;
825 }
826
827 rb_link_node(&he->rb_node, parent, p);
828 rb_insert_color(&he->rb_node, &output_hists);
829}
830
831static void output__resort(void)
832{
Peter Zijlstra82292892009-06-03 12:37:36 +0200833 struct rb_node *next;
Peter Zijlstrae7fb08b2009-05-27 20:20:24 +0200834 struct hist_entry *n;
Arnaldo Carvalho de Meloa4c43be2009-06-03 23:02:33 -0300835 struct rb_root *tree = &hist;
Peter Zijlstrae7fb08b2009-05-27 20:20:24 +0200836
Peter Zijlstra82292892009-06-03 12:37:36 +0200837 if (sort__need_collapse)
Arnaldo Carvalho de Meloa4c43be2009-06-03 23:02:33 -0300838 tree = &collapse_hists;
839
840 next = rb_first(tree);
Peter Zijlstra82292892009-06-03 12:37:36 +0200841
Peter Zijlstrae7fb08b2009-05-27 20:20:24 +0200842 while (next) {
843 n = rb_entry(next, struct hist_entry, rb_node);
844 next = rb_next(&n->rb_node);
845
Arnaldo Carvalho de Meloa4c43be2009-06-03 23:02:33 -0300846 rb_erase(&n->rb_node, tree);
Peter Zijlstrae7fb08b2009-05-27 20:20:24 +0200847 output__insert_entry(n);
Arnaldo Carvalho de Melo3a4b8cc2009-05-26 16:19:04 -0300848 }
849}
850
Peter Zijlstrae7fb08b2009-05-27 20:20:24 +0200851static size_t output__fprintf(FILE *fp, uint64_t total_samples)
Arnaldo Carvalho de Melo3a4b8cc2009-05-26 16:19:04 -0300852{
Peter Zijlstrae7fb08b2009-05-27 20:20:24 +0200853 struct hist_entry *pos;
Ingo Molnar2d655372009-05-27 21:36:22 +0200854 struct sort_entry *se;
Arnaldo Carvalho de Melo3a4b8cc2009-05-26 16:19:04 -0300855 struct rb_node *nd;
856 size_t ret = 0;
857
Peter Zijlstra71dd8942009-06-04 15:16:56 +0200858 fprintf(fp, "\n");
Peter Zijlstraca8cdee2009-05-28 11:08:33 +0200859 fprintf(fp, "#\n");
Ingo Molnar2debbc82009-06-05 14:29:10 +0200860 fprintf(fp, "# (%Ld samples)\n", (__u64)total_samples);
Ingo Molnar05ca0612009-06-04 14:21:16 +0200861 fprintf(fp, "#\n");
Peter Zijlstraca8cdee2009-05-28 11:08:33 +0200862
863 fprintf(fp, "# Overhead");
864 list_for_each_entry(se, &hist_entry__sort_list, list)
Peter Zijlstra71dd8942009-06-04 15:16:56 +0200865 fprintf(fp, " %s", se->header);
Peter Zijlstraca8cdee2009-05-28 11:08:33 +0200866 fprintf(fp, "\n");
867
868 fprintf(fp, "# ........");
Ingo Molnar2d655372009-05-27 21:36:22 +0200869 list_for_each_entry(se, &hist_entry__sort_list, list) {
Peter Zijlstraca8cdee2009-05-28 11:08:33 +0200870 int i;
871
Ingo Molnar4593bba2009-06-02 15:34:25 +0200872 fprintf(fp, " ");
Peter Zijlstra71dd8942009-06-04 15:16:56 +0200873 for (i = 0; i < strlen(se->header); i++)
Peter Zijlstraca8cdee2009-05-28 11:08:33 +0200874 fprintf(fp, ".");
Ingo Molnar2d655372009-05-27 21:36:22 +0200875 }
Peter Zijlstraca8cdee2009-05-28 11:08:33 +0200876 fprintf(fp, "\n");
877
878 fprintf(fp, "#\n");
Ingo Molnar2d655372009-05-27 21:36:22 +0200879
Peter Zijlstrae7fb08b2009-05-27 20:20:24 +0200880 for (nd = rb_first(&output_hists); nd; nd = rb_next(nd)) {
881 pos = rb_entry(nd, struct hist_entry, rb_node);
882 ret += hist_entry__fprintf(fp, pos, total_samples);
Arnaldo Carvalho de Melo3a4b8cc2009-05-26 16:19:04 -0300883 }
884
Ingo Molnarbd741372009-06-04 14:13:04 +0200885 if (!strcmp(sort_order, default_sort_order)) {
886 fprintf(fp, "#\n");
Peter Zijlstra71dd8942009-06-04 15:16:56 +0200887 fprintf(fp, "# (For more details, try: perf report --sort comm,dso,symbol)\n");
Ingo Molnarbd741372009-06-04 14:13:04 +0200888 fprintf(fp, "#\n");
889 }
Peter Zijlstra71dd8942009-06-04 15:16:56 +0200890 fprintf(fp, "\n");
Ingo Molnarbd741372009-06-04 14:13:04 +0200891
Arnaldo Carvalho de Melo3a4b8cc2009-05-26 16:19:04 -0300892 return ret;
893}
894
Peter Zijlstra436224a2009-06-02 21:02:36 +0200895static void register_idle_thread(void)
896{
897 struct thread *thread = threads__findnew(0);
898
899 if (thread == NULL ||
900 thread__set_comm(thread, "[idle]")) {
901 fprintf(stderr, "problem inserting idle task.\n");
902 exit(-1);
903 }
904}
905
Peter Zijlstra62fc4452009-06-04 16:53:49 +0200906static unsigned long total = 0,
907 total_mmap = 0,
908 total_comm = 0,
909 total_fork = 0,
910 total_unknown = 0;
Peter Zijlstrae7fb08b2009-05-27 20:20:24 +0200911
Ingo Molnard80d3382009-06-03 23:14:49 +0200912static int
Ingo Molnar75051722009-06-03 23:14:49 +0200913process_overflow_event(event_t *event, unsigned long offset, unsigned long head)
914{
915 char level;
916 int show = 0;
917 struct dso *dso = NULL;
918 struct thread *thread = threads__findnew(event->ip.pid);
919 uint64_t ip = event->ip.ip;
920 struct map *map = NULL;
921
922 dprintf("%p [%p]: PERF_EVENT (IP, %d): %d: %p\n",
923 (void *)(offset + head),
924 (void *)(long)(event->header.size),
925 event->header.misc,
926 event->ip.pid,
927 (void *)(long)ip);
928
929 dprintf(" ... thread: %s:%d\n", thread->comm, thread->pid);
930
931 if (thread == NULL) {
932 fprintf(stderr, "problem processing %d event, skipping it.\n",
933 event->header.type);
934 return -1;
935 }
936
937 if (event->header.misc & PERF_EVENT_MISC_KERNEL) {
938 show = SHOW_KERNEL;
939 level = 'k';
940
941 dso = kernel_dso;
942
943 dprintf(" ...... dso: %s\n", dso->name);
944
945 } else if (event->header.misc & PERF_EVENT_MISC_USER) {
946
947 show = SHOW_USER;
948 level = '.';
949
950 map = thread__find_map(thread, ip);
951 if (map != NULL) {
Peter Zijlstrafc54db52009-06-05 14:04:59 +0200952 ip = map->map_ip(map, ip);
Ingo Molnar75051722009-06-03 23:14:49 +0200953 dso = map->dso;
Ingo Molnar75051722009-06-03 23:14:49 +0200954 } else {
955 /*
956 * If this is outside of all known maps,
957 * and is a negative address, try to look it
958 * up in the kernel dso, as it might be a
959 * vsyscall (which executes in user-mode):
960 */
961 if ((long long)ip < 0)
962 dso = kernel_dso;
963 }
964 dprintf(" ...... dso: %s\n", dso ? dso->name : "<not found>");
965
966 } else {
967 show = SHOW_HV;
968 level = 'H';
969 dprintf(" ...... dso: [hypervisor]\n");
970 }
971
972 if (show & show_mask) {
Peter Zijlstrafc54db52009-06-05 14:04:59 +0200973 struct symbol *sym = NULL;
974
975 if (dso)
976 sym = dso->find_symbol(dso, ip);
Ingo Molnar75051722009-06-03 23:14:49 +0200977
978 if (hist_entry__add(thread, map, dso, sym, ip, level)) {
979 fprintf(stderr,
980 "problem incrementing symbol count, skipping event\n");
981 return -1;
982 }
983 }
984 total++;
985
986 return 0;
987}
988
989static int
990process_mmap_event(event_t *event, unsigned long offset, unsigned long head)
991{
992 struct thread *thread = threads__findnew(event->mmap.pid);
993 struct map *map = map__new(&event->mmap);
994
Peter Zijlstra62fc4452009-06-04 16:53:49 +0200995 dprintf("%p [%p]: PERF_EVENT_MMAP %d: [%p(%p) @ %p]: %s\n",
Ingo Molnar75051722009-06-03 23:14:49 +0200996 (void *)(offset + head),
997 (void *)(long)(event->header.size),
Peter Zijlstra62fc4452009-06-04 16:53:49 +0200998 event->mmap.pid,
Ingo Molnar75051722009-06-03 23:14:49 +0200999 (void *)(long)event->mmap.start,
1000 (void *)(long)event->mmap.len,
1001 (void *)(long)event->mmap.pgoff,
1002 event->mmap.filename);
1003
1004 if (thread == NULL || map == NULL) {
1005 dprintf("problem processing PERF_EVENT_MMAP, skipping event.\n");
Ingo Molnardf979922009-06-04 13:41:22 +02001006 return 0;
Ingo Molnar75051722009-06-03 23:14:49 +02001007 }
1008
1009 thread__insert_map(thread, map);
1010 total_mmap++;
1011
1012 return 0;
1013}
1014
1015static int
1016process_comm_event(event_t *event, unsigned long offset, unsigned long head)
1017{
1018 struct thread *thread = threads__findnew(event->comm.pid);
1019
1020 dprintf("%p [%p]: PERF_EVENT_COMM: %s:%d\n",
1021 (void *)(offset + head),
1022 (void *)(long)(event->header.size),
1023 event->comm.comm, event->comm.pid);
1024
1025 if (thread == NULL ||
1026 thread__set_comm(thread, event->comm.comm)) {
1027 dprintf("problem processing PERF_EVENT_COMM, skipping event.\n");
1028 return -1;
1029 }
1030 total_comm++;
1031
1032 return 0;
1033}
1034
1035static int
Peter Zijlstra62fc4452009-06-04 16:53:49 +02001036process_fork_event(event_t *event, unsigned long offset, unsigned long head)
1037{
1038 struct thread *thread = threads__findnew(event->fork.pid);
1039 struct thread *parent = threads__findnew(event->fork.ppid);
1040
1041 dprintf("%p [%p]: PERF_EVENT_FORK: %d:%d\n",
1042 (void *)(offset + head),
1043 (void *)(long)(event->header.size),
1044 event->fork.pid, event->fork.ppid);
1045
1046 if (!thread || !parent || thread__fork(thread, parent)) {
1047 dprintf("problem processing PERF_EVENT_FORK, skipping event.\n");
1048 return -1;
1049 }
1050 total_fork++;
1051
1052 return 0;
1053}
1054
1055static int
Ingo Molnard80d3382009-06-03 23:14:49 +02001056process_event(event_t *event, unsigned long offset, unsigned long head)
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -03001057{
Ingo Molnar75051722009-06-03 23:14:49 +02001058 if (event->header.misc & PERF_EVENT_MISC_OVERFLOW)
1059 return process_overflow_event(event, offset, head);
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -03001060
Ingo Molnar75051722009-06-03 23:14:49 +02001061 switch (event->header.type) {
1062 case PERF_EVENT_MMAP:
1063 return process_mmap_event(event, offset, head);
Ingo Molnar97b07b62009-05-26 18:48:58 +02001064
Ingo Molnar75051722009-06-03 23:14:49 +02001065 case PERF_EVENT_COMM:
1066 return process_comm_event(event, offset, head);
Ingo Molnared966aa2009-06-03 10:39:26 +02001067
Peter Zijlstra62fc4452009-06-04 16:53:49 +02001068 case PERF_EVENT_FORK:
1069 return process_fork_event(event, offset, head);
1070
Ingo Molnard11444d2009-06-03 23:29:14 +02001071 /*
1072 * We dont process them right now but they are fine:
1073 */
Peter Zijlstra62fc4452009-06-04 16:53:49 +02001074
Ingo Molnard11444d2009-06-03 23:29:14 +02001075 case PERF_EVENT_PERIOD:
1076 case PERF_EVENT_THROTTLE:
1077 case PERF_EVENT_UNTHROTTLE:
1078 return 0;
1079
Ingo Molnard80d3382009-06-03 23:14:49 +02001080 default:
1081 return -1;
1082 }
1083
1084 return 0;
1085}
1086
1087static int __cmd_report(void)
1088{
Ingo Molnar75051722009-06-03 23:14:49 +02001089 int ret, rc = EXIT_FAILURE;
Ingo Molnard80d3382009-06-03 23:14:49 +02001090 unsigned long offset = 0;
1091 unsigned long head = 0;
1092 struct stat stat;
Ingo Molnard80d3382009-06-03 23:14:49 +02001093 event_t *event;
Ingo Molnard80d3382009-06-03 23:14:49 +02001094 uint32_t size;
Ingo Molnar75051722009-06-03 23:14:49 +02001095 char *buf;
Ingo Molnard80d3382009-06-03 23:14:49 +02001096
1097 register_idle_thread();
1098
1099 input = open(input_name, O_RDONLY);
1100 if (input < 0) {
1101 perror("failed to open file");
1102 exit(-1);
1103 }
1104
1105 ret = fstat(input, &stat);
1106 if (ret < 0) {
1107 perror("failed to stat file");
1108 exit(-1);
1109 }
1110
1111 if (!stat.st_size) {
1112 fprintf(stderr, "zero-sized file, nothing to do!\n");
1113 exit(0);
1114 }
1115
1116 if (load_kernel() < 0) {
1117 perror("failed to load kernel symbols");
1118 return EXIT_FAILURE;
1119 }
1120
1121 if (!full_paths) {
1122 if (getcwd(__cwd, sizeof(__cwd)) == NULL) {
1123 perror("failed to get the current directory");
1124 return EXIT_FAILURE;
1125 }
1126 cwdlen = strlen(cwd);
1127 } else {
1128 cwd = NULL;
1129 cwdlen = 0;
1130 }
1131remap:
1132 buf = (char *)mmap(NULL, page_size * mmap_window, PROT_READ,
1133 MAP_SHARED, input, offset);
1134 if (buf == MAP_FAILED) {
1135 perror("failed to mmap file");
1136 exit(-1);
1137 }
1138
1139more:
1140 event = (event_t *)(buf + head);
1141
1142 size = event->header.size;
1143 if (!size)
1144 size = 8;
1145
1146 if (head + event->header.size >= page_size * mmap_window) {
1147 unsigned long shift = page_size * (head / page_size);
1148 int ret;
1149
1150 ret = munmap(buf, page_size * mmap_window);
1151 assert(ret == 0);
1152
1153 offset += shift;
1154 head -= shift;
1155 goto remap;
1156 }
1157
1158 size = event->header.size;
1159
1160 if (!size || process_event(event, offset, head) < 0) {
1161
Ingo Molnar35029732009-06-03 09:38:58 +02001162 dprintf("%p [%p]: skipping unknown header type: %d\n",
1163 (void *)(offset + head),
1164 (void *)(long)(event->header.size),
1165 event->header.type);
Peter Zijlstrab7a16ea2009-05-27 13:35:35 +02001166
Ingo Molnar3e706112009-05-26 18:53:17 +02001167 total_unknown++;
Peter Zijlstra6142f9e2009-05-26 20:51:47 +02001168
1169 /*
1170 * assume we lost track of the stream, check alignment, and
1171 * increment a single u64 in the hope to catch on again 'soon'.
1172 */
1173
1174 if (unlikely(head & 7))
1175 head &= ~7ULL;
1176
1177 size = 8;
Ingo Molnar97b07b62009-05-26 18:48:58 +02001178 }
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -03001179
Peter Zijlstra6142f9e2009-05-26 20:51:47 +02001180 head += size;
Ingo Molnarf49515b2009-05-26 19:03:36 +02001181
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -03001182 if (offset + head < stat.st_size)
1183 goto more;
1184
1185 rc = EXIT_SUCCESS;
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -03001186 close(input);
Ingo Molnar97b07b62009-05-26 18:48:58 +02001187
Ingo Molnar35029732009-06-03 09:38:58 +02001188 dprintf(" IP events: %10ld\n", total);
1189 dprintf(" mmap events: %10ld\n", total_mmap);
1190 dprintf(" comm events: %10ld\n", total_comm);
Peter Zijlstra62fc4452009-06-04 16:53:49 +02001191 dprintf(" fork events: %10ld\n", total_fork);
Ingo Molnar35029732009-06-03 09:38:58 +02001192 dprintf(" unknown events: %10ld\n", total_unknown);
Ingo Molnar97b07b62009-05-26 18:48:58 +02001193
Ingo Molnar35029732009-06-03 09:38:58 +02001194 if (dump_trace)
Ingo Molnar97b07b62009-05-26 18:48:58 +02001195 return 0;
Ingo Molnar97b07b62009-05-26 18:48:58 +02001196
Arnaldo Carvalho de Melo9ac99542009-06-04 13:54:00 -03001197 if (verbose >= 3)
1198 threads__fprintf(stdout);
1199
Peter Zijlstrae7fb08b2009-05-27 20:20:24 +02001200 if (verbose >= 2)
Ingo Molnar16f762a2009-05-27 09:10:38 +02001201 dsos__fprintf(stdout);
Ingo Molnar16f762a2009-05-27 09:10:38 +02001202
Peter Zijlstra82292892009-06-03 12:37:36 +02001203 collapse__resort();
Peter Zijlstrae7fb08b2009-05-27 20:20:24 +02001204 output__resort();
1205 output__fprintf(stdout, total);
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -03001206
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -03001207 return rc;
1208}
1209
Ingo Molnar53cb8bc2009-05-26 09:17:18 +02001210static const char * const report_usage[] = {
1211 "perf report [<options>] <command>",
1212 NULL
1213};
1214
1215static const struct option options[] = {
1216 OPT_STRING('i', "input", &input_name, "file",
1217 "input file name"),
Arnaldo Carvalho de Melo815e7772009-05-26 19:46:14 -03001218 OPT_BOOLEAN('v', "verbose", &verbose,
1219 "be more verbose (show symbol address, etc)"),
Ingo Molnar97b07b62009-05-26 18:48:58 +02001220 OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace,
1221 "dump raw trace in ASCII"),
Peter Zijlstra450aaa22009-05-27 20:20:23 +02001222 OPT_STRING('k', "vmlinux", &vmlinux, "file", "vmlinux pathname"),
Ingo Molnar63299f02009-05-28 10:52:00 +02001223 OPT_STRING('s', "sort", &sort_order, "key[,key2...]",
1224 "sort by key(s): pid, comm, dso, symbol. Default: pid,symbol"),
Arnaldo Carvalho de Melob78c07d2009-05-29 13:48:59 -03001225 OPT_BOOLEAN('P', "full-paths", &full_paths,
1226 "Don't shorten the pathnames taking into account the cwd"),
Ingo Molnar53cb8bc2009-05-26 09:17:18 +02001227 OPT_END()
1228};
1229
Ingo Molnar5352f352009-06-03 10:07:39 +02001230static void setup_sorting(void)
1231{
1232 char *tmp, *tok, *str = strdup(sort_order);
1233
1234 for (tok = strtok_r(str, ", ", &tmp);
1235 tok; tok = strtok_r(NULL, ", ", &tmp)) {
1236 if (sort_dimension__add(tok) < 0) {
1237 error("Unknown --sort key: `%s'", tok);
1238 usage_with_options(report_usage, options);
1239 }
1240 }
1241
1242 free(str);
1243}
1244
Ingo Molnar53cb8bc2009-05-26 09:17:18 +02001245int cmd_report(int argc, const char **argv, const char *prefix)
1246{
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -03001247 symbol__init();
Ingo Molnar53cb8bc2009-05-26 09:17:18 +02001248
1249 page_size = getpagesize();
1250
Ingo Molnaredc52de2009-06-04 16:24:37 +02001251 argc = parse_options(argc, argv, options, report_usage, 0);
Ingo Molnar53cb8bc2009-05-26 09:17:18 +02001252
Peter Zijlstra1aa16732009-05-27 20:20:25 +02001253 setup_sorting();
1254
Ingo Molnaredc52de2009-06-04 16:24:37 +02001255 /*
1256 * Any (unrecognized) arguments left?
1257 */
1258 if (argc)
1259 usage_with_options(report_usage, options);
1260
Ingo Molnara930d2c2009-05-27 09:50:13 +02001261 setup_pager();
1262
Ingo Molnar53cb8bc2009-05-26 09:17:18 +02001263 return __cmd_report();
1264}