blob: 298f26b8ac7899b79f3de1df5b93bd17d91e35f9 [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
Frederic Weisbecker6baa0a5a2009-08-14 12:21:53 +020028#include "util/thread.h"
29
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -030030#define SHOW_KERNEL 1
31#define SHOW_USER 2
32#define SHOW_HV 4
33
Ingo Molnar23ac9cb2009-05-27 09:33:18 +020034static char const *input_name = "perf.data";
Ingo Molnarbd741372009-06-04 14:13:04 +020035
Pekka Enberg114cfab2009-08-05 13:25:21 +030036static char default_sort_order[] = "comm,dso,symbol";
Ingo Molnarbd741372009-06-04 14:13:04 +020037static char *sort_order = default_sort_order;
Arnaldo Carvalho de Melo52d422d2009-07-10 22:47:28 -030038static char *dso_list_str, *comm_list_str, *sym_list_str,
39 *col_width_list_str;
Arnaldo Carvalho de Melo7bec7a92009-06-30 19:01:22 -030040static struct strlist *dso_list, *comm_list, *sym_list;
Arnaldo Carvalho de Melo52d422d2009-07-10 22:47:28 -030041static char *field_sep;
Ingo Molnarbd741372009-06-04 14:13:04 +020042
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -030043static int input;
44static int show_mask = SHOW_KERNEL | SHOW_USER | SHOW_HV;
45
Ingo Molnar97b07b62009-05-26 18:48:58 +020046static int dump_trace = 0;
Ingo Molnar35029732009-06-03 09:38:58 +020047#define dprintf(x...) do { if (dump_trace) printf(x); } while (0)
Ingo Molnar3efa1cc92009-06-14 15:04:15 +020048#define cdprintf(x...) do { if (dump_trace) color_fprintf(stdout, color, x); } while (0)
Ingo Molnar35029732009-06-03 09:38:58 +020049
Arnaldo Carvalho de Melob78c07d2009-05-29 13:48:59 -030050static int full_paths;
Arnaldo Carvalho de Meloe3d7e182009-07-11 12:18:37 -030051static int show_nr_samples;
Ingo Molnar97b07b62009-05-26 18:48:58 +020052
Brice Goglin8d513272009-08-07 13:55:24 +020053static int show_threads;
54static struct perf_read_values show_threads_values;
55
Brice Goglin9f866692009-08-10 15:26:32 +020056static char default_pretty_printing_style[] = "normal";
57static char *pretty_printing_style = default_pretty_printing_style;
58
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -030059static unsigned long page_size;
60static unsigned long mmap_window = 32;
61
Ingo Molnarb8e6d822009-06-18 14:32:19 +020062static char default_parent_pattern[] = "^sys_|^do_page_fault";
63static char *parent_pattern = default_parent_pattern;
Ingo Molnarb25bcf22009-06-18 07:01:03 +020064static regex_t parent_regex;
Peter Zijlstra6e7d6fd2009-06-17 15:51:44 +020065
Ingo Molnarb8e6d822009-06-18 14:32:19 +020066static int exclude_other = 1;
Frederic Weisbeckerbe903882009-07-05 07:39:18 +020067
Frederic Weisbecker805d1272009-07-05 07:39:21 +020068static char callchain_default_opt[] = "fractal,0.5";
69
Frederic Weisbeckerf55c5552009-06-26 16:28:01 +020070static int callchain;
Frederic Weisbecker805d1272009-07-05 07:39:21 +020071
Frederic Weisbecker66e274f2009-08-12 11:07:25 +020072static char __cwd[PATH_MAX];
73static char *cwd = __cwd;
74static int cwdlen;
75
Frederic Weisbecker6baa0a5a2009-08-14 12:21:53 +020076static struct rb_root threads;
77static struct thread *last_match;
78
Frederic Weisbecker805d1272009-07-05 07:39:21 +020079static
80struct callchain_param callchain_param = {
Frederic Weisbeckerb1a88342009-08-08 02:16:24 +020081 .mode = CHAIN_GRAPH_REL,
Frederic Weisbecker805d1272009-07-05 07:39:21 +020082 .min_percent = 0.5
83};
Ingo Molnarb8e6d822009-06-18 14:32:19 +020084
Peter Zijlstrae6e18ec2009-06-25 11:27:12 +020085static u64 sample_type;
86
Arnaldo Carvalho de Melo52d422d2009-07-10 22:47:28 -030087static int repsep_fprintf(FILE *fp, const char *fmt, ...)
88{
89 int n;
90 va_list ap;
91
92 va_start(ap, fmt);
93 if (!field_sep)
94 n = vfprintf(fp, fmt, ap);
95 else {
96 char *bf = NULL;
97 n = vasprintf(&bf, fmt, ap);
98 if (n > 0) {
99 char *sep = bf;
100 while (1) {
101 sep = strchr(sep, *field_sep);
102 if (sep == NULL)
103 break;
104 *sep = '.';
105 }
106 }
107 fputs(bf, fp);
108 free(bf);
109 }
110 va_end(ap);
111 return n;
112}
113
Arnaldo Carvalho de Melo52d422d2009-07-10 22:47:28 -0300114static unsigned int dsos__col_width,
115 comms__col_width,
116 threads__col_width;
117
Peter Zijlstrae7fb08b2009-05-27 20:20:24 +0200118/*
119 * histogram, sorted on item, collects counts
120 */
121
122static struct rb_root hist;
123
124struct hist_entry {
Frederic Weisbeckerf55c5552009-06-26 16:28:01 +0200125 struct rb_node rb_node;
Peter Zijlstrae7fb08b2009-05-27 20:20:24 +0200126
Frederic Weisbeckerf55c5552009-06-26 16:28:01 +0200127 struct thread *thread;
128 struct map *map;
129 struct dso *dso;
130 struct symbol *sym;
131 struct symbol *parent;
132 u64 ip;
133 char level;
134 struct callchain_node callchain;
135 struct rb_root sorted_chain;
Peter Zijlstrae7fb08b2009-05-27 20:20:24 +0200136
Frederic Weisbeckerf55c5552009-06-26 16:28:01 +0200137 u64 count;
Peter Zijlstrae7fb08b2009-05-27 20:20:24 +0200138};
139
Peter Zijlstra1aa16732009-05-27 20:20:25 +0200140/*
141 * configurable sorting bits
142 */
143
144struct sort_entry {
145 struct list_head list;
146
Peter Zijlstraca8cdee2009-05-28 11:08:33 +0200147 char *header;
148
Peter Zijlstra1aa16732009-05-27 20:20:25 +0200149 int64_t (*cmp)(struct hist_entry *, struct hist_entry *);
Peter Zijlstra82292892009-06-03 12:37:36 +0200150 int64_t (*collapse)(struct hist_entry *, struct hist_entry *);
Arnaldo Carvalho de Melo52d422d2009-07-10 22:47:28 -0300151 size_t (*print)(FILE *fp, struct hist_entry *, unsigned int width);
152 unsigned int *width;
Arnaldo Carvalho de Melo021191b2009-07-11 12:18:35 -0300153 bool elide;
Peter Zijlstra1aa16732009-05-27 20:20:25 +0200154};
155
Peter Zijlstra6e7d6fd2009-06-17 15:51:44 +0200156static int64_t cmp_null(void *l, void *r)
157{
158 if (!l && !r)
159 return 0;
160 else if (!l)
161 return -1;
162 else
163 return 1;
164}
165
Peter Zijlstra82292892009-06-03 12:37:36 +0200166/* --sort pid */
167
Peter Zijlstrae7fb08b2009-05-27 20:20:24 +0200168static int64_t
Peter Zijlstra1aa16732009-05-27 20:20:25 +0200169sort__thread_cmp(struct hist_entry *left, struct hist_entry *right)
170{
171 return right->thread->pid - left->thread->pid;
172}
173
174static size_t
Arnaldo Carvalho de Melo52d422d2009-07-10 22:47:28 -0300175sort__thread_print(FILE *fp, struct hist_entry *self, unsigned int width)
Peter Zijlstra1aa16732009-05-27 20:20:25 +0200176{
Arnaldo Carvalho de Melo52d422d2009-07-10 22:47:28 -0300177 return repsep_fprintf(fp, "%*s:%5d", width - 6,
178 self->thread->comm ?: "", self->thread->pid);
Peter Zijlstra1aa16732009-05-27 20:20:25 +0200179}
180
181static struct sort_entry sort_thread = {
Arnaldo Carvalho de Melo52d422d2009-07-10 22:47:28 -0300182 .header = "Command: Pid",
Peter Zijlstra1aa16732009-05-27 20:20:25 +0200183 .cmp = sort__thread_cmp,
184 .print = sort__thread_print,
Arnaldo Carvalho de Melo52d422d2009-07-10 22:47:28 -0300185 .width = &threads__col_width,
Peter Zijlstra1aa16732009-05-27 20:20:25 +0200186};
187
Peter Zijlstra82292892009-06-03 12:37:36 +0200188/* --sort comm */
189
Peter Zijlstra1aa16732009-05-27 20:20:25 +0200190static int64_t
Peter Zijlstra992444b2009-05-27 20:20:27 +0200191sort__comm_cmp(struct hist_entry *left, struct hist_entry *right)
192{
Peter Zijlstra82292892009-06-03 12:37:36 +0200193 return right->thread->pid - left->thread->pid;
194}
195
196static int64_t
197sort__comm_collapse(struct hist_entry *left, struct hist_entry *right)
198{
Peter Zijlstra992444b2009-05-27 20:20:27 +0200199 char *comm_l = left->thread->comm;
200 char *comm_r = right->thread->comm;
201
Peter Zijlstra6e7d6fd2009-06-17 15:51:44 +0200202 if (!comm_l || !comm_r)
203 return cmp_null(comm_l, comm_r);
Peter Zijlstra992444b2009-05-27 20:20:27 +0200204
205 return strcmp(comm_l, comm_r);
206}
207
208static size_t
Arnaldo Carvalho de Melo52d422d2009-07-10 22:47:28 -0300209sort__comm_print(FILE *fp, struct hist_entry *self, unsigned int width)
Peter Zijlstra992444b2009-05-27 20:20:27 +0200210{
Arnaldo Carvalho de Melo52d422d2009-07-10 22:47:28 -0300211 return repsep_fprintf(fp, "%*s", width, self->thread->comm);
Peter Zijlstra992444b2009-05-27 20:20:27 +0200212}
213
214static struct sort_entry sort_comm = {
Arnaldo Carvalho de Melo52d422d2009-07-10 22:47:28 -0300215 .header = "Command",
Peter Zijlstra82292892009-06-03 12:37:36 +0200216 .cmp = sort__comm_cmp,
217 .collapse = sort__comm_collapse,
218 .print = sort__comm_print,
Arnaldo Carvalho de Melo52d422d2009-07-10 22:47:28 -0300219 .width = &comms__col_width,
Peter Zijlstra992444b2009-05-27 20:20:27 +0200220};
221
Peter Zijlstra82292892009-06-03 12:37:36 +0200222/* --sort dso */
223
Peter Zijlstra992444b2009-05-27 20:20:27 +0200224static int64_t
Peter Zijlstra55e5ec42009-05-27 20:20:28 +0200225sort__dso_cmp(struct hist_entry *left, struct hist_entry *right)
226{
227 struct dso *dso_l = left->dso;
228 struct dso *dso_r = right->dso;
229
Peter Zijlstra6e7d6fd2009-06-17 15:51:44 +0200230 if (!dso_l || !dso_r)
231 return cmp_null(dso_l, dso_r);
Peter Zijlstra55e5ec42009-05-27 20:20:28 +0200232
233 return strcmp(dso_l->name, dso_r->name);
234}
235
236static size_t
Arnaldo Carvalho de Melo52d422d2009-07-10 22:47:28 -0300237sort__dso_print(FILE *fp, struct hist_entry *self, unsigned int width)
Peter Zijlstra55e5ec42009-05-27 20:20:28 +0200238{
Ingo Molnar0a520c62009-06-02 23:24:45 +0200239 if (self->dso)
Arnaldo Carvalho de Melo52d422d2009-07-10 22:47:28 -0300240 return repsep_fprintf(fp, "%-*s", width, self->dso->name);
Ingo Molnar0a520c62009-06-02 23:24:45 +0200241
Arnaldo Carvalho de Melo52d422d2009-07-10 22:47:28 -0300242 return repsep_fprintf(fp, "%*llx", width, (u64)self->ip);
Peter Zijlstra55e5ec42009-05-27 20:20:28 +0200243}
244
245static struct sort_entry sort_dso = {
Arnaldo Carvalho de Melo52d422d2009-07-10 22:47:28 -0300246 .header = "Shared Object",
Peter Zijlstra55e5ec42009-05-27 20:20:28 +0200247 .cmp = sort__dso_cmp,
248 .print = sort__dso_print,
Arnaldo Carvalho de Melo52d422d2009-07-10 22:47:28 -0300249 .width = &dsos__col_width,
Peter Zijlstra55e5ec42009-05-27 20:20:28 +0200250};
251
Peter Zijlstra82292892009-06-03 12:37:36 +0200252/* --sort symbol */
253
Peter Zijlstra55e5ec42009-05-27 20:20:28 +0200254static int64_t
Peter Zijlstra1aa16732009-05-27 20:20:25 +0200255sort__sym_cmp(struct hist_entry *left, struct hist_entry *right)
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300256{
Paul Mackerras9cffa8d2009-06-19 22:21:42 +1000257 u64 ip_l, ip_r;
Peter Zijlstrae7fb08b2009-05-27 20:20:24 +0200258
259 if (left->sym == right->sym)
260 return 0;
261
262 ip_l = left->sym ? left->sym->start : left->ip;
263 ip_r = right->sym ? right->sym->start : right->ip;
264
265 return (int64_t)(ip_r - ip_l);
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300266}
267
Peter Zijlstra1aa16732009-05-27 20:20:25 +0200268static size_t
Arnaldo Carvalho de Melo52d422d2009-07-10 22:47:28 -0300269sort__sym_print(FILE *fp, struct hist_entry *self, unsigned int width __used)
Peter Zijlstra1aa16732009-05-27 20:20:25 +0200270{
271 size_t ret = 0;
272
Peter Zijlstra1aa16732009-05-27 20:20:25 +0200273 if (verbose)
Arnaldo Carvalho de Melo94cb9e32009-08-06 14:43:17 -0300274 ret += repsep_fprintf(fp, "%#018llx %c ", (u64)self->ip,
275 dso__symtab_origin(self->dso));
Peter Zijlstra1aa16732009-05-27 20:20:25 +0200276
Arnaldo Carvalho de Melo60c1baf2009-07-11 12:18:33 -0300277 ret += repsep_fprintf(fp, "[%c] ", self->level);
Ingo Molnar8edd4282009-06-05 14:13:18 +0200278 if (self->sym) {
Arnaldo Carvalho de Melo60c1baf2009-07-11 12:18:33 -0300279 ret += repsep_fprintf(fp, "%s", self->sym->name);
Mike Galbraith42976482009-07-02 08:09:46 +0200280
281 if (self->sym->module)
Arnaldo Carvalho de Melo52d422d2009-07-10 22:47:28 -0300282 ret += repsep_fprintf(fp, "\t[%s]",
283 self->sym->module->name);
Ingo Molnar8edd4282009-06-05 14:13:18 +0200284 } else {
Arnaldo Carvalho de Melo52d422d2009-07-10 22:47:28 -0300285 ret += repsep_fprintf(fp, "%#016llx", (u64)self->ip);
Ingo Molnar8edd4282009-06-05 14:13:18 +0200286 }
Peter Zijlstra1aa16732009-05-27 20:20:25 +0200287
288 return ret;
289}
290
291static struct sort_entry sort_sym = {
Peter Zijlstra71dd8942009-06-04 15:16:56 +0200292 .header = "Symbol",
Peter Zijlstraca8cdee2009-05-28 11:08:33 +0200293 .cmp = sort__sym_cmp,
294 .print = sort__sym_print,
Peter Zijlstra1aa16732009-05-27 20:20:25 +0200295};
296
Ingo Molnarb25bcf22009-06-18 07:01:03 +0200297/* --sort parent */
Peter Zijlstra6e7d6fd2009-06-17 15:51:44 +0200298
299static int64_t
Ingo Molnarb25bcf22009-06-18 07:01:03 +0200300sort__parent_cmp(struct hist_entry *left, struct hist_entry *right)
Peter Zijlstra6e7d6fd2009-06-17 15:51:44 +0200301{
Ingo Molnarb25bcf22009-06-18 07:01:03 +0200302 struct symbol *sym_l = left->parent;
303 struct symbol *sym_r = right->parent;
Peter Zijlstra6e7d6fd2009-06-17 15:51:44 +0200304
305 if (!sym_l || !sym_r)
306 return cmp_null(sym_l, sym_r);
307
308 return strcmp(sym_l->name, sym_r->name);
309}
310
311static size_t
Arnaldo Carvalho de Melo52d422d2009-07-10 22:47:28 -0300312sort__parent_print(FILE *fp, struct hist_entry *self, unsigned int width)
Peter Zijlstra6e7d6fd2009-06-17 15:51:44 +0200313{
Arnaldo Carvalho de Melo52d422d2009-07-10 22:47:28 -0300314 return repsep_fprintf(fp, "%-*s", width,
315 self->parent ? self->parent->name : "[other]");
Peter Zijlstra6e7d6fd2009-06-17 15:51:44 +0200316}
317
Arnaldo Carvalho de Melo52d422d2009-07-10 22:47:28 -0300318static unsigned int parent_symbol__col_width;
319
Ingo Molnarb25bcf22009-06-18 07:01:03 +0200320static struct sort_entry sort_parent = {
Arnaldo Carvalho de Melo52d422d2009-07-10 22:47:28 -0300321 .header = "Parent symbol",
Ingo Molnarb25bcf22009-06-18 07:01:03 +0200322 .cmp = sort__parent_cmp,
323 .print = sort__parent_print,
Arnaldo Carvalho de Melo52d422d2009-07-10 22:47:28 -0300324 .width = &parent_symbol__col_width,
Peter Zijlstra6e7d6fd2009-06-17 15:51:44 +0200325};
326
Peter Zijlstra82292892009-06-03 12:37:36 +0200327static int sort__need_collapse = 0;
Ingo Molnarb25bcf22009-06-18 07:01:03 +0200328static int sort__has_parent = 0;
Peter Zijlstra82292892009-06-03 12:37:36 +0200329
Peter Zijlstra37f440c2009-05-27 20:20:26 +0200330struct sort_dimension {
Ingo Molnar8edd4282009-06-05 14:13:18 +0200331 char *name;
332 struct sort_entry *entry;
333 int taken;
Peter Zijlstra37f440c2009-05-27 20:20:26 +0200334};
335
336static struct sort_dimension sort_dimensions[] = {
337 { .name = "pid", .entry = &sort_thread, },
Peter Zijlstra992444b2009-05-27 20:20:27 +0200338 { .name = "comm", .entry = &sort_comm, },
Peter Zijlstra55e5ec42009-05-27 20:20:28 +0200339 { .name = "dso", .entry = &sort_dso, },
Peter Zijlstra37f440c2009-05-27 20:20:26 +0200340 { .name = "symbol", .entry = &sort_sym, },
Ingo Molnarb25bcf22009-06-18 07:01:03 +0200341 { .name = "parent", .entry = &sort_parent, },
Peter Zijlstra37f440c2009-05-27 20:20:26 +0200342};
343
Peter Zijlstra1aa16732009-05-27 20:20:25 +0200344static LIST_HEAD(hist_entry__sort_list);
345
Peter Zijlstra37f440c2009-05-27 20:20:26 +0200346static int sort_dimension__add(char *tok)
347{
Ingo Molnarf37a2912009-07-01 12:37:06 +0200348 unsigned int i;
Peter Zijlstra37f440c2009-05-27 20:20:26 +0200349
350 for (i = 0; i < ARRAY_SIZE(sort_dimensions); i++) {
351 struct sort_dimension *sd = &sort_dimensions[i];
352
353 if (sd->taken)
354 continue;
355
Ingo Molnar5352f352009-06-03 10:07:39 +0200356 if (strncasecmp(tok, sd->name, strlen(tok)))
Peter Zijlstra37f440c2009-05-27 20:20:26 +0200357 continue;
358
Peter Zijlstra82292892009-06-03 12:37:36 +0200359 if (sd->entry->collapse)
360 sort__need_collapse = 1;
361
Ingo Molnarb25bcf22009-06-18 07:01:03 +0200362 if (sd->entry == &sort_parent) {
363 int ret = regcomp(&parent_regex, parent_pattern, REG_EXTENDED);
Peter Zijlstra6e7d6fd2009-06-17 15:51:44 +0200364 if (ret) {
365 char err[BUFSIZ];
366
Ingo Molnarb25bcf22009-06-18 07:01:03 +0200367 regerror(ret, &parent_regex, err, sizeof(err));
368 fprintf(stderr, "Invalid regex: %s\n%s",
369 parent_pattern, err);
Peter Zijlstra6e7d6fd2009-06-17 15:51:44 +0200370 exit(-1);
371 }
Ingo Molnarb25bcf22009-06-18 07:01:03 +0200372 sort__has_parent = 1;
Peter Zijlstra6e7d6fd2009-06-17 15:51:44 +0200373 }
374
Peter Zijlstra37f440c2009-05-27 20:20:26 +0200375 list_add_tail(&sd->entry->list, &hist_entry__sort_list);
376 sd->taken = 1;
Ingo Molnar5352f352009-06-03 10:07:39 +0200377
Peter Zijlstra37f440c2009-05-27 20:20:26 +0200378 return 0;
379 }
380
381 return -ESRCH;
382}
383
Peter Zijlstra1aa16732009-05-27 20:20:25 +0200384static int64_t
385hist_entry__cmp(struct hist_entry *left, struct hist_entry *right)
386{
387 struct sort_entry *se;
388 int64_t cmp = 0;
389
390 list_for_each_entry(se, &hist_entry__sort_list, list) {
391 cmp = se->cmp(left, right);
392 if (cmp)
393 break;
394 }
395
396 return cmp;
397}
398
Peter Zijlstra82292892009-06-03 12:37:36 +0200399static int64_t
400hist_entry__collapse(struct hist_entry *left, struct hist_entry *right)
401{
402 struct sort_entry *se;
403 int64_t cmp = 0;
404
405 list_for_each_entry(se, &hist_entry__sort_list, list) {
406 int64_t (*f)(struct hist_entry *, struct hist_entry *);
407
408 f = se->collapse ?: se->cmp;
409
410 cmp = f(left, right);
411 if (cmp)
412 break;
413 }
414
415 return cmp;
416}
417
Frederic Weisbecker4eb3e472009-07-02 17:58:21 +0200418static size_t ipchain__fprintf_graph_line(FILE *fp, int depth, int depth_mask)
419{
420 int i;
421 size_t ret = 0;
422
423 ret += fprintf(fp, "%s", " ");
424
425 for (i = 0; i < depth; i++)
426 if (depth_mask & (1 << i))
427 ret += fprintf(fp, "| ");
428 else
429 ret += fprintf(fp, " ");
430
431 ret += fprintf(fp, "\n");
432
433 return ret;
434}
Peter Zijlstra1aa16732009-05-27 20:20:25 +0200435static size_t
Frederic Weisbecker4eb3e472009-07-02 17:58:21 +0200436ipchain__fprintf_graph(FILE *fp, struct callchain_list *chain, int depth,
437 int depth_mask, int count, u64 total_samples,
438 int hits)
439{
440 int i;
441 size_t ret = 0;
442
443 ret += fprintf(fp, "%s", " ");
444 for (i = 0; i < depth; i++) {
445 if (depth_mask & (1 << i))
446 ret += fprintf(fp, "|");
447 else
448 ret += fprintf(fp, " ");
449 if (!count && i == depth - 1) {
450 double percent;
451
452 percent = hits * 100.0 / total_samples;
Frederic Weisbecker24b57c62009-07-02 20:14:35 +0200453 ret += percent_color_fprintf(fp, "--%2.2f%%-- ", percent);
Frederic Weisbecker4eb3e472009-07-02 17:58:21 +0200454 } else
455 ret += fprintf(fp, "%s", " ");
456 }
457 if (chain->sym)
458 ret += fprintf(fp, "%s\n", chain->sym->name);
459 else
460 ret += fprintf(fp, "%p\n", (void *)(long)chain->ip);
461
462 return ret;
463}
464
Frederic Weisbecker25446032009-08-08 02:16:25 +0200465static struct symbol *rem_sq_bracket;
466static struct callchain_list rem_hits;
467
468static void init_rem_hits(void)
469{
470 rem_sq_bracket = malloc(sizeof(*rem_sq_bracket) + 6);
471 if (!rem_sq_bracket) {
472 fprintf(stderr, "Not enough memory to display remaining hits\n");
473 return;
474 }
475
476 strcpy(rem_sq_bracket->name, "[...]");
477 rem_hits.sym = rem_sq_bracket;
478}
479
Frederic Weisbecker4eb3e472009-07-02 17:58:21 +0200480static size_t
481callchain__fprintf_graph(FILE *fp, struct callchain_node *self,
482 u64 total_samples, int depth, int depth_mask)
483{
484 struct rb_node *node, *next;
485 struct callchain_node *child;
486 struct callchain_list *chain;
487 int new_depth_mask = depth_mask;
Frederic Weisbecker805d1272009-07-05 07:39:21 +0200488 u64 new_total;
Frederic Weisbecker25446032009-08-08 02:16:25 +0200489 u64 remaining;
Frederic Weisbecker4eb3e472009-07-02 17:58:21 +0200490 size_t ret = 0;
491 int i;
492
Frederic Weisbecker805d1272009-07-05 07:39:21 +0200493 if (callchain_param.mode == CHAIN_GRAPH_REL)
Frederic Weisbecker1953287b2009-08-07 07:11:05 +0200494 new_total = self->children_hit;
Frederic Weisbecker805d1272009-07-05 07:39:21 +0200495 else
496 new_total = total_samples;
497
Frederic Weisbecker25446032009-08-08 02:16:25 +0200498 remaining = new_total;
499
Frederic Weisbecker4eb3e472009-07-02 17:58:21 +0200500 node = rb_first(&self->rb_root);
501 while (node) {
Frederic Weisbecker25446032009-08-08 02:16:25 +0200502 u64 cumul;
503
Frederic Weisbecker4eb3e472009-07-02 17:58:21 +0200504 child = rb_entry(node, struct callchain_node, rb_node);
Frederic Weisbecker25446032009-08-08 02:16:25 +0200505 cumul = cumul_hits(child);
506 remaining -= cumul;
Frederic Weisbecker4eb3e472009-07-02 17:58:21 +0200507
508 /*
509 * The depth mask manages the output of pipes that show
510 * the depth. We don't want to keep the pipes of the current
Frederic Weisbecker25446032009-08-08 02:16:25 +0200511 * level for the last child of this depth.
512 * Except if we have remaining filtered hits. They will
513 * supersede the last child
Frederic Weisbecker4eb3e472009-07-02 17:58:21 +0200514 */
515 next = rb_next(node);
Frederic Weisbecker25446032009-08-08 02:16:25 +0200516 if (!next && (callchain_param.mode != CHAIN_GRAPH_REL || !remaining))
Frederic Weisbecker4eb3e472009-07-02 17:58:21 +0200517 new_depth_mask &= ~(1 << (depth - 1));
518
519 /*
520 * But we keep the older depth mask for the line seperator
521 * to keep the level link until we reach the last child
522 */
523 ret += ipchain__fprintf_graph_line(fp, depth, depth_mask);
524 i = 0;
525 list_for_each_entry(chain, &child->val, list) {
526 if (chain->ip >= PERF_CONTEXT_MAX)
527 continue;
528 ret += ipchain__fprintf_graph(fp, chain, depth,
529 new_depth_mask, i++,
Frederic Weisbecker805d1272009-07-05 07:39:21 +0200530 new_total,
Frederic Weisbecker25446032009-08-08 02:16:25 +0200531 cumul);
Frederic Weisbecker4eb3e472009-07-02 17:58:21 +0200532 }
Frederic Weisbecker805d1272009-07-05 07:39:21 +0200533 ret += callchain__fprintf_graph(fp, child, new_total,
Frederic Weisbecker4eb3e472009-07-02 17:58:21 +0200534 depth + 1,
535 new_depth_mask | (1 << depth));
536 node = next;
537 }
538
Frederic Weisbecker25446032009-08-08 02:16:25 +0200539 if (callchain_param.mode == CHAIN_GRAPH_REL &&
540 remaining && remaining != new_total) {
541
542 if (!rem_sq_bracket)
543 return ret;
544
545 new_depth_mask &= ~(1 << (depth - 1));
546
547 ret += ipchain__fprintf_graph(fp, &rem_hits, depth,
548 new_depth_mask, 0, new_total,
549 remaining);
550 }
551
Frederic Weisbecker4eb3e472009-07-02 17:58:21 +0200552 return ret;
553}
554
555static size_t
556callchain__fprintf_flat(FILE *fp, struct callchain_node *self,
557 u64 total_samples)
Frederic Weisbeckerf55c5552009-06-26 16:28:01 +0200558{
559 struct callchain_list *chain;
560 size_t ret = 0;
561
562 if (!self)
563 return 0;
564
Frederic Weisbecker4eb3e472009-07-02 17:58:21 +0200565 ret += callchain__fprintf_flat(fp, self->parent, total_samples);
Frederic Weisbeckerf55c5552009-06-26 16:28:01 +0200566
567
Frederic Weisbecker44249612009-07-01 05:35:14 +0200568 list_for_each_entry(chain, &self->val, list) {
569 if (chain->ip >= PERF_CONTEXT_MAX)
570 continue;
571 if (chain->sym)
572 ret += fprintf(fp, " %s\n", chain->sym->name);
573 else
574 ret += fprintf(fp, " %p\n",
Ingo Molnarf37a2912009-07-01 12:37:06 +0200575 (void *)(long)chain->ip);
Frederic Weisbecker44249612009-07-01 05:35:14 +0200576 }
Frederic Weisbeckerf55c5552009-06-26 16:28:01 +0200577
578 return ret;
579}
580
581static size_t
582hist_entry_callchain__fprintf(FILE *fp, struct hist_entry *self,
583 u64 total_samples)
584{
585 struct rb_node *rb_node;
586 struct callchain_node *chain;
587 size_t ret = 0;
588
589 rb_node = rb_first(&self->sorted_chain);
590 while (rb_node) {
591 double percent;
592
593 chain = rb_entry(rb_node, struct callchain_node, rb_node);
594 percent = chain->hit * 100.0 / total_samples;
Frederic Weisbecker805d1272009-07-05 07:39:21 +0200595 switch (callchain_param.mode) {
596 case CHAIN_FLAT:
Frederic Weisbecker24b57c62009-07-02 20:14:35 +0200597 ret += percent_color_fprintf(fp, " %6.2f%%\n",
598 percent);
Frederic Weisbecker4eb3e472009-07-02 17:58:21 +0200599 ret += callchain__fprintf_flat(fp, chain, total_samples);
Frederic Weisbecker805d1272009-07-05 07:39:21 +0200600 break;
601 case CHAIN_GRAPH_ABS: /* Falldown */
602 case CHAIN_GRAPH_REL:
Frederic Weisbecker4eb3e472009-07-02 17:58:21 +0200603 ret += callchain__fprintf_graph(fp, chain,
604 total_samples, 1, 1);
Frederic Weisbecker805d1272009-07-05 07:39:21 +0200605 default:
606 break;
Frederic Weisbecker4eb3e472009-07-02 17:58:21 +0200607 }
Frederic Weisbeckerf55c5552009-06-26 16:28:01 +0200608 ret += fprintf(fp, "\n");
609 rb_node = rb_next(rb_node);
610 }
611
612 return ret;
613}
614
615
616static size_t
Paul Mackerras9cffa8d2009-06-19 22:21:42 +1000617hist_entry__fprintf(FILE *fp, struct hist_entry *self, u64 total_samples)
Peter Zijlstra1aa16732009-05-27 20:20:25 +0200618{
619 struct sort_entry *se;
620 size_t ret;
621
Ingo Molnarb8e6d822009-06-18 14:32:19 +0200622 if (exclude_other && !self->parent)
623 return 0;
624
Frederic Weisbecker1e11fd82009-07-02 20:14:34 +0200625 if (total_samples)
Arnaldo Carvalho de Melo52d422d2009-07-10 22:47:28 -0300626 ret = percent_color_fprintf(fp,
627 field_sep ? "%.2f" : " %6.2f%%",
628 (self->count * 100.0) / total_samples);
Frederic Weisbecker1e11fd82009-07-02 20:14:34 +0200629 else
Arnaldo Carvalho de Melo52d422d2009-07-10 22:47:28 -0300630 ret = fprintf(fp, field_sep ? "%lld" : "%12lld ", self->count);
Peter Zijlstra1aa16732009-05-27 20:20:25 +0200631
Arnaldo Carvalho de Meloe3d7e182009-07-11 12:18:37 -0300632 if (show_nr_samples) {
633 if (field_sep)
634 fprintf(fp, "%c%lld", *field_sep, self->count);
635 else
636 fprintf(fp, "%11lld", self->count);
637 }
Peter Zijlstra1aa16732009-05-27 20:20:25 +0200638
Peter Zijlstra71dd8942009-06-04 15:16:56 +0200639 list_for_each_entry(se, &hist_entry__sort_list, list) {
Arnaldo Carvalho de Melo021191b2009-07-11 12:18:35 -0300640 if (se->elide)
Ingo Molnarb8e6d822009-06-18 14:32:19 +0200641 continue;
642
Arnaldo Carvalho de Melo52d422d2009-07-10 22:47:28 -0300643 fprintf(fp, "%s", field_sep ?: " ");
644 ret += se->print(fp, self, se->width ? *se->width : 0);
Peter Zijlstra71dd8942009-06-04 15:16:56 +0200645 }
Peter Zijlstra1aa16732009-05-27 20:20:25 +0200646
647 ret += fprintf(fp, "\n");
648
Frederic Weisbeckerf55c5552009-06-26 16:28:01 +0200649 if (callchain)
650 hist_entry_callchain__fprintf(fp, self, total_samples);
651
Peter Zijlstra1aa16732009-05-27 20:20:25 +0200652 return ret;
653}
654
655/*
Peter Zijlstra6e7d6fd2009-06-17 15:51:44 +0200656 *
657 */
658
Arnaldo Carvalho de Melo52d422d2009-07-10 22:47:28 -0300659static void dso__calc_col_width(struct dso *self)
660{
661 if (!col_width_list_str && !field_sep &&
662 (!dso_list || strlist__has_entry(dso_list, self->name))) {
663 unsigned int slen = strlen(self->name);
664 if (slen > dsos__col_width)
665 dsos__col_width = slen;
666 }
667
668 self->slen_calculated = 1;
669}
670
Peter Zijlstra6e7d6fd2009-06-17 15:51:44 +0200671static struct symbol *
672resolve_symbol(struct thread *thread, struct map **mapp,
Paul Mackerras9cffa8d2009-06-19 22:21:42 +1000673 struct dso **dsop, u64 *ipp)
Peter Zijlstra6e7d6fd2009-06-17 15:51:44 +0200674{
675 struct dso *dso = dsop ? *dsop : NULL;
676 struct map *map = mapp ? *mapp : NULL;
Peter Zijlstra520f2c342009-06-22 16:52:51 +0200677 u64 ip = *ipp;
Peter Zijlstra6e7d6fd2009-06-17 15:51:44 +0200678
679 if (!thread)
680 return NULL;
681
682 if (dso)
683 goto got_dso;
684
685 if (map)
686 goto got_map;
687
688 map = thread__find_map(thread, ip);
689 if (map != NULL) {
Arnaldo Carvalho de Melo52d422d2009-07-10 22:47:28 -0300690 /*
691 * We have to do this here as we may have a dso
692 * with no symbol hit that has a name longer than
693 * the ones with symbols sampled.
694 */
Arnaldo Carvalho de Melo021191b2009-07-11 12:18:35 -0300695 if (!sort_dso.elide && !map->dso->slen_calculated)
Arnaldo Carvalho de Melo52d422d2009-07-10 22:47:28 -0300696 dso__calc_col_width(map->dso);
697
Peter Zijlstra6e7d6fd2009-06-17 15:51:44 +0200698 if (mapp)
699 *mapp = map;
700got_map:
701 ip = map->map_ip(map, ip);
Peter Zijlstra6e7d6fd2009-06-17 15:51:44 +0200702
703 dso = map->dso;
704 } else {
705 /*
706 * If this is outside of all known maps,
707 * and is a negative address, try to look it
708 * up in the kernel dso, as it might be a
709 * vsyscall (which executes in user-mode):
710 */
711 if ((long long)ip < 0)
712 dso = kernel_dso;
713 }
714 dprintf(" ...... dso: %s\n", dso ? dso->name : "<not found>");
Peter Zijlstra520f2c342009-06-22 16:52:51 +0200715 dprintf(" ...... map: %Lx -> %Lx\n", *ipp, ip);
716 *ipp = ip;
Peter Zijlstra6e7d6fd2009-06-17 15:51:44 +0200717
718 if (dsop)
719 *dsop = dso;
720
721 if (!dso)
722 return NULL;
723got_dso:
724 return dso->find_symbol(dso, ip);
725}
726
Peter Zijlstra2a0a50f2009-06-18 22:20:45 +0200727static int call__match(struct symbol *sym)
Peter Zijlstra6e7d6fd2009-06-17 15:51:44 +0200728{
Ingo Molnarb25bcf22009-06-18 07:01:03 +0200729 if (sym->name && !regexec(&parent_regex, sym->name, 0, NULL, 0))
Peter Zijlstra2a0a50f2009-06-18 22:20:45 +0200730 return 1;
Peter Zijlstra6e7d6fd2009-06-17 15:51:44 +0200731
Peter Zijlstra2a0a50f2009-06-18 22:20:45 +0200732 return 0;
Peter Zijlstra6e7d6fd2009-06-17 15:51:44 +0200733}
734
Frederic Weisbecker44249612009-07-01 05:35:14 +0200735static struct symbol **
Ingo Molnarf37a2912009-07-01 12:37:06 +0200736resolve_callchain(struct thread *thread, struct map *map __used,
Frederic Weisbecker44249612009-07-01 05:35:14 +0200737 struct ip_callchain *chain, struct hist_entry *entry)
738{
Frederic Weisbecker44249612009-07-01 05:35:14 +0200739 u64 context = PERF_CONTEXT_MAX;
Ingo Molnar029e5b12009-07-03 13:17:28 +0200740 struct symbol **syms = NULL;
Ingo Molnarf37a2912009-07-01 12:37:06 +0200741 unsigned int i;
Frederic Weisbecker44249612009-07-01 05:35:14 +0200742
743 if (callchain) {
744 syms = calloc(chain->nr, sizeof(*syms));
745 if (!syms) {
746 fprintf(stderr, "Can't allocate memory for symbols\n");
747 exit(-1);
748 }
749 }
750
751 for (i = 0; i < chain->nr; i++) {
752 u64 ip = chain->ips[i];
753 struct dso *dso = NULL;
754 struct symbol *sym;
755
756 if (ip >= PERF_CONTEXT_MAX) {
757 context = ip;
758 continue;
759 }
760
761 switch (context) {
Ingo Molnar88a69df2009-07-01 11:17:20 +0200762 case PERF_CONTEXT_HV:
763 dso = hypervisor_dso;
764 break;
Frederic Weisbecker44249612009-07-01 05:35:14 +0200765 case PERF_CONTEXT_KERNEL:
766 dso = kernel_dso;
767 break;
768 default:
769 break;
770 }
771
772 sym = resolve_symbol(thread, NULL, &dso, &ip);
773
774 if (sym) {
775 if (sort__has_parent && call__match(sym) &&
776 !entry->parent)
777 entry->parent = sym;
778 if (!callchain)
779 break;
780 syms[i] = sym;
781 }
782 }
783
784 return syms;
785}
786
Peter Zijlstra6e7d6fd2009-06-17 15:51:44 +0200787/*
Peter Zijlstra1aa16732009-05-27 20:20:25 +0200788 * collect histogram counts
789 */
790
Peter Zijlstrae7fb08b2009-05-27 20:20:24 +0200791static int
792hist_entry__add(struct thread *thread, struct map *map, struct dso *dso,
Paul Mackerras9cffa8d2009-06-19 22:21:42 +1000793 struct symbol *sym, u64 ip, struct ip_callchain *chain,
794 char level, u64 count)
Arnaldo Carvalho de Melo3a4b8cc2009-05-26 16:19:04 -0300795{
Peter Zijlstrae7fb08b2009-05-27 20:20:24 +0200796 struct rb_node **p = &hist.rb_node;
Arnaldo Carvalho de Melo3a4b8cc2009-05-26 16:19:04 -0300797 struct rb_node *parent = NULL;
Peter Zijlstrae7fb08b2009-05-27 20:20:24 +0200798 struct hist_entry *he;
Frederic Weisbecker44249612009-07-01 05:35:14 +0200799 struct symbol **syms = NULL;
Peter Zijlstrae7fb08b2009-05-27 20:20:24 +0200800 struct hist_entry entry = {
801 .thread = thread,
802 .map = map,
803 .dso = dso,
804 .sym = sym,
805 .ip = ip,
806 .level = level,
Peter Zijlstraea1900e2009-06-10 21:45:22 +0200807 .count = count,
Ingo Molnarb8e6d822009-06-18 14:32:19 +0200808 .parent = NULL,
Frederic Weisbeckerf55c5552009-06-26 16:28:01 +0200809 .sorted_chain = RB_ROOT
Peter Zijlstrae7fb08b2009-05-27 20:20:24 +0200810 };
811 int cmp;
Arnaldo Carvalho de Melo3a4b8cc2009-05-26 16:19:04 -0300812
Frederic Weisbecker44249612009-07-01 05:35:14 +0200813 if ((sort__has_parent || callchain) && chain)
814 syms = resolve_callchain(thread, map, chain, &entry);
Peter Zijlstra6e7d6fd2009-06-17 15:51:44 +0200815
Arnaldo Carvalho de Melo3a4b8cc2009-05-26 16:19:04 -0300816 while (*p != NULL) {
817 parent = *p;
Peter Zijlstrae7fb08b2009-05-27 20:20:24 +0200818 he = rb_entry(parent, struct hist_entry, rb_node);
Arnaldo Carvalho de Melo3a4b8cc2009-05-26 16:19:04 -0300819
Peter Zijlstrae7fb08b2009-05-27 20:20:24 +0200820 cmp = hist_entry__cmp(&entry, he);
821
822 if (!cmp) {
Peter Zijlstraea1900e2009-06-10 21:45:22 +0200823 he->count += count;
Frederic Weisbecker44249612009-07-01 05:35:14 +0200824 if (callchain) {
825 append_chain(&he->callchain, chain, syms);
826 free(syms);
827 }
Peter Zijlstrae7fb08b2009-05-27 20:20:24 +0200828 return 0;
829 }
830
831 if (cmp < 0)
Arnaldo Carvalho de Melo3a4b8cc2009-05-26 16:19:04 -0300832 p = &(*p)->rb_left;
833 else
834 p = &(*p)->rb_right;
835 }
836
Peter Zijlstrae7fb08b2009-05-27 20:20:24 +0200837 he = malloc(sizeof(*he));
838 if (!he)
839 return -ENOMEM;
840 *he = entry;
Frederic Weisbeckerf55c5552009-06-26 16:28:01 +0200841 if (callchain) {
842 callchain_init(&he->callchain);
Frederic Weisbecker44249612009-07-01 05:35:14 +0200843 append_chain(&he->callchain, chain, syms);
844 free(syms);
Frederic Weisbeckerf55c5552009-06-26 16:28:01 +0200845 }
Peter Zijlstrae7fb08b2009-05-27 20:20:24 +0200846 rb_link_node(&he->rb_node, parent, p);
847 rb_insert_color(&he->rb_node, &hist);
848
849 return 0;
Arnaldo Carvalho de Melo3a4b8cc2009-05-26 16:19:04 -0300850}
851
Peter Zijlstra82292892009-06-03 12:37:36 +0200852static void hist_entry__free(struct hist_entry *he)
853{
854 free(he);
855}
856
857/*
858 * collapse the histogram
859 */
860
861static struct rb_root collapse_hists;
862
863static void collapse__insert_entry(struct hist_entry *he)
864{
865 struct rb_node **p = &collapse_hists.rb_node;
866 struct rb_node *parent = NULL;
867 struct hist_entry *iter;
868 int64_t cmp;
869
870 while (*p != NULL) {
871 parent = *p;
872 iter = rb_entry(parent, struct hist_entry, rb_node);
873
874 cmp = hist_entry__collapse(iter, he);
875
876 if (!cmp) {
877 iter->count += he->count;
878 hist_entry__free(he);
879 return;
880 }
881
882 if (cmp < 0)
883 p = &(*p)->rb_left;
884 else
885 p = &(*p)->rb_right;
886 }
887
888 rb_link_node(&he->rb_node, parent, p);
889 rb_insert_color(&he->rb_node, &collapse_hists);
890}
891
892static void collapse__resort(void)
893{
894 struct rb_node *next;
895 struct hist_entry *n;
896
897 if (!sort__need_collapse)
898 return;
899
900 next = rb_first(&hist);
901 while (next) {
902 n = rb_entry(next, struct hist_entry, rb_node);
903 next = rb_next(&n->rb_node);
904
905 rb_erase(&n->rb_node, &hist);
906 collapse__insert_entry(n);
907 }
908}
909
Peter Zijlstrae7fb08b2009-05-27 20:20:24 +0200910/*
911 * reverse the map, sort on count.
912 */
913
914static struct rb_root output_hists;
915
Frederic Weisbeckerc20ab372009-07-02 20:14:33 +0200916static void output__insert_entry(struct hist_entry *he, u64 min_callchain_hits)
Peter Zijlstrae7fb08b2009-05-27 20:20:24 +0200917{
918 struct rb_node **p = &output_hists.rb_node;
919 struct rb_node *parent = NULL;
920 struct hist_entry *iter;
921
Frederic Weisbecker805d1272009-07-05 07:39:21 +0200922 if (callchain)
923 callchain_param.sort(&he->sorted_chain, &he->callchain,
924 min_callchain_hits, &callchain_param);
Frederic Weisbeckerf55c5552009-06-26 16:28:01 +0200925
Peter Zijlstrae7fb08b2009-05-27 20:20:24 +0200926 while (*p != NULL) {
927 parent = *p;
928 iter = rb_entry(parent, struct hist_entry, rb_node);
929
930 if (he->count > iter->count)
931 p = &(*p)->rb_left;
932 else
933 p = &(*p)->rb_right;
934 }
935
936 rb_link_node(&he->rb_node, parent, p);
937 rb_insert_color(&he->rb_node, &output_hists);
938}
939
Frederic Weisbeckerc20ab372009-07-02 20:14:33 +0200940static void output__resort(u64 total_samples)
Peter Zijlstrae7fb08b2009-05-27 20:20:24 +0200941{
Peter Zijlstra82292892009-06-03 12:37:36 +0200942 struct rb_node *next;
Peter Zijlstrae7fb08b2009-05-27 20:20:24 +0200943 struct hist_entry *n;
Arnaldo Carvalho de Meloa4c43bea2009-06-03 23:02:33 -0300944 struct rb_root *tree = &hist;
Frederic Weisbeckerc20ab372009-07-02 20:14:33 +0200945 u64 min_callchain_hits;
946
Frederic Weisbecker805d1272009-07-05 07:39:21 +0200947 min_callchain_hits = total_samples * (callchain_param.min_percent / 100);
Peter Zijlstrae7fb08b2009-05-27 20:20:24 +0200948
Peter Zijlstra82292892009-06-03 12:37:36 +0200949 if (sort__need_collapse)
Arnaldo Carvalho de Meloa4c43bea2009-06-03 23:02:33 -0300950 tree = &collapse_hists;
951
952 next = rb_first(tree);
Peter Zijlstra82292892009-06-03 12:37:36 +0200953
Peter Zijlstrae7fb08b2009-05-27 20:20:24 +0200954 while (next) {
955 n = rb_entry(next, struct hist_entry, rb_node);
956 next = rb_next(&n->rb_node);
957
Arnaldo Carvalho de Meloa4c43bea2009-06-03 23:02:33 -0300958 rb_erase(&n->rb_node, tree);
Frederic Weisbeckerc20ab372009-07-02 20:14:33 +0200959 output__insert_entry(n, min_callchain_hits);
Arnaldo Carvalho de Melo3a4b8cc2009-05-26 16:19:04 -0300960 }
961}
962
Paul Mackerras9cffa8d2009-06-19 22:21:42 +1000963static size_t output__fprintf(FILE *fp, u64 total_samples)
Arnaldo Carvalho de Melo3a4b8cc2009-05-26 16:19:04 -0300964{
Peter Zijlstrae7fb08b2009-05-27 20:20:24 +0200965 struct hist_entry *pos;
Ingo Molnar2d655372009-05-27 21:36:22 +0200966 struct sort_entry *se;
Arnaldo Carvalho de Melo3a4b8cc2009-05-26 16:19:04 -0300967 struct rb_node *nd;
968 size_t ret = 0;
Arnaldo Carvalho de Melo52d422d2009-07-10 22:47:28 -0300969 unsigned int width;
970 char *col_width = col_width_list_str;
Brice Goglin9f866692009-08-10 15:26:32 +0200971 int raw_printing_style;
972
973 raw_printing_style = !strcmp(pretty_printing_style, "raw");
Arnaldo Carvalho de Melo3a4b8cc2009-05-26 16:19:04 -0300974
Frederic Weisbecker25446032009-08-08 02:16:25 +0200975 init_rem_hits();
976
Arnaldo Carvalho de Melo021191b2009-07-11 12:18:35 -0300977 fprintf(fp, "# Samples: %Ld\n", (u64)total_samples);
Ingo Molnar05ca0612009-06-04 14:21:16 +0200978 fprintf(fp, "#\n");
Peter Zijlstraca8cdee2009-05-28 11:08:33 +0200979
980 fprintf(fp, "# Overhead");
Arnaldo Carvalho de Meloe3d7e182009-07-11 12:18:37 -0300981 if (show_nr_samples) {
982 if (field_sep)
983 fprintf(fp, "%cSamples", *field_sep);
984 else
985 fputs(" Samples ", fp);
986 }
Ingo Molnarb8e6d822009-06-18 14:32:19 +0200987 list_for_each_entry(se, &hist_entry__sort_list, list) {
Arnaldo Carvalho de Melo021191b2009-07-11 12:18:35 -0300988 if (se->elide)
Ingo Molnarb8e6d822009-06-18 14:32:19 +0200989 continue;
Arnaldo Carvalho de Melo52d422d2009-07-10 22:47:28 -0300990 if (field_sep) {
991 fprintf(fp, "%c%s", *field_sep, se->header);
992 continue;
993 }
994 width = strlen(se->header);
995 if (se->width) {
996 if (col_width_list_str) {
997 if (col_width) {
998 *se->width = atoi(col_width);
999 col_width = strchr(col_width, ',');
1000 if (col_width)
1001 ++col_width;
1002 }
1003 }
1004 width = *se->width = max(*se->width, width);
1005 }
1006 fprintf(fp, " %*s", width, se->header);
Ingo Molnarb8e6d822009-06-18 14:32:19 +02001007 }
Peter Zijlstraca8cdee2009-05-28 11:08:33 +02001008 fprintf(fp, "\n");
1009
Arnaldo Carvalho de Melo52d422d2009-07-10 22:47:28 -03001010 if (field_sep)
1011 goto print_entries;
1012
Peter Zijlstraca8cdee2009-05-28 11:08:33 +02001013 fprintf(fp, "# ........");
Arnaldo Carvalho de Meloe3d7e182009-07-11 12:18:37 -03001014 if (show_nr_samples)
1015 fprintf(fp, " ..........");
Ingo Molnar2d655372009-05-27 21:36:22 +02001016 list_for_each_entry(se, &hist_entry__sort_list, list) {
Ingo Molnarf37a2912009-07-01 12:37:06 +02001017 unsigned int i;
Peter Zijlstraca8cdee2009-05-28 11:08:33 +02001018
Arnaldo Carvalho de Melo021191b2009-07-11 12:18:35 -03001019 if (se->elide)
Ingo Molnarb8e6d822009-06-18 14:32:19 +02001020 continue;
1021
Ingo Molnar4593bba2009-06-02 15:34:25 +02001022 fprintf(fp, " ");
Arnaldo Carvalho de Melo52d422d2009-07-10 22:47:28 -03001023 if (se->width)
1024 width = *se->width;
1025 else
1026 width = strlen(se->header);
1027 for (i = 0; i < width; i++)
Peter Zijlstraca8cdee2009-05-28 11:08:33 +02001028 fprintf(fp, ".");
Ingo Molnar2d655372009-05-27 21:36:22 +02001029 }
Peter Zijlstraca8cdee2009-05-28 11:08:33 +02001030 fprintf(fp, "\n");
1031
1032 fprintf(fp, "#\n");
Ingo Molnar2d655372009-05-27 21:36:22 +02001033
Arnaldo Carvalho de Melo52d422d2009-07-10 22:47:28 -03001034print_entries:
Peter Zijlstrae7fb08b2009-05-27 20:20:24 +02001035 for (nd = rb_first(&output_hists); nd; nd = rb_next(nd)) {
1036 pos = rb_entry(nd, struct hist_entry, rb_node);
1037 ret += hist_entry__fprintf(fp, pos, total_samples);
Arnaldo Carvalho de Melo3a4b8cc2009-05-26 16:19:04 -03001038 }
1039
Ingo Molnarb8e6d822009-06-18 14:32:19 +02001040 if (sort_order == default_sort_order &&
1041 parent_pattern == default_parent_pattern) {
Ingo Molnarbd741372009-06-04 14:13:04 +02001042 fprintf(fp, "#\n");
Pekka Enberg114cfab2009-08-05 13:25:21 +03001043 fprintf(fp, "# (For a higher level overview, try: perf report --sort comm,dso)\n");
Ingo Molnarbd741372009-06-04 14:13:04 +02001044 fprintf(fp, "#\n");
1045 }
Peter Zijlstra71dd8942009-06-04 15:16:56 +02001046 fprintf(fp, "\n");
Ingo Molnarbd741372009-06-04 14:13:04 +02001047
Frederic Weisbecker25446032009-08-08 02:16:25 +02001048 free(rem_sq_bracket);
1049
Brice Goglin8d513272009-08-07 13:55:24 +02001050 if (show_threads)
Brice Goglin9f866692009-08-10 15:26:32 +02001051 perf_read_values_display(fp, &show_threads_values,
1052 raw_printing_style);
Brice Goglin8d513272009-08-07 13:55:24 +02001053
Arnaldo Carvalho de Melo3a4b8cc2009-05-26 16:19:04 -03001054 return ret;
1055}
1056
Peter Zijlstra436224a2009-06-02 21:02:36 +02001057static void register_idle_thread(void)
1058{
Frederic Weisbecker6baa0a5a2009-08-14 12:21:53 +02001059 struct thread *thread = threads__findnew(0, &threads, &last_match);
Peter Zijlstra436224a2009-06-02 21:02:36 +02001060
1061 if (thread == NULL ||
1062 thread__set_comm(thread, "[idle]")) {
1063 fprintf(stderr, "problem inserting idle task.\n");
1064 exit(-1);
1065 }
1066}
1067
Peter Zijlstra62fc4452009-06-04 16:53:49 +02001068static unsigned long total = 0,
1069 total_mmap = 0,
1070 total_comm = 0,
1071 total_fork = 0,
Peter Zijlstra9d91a6f2009-06-18 11:40:28 +02001072 total_unknown = 0,
1073 total_lost = 0;
Peter Zijlstrae7fb08b2009-05-27 20:20:24 +02001074
Peter Zijlstra2a0a50f2009-06-18 22:20:45 +02001075static int validate_chain(struct ip_callchain *chain, event_t *event)
Ingo Molnar75220602009-06-18 08:00:17 +02001076{
1077 unsigned int chain_size;
1078
Ingo Molnar75220602009-06-18 08:00:17 +02001079 chain_size = event->header.size;
1080 chain_size -= (unsigned long)&event->ip.__more_data - (unsigned long)event;
1081
Paul Mackerras9cffa8d2009-06-19 22:21:42 +10001082 if (chain->nr*sizeof(u64) > chain_size)
Ingo Molnar75220602009-06-18 08:00:17 +02001083 return -1;
1084
1085 return 0;
1086}
1087
Ingo Molnard80d3382009-06-03 23:14:49 +02001088static int
Peter Zijlstrae6e18ec2009-06-25 11:27:12 +02001089process_sample_event(event_t *event, unsigned long offset, unsigned long head)
Ingo Molnar75051722009-06-03 23:14:49 +02001090{
1091 char level;
1092 int show = 0;
1093 struct dso *dso = NULL;
Frederic Weisbecker6baa0a5a2009-08-14 12:21:53 +02001094 struct thread *thread;
Paul Mackerras9cffa8d2009-06-19 22:21:42 +10001095 u64 ip = event->ip.ip;
1096 u64 period = 1;
Ingo Molnar75051722009-06-03 23:14:49 +02001097 struct map *map = NULL;
Ingo Molnar3efa1cc92009-06-14 15:04:15 +02001098 void *more_data = event->ip.__more_data;
Peter Zijlstra2a0a50f2009-06-18 22:20:45 +02001099 struct ip_callchain *chain = NULL;
Anton Blanchardd8db1b52009-07-01 09:00:48 +10001100 int cpumode;
Ingo Molnar75051722009-06-03 23:14:49 +02001101
Frederic Weisbecker6baa0a5a2009-08-14 12:21:53 +02001102 thread = threads__findnew(event->ip.pid, &threads, &last_match);
1103
Peter Zijlstrae6e18ec2009-06-25 11:27:12 +02001104 if (sample_type & PERF_SAMPLE_PERIOD) {
Paul Mackerras9cffa8d2009-06-19 22:21:42 +10001105 period = *(u64 *)more_data;
1106 more_data += sizeof(u64);
Ingo Molnar3efa1cc92009-06-14 15:04:15 +02001107 }
Peter Zijlstraea1900e2009-06-10 21:45:22 +02001108
Arnaldo Carvalho de Melo94a24752009-08-11 16:21:38 -03001109 dprintf("%p [%p]: PERF_EVENT_SAMPLE (IP, %d): %d/%d: %p period: %Ld\n",
Ingo Molnar75051722009-06-03 23:14:49 +02001110 (void *)(offset + head),
1111 (void *)(long)(event->header.size),
1112 event->header.misc,
Arnaldo Carvalho de Melo94a24752009-08-11 16:21:38 -03001113 event->ip.pid, event->ip.tid,
Peter Zijlstra4502d772009-06-10 15:03:06 +02001114 (void *)(long)ip,
Peter Zijlstraea1900e2009-06-10 21:45:22 +02001115 (long long)period);
Ingo Molnar75051722009-06-03 23:14:49 +02001116
Peter Zijlstrae6e18ec2009-06-25 11:27:12 +02001117 if (sample_type & PERF_SAMPLE_CALLCHAIN) {
Ingo Molnarf37a2912009-07-01 12:37:06 +02001118 unsigned int i;
Ingo Molnar3efa1cc92009-06-14 15:04:15 +02001119
1120 chain = (void *)more_data;
1121
Peter Zijlstra2a0a50f2009-06-18 22:20:45 +02001122 dprintf("... chain: nr:%Lu\n", chain->nr);
Ingo Molnar3efa1cc92009-06-14 15:04:15 +02001123
Ingo Molnar75220602009-06-18 08:00:17 +02001124 if (validate_chain(chain, event) < 0) {
1125 eprintf("call-chain problem with event, skipping it.\n");
1126 return 0;
1127 }
1128
1129 if (dump_trace) {
Ingo Molnar3efa1cc92009-06-14 15:04:15 +02001130 for (i = 0; i < chain->nr; i++)
Peter Zijlstra2a0a50f2009-06-18 22:20:45 +02001131 dprintf("..... %2d: %016Lx\n", i, chain->ips[i]);
Ingo Molnar3efa1cc92009-06-14 15:04:15 +02001132 }
1133 }
1134
Ingo Molnar75051722009-06-03 23:14:49 +02001135 dprintf(" ... thread: %s:%d\n", thread->comm, thread->pid);
1136
1137 if (thread == NULL) {
Ingo Molnar75220602009-06-18 08:00:17 +02001138 eprintf("problem processing %d event, skipping it.\n",
Ingo Molnar75051722009-06-03 23:14:49 +02001139 event->header.type);
1140 return -1;
1141 }
1142
Arnaldo Carvalho de Melocc8b88b2009-06-30 19:01:21 -03001143 if (comm_list && !strlist__has_entry(comm_list, thread->comm))
1144 return 0;
1145
Anton Blanchardd8db1b52009-07-01 09:00:48 +10001146 cpumode = event->header.misc & PERF_EVENT_MISC_CPUMODE_MASK;
1147
1148 if (cpumode == PERF_EVENT_MISC_KERNEL) {
Ingo Molnar75051722009-06-03 23:14:49 +02001149 show = SHOW_KERNEL;
1150 level = 'k';
1151
1152 dso = kernel_dso;
1153
1154 dprintf(" ...... dso: %s\n", dso->name);
1155
Anton Blanchardd8db1b52009-07-01 09:00:48 +10001156 } else if (cpumode == PERF_EVENT_MISC_USER) {
Ingo Molnar75051722009-06-03 23:14:49 +02001157
1158 show = SHOW_USER;
1159 level = '.';
1160
Ingo Molnar75051722009-06-03 23:14:49 +02001161 } else {
1162 show = SHOW_HV;
1163 level = 'H';
Anton Blanchardfb9c8182009-07-01 09:00:49 +10001164
1165 dso = hypervisor_dso;
1166
Ingo Molnar75051722009-06-03 23:14:49 +02001167 dprintf(" ...... dso: [hypervisor]\n");
1168 }
1169
1170 if (show & show_mask) {
Peter Zijlstra6e7d6fd2009-06-17 15:51:44 +02001171 struct symbol *sym = resolve_symbol(thread, &map, &dso, &ip);
Peter Zijlstrafc54db52009-06-05 14:04:59 +02001172
Arnaldo Carvalho de Melo8fd101f2009-08-12 18:19:57 -03001173 if (dso_list && (!dso || !dso->name ||
1174 !strlist__has_entry(dso_list, dso->name)))
Arnaldo Carvalho de Melo25903402009-06-30 19:01:20 -03001175 return 0;
1176
Arnaldo Carvalho de Melo8fd101f2009-08-12 18:19:57 -03001177 if (sym_list && (!sym || !strlist__has_entry(sym_list, sym->name)))
Arnaldo Carvalho de Melo7bec7a92009-06-30 19:01:22 -03001178 return 0;
1179
Peter Zijlstra6e7d6fd2009-06-17 15:51:44 +02001180 if (hist_entry__add(thread, map, dso, sym, ip, chain, level, period)) {
Ingo Molnar75220602009-06-18 08:00:17 +02001181 eprintf("problem incrementing symbol count, skipping event\n");
Ingo Molnar75051722009-06-03 23:14:49 +02001182 return -1;
1183 }
1184 }
Peter Zijlstraea1900e2009-06-10 21:45:22 +02001185 total += period;
Ingo Molnar75051722009-06-03 23:14:49 +02001186
1187 return 0;
1188}
1189
1190static int
1191process_mmap_event(event_t *event, unsigned long offset, unsigned long head)
1192{
Frederic Weisbecker6baa0a5a2009-08-14 12:21:53 +02001193 struct thread *thread;
Frederic Weisbecker66e274f2009-08-12 11:07:25 +02001194 struct map *map = map__new(&event->mmap, cwd, cwdlen);
Ingo Molnar75051722009-06-03 23:14:49 +02001195
Frederic Weisbecker6baa0a5a2009-08-14 12:21:53 +02001196 thread = threads__findnew(event->mmap.pid, &threads, &last_match);
1197
Arnaldo Carvalho de Melo94a24752009-08-11 16:21:38 -03001198 dprintf("%p [%p]: PERF_EVENT_MMAP %d/%d: [%p(%p) @ %p]: %s\n",
Ingo Molnar75051722009-06-03 23:14:49 +02001199 (void *)(offset + head),
1200 (void *)(long)(event->header.size),
Peter Zijlstra62fc4452009-06-04 16:53:49 +02001201 event->mmap.pid,
Arnaldo Carvalho de Melo94a24752009-08-11 16:21:38 -03001202 event->mmap.tid,
Ingo Molnar75051722009-06-03 23:14:49 +02001203 (void *)(long)event->mmap.start,
1204 (void *)(long)event->mmap.len,
1205 (void *)(long)event->mmap.pgoff,
1206 event->mmap.filename);
1207
1208 if (thread == NULL || map == NULL) {
1209 dprintf("problem processing PERF_EVENT_MMAP, skipping event.\n");
Ingo Molnardf979922009-06-04 13:41:22 +02001210 return 0;
Ingo Molnar75051722009-06-03 23:14:49 +02001211 }
1212
1213 thread__insert_map(thread, map);
1214 total_mmap++;
1215
1216 return 0;
1217}
1218
1219static int
1220process_comm_event(event_t *event, unsigned long offset, unsigned long head)
1221{
Frederic Weisbecker6baa0a5a2009-08-14 12:21:53 +02001222 struct thread *thread;
1223
1224 thread = threads__findnew(event->comm.pid, &threads, &last_match);
Ingo Molnar75051722009-06-03 23:14:49 +02001225
1226 dprintf("%p [%p]: PERF_EVENT_COMM: %s:%d\n",
1227 (void *)(offset + head),
1228 (void *)(long)(event->header.size),
1229 event->comm.comm, event->comm.pid);
1230
1231 if (thread == NULL ||
1232 thread__set_comm(thread, event->comm.comm)) {
1233 dprintf("problem processing PERF_EVENT_COMM, skipping event.\n");
1234 return -1;
1235 }
1236 total_comm++;
1237
1238 return 0;
1239}
1240
1241static int
Peter Zijlstra27d028d2009-07-23 16:52:41 +02001242process_task_event(event_t *event, unsigned long offset, unsigned long head)
Peter Zijlstra62fc4452009-06-04 16:53:49 +02001243{
Frederic Weisbecker6baa0a5a2009-08-14 12:21:53 +02001244 struct thread *thread;
1245 struct thread *parent;
1246
1247 thread = threads__findnew(event->fork.pid, &threads, &last_match);
1248 parent = threads__findnew(event->fork.ppid, &threads, &last_match);
Peter Zijlstra62fc4452009-06-04 16:53:49 +02001249
Peter Zijlstra27d028d2009-07-23 16:52:41 +02001250 dprintf("%p [%p]: PERF_EVENT_%s: (%d:%d):(%d:%d)\n",
Peter Zijlstra62fc4452009-06-04 16:53:49 +02001251 (void *)(offset + head),
1252 (void *)(long)(event->header.size),
Peter Zijlstra27d028d2009-07-23 16:52:41 +02001253 event->header.type == PERF_EVENT_FORK ? "FORK" : "EXIT",
1254 event->fork.pid, event->fork.tid,
1255 event->fork.ppid, event->fork.ptid);
1256
1257 /*
1258 * A thread clone will have the same PID for both
1259 * parent and child.
1260 */
1261 if (thread == parent)
1262 return 0;
1263
1264 if (event->header.type == PERF_EVENT_EXIT)
1265 return 0;
Peter Zijlstra62fc4452009-06-04 16:53:49 +02001266
1267 if (!thread || !parent || thread__fork(thread, parent)) {
1268 dprintf("problem processing PERF_EVENT_FORK, skipping event.\n");
1269 return -1;
1270 }
1271 total_fork++;
1272
1273 return 0;
1274}
1275
1276static int
Peter Zijlstra9d91a6f2009-06-18 11:40:28 +02001277process_lost_event(event_t *event, unsigned long offset, unsigned long head)
1278{
1279 dprintf("%p [%p]: PERF_EVENT_LOST: id:%Ld: lost:%Ld\n",
1280 (void *)(offset + head),
1281 (void *)(long)(event->header.size),
1282 event->lost.id,
1283 event->lost.lost);
1284
1285 total_lost += event->lost.lost;
1286
1287 return 0;
1288}
1289
Ingo Molnar8465b052009-06-14 14:44:07 +02001290static void trace_event(event_t *event)
1291{
1292 unsigned char *raw_event = (void *)event;
Ingo Molnar3efa1cc92009-06-14 15:04:15 +02001293 char *color = PERF_COLOR_BLUE;
Ingo Molnar8465b052009-06-14 14:44:07 +02001294 int i, j;
1295
1296 if (!dump_trace)
1297 return;
1298
Ingo Molnar3efa1cc92009-06-14 15:04:15 +02001299 dprintf(".");
1300 cdprintf("\n. ... raw event: size %d bytes\n", event->header.size);
Ingo Molnar8465b052009-06-14 14:44:07 +02001301
1302 for (i = 0; i < event->header.size; i++) {
Ingo Molnar3efa1cc92009-06-14 15:04:15 +02001303 if ((i & 15) == 0) {
1304 dprintf(".");
1305 cdprintf(" %04x: ", i);
1306 }
Ingo Molnar8465b052009-06-14 14:44:07 +02001307
Ingo Molnar3efa1cc92009-06-14 15:04:15 +02001308 cdprintf(" %02x", raw_event[i]);
Ingo Molnar8465b052009-06-14 14:44:07 +02001309
1310 if (((i & 15) == 15) || i == event->header.size-1) {
Ingo Molnar3efa1cc92009-06-14 15:04:15 +02001311 cdprintf(" ");
Ingo Molnar8465b052009-06-14 14:44:07 +02001312 for (j = 0; j < 15-(i & 15); j++)
Ingo Molnar3efa1cc92009-06-14 15:04:15 +02001313 cdprintf(" ");
Ingo Molnar8465b052009-06-14 14:44:07 +02001314 for (j = 0; j < (i & 15); j++) {
Peter Zijlstraa73c7d82009-06-18 09:44:20 +02001315 if (isprint(raw_event[i-15+j]))
Ingo Molnar3efa1cc92009-06-14 15:04:15 +02001316 cdprintf("%c", raw_event[i-15+j]);
Ingo Molnar8465b052009-06-14 14:44:07 +02001317 else
Ingo Molnar3efa1cc92009-06-14 15:04:15 +02001318 cdprintf(".");
Ingo Molnar8465b052009-06-14 14:44:07 +02001319 }
Ingo Molnar3efa1cc92009-06-14 15:04:15 +02001320 cdprintf("\n");
Ingo Molnar8465b052009-06-14 14:44:07 +02001321 }
1322 }
1323 dprintf(".\n");
1324}
1325
Peter Zijlstra8f18aec2009-08-06 19:40:28 +02001326static struct perf_header *header;
1327
1328static struct perf_counter_attr *perf_header__find_attr(u64 id)
1329{
1330 int i;
1331
1332 for (i = 0; i < header->attrs; i++) {
1333 struct perf_header_attr *attr = header->attr[i];
1334 int j;
1335
1336 for (j = 0; j < attr->ids; j++) {
1337 if (attr->id[j] == id)
1338 return &attr->attr;
1339 }
1340 }
1341
1342 return NULL;
1343}
1344
Ingo Molnarb2fef072009-06-05 18:07:51 +02001345static int
Peter Zijlstrae9ea2fd2009-06-24 22:46:04 +02001346process_read_event(event_t *event, unsigned long offset, unsigned long head)
1347{
Peter Zijlstra8f18aec2009-08-06 19:40:28 +02001348 struct perf_counter_attr *attr = perf_header__find_attr(event->read.id);
1349
Brice Goglin8d513272009-08-07 13:55:24 +02001350 if (show_threads) {
1351 char *name = attr ? __event_name(attr->type, attr->config)
1352 : "unknown";
1353 perf_read_values_add_value(&show_threads_values,
1354 event->read.pid, event->read.tid,
1355 event->read.id,
1356 name,
1357 event->read.value);
1358 }
1359
Peter Zijlstra8f18aec2009-08-06 19:40:28 +02001360 dprintf("%p [%p]: PERF_EVENT_READ: %d %d %s %Lu\n",
Peter Zijlstrae9ea2fd2009-06-24 22:46:04 +02001361 (void *)(offset + head),
1362 (void *)(long)(event->header.size),
1363 event->read.pid,
1364 event->read.tid,
Peter Zijlstra8f18aec2009-08-06 19:40:28 +02001365 attr ? __event_name(attr->type, attr->config)
1366 : "FAIL",
Peter Zijlstrae9ea2fd2009-06-24 22:46:04 +02001367 event->read.value);
1368
1369 return 0;
1370}
1371
1372static int
Ingo Molnard80d3382009-06-03 23:14:49 +02001373process_event(event_t *event, unsigned long offset, unsigned long head)
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -03001374{
Ingo Molnar8465b052009-06-14 14:44:07 +02001375 trace_event(event);
1376
Ingo Molnar75051722009-06-03 23:14:49 +02001377 switch (event->header.type) {
Peter Zijlstrae6e18ec2009-06-25 11:27:12 +02001378 case PERF_EVENT_SAMPLE:
1379 return process_sample_event(event, offset, head);
1380
Ingo Molnar75051722009-06-03 23:14:49 +02001381 case PERF_EVENT_MMAP:
1382 return process_mmap_event(event, offset, head);
Ingo Molnar97b07b62009-05-26 18:48:58 +02001383
Ingo Molnar75051722009-06-03 23:14:49 +02001384 case PERF_EVENT_COMM:
1385 return process_comm_event(event, offset, head);
Ingo Molnared966aa2009-06-03 10:39:26 +02001386
Peter Zijlstra62fc4452009-06-04 16:53:49 +02001387 case PERF_EVENT_FORK:
Peter Zijlstra27d028d2009-07-23 16:52:41 +02001388 case PERF_EVENT_EXIT:
1389 return process_task_event(event, offset, head);
Peter Zijlstra62fc4452009-06-04 16:53:49 +02001390
Peter Zijlstra9d91a6f2009-06-18 11:40:28 +02001391 case PERF_EVENT_LOST:
1392 return process_lost_event(event, offset, head);
1393
Peter Zijlstrae9ea2fd2009-06-24 22:46:04 +02001394 case PERF_EVENT_READ:
1395 return process_read_event(event, offset, head);
1396
Ingo Molnard11444d2009-06-03 23:29:14 +02001397 /*
1398 * We dont process them right now but they are fine:
1399 */
Peter Zijlstra62fc4452009-06-04 16:53:49 +02001400
Ingo Molnard11444d2009-06-03 23:29:14 +02001401 case PERF_EVENT_THROTTLE:
1402 case PERF_EVENT_UNTHROTTLE:
1403 return 0;
1404
Ingo Molnard80d3382009-06-03 23:14:49 +02001405 default:
1406 return -1;
1407 }
1408
1409 return 0;
1410}
1411
Peter Zijlstrae6e18ec2009-06-25 11:27:12 +02001412static u64 perf_header__sample_type(void)
Peter Zijlstra7c6a1c62009-06-25 17:05:54 +02001413{
Peter Zijlstrae6e18ec2009-06-25 11:27:12 +02001414 u64 sample_type = 0;
Peter Zijlstra7c6a1c62009-06-25 17:05:54 +02001415 int i;
1416
1417 for (i = 0; i < header->attrs; i++) {
1418 struct perf_header_attr *attr = header->attr[i];
1419
Peter Zijlstrae6e18ec2009-06-25 11:27:12 +02001420 if (!sample_type)
1421 sample_type = attr->attr.sample_type;
1422 else if (sample_type != attr->attr.sample_type)
1423 die("non matching sample_type");
Peter Zijlstra7c6a1c62009-06-25 17:05:54 +02001424 }
1425
Peter Zijlstrae6e18ec2009-06-25 11:27:12 +02001426 return sample_type;
Peter Zijlstra7c6a1c62009-06-25 17:05:54 +02001427}
Peter Zijlstraf5970552009-06-18 23:22:55 +02001428
Ingo Molnard80d3382009-06-03 23:14:49 +02001429static int __cmd_report(void)
1430{
Ingo Molnar75051722009-06-03 23:14:49 +02001431 int ret, rc = EXIT_FAILURE;
Ingo Molnard80d3382009-06-03 23:14:49 +02001432 unsigned long offset = 0;
Peter Zijlstra7c6a1c62009-06-25 17:05:54 +02001433 unsigned long head, shift;
Ingo Molnard80d3382009-06-03 23:14:49 +02001434 struct stat stat;
Ingo Molnard80d3382009-06-03 23:14:49 +02001435 event_t *event;
Ingo Molnard80d3382009-06-03 23:14:49 +02001436 uint32_t size;
Ingo Molnar75051722009-06-03 23:14:49 +02001437 char *buf;
Ingo Molnard80d3382009-06-03 23:14:49 +02001438
1439 register_idle_thread();
1440
Brice Goglin8d513272009-08-07 13:55:24 +02001441 if (show_threads)
1442 perf_read_values_init(&show_threads_values);
1443
Ingo Molnard80d3382009-06-03 23:14:49 +02001444 input = open(input_name, O_RDONLY);
1445 if (input < 0) {
Ingo Molnara14832f2009-06-07 17:58:23 +02001446 fprintf(stderr, " failed to open file: %s", input_name);
1447 if (!strcmp(input_name, "perf.data"))
1448 fprintf(stderr, " (try 'perf record' first)");
1449 fprintf(stderr, "\n");
Ingo Molnard80d3382009-06-03 23:14:49 +02001450 exit(-1);
1451 }
1452
1453 ret = fstat(input, &stat);
1454 if (ret < 0) {
1455 perror("failed to stat file");
1456 exit(-1);
1457 }
1458
1459 if (!stat.st_size) {
1460 fprintf(stderr, "zero-sized file, nothing to do!\n");
1461 exit(0);
1462 }
1463
Peter Zijlstra7c6a1c62009-06-25 17:05:54 +02001464 header = perf_header__read(input);
1465 head = header->data_offset;
Peter Zijlstraf5970552009-06-18 23:22:55 +02001466
Peter Zijlstrae6e18ec2009-06-25 11:27:12 +02001467 sample_type = perf_header__sample_type();
1468
Frederic Weisbecker91b4eae2009-07-05 07:39:17 +02001469 if (!(sample_type & PERF_SAMPLE_CALLCHAIN)) {
1470 if (sort__has_parent) {
1471 fprintf(stderr, "selected --sort parent, but no"
1472 " callchain data. Did you call"
1473 " perf record without -g?\n");
1474 exit(-1);
1475 }
1476 if (callchain) {
1477 fprintf(stderr, "selected -c but no callchain data."
1478 " Did you call perf record without"
1479 " -g?\n");
1480 exit(-1);
1481 }
Frederic Weisbeckerb1a88342009-08-08 02:16:24 +02001482 } else if (callchain_param.mode != CHAIN_NONE && !callchain) {
1483 callchain = 1;
1484 if (register_callchain_param(&callchain_param) < 0) {
1485 fprintf(stderr, "Can't register callchain"
1486 " params\n");
1487 exit(-1);
1488 }
Peter Zijlstraf5970552009-06-18 23:22:55 +02001489 }
1490
Ingo Molnard80d3382009-06-03 23:14:49 +02001491 if (load_kernel() < 0) {
1492 perror("failed to load kernel symbols");
1493 return EXIT_FAILURE;
1494 }
1495
1496 if (!full_paths) {
1497 if (getcwd(__cwd, sizeof(__cwd)) == NULL) {
1498 perror("failed to get the current directory");
1499 return EXIT_FAILURE;
1500 }
1501 cwdlen = strlen(cwd);
1502 } else {
1503 cwd = NULL;
1504 cwdlen = 0;
1505 }
Peter Zijlstra7c6a1c62009-06-25 17:05:54 +02001506
1507 shift = page_size * (head / page_size);
1508 offset += shift;
1509 head -= shift;
1510
Ingo Molnard80d3382009-06-03 23:14:49 +02001511remap:
1512 buf = (char *)mmap(NULL, page_size * mmap_window, PROT_READ,
1513 MAP_SHARED, input, offset);
1514 if (buf == MAP_FAILED) {
1515 perror("failed to mmap file");
1516 exit(-1);
1517 }
1518
1519more:
1520 event = (event_t *)(buf + head);
1521
1522 size = event->header.size;
1523 if (!size)
1524 size = 8;
1525
1526 if (head + event->header.size >= page_size * mmap_window) {
Ingo Molnard80d3382009-06-03 23:14:49 +02001527 int ret;
1528
Peter Zijlstra7c6a1c62009-06-25 17:05:54 +02001529 shift = page_size * (head / page_size);
1530
Ingo Molnard80d3382009-06-03 23:14:49 +02001531 ret = munmap(buf, page_size * mmap_window);
1532 assert(ret == 0);
1533
1534 offset += shift;
1535 head -= shift;
1536 goto remap;
1537 }
1538
1539 size = event->header.size;
1540
Ingo Molnar8465b052009-06-14 14:44:07 +02001541 dprintf("\n%p [%p]: event: %d\n",
Ingo Molnarb2fef072009-06-05 18:07:51 +02001542 (void *)(offset + head),
1543 (void *)(long)event->header.size,
1544 event->header.type);
1545
Ingo Molnard80d3382009-06-03 23:14:49 +02001546 if (!size || process_event(event, offset, head) < 0) {
1547
Ingo Molnar35029732009-06-03 09:38:58 +02001548 dprintf("%p [%p]: skipping unknown header type: %d\n",
1549 (void *)(offset + head),
1550 (void *)(long)(event->header.size),
1551 event->header.type);
Peter Zijlstrab7a16ea2009-05-27 13:35:35 +02001552
Ingo Molnar3e706112009-05-26 18:53:17 +02001553 total_unknown++;
Peter Zijlstra6142f9e2009-05-26 20:51:47 +02001554
1555 /*
1556 * assume we lost track of the stream, check alignment, and
1557 * increment a single u64 in the hope to catch on again 'soon'.
1558 */
1559
1560 if (unlikely(head & 7))
1561 head &= ~7ULL;
1562
1563 size = 8;
Ingo Molnar97b07b62009-05-26 18:48:58 +02001564 }
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -03001565
Peter Zijlstra6142f9e2009-05-26 20:51:47 +02001566 head += size;
Ingo Molnarf49515b2009-05-26 19:03:36 +02001567
Peter Zijlstra7c6a1c62009-06-25 17:05:54 +02001568 if (offset + head >= header->data_offset + header->data_size)
Peter Zijlstraf5970552009-06-18 23:22:55 +02001569 goto done;
1570
Ingo Molnarf37a2912009-07-01 12:37:06 +02001571 if (offset + head < (unsigned long)stat.st_size)
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -03001572 goto more;
1573
Peter Zijlstraf5970552009-06-18 23:22:55 +02001574done:
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -03001575 rc = EXIT_SUCCESS;
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -03001576 close(input);
Ingo Molnar97b07b62009-05-26 18:48:58 +02001577
Ingo Molnar35029732009-06-03 09:38:58 +02001578 dprintf(" IP events: %10ld\n", total);
1579 dprintf(" mmap events: %10ld\n", total_mmap);
1580 dprintf(" comm events: %10ld\n", total_comm);
Peter Zijlstra62fc4452009-06-04 16:53:49 +02001581 dprintf(" fork events: %10ld\n", total_fork);
Peter Zijlstra9d91a6f2009-06-18 11:40:28 +02001582 dprintf(" lost events: %10ld\n", total_lost);
Ingo Molnar35029732009-06-03 09:38:58 +02001583 dprintf(" unknown events: %10ld\n", total_unknown);
Ingo Molnar97b07b62009-05-26 18:48:58 +02001584
Ingo Molnar35029732009-06-03 09:38:58 +02001585 if (dump_trace)
Ingo Molnar97b07b62009-05-26 18:48:58 +02001586 return 0;
Ingo Molnar97b07b62009-05-26 18:48:58 +02001587
Arnaldo Carvalho de Melo9ac99542009-06-04 13:54:00 -03001588 if (verbose >= 3)
Frederic Weisbecker6baa0a5a2009-08-14 12:21:53 +02001589 threads__fprintf(stdout, &threads);
Arnaldo Carvalho de Melo9ac99542009-06-04 13:54:00 -03001590
Peter Zijlstrae7fb08b2009-05-27 20:20:24 +02001591 if (verbose >= 2)
Ingo Molnar16f762a2009-05-27 09:10:38 +02001592 dsos__fprintf(stdout);
Ingo Molnar16f762a2009-05-27 09:10:38 +02001593
Peter Zijlstra82292892009-06-03 12:37:36 +02001594 collapse__resort();
Frederic Weisbeckerc20ab372009-07-02 20:14:33 +02001595 output__resort(total);
Peter Zijlstrae7fb08b2009-05-27 20:20:24 +02001596 output__fprintf(stdout, total);
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -03001597
Brice Goglin8d513272009-08-07 13:55:24 +02001598 if (show_threads)
1599 perf_read_values_destroy(&show_threads_values);
1600
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -03001601 return rc;
1602}
1603
Frederic Weisbecker4eb3e472009-07-02 17:58:21 +02001604static int
1605parse_callchain_opt(const struct option *opt __used, const char *arg,
1606 int unset __used)
1607{
Frederic Weisbeckerc20ab372009-07-02 20:14:33 +02001608 char *tok;
1609 char *endptr;
1610
Frederic Weisbecker4eb3e472009-07-02 17:58:21 +02001611 callchain = 1;
1612
1613 if (!arg)
1614 return 0;
1615
Frederic Weisbeckerc20ab372009-07-02 20:14:33 +02001616 tok = strtok((char *)arg, ",");
1617 if (!tok)
1618 return -1;
1619
1620 /* get the output mode */
1621 if (!strncmp(tok, "graph", strlen(arg)))
Frederic Weisbecker805d1272009-07-05 07:39:21 +02001622 callchain_param.mode = CHAIN_GRAPH_ABS;
Frederic Weisbecker4eb3e472009-07-02 17:58:21 +02001623
Frederic Weisbeckerc20ab372009-07-02 20:14:33 +02001624 else if (!strncmp(tok, "flat", strlen(arg)))
Frederic Weisbecker805d1272009-07-05 07:39:21 +02001625 callchain_param.mode = CHAIN_FLAT;
1626
1627 else if (!strncmp(tok, "fractal", strlen(arg)))
1628 callchain_param.mode = CHAIN_GRAPH_REL;
1629
Frederic Weisbeckerb1a88342009-08-08 02:16:24 +02001630 else if (!strncmp(tok, "none", strlen(arg))) {
1631 callchain_param.mode = CHAIN_NONE;
1632 callchain = 0;
1633
1634 return 0;
1635 }
1636
Frederic Weisbecker4eb3e472009-07-02 17:58:21 +02001637 else
1638 return -1;
1639
Frederic Weisbeckerc20ab372009-07-02 20:14:33 +02001640 /* get the min percentage */
1641 tok = strtok(NULL, ",");
1642 if (!tok)
Frederic Weisbecker805d1272009-07-05 07:39:21 +02001643 goto setup;
Frederic Weisbeckerc20ab372009-07-02 20:14:33 +02001644
Frederic Weisbecker805d1272009-07-05 07:39:21 +02001645 callchain_param.min_percent = strtod(tok, &endptr);
Frederic Weisbeckerc20ab372009-07-02 20:14:33 +02001646 if (tok == endptr)
1647 return -1;
1648
Frederic Weisbecker805d1272009-07-05 07:39:21 +02001649setup:
1650 if (register_callchain_param(&callchain_param) < 0) {
1651 fprintf(stderr, "Can't register callchain params\n");
1652 return -1;
1653 }
Frederic Weisbecker4eb3e472009-07-02 17:58:21 +02001654 return 0;
1655}
1656
Ingo Molnar53cb8bc2009-05-26 09:17:18 +02001657static const char * const report_usage[] = {
1658 "perf report [<options>] <command>",
1659 NULL
1660};
1661
1662static const struct option options[] = {
1663 OPT_STRING('i', "input", &input_name, "file",
1664 "input file name"),
Arnaldo Carvalho de Melo815e7772009-05-26 19:46:14 -03001665 OPT_BOOLEAN('v', "verbose", &verbose,
1666 "be more verbose (show symbol address, etc)"),
Ingo Molnar97b07b62009-05-26 18:48:58 +02001667 OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace,
1668 "dump raw trace in ASCII"),
Peter Zijlstra450aaa22009-05-27 20:20:23 +02001669 OPT_STRING('k', "vmlinux", &vmlinux, "file", "vmlinux pathname"),
Mike Galbraith42976482009-07-02 08:09:46 +02001670 OPT_BOOLEAN('m', "modules", &modules,
1671 "load module symbols - WARNING: use only with -k and LIVE kernel"),
Arnaldo Carvalho de Meloe3d7e182009-07-11 12:18:37 -03001672 OPT_BOOLEAN('n', "show-nr-samples", &show_nr_samples,
1673 "Show a column with the number of samples"),
Brice Goglin8d513272009-08-07 13:55:24 +02001674 OPT_BOOLEAN('T', "threads", &show_threads,
1675 "Show per-thread event counters"),
Brice Goglin9f866692009-08-10 15:26:32 +02001676 OPT_STRING(0, "pretty", &pretty_printing_style, "key",
1677 "pretty printing style key: normal raw"),
Ingo Molnar63299f02009-05-28 10:52:00 +02001678 OPT_STRING('s', "sort", &sort_order, "key[,key2...]",
Ingo Molnarb25bcf22009-06-18 07:01:03 +02001679 "sort by key(s): pid, comm, dso, symbol, parent"),
Arnaldo Carvalho de Melob78c07d2009-05-29 13:48:59 -03001680 OPT_BOOLEAN('P', "full-paths", &full_paths,
1681 "Don't shorten the pathnames taking into account the cwd"),
Ingo Molnarb25bcf22009-06-18 07:01:03 +02001682 OPT_STRING('p', "parent", &parent_pattern, "regex",
1683 "regex filter to identify parent, see: '--sort parent'"),
Ingo Molnarb8e6d822009-06-18 14:32:19 +02001684 OPT_BOOLEAN('x', "exclude-other", &exclude_other,
1685 "Only display entries with parent-match"),
Anton Blanchard1483b19f2009-07-16 15:44:29 +02001686 OPT_CALLBACK_DEFAULT('g', "call-graph", NULL, "output_type,min_percent",
Frederic Weisbeckerc20ab372009-07-02 20:14:33 +02001687 "Display callchains using output_type and min percent threshold. "
Anton Blanchard1483b19f2009-07-16 15:44:29 +02001688 "Default: fractal,0.5", &parse_callchain_opt, callchain_default_opt),
Arnaldo Carvalho de Melo25903402009-06-30 19:01:20 -03001689 OPT_STRING('d', "dsos", &dso_list_str, "dso[,dso...]",
1690 "only consider symbols in these dsos"),
Arnaldo Carvalho de Melocc8b88b2009-06-30 19:01:21 -03001691 OPT_STRING('C', "comms", &comm_list_str, "comm[,comm...]",
1692 "only consider symbols in these comms"),
Arnaldo Carvalho de Melo7bec7a92009-06-30 19:01:22 -03001693 OPT_STRING('S', "symbols", &sym_list_str, "symbol[,symbol...]",
1694 "only consider these symbols"),
Arnaldo Carvalho de Melo52d422d2009-07-10 22:47:28 -03001695 OPT_STRING('w', "column-widths", &col_width_list_str,
1696 "width[,width...]",
1697 "don't try to adjust column width, use these fixed values"),
1698 OPT_STRING('t', "field-separator", &field_sep, "separator",
1699 "separator for columns, no spaces will be added between "
1700 "columns '.' is reserved."),
Ingo Molnar53cb8bc2009-05-26 09:17:18 +02001701 OPT_END()
1702};
1703
Ingo Molnar5352f352009-06-03 10:07:39 +02001704static void setup_sorting(void)
1705{
1706 char *tmp, *tok, *str = strdup(sort_order);
1707
1708 for (tok = strtok_r(str, ", ", &tmp);
1709 tok; tok = strtok_r(NULL, ", ", &tmp)) {
1710 if (sort_dimension__add(tok) < 0) {
1711 error("Unknown --sort key: `%s'", tok);
1712 usage_with_options(report_usage, options);
1713 }
1714 }
1715
1716 free(str);
1717}
1718
Arnaldo Carvalho de Melocc8b88b2009-06-30 19:01:21 -03001719static void setup_list(struct strlist **list, const char *list_str,
Arnaldo Carvalho de Melo021191b2009-07-11 12:18:35 -03001720 struct sort_entry *se, const char *list_name,
1721 FILE *fp)
Arnaldo Carvalho de Melocc8b88b2009-06-30 19:01:21 -03001722{
1723 if (list_str) {
1724 *list = strlist__new(true, list_str);
1725 if (!*list) {
1726 fprintf(stderr, "problems parsing %s list\n",
1727 list_name);
1728 exit(129);
1729 }
Arnaldo Carvalho de Melo021191b2009-07-11 12:18:35 -03001730 if (strlist__nr_entries(*list) == 1) {
1731 fprintf(fp, "# %s: %s\n", list_name,
1732 strlist__entry(*list, 0)->s);
1733 se->elide = true;
1734 }
Arnaldo Carvalho de Melocc8b88b2009-06-30 19:01:21 -03001735 }
1736}
1737
Ingo Molnarf37a2912009-07-01 12:37:06 +02001738int cmd_report(int argc, const char **argv, const char *prefix __used)
Ingo Molnar53cb8bc2009-05-26 09:17:18 +02001739{
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -03001740 symbol__init();
Ingo Molnar53cb8bc2009-05-26 09:17:18 +02001741
1742 page_size = getpagesize();
1743
Ingo Molnaredc52de2009-06-04 16:24:37 +02001744 argc = parse_options(argc, argv, options, report_usage, 0);
Ingo Molnar53cb8bc2009-05-26 09:17:18 +02001745
Peter Zijlstra1aa16732009-05-27 20:20:25 +02001746 setup_sorting();
1747
Arnaldo Carvalho de Melo021191b2009-07-11 12:18:35 -03001748 if (parent_pattern != default_parent_pattern) {
Ingo Molnarb8e6d822009-06-18 14:32:19 +02001749 sort_dimension__add("parent");
Arnaldo Carvalho de Melo021191b2009-07-11 12:18:35 -03001750 sort_parent.elide = 1;
1751 } else
Ingo Molnarb8e6d822009-06-18 14:32:19 +02001752 exclude_other = 0;
1753
Ingo Molnaredc52de2009-06-04 16:24:37 +02001754 /*
1755 * Any (unrecognized) arguments left?
1756 */
1757 if (argc)
1758 usage_with_options(report_usage, options);
1759
Ingo Molnara930d2c2009-05-27 09:50:13 +02001760 setup_pager();
1761
Arnaldo Carvalho de Melo021191b2009-07-11 12:18:35 -03001762 setup_list(&dso_list, dso_list_str, &sort_dso, "dso", stdout);
1763 setup_list(&comm_list, comm_list_str, &sort_comm, "comm", stdout);
1764 setup_list(&sym_list, sym_list_str, &sort_sym, "symbol", stdout);
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -03001765
Arnaldo Carvalho de Melo52d422d2009-07-10 22:47:28 -03001766 if (field_sep && *field_sep == '.') {
1767 fputs("'.' is the only non valid --field-separator argument\n",
1768 stderr);
1769 exit(129);
1770 }
1771
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -03001772 return __cmd_report();
1773}