blob: a4f8cc20915138250c288787205dd23f4b187cbb [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"
Frederic Weisbecker8f28827a2009-08-16 22:05:48 +020023#include "util/debug.h"
Peter Zijlstra7c6a1c62009-06-25 17:05:54 +020024#include "util/header.h"
Ingo Molnar53cb8bc2009-05-26 09:17:18 +020025
26#include "util/parse-options.h"
27#include "util/parse-events.h"
28
Frederic Weisbecker016e92f2009-10-07 12:47:31 +020029#include "util/data_map.h"
Frederic Weisbecker6baa0a52009-08-14 12:21:53 +020030#include "util/thread.h"
John Kacurdd68ada2009-09-24 18:02:49 +020031#include "util/sort.h"
John Kacur3d1d07e2009-09-28 15:32:55 +020032#include "util/hist.h"
Frederic Weisbecker6baa0a52009-08-14 12:21:53 +020033
Ingo Molnar23ac9cb2009-05-27 09:33:18 +020034static char const *input_name = "perf.data";
Ingo Molnarbd741372009-06-04 14:13:04 +020035
Arnaldo Carvalho de Melo52d422d2009-07-10 22:47:28 -030036static char *dso_list_str, *comm_list_str, *sym_list_str,
37 *col_width_list_str;
Arnaldo Carvalho de Melo7bec7a92009-06-30 19:01:22 -030038static struct strlist *dso_list, *comm_list, *sym_list;
Ingo Molnarbd741372009-06-04 14:13:04 +020039
Peter Zijlstrafa6963b2009-08-19 11:18:26 +020040static int force;
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -030041
Arnaldo Carvalho de Melob78c07d2009-05-29 13:48:59 -030042static int full_paths;
Arnaldo Carvalho de Meloe3d7e182009-07-11 12:18:37 -030043static int show_nr_samples;
Ingo Molnar97b07b62009-05-26 18:48:58 +020044
Brice Goglin8d513272009-08-07 13:55:24 +020045static int show_threads;
46static struct perf_read_values show_threads_values;
47
Brice Goglin9f866692009-08-10 15:26:32 +020048static char default_pretty_printing_style[] = "normal";
49static char *pretty_printing_style = default_pretty_printing_style;
50
Ingo Molnarb8e6d822009-06-18 14:32:19 +020051static int exclude_other = 1;
Frederic Weisbeckerbe903882009-07-05 07:39:18 +020052
Frederic Weisbecker805d1272009-07-05 07:39:21 +020053static char callchain_default_opt[] = "fractal,0.5";
54
Frederic Weisbecker016e92f2009-10-07 12:47:31 +020055static char *cwd;
Frederic Weisbecker66e274f2009-08-12 11:07:25 +020056static int cwdlen;
57
Frederic Weisbecker0d3a5c82009-08-16 20:56:37 +020058static struct perf_header *header;
59
Peter Zijlstrae6e18ec2009-06-25 11:27:12 +020060static u64 sample_type;
61
Frederic Weisbecker4eb3e472009-07-02 17:58:21 +020062static size_t ipchain__fprintf_graph_line(FILE *fp, int depth, int depth_mask)
63{
64 int i;
65 size_t ret = 0;
66
67 ret += fprintf(fp, "%s", " ");
68
69 for (i = 0; i < depth; i++)
70 if (depth_mask & (1 << i))
71 ret += fprintf(fp, "| ");
72 else
73 ret += fprintf(fp, " ");
74
75 ret += fprintf(fp, "\n");
76
77 return ret;
78}
Peter Zijlstra1aa16732009-05-27 20:20:25 +020079static size_t
Frederic Weisbecker4eb3e472009-07-02 17:58:21 +020080ipchain__fprintf_graph(FILE *fp, struct callchain_list *chain, int depth,
81 int depth_mask, int count, u64 total_samples,
82 int hits)
83{
84 int i;
85 size_t ret = 0;
86
87 ret += fprintf(fp, "%s", " ");
88 for (i = 0; i < depth; i++) {
89 if (depth_mask & (1 << i))
90 ret += fprintf(fp, "|");
91 else
92 ret += fprintf(fp, " ");
93 if (!count && i == depth - 1) {
94 double percent;
95
96 percent = hits * 100.0 / total_samples;
Frederic Weisbecker24b57c62009-07-02 20:14:35 +020097 ret += percent_color_fprintf(fp, "--%2.2f%%-- ", percent);
Frederic Weisbecker4eb3e472009-07-02 17:58:21 +020098 } else
99 ret += fprintf(fp, "%s", " ");
100 }
101 if (chain->sym)
102 ret += fprintf(fp, "%s\n", chain->sym->name);
103 else
104 ret += fprintf(fp, "%p\n", (void *)(long)chain->ip);
105
106 return ret;
107}
108
Frederic Weisbecker25446032009-08-08 02:16:25 +0200109static struct symbol *rem_sq_bracket;
110static struct callchain_list rem_hits;
111
112static void init_rem_hits(void)
113{
114 rem_sq_bracket = malloc(sizeof(*rem_sq_bracket) + 6);
115 if (!rem_sq_bracket) {
116 fprintf(stderr, "Not enough memory to display remaining hits\n");
117 return;
118 }
119
120 strcpy(rem_sq_bracket->name, "[...]");
121 rem_hits.sym = rem_sq_bracket;
122}
123
Frederic Weisbecker4eb3e472009-07-02 17:58:21 +0200124static size_t
125callchain__fprintf_graph(FILE *fp, struct callchain_node *self,
126 u64 total_samples, int depth, int depth_mask)
127{
128 struct rb_node *node, *next;
129 struct callchain_node *child;
130 struct callchain_list *chain;
131 int new_depth_mask = depth_mask;
Frederic Weisbecker805d1272009-07-05 07:39:21 +0200132 u64 new_total;
Frederic Weisbecker25446032009-08-08 02:16:25 +0200133 u64 remaining;
Frederic Weisbecker4eb3e472009-07-02 17:58:21 +0200134 size_t ret = 0;
135 int i;
136
Frederic Weisbecker805d1272009-07-05 07:39:21 +0200137 if (callchain_param.mode == CHAIN_GRAPH_REL)
Frederic Weisbecker19532872009-08-07 07:11:05 +0200138 new_total = self->children_hit;
Frederic Weisbecker805d1272009-07-05 07:39:21 +0200139 else
140 new_total = total_samples;
141
Frederic Weisbecker25446032009-08-08 02:16:25 +0200142 remaining = new_total;
143
Frederic Weisbecker4eb3e472009-07-02 17:58:21 +0200144 node = rb_first(&self->rb_root);
145 while (node) {
Frederic Weisbecker25446032009-08-08 02:16:25 +0200146 u64 cumul;
147
Frederic Weisbecker4eb3e472009-07-02 17:58:21 +0200148 child = rb_entry(node, struct callchain_node, rb_node);
Frederic Weisbecker25446032009-08-08 02:16:25 +0200149 cumul = cumul_hits(child);
150 remaining -= cumul;
Frederic Weisbecker4eb3e472009-07-02 17:58:21 +0200151
152 /*
153 * The depth mask manages the output of pipes that show
154 * the depth. We don't want to keep the pipes of the current
Frederic Weisbecker25446032009-08-08 02:16:25 +0200155 * level for the last child of this depth.
156 * Except if we have remaining filtered hits. They will
157 * supersede the last child
Frederic Weisbecker4eb3e472009-07-02 17:58:21 +0200158 */
159 next = rb_next(node);
Frederic Weisbecker25446032009-08-08 02:16:25 +0200160 if (!next && (callchain_param.mode != CHAIN_GRAPH_REL || !remaining))
Frederic Weisbecker4eb3e472009-07-02 17:58:21 +0200161 new_depth_mask &= ~(1 << (depth - 1));
162
163 /*
164 * But we keep the older depth mask for the line seperator
165 * to keep the level link until we reach the last child
166 */
167 ret += ipchain__fprintf_graph_line(fp, depth, depth_mask);
168 i = 0;
169 list_for_each_entry(chain, &child->val, list) {
170 if (chain->ip >= PERF_CONTEXT_MAX)
171 continue;
172 ret += ipchain__fprintf_graph(fp, chain, depth,
173 new_depth_mask, i++,
Frederic Weisbecker805d1272009-07-05 07:39:21 +0200174 new_total,
Frederic Weisbecker25446032009-08-08 02:16:25 +0200175 cumul);
Frederic Weisbecker4eb3e472009-07-02 17:58:21 +0200176 }
Frederic Weisbecker805d1272009-07-05 07:39:21 +0200177 ret += callchain__fprintf_graph(fp, child, new_total,
Frederic Weisbecker4eb3e472009-07-02 17:58:21 +0200178 depth + 1,
179 new_depth_mask | (1 << depth));
180 node = next;
181 }
182
Frederic Weisbecker25446032009-08-08 02:16:25 +0200183 if (callchain_param.mode == CHAIN_GRAPH_REL &&
184 remaining && remaining != new_total) {
185
186 if (!rem_sq_bracket)
187 return ret;
188
189 new_depth_mask &= ~(1 << (depth - 1));
190
191 ret += ipchain__fprintf_graph(fp, &rem_hits, depth,
192 new_depth_mask, 0, new_total,
193 remaining);
194 }
195
Frederic Weisbecker4eb3e472009-07-02 17:58:21 +0200196 return ret;
197}
198
199static size_t
200callchain__fprintf_flat(FILE *fp, struct callchain_node *self,
201 u64 total_samples)
Frederic Weisbeckerf55c5552009-06-26 16:28:01 +0200202{
203 struct callchain_list *chain;
204 size_t ret = 0;
205
206 if (!self)
207 return 0;
208
Frederic Weisbecker4eb3e472009-07-02 17:58:21 +0200209 ret += callchain__fprintf_flat(fp, self->parent, total_samples);
Frederic Weisbeckerf55c5552009-06-26 16:28:01 +0200210
211
Frederic Weisbecker44249612009-07-01 05:35:14 +0200212 list_for_each_entry(chain, &self->val, list) {
213 if (chain->ip >= PERF_CONTEXT_MAX)
214 continue;
215 if (chain->sym)
216 ret += fprintf(fp, " %s\n", chain->sym->name);
217 else
218 ret += fprintf(fp, " %p\n",
Ingo Molnarf37a2912009-07-01 12:37:06 +0200219 (void *)(long)chain->ip);
Frederic Weisbecker44249612009-07-01 05:35:14 +0200220 }
Frederic Weisbeckerf55c5552009-06-26 16:28:01 +0200221
222 return ret;
223}
224
225static size_t
226hist_entry_callchain__fprintf(FILE *fp, struct hist_entry *self,
227 u64 total_samples)
228{
229 struct rb_node *rb_node;
230 struct callchain_node *chain;
231 size_t ret = 0;
232
233 rb_node = rb_first(&self->sorted_chain);
234 while (rb_node) {
235 double percent;
236
237 chain = rb_entry(rb_node, struct callchain_node, rb_node);
238 percent = chain->hit * 100.0 / total_samples;
Frederic Weisbecker805d1272009-07-05 07:39:21 +0200239 switch (callchain_param.mode) {
240 case CHAIN_FLAT:
Frederic Weisbecker24b57c62009-07-02 20:14:35 +0200241 ret += percent_color_fprintf(fp, " %6.2f%%\n",
242 percent);
Frederic Weisbecker4eb3e472009-07-02 17:58:21 +0200243 ret += callchain__fprintf_flat(fp, chain, total_samples);
Frederic Weisbecker805d1272009-07-05 07:39:21 +0200244 break;
245 case CHAIN_GRAPH_ABS: /* Falldown */
246 case CHAIN_GRAPH_REL:
Frederic Weisbecker4eb3e472009-07-02 17:58:21 +0200247 ret += callchain__fprintf_graph(fp, chain,
248 total_samples, 1, 1);
Ingo Molnar83a09442009-08-15 12:26:57 +0200249 case CHAIN_NONE:
Frederic Weisbecker805d1272009-07-05 07:39:21 +0200250 default:
251 break;
Frederic Weisbecker4eb3e472009-07-02 17:58:21 +0200252 }
Frederic Weisbeckerf55c5552009-06-26 16:28:01 +0200253 ret += fprintf(fp, "\n");
254 rb_node = rb_next(rb_node);
255 }
256
257 return ret;
258}
259
Frederic Weisbeckerf55c5552009-06-26 16:28:01 +0200260static size_t
Paul Mackerras9cffa8d2009-06-19 22:21:42 +1000261hist_entry__fprintf(FILE *fp, struct hist_entry *self, u64 total_samples)
Peter Zijlstra1aa16732009-05-27 20:20:25 +0200262{
263 struct sort_entry *se;
264 size_t ret;
265
Ingo Molnarb8e6d822009-06-18 14:32:19 +0200266 if (exclude_other && !self->parent)
267 return 0;
268
Frederic Weisbecker1e11fd82009-07-02 20:14:34 +0200269 if (total_samples)
Arnaldo Carvalho de Melo52d422d2009-07-10 22:47:28 -0300270 ret = percent_color_fprintf(fp,
271 field_sep ? "%.2f" : " %6.2f%%",
272 (self->count * 100.0) / total_samples);
Frederic Weisbecker1e11fd82009-07-02 20:14:34 +0200273 else
Arnaldo Carvalho de Melo52d422d2009-07-10 22:47:28 -0300274 ret = fprintf(fp, field_sep ? "%lld" : "%12lld ", self->count);
Peter Zijlstra1aa16732009-05-27 20:20:25 +0200275
Arnaldo Carvalho de Meloe3d7e182009-07-11 12:18:37 -0300276 if (show_nr_samples) {
277 if (field_sep)
278 fprintf(fp, "%c%lld", *field_sep, self->count);
279 else
280 fprintf(fp, "%11lld", self->count);
281 }
Peter Zijlstra1aa16732009-05-27 20:20:25 +0200282
Peter Zijlstra71dd8942009-06-04 15:16:56 +0200283 list_for_each_entry(se, &hist_entry__sort_list, list) {
Arnaldo Carvalho de Melo021191b2009-07-11 12:18:35 -0300284 if (se->elide)
Ingo Molnarb8e6d822009-06-18 14:32:19 +0200285 continue;
286
Arnaldo Carvalho de Melo52d422d2009-07-10 22:47:28 -0300287 fprintf(fp, "%s", field_sep ?: " ");
288 ret += se->print(fp, self, se->width ? *se->width : 0);
Peter Zijlstra71dd8942009-06-04 15:16:56 +0200289 }
Peter Zijlstra1aa16732009-05-27 20:20:25 +0200290
291 ret += fprintf(fp, "\n");
292
Frederic Weisbeckerf55c5552009-06-26 16:28:01 +0200293 if (callchain)
294 hist_entry_callchain__fprintf(fp, self, total_samples);
295
Peter Zijlstra1aa16732009-05-27 20:20:25 +0200296 return ret;
297}
298
299/*
Peter Zijlstra6e7d6fd2009-06-17 15:51:44 +0200300 *
301 */
302
Arnaldo Carvalho de Melo52d422d2009-07-10 22:47:28 -0300303static void dso__calc_col_width(struct dso *self)
304{
305 if (!col_width_list_str && !field_sep &&
306 (!dso_list || strlist__has_entry(dso_list, self->name))) {
307 unsigned int slen = strlen(self->name);
308 if (slen > dsos__col_width)
309 dsos__col_width = slen;
310 }
311
312 self->slen_calculated = 1;
313}
314
Frederic Weisbecker5b447a62009-08-31 06:45:18 +0200315static void thread__comm_adjust(struct thread *self)
Frederic Weisbecker4273b002009-08-18 16:03:46 +0200316{
Frederic Weisbecker5b447a62009-08-31 06:45:18 +0200317 char *comm = self->comm;
Frederic Weisbecker4273b002009-08-18 16:03:46 +0200318
319 if (!col_width_list_str && !field_sep &&
320 (!comm_list || strlist__has_entry(comm_list, comm))) {
321 unsigned int slen = strlen(comm);
322
323 if (slen > comms__col_width) {
324 comms__col_width = slen;
325 threads__col_width = slen + 6;
326 }
327 }
Frederic Weisbecker5b447a62009-08-31 06:45:18 +0200328}
329
330static int thread__set_comm_adjust(struct thread *self, const char *comm)
331{
332 int ret = thread__set_comm(self, comm);
333
334 if (ret)
335 return ret;
336
337 thread__comm_adjust(self);
Frederic Weisbecker4273b002009-08-18 16:03:46 +0200338
339 return 0;
340}
341
342
Peter Zijlstra6e7d6fd2009-06-17 15:51:44 +0200343static struct symbol *
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -0300344resolve_symbol(struct thread *thread, struct map **mapp, u64 *ipp)
Peter Zijlstra6e7d6fd2009-06-17 15:51:44 +0200345{
Peter Zijlstra6e7d6fd2009-06-17 15:51:44 +0200346 struct map *map = mapp ? *mapp : NULL;
Peter Zijlstra520f2c32009-06-22 16:52:51 +0200347 u64 ip = *ipp;
Peter Zijlstra6e7d6fd2009-06-17 15:51:44 +0200348
Peter Zijlstra6e7d6fd2009-06-17 15:51:44 +0200349 if (map)
350 goto got_map;
351
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -0300352 if (!thread)
353 return NULL;
354
Peter Zijlstra6e7d6fd2009-06-17 15:51:44 +0200355 map = thread__find_map(thread, ip);
356 if (map != NULL) {
Arnaldo Carvalho de Melo52d422d2009-07-10 22:47:28 -0300357 /*
358 * We have to do this here as we may have a dso
359 * with no symbol hit that has a name longer than
360 * the ones with symbols sampled.
361 */
Arnaldo Carvalho de Melo021191b2009-07-11 12:18:35 -0300362 if (!sort_dso.elide && !map->dso->slen_calculated)
Arnaldo Carvalho de Melo52d422d2009-07-10 22:47:28 -0300363 dso__calc_col_width(map->dso);
364
Peter Zijlstra6e7d6fd2009-06-17 15:51:44 +0200365 if (mapp)
366 *mapp = map;
367got_map:
368 ip = map->map_ip(map, ip);
Peter Zijlstra6e7d6fd2009-06-17 15:51:44 +0200369 } else {
370 /*
371 * If this is outside of all known maps,
372 * and is a negative address, try to look it
373 * up in the kernel dso, as it might be a
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -0300374 * vsyscall or vdso (which executes in user-mode).
375 *
376 * XXX This is nasty, we should have a symbol list in
377 * the "[vdso]" dso, but for now lets use the old
378 * trick of looking in the whole kernel symbol list.
Peter Zijlstra6e7d6fd2009-06-17 15:51:44 +0200379 */
Arnaldo Carvalho de Meloc3b32fc2009-10-05 14:26:16 -0300380 if ((long long)ip < 0)
381 return kernel_maps__find_symbol(ip, mapp);
Peter Zijlstra6e7d6fd2009-06-17 15:51:44 +0200382 }
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -0300383 dump_printf(" ...... dso: %s\n",
384 map ? map->dso->long_name : "<not found>");
Frederic Weisbecker2cec19d2009-08-16 19:24:21 +0200385 dump_printf(" ...... map: %Lx -> %Lx\n", *ipp, ip);
Peter Zijlstra520f2c32009-06-22 16:52:51 +0200386 *ipp = ip;
Peter Zijlstra6e7d6fd2009-06-17 15:51:44 +0200387
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -0300388 return map ? map->dso->find_symbol(map->dso, ip) : NULL;
Peter Zijlstra6e7d6fd2009-06-17 15:51:44 +0200389}
390
Peter Zijlstra2a0a50f2009-06-18 22:20:45 +0200391static int call__match(struct symbol *sym)
Peter Zijlstra6e7d6fd2009-06-17 15:51:44 +0200392{
Ingo Molnarb25bcf22009-06-18 07:01:03 +0200393 if (sym->name && !regexec(&parent_regex, sym->name, 0, NULL, 0))
Peter Zijlstra2a0a50f2009-06-18 22:20:45 +0200394 return 1;
Peter Zijlstra6e7d6fd2009-06-17 15:51:44 +0200395
Peter Zijlstra2a0a50f2009-06-18 22:20:45 +0200396 return 0;
Peter Zijlstra6e7d6fd2009-06-17 15:51:44 +0200397}
398
Arnaldo Carvalho de Melo9735abf2009-10-03 10:42:45 -0300399static struct symbol **resolve_callchain(struct thread *thread, struct map *map,
400 struct ip_callchain *chain,
401 struct symbol **parent)
Frederic Weisbecker44249612009-07-01 05:35:14 +0200402{
Frederic Weisbecker44249612009-07-01 05:35:14 +0200403 u64 context = PERF_CONTEXT_MAX;
Ingo Molnar029e5b12009-07-03 13:17:28 +0200404 struct symbol **syms = NULL;
Ingo Molnarf37a2912009-07-01 12:37:06 +0200405 unsigned int i;
Frederic Weisbecker44249612009-07-01 05:35:14 +0200406
407 if (callchain) {
408 syms = calloc(chain->nr, sizeof(*syms));
409 if (!syms) {
410 fprintf(stderr, "Can't allocate memory for symbols\n");
411 exit(-1);
412 }
413 }
414
415 for (i = 0; i < chain->nr; i++) {
416 u64 ip = chain->ips[i];
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -0300417 struct symbol *sym = NULL;
Frederic Weisbecker44249612009-07-01 05:35:14 +0200418
419 if (ip >= PERF_CONTEXT_MAX) {
420 context = ip;
421 continue;
422 }
423
424 switch (context) {
Ingo Molnar88a69df2009-07-01 11:17:20 +0200425 case PERF_CONTEXT_HV:
Ingo Molnar88a69df2009-07-01 11:17:20 +0200426 break;
Frederic Weisbecker44249612009-07-01 05:35:14 +0200427 case PERF_CONTEXT_KERNEL:
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -0300428 sym = kernel_maps__find_symbol(ip, &map);
Frederic Weisbecker44249612009-07-01 05:35:14 +0200429 break;
430 default:
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -0300431 sym = resolve_symbol(thread, &map, &ip);
Frederic Weisbecker44249612009-07-01 05:35:14 +0200432 break;
433 }
434
Frederic Weisbecker44249612009-07-01 05:35:14 +0200435 if (sym) {
Arnaldo Carvalho de Melo9735abf2009-10-03 10:42:45 -0300436 if (sort__has_parent && !*parent && call__match(sym))
437 *parent = sym;
Frederic Weisbecker44249612009-07-01 05:35:14 +0200438 if (!callchain)
439 break;
440 syms[i] = sym;
441 }
442 }
443
444 return syms;
445}
446
Peter Zijlstra6e7d6fd2009-06-17 15:51:44 +0200447/*
Peter Zijlstra1aa16732009-05-27 20:20:25 +0200448 * collect histogram counts
449 */
450
Peter Zijlstrae7fb08b2009-05-27 20:20:24 +0200451static int
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -0300452hist_entry__add(struct thread *thread, struct map *map,
Paul Mackerras9cffa8d2009-06-19 22:21:42 +1000453 struct symbol *sym, u64 ip, struct ip_callchain *chain,
454 char level, u64 count)
Arnaldo Carvalho de Melo3a4b8cc2009-05-26 16:19:04 -0300455{
Arnaldo Carvalho de Melo9735abf2009-10-03 10:42:45 -0300456 struct symbol **syms = NULL, *parent = NULL;
457 bool hit;
Peter Zijlstrae7fb08b2009-05-27 20:20:24 +0200458 struct hist_entry *he;
Arnaldo Carvalho de Melo3a4b8cc2009-05-26 16:19:04 -0300459
Frederic Weisbecker44249612009-07-01 05:35:14 +0200460 if ((sort__has_parent || callchain) && chain)
Arnaldo Carvalho de Melo9735abf2009-10-03 10:42:45 -0300461 syms = resolve_callchain(thread, map, chain, &parent);
Peter Zijlstra6e7d6fd2009-06-17 15:51:44 +0200462
Arnaldo Carvalho de Melo9735abf2009-10-03 10:42:45 -0300463 he = __hist_entry__add(thread, map, sym, parent,
464 ip, count, level, &hit);
465 if (he == NULL)
Peter Zijlstrae7fb08b2009-05-27 20:20:24 +0200466 return -ENOMEM;
Arnaldo Carvalho de Melo9735abf2009-10-03 10:42:45 -0300467
468 if (hit)
469 he->count += count;
470
Frederic Weisbeckerf55c5552009-06-26 16:28:01 +0200471 if (callchain) {
Arnaldo Carvalho de Melo9735abf2009-10-03 10:42:45 -0300472 if (!hit)
473 callchain_init(&he->callchain);
Frederic Weisbecker44249612009-07-01 05:35:14 +0200474 append_chain(&he->callchain, chain, syms);
475 free(syms);
Frederic Weisbeckerf55c5552009-06-26 16:28:01 +0200476 }
Peter Zijlstrae7fb08b2009-05-27 20:20:24 +0200477
478 return 0;
Arnaldo Carvalho de Melo3a4b8cc2009-05-26 16:19:04 -0300479}
480
Paul Mackerras9cffa8d2009-06-19 22:21:42 +1000481static size_t output__fprintf(FILE *fp, u64 total_samples)
Arnaldo Carvalho de Melo3a4b8cc2009-05-26 16:19:04 -0300482{
Peter Zijlstrae7fb08b2009-05-27 20:20:24 +0200483 struct hist_entry *pos;
Ingo Molnar2d655372009-05-27 21:36:22 +0200484 struct sort_entry *se;
Arnaldo Carvalho de Melo3a4b8cc2009-05-26 16:19:04 -0300485 struct rb_node *nd;
486 size_t ret = 0;
Arnaldo Carvalho de Melo52d422d2009-07-10 22:47:28 -0300487 unsigned int width;
488 char *col_width = col_width_list_str;
Brice Goglin9f866692009-08-10 15:26:32 +0200489 int raw_printing_style;
490
491 raw_printing_style = !strcmp(pretty_printing_style, "raw");
Arnaldo Carvalho de Melo3a4b8cc2009-05-26 16:19:04 -0300492
Frederic Weisbecker25446032009-08-08 02:16:25 +0200493 init_rem_hits();
494
Arnaldo Carvalho de Melo021191b2009-07-11 12:18:35 -0300495 fprintf(fp, "# Samples: %Ld\n", (u64)total_samples);
Ingo Molnar05ca0612009-06-04 14:21:16 +0200496 fprintf(fp, "#\n");
Peter Zijlstraca8cdee2009-05-28 11:08:33 +0200497
498 fprintf(fp, "# Overhead");
Arnaldo Carvalho de Meloe3d7e182009-07-11 12:18:37 -0300499 if (show_nr_samples) {
500 if (field_sep)
501 fprintf(fp, "%cSamples", *field_sep);
502 else
503 fputs(" Samples ", fp);
504 }
Ingo Molnarb8e6d822009-06-18 14:32:19 +0200505 list_for_each_entry(se, &hist_entry__sort_list, list) {
Arnaldo Carvalho de Melo021191b2009-07-11 12:18:35 -0300506 if (se->elide)
Ingo Molnarb8e6d822009-06-18 14:32:19 +0200507 continue;
Arnaldo Carvalho de Melo52d422d2009-07-10 22:47:28 -0300508 if (field_sep) {
509 fprintf(fp, "%c%s", *field_sep, se->header);
510 continue;
511 }
512 width = strlen(se->header);
513 if (se->width) {
514 if (col_width_list_str) {
515 if (col_width) {
516 *se->width = atoi(col_width);
517 col_width = strchr(col_width, ',');
518 if (col_width)
519 ++col_width;
520 }
521 }
522 width = *se->width = max(*se->width, width);
523 }
524 fprintf(fp, " %*s", width, se->header);
Ingo Molnarb8e6d822009-06-18 14:32:19 +0200525 }
Peter Zijlstraca8cdee2009-05-28 11:08:33 +0200526 fprintf(fp, "\n");
527
Arnaldo Carvalho de Melo52d422d2009-07-10 22:47:28 -0300528 if (field_sep)
529 goto print_entries;
530
Peter Zijlstraca8cdee2009-05-28 11:08:33 +0200531 fprintf(fp, "# ........");
Arnaldo Carvalho de Meloe3d7e182009-07-11 12:18:37 -0300532 if (show_nr_samples)
533 fprintf(fp, " ..........");
Ingo Molnar2d655372009-05-27 21:36:22 +0200534 list_for_each_entry(se, &hist_entry__sort_list, list) {
Ingo Molnarf37a2912009-07-01 12:37:06 +0200535 unsigned int i;
Peter Zijlstraca8cdee2009-05-28 11:08:33 +0200536
Arnaldo Carvalho de Melo021191b2009-07-11 12:18:35 -0300537 if (se->elide)
Ingo Molnarb8e6d822009-06-18 14:32:19 +0200538 continue;
539
Ingo Molnar4593bba2009-06-02 15:34:25 +0200540 fprintf(fp, " ");
Arnaldo Carvalho de Melo52d422d2009-07-10 22:47:28 -0300541 if (se->width)
542 width = *se->width;
543 else
544 width = strlen(se->header);
545 for (i = 0; i < width; i++)
Peter Zijlstraca8cdee2009-05-28 11:08:33 +0200546 fprintf(fp, ".");
Ingo Molnar2d655372009-05-27 21:36:22 +0200547 }
Peter Zijlstraca8cdee2009-05-28 11:08:33 +0200548 fprintf(fp, "\n");
549
550 fprintf(fp, "#\n");
Ingo Molnar2d655372009-05-27 21:36:22 +0200551
Arnaldo Carvalho de Melo52d422d2009-07-10 22:47:28 -0300552print_entries:
Peter Zijlstrae7fb08b2009-05-27 20:20:24 +0200553 for (nd = rb_first(&output_hists); nd; nd = rb_next(nd)) {
554 pos = rb_entry(nd, struct hist_entry, rb_node);
555 ret += hist_entry__fprintf(fp, pos, total_samples);
Arnaldo Carvalho de Melo3a4b8cc2009-05-26 16:19:04 -0300556 }
557
Ingo Molnarb8e6d822009-06-18 14:32:19 +0200558 if (sort_order == default_sort_order &&
559 parent_pattern == default_parent_pattern) {
Ingo Molnarbd741372009-06-04 14:13:04 +0200560 fprintf(fp, "#\n");
Pekka Enberg114cfab2009-08-05 13:25:21 +0300561 fprintf(fp, "# (For a higher level overview, try: perf report --sort comm,dso)\n");
Ingo Molnarbd741372009-06-04 14:13:04 +0200562 fprintf(fp, "#\n");
563 }
Peter Zijlstra71dd8942009-06-04 15:16:56 +0200564 fprintf(fp, "\n");
Ingo Molnarbd741372009-06-04 14:13:04 +0200565
Frederic Weisbecker25446032009-08-08 02:16:25 +0200566 free(rem_sq_bracket);
567
Brice Goglin8d513272009-08-07 13:55:24 +0200568 if (show_threads)
Brice Goglin9f866692009-08-10 15:26:32 +0200569 perf_read_values_display(fp, &show_threads_values,
570 raw_printing_style);
Brice Goglin8d513272009-08-07 13:55:24 +0200571
Arnaldo Carvalho de Melo3a4b8cc2009-05-26 16:19:04 -0300572 return ret;
573}
574
Peter Zijlstra2a0a50f2009-06-18 22:20:45 +0200575static int validate_chain(struct ip_callchain *chain, event_t *event)
Ingo Molnar75220602009-06-18 08:00:17 +0200576{
577 unsigned int chain_size;
578
Ingo Molnar75220602009-06-18 08:00:17 +0200579 chain_size = event->header.size;
580 chain_size -= (unsigned long)&event->ip.__more_data - (unsigned long)event;
581
Paul Mackerras9cffa8d2009-06-19 22:21:42 +1000582 if (chain->nr*sizeof(u64) > chain_size)
Ingo Molnar75220602009-06-18 08:00:17 +0200583 return -1;
584
585 return 0;
586}
587
Ingo Molnard80d3382009-06-03 23:14:49 +0200588static int
Peter Zijlstrae6e18ec2009-06-25 11:27:12 +0200589process_sample_event(event_t *event, unsigned long offset, unsigned long head)
Ingo Molnar75051722009-06-03 23:14:49 +0200590{
591 char level;
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -0300592 struct symbol *sym = NULL;
Paul Mackerras9cffa8d2009-06-19 22:21:42 +1000593 u64 ip = event->ip.ip;
594 u64 period = 1;
Ingo Molnar75051722009-06-03 23:14:49 +0200595 struct map *map = NULL;
Ingo Molnar3efa1cc92009-06-14 15:04:15 +0200596 void *more_data = event->ip.__more_data;
Peter Zijlstra2a0a50f2009-06-18 22:20:45 +0200597 struct ip_callchain *chain = NULL;
Anton Blanchardd8db1b52009-07-01 09:00:48 +1000598 int cpumode;
Arnaldo Carvalho de Melod5b889f2009-10-13 11:16:29 -0300599 struct thread *thread = threads__findnew(event->ip.pid);
Frederic Weisbecker6baa0a52009-08-14 12:21:53 +0200600
Peter Zijlstrae6e18ec2009-06-25 11:27:12 +0200601 if (sample_type & PERF_SAMPLE_PERIOD) {
Paul Mackerras9cffa8d2009-06-19 22:21:42 +1000602 period = *(u64 *)more_data;
603 more_data += sizeof(u64);
Ingo Molnar3efa1cc92009-06-14 15:04:15 +0200604 }
Peter Zijlstraea1900e2009-06-10 21:45:22 +0200605
Ingo Molnarcdd6c482009-09-21 12:02:48 +0200606 dump_printf("%p [%p]: PERF_RECORD_SAMPLE (IP, %d): %d/%d: %p period: %Ld\n",
Ingo Molnar75051722009-06-03 23:14:49 +0200607 (void *)(offset + head),
608 (void *)(long)(event->header.size),
609 event->header.misc,
Arnaldo Carvalho de Melo94a24752009-08-11 16:21:38 -0300610 event->ip.pid, event->ip.tid,
Peter Zijlstra4502d772009-06-10 15:03:06 +0200611 (void *)(long)ip,
Peter Zijlstraea1900e2009-06-10 21:45:22 +0200612 (long long)period);
Ingo Molnar75051722009-06-03 23:14:49 +0200613
Peter Zijlstrae6e18ec2009-06-25 11:27:12 +0200614 if (sample_type & PERF_SAMPLE_CALLCHAIN) {
Ingo Molnarf37a2912009-07-01 12:37:06 +0200615 unsigned int i;
Ingo Molnar3efa1cc92009-06-14 15:04:15 +0200616
617 chain = (void *)more_data;
618
Frederic Weisbecker2cec19d2009-08-16 19:24:21 +0200619 dump_printf("... chain: nr:%Lu\n", chain->nr);
Ingo Molnar3efa1cc92009-06-14 15:04:15 +0200620
Ingo Molnar75220602009-06-18 08:00:17 +0200621 if (validate_chain(chain, event) < 0) {
622 eprintf("call-chain problem with event, skipping it.\n");
623 return 0;
624 }
625
626 if (dump_trace) {
Ingo Molnar3efa1cc92009-06-14 15:04:15 +0200627 for (i = 0; i < chain->nr; i++)
Frederic Weisbecker2cec19d2009-08-16 19:24:21 +0200628 dump_printf("..... %2d: %016Lx\n", i, chain->ips[i]);
Ingo Molnar3efa1cc92009-06-14 15:04:15 +0200629 }
630 }
631
Ingo Molnar75051722009-06-03 23:14:49 +0200632 if (thread == NULL) {
Ingo Molnar75220602009-06-18 08:00:17 +0200633 eprintf("problem processing %d event, skipping it.\n",
Ingo Molnar75051722009-06-03 23:14:49 +0200634 event->header.type);
635 return -1;
636 }
637
Julia Lawallf39cdf22009-10-17 08:43:17 +0200638 dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid);
639
Arnaldo Carvalho de Melocc8b88b2009-06-30 19:01:21 -0300640 if (comm_list && !strlist__has_entry(comm_list, thread->comm))
641 return 0;
642
Ingo Molnarcdd6c482009-09-21 12:02:48 +0200643 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
Anton Blanchardd8db1b52009-07-01 09:00:48 +1000644
Ingo Molnarcdd6c482009-09-21 12:02:48 +0200645 if (cpumode == PERF_RECORD_MISC_KERNEL) {
Ingo Molnar75051722009-06-03 23:14:49 +0200646 level = 'k';
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -0300647 sym = kernel_maps__find_symbol(ip, &map);
648 dump_printf(" ...... dso: %s\n",
649 map ? map->dso->long_name : "<not found>");
Ingo Molnarcdd6c482009-09-21 12:02:48 +0200650 } else if (cpumode == PERF_RECORD_MISC_USER) {
Ingo Molnar75051722009-06-03 23:14:49 +0200651 level = '.';
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -0300652 sym = resolve_symbol(thread, &map, &ip);
Ingo Molnar75051722009-06-03 23:14:49 +0200653
Ingo Molnar75051722009-06-03 23:14:49 +0200654 } else {
Ingo Molnar75051722009-06-03 23:14:49 +0200655 level = 'H';
Frederic Weisbecker2cec19d2009-08-16 19:24:21 +0200656 dump_printf(" ...... dso: [hypervisor]\n");
Ingo Molnar75051722009-06-03 23:14:49 +0200657 }
658
Arnaldo Carvalho de Meloec218fc2009-10-03 20:30:48 -0300659 if (dso_list &&
660 (!map || !map->dso ||
661 !(strlist__has_entry(dso_list, map->dso->short_name) ||
662 (map->dso->short_name != map->dso->long_name &&
663 strlist__has_entry(dso_list, map->dso->long_name)))))
664 return 0;
Arnaldo Carvalho de Melo25903402009-06-30 19:01:20 -0300665
Arnaldo Carvalho de Meloec218fc2009-10-03 20:30:48 -0300666 if (sym_list && sym && !strlist__has_entry(sym_list, sym->name))
667 return 0;
Arnaldo Carvalho de Melo7bec7a92009-06-30 19:01:22 -0300668
Arnaldo Carvalho de Meloec218fc2009-10-03 20:30:48 -0300669 if (hist_entry__add(thread, map, sym, ip,
670 chain, level, period)) {
671 eprintf("problem incrementing symbol count, skipping event\n");
672 return -1;
Ingo Molnar75051722009-06-03 23:14:49 +0200673 }
Arnaldo Carvalho de Meloec218fc2009-10-03 20:30:48 -0300674
Peter Zijlstraea1900e2009-06-10 21:45:22 +0200675 total += period;
Ingo Molnar75051722009-06-03 23:14:49 +0200676
677 return 0;
678}
679
680static int
681process_mmap_event(event_t *event, unsigned long offset, unsigned long head)
682{
Frederic Weisbecker66e274f2009-08-12 11:07:25 +0200683 struct map *map = map__new(&event->mmap, cwd, cwdlen);
Arnaldo Carvalho de Melod5b889f2009-10-13 11:16:29 -0300684 struct thread *thread = threads__findnew(event->mmap.pid);
Frederic Weisbecker6baa0a52009-08-14 12:21:53 +0200685
Ingo Molnarcdd6c482009-09-21 12:02:48 +0200686 dump_printf("%p [%p]: PERF_RECORD_MMAP %d/%d: [%p(%p) @ %p]: %s\n",
Ingo Molnar75051722009-06-03 23:14:49 +0200687 (void *)(offset + head),
688 (void *)(long)(event->header.size),
Peter Zijlstra62fc4452009-06-04 16:53:49 +0200689 event->mmap.pid,
Arnaldo Carvalho de Melo94a24752009-08-11 16:21:38 -0300690 event->mmap.tid,
Ingo Molnar75051722009-06-03 23:14:49 +0200691 (void *)(long)event->mmap.start,
692 (void *)(long)event->mmap.len,
693 (void *)(long)event->mmap.pgoff,
694 event->mmap.filename);
695
696 if (thread == NULL || map == NULL) {
Ingo Molnarcdd6c482009-09-21 12:02:48 +0200697 dump_printf("problem processing PERF_RECORD_MMAP, skipping event.\n");
Ingo Molnardf979922009-06-04 13:41:22 +0200698 return 0;
Ingo Molnar75051722009-06-03 23:14:49 +0200699 }
700
701 thread__insert_map(thread, map);
702 total_mmap++;
703
704 return 0;
705}
706
707static int
708process_comm_event(event_t *event, unsigned long offset, unsigned long head)
709{
Arnaldo Carvalho de Melod5b889f2009-10-13 11:16:29 -0300710 struct thread *thread = threads__findnew(event->comm.pid);
Ingo Molnar75051722009-06-03 23:14:49 +0200711
Ingo Molnarcdd6c482009-09-21 12:02:48 +0200712 dump_printf("%p [%p]: PERF_RECORD_COMM: %s:%d\n",
Ingo Molnar75051722009-06-03 23:14:49 +0200713 (void *)(offset + head),
714 (void *)(long)(event->header.size),
715 event->comm.comm, event->comm.pid);
716
717 if (thread == NULL ||
Frederic Weisbecker4273b002009-08-18 16:03:46 +0200718 thread__set_comm_adjust(thread, event->comm.comm)) {
Ingo Molnarcdd6c482009-09-21 12:02:48 +0200719 dump_printf("problem processing PERF_RECORD_COMM, skipping event.\n");
Ingo Molnar75051722009-06-03 23:14:49 +0200720 return -1;
721 }
722 total_comm++;
723
724 return 0;
725}
726
727static int
Peter Zijlstra27d028d2009-07-23 16:52:41 +0200728process_task_event(event_t *event, unsigned long offset, unsigned long head)
Peter Zijlstra62fc4452009-06-04 16:53:49 +0200729{
Arnaldo Carvalho de Melod5b889f2009-10-13 11:16:29 -0300730 struct thread *thread = threads__findnew(event->fork.pid);
731 struct thread *parent = threads__findnew(event->fork.ppid);
Peter Zijlstra62fc4452009-06-04 16:53:49 +0200732
Ingo Molnarcdd6c482009-09-21 12:02:48 +0200733 dump_printf("%p [%p]: PERF_RECORD_%s: (%d:%d):(%d:%d)\n",
Peter Zijlstra62fc4452009-06-04 16:53:49 +0200734 (void *)(offset + head),
735 (void *)(long)(event->header.size),
Ingo Molnarcdd6c482009-09-21 12:02:48 +0200736 event->header.type == PERF_RECORD_FORK ? "FORK" : "EXIT",
Peter Zijlstra27d028d2009-07-23 16:52:41 +0200737 event->fork.pid, event->fork.tid,
738 event->fork.ppid, event->fork.ptid);
739
740 /*
741 * A thread clone will have the same PID for both
742 * parent and child.
743 */
744 if (thread == parent)
745 return 0;
746
Ingo Molnarcdd6c482009-09-21 12:02:48 +0200747 if (event->header.type == PERF_RECORD_EXIT)
Peter Zijlstra27d028d2009-07-23 16:52:41 +0200748 return 0;
Peter Zijlstra62fc4452009-06-04 16:53:49 +0200749
750 if (!thread || !parent || thread__fork(thread, parent)) {
Ingo Molnarcdd6c482009-09-21 12:02:48 +0200751 dump_printf("problem processing PERF_RECORD_FORK, skipping event.\n");
Peter Zijlstra62fc4452009-06-04 16:53:49 +0200752 return -1;
753 }
754 total_fork++;
755
756 return 0;
757}
758
759static int
Peter Zijlstra9d91a6f2009-06-18 11:40:28 +0200760process_lost_event(event_t *event, unsigned long offset, unsigned long head)
761{
Ingo Molnarcdd6c482009-09-21 12:02:48 +0200762 dump_printf("%p [%p]: PERF_RECORD_LOST: id:%Ld: lost:%Ld\n",
Peter Zijlstra9d91a6f2009-06-18 11:40:28 +0200763 (void *)(offset + head),
764 (void *)(long)(event->header.size),
765 event->lost.id,
766 event->lost.lost);
767
768 total_lost += event->lost.lost;
769
770 return 0;
771}
772
Ingo Molnarb2fef072009-06-05 18:07:51 +0200773static int
Peter Zijlstrae9ea2fd2009-06-24 22:46:04 +0200774process_read_event(event_t *event, unsigned long offset, unsigned long head)
775{
Ingo Molnarcdd6c482009-09-21 12:02:48 +0200776 struct perf_event_attr *attr;
Frederic Weisbecker0d3a5c82009-08-16 20:56:37 +0200777
778 attr = perf_header__find_attr(event->read.id, header);
Peter Zijlstra8f18aec2009-08-06 19:40:28 +0200779
Brice Goglin8d513272009-08-07 13:55:24 +0200780 if (show_threads) {
Ingo Molnar83a09442009-08-15 12:26:57 +0200781 const char *name = attr ? __event_name(attr->type, attr->config)
Brice Goglin8d513272009-08-07 13:55:24 +0200782 : "unknown";
783 perf_read_values_add_value(&show_threads_values,
784 event->read.pid, event->read.tid,
785 event->read.id,
786 name,
787 event->read.value);
788 }
789
Ingo Molnarcdd6c482009-09-21 12:02:48 +0200790 dump_printf("%p [%p]: PERF_RECORD_READ: %d %d %s %Lu\n",
Peter Zijlstrae9ea2fd2009-06-24 22:46:04 +0200791 (void *)(offset + head),
792 (void *)(long)(event->header.size),
793 event->read.pid,
794 event->read.tid,
Peter Zijlstra8f18aec2009-08-06 19:40:28 +0200795 attr ? __event_name(attr->type, attr->config)
796 : "FAIL",
Peter Zijlstrae9ea2fd2009-06-24 22:46:04 +0200797 event->read.value);
798
799 return 0;
800}
801
Frederic Weisbecker016e92f2009-10-07 12:47:31 +0200802static int sample_type_check(u64 type)
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300803{
Frederic Weisbecker016e92f2009-10-07 12:47:31 +0200804 sample_type = type;
Ingo Molnar8465b052009-06-14 14:44:07 +0200805
Frederic Weisbecker016e92f2009-10-07 12:47:31 +0200806 if (!(sample_type & PERF_SAMPLE_CALLCHAIN)) {
807 if (sort__has_parent) {
808 fprintf(stderr, "selected --sort parent, but no"
809 " callchain data. Did you call"
810 " perf record without -g?\n");
811 return -1;
812 }
813 if (callchain) {
814 fprintf(stderr, "selected -g but no callchain data."
815 " Did you call perf record without"
816 " -g?\n");
817 return -1;
818 }
819 } else if (callchain_param.mode != CHAIN_NONE && !callchain) {
820 callchain = 1;
821 if (register_callchain_param(&callchain_param) < 0) {
822 fprintf(stderr, "Can't register callchain"
823 " params\n");
824 return -1;
825 }
Ingo Molnard80d3382009-06-03 23:14:49 +0200826 }
827
828 return 0;
829}
830
Frederic Weisbecker016e92f2009-10-07 12:47:31 +0200831static struct perf_file_handler file_handler = {
832 .process_sample_event = process_sample_event,
833 .process_mmap_event = process_mmap_event,
834 .process_comm_event = process_comm_event,
835 .process_exit_event = process_task_event,
836 .process_fork_event = process_task_event,
837 .process_lost_event = process_lost_event,
838 .process_read_event = process_read_event,
839 .sample_type_check = sample_type_check,
840};
841
842
Ingo Molnard80d3382009-06-03 23:14:49 +0200843static int __cmd_report(void)
844{
Frederic Weisbecker5b447a62009-08-31 06:45:18 +0200845 struct thread *idle;
Frederic Weisbecker016e92f2009-10-07 12:47:31 +0200846 int ret;
Ingo Molnard80d3382009-06-03 23:14:49 +0200847
Arnaldo Carvalho de Melod5b889f2009-10-13 11:16:29 -0300848 idle = register_idle_thread();
Frederic Weisbecker5b447a62009-08-31 06:45:18 +0200849 thread__comm_adjust(idle);
Ingo Molnard80d3382009-06-03 23:14:49 +0200850
Brice Goglin8d513272009-08-07 13:55:24 +0200851 if (show_threads)
852 perf_read_values_init(&show_threads_values);
853
Frederic Weisbecker016e92f2009-10-07 12:47:31 +0200854 register_perf_file_handler(&file_handler);
Ingo Molnard80d3382009-06-03 23:14:49 +0200855
Frederic Weisbecker016e92f2009-10-07 12:47:31 +0200856 ret = mmap_dispatch_perf_file(&header, input_name, force, full_paths,
857 &cwdlen, &cwd);
858 if (ret)
859 return ret;
Ingo Molnar97b07b62009-05-26 18:48:58 +0200860
Frederic Weisbecker2cec19d2009-08-16 19:24:21 +0200861 dump_printf(" IP events: %10ld\n", total);
862 dump_printf(" mmap events: %10ld\n", total_mmap);
863 dump_printf(" comm events: %10ld\n", total_comm);
864 dump_printf(" fork events: %10ld\n", total_fork);
865 dump_printf(" lost events: %10ld\n", total_lost);
Frederic Weisbecker016e92f2009-10-07 12:47:31 +0200866 dump_printf(" unknown events: %10ld\n", file_handler.total_unknown);
Ingo Molnar97b07b62009-05-26 18:48:58 +0200867
Ingo Molnar35029732009-06-03 09:38:58 +0200868 if (dump_trace)
Ingo Molnar97b07b62009-05-26 18:48:58 +0200869 return 0;
Ingo Molnar97b07b62009-05-26 18:48:58 +0200870
Arnaldo Carvalho de Meloda21d1b2009-10-07 10:49:00 -0300871 if (verbose > 3)
Arnaldo Carvalho de Melod5b889f2009-10-13 11:16:29 -0300872 threads__fprintf(stdout);
Arnaldo Carvalho de Melo9ac99542009-06-04 13:54:00 -0300873
Arnaldo Carvalho de Meloda21d1b2009-10-07 10:49:00 -0300874 if (verbose > 2)
Ingo Molnar16f762a2009-05-27 09:10:38 +0200875 dsos__fprintf(stdout);
Ingo Molnar16f762a2009-05-27 09:10:38 +0200876
Peter Zijlstra82292892009-06-03 12:37:36 +0200877 collapse__resort();
Frederic Weisbeckerc20ab372009-07-02 20:14:33 +0200878 output__resort(total);
Peter Zijlstrae7fb08b2009-05-27 20:20:24 +0200879 output__fprintf(stdout, total);
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300880
Brice Goglin8d513272009-08-07 13:55:24 +0200881 if (show_threads)
882 perf_read_values_destroy(&show_threads_values);
883
Frederic Weisbecker016e92f2009-10-07 12:47:31 +0200884 return ret;
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300885}
886
Frederic Weisbecker4eb3e472009-07-02 17:58:21 +0200887static int
888parse_callchain_opt(const struct option *opt __used, const char *arg,
889 int unset __used)
890{
Frederic Weisbeckerc20ab372009-07-02 20:14:33 +0200891 char *tok;
892 char *endptr;
893
Frederic Weisbecker4eb3e472009-07-02 17:58:21 +0200894 callchain = 1;
895
896 if (!arg)
897 return 0;
898
Frederic Weisbeckerc20ab372009-07-02 20:14:33 +0200899 tok = strtok((char *)arg, ",");
900 if (!tok)
901 return -1;
902
903 /* get the output mode */
904 if (!strncmp(tok, "graph", strlen(arg)))
Frederic Weisbecker805d1272009-07-05 07:39:21 +0200905 callchain_param.mode = CHAIN_GRAPH_ABS;
Frederic Weisbecker4eb3e472009-07-02 17:58:21 +0200906
Frederic Weisbeckerc20ab372009-07-02 20:14:33 +0200907 else if (!strncmp(tok, "flat", strlen(arg)))
Frederic Weisbecker805d1272009-07-05 07:39:21 +0200908 callchain_param.mode = CHAIN_FLAT;
909
910 else if (!strncmp(tok, "fractal", strlen(arg)))
911 callchain_param.mode = CHAIN_GRAPH_REL;
912
Frederic Weisbeckerb1a88342009-08-08 02:16:24 +0200913 else if (!strncmp(tok, "none", strlen(arg))) {
914 callchain_param.mode = CHAIN_NONE;
915 callchain = 0;
916
917 return 0;
918 }
919
Frederic Weisbecker4eb3e472009-07-02 17:58:21 +0200920 else
921 return -1;
922
Frederic Weisbeckerc20ab372009-07-02 20:14:33 +0200923 /* get the min percentage */
924 tok = strtok(NULL, ",");
925 if (!tok)
Frederic Weisbecker805d1272009-07-05 07:39:21 +0200926 goto setup;
Frederic Weisbeckerc20ab372009-07-02 20:14:33 +0200927
Frederic Weisbecker805d1272009-07-05 07:39:21 +0200928 callchain_param.min_percent = strtod(tok, &endptr);
Frederic Weisbeckerc20ab372009-07-02 20:14:33 +0200929 if (tok == endptr)
930 return -1;
931
Frederic Weisbecker805d1272009-07-05 07:39:21 +0200932setup:
933 if (register_callchain_param(&callchain_param) < 0) {
934 fprintf(stderr, "Can't register callchain params\n");
935 return -1;
936 }
Frederic Weisbecker4eb3e472009-07-02 17:58:21 +0200937 return 0;
938}
939
John Kacurdd68ada2009-09-24 18:02:49 +0200940//static const char * const report_usage[] = {
941const char * const report_usage[] = {
Ingo Molnar53cb8bc2009-05-26 09:17:18 +0200942 "perf report [<options>] <command>",
943 NULL
944};
945
946static const struct option options[] = {
947 OPT_STRING('i', "input", &input_name, "file",
948 "input file name"),
Arnaldo Carvalho de Melo815e7772009-05-26 19:46:14 -0300949 OPT_BOOLEAN('v', "verbose", &verbose,
950 "be more verbose (show symbol address, etc)"),
Ingo Molnar97b07b62009-05-26 18:48:58 +0200951 OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace,
952 "dump raw trace in ASCII"),
Ingo Molnar83a09442009-08-15 12:26:57 +0200953 OPT_STRING('k', "vmlinux", &vmlinux_name, "file", "vmlinux pathname"),
Peter Zijlstrafa6963b2009-08-19 11:18:26 +0200954 OPT_BOOLEAN('f', "force", &force, "don't complain, do it"),
Mike Galbraith42976482009-07-02 08:09:46 +0200955 OPT_BOOLEAN('m', "modules", &modules,
956 "load module symbols - WARNING: use only with -k and LIVE kernel"),
Arnaldo Carvalho de Meloe3d7e182009-07-11 12:18:37 -0300957 OPT_BOOLEAN('n', "show-nr-samples", &show_nr_samples,
958 "Show a column with the number of samples"),
Brice Goglin8d513272009-08-07 13:55:24 +0200959 OPT_BOOLEAN('T', "threads", &show_threads,
960 "Show per-thread event counters"),
Brice Goglin9f866692009-08-10 15:26:32 +0200961 OPT_STRING(0, "pretty", &pretty_printing_style, "key",
962 "pretty printing style key: normal raw"),
Ingo Molnar63299f02009-05-28 10:52:00 +0200963 OPT_STRING('s', "sort", &sort_order, "key[,key2...]",
Ingo Molnarb25bcf22009-06-18 07:01:03 +0200964 "sort by key(s): pid, comm, dso, symbol, parent"),
Arnaldo Carvalho de Melob78c07d2009-05-29 13:48:59 -0300965 OPT_BOOLEAN('P', "full-paths", &full_paths,
966 "Don't shorten the pathnames taking into account the cwd"),
Ingo Molnarb25bcf22009-06-18 07:01:03 +0200967 OPT_STRING('p', "parent", &parent_pattern, "regex",
968 "regex filter to identify parent, see: '--sort parent'"),
Ingo Molnarb8e6d822009-06-18 14:32:19 +0200969 OPT_BOOLEAN('x', "exclude-other", &exclude_other,
970 "Only display entries with parent-match"),
Anton Blanchard1483b19f2009-07-16 15:44:29 +0200971 OPT_CALLBACK_DEFAULT('g', "call-graph", NULL, "output_type,min_percent",
Frederic Weisbeckerc20ab372009-07-02 20:14:33 +0200972 "Display callchains using output_type and min percent threshold. "
Anton Blanchard1483b19f2009-07-16 15:44:29 +0200973 "Default: fractal,0.5", &parse_callchain_opt, callchain_default_opt),
Arnaldo Carvalho de Melo25903402009-06-30 19:01:20 -0300974 OPT_STRING('d', "dsos", &dso_list_str, "dso[,dso...]",
975 "only consider symbols in these dsos"),
Arnaldo Carvalho de Melocc8b88b2009-06-30 19:01:21 -0300976 OPT_STRING('C', "comms", &comm_list_str, "comm[,comm...]",
977 "only consider symbols in these comms"),
Arnaldo Carvalho de Melo7bec7a92009-06-30 19:01:22 -0300978 OPT_STRING('S', "symbols", &sym_list_str, "symbol[,symbol...]",
979 "only consider these symbols"),
Arnaldo Carvalho de Melo52d422d2009-07-10 22:47:28 -0300980 OPT_STRING('w', "column-widths", &col_width_list_str,
981 "width[,width...]",
982 "don't try to adjust column width, use these fixed values"),
983 OPT_STRING('t', "field-separator", &field_sep, "separator",
984 "separator for columns, no spaces will be added between "
985 "columns '.' is reserved."),
Ingo Molnar53cb8bc2009-05-26 09:17:18 +0200986 OPT_END()
987};
988
Ingo Molnar5352f352009-06-03 10:07:39 +0200989static void setup_sorting(void)
990{
991 char *tmp, *tok, *str = strdup(sort_order);
992
993 for (tok = strtok_r(str, ", ", &tmp);
994 tok; tok = strtok_r(NULL, ", ", &tmp)) {
995 if (sort_dimension__add(tok) < 0) {
996 error("Unknown --sort key: `%s'", tok);
997 usage_with_options(report_usage, options);
998 }
999 }
1000
1001 free(str);
1002}
1003
Arnaldo Carvalho de Melocc8b88b2009-06-30 19:01:21 -03001004static void setup_list(struct strlist **list, const char *list_str,
Arnaldo Carvalho de Melo021191b2009-07-11 12:18:35 -03001005 struct sort_entry *se, const char *list_name,
1006 FILE *fp)
Arnaldo Carvalho de Melocc8b88b2009-06-30 19:01:21 -03001007{
1008 if (list_str) {
1009 *list = strlist__new(true, list_str);
1010 if (!*list) {
1011 fprintf(stderr, "problems parsing %s list\n",
1012 list_name);
1013 exit(129);
1014 }
Arnaldo Carvalho de Melo021191b2009-07-11 12:18:35 -03001015 if (strlist__nr_entries(*list) == 1) {
1016 fprintf(fp, "# %s: %s\n", list_name,
1017 strlist__entry(*list, 0)->s);
1018 se->elide = true;
1019 }
Arnaldo Carvalho de Melocc8b88b2009-06-30 19:01:21 -03001020 }
1021}
1022
Ingo Molnarf37a2912009-07-01 12:37:06 +02001023int cmd_report(int argc, const char **argv, const char *prefix __used)
Ingo Molnar53cb8bc2009-05-26 09:17:18 +02001024{
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -03001025 symbol__init();
Ingo Molnar53cb8bc2009-05-26 09:17:18 +02001026
Ingo Molnaredc52de2009-06-04 16:24:37 +02001027 argc = parse_options(argc, argv, options, report_usage, 0);
Ingo Molnar53cb8bc2009-05-26 09:17:18 +02001028
Peter Zijlstra1aa16732009-05-27 20:20:25 +02001029 setup_sorting();
1030
Arnaldo Carvalho de Melo021191b2009-07-11 12:18:35 -03001031 if (parent_pattern != default_parent_pattern) {
Ingo Molnarb8e6d822009-06-18 14:32:19 +02001032 sort_dimension__add("parent");
Arnaldo Carvalho de Melo021191b2009-07-11 12:18:35 -03001033 sort_parent.elide = 1;
1034 } else
Ingo Molnarb8e6d822009-06-18 14:32:19 +02001035 exclude_other = 0;
1036
Ingo Molnaredc52de2009-06-04 16:24:37 +02001037 /*
1038 * Any (unrecognized) arguments left?
1039 */
1040 if (argc)
1041 usage_with_options(report_usage, options);
1042
Ingo Molnara930d2c2009-05-27 09:50:13 +02001043 setup_pager();
1044
Arnaldo Carvalho de Melo021191b2009-07-11 12:18:35 -03001045 setup_list(&dso_list, dso_list_str, &sort_dso, "dso", stdout);
1046 setup_list(&comm_list, comm_list_str, &sort_comm, "comm", stdout);
1047 setup_list(&sym_list, sym_list_str, &sort_sym, "symbol", stdout);
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -03001048
Arnaldo Carvalho de Melo52d422d2009-07-10 22:47:28 -03001049 if (field_sep && *field_sep == '.') {
1050 fputs("'.' is the only non valid --field-separator argument\n",
1051 stderr);
1052 exit(129);
1053 }
1054
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -03001055 return __cmd_report();
1056}