blob: 2357c66fb91dc059d4d414298b32b1283c7c5ab7 [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 Melo5da50252009-07-01 14:46:08 -030013#include <linux/list.h>
Ingo Molnara930d2c2009-05-27 09:50:13 +020014#include "util/cache.h"
Arnaldo Carvalho de Melo43cbcd82009-07-01 12:28:37 -030015#include <linux/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"
Frederic Weisbeckerf55c5552009-06-26 16:28:01 +020018#include "util/callchain.h"
Arnaldo Carvalho de Melo25903402009-06-30 19:01:20 -030019#include "util/strlist.h"
Brice Goglin8d513272009-08-07 13:55:24 +020020#include "util/values.h"
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -030021
Ingo Molnar53cb8bc2009-05-26 09:17:18 +020022#include "perf.h"
Peter Zijlstra7c6a1c62009-06-25 17:05:54 +020023#include "util/header.h"
Ingo Molnar53cb8bc2009-05-26 09:17:18 +020024
25#include "util/parse-options.h"
26#include "util/parse-events.h"
27
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -030028#define SHOW_KERNEL 1
29#define SHOW_USER 2
30#define SHOW_HV 4
31
Ingo Molnar23ac9cb2009-05-27 09:33:18 +020032static char const *input_name = "perf.data";
Peter Zijlstra450aaa22009-05-27 20:20:23 +020033static char *vmlinux = NULL;
Ingo Molnarbd741372009-06-04 14:13:04 +020034
Pekka Enberg114cfab2009-08-05 13:25:21 +030035static char default_sort_order[] = "comm,dso,symbol";
Ingo Molnarbd741372009-06-04 14:13:04 +020036static char *sort_order = default_sort_order;
Arnaldo Carvalho de Melo52d422d2009-07-10 22:47:28 -030037static char *dso_list_str, *comm_list_str, *sym_list_str,
38 *col_width_list_str;
Arnaldo Carvalho de Melo7bec7a92009-06-30 19:01:22 -030039static struct strlist *dso_list, *comm_list, *sym_list;
Arnaldo Carvalho de Melo52d422d2009-07-10 22:47:28 -030040static char *field_sep;
Ingo Molnarbd741372009-06-04 14:13:04 +020041
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -030042static int input;
43static int show_mask = SHOW_KERNEL | SHOW_USER | SHOW_HV;
44
Ingo Molnar97b07b62009-05-26 18:48:58 +020045static int dump_trace = 0;
Ingo Molnar35029732009-06-03 09:38:58 +020046#define dprintf(x...) do { if (dump_trace) printf(x); } while (0)
Ingo Molnar3efa1cc92009-06-14 15:04:15 +020047#define cdprintf(x...) do { if (dump_trace) color_fprintf(stdout, color, x); } while (0)
Ingo Molnar35029732009-06-03 09:38:58 +020048
Ingo Molnar16f762a2009-05-27 09:10:38 +020049static int verbose;
Ingo Molnar75220602009-06-18 08:00:17 +020050#define eprintf(x...) do { if (verbose) fprintf(stderr, x); } while (0)
51
Mike Galbraith42976482009-07-02 08:09:46 +020052static int modules;
53
Arnaldo Carvalho de Melob78c07d2009-05-29 13:48:59 -030054static int full_paths;
Arnaldo Carvalho de Meloe3d7e182009-07-11 12:18:37 -030055static int show_nr_samples;
Ingo Molnar97b07b62009-05-26 18:48:58 +020056
Brice Goglin8d513272009-08-07 13:55:24 +020057static int show_threads;
58static struct perf_read_values show_threads_values;
59
Brice Goglin9f866692009-08-10 15:26:32 +020060static char default_pretty_printing_style[] = "normal";
61static char *pretty_printing_style = default_pretty_printing_style;
62
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -030063static unsigned long page_size;
64static unsigned long mmap_window = 32;
65
Ingo Molnarb8e6d822009-06-18 14:32:19 +020066static char default_parent_pattern[] = "^sys_|^do_page_fault";
67static char *parent_pattern = default_parent_pattern;
Ingo Molnarb25bcf22009-06-18 07:01:03 +020068static regex_t parent_regex;
Peter Zijlstra6e7d6fd2009-06-17 15:51:44 +020069
Ingo Molnarb8e6d822009-06-18 14:32:19 +020070static int exclude_other = 1;
Frederic Weisbeckerbe903882009-07-05 07:39:18 +020071
Frederic Weisbecker805d1272009-07-05 07:39:21 +020072static char callchain_default_opt[] = "fractal,0.5";
73
Frederic Weisbeckerf55c5552009-06-26 16:28:01 +020074static int callchain;
Frederic Weisbecker805d1272009-07-05 07:39:21 +020075
76static
77struct callchain_param callchain_param = {
Frederic Weisbeckerb1a88342009-08-08 02:16:24 +020078 .mode = CHAIN_GRAPH_REL,
Frederic Weisbecker805d1272009-07-05 07:39:21 +020079 .min_percent = 0.5
80};
Ingo Molnarb8e6d822009-06-18 14:32:19 +020081
Peter Zijlstrae6e18ec2009-06-25 11:27:12 +020082static u64 sample_type;
83
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -030084struct ip_event {
85 struct perf_event_header header;
Paul Mackerras9cffa8d2009-06-19 22:21:42 +100086 u64 ip;
87 u32 pid, tid;
Ingo Molnar3efa1cc92009-06-14 15:04:15 +020088 unsigned char __more_data[];
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -030089};
Ingo Molnar75051722009-06-03 23:14:49 +020090
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -030091struct mmap_event {
92 struct perf_event_header header;
Paul Mackerras9cffa8d2009-06-19 22:21:42 +100093 u32 pid, tid;
94 u64 start;
95 u64 len;
96 u64 pgoff;
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -030097 char filename[PATH_MAX];
98};
Ingo Molnar75051722009-06-03 23:14:49 +020099
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300100struct comm_event {
101 struct perf_event_header header;
Paul Mackerras9cffa8d2009-06-19 22:21:42 +1000102 u32 pid, tid;
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300103 char comm[16];
104};
105
Peter Zijlstra62fc4452009-06-04 16:53:49 +0200106struct fork_event {
107 struct perf_event_header header;
Paul Mackerras9cffa8d2009-06-19 22:21:42 +1000108 u32 pid, ppid;
Peter Zijlstra27d028d2009-07-23 16:52:41 +0200109 u32 tid, ptid;
Peter Zijlstra62fc4452009-06-04 16:53:49 +0200110};
111
Peter Zijlstra9d91a6f2009-06-18 11:40:28 +0200112struct lost_event {
113 struct perf_event_header header;
Paul Mackerras9cffa8d2009-06-19 22:21:42 +1000114 u64 id;
115 u64 lost;
Peter Zijlstra9d91a6f2009-06-18 11:40:28 +0200116};
117
Peter Zijlstrae9ea2fd2009-06-24 22:46:04 +0200118struct read_event {
119 struct perf_event_header header;
120 u32 pid,tid;
121 u64 value;
Peter Zijlstra8f18aec2009-08-06 19:40:28 +0200122 u64 time_enabled;
123 u64 time_running;
124 u64 id;
Peter Zijlstrae9ea2fd2009-06-24 22:46:04 +0200125};
126
Ingo Molnarb2fef072009-06-05 18:07:51 +0200127typedef union event_union {
128 struct perf_event_header header;
129 struct ip_event ip;
130 struct mmap_event mmap;
131 struct comm_event comm;
132 struct fork_event fork;
Peter Zijlstra9d91a6f2009-06-18 11:40:28 +0200133 struct lost_event lost;
Peter Zijlstrae9ea2fd2009-06-24 22:46:04 +0200134 struct read_event read;
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300135} event_t;
136
Arnaldo Carvalho de Melo52d422d2009-07-10 22:47:28 -0300137static int repsep_fprintf(FILE *fp, const char *fmt, ...)
138{
139 int n;
140 va_list ap;
141
142 va_start(ap, fmt);
143 if (!field_sep)
144 n = vfprintf(fp, fmt, ap);
145 else {
146 char *bf = NULL;
147 n = vasprintf(&bf, fmt, ap);
148 if (n > 0) {
149 char *sep = bf;
150 while (1) {
151 sep = strchr(sep, *field_sep);
152 if (sep == NULL)
153 break;
154 *sep = '.';
155 }
156 }
157 fputs(bf, fp);
158 free(bf);
159 }
160 va_end(ap);
161 return n;
162}
163
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300164static LIST_HEAD(dsos);
165static struct dso *kernel_dso;
Peter Zijlstrafc54db52009-06-05 14:04:59 +0200166static struct dso *vdso;
Anton Blanchardfb9c8182009-07-01 09:00:49 +1000167static struct dso *hypervisor_dso;
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300168
169static void dsos__add(struct dso *dso)
170{
171 list_add_tail(&dso->node, &dsos);
172}
173
174static struct dso *dsos__find(const char *name)
175{
176 struct dso *pos;
177
178 list_for_each_entry(pos, &dsos, node)
179 if (strcmp(pos->name, name) == 0)
180 return pos;
181 return NULL;
182}
183
184static struct dso *dsos__findnew(const char *name)
185{
186 struct dso *dso = dsos__find(name);
Peter Zijlstrab7a16ea2009-05-27 13:35:35 +0200187 int nr;
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300188
Ingo Molnar4593bba2009-06-02 15:34:25 +0200189 if (dso)
190 return dso;
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300191
Ingo Molnar4593bba2009-06-02 15:34:25 +0200192 dso = dso__new(name, 0);
193 if (!dso)
194 goto out_delete_dso;
Peter Zijlstrab7a16ea2009-05-27 13:35:35 +0200195
Ingo Molnarbd741372009-06-04 14:13:04 +0200196 nr = dso__load(dso, NULL, verbose);
Ingo Molnar4593bba2009-06-02 15:34:25 +0200197 if (nr < 0) {
Ingo Molnar75220602009-06-18 08:00:17 +0200198 eprintf("Failed to open: %s\n", name);
Ingo Molnar4593bba2009-06-02 15:34:25 +0200199 goto out_delete_dso;
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300200 }
Ingo Molnar75220602009-06-18 08:00:17 +0200201 if (!nr)
202 eprintf("No symbols found in: %s, maybe install a debug package?\n", name);
Ingo Molnar4593bba2009-06-02 15:34:25 +0200203
204 dsos__add(dso);
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300205
206 return dso;
207
208out_delete_dso:
209 dso__delete(dso);
210 return NULL;
211}
212
Ingo Molnar16f762a2009-05-27 09:10:38 +0200213static void dsos__fprintf(FILE *fp)
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300214{
215 struct dso *pos;
216
217 list_for_each_entry(pos, &dsos, node)
218 dso__fprintf(pos, fp);
219}
220
Paul Mackerras9cffa8d2009-06-19 22:21:42 +1000221static struct symbol *vdso__find_symbol(struct dso *dso, u64 ip)
Peter Zijlstrafc54db52009-06-05 14:04:59 +0200222{
Ingo Molnarf37a2912009-07-01 12:37:06 +0200223 return dso__find_symbol(dso, ip);
Peter Zijlstrafc54db52009-06-05 14:04:59 +0200224}
225
Peter Zijlstra450aaa22009-05-27 20:20:23 +0200226static int load_kernel(void)
227{
Arnaldo Carvalho de Meloa827c872009-05-28 14:55:19 -0300228 int err;
Peter Zijlstra450aaa22009-05-27 20:20:23 +0200229
Arnaldo Carvalho de Melo0085c9542009-05-28 14:55:13 -0300230 kernel_dso = dso__new("[kernel]", 0);
Peter Zijlstra450aaa22009-05-27 20:20:23 +0200231 if (!kernel_dso)
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300232 return -1;
Peter Zijlstra450aaa22009-05-27 20:20:23 +0200233
Mike Galbraith42976482009-07-02 08:09:46 +0200234 err = dso__load_kernel(kernel_dso, vmlinux, NULL, verbose, modules);
Mike Galbraith9974f492009-07-02 08:05:58 +0200235 if (err <= 0) {
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300236 dso__delete(kernel_dso);
237 kernel_dso = NULL;
238 } else
239 dsos__add(kernel_dso);
Peter Zijlstra450aaa22009-05-27 20:20:23 +0200240
Peter Zijlstrafc54db52009-06-05 14:04:59 +0200241 vdso = dso__new("[vdso]", 0);
242 if (!vdso)
243 return -1;
244
245 vdso->find_symbol = vdso__find_symbol;
246
247 dsos__add(vdso);
248
Anton Blanchardfb9c8182009-07-01 09:00:49 +1000249 hypervisor_dso = dso__new("[hypervisor]", 0);
250 if (!hypervisor_dso)
251 return -1;
252 dsos__add(hypervisor_dso);
253
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -0300254 return err;
Peter Zijlstra450aaa22009-05-27 20:20:23 +0200255}
256
Ingo Molnard80d3382009-06-03 23:14:49 +0200257static char __cwd[PATH_MAX];
258static char *cwd = __cwd;
259static int cwdlen;
260
261static int strcommon(const char *pathname)
Arnaldo Carvalho de Melob78c07d2009-05-29 13:48:59 -0300262{
263 int n = 0;
264
Roel Kluin7e030652009-08-02 13:43:11 +0200265 while (n < cwdlen && pathname[n] == cwd[n])
Arnaldo Carvalho de Melob78c07d2009-05-29 13:48:59 -0300266 ++n;
267
268 return n;
269}
270
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300271struct map {
272 struct list_head node;
Paul Mackerras9cffa8d2009-06-19 22:21:42 +1000273 u64 start;
274 u64 end;
275 u64 pgoff;
276 u64 (*map_ip)(struct map *, u64);
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300277 struct dso *dso;
278};
279
Paul Mackerras9cffa8d2009-06-19 22:21:42 +1000280static u64 map__map_ip(struct map *map, u64 ip)
Peter Zijlstrafc54db52009-06-05 14:04:59 +0200281{
282 return ip - map->start + map->pgoff;
283}
284
Ingo Molnarf37a2912009-07-01 12:37:06 +0200285static u64 vdso__map_ip(struct map *map __used, u64 ip)
Peter Zijlstrafc54db52009-06-05 14:04:59 +0200286{
287 return ip;
288}
289
Pekka Enberg80d496b2009-06-08 21:12:48 +0300290static inline int is_anon_memory(const char *filename)
291{
Arnaldo Carvalho de Melocc8b88b2009-06-30 19:01:21 -0300292 return strcmp(filename, "//anon") == 0;
Pekka Enberg80d496b2009-06-08 21:12:48 +0300293}
294
Ingo Molnard80d3382009-06-03 23:14:49 +0200295static struct map *map__new(struct mmap_event *event)
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300296{
297 struct map *self = malloc(sizeof(*self));
298
299 if (self != NULL) {
Arnaldo Carvalho de Melob78c07d2009-05-29 13:48:59 -0300300 const char *filename = event->filename;
301 char newfilename[PATH_MAX];
Pekka Enberg80d496b2009-06-08 21:12:48 +0300302 int anon;
Arnaldo Carvalho de Melob78c07d2009-05-29 13:48:59 -0300303
304 if (cwd) {
Ingo Molnard80d3382009-06-03 23:14:49 +0200305 int n = strcommon(filename);
306
Arnaldo Carvalho de Melob78c07d2009-05-29 13:48:59 -0300307 if (n == cwdlen) {
308 snprintf(newfilename, sizeof(newfilename),
309 ".%s", filename + n);
310 filename = newfilename;
311 }
312 }
313
Pekka Enberg80d496b2009-06-08 21:12:48 +0300314 anon = is_anon_memory(filename);
315
316 if (anon) {
317 snprintf(newfilename, sizeof(newfilename), "/tmp/perf-%d.map", event->pid);
318 filename = newfilename;
319 }
320
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300321 self->start = event->start;
322 self->end = event->start + event->len;
323 self->pgoff = event->pgoff;
324
Arnaldo Carvalho de Melob78c07d2009-05-29 13:48:59 -0300325 self->dso = dsos__findnew(filename);
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300326 if (self->dso == NULL)
327 goto out_delete;
Peter Zijlstrafc54db52009-06-05 14:04:59 +0200328
Pekka Enberg80d496b2009-06-08 21:12:48 +0300329 if (self->dso == vdso || anon)
Peter Zijlstrafc54db52009-06-05 14:04:59 +0200330 self->map_ip = vdso__map_ip;
331 else
332 self->map_ip = map__map_ip;
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300333 }
334 return self;
335out_delete:
336 free(self);
337 return NULL;
338}
339
Peter Zijlstra62fc4452009-06-04 16:53:49 +0200340static struct map *map__clone(struct map *self)
341{
342 struct map *map = malloc(sizeof(*self));
343
344 if (!map)
345 return NULL;
346
347 memcpy(map, self, sizeof(*self));
348
349 return map;
350}
351
352static int map__overlap(struct map *l, struct map *r)
353{
354 if (l->start > r->start) {
355 struct map *t = l;
356 l = r;
357 r = t;
358 }
359
360 if (l->end > r->start)
361 return 1;
362
363 return 0;
364}
Arnaldo Carvalho de Melo3a4b8cc2009-05-26 16:19:04 -0300365
Arnaldo Carvalho de Melo9ac99542009-06-04 13:54:00 -0300366static size_t map__fprintf(struct map *self, FILE *fp)
367{
Ingo Molnar729ff5e22009-06-11 14:16:15 +0200368 return fprintf(fp, " %Lx-%Lx %Lx %s\n",
Arnaldo Carvalho de Melo9ac99542009-06-04 13:54:00 -0300369 self->start, self->end, self->pgoff, self->dso->name);
370}
371
372
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300373struct thread {
Arnaldo Carvalho de Meloce7e4362009-05-19 09:30:23 -0300374 struct rb_node rb_node;
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300375 struct list_head maps;
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300376 pid_t pid;
377 char *comm;
378};
379
380static struct thread *thread__new(pid_t pid)
381{
382 struct thread *self = malloc(sizeof(*self));
383
384 if (self != NULL) {
385 self->pid = pid;
Peter Zijlstra82292892009-06-03 12:37:36 +0200386 self->comm = malloc(32);
Ingo Molnar0a520c62009-06-02 23:24:45 +0200387 if (self->comm)
Peter Zijlstra82292892009-06-03 12:37:36 +0200388 snprintf(self->comm, 32, ":%d", self->pid);
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300389 INIT_LIST_HEAD(&self->maps);
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300390 }
391
392 return self;
393}
394
Arnaldo Carvalho de Melo52d422d2009-07-10 22:47:28 -0300395static unsigned int dsos__col_width,
396 comms__col_width,
397 threads__col_width;
398
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300399static int thread__set_comm(struct thread *self, const char *comm)
400{
Peter Zijlstra82292892009-06-03 12:37:36 +0200401 if (self->comm)
402 free(self->comm);
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300403 self->comm = strdup(comm);
Arnaldo Carvalho de Melo52d422d2009-07-10 22:47:28 -0300404 if (!self->comm)
405 return -ENOMEM;
406
407 if (!col_width_list_str && !field_sep &&
408 (!comm_list || strlist__has_entry(comm_list, comm))) {
409 unsigned int slen = strlen(comm);
410 if (slen > comms__col_width) {
411 comms__col_width = slen;
412 threads__col_width = slen + 6;
413 }
414 }
415
416 return 0;
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300417}
418
Arnaldo Carvalho de Melo9ac99542009-06-04 13:54:00 -0300419static size_t thread__fprintf(struct thread *self, FILE *fp)
420{
421 struct map *pos;
422 size_t ret = fprintf(fp, "Thread %d %s\n", self->pid, self->comm);
423
424 list_for_each_entry(pos, &self->maps, node)
425 ret += map__fprintf(pos, fp);
426
427 return ret;
428}
429
430
Ingo Molnar16f762a2009-05-27 09:10:38 +0200431static struct rb_root threads;
Ingo Molnareed4dcd2009-06-03 19:59:24 +0200432static struct thread *last_match;
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300433
434static struct thread *threads__findnew(pid_t pid)
435{
Arnaldo Carvalho de Meloce7e4362009-05-19 09:30:23 -0300436 struct rb_node **p = &threads.rb_node;
437 struct rb_node *parent = NULL;
438 struct thread *th;
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300439
Ingo Molnareed4dcd2009-06-03 19:59:24 +0200440 /*
441 * Font-end cache - PID lookups come in blocks,
442 * so most of the time we dont have to look up
443 * the full rbtree:
444 */
445 if (last_match && last_match->pid == pid)
446 return last_match;
447
Arnaldo Carvalho de Meloce7e4362009-05-19 09:30:23 -0300448 while (*p != NULL) {
449 parent = *p;
450 th = rb_entry(parent, struct thread, rb_node);
451
Ingo Molnareed4dcd2009-06-03 19:59:24 +0200452 if (th->pid == pid) {
453 last_match = th;
Arnaldo Carvalho de Meloce7e4362009-05-19 09:30:23 -0300454 return th;
Ingo Molnareed4dcd2009-06-03 19:59:24 +0200455 }
Arnaldo Carvalho de Meloce7e4362009-05-19 09:30:23 -0300456
457 if (pid < th->pid)
458 p = &(*p)->rb_left;
459 else
460 p = &(*p)->rb_right;
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300461 }
462
Arnaldo Carvalho de Meloce7e4362009-05-19 09:30:23 -0300463 th = thread__new(pid);
464 if (th != NULL) {
465 rb_link_node(&th->rb_node, parent, p);
466 rb_insert_color(&th->rb_node, &threads);
Ingo Molnareed4dcd2009-06-03 19:59:24 +0200467 last_match = th;
Arnaldo Carvalho de Meloce7e4362009-05-19 09:30:23 -0300468 }
Ingo Molnareed4dcd2009-06-03 19:59:24 +0200469
Arnaldo Carvalho de Meloce7e4362009-05-19 09:30:23 -0300470 return th;
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300471}
472
473static void thread__insert_map(struct thread *self, struct map *map)
474{
Peter Zijlstra62fc4452009-06-04 16:53:49 +0200475 struct map *pos, *tmp;
476
477 list_for_each_entry_safe(pos, tmp, &self->maps, node) {
478 if (map__overlap(pos, map)) {
Peter Zijlstra3d906ef2009-06-23 11:23:07 +0200479 if (verbose >= 2) {
480 printf("overlapping maps:\n");
481 map__fprintf(map, stdout);
482 map__fprintf(pos, stdout);
483 }
484
485 if (map->start <= pos->start && map->end > pos->start)
486 pos->start = map->end;
487
488 if (map->end >= pos->end && map->start < pos->end)
489 pos->end = map->start;
490
491 if (verbose >= 2) {
492 printf("after collision:\n");
493 map__fprintf(pos, stdout);
494 }
495
496 if (pos->start >= pos->end) {
497 list_del_init(&pos->node);
498 free(pos);
499 }
Peter Zijlstra62fc4452009-06-04 16:53:49 +0200500 }
501 }
502
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300503 list_add_tail(&map->node, &self->maps);
504}
505
Peter Zijlstra62fc4452009-06-04 16:53:49 +0200506static int thread__fork(struct thread *self, struct thread *parent)
507{
508 struct map *map;
509
510 if (self->comm)
511 free(self->comm);
512 self->comm = strdup(parent->comm);
513 if (!self->comm)
514 return -ENOMEM;
515
516 list_for_each_entry(map, &parent->maps, node) {
517 struct map *new = map__clone(map);
518 if (!new)
519 return -ENOMEM;
520 thread__insert_map(self, new);
521 }
522
523 return 0;
524}
525
Paul Mackerras9cffa8d2009-06-19 22:21:42 +1000526static struct map *thread__find_map(struct thread *self, u64 ip)
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300527{
Ingo Molnar16f762a2009-05-27 09:10:38 +0200528 struct map *pos;
529
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300530 if (self == NULL)
531 return NULL;
532
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300533 list_for_each_entry(pos, &self->maps, node)
534 if (ip >= pos->start && ip <= pos->end)
535 return pos;
536
537 return NULL;
538}
539
Arnaldo Carvalho de Melo9ac99542009-06-04 13:54:00 -0300540static size_t threads__fprintf(FILE *fp)
541{
542 size_t ret = 0;
543 struct rb_node *nd;
544
545 for (nd = rb_first(&threads); nd; nd = rb_next(nd)) {
546 struct thread *pos = rb_entry(nd, struct thread, rb_node);
547
548 ret += thread__fprintf(pos, fp);
549 }
550
551 return ret;
552}
553
Peter Zijlstrae7fb08b2009-05-27 20:20:24 +0200554/*
555 * histogram, sorted on item, collects counts
556 */
557
558static struct rb_root hist;
559
560struct hist_entry {
Frederic Weisbeckerf55c5552009-06-26 16:28:01 +0200561 struct rb_node rb_node;
Peter Zijlstrae7fb08b2009-05-27 20:20:24 +0200562
Frederic Weisbeckerf55c5552009-06-26 16:28:01 +0200563 struct thread *thread;
564 struct map *map;
565 struct dso *dso;
566 struct symbol *sym;
567 struct symbol *parent;
568 u64 ip;
569 char level;
570 struct callchain_node callchain;
571 struct rb_root sorted_chain;
Peter Zijlstrae7fb08b2009-05-27 20:20:24 +0200572
Frederic Weisbeckerf55c5552009-06-26 16:28:01 +0200573 u64 count;
Peter Zijlstrae7fb08b2009-05-27 20:20:24 +0200574};
575
Peter Zijlstra1aa16732009-05-27 20:20:25 +0200576/*
577 * configurable sorting bits
578 */
579
580struct sort_entry {
581 struct list_head list;
582
Peter Zijlstraca8cdee2009-05-28 11:08:33 +0200583 char *header;
584
Peter Zijlstra1aa16732009-05-27 20:20:25 +0200585 int64_t (*cmp)(struct hist_entry *, struct hist_entry *);
Peter Zijlstra82292892009-06-03 12:37:36 +0200586 int64_t (*collapse)(struct hist_entry *, struct hist_entry *);
Arnaldo Carvalho de Melo52d422d2009-07-10 22:47:28 -0300587 size_t (*print)(FILE *fp, struct hist_entry *, unsigned int width);
588 unsigned int *width;
Arnaldo Carvalho de Melo021191b2009-07-11 12:18:35 -0300589 bool elide;
Peter Zijlstra1aa16732009-05-27 20:20:25 +0200590};
591
Peter Zijlstra6e7d6fd2009-06-17 15:51:44 +0200592static int64_t cmp_null(void *l, void *r)
593{
594 if (!l && !r)
595 return 0;
596 else if (!l)
597 return -1;
598 else
599 return 1;
600}
601
Peter Zijlstra82292892009-06-03 12:37:36 +0200602/* --sort pid */
603
Peter Zijlstrae7fb08b2009-05-27 20:20:24 +0200604static int64_t
Peter Zijlstra1aa16732009-05-27 20:20:25 +0200605sort__thread_cmp(struct hist_entry *left, struct hist_entry *right)
606{
607 return right->thread->pid - left->thread->pid;
608}
609
610static size_t
Arnaldo Carvalho de Melo52d422d2009-07-10 22:47:28 -0300611sort__thread_print(FILE *fp, struct hist_entry *self, unsigned int width)
Peter Zijlstra1aa16732009-05-27 20:20:25 +0200612{
Arnaldo Carvalho de Melo52d422d2009-07-10 22:47:28 -0300613 return repsep_fprintf(fp, "%*s:%5d", width - 6,
614 self->thread->comm ?: "", self->thread->pid);
Peter Zijlstra1aa16732009-05-27 20:20:25 +0200615}
616
617static struct sort_entry sort_thread = {
Arnaldo Carvalho de Melo52d422d2009-07-10 22:47:28 -0300618 .header = "Command: Pid",
Peter Zijlstra1aa16732009-05-27 20:20:25 +0200619 .cmp = sort__thread_cmp,
620 .print = sort__thread_print,
Arnaldo Carvalho de Melo52d422d2009-07-10 22:47:28 -0300621 .width = &threads__col_width,
Peter Zijlstra1aa16732009-05-27 20:20:25 +0200622};
623
Peter Zijlstra82292892009-06-03 12:37:36 +0200624/* --sort comm */
625
Peter Zijlstra1aa16732009-05-27 20:20:25 +0200626static int64_t
Peter Zijlstra992444b2009-05-27 20:20:27 +0200627sort__comm_cmp(struct hist_entry *left, struct hist_entry *right)
628{
Peter Zijlstra82292892009-06-03 12:37:36 +0200629 return right->thread->pid - left->thread->pid;
630}
631
632static int64_t
633sort__comm_collapse(struct hist_entry *left, struct hist_entry *right)
634{
Peter Zijlstra992444b2009-05-27 20:20:27 +0200635 char *comm_l = left->thread->comm;
636 char *comm_r = right->thread->comm;
637
Peter Zijlstra6e7d6fd2009-06-17 15:51:44 +0200638 if (!comm_l || !comm_r)
639 return cmp_null(comm_l, comm_r);
Peter Zijlstra992444b2009-05-27 20:20:27 +0200640
641 return strcmp(comm_l, comm_r);
642}
643
644static size_t
Arnaldo Carvalho de Melo52d422d2009-07-10 22:47:28 -0300645sort__comm_print(FILE *fp, struct hist_entry *self, unsigned int width)
Peter Zijlstra992444b2009-05-27 20:20:27 +0200646{
Arnaldo Carvalho de Melo52d422d2009-07-10 22:47:28 -0300647 return repsep_fprintf(fp, "%*s", width, self->thread->comm);
Peter Zijlstra992444b2009-05-27 20:20:27 +0200648}
649
650static struct sort_entry sort_comm = {
Arnaldo Carvalho de Melo52d422d2009-07-10 22:47:28 -0300651 .header = "Command",
Peter Zijlstra82292892009-06-03 12:37:36 +0200652 .cmp = sort__comm_cmp,
653 .collapse = sort__comm_collapse,
654 .print = sort__comm_print,
Arnaldo Carvalho de Melo52d422d2009-07-10 22:47:28 -0300655 .width = &comms__col_width,
Peter Zijlstra992444b2009-05-27 20:20:27 +0200656};
657
Peter Zijlstra82292892009-06-03 12:37:36 +0200658/* --sort dso */
659
Peter Zijlstra992444b2009-05-27 20:20:27 +0200660static int64_t
Peter Zijlstra55e5ec42009-05-27 20:20:28 +0200661sort__dso_cmp(struct hist_entry *left, struct hist_entry *right)
662{
663 struct dso *dso_l = left->dso;
664 struct dso *dso_r = right->dso;
665
Peter Zijlstra6e7d6fd2009-06-17 15:51:44 +0200666 if (!dso_l || !dso_r)
667 return cmp_null(dso_l, dso_r);
Peter Zijlstra55e5ec42009-05-27 20:20:28 +0200668
669 return strcmp(dso_l->name, dso_r->name);
670}
671
672static size_t
Arnaldo Carvalho de Melo52d422d2009-07-10 22:47:28 -0300673sort__dso_print(FILE *fp, struct hist_entry *self, unsigned int width)
Peter Zijlstra55e5ec42009-05-27 20:20:28 +0200674{
Ingo Molnar0a520c62009-06-02 23:24:45 +0200675 if (self->dso)
Arnaldo Carvalho de Melo52d422d2009-07-10 22:47:28 -0300676 return repsep_fprintf(fp, "%-*s", width, self->dso->name);
Ingo Molnar0a520c62009-06-02 23:24:45 +0200677
Arnaldo Carvalho de Melo52d422d2009-07-10 22:47:28 -0300678 return repsep_fprintf(fp, "%*llx", width, (u64)self->ip);
Peter Zijlstra55e5ec42009-05-27 20:20:28 +0200679}
680
681static struct sort_entry sort_dso = {
Arnaldo Carvalho de Melo52d422d2009-07-10 22:47:28 -0300682 .header = "Shared Object",
Peter Zijlstra55e5ec42009-05-27 20:20:28 +0200683 .cmp = sort__dso_cmp,
684 .print = sort__dso_print,
Arnaldo Carvalho de Melo52d422d2009-07-10 22:47:28 -0300685 .width = &dsos__col_width,
Peter Zijlstra55e5ec42009-05-27 20:20:28 +0200686};
687
Peter Zijlstra82292892009-06-03 12:37:36 +0200688/* --sort symbol */
689
Peter Zijlstra55e5ec42009-05-27 20:20:28 +0200690static int64_t
Peter Zijlstra1aa16732009-05-27 20:20:25 +0200691sort__sym_cmp(struct hist_entry *left, struct hist_entry *right)
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300692{
Paul Mackerras9cffa8d2009-06-19 22:21:42 +1000693 u64 ip_l, ip_r;
Peter Zijlstrae7fb08b2009-05-27 20:20:24 +0200694
695 if (left->sym == right->sym)
696 return 0;
697
698 ip_l = left->sym ? left->sym->start : left->ip;
699 ip_r = right->sym ? right->sym->start : right->ip;
700
701 return (int64_t)(ip_r - ip_l);
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300702}
703
Peter Zijlstra1aa16732009-05-27 20:20:25 +0200704static size_t
Arnaldo Carvalho de Melo52d422d2009-07-10 22:47:28 -0300705sort__sym_print(FILE *fp, struct hist_entry *self, unsigned int width __used)
Peter Zijlstra1aa16732009-05-27 20:20:25 +0200706{
707 size_t ret = 0;
708
Peter Zijlstra1aa16732009-05-27 20:20:25 +0200709 if (verbose)
Arnaldo Carvalho de Melo94cb9e32009-08-06 14:43:17 -0300710 ret += repsep_fprintf(fp, "%#018llx %c ", (u64)self->ip,
711 dso__symtab_origin(self->dso));
Peter Zijlstra1aa16732009-05-27 20:20:25 +0200712
Arnaldo Carvalho de Melo60c1baf2009-07-11 12:18:33 -0300713 ret += repsep_fprintf(fp, "[%c] ", self->level);
Ingo Molnar8edd4282009-06-05 14:13:18 +0200714 if (self->sym) {
Arnaldo Carvalho de Melo60c1baf2009-07-11 12:18:33 -0300715 ret += repsep_fprintf(fp, "%s", self->sym->name);
Mike Galbraith42976482009-07-02 08:09:46 +0200716
717 if (self->sym->module)
Arnaldo Carvalho de Melo52d422d2009-07-10 22:47:28 -0300718 ret += repsep_fprintf(fp, "\t[%s]",
719 self->sym->module->name);
Ingo Molnar8edd4282009-06-05 14:13:18 +0200720 } else {
Arnaldo Carvalho de Melo52d422d2009-07-10 22:47:28 -0300721 ret += repsep_fprintf(fp, "%#016llx", (u64)self->ip);
Ingo Molnar8edd4282009-06-05 14:13:18 +0200722 }
Peter Zijlstra1aa16732009-05-27 20:20:25 +0200723
724 return ret;
725}
726
727static struct sort_entry sort_sym = {
Peter Zijlstra71dd8942009-06-04 15:16:56 +0200728 .header = "Symbol",
Peter Zijlstraca8cdee2009-05-28 11:08:33 +0200729 .cmp = sort__sym_cmp,
730 .print = sort__sym_print,
Peter Zijlstra1aa16732009-05-27 20:20:25 +0200731};
732
Ingo Molnarb25bcf22009-06-18 07:01:03 +0200733/* --sort parent */
Peter Zijlstra6e7d6fd2009-06-17 15:51:44 +0200734
735static int64_t
Ingo Molnarb25bcf22009-06-18 07:01:03 +0200736sort__parent_cmp(struct hist_entry *left, struct hist_entry *right)
Peter Zijlstra6e7d6fd2009-06-17 15:51:44 +0200737{
Ingo Molnarb25bcf22009-06-18 07:01:03 +0200738 struct symbol *sym_l = left->parent;
739 struct symbol *sym_r = right->parent;
Peter Zijlstra6e7d6fd2009-06-17 15:51:44 +0200740
741 if (!sym_l || !sym_r)
742 return cmp_null(sym_l, sym_r);
743
744 return strcmp(sym_l->name, sym_r->name);
745}
746
747static size_t
Arnaldo Carvalho de Melo52d422d2009-07-10 22:47:28 -0300748sort__parent_print(FILE *fp, struct hist_entry *self, unsigned int width)
Peter Zijlstra6e7d6fd2009-06-17 15:51:44 +0200749{
Arnaldo Carvalho de Melo52d422d2009-07-10 22:47:28 -0300750 return repsep_fprintf(fp, "%-*s", width,
751 self->parent ? self->parent->name : "[other]");
Peter Zijlstra6e7d6fd2009-06-17 15:51:44 +0200752}
753
Arnaldo Carvalho de Melo52d422d2009-07-10 22:47:28 -0300754static unsigned int parent_symbol__col_width;
755
Ingo Molnarb25bcf22009-06-18 07:01:03 +0200756static struct sort_entry sort_parent = {
Arnaldo Carvalho de Melo52d422d2009-07-10 22:47:28 -0300757 .header = "Parent symbol",
Ingo Molnarb25bcf22009-06-18 07:01:03 +0200758 .cmp = sort__parent_cmp,
759 .print = sort__parent_print,
Arnaldo Carvalho de Melo52d422d2009-07-10 22:47:28 -0300760 .width = &parent_symbol__col_width,
Peter Zijlstra6e7d6fd2009-06-17 15:51:44 +0200761};
762
Peter Zijlstra82292892009-06-03 12:37:36 +0200763static int sort__need_collapse = 0;
Ingo Molnarb25bcf22009-06-18 07:01:03 +0200764static int sort__has_parent = 0;
Peter Zijlstra82292892009-06-03 12:37:36 +0200765
Peter Zijlstra37f440c2009-05-27 20:20:26 +0200766struct sort_dimension {
Ingo Molnar8edd4282009-06-05 14:13:18 +0200767 char *name;
768 struct sort_entry *entry;
769 int taken;
Peter Zijlstra37f440c2009-05-27 20:20:26 +0200770};
771
772static struct sort_dimension sort_dimensions[] = {
773 { .name = "pid", .entry = &sort_thread, },
Peter Zijlstra992444b2009-05-27 20:20:27 +0200774 { .name = "comm", .entry = &sort_comm, },
Peter Zijlstra55e5ec42009-05-27 20:20:28 +0200775 { .name = "dso", .entry = &sort_dso, },
Peter Zijlstra37f440c2009-05-27 20:20:26 +0200776 { .name = "symbol", .entry = &sort_sym, },
Ingo Molnarb25bcf22009-06-18 07:01:03 +0200777 { .name = "parent", .entry = &sort_parent, },
Peter Zijlstra37f440c2009-05-27 20:20:26 +0200778};
779
Peter Zijlstra1aa16732009-05-27 20:20:25 +0200780static LIST_HEAD(hist_entry__sort_list);
781
Peter Zijlstra37f440c2009-05-27 20:20:26 +0200782static int sort_dimension__add(char *tok)
783{
Ingo Molnarf37a2912009-07-01 12:37:06 +0200784 unsigned int i;
Peter Zijlstra37f440c2009-05-27 20:20:26 +0200785
786 for (i = 0; i < ARRAY_SIZE(sort_dimensions); i++) {
787 struct sort_dimension *sd = &sort_dimensions[i];
788
789 if (sd->taken)
790 continue;
791
Ingo Molnar5352f352009-06-03 10:07:39 +0200792 if (strncasecmp(tok, sd->name, strlen(tok)))
Peter Zijlstra37f440c2009-05-27 20:20:26 +0200793 continue;
794
Peter Zijlstra82292892009-06-03 12:37:36 +0200795 if (sd->entry->collapse)
796 sort__need_collapse = 1;
797
Ingo Molnarb25bcf22009-06-18 07:01:03 +0200798 if (sd->entry == &sort_parent) {
799 int ret = regcomp(&parent_regex, parent_pattern, REG_EXTENDED);
Peter Zijlstra6e7d6fd2009-06-17 15:51:44 +0200800 if (ret) {
801 char err[BUFSIZ];
802
Ingo Molnarb25bcf22009-06-18 07:01:03 +0200803 regerror(ret, &parent_regex, err, sizeof(err));
804 fprintf(stderr, "Invalid regex: %s\n%s",
805 parent_pattern, err);
Peter Zijlstra6e7d6fd2009-06-17 15:51:44 +0200806 exit(-1);
807 }
Ingo Molnarb25bcf22009-06-18 07:01:03 +0200808 sort__has_parent = 1;
Peter Zijlstra6e7d6fd2009-06-17 15:51:44 +0200809 }
810
Peter Zijlstra37f440c2009-05-27 20:20:26 +0200811 list_add_tail(&sd->entry->list, &hist_entry__sort_list);
812 sd->taken = 1;
Ingo Molnar5352f352009-06-03 10:07:39 +0200813
Peter Zijlstra37f440c2009-05-27 20:20:26 +0200814 return 0;
815 }
816
817 return -ESRCH;
818}
819
Peter Zijlstra1aa16732009-05-27 20:20:25 +0200820static int64_t
821hist_entry__cmp(struct hist_entry *left, struct hist_entry *right)
822{
823 struct sort_entry *se;
824 int64_t cmp = 0;
825
826 list_for_each_entry(se, &hist_entry__sort_list, list) {
827 cmp = se->cmp(left, right);
828 if (cmp)
829 break;
830 }
831
832 return cmp;
833}
834
Peter Zijlstra82292892009-06-03 12:37:36 +0200835static int64_t
836hist_entry__collapse(struct hist_entry *left, struct hist_entry *right)
837{
838 struct sort_entry *se;
839 int64_t cmp = 0;
840
841 list_for_each_entry(se, &hist_entry__sort_list, list) {
842 int64_t (*f)(struct hist_entry *, struct hist_entry *);
843
844 f = se->collapse ?: se->cmp;
845
846 cmp = f(left, right);
847 if (cmp)
848 break;
849 }
850
851 return cmp;
852}
853
Frederic Weisbecker4eb3e472009-07-02 17:58:21 +0200854static size_t ipchain__fprintf_graph_line(FILE *fp, int depth, int depth_mask)
855{
856 int i;
857 size_t ret = 0;
858
859 ret += fprintf(fp, "%s", " ");
860
861 for (i = 0; i < depth; i++)
862 if (depth_mask & (1 << i))
863 ret += fprintf(fp, "| ");
864 else
865 ret += fprintf(fp, " ");
866
867 ret += fprintf(fp, "\n");
868
869 return ret;
870}
Peter Zijlstra1aa16732009-05-27 20:20:25 +0200871static size_t
Frederic Weisbecker4eb3e472009-07-02 17:58:21 +0200872ipchain__fprintf_graph(FILE *fp, struct callchain_list *chain, int depth,
873 int depth_mask, int count, u64 total_samples,
874 int hits)
875{
876 int i;
877 size_t ret = 0;
878
879 ret += fprintf(fp, "%s", " ");
880 for (i = 0; i < depth; i++) {
881 if (depth_mask & (1 << i))
882 ret += fprintf(fp, "|");
883 else
884 ret += fprintf(fp, " ");
885 if (!count && i == depth - 1) {
886 double percent;
887
888 percent = hits * 100.0 / total_samples;
Frederic Weisbecker24b57c62009-07-02 20:14:35 +0200889 ret += percent_color_fprintf(fp, "--%2.2f%%-- ", percent);
Frederic Weisbecker4eb3e472009-07-02 17:58:21 +0200890 } else
891 ret += fprintf(fp, "%s", " ");
892 }
893 if (chain->sym)
894 ret += fprintf(fp, "%s\n", chain->sym->name);
895 else
896 ret += fprintf(fp, "%p\n", (void *)(long)chain->ip);
897
898 return ret;
899}
900
Frederic Weisbecker25446032009-08-08 02:16:25 +0200901static struct symbol *rem_sq_bracket;
902static struct callchain_list rem_hits;
903
904static void init_rem_hits(void)
905{
906 rem_sq_bracket = malloc(sizeof(*rem_sq_bracket) + 6);
907 if (!rem_sq_bracket) {
908 fprintf(stderr, "Not enough memory to display remaining hits\n");
909 return;
910 }
911
912 strcpy(rem_sq_bracket->name, "[...]");
913 rem_hits.sym = rem_sq_bracket;
914}
915
Frederic Weisbecker4eb3e472009-07-02 17:58:21 +0200916static size_t
917callchain__fprintf_graph(FILE *fp, struct callchain_node *self,
918 u64 total_samples, int depth, int depth_mask)
919{
920 struct rb_node *node, *next;
921 struct callchain_node *child;
922 struct callchain_list *chain;
923 int new_depth_mask = depth_mask;
Frederic Weisbecker805d1272009-07-05 07:39:21 +0200924 u64 new_total;
Frederic Weisbecker25446032009-08-08 02:16:25 +0200925 u64 remaining;
Frederic Weisbecker4eb3e472009-07-02 17:58:21 +0200926 size_t ret = 0;
927 int i;
928
Frederic Weisbecker805d1272009-07-05 07:39:21 +0200929 if (callchain_param.mode == CHAIN_GRAPH_REL)
Frederic Weisbecker19532872009-08-07 07:11:05 +0200930 new_total = self->children_hit;
Frederic Weisbecker805d1272009-07-05 07:39:21 +0200931 else
932 new_total = total_samples;
933
Frederic Weisbecker25446032009-08-08 02:16:25 +0200934 remaining = new_total;
935
Frederic Weisbecker4eb3e472009-07-02 17:58:21 +0200936 node = rb_first(&self->rb_root);
937 while (node) {
Frederic Weisbecker25446032009-08-08 02:16:25 +0200938 u64 cumul;
939
Frederic Weisbecker4eb3e472009-07-02 17:58:21 +0200940 child = rb_entry(node, struct callchain_node, rb_node);
Frederic Weisbecker25446032009-08-08 02:16:25 +0200941 cumul = cumul_hits(child);
942 remaining -= cumul;
Frederic Weisbecker4eb3e472009-07-02 17:58:21 +0200943
944 /*
945 * The depth mask manages the output of pipes that show
946 * the depth. We don't want to keep the pipes of the current
Frederic Weisbecker25446032009-08-08 02:16:25 +0200947 * level for the last child of this depth.
948 * Except if we have remaining filtered hits. They will
949 * supersede the last child
Frederic Weisbecker4eb3e472009-07-02 17:58:21 +0200950 */
951 next = rb_next(node);
Frederic Weisbecker25446032009-08-08 02:16:25 +0200952 if (!next && (callchain_param.mode != CHAIN_GRAPH_REL || !remaining))
Frederic Weisbecker4eb3e472009-07-02 17:58:21 +0200953 new_depth_mask &= ~(1 << (depth - 1));
954
955 /*
956 * But we keep the older depth mask for the line seperator
957 * to keep the level link until we reach the last child
958 */
959 ret += ipchain__fprintf_graph_line(fp, depth, depth_mask);
960 i = 0;
961 list_for_each_entry(chain, &child->val, list) {
962 if (chain->ip >= PERF_CONTEXT_MAX)
963 continue;
964 ret += ipchain__fprintf_graph(fp, chain, depth,
965 new_depth_mask, i++,
Frederic Weisbecker805d1272009-07-05 07:39:21 +0200966 new_total,
Frederic Weisbecker25446032009-08-08 02:16:25 +0200967 cumul);
Frederic Weisbecker4eb3e472009-07-02 17:58:21 +0200968 }
Frederic Weisbecker805d1272009-07-05 07:39:21 +0200969 ret += callchain__fprintf_graph(fp, child, new_total,
Frederic Weisbecker4eb3e472009-07-02 17:58:21 +0200970 depth + 1,
971 new_depth_mask | (1 << depth));
972 node = next;
973 }
974
Frederic Weisbecker25446032009-08-08 02:16:25 +0200975 if (callchain_param.mode == CHAIN_GRAPH_REL &&
976 remaining && remaining != new_total) {
977
978 if (!rem_sq_bracket)
979 return ret;
980
981 new_depth_mask &= ~(1 << (depth - 1));
982
983 ret += ipchain__fprintf_graph(fp, &rem_hits, depth,
984 new_depth_mask, 0, new_total,
985 remaining);
986 }
987
Frederic Weisbecker4eb3e472009-07-02 17:58:21 +0200988 return ret;
989}
990
991static size_t
992callchain__fprintf_flat(FILE *fp, struct callchain_node *self,
993 u64 total_samples)
Frederic Weisbeckerf55c5552009-06-26 16:28:01 +0200994{
995 struct callchain_list *chain;
996 size_t ret = 0;
997
998 if (!self)
999 return 0;
1000
Frederic Weisbecker4eb3e472009-07-02 17:58:21 +02001001 ret += callchain__fprintf_flat(fp, self->parent, total_samples);
Frederic Weisbeckerf55c5552009-06-26 16:28:01 +02001002
1003
Frederic Weisbecker44249612009-07-01 05:35:14 +02001004 list_for_each_entry(chain, &self->val, list) {
1005 if (chain->ip >= PERF_CONTEXT_MAX)
1006 continue;
1007 if (chain->sym)
1008 ret += fprintf(fp, " %s\n", chain->sym->name);
1009 else
1010 ret += fprintf(fp, " %p\n",
Ingo Molnarf37a2912009-07-01 12:37:06 +02001011 (void *)(long)chain->ip);
Frederic Weisbecker44249612009-07-01 05:35:14 +02001012 }
Frederic Weisbeckerf55c5552009-06-26 16:28:01 +02001013
1014 return ret;
1015}
1016
1017static size_t
1018hist_entry_callchain__fprintf(FILE *fp, struct hist_entry *self,
1019 u64 total_samples)
1020{
1021 struct rb_node *rb_node;
1022 struct callchain_node *chain;
1023 size_t ret = 0;
1024
1025 rb_node = rb_first(&self->sorted_chain);
1026 while (rb_node) {
1027 double percent;
1028
1029 chain = rb_entry(rb_node, struct callchain_node, rb_node);
1030 percent = chain->hit * 100.0 / total_samples;
Frederic Weisbecker805d1272009-07-05 07:39:21 +02001031 switch (callchain_param.mode) {
1032 case CHAIN_FLAT:
Frederic Weisbecker24b57c62009-07-02 20:14:35 +02001033 ret += percent_color_fprintf(fp, " %6.2f%%\n",
1034 percent);
Frederic Weisbecker4eb3e472009-07-02 17:58:21 +02001035 ret += callchain__fprintf_flat(fp, chain, total_samples);
Frederic Weisbecker805d1272009-07-05 07:39:21 +02001036 break;
1037 case CHAIN_GRAPH_ABS: /* Falldown */
1038 case CHAIN_GRAPH_REL:
Frederic Weisbecker4eb3e472009-07-02 17:58:21 +02001039 ret += callchain__fprintf_graph(fp, chain,
1040 total_samples, 1, 1);
Frederic Weisbecker805d1272009-07-05 07:39:21 +02001041 default:
1042 break;
Frederic Weisbecker4eb3e472009-07-02 17:58:21 +02001043 }
Frederic Weisbeckerf55c5552009-06-26 16:28:01 +02001044 ret += fprintf(fp, "\n");
1045 rb_node = rb_next(rb_node);
1046 }
1047
1048 return ret;
1049}
1050
1051
1052static size_t
Paul Mackerras9cffa8d2009-06-19 22:21:42 +10001053hist_entry__fprintf(FILE *fp, struct hist_entry *self, u64 total_samples)
Peter Zijlstra1aa16732009-05-27 20:20:25 +02001054{
1055 struct sort_entry *se;
1056 size_t ret;
1057
Ingo Molnarb8e6d822009-06-18 14:32:19 +02001058 if (exclude_other && !self->parent)
1059 return 0;
1060
Frederic Weisbecker1e11fd82009-07-02 20:14:34 +02001061 if (total_samples)
Arnaldo Carvalho de Melo52d422d2009-07-10 22:47:28 -03001062 ret = percent_color_fprintf(fp,
1063 field_sep ? "%.2f" : " %6.2f%%",
1064 (self->count * 100.0) / total_samples);
Frederic Weisbecker1e11fd82009-07-02 20:14:34 +02001065 else
Arnaldo Carvalho de Melo52d422d2009-07-10 22:47:28 -03001066 ret = fprintf(fp, field_sep ? "%lld" : "%12lld ", self->count);
Peter Zijlstra1aa16732009-05-27 20:20:25 +02001067
Arnaldo Carvalho de Meloe3d7e182009-07-11 12:18:37 -03001068 if (show_nr_samples) {
1069 if (field_sep)
1070 fprintf(fp, "%c%lld", *field_sep, self->count);
1071 else
1072 fprintf(fp, "%11lld", self->count);
1073 }
Peter Zijlstra1aa16732009-05-27 20:20:25 +02001074
Peter Zijlstra71dd8942009-06-04 15:16:56 +02001075 list_for_each_entry(se, &hist_entry__sort_list, list) {
Arnaldo Carvalho de Melo021191b2009-07-11 12:18:35 -03001076 if (se->elide)
Ingo Molnarb8e6d822009-06-18 14:32:19 +02001077 continue;
1078
Arnaldo Carvalho de Melo52d422d2009-07-10 22:47:28 -03001079 fprintf(fp, "%s", field_sep ?: " ");
1080 ret += se->print(fp, self, se->width ? *se->width : 0);
Peter Zijlstra71dd8942009-06-04 15:16:56 +02001081 }
Peter Zijlstra1aa16732009-05-27 20:20:25 +02001082
1083 ret += fprintf(fp, "\n");
1084
Frederic Weisbeckerf55c5552009-06-26 16:28:01 +02001085 if (callchain)
1086 hist_entry_callchain__fprintf(fp, self, total_samples);
1087
Peter Zijlstra1aa16732009-05-27 20:20:25 +02001088 return ret;
1089}
1090
1091/*
Peter Zijlstra6e7d6fd2009-06-17 15:51:44 +02001092 *
1093 */
1094
Arnaldo Carvalho de Melo52d422d2009-07-10 22:47:28 -03001095static void dso__calc_col_width(struct dso *self)
1096{
1097 if (!col_width_list_str && !field_sep &&
1098 (!dso_list || strlist__has_entry(dso_list, self->name))) {
1099 unsigned int slen = strlen(self->name);
1100 if (slen > dsos__col_width)
1101 dsos__col_width = slen;
1102 }
1103
1104 self->slen_calculated = 1;
1105}
1106
Peter Zijlstra6e7d6fd2009-06-17 15:51:44 +02001107static struct symbol *
1108resolve_symbol(struct thread *thread, struct map **mapp,
Paul Mackerras9cffa8d2009-06-19 22:21:42 +10001109 struct dso **dsop, u64 *ipp)
Peter Zijlstra6e7d6fd2009-06-17 15:51:44 +02001110{
1111 struct dso *dso = dsop ? *dsop : NULL;
1112 struct map *map = mapp ? *mapp : NULL;
Peter Zijlstra520f2c32009-06-22 16:52:51 +02001113 u64 ip = *ipp;
Peter Zijlstra6e7d6fd2009-06-17 15:51:44 +02001114
1115 if (!thread)
1116 return NULL;
1117
1118 if (dso)
1119 goto got_dso;
1120
1121 if (map)
1122 goto got_map;
1123
1124 map = thread__find_map(thread, ip);
1125 if (map != NULL) {
Arnaldo Carvalho de Melo52d422d2009-07-10 22:47:28 -03001126 /*
1127 * We have to do this here as we may have a dso
1128 * with no symbol hit that has a name longer than
1129 * the ones with symbols sampled.
1130 */
Arnaldo Carvalho de Melo021191b2009-07-11 12:18:35 -03001131 if (!sort_dso.elide && !map->dso->slen_calculated)
Arnaldo Carvalho de Melo52d422d2009-07-10 22:47:28 -03001132 dso__calc_col_width(map->dso);
1133
Peter Zijlstra6e7d6fd2009-06-17 15:51:44 +02001134 if (mapp)
1135 *mapp = map;
1136got_map:
1137 ip = map->map_ip(map, ip);
Peter Zijlstra6e7d6fd2009-06-17 15:51:44 +02001138
1139 dso = map->dso;
1140 } else {
1141 /*
1142 * If this is outside of all known maps,
1143 * and is a negative address, try to look it
1144 * up in the kernel dso, as it might be a
1145 * vsyscall (which executes in user-mode):
1146 */
1147 if ((long long)ip < 0)
1148 dso = kernel_dso;
1149 }
1150 dprintf(" ...... dso: %s\n", dso ? dso->name : "<not found>");
Peter Zijlstra520f2c32009-06-22 16:52:51 +02001151 dprintf(" ...... map: %Lx -> %Lx\n", *ipp, ip);
1152 *ipp = ip;
Peter Zijlstra6e7d6fd2009-06-17 15:51:44 +02001153
1154 if (dsop)
1155 *dsop = dso;
1156
1157 if (!dso)
1158 return NULL;
1159got_dso:
1160 return dso->find_symbol(dso, ip);
1161}
1162
Peter Zijlstra2a0a50f2009-06-18 22:20:45 +02001163static int call__match(struct symbol *sym)
Peter Zijlstra6e7d6fd2009-06-17 15:51:44 +02001164{
Ingo Molnarb25bcf22009-06-18 07:01:03 +02001165 if (sym->name && !regexec(&parent_regex, sym->name, 0, NULL, 0))
Peter Zijlstra2a0a50f2009-06-18 22:20:45 +02001166 return 1;
Peter Zijlstra6e7d6fd2009-06-17 15:51:44 +02001167
Peter Zijlstra2a0a50f2009-06-18 22:20:45 +02001168 return 0;
Peter Zijlstra6e7d6fd2009-06-17 15:51:44 +02001169}
1170
Frederic Weisbecker44249612009-07-01 05:35:14 +02001171static struct symbol **
Ingo Molnarf37a2912009-07-01 12:37:06 +02001172resolve_callchain(struct thread *thread, struct map *map __used,
Frederic Weisbecker44249612009-07-01 05:35:14 +02001173 struct ip_callchain *chain, struct hist_entry *entry)
1174{
Frederic Weisbecker44249612009-07-01 05:35:14 +02001175 u64 context = PERF_CONTEXT_MAX;
Ingo Molnar029e5b12009-07-03 13:17:28 +02001176 struct symbol **syms = NULL;
Ingo Molnarf37a2912009-07-01 12:37:06 +02001177 unsigned int i;
Frederic Weisbecker44249612009-07-01 05:35:14 +02001178
1179 if (callchain) {
1180 syms = calloc(chain->nr, sizeof(*syms));
1181 if (!syms) {
1182 fprintf(stderr, "Can't allocate memory for symbols\n");
1183 exit(-1);
1184 }
1185 }
1186
1187 for (i = 0; i < chain->nr; i++) {
1188 u64 ip = chain->ips[i];
1189 struct dso *dso = NULL;
1190 struct symbol *sym;
1191
1192 if (ip >= PERF_CONTEXT_MAX) {
1193 context = ip;
1194 continue;
1195 }
1196
1197 switch (context) {
Ingo Molnar88a69df2009-07-01 11:17:20 +02001198 case PERF_CONTEXT_HV:
1199 dso = hypervisor_dso;
1200 break;
Frederic Weisbecker44249612009-07-01 05:35:14 +02001201 case PERF_CONTEXT_KERNEL:
1202 dso = kernel_dso;
1203 break;
1204 default:
1205 break;
1206 }
1207
1208 sym = resolve_symbol(thread, NULL, &dso, &ip);
1209
1210 if (sym) {
1211 if (sort__has_parent && call__match(sym) &&
1212 !entry->parent)
1213 entry->parent = sym;
1214 if (!callchain)
1215 break;
1216 syms[i] = sym;
1217 }
1218 }
1219
1220 return syms;
1221}
1222
Peter Zijlstra6e7d6fd2009-06-17 15:51:44 +02001223/*
Peter Zijlstra1aa16732009-05-27 20:20:25 +02001224 * collect histogram counts
1225 */
1226
Peter Zijlstrae7fb08b2009-05-27 20:20:24 +02001227static int
1228hist_entry__add(struct thread *thread, struct map *map, struct dso *dso,
Paul Mackerras9cffa8d2009-06-19 22:21:42 +10001229 struct symbol *sym, u64 ip, struct ip_callchain *chain,
1230 char level, u64 count)
Arnaldo Carvalho de Melo3a4b8cc2009-05-26 16:19:04 -03001231{
Peter Zijlstrae7fb08b2009-05-27 20:20:24 +02001232 struct rb_node **p = &hist.rb_node;
Arnaldo Carvalho de Melo3a4b8cc2009-05-26 16:19:04 -03001233 struct rb_node *parent = NULL;
Peter Zijlstrae7fb08b2009-05-27 20:20:24 +02001234 struct hist_entry *he;
Frederic Weisbecker44249612009-07-01 05:35:14 +02001235 struct symbol **syms = NULL;
Peter Zijlstrae7fb08b2009-05-27 20:20:24 +02001236 struct hist_entry entry = {
1237 .thread = thread,
1238 .map = map,
1239 .dso = dso,
1240 .sym = sym,
1241 .ip = ip,
1242 .level = level,
Peter Zijlstraea1900e2009-06-10 21:45:22 +02001243 .count = count,
Ingo Molnarb8e6d822009-06-18 14:32:19 +02001244 .parent = NULL,
Frederic Weisbeckerf55c5552009-06-26 16:28:01 +02001245 .sorted_chain = RB_ROOT
Peter Zijlstrae7fb08b2009-05-27 20:20:24 +02001246 };
1247 int cmp;
Arnaldo Carvalho de Melo3a4b8cc2009-05-26 16:19:04 -03001248
Frederic Weisbecker44249612009-07-01 05:35:14 +02001249 if ((sort__has_parent || callchain) && chain)
1250 syms = resolve_callchain(thread, map, chain, &entry);
Peter Zijlstra6e7d6fd2009-06-17 15:51:44 +02001251
Arnaldo Carvalho de Melo3a4b8cc2009-05-26 16:19:04 -03001252 while (*p != NULL) {
1253 parent = *p;
Peter Zijlstrae7fb08b2009-05-27 20:20:24 +02001254 he = rb_entry(parent, struct hist_entry, rb_node);
Arnaldo Carvalho de Melo3a4b8cc2009-05-26 16:19:04 -03001255
Peter Zijlstrae7fb08b2009-05-27 20:20:24 +02001256 cmp = hist_entry__cmp(&entry, he);
1257
1258 if (!cmp) {
Peter Zijlstraea1900e2009-06-10 21:45:22 +02001259 he->count += count;
Frederic Weisbecker44249612009-07-01 05:35:14 +02001260 if (callchain) {
1261 append_chain(&he->callchain, chain, syms);
1262 free(syms);
1263 }
Peter Zijlstrae7fb08b2009-05-27 20:20:24 +02001264 return 0;
1265 }
1266
1267 if (cmp < 0)
Arnaldo Carvalho de Melo3a4b8cc2009-05-26 16:19:04 -03001268 p = &(*p)->rb_left;
1269 else
1270 p = &(*p)->rb_right;
1271 }
1272
Peter Zijlstrae7fb08b2009-05-27 20:20:24 +02001273 he = malloc(sizeof(*he));
1274 if (!he)
1275 return -ENOMEM;
1276 *he = entry;
Frederic Weisbeckerf55c5552009-06-26 16:28:01 +02001277 if (callchain) {
1278 callchain_init(&he->callchain);
Frederic Weisbecker44249612009-07-01 05:35:14 +02001279 append_chain(&he->callchain, chain, syms);
1280 free(syms);
Frederic Weisbeckerf55c5552009-06-26 16:28:01 +02001281 }
Peter Zijlstrae7fb08b2009-05-27 20:20:24 +02001282 rb_link_node(&he->rb_node, parent, p);
1283 rb_insert_color(&he->rb_node, &hist);
1284
1285 return 0;
Arnaldo Carvalho de Melo3a4b8cc2009-05-26 16:19:04 -03001286}
1287
Peter Zijlstra82292892009-06-03 12:37:36 +02001288static void hist_entry__free(struct hist_entry *he)
1289{
1290 free(he);
1291}
1292
1293/*
1294 * collapse the histogram
1295 */
1296
1297static struct rb_root collapse_hists;
1298
1299static void collapse__insert_entry(struct hist_entry *he)
1300{
1301 struct rb_node **p = &collapse_hists.rb_node;
1302 struct rb_node *parent = NULL;
1303 struct hist_entry *iter;
1304 int64_t cmp;
1305
1306 while (*p != NULL) {
1307 parent = *p;
1308 iter = rb_entry(parent, struct hist_entry, rb_node);
1309
1310 cmp = hist_entry__collapse(iter, he);
1311
1312 if (!cmp) {
1313 iter->count += he->count;
1314 hist_entry__free(he);
1315 return;
1316 }
1317
1318 if (cmp < 0)
1319 p = &(*p)->rb_left;
1320 else
1321 p = &(*p)->rb_right;
1322 }
1323
1324 rb_link_node(&he->rb_node, parent, p);
1325 rb_insert_color(&he->rb_node, &collapse_hists);
1326}
1327
1328static void collapse__resort(void)
1329{
1330 struct rb_node *next;
1331 struct hist_entry *n;
1332
1333 if (!sort__need_collapse)
1334 return;
1335
1336 next = rb_first(&hist);
1337 while (next) {
1338 n = rb_entry(next, struct hist_entry, rb_node);
1339 next = rb_next(&n->rb_node);
1340
1341 rb_erase(&n->rb_node, &hist);
1342 collapse__insert_entry(n);
1343 }
1344}
1345
Peter Zijlstrae7fb08b2009-05-27 20:20:24 +02001346/*
1347 * reverse the map, sort on count.
1348 */
1349
1350static struct rb_root output_hists;
1351
Frederic Weisbeckerc20ab372009-07-02 20:14:33 +02001352static void output__insert_entry(struct hist_entry *he, u64 min_callchain_hits)
Peter Zijlstrae7fb08b2009-05-27 20:20:24 +02001353{
1354 struct rb_node **p = &output_hists.rb_node;
1355 struct rb_node *parent = NULL;
1356 struct hist_entry *iter;
1357
Frederic Weisbecker805d1272009-07-05 07:39:21 +02001358 if (callchain)
1359 callchain_param.sort(&he->sorted_chain, &he->callchain,
1360 min_callchain_hits, &callchain_param);
Frederic Weisbeckerf55c5552009-06-26 16:28:01 +02001361
Peter Zijlstrae7fb08b2009-05-27 20:20:24 +02001362 while (*p != NULL) {
1363 parent = *p;
1364 iter = rb_entry(parent, struct hist_entry, rb_node);
1365
1366 if (he->count > iter->count)
1367 p = &(*p)->rb_left;
1368 else
1369 p = &(*p)->rb_right;
1370 }
1371
1372 rb_link_node(&he->rb_node, parent, p);
1373 rb_insert_color(&he->rb_node, &output_hists);
1374}
1375
Frederic Weisbeckerc20ab372009-07-02 20:14:33 +02001376static void output__resort(u64 total_samples)
Peter Zijlstrae7fb08b2009-05-27 20:20:24 +02001377{
Peter Zijlstra82292892009-06-03 12:37:36 +02001378 struct rb_node *next;
Peter Zijlstrae7fb08b2009-05-27 20:20:24 +02001379 struct hist_entry *n;
Arnaldo Carvalho de Meloa4c43be2009-06-03 23:02:33 -03001380 struct rb_root *tree = &hist;
Frederic Weisbeckerc20ab372009-07-02 20:14:33 +02001381 u64 min_callchain_hits;
1382
Frederic Weisbecker805d1272009-07-05 07:39:21 +02001383 min_callchain_hits = total_samples * (callchain_param.min_percent / 100);
Peter Zijlstrae7fb08b2009-05-27 20:20:24 +02001384
Peter Zijlstra82292892009-06-03 12:37:36 +02001385 if (sort__need_collapse)
Arnaldo Carvalho de Meloa4c43be2009-06-03 23:02:33 -03001386 tree = &collapse_hists;
1387
1388 next = rb_first(tree);
Peter Zijlstra82292892009-06-03 12:37:36 +02001389
Peter Zijlstrae7fb08b2009-05-27 20:20:24 +02001390 while (next) {
1391 n = rb_entry(next, struct hist_entry, rb_node);
1392 next = rb_next(&n->rb_node);
1393
Arnaldo Carvalho de Meloa4c43be2009-06-03 23:02:33 -03001394 rb_erase(&n->rb_node, tree);
Frederic Weisbeckerc20ab372009-07-02 20:14:33 +02001395 output__insert_entry(n, min_callchain_hits);
Arnaldo Carvalho de Melo3a4b8cc2009-05-26 16:19:04 -03001396 }
1397}
1398
Paul Mackerras9cffa8d2009-06-19 22:21:42 +10001399static size_t output__fprintf(FILE *fp, u64 total_samples)
Arnaldo Carvalho de Melo3a4b8cc2009-05-26 16:19:04 -03001400{
Peter Zijlstrae7fb08b2009-05-27 20:20:24 +02001401 struct hist_entry *pos;
Ingo Molnar2d655372009-05-27 21:36:22 +02001402 struct sort_entry *se;
Arnaldo Carvalho de Melo3a4b8cc2009-05-26 16:19:04 -03001403 struct rb_node *nd;
1404 size_t ret = 0;
Arnaldo Carvalho de Melo52d422d2009-07-10 22:47:28 -03001405 unsigned int width;
1406 char *col_width = col_width_list_str;
Brice Goglin9f866692009-08-10 15:26:32 +02001407 int raw_printing_style;
1408
1409 raw_printing_style = !strcmp(pretty_printing_style, "raw");
Arnaldo Carvalho de Melo3a4b8cc2009-05-26 16:19:04 -03001410
Frederic Weisbecker25446032009-08-08 02:16:25 +02001411 init_rem_hits();
1412
Arnaldo Carvalho de Melo021191b2009-07-11 12:18:35 -03001413 fprintf(fp, "# Samples: %Ld\n", (u64)total_samples);
Ingo Molnar05ca0612009-06-04 14:21:16 +02001414 fprintf(fp, "#\n");
Peter Zijlstraca8cdee2009-05-28 11:08:33 +02001415
1416 fprintf(fp, "# Overhead");
Arnaldo Carvalho de Meloe3d7e182009-07-11 12:18:37 -03001417 if (show_nr_samples) {
1418 if (field_sep)
1419 fprintf(fp, "%cSamples", *field_sep);
1420 else
1421 fputs(" Samples ", fp);
1422 }
Ingo Molnarb8e6d822009-06-18 14:32:19 +02001423 list_for_each_entry(se, &hist_entry__sort_list, list) {
Arnaldo Carvalho de Melo021191b2009-07-11 12:18:35 -03001424 if (se->elide)
Ingo Molnarb8e6d822009-06-18 14:32:19 +02001425 continue;
Arnaldo Carvalho de Melo52d422d2009-07-10 22:47:28 -03001426 if (field_sep) {
1427 fprintf(fp, "%c%s", *field_sep, se->header);
1428 continue;
1429 }
1430 width = strlen(se->header);
1431 if (se->width) {
1432 if (col_width_list_str) {
1433 if (col_width) {
1434 *se->width = atoi(col_width);
1435 col_width = strchr(col_width, ',');
1436 if (col_width)
1437 ++col_width;
1438 }
1439 }
1440 width = *se->width = max(*se->width, width);
1441 }
1442 fprintf(fp, " %*s", width, se->header);
Ingo Molnarb8e6d822009-06-18 14:32:19 +02001443 }
Peter Zijlstraca8cdee2009-05-28 11:08:33 +02001444 fprintf(fp, "\n");
1445
Arnaldo Carvalho de Melo52d422d2009-07-10 22:47:28 -03001446 if (field_sep)
1447 goto print_entries;
1448
Peter Zijlstraca8cdee2009-05-28 11:08:33 +02001449 fprintf(fp, "# ........");
Arnaldo Carvalho de Meloe3d7e182009-07-11 12:18:37 -03001450 if (show_nr_samples)
1451 fprintf(fp, " ..........");
Ingo Molnar2d655372009-05-27 21:36:22 +02001452 list_for_each_entry(se, &hist_entry__sort_list, list) {
Ingo Molnarf37a2912009-07-01 12:37:06 +02001453 unsigned int i;
Peter Zijlstraca8cdee2009-05-28 11:08:33 +02001454
Arnaldo Carvalho de Melo021191b2009-07-11 12:18:35 -03001455 if (se->elide)
Ingo Molnarb8e6d822009-06-18 14:32:19 +02001456 continue;
1457
Ingo Molnar4593bba2009-06-02 15:34:25 +02001458 fprintf(fp, " ");
Arnaldo Carvalho de Melo52d422d2009-07-10 22:47:28 -03001459 if (se->width)
1460 width = *se->width;
1461 else
1462 width = strlen(se->header);
1463 for (i = 0; i < width; i++)
Peter Zijlstraca8cdee2009-05-28 11:08:33 +02001464 fprintf(fp, ".");
Ingo Molnar2d655372009-05-27 21:36:22 +02001465 }
Peter Zijlstraca8cdee2009-05-28 11:08:33 +02001466 fprintf(fp, "\n");
1467
1468 fprintf(fp, "#\n");
Ingo Molnar2d655372009-05-27 21:36:22 +02001469
Arnaldo Carvalho de Melo52d422d2009-07-10 22:47:28 -03001470print_entries:
Peter Zijlstrae7fb08b2009-05-27 20:20:24 +02001471 for (nd = rb_first(&output_hists); nd; nd = rb_next(nd)) {
1472 pos = rb_entry(nd, struct hist_entry, rb_node);
1473 ret += hist_entry__fprintf(fp, pos, total_samples);
Arnaldo Carvalho de Melo3a4b8cc2009-05-26 16:19:04 -03001474 }
1475
Ingo Molnarb8e6d822009-06-18 14:32:19 +02001476 if (sort_order == default_sort_order &&
1477 parent_pattern == default_parent_pattern) {
Ingo Molnarbd741372009-06-04 14:13:04 +02001478 fprintf(fp, "#\n");
Pekka Enberg114cfab2009-08-05 13:25:21 +03001479 fprintf(fp, "# (For a higher level overview, try: perf report --sort comm,dso)\n");
Ingo Molnarbd741372009-06-04 14:13:04 +02001480 fprintf(fp, "#\n");
1481 }
Peter Zijlstra71dd8942009-06-04 15:16:56 +02001482 fprintf(fp, "\n");
Ingo Molnarbd741372009-06-04 14:13:04 +02001483
Frederic Weisbecker25446032009-08-08 02:16:25 +02001484 free(rem_sq_bracket);
1485
Brice Goglin8d513272009-08-07 13:55:24 +02001486 if (show_threads)
Brice Goglin9f866692009-08-10 15:26:32 +02001487 perf_read_values_display(fp, &show_threads_values,
1488 raw_printing_style);
Brice Goglin8d513272009-08-07 13:55:24 +02001489
Arnaldo Carvalho de Melo3a4b8cc2009-05-26 16:19:04 -03001490 return ret;
1491}
1492
Peter Zijlstra436224a2009-06-02 21:02:36 +02001493static void register_idle_thread(void)
1494{
1495 struct thread *thread = threads__findnew(0);
1496
1497 if (thread == NULL ||
1498 thread__set_comm(thread, "[idle]")) {
1499 fprintf(stderr, "problem inserting idle task.\n");
1500 exit(-1);
1501 }
1502}
1503
Peter Zijlstra62fc4452009-06-04 16:53:49 +02001504static unsigned long total = 0,
1505 total_mmap = 0,
1506 total_comm = 0,
1507 total_fork = 0,
Peter Zijlstra9d91a6f2009-06-18 11:40:28 +02001508 total_unknown = 0,
1509 total_lost = 0;
Peter Zijlstrae7fb08b2009-05-27 20:20:24 +02001510
Peter Zijlstra2a0a50f2009-06-18 22:20:45 +02001511static int validate_chain(struct ip_callchain *chain, event_t *event)
Ingo Molnar75220602009-06-18 08:00:17 +02001512{
1513 unsigned int chain_size;
1514
Ingo Molnar75220602009-06-18 08:00:17 +02001515 chain_size = event->header.size;
1516 chain_size -= (unsigned long)&event->ip.__more_data - (unsigned long)event;
1517
Paul Mackerras9cffa8d2009-06-19 22:21:42 +10001518 if (chain->nr*sizeof(u64) > chain_size)
Ingo Molnar75220602009-06-18 08:00:17 +02001519 return -1;
1520
1521 return 0;
1522}
1523
Ingo Molnard80d3382009-06-03 23:14:49 +02001524static int
Peter Zijlstrae6e18ec2009-06-25 11:27:12 +02001525process_sample_event(event_t *event, unsigned long offset, unsigned long head)
Ingo Molnar75051722009-06-03 23:14:49 +02001526{
1527 char level;
1528 int show = 0;
1529 struct dso *dso = NULL;
1530 struct thread *thread = threads__findnew(event->ip.pid);
Paul Mackerras9cffa8d2009-06-19 22:21:42 +10001531 u64 ip = event->ip.ip;
1532 u64 period = 1;
Ingo Molnar75051722009-06-03 23:14:49 +02001533 struct map *map = NULL;
Ingo Molnar3efa1cc92009-06-14 15:04:15 +02001534 void *more_data = event->ip.__more_data;
Peter Zijlstra2a0a50f2009-06-18 22:20:45 +02001535 struct ip_callchain *chain = NULL;
Anton Blanchardd8db1b52009-07-01 09:00:48 +10001536 int cpumode;
Ingo Molnar75051722009-06-03 23:14:49 +02001537
Peter Zijlstrae6e18ec2009-06-25 11:27:12 +02001538 if (sample_type & PERF_SAMPLE_PERIOD) {
Paul Mackerras9cffa8d2009-06-19 22:21:42 +10001539 period = *(u64 *)more_data;
1540 more_data += sizeof(u64);
Ingo Molnar3efa1cc92009-06-14 15:04:15 +02001541 }
Peter Zijlstraea1900e2009-06-10 21:45:22 +02001542
Peter Zijlstrae6e18ec2009-06-25 11:27:12 +02001543 dprintf("%p [%p]: PERF_EVENT_SAMPLE (IP, %d): %d: %p period: %Ld\n",
Ingo Molnar75051722009-06-03 23:14:49 +02001544 (void *)(offset + head),
1545 (void *)(long)(event->header.size),
1546 event->header.misc,
1547 event->ip.pid,
Peter Zijlstra4502d772009-06-10 15:03:06 +02001548 (void *)(long)ip,
Peter Zijlstraea1900e2009-06-10 21:45:22 +02001549 (long long)period);
Ingo Molnar75051722009-06-03 23:14:49 +02001550
Peter Zijlstrae6e18ec2009-06-25 11:27:12 +02001551 if (sample_type & PERF_SAMPLE_CALLCHAIN) {
Ingo Molnarf37a2912009-07-01 12:37:06 +02001552 unsigned int i;
Ingo Molnar3efa1cc92009-06-14 15:04:15 +02001553
1554 chain = (void *)more_data;
1555
Peter Zijlstra2a0a50f2009-06-18 22:20:45 +02001556 dprintf("... chain: nr:%Lu\n", chain->nr);
Ingo Molnar3efa1cc92009-06-14 15:04:15 +02001557
Ingo Molnar75220602009-06-18 08:00:17 +02001558 if (validate_chain(chain, event) < 0) {
1559 eprintf("call-chain problem with event, skipping it.\n");
1560 return 0;
1561 }
1562
1563 if (dump_trace) {
Ingo Molnar3efa1cc92009-06-14 15:04:15 +02001564 for (i = 0; i < chain->nr; i++)
Peter Zijlstra2a0a50f2009-06-18 22:20:45 +02001565 dprintf("..... %2d: %016Lx\n", i, chain->ips[i]);
Ingo Molnar3efa1cc92009-06-14 15:04:15 +02001566 }
1567 }
1568
Ingo Molnar75051722009-06-03 23:14:49 +02001569 dprintf(" ... thread: %s:%d\n", thread->comm, thread->pid);
1570
1571 if (thread == NULL) {
Ingo Molnar75220602009-06-18 08:00:17 +02001572 eprintf("problem processing %d event, skipping it.\n",
Ingo Molnar75051722009-06-03 23:14:49 +02001573 event->header.type);
1574 return -1;
1575 }
1576
Arnaldo Carvalho de Melocc8b88b2009-06-30 19:01:21 -03001577 if (comm_list && !strlist__has_entry(comm_list, thread->comm))
1578 return 0;
1579
Anton Blanchardd8db1b52009-07-01 09:00:48 +10001580 cpumode = event->header.misc & PERF_EVENT_MISC_CPUMODE_MASK;
1581
1582 if (cpumode == PERF_EVENT_MISC_KERNEL) {
Ingo Molnar75051722009-06-03 23:14:49 +02001583 show = SHOW_KERNEL;
1584 level = 'k';
1585
1586 dso = kernel_dso;
1587
1588 dprintf(" ...... dso: %s\n", dso->name);
1589
Anton Blanchardd8db1b52009-07-01 09:00:48 +10001590 } else if (cpumode == PERF_EVENT_MISC_USER) {
Ingo Molnar75051722009-06-03 23:14:49 +02001591
1592 show = SHOW_USER;
1593 level = '.';
1594
Ingo Molnar75051722009-06-03 23:14:49 +02001595 } else {
1596 show = SHOW_HV;
1597 level = 'H';
Anton Blanchardfb9c8182009-07-01 09:00:49 +10001598
1599 dso = hypervisor_dso;
1600
Ingo Molnar75051722009-06-03 23:14:49 +02001601 dprintf(" ...... dso: [hypervisor]\n");
1602 }
1603
1604 if (show & show_mask) {
Peter Zijlstra6e7d6fd2009-06-17 15:51:44 +02001605 struct symbol *sym = resolve_symbol(thread, &map, &dso, &ip);
Peter Zijlstrafc54db52009-06-05 14:04:59 +02001606
Arnaldo Carvalho de Melo25903402009-06-30 19:01:20 -03001607 if (dso_list && dso && dso->name && !strlist__has_entry(dso_list, dso->name))
1608 return 0;
1609
Arnaldo Carvalho de Melo7bec7a92009-06-30 19:01:22 -03001610 if (sym_list && sym && !strlist__has_entry(sym_list, sym->name))
1611 return 0;
1612
Peter Zijlstra6e7d6fd2009-06-17 15:51:44 +02001613 if (hist_entry__add(thread, map, dso, sym, ip, chain, level, period)) {
Ingo Molnar75220602009-06-18 08:00:17 +02001614 eprintf("problem incrementing symbol count, skipping event\n");
Ingo Molnar75051722009-06-03 23:14:49 +02001615 return -1;
1616 }
1617 }
Peter Zijlstraea1900e2009-06-10 21:45:22 +02001618 total += period;
Ingo Molnar75051722009-06-03 23:14:49 +02001619
1620 return 0;
1621}
1622
1623static int
1624process_mmap_event(event_t *event, unsigned long offset, unsigned long head)
1625{
1626 struct thread *thread = threads__findnew(event->mmap.pid);
1627 struct map *map = map__new(&event->mmap);
1628
Peter Zijlstra62fc4452009-06-04 16:53:49 +02001629 dprintf("%p [%p]: PERF_EVENT_MMAP %d: [%p(%p) @ %p]: %s\n",
Ingo Molnar75051722009-06-03 23:14:49 +02001630 (void *)(offset + head),
1631 (void *)(long)(event->header.size),
Peter Zijlstra62fc4452009-06-04 16:53:49 +02001632 event->mmap.pid,
Ingo Molnar75051722009-06-03 23:14:49 +02001633 (void *)(long)event->mmap.start,
1634 (void *)(long)event->mmap.len,
1635 (void *)(long)event->mmap.pgoff,
1636 event->mmap.filename);
1637
1638 if (thread == NULL || map == NULL) {
1639 dprintf("problem processing PERF_EVENT_MMAP, skipping event.\n");
Ingo Molnardf979922009-06-04 13:41:22 +02001640 return 0;
Ingo Molnar75051722009-06-03 23:14:49 +02001641 }
1642
1643 thread__insert_map(thread, map);
1644 total_mmap++;
1645
1646 return 0;
1647}
1648
1649static int
1650process_comm_event(event_t *event, unsigned long offset, unsigned long head)
1651{
1652 struct thread *thread = threads__findnew(event->comm.pid);
1653
1654 dprintf("%p [%p]: PERF_EVENT_COMM: %s:%d\n",
1655 (void *)(offset + head),
1656 (void *)(long)(event->header.size),
1657 event->comm.comm, event->comm.pid);
1658
1659 if (thread == NULL ||
1660 thread__set_comm(thread, event->comm.comm)) {
1661 dprintf("problem processing PERF_EVENT_COMM, skipping event.\n");
1662 return -1;
1663 }
1664 total_comm++;
1665
1666 return 0;
1667}
1668
1669static int
Peter Zijlstra27d028d2009-07-23 16:52:41 +02001670process_task_event(event_t *event, unsigned long offset, unsigned long head)
Peter Zijlstra62fc4452009-06-04 16:53:49 +02001671{
1672 struct thread *thread = threads__findnew(event->fork.pid);
1673 struct thread *parent = threads__findnew(event->fork.ppid);
1674
Peter Zijlstra27d028d2009-07-23 16:52:41 +02001675 dprintf("%p [%p]: PERF_EVENT_%s: (%d:%d):(%d:%d)\n",
Peter Zijlstra62fc4452009-06-04 16:53:49 +02001676 (void *)(offset + head),
1677 (void *)(long)(event->header.size),
Peter Zijlstra27d028d2009-07-23 16:52:41 +02001678 event->header.type == PERF_EVENT_FORK ? "FORK" : "EXIT",
1679 event->fork.pid, event->fork.tid,
1680 event->fork.ppid, event->fork.ptid);
1681
1682 /*
1683 * A thread clone will have the same PID for both
1684 * parent and child.
1685 */
1686 if (thread == parent)
1687 return 0;
1688
1689 if (event->header.type == PERF_EVENT_EXIT)
1690 return 0;
Peter Zijlstra62fc4452009-06-04 16:53:49 +02001691
1692 if (!thread || !parent || thread__fork(thread, parent)) {
1693 dprintf("problem processing PERF_EVENT_FORK, skipping event.\n");
1694 return -1;
1695 }
1696 total_fork++;
1697
1698 return 0;
1699}
1700
1701static int
Peter Zijlstra9d91a6f2009-06-18 11:40:28 +02001702process_lost_event(event_t *event, unsigned long offset, unsigned long head)
1703{
1704 dprintf("%p [%p]: PERF_EVENT_LOST: id:%Ld: lost:%Ld\n",
1705 (void *)(offset + head),
1706 (void *)(long)(event->header.size),
1707 event->lost.id,
1708 event->lost.lost);
1709
1710 total_lost += event->lost.lost;
1711
1712 return 0;
1713}
1714
Ingo Molnar8465b052009-06-14 14:44:07 +02001715static void trace_event(event_t *event)
1716{
1717 unsigned char *raw_event = (void *)event;
Ingo Molnar3efa1cc92009-06-14 15:04:15 +02001718 char *color = PERF_COLOR_BLUE;
Ingo Molnar8465b052009-06-14 14:44:07 +02001719 int i, j;
1720
1721 if (!dump_trace)
1722 return;
1723
Ingo Molnar3efa1cc92009-06-14 15:04:15 +02001724 dprintf(".");
1725 cdprintf("\n. ... raw event: size %d bytes\n", event->header.size);
Ingo Molnar8465b052009-06-14 14:44:07 +02001726
1727 for (i = 0; i < event->header.size; i++) {
Ingo Molnar3efa1cc92009-06-14 15:04:15 +02001728 if ((i & 15) == 0) {
1729 dprintf(".");
1730 cdprintf(" %04x: ", i);
1731 }
Ingo Molnar8465b052009-06-14 14:44:07 +02001732
Ingo Molnar3efa1cc92009-06-14 15:04:15 +02001733 cdprintf(" %02x", raw_event[i]);
Ingo Molnar8465b052009-06-14 14:44:07 +02001734
1735 if (((i & 15) == 15) || i == event->header.size-1) {
Ingo Molnar3efa1cc92009-06-14 15:04:15 +02001736 cdprintf(" ");
Ingo Molnar8465b052009-06-14 14:44:07 +02001737 for (j = 0; j < 15-(i & 15); j++)
Ingo Molnar3efa1cc92009-06-14 15:04:15 +02001738 cdprintf(" ");
Ingo Molnar8465b052009-06-14 14:44:07 +02001739 for (j = 0; j < (i & 15); j++) {
Peter Zijlstraa73c7d82009-06-18 09:44:20 +02001740 if (isprint(raw_event[i-15+j]))
Ingo Molnar3efa1cc92009-06-14 15:04:15 +02001741 cdprintf("%c", raw_event[i-15+j]);
Ingo Molnar8465b052009-06-14 14:44:07 +02001742 else
Ingo Molnar3efa1cc92009-06-14 15:04:15 +02001743 cdprintf(".");
Ingo Molnar8465b052009-06-14 14:44:07 +02001744 }
Ingo Molnar3efa1cc92009-06-14 15:04:15 +02001745 cdprintf("\n");
Ingo Molnar8465b052009-06-14 14:44:07 +02001746 }
1747 }
1748 dprintf(".\n");
1749}
1750
Peter Zijlstra8f18aec2009-08-06 19:40:28 +02001751static struct perf_header *header;
1752
1753static struct perf_counter_attr *perf_header__find_attr(u64 id)
1754{
1755 int i;
1756
1757 for (i = 0; i < header->attrs; i++) {
1758 struct perf_header_attr *attr = header->attr[i];
1759 int j;
1760
1761 for (j = 0; j < attr->ids; j++) {
1762 if (attr->id[j] == id)
1763 return &attr->attr;
1764 }
1765 }
1766
1767 return NULL;
1768}
1769
Ingo Molnarb2fef072009-06-05 18:07:51 +02001770static int
Peter Zijlstrae9ea2fd2009-06-24 22:46:04 +02001771process_read_event(event_t *event, unsigned long offset, unsigned long head)
1772{
Peter Zijlstra8f18aec2009-08-06 19:40:28 +02001773 struct perf_counter_attr *attr = perf_header__find_attr(event->read.id);
1774
Brice Goglin8d513272009-08-07 13:55:24 +02001775 if (show_threads) {
1776 char *name = attr ? __event_name(attr->type, attr->config)
1777 : "unknown";
1778 perf_read_values_add_value(&show_threads_values,
1779 event->read.pid, event->read.tid,
1780 event->read.id,
1781 name,
1782 event->read.value);
1783 }
1784
Peter Zijlstra8f18aec2009-08-06 19:40:28 +02001785 dprintf("%p [%p]: PERF_EVENT_READ: %d %d %s %Lu\n",
Peter Zijlstrae9ea2fd2009-06-24 22:46:04 +02001786 (void *)(offset + head),
1787 (void *)(long)(event->header.size),
1788 event->read.pid,
1789 event->read.tid,
Peter Zijlstra8f18aec2009-08-06 19:40:28 +02001790 attr ? __event_name(attr->type, attr->config)
1791 : "FAIL",
Peter Zijlstrae9ea2fd2009-06-24 22:46:04 +02001792 event->read.value);
1793
1794 return 0;
1795}
1796
1797static int
Ingo Molnard80d3382009-06-03 23:14:49 +02001798process_event(event_t *event, unsigned long offset, unsigned long head)
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -03001799{
Ingo Molnar8465b052009-06-14 14:44:07 +02001800 trace_event(event);
1801
Ingo Molnar75051722009-06-03 23:14:49 +02001802 switch (event->header.type) {
Peter Zijlstrae6e18ec2009-06-25 11:27:12 +02001803 case PERF_EVENT_SAMPLE:
1804 return process_sample_event(event, offset, head);
1805
Ingo Molnar75051722009-06-03 23:14:49 +02001806 case PERF_EVENT_MMAP:
1807 return process_mmap_event(event, offset, head);
Ingo Molnar97b07b62009-05-26 18:48:58 +02001808
Ingo Molnar75051722009-06-03 23:14:49 +02001809 case PERF_EVENT_COMM:
1810 return process_comm_event(event, offset, head);
Ingo Molnared966aa2009-06-03 10:39:26 +02001811
Peter Zijlstra62fc4452009-06-04 16:53:49 +02001812 case PERF_EVENT_FORK:
Peter Zijlstra27d028d2009-07-23 16:52:41 +02001813 case PERF_EVENT_EXIT:
1814 return process_task_event(event, offset, head);
Peter Zijlstra62fc4452009-06-04 16:53:49 +02001815
Peter Zijlstra9d91a6f2009-06-18 11:40:28 +02001816 case PERF_EVENT_LOST:
1817 return process_lost_event(event, offset, head);
1818
Peter Zijlstrae9ea2fd2009-06-24 22:46:04 +02001819 case PERF_EVENT_READ:
1820 return process_read_event(event, offset, head);
1821
Ingo Molnard11444d2009-06-03 23:29:14 +02001822 /*
1823 * We dont process them right now but they are fine:
1824 */
Peter Zijlstra62fc4452009-06-04 16:53:49 +02001825
Ingo Molnard11444d2009-06-03 23:29:14 +02001826 case PERF_EVENT_THROTTLE:
1827 case PERF_EVENT_UNTHROTTLE:
1828 return 0;
1829
Ingo Molnard80d3382009-06-03 23:14:49 +02001830 default:
1831 return -1;
1832 }
1833
1834 return 0;
1835}
1836
Peter Zijlstrae6e18ec2009-06-25 11:27:12 +02001837static u64 perf_header__sample_type(void)
Peter Zijlstra7c6a1c62009-06-25 17:05:54 +02001838{
Peter Zijlstrae6e18ec2009-06-25 11:27:12 +02001839 u64 sample_type = 0;
Peter Zijlstra7c6a1c62009-06-25 17:05:54 +02001840 int i;
1841
1842 for (i = 0; i < header->attrs; i++) {
1843 struct perf_header_attr *attr = header->attr[i];
1844
Peter Zijlstrae6e18ec2009-06-25 11:27:12 +02001845 if (!sample_type)
1846 sample_type = attr->attr.sample_type;
1847 else if (sample_type != attr->attr.sample_type)
1848 die("non matching sample_type");
Peter Zijlstra7c6a1c62009-06-25 17:05:54 +02001849 }
1850
Peter Zijlstrae6e18ec2009-06-25 11:27:12 +02001851 return sample_type;
Peter Zijlstra7c6a1c62009-06-25 17:05:54 +02001852}
Peter Zijlstraf5970552009-06-18 23:22:55 +02001853
Ingo Molnard80d3382009-06-03 23:14:49 +02001854static int __cmd_report(void)
1855{
Ingo Molnar75051722009-06-03 23:14:49 +02001856 int ret, rc = EXIT_FAILURE;
Ingo Molnard80d3382009-06-03 23:14:49 +02001857 unsigned long offset = 0;
Peter Zijlstra7c6a1c62009-06-25 17:05:54 +02001858 unsigned long head, shift;
Ingo Molnard80d3382009-06-03 23:14:49 +02001859 struct stat stat;
Ingo Molnard80d3382009-06-03 23:14:49 +02001860 event_t *event;
Ingo Molnard80d3382009-06-03 23:14:49 +02001861 uint32_t size;
Ingo Molnar75051722009-06-03 23:14:49 +02001862 char *buf;
Ingo Molnard80d3382009-06-03 23:14:49 +02001863
1864 register_idle_thread();
1865
Brice Goglin8d513272009-08-07 13:55:24 +02001866 if (show_threads)
1867 perf_read_values_init(&show_threads_values);
1868
Ingo Molnard80d3382009-06-03 23:14:49 +02001869 input = open(input_name, O_RDONLY);
1870 if (input < 0) {
Ingo Molnara14832f2009-06-07 17:58:23 +02001871 fprintf(stderr, " failed to open file: %s", input_name);
1872 if (!strcmp(input_name, "perf.data"))
1873 fprintf(stderr, " (try 'perf record' first)");
1874 fprintf(stderr, "\n");
Ingo Molnard80d3382009-06-03 23:14:49 +02001875 exit(-1);
1876 }
1877
1878 ret = fstat(input, &stat);
1879 if (ret < 0) {
1880 perror("failed to stat file");
1881 exit(-1);
1882 }
1883
1884 if (!stat.st_size) {
1885 fprintf(stderr, "zero-sized file, nothing to do!\n");
1886 exit(0);
1887 }
1888
Peter Zijlstra7c6a1c62009-06-25 17:05:54 +02001889 header = perf_header__read(input);
1890 head = header->data_offset;
Peter Zijlstraf5970552009-06-18 23:22:55 +02001891
Peter Zijlstrae6e18ec2009-06-25 11:27:12 +02001892 sample_type = perf_header__sample_type();
1893
Frederic Weisbecker91b4eae2009-07-05 07:39:17 +02001894 if (!(sample_type & PERF_SAMPLE_CALLCHAIN)) {
1895 if (sort__has_parent) {
1896 fprintf(stderr, "selected --sort parent, but no"
1897 " callchain data. Did you call"
1898 " perf record without -g?\n");
1899 exit(-1);
1900 }
1901 if (callchain) {
1902 fprintf(stderr, "selected -c but no callchain data."
1903 " Did you call perf record without"
1904 " -g?\n");
1905 exit(-1);
1906 }
Frederic Weisbeckerb1a88342009-08-08 02:16:24 +02001907 } else if (callchain_param.mode != CHAIN_NONE && !callchain) {
1908 callchain = 1;
1909 if (register_callchain_param(&callchain_param) < 0) {
1910 fprintf(stderr, "Can't register callchain"
1911 " params\n");
1912 exit(-1);
1913 }
Peter Zijlstraf5970552009-06-18 23:22:55 +02001914 }
1915
Ingo Molnard80d3382009-06-03 23:14:49 +02001916 if (load_kernel() < 0) {
1917 perror("failed to load kernel symbols");
1918 return EXIT_FAILURE;
1919 }
1920
1921 if (!full_paths) {
1922 if (getcwd(__cwd, sizeof(__cwd)) == NULL) {
1923 perror("failed to get the current directory");
1924 return EXIT_FAILURE;
1925 }
1926 cwdlen = strlen(cwd);
1927 } else {
1928 cwd = NULL;
1929 cwdlen = 0;
1930 }
Peter Zijlstra7c6a1c62009-06-25 17:05:54 +02001931
1932 shift = page_size * (head / page_size);
1933 offset += shift;
1934 head -= shift;
1935
Ingo Molnard80d3382009-06-03 23:14:49 +02001936remap:
1937 buf = (char *)mmap(NULL, page_size * mmap_window, PROT_READ,
1938 MAP_SHARED, input, offset);
1939 if (buf == MAP_FAILED) {
1940 perror("failed to mmap file");
1941 exit(-1);
1942 }
1943
1944more:
1945 event = (event_t *)(buf + head);
1946
1947 size = event->header.size;
1948 if (!size)
1949 size = 8;
1950
1951 if (head + event->header.size >= page_size * mmap_window) {
Ingo Molnard80d3382009-06-03 23:14:49 +02001952 int ret;
1953
Peter Zijlstra7c6a1c62009-06-25 17:05:54 +02001954 shift = page_size * (head / page_size);
1955
Ingo Molnard80d3382009-06-03 23:14:49 +02001956 ret = munmap(buf, page_size * mmap_window);
1957 assert(ret == 0);
1958
1959 offset += shift;
1960 head -= shift;
1961 goto remap;
1962 }
1963
1964 size = event->header.size;
1965
Ingo Molnar8465b052009-06-14 14:44:07 +02001966 dprintf("\n%p [%p]: event: %d\n",
Ingo Molnarb2fef072009-06-05 18:07:51 +02001967 (void *)(offset + head),
1968 (void *)(long)event->header.size,
1969 event->header.type);
1970
Ingo Molnard80d3382009-06-03 23:14:49 +02001971 if (!size || process_event(event, offset, head) < 0) {
1972
Ingo Molnar35029732009-06-03 09:38:58 +02001973 dprintf("%p [%p]: skipping unknown header type: %d\n",
1974 (void *)(offset + head),
1975 (void *)(long)(event->header.size),
1976 event->header.type);
Peter Zijlstrab7a16ea2009-05-27 13:35:35 +02001977
Ingo Molnar3e706112009-05-26 18:53:17 +02001978 total_unknown++;
Peter Zijlstra6142f9e2009-05-26 20:51:47 +02001979
1980 /*
1981 * assume we lost track of the stream, check alignment, and
1982 * increment a single u64 in the hope to catch on again 'soon'.
1983 */
1984
1985 if (unlikely(head & 7))
1986 head &= ~7ULL;
1987
1988 size = 8;
Ingo Molnar97b07b62009-05-26 18:48:58 +02001989 }
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -03001990
Peter Zijlstra6142f9e2009-05-26 20:51:47 +02001991 head += size;
Ingo Molnarf49515b2009-05-26 19:03:36 +02001992
Peter Zijlstra7c6a1c62009-06-25 17:05:54 +02001993 if (offset + head >= header->data_offset + header->data_size)
Peter Zijlstraf5970552009-06-18 23:22:55 +02001994 goto done;
1995
Ingo Molnarf37a2912009-07-01 12:37:06 +02001996 if (offset + head < (unsigned long)stat.st_size)
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -03001997 goto more;
1998
Peter Zijlstraf5970552009-06-18 23:22:55 +02001999done:
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -03002000 rc = EXIT_SUCCESS;
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -03002001 close(input);
Ingo Molnar97b07b62009-05-26 18:48:58 +02002002
Ingo Molnar35029732009-06-03 09:38:58 +02002003 dprintf(" IP events: %10ld\n", total);
2004 dprintf(" mmap events: %10ld\n", total_mmap);
2005 dprintf(" comm events: %10ld\n", total_comm);
Peter Zijlstra62fc4452009-06-04 16:53:49 +02002006 dprintf(" fork events: %10ld\n", total_fork);
Peter Zijlstra9d91a6f2009-06-18 11:40:28 +02002007 dprintf(" lost events: %10ld\n", total_lost);
Ingo Molnar35029732009-06-03 09:38:58 +02002008 dprintf(" unknown events: %10ld\n", total_unknown);
Ingo Molnar97b07b62009-05-26 18:48:58 +02002009
Ingo Molnar35029732009-06-03 09:38:58 +02002010 if (dump_trace)
Ingo Molnar97b07b62009-05-26 18:48:58 +02002011 return 0;
Ingo Molnar97b07b62009-05-26 18:48:58 +02002012
Arnaldo Carvalho de Melo9ac99542009-06-04 13:54:00 -03002013 if (verbose >= 3)
2014 threads__fprintf(stdout);
2015
Peter Zijlstrae7fb08b2009-05-27 20:20:24 +02002016 if (verbose >= 2)
Ingo Molnar16f762a2009-05-27 09:10:38 +02002017 dsos__fprintf(stdout);
Ingo Molnar16f762a2009-05-27 09:10:38 +02002018
Peter Zijlstra82292892009-06-03 12:37:36 +02002019 collapse__resort();
Frederic Weisbeckerc20ab372009-07-02 20:14:33 +02002020 output__resort(total);
Peter Zijlstrae7fb08b2009-05-27 20:20:24 +02002021 output__fprintf(stdout, total);
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -03002022
Brice Goglin8d513272009-08-07 13:55:24 +02002023 if (show_threads)
2024 perf_read_values_destroy(&show_threads_values);
2025
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -03002026 return rc;
2027}
2028
Frederic Weisbecker4eb3e472009-07-02 17:58:21 +02002029static int
2030parse_callchain_opt(const struct option *opt __used, const char *arg,
2031 int unset __used)
2032{
Frederic Weisbeckerc20ab372009-07-02 20:14:33 +02002033 char *tok;
2034 char *endptr;
2035
Frederic Weisbecker4eb3e472009-07-02 17:58:21 +02002036 callchain = 1;
2037
2038 if (!arg)
2039 return 0;
2040
Frederic Weisbeckerc20ab372009-07-02 20:14:33 +02002041 tok = strtok((char *)arg, ",");
2042 if (!tok)
2043 return -1;
2044
2045 /* get the output mode */
2046 if (!strncmp(tok, "graph", strlen(arg)))
Frederic Weisbecker805d1272009-07-05 07:39:21 +02002047 callchain_param.mode = CHAIN_GRAPH_ABS;
Frederic Weisbecker4eb3e472009-07-02 17:58:21 +02002048
Frederic Weisbeckerc20ab372009-07-02 20:14:33 +02002049 else if (!strncmp(tok, "flat", strlen(arg)))
Frederic Weisbecker805d1272009-07-05 07:39:21 +02002050 callchain_param.mode = CHAIN_FLAT;
2051
2052 else if (!strncmp(tok, "fractal", strlen(arg)))
2053 callchain_param.mode = CHAIN_GRAPH_REL;
2054
Frederic Weisbeckerb1a88342009-08-08 02:16:24 +02002055 else if (!strncmp(tok, "none", strlen(arg))) {
2056 callchain_param.mode = CHAIN_NONE;
2057 callchain = 0;
2058
2059 return 0;
2060 }
2061
Frederic Weisbecker4eb3e472009-07-02 17:58:21 +02002062 else
2063 return -1;
2064
Frederic Weisbeckerc20ab372009-07-02 20:14:33 +02002065 /* get the min percentage */
2066 tok = strtok(NULL, ",");
2067 if (!tok)
Frederic Weisbecker805d1272009-07-05 07:39:21 +02002068 goto setup;
Frederic Weisbeckerc20ab372009-07-02 20:14:33 +02002069
Frederic Weisbecker805d1272009-07-05 07:39:21 +02002070 callchain_param.min_percent = strtod(tok, &endptr);
Frederic Weisbeckerc20ab372009-07-02 20:14:33 +02002071 if (tok == endptr)
2072 return -1;
2073
Frederic Weisbecker805d1272009-07-05 07:39:21 +02002074setup:
2075 if (register_callchain_param(&callchain_param) < 0) {
2076 fprintf(stderr, "Can't register callchain params\n");
2077 return -1;
2078 }
Frederic Weisbecker4eb3e472009-07-02 17:58:21 +02002079 return 0;
2080}
2081
Ingo Molnar53cb8bc2009-05-26 09:17:18 +02002082static const char * const report_usage[] = {
2083 "perf report [<options>] <command>",
2084 NULL
2085};
2086
2087static const struct option options[] = {
2088 OPT_STRING('i', "input", &input_name, "file",
2089 "input file name"),
Arnaldo Carvalho de Melo815e7772009-05-26 19:46:14 -03002090 OPT_BOOLEAN('v', "verbose", &verbose,
2091 "be more verbose (show symbol address, etc)"),
Ingo Molnar97b07b62009-05-26 18:48:58 +02002092 OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace,
2093 "dump raw trace in ASCII"),
Peter Zijlstra450aaa22009-05-27 20:20:23 +02002094 OPT_STRING('k', "vmlinux", &vmlinux, "file", "vmlinux pathname"),
Mike Galbraith42976482009-07-02 08:09:46 +02002095 OPT_BOOLEAN('m', "modules", &modules,
2096 "load module symbols - WARNING: use only with -k and LIVE kernel"),
Arnaldo Carvalho de Meloe3d7e182009-07-11 12:18:37 -03002097 OPT_BOOLEAN('n', "show-nr-samples", &show_nr_samples,
2098 "Show a column with the number of samples"),
Brice Goglin8d513272009-08-07 13:55:24 +02002099 OPT_BOOLEAN('T', "threads", &show_threads,
2100 "Show per-thread event counters"),
Brice Goglin9f866692009-08-10 15:26:32 +02002101 OPT_STRING(0, "pretty", &pretty_printing_style, "key",
2102 "pretty printing style key: normal raw"),
Ingo Molnar63299f02009-05-28 10:52:00 +02002103 OPT_STRING('s', "sort", &sort_order, "key[,key2...]",
Ingo Molnarb25bcf22009-06-18 07:01:03 +02002104 "sort by key(s): pid, comm, dso, symbol, parent"),
Arnaldo Carvalho de Melob78c07d2009-05-29 13:48:59 -03002105 OPT_BOOLEAN('P', "full-paths", &full_paths,
2106 "Don't shorten the pathnames taking into account the cwd"),
Ingo Molnarb25bcf22009-06-18 07:01:03 +02002107 OPT_STRING('p', "parent", &parent_pattern, "regex",
2108 "regex filter to identify parent, see: '--sort parent'"),
Ingo Molnarb8e6d822009-06-18 14:32:19 +02002109 OPT_BOOLEAN('x', "exclude-other", &exclude_other,
2110 "Only display entries with parent-match"),
Anton Blanchard1483b19f2009-07-16 15:44:29 +02002111 OPT_CALLBACK_DEFAULT('g', "call-graph", NULL, "output_type,min_percent",
Frederic Weisbeckerc20ab372009-07-02 20:14:33 +02002112 "Display callchains using output_type and min percent threshold. "
Anton Blanchard1483b19f2009-07-16 15:44:29 +02002113 "Default: fractal,0.5", &parse_callchain_opt, callchain_default_opt),
Arnaldo Carvalho de Melo25903402009-06-30 19:01:20 -03002114 OPT_STRING('d', "dsos", &dso_list_str, "dso[,dso...]",
2115 "only consider symbols in these dsos"),
Arnaldo Carvalho de Melocc8b88b2009-06-30 19:01:21 -03002116 OPT_STRING('C', "comms", &comm_list_str, "comm[,comm...]",
2117 "only consider symbols in these comms"),
Arnaldo Carvalho de Melo7bec7a92009-06-30 19:01:22 -03002118 OPT_STRING('S', "symbols", &sym_list_str, "symbol[,symbol...]",
2119 "only consider these symbols"),
Arnaldo Carvalho de Melo52d422d2009-07-10 22:47:28 -03002120 OPT_STRING('w', "column-widths", &col_width_list_str,
2121 "width[,width...]",
2122 "don't try to adjust column width, use these fixed values"),
2123 OPT_STRING('t', "field-separator", &field_sep, "separator",
2124 "separator for columns, no spaces will be added between "
2125 "columns '.' is reserved."),
Ingo Molnar53cb8bc2009-05-26 09:17:18 +02002126 OPT_END()
2127};
2128
Ingo Molnar5352f352009-06-03 10:07:39 +02002129static void setup_sorting(void)
2130{
2131 char *tmp, *tok, *str = strdup(sort_order);
2132
2133 for (tok = strtok_r(str, ", ", &tmp);
2134 tok; tok = strtok_r(NULL, ", ", &tmp)) {
2135 if (sort_dimension__add(tok) < 0) {
2136 error("Unknown --sort key: `%s'", tok);
2137 usage_with_options(report_usage, options);
2138 }
2139 }
2140
2141 free(str);
2142}
2143
Arnaldo Carvalho de Melocc8b88b2009-06-30 19:01:21 -03002144static void setup_list(struct strlist **list, const char *list_str,
Arnaldo Carvalho de Melo021191b2009-07-11 12:18:35 -03002145 struct sort_entry *se, const char *list_name,
2146 FILE *fp)
Arnaldo Carvalho de Melocc8b88b2009-06-30 19:01:21 -03002147{
2148 if (list_str) {
2149 *list = strlist__new(true, list_str);
2150 if (!*list) {
2151 fprintf(stderr, "problems parsing %s list\n",
2152 list_name);
2153 exit(129);
2154 }
Arnaldo Carvalho de Melo021191b2009-07-11 12:18:35 -03002155 if (strlist__nr_entries(*list) == 1) {
2156 fprintf(fp, "# %s: %s\n", list_name,
2157 strlist__entry(*list, 0)->s);
2158 se->elide = true;
2159 }
Arnaldo Carvalho de Melocc8b88b2009-06-30 19:01:21 -03002160 }
2161}
2162
Ingo Molnarf37a2912009-07-01 12:37:06 +02002163int cmd_report(int argc, const char **argv, const char *prefix __used)
Ingo Molnar53cb8bc2009-05-26 09:17:18 +02002164{
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -03002165 symbol__init();
Ingo Molnar53cb8bc2009-05-26 09:17:18 +02002166
2167 page_size = getpagesize();
2168
Ingo Molnaredc52de2009-06-04 16:24:37 +02002169 argc = parse_options(argc, argv, options, report_usage, 0);
Ingo Molnar53cb8bc2009-05-26 09:17:18 +02002170
Peter Zijlstra1aa16732009-05-27 20:20:25 +02002171 setup_sorting();
2172
Arnaldo Carvalho de Melo021191b2009-07-11 12:18:35 -03002173 if (parent_pattern != default_parent_pattern) {
Ingo Molnarb8e6d822009-06-18 14:32:19 +02002174 sort_dimension__add("parent");
Arnaldo Carvalho de Melo021191b2009-07-11 12:18:35 -03002175 sort_parent.elide = 1;
2176 } else
Ingo Molnarb8e6d822009-06-18 14:32:19 +02002177 exclude_other = 0;
2178
Ingo Molnaredc52de2009-06-04 16:24:37 +02002179 /*
2180 * Any (unrecognized) arguments left?
2181 */
2182 if (argc)
2183 usage_with_options(report_usage, options);
2184
Ingo Molnara930d2c2009-05-27 09:50:13 +02002185 setup_pager();
2186
Arnaldo Carvalho de Melo021191b2009-07-11 12:18:35 -03002187 setup_list(&dso_list, dso_list_str, &sort_dso, "dso", stdout);
2188 setup_list(&comm_list, comm_list_str, &sort_comm, "comm", stdout);
2189 setup_list(&sym_list, sym_list_str, &sort_sym, "symbol", stdout);
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -03002190
Arnaldo Carvalho de Melo52d422d2009-07-10 22:47:28 -03002191 if (field_sep && *field_sep == '.') {
2192 fputs("'.' is the only non valid --field-separator argument\n",
2193 stderr);
2194 exit(129);
2195 }
2196
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -03002197 return __cmd_report();
2198}