blob: 3d8c52220f1ff2ec774e9f64b347b38c46ef6262 [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
Frederic Weisbeckeraf0a6fa2009-10-22 23:23:22 +0200125__callchain__fprintf_graph(FILE *fp, struct callchain_node *self,
126 u64 total_samples, int depth, int depth_mask)
Frederic Weisbecker4eb3e472009-07-02 17:58:21 +0200127{
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 Weisbeckeraf0a6fa2009-10-22 23:23:22 +0200177 ret += __callchain__fprintf_graph(fp, child, new_total,
178 depth + 1,
179 new_depth_mask | (1 << depth));
Frederic Weisbecker4eb3e472009-07-02 17:58:21 +0200180 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
Frederic Weisbeckeraf0a6fa2009-10-22 23:23:22 +0200200callchain__fprintf_graph(FILE *fp, struct callchain_node *self,
201 u64 total_samples)
202{
203 struct callchain_list *chain;
204 int i = 0;
205 int ret = 0;
206
207 list_for_each_entry(chain, &self->val, list) {
208 if (chain->ip >= PERF_CONTEXT_MAX)
209 continue;
210
211 if (!i++ && sort_by_sym_first)
212 continue;
213
214 if (chain->sym)
215 ret += fprintf(fp, " %s\n", chain->sym->name);
216 else
217 ret += fprintf(fp, " %p\n",
218 (void *)(long)chain->ip);
219 }
220
221 ret += __callchain__fprintf_graph(fp, self, total_samples, 1, 1);
222
223 return ret;
224}
225
226static size_t
Frederic Weisbecker4eb3e472009-07-02 17:58:21 +0200227callchain__fprintf_flat(FILE *fp, struct callchain_node *self,
228 u64 total_samples)
Frederic Weisbeckerf55c5552009-06-26 16:28:01 +0200229{
230 struct callchain_list *chain;
231 size_t ret = 0;
232
233 if (!self)
234 return 0;
235
Frederic Weisbecker4eb3e472009-07-02 17:58:21 +0200236 ret += callchain__fprintf_flat(fp, self->parent, total_samples);
Frederic Weisbeckerf55c5552009-06-26 16:28:01 +0200237
238
Frederic Weisbecker44249612009-07-01 05:35:14 +0200239 list_for_each_entry(chain, &self->val, list) {
240 if (chain->ip >= PERF_CONTEXT_MAX)
241 continue;
242 if (chain->sym)
243 ret += fprintf(fp, " %s\n", chain->sym->name);
244 else
245 ret += fprintf(fp, " %p\n",
Ingo Molnarf37a2912009-07-01 12:37:06 +0200246 (void *)(long)chain->ip);
Frederic Weisbecker44249612009-07-01 05:35:14 +0200247 }
Frederic Weisbeckerf55c5552009-06-26 16:28:01 +0200248
249 return ret;
250}
251
252static size_t
253hist_entry_callchain__fprintf(FILE *fp, struct hist_entry *self,
254 u64 total_samples)
255{
256 struct rb_node *rb_node;
257 struct callchain_node *chain;
258 size_t ret = 0;
259
260 rb_node = rb_first(&self->sorted_chain);
261 while (rb_node) {
262 double percent;
263
264 chain = rb_entry(rb_node, struct callchain_node, rb_node);
265 percent = chain->hit * 100.0 / total_samples;
Frederic Weisbecker805d1272009-07-05 07:39:21 +0200266 switch (callchain_param.mode) {
267 case CHAIN_FLAT:
Frederic Weisbecker24b57c62009-07-02 20:14:35 +0200268 ret += percent_color_fprintf(fp, " %6.2f%%\n",
269 percent);
Frederic Weisbecker4eb3e472009-07-02 17:58:21 +0200270 ret += callchain__fprintf_flat(fp, chain, total_samples);
Frederic Weisbecker805d1272009-07-05 07:39:21 +0200271 break;
272 case CHAIN_GRAPH_ABS: /* Falldown */
273 case CHAIN_GRAPH_REL:
Frederic Weisbeckeraf0a6fa2009-10-22 23:23:22 +0200274 ret += callchain__fprintf_graph(fp, chain, total_samples);
Ingo Molnar83a09442009-08-15 12:26:57 +0200275 case CHAIN_NONE:
Frederic Weisbecker805d1272009-07-05 07:39:21 +0200276 default:
277 break;
Frederic Weisbecker4eb3e472009-07-02 17:58:21 +0200278 }
Frederic Weisbeckerf55c5552009-06-26 16:28:01 +0200279 ret += fprintf(fp, "\n");
280 rb_node = rb_next(rb_node);
281 }
282
283 return ret;
284}
285
Frederic Weisbeckerf55c5552009-06-26 16:28:01 +0200286static size_t
Paul Mackerras9cffa8d2009-06-19 22:21:42 +1000287hist_entry__fprintf(FILE *fp, struct hist_entry *self, u64 total_samples)
Peter Zijlstra1aa16732009-05-27 20:20:25 +0200288{
289 struct sort_entry *se;
290 size_t ret;
291
Ingo Molnarb8e6d822009-06-18 14:32:19 +0200292 if (exclude_other && !self->parent)
293 return 0;
294
Frederic Weisbecker1e11fd82009-07-02 20:14:34 +0200295 if (total_samples)
Arnaldo Carvalho de Melo52d422d2009-07-10 22:47:28 -0300296 ret = percent_color_fprintf(fp,
297 field_sep ? "%.2f" : " %6.2f%%",
298 (self->count * 100.0) / total_samples);
Frederic Weisbecker1e11fd82009-07-02 20:14:34 +0200299 else
Arnaldo Carvalho de Melo52d422d2009-07-10 22:47:28 -0300300 ret = fprintf(fp, field_sep ? "%lld" : "%12lld ", self->count);
Peter Zijlstra1aa16732009-05-27 20:20:25 +0200301
Arnaldo Carvalho de Meloe3d7e182009-07-11 12:18:37 -0300302 if (show_nr_samples) {
303 if (field_sep)
304 fprintf(fp, "%c%lld", *field_sep, self->count);
305 else
306 fprintf(fp, "%11lld", self->count);
307 }
Peter Zijlstra1aa16732009-05-27 20:20:25 +0200308
Peter Zijlstra71dd8942009-06-04 15:16:56 +0200309 list_for_each_entry(se, &hist_entry__sort_list, list) {
Arnaldo Carvalho de Melo021191b2009-07-11 12:18:35 -0300310 if (se->elide)
Ingo Molnarb8e6d822009-06-18 14:32:19 +0200311 continue;
312
Arnaldo Carvalho de Melo52d422d2009-07-10 22:47:28 -0300313 fprintf(fp, "%s", field_sep ?: " ");
314 ret += se->print(fp, self, se->width ? *se->width : 0);
Peter Zijlstra71dd8942009-06-04 15:16:56 +0200315 }
Peter Zijlstra1aa16732009-05-27 20:20:25 +0200316
317 ret += fprintf(fp, "\n");
318
Frederic Weisbeckerf55c5552009-06-26 16:28:01 +0200319 if (callchain)
320 hist_entry_callchain__fprintf(fp, self, total_samples);
321
Peter Zijlstra1aa16732009-05-27 20:20:25 +0200322 return ret;
323}
324
325/*
Peter Zijlstra6e7d6fd2009-06-17 15:51:44 +0200326 *
327 */
328
Arnaldo Carvalho de Melo52d422d2009-07-10 22:47:28 -0300329static void dso__calc_col_width(struct dso *self)
330{
331 if (!col_width_list_str && !field_sep &&
332 (!dso_list || strlist__has_entry(dso_list, self->name))) {
333 unsigned int slen = strlen(self->name);
334 if (slen > dsos__col_width)
335 dsos__col_width = slen;
336 }
337
338 self->slen_calculated = 1;
339}
340
Frederic Weisbecker5b447a62009-08-31 06:45:18 +0200341static void thread__comm_adjust(struct thread *self)
Frederic Weisbecker4273b002009-08-18 16:03:46 +0200342{
Frederic Weisbecker5b447a62009-08-31 06:45:18 +0200343 char *comm = self->comm;
Frederic Weisbecker4273b002009-08-18 16:03:46 +0200344
345 if (!col_width_list_str && !field_sep &&
346 (!comm_list || strlist__has_entry(comm_list, comm))) {
347 unsigned int slen = strlen(comm);
348
349 if (slen > comms__col_width) {
350 comms__col_width = slen;
351 threads__col_width = slen + 6;
352 }
353 }
Frederic Weisbecker5b447a62009-08-31 06:45:18 +0200354}
355
356static int thread__set_comm_adjust(struct thread *self, const char *comm)
357{
358 int ret = thread__set_comm(self, comm);
359
360 if (ret)
361 return ret;
362
363 thread__comm_adjust(self);
Frederic Weisbecker4273b002009-08-18 16:03:46 +0200364
365 return 0;
366}
367
368
Peter Zijlstra6e7d6fd2009-06-17 15:51:44 +0200369static struct symbol *
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -0300370resolve_symbol(struct thread *thread, struct map **mapp, u64 *ipp)
Peter Zijlstra6e7d6fd2009-06-17 15:51:44 +0200371{
Peter Zijlstra6e7d6fd2009-06-17 15:51:44 +0200372 struct map *map = mapp ? *mapp : NULL;
Peter Zijlstra520f2c32009-06-22 16:52:51 +0200373 u64 ip = *ipp;
Peter Zijlstra6e7d6fd2009-06-17 15:51:44 +0200374
Peter Zijlstra6e7d6fd2009-06-17 15:51:44 +0200375 if (map)
376 goto got_map;
377
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -0300378 if (!thread)
379 return NULL;
380
Peter Zijlstra6e7d6fd2009-06-17 15:51:44 +0200381 map = thread__find_map(thread, ip);
382 if (map != NULL) {
Arnaldo Carvalho de Melo52d422d2009-07-10 22:47:28 -0300383 /*
384 * We have to do this here as we may have a dso
385 * with no symbol hit that has a name longer than
386 * the ones with symbols sampled.
387 */
Arnaldo Carvalho de Melo021191b2009-07-11 12:18:35 -0300388 if (!sort_dso.elide && !map->dso->slen_calculated)
Arnaldo Carvalho de Melo52d422d2009-07-10 22:47:28 -0300389 dso__calc_col_width(map->dso);
390
Peter Zijlstra6e7d6fd2009-06-17 15:51:44 +0200391 if (mapp)
392 *mapp = map;
393got_map:
394 ip = map->map_ip(map, ip);
Peter Zijlstra6e7d6fd2009-06-17 15:51:44 +0200395 } else {
396 /*
397 * If this is outside of all known maps,
398 * and is a negative address, try to look it
399 * up in the kernel dso, as it might be a
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -0300400 * vsyscall or vdso (which executes in user-mode).
401 *
402 * XXX This is nasty, we should have a symbol list in
403 * the "[vdso]" dso, but for now lets use the old
404 * trick of looking in the whole kernel symbol list.
Peter Zijlstra6e7d6fd2009-06-17 15:51:44 +0200405 */
Arnaldo Carvalho de Meloc3b32fc2009-10-05 14:26:16 -0300406 if ((long long)ip < 0)
407 return kernel_maps__find_symbol(ip, mapp);
Peter Zijlstra6e7d6fd2009-06-17 15:51:44 +0200408 }
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -0300409 dump_printf(" ...... dso: %s\n",
410 map ? map->dso->long_name : "<not found>");
Frederic Weisbecker2cec19d2009-08-16 19:24:21 +0200411 dump_printf(" ...... map: %Lx -> %Lx\n", *ipp, ip);
Peter Zijlstra520f2c32009-06-22 16:52:51 +0200412 *ipp = ip;
Peter Zijlstra6e7d6fd2009-06-17 15:51:44 +0200413
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -0300414 return map ? map->dso->find_symbol(map->dso, ip) : NULL;
Peter Zijlstra6e7d6fd2009-06-17 15:51:44 +0200415}
416
Peter Zijlstra2a0a50f2009-06-18 22:20:45 +0200417static int call__match(struct symbol *sym)
Peter Zijlstra6e7d6fd2009-06-17 15:51:44 +0200418{
Ingo Molnarb25bcf22009-06-18 07:01:03 +0200419 if (sym->name && !regexec(&parent_regex, sym->name, 0, NULL, 0))
Peter Zijlstra2a0a50f2009-06-18 22:20:45 +0200420 return 1;
Peter Zijlstra6e7d6fd2009-06-17 15:51:44 +0200421
Peter Zijlstra2a0a50f2009-06-18 22:20:45 +0200422 return 0;
Peter Zijlstra6e7d6fd2009-06-17 15:51:44 +0200423}
424
Arnaldo Carvalho de Melo9735abf2009-10-03 10:42:45 -0300425static struct symbol **resolve_callchain(struct thread *thread, struct map *map,
426 struct ip_callchain *chain,
427 struct symbol **parent)
Frederic Weisbecker44249612009-07-01 05:35:14 +0200428{
Frederic Weisbecker44249612009-07-01 05:35:14 +0200429 u64 context = PERF_CONTEXT_MAX;
Ingo Molnar029e5b12009-07-03 13:17:28 +0200430 struct symbol **syms = NULL;
Ingo Molnarf37a2912009-07-01 12:37:06 +0200431 unsigned int i;
Frederic Weisbecker44249612009-07-01 05:35:14 +0200432
433 if (callchain) {
434 syms = calloc(chain->nr, sizeof(*syms));
435 if (!syms) {
436 fprintf(stderr, "Can't allocate memory for symbols\n");
437 exit(-1);
438 }
439 }
440
441 for (i = 0; i < chain->nr; i++) {
442 u64 ip = chain->ips[i];
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -0300443 struct symbol *sym = NULL;
Frederic Weisbecker44249612009-07-01 05:35:14 +0200444
445 if (ip >= PERF_CONTEXT_MAX) {
446 context = ip;
447 continue;
448 }
449
450 switch (context) {
Ingo Molnar88a69df2009-07-01 11:17:20 +0200451 case PERF_CONTEXT_HV:
Ingo Molnar88a69df2009-07-01 11:17:20 +0200452 break;
Frederic Weisbecker44249612009-07-01 05:35:14 +0200453 case PERF_CONTEXT_KERNEL:
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -0300454 sym = kernel_maps__find_symbol(ip, &map);
Frederic Weisbecker44249612009-07-01 05:35:14 +0200455 break;
456 default:
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -0300457 sym = resolve_symbol(thread, &map, &ip);
Frederic Weisbecker44249612009-07-01 05:35:14 +0200458 break;
459 }
460
Frederic Weisbecker44249612009-07-01 05:35:14 +0200461 if (sym) {
Arnaldo Carvalho de Melo9735abf2009-10-03 10:42:45 -0300462 if (sort__has_parent && !*parent && call__match(sym))
463 *parent = sym;
Frederic Weisbecker44249612009-07-01 05:35:14 +0200464 if (!callchain)
465 break;
466 syms[i] = sym;
467 }
468 }
469
470 return syms;
471}
472
Peter Zijlstra6e7d6fd2009-06-17 15:51:44 +0200473/*
Peter Zijlstra1aa16732009-05-27 20:20:25 +0200474 * collect histogram counts
475 */
476
Peter Zijlstrae7fb08b2009-05-27 20:20:24 +0200477static int
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -0300478hist_entry__add(struct thread *thread, struct map *map,
Paul Mackerras9cffa8d2009-06-19 22:21:42 +1000479 struct symbol *sym, u64 ip, struct ip_callchain *chain,
480 char level, u64 count)
Arnaldo Carvalho de Melo3a4b8cc2009-05-26 16:19:04 -0300481{
Arnaldo Carvalho de Melo9735abf2009-10-03 10:42:45 -0300482 struct symbol **syms = NULL, *parent = NULL;
483 bool hit;
Peter Zijlstrae7fb08b2009-05-27 20:20:24 +0200484 struct hist_entry *he;
Arnaldo Carvalho de Melo3a4b8cc2009-05-26 16:19:04 -0300485
Frederic Weisbecker44249612009-07-01 05:35:14 +0200486 if ((sort__has_parent || callchain) && chain)
Arnaldo Carvalho de Melo9735abf2009-10-03 10:42:45 -0300487 syms = resolve_callchain(thread, map, chain, &parent);
Peter Zijlstra6e7d6fd2009-06-17 15:51:44 +0200488
Arnaldo Carvalho de Melo9735abf2009-10-03 10:42:45 -0300489 he = __hist_entry__add(thread, map, sym, parent,
490 ip, count, level, &hit);
491 if (he == NULL)
Peter Zijlstrae7fb08b2009-05-27 20:20:24 +0200492 return -ENOMEM;
Arnaldo Carvalho de Melo9735abf2009-10-03 10:42:45 -0300493
494 if (hit)
495 he->count += count;
496
Frederic Weisbeckerf55c5552009-06-26 16:28:01 +0200497 if (callchain) {
Arnaldo Carvalho de Melo9735abf2009-10-03 10:42:45 -0300498 if (!hit)
499 callchain_init(&he->callchain);
Frederic Weisbecker44249612009-07-01 05:35:14 +0200500 append_chain(&he->callchain, chain, syms);
501 free(syms);
Frederic Weisbeckerf55c5552009-06-26 16:28:01 +0200502 }
Peter Zijlstrae7fb08b2009-05-27 20:20:24 +0200503
504 return 0;
Arnaldo Carvalho de Melo3a4b8cc2009-05-26 16:19:04 -0300505}
506
Paul Mackerras9cffa8d2009-06-19 22:21:42 +1000507static size_t output__fprintf(FILE *fp, u64 total_samples)
Arnaldo Carvalho de Melo3a4b8cc2009-05-26 16:19:04 -0300508{
Peter Zijlstrae7fb08b2009-05-27 20:20:24 +0200509 struct hist_entry *pos;
Ingo Molnar2d655372009-05-27 21:36:22 +0200510 struct sort_entry *se;
Arnaldo Carvalho de Melo3a4b8cc2009-05-26 16:19:04 -0300511 struct rb_node *nd;
512 size_t ret = 0;
Arnaldo Carvalho de Melo52d422d2009-07-10 22:47:28 -0300513 unsigned int width;
514 char *col_width = col_width_list_str;
Brice Goglin9f866692009-08-10 15:26:32 +0200515 int raw_printing_style;
516
517 raw_printing_style = !strcmp(pretty_printing_style, "raw");
Arnaldo Carvalho de Melo3a4b8cc2009-05-26 16:19:04 -0300518
Frederic Weisbecker25446032009-08-08 02:16:25 +0200519 init_rem_hits();
520
Arnaldo Carvalho de Melo021191b2009-07-11 12:18:35 -0300521 fprintf(fp, "# Samples: %Ld\n", (u64)total_samples);
Ingo Molnar05ca0612009-06-04 14:21:16 +0200522 fprintf(fp, "#\n");
Peter Zijlstraca8cdee2009-05-28 11:08:33 +0200523
524 fprintf(fp, "# Overhead");
Arnaldo Carvalho de Meloe3d7e182009-07-11 12:18:37 -0300525 if (show_nr_samples) {
526 if (field_sep)
527 fprintf(fp, "%cSamples", *field_sep);
528 else
529 fputs(" Samples ", fp);
530 }
Ingo Molnarb8e6d822009-06-18 14:32:19 +0200531 list_for_each_entry(se, &hist_entry__sort_list, list) {
Arnaldo Carvalho de Melo021191b2009-07-11 12:18:35 -0300532 if (se->elide)
Ingo Molnarb8e6d822009-06-18 14:32:19 +0200533 continue;
Arnaldo Carvalho de Melo52d422d2009-07-10 22:47:28 -0300534 if (field_sep) {
535 fprintf(fp, "%c%s", *field_sep, se->header);
536 continue;
537 }
538 width = strlen(se->header);
539 if (se->width) {
540 if (col_width_list_str) {
541 if (col_width) {
542 *se->width = atoi(col_width);
543 col_width = strchr(col_width, ',');
544 if (col_width)
545 ++col_width;
546 }
547 }
548 width = *se->width = max(*se->width, width);
549 }
550 fprintf(fp, " %*s", width, se->header);
Ingo Molnarb8e6d822009-06-18 14:32:19 +0200551 }
Peter Zijlstraca8cdee2009-05-28 11:08:33 +0200552 fprintf(fp, "\n");
553
Arnaldo Carvalho de Melo52d422d2009-07-10 22:47:28 -0300554 if (field_sep)
555 goto print_entries;
556
Peter Zijlstraca8cdee2009-05-28 11:08:33 +0200557 fprintf(fp, "# ........");
Arnaldo Carvalho de Meloe3d7e182009-07-11 12:18:37 -0300558 if (show_nr_samples)
559 fprintf(fp, " ..........");
Ingo Molnar2d655372009-05-27 21:36:22 +0200560 list_for_each_entry(se, &hist_entry__sort_list, list) {
Ingo Molnarf37a2912009-07-01 12:37:06 +0200561 unsigned int i;
Peter Zijlstraca8cdee2009-05-28 11:08:33 +0200562
Arnaldo Carvalho de Melo021191b2009-07-11 12:18:35 -0300563 if (se->elide)
Ingo Molnarb8e6d822009-06-18 14:32:19 +0200564 continue;
565
Ingo Molnar4593bba2009-06-02 15:34:25 +0200566 fprintf(fp, " ");
Arnaldo Carvalho de Melo52d422d2009-07-10 22:47:28 -0300567 if (se->width)
568 width = *se->width;
569 else
570 width = strlen(se->header);
571 for (i = 0; i < width; i++)
Peter Zijlstraca8cdee2009-05-28 11:08:33 +0200572 fprintf(fp, ".");
Ingo Molnar2d655372009-05-27 21:36:22 +0200573 }
Peter Zijlstraca8cdee2009-05-28 11:08:33 +0200574 fprintf(fp, "\n");
575
576 fprintf(fp, "#\n");
Ingo Molnar2d655372009-05-27 21:36:22 +0200577
Arnaldo Carvalho de Melo52d422d2009-07-10 22:47:28 -0300578print_entries:
Peter Zijlstrae7fb08b2009-05-27 20:20:24 +0200579 for (nd = rb_first(&output_hists); nd; nd = rb_next(nd)) {
580 pos = rb_entry(nd, struct hist_entry, rb_node);
581 ret += hist_entry__fprintf(fp, pos, total_samples);
Arnaldo Carvalho de Melo3a4b8cc2009-05-26 16:19:04 -0300582 }
583
Ingo Molnarb8e6d822009-06-18 14:32:19 +0200584 if (sort_order == default_sort_order &&
585 parent_pattern == default_parent_pattern) {
Ingo Molnarbd741372009-06-04 14:13:04 +0200586 fprintf(fp, "#\n");
Pekka Enberg114cfab2009-08-05 13:25:21 +0300587 fprintf(fp, "# (For a higher level overview, try: perf report --sort comm,dso)\n");
Ingo Molnarbd741372009-06-04 14:13:04 +0200588 fprintf(fp, "#\n");
589 }
Peter Zijlstra71dd8942009-06-04 15:16:56 +0200590 fprintf(fp, "\n");
Ingo Molnarbd741372009-06-04 14:13:04 +0200591
Frederic Weisbecker25446032009-08-08 02:16:25 +0200592 free(rem_sq_bracket);
593
Brice Goglin8d513272009-08-07 13:55:24 +0200594 if (show_threads)
Brice Goglin9f866692009-08-10 15:26:32 +0200595 perf_read_values_display(fp, &show_threads_values,
596 raw_printing_style);
Brice Goglin8d513272009-08-07 13:55:24 +0200597
Arnaldo Carvalho de Melo3a4b8cc2009-05-26 16:19:04 -0300598 return ret;
599}
600
Peter Zijlstra2a0a50f2009-06-18 22:20:45 +0200601static int validate_chain(struct ip_callchain *chain, event_t *event)
Ingo Molnar75220602009-06-18 08:00:17 +0200602{
603 unsigned int chain_size;
604
Ingo Molnar75220602009-06-18 08:00:17 +0200605 chain_size = event->header.size;
606 chain_size -= (unsigned long)&event->ip.__more_data - (unsigned long)event;
607
Paul Mackerras9cffa8d2009-06-19 22:21:42 +1000608 if (chain->nr*sizeof(u64) > chain_size)
Ingo Molnar75220602009-06-18 08:00:17 +0200609 return -1;
610
611 return 0;
612}
613
Ingo Molnard80d3382009-06-03 23:14:49 +0200614static int
Peter Zijlstrae6e18ec2009-06-25 11:27:12 +0200615process_sample_event(event_t *event, unsigned long offset, unsigned long head)
Ingo Molnar75051722009-06-03 23:14:49 +0200616{
617 char level;
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -0300618 struct symbol *sym = NULL;
Paul Mackerras9cffa8d2009-06-19 22:21:42 +1000619 u64 ip = event->ip.ip;
620 u64 period = 1;
Ingo Molnar75051722009-06-03 23:14:49 +0200621 struct map *map = NULL;
Ingo Molnar3efa1cc92009-06-14 15:04:15 +0200622 void *more_data = event->ip.__more_data;
Peter Zijlstra2a0a50f2009-06-18 22:20:45 +0200623 struct ip_callchain *chain = NULL;
Anton Blanchardd8db1b52009-07-01 09:00:48 +1000624 int cpumode;
Arnaldo Carvalho de Melod5b889f2009-10-13 11:16:29 -0300625 struct thread *thread = threads__findnew(event->ip.pid);
Frederic Weisbecker6baa0a52009-08-14 12:21:53 +0200626
Peter Zijlstrae6e18ec2009-06-25 11:27:12 +0200627 if (sample_type & PERF_SAMPLE_PERIOD) {
Paul Mackerras9cffa8d2009-06-19 22:21:42 +1000628 period = *(u64 *)more_data;
629 more_data += sizeof(u64);
Ingo Molnar3efa1cc92009-06-14 15:04:15 +0200630 }
Peter Zijlstraea1900e2009-06-10 21:45:22 +0200631
Ingo Molnarcdd6c482009-09-21 12:02:48 +0200632 dump_printf("%p [%p]: PERF_RECORD_SAMPLE (IP, %d): %d/%d: %p period: %Ld\n",
Ingo Molnar75051722009-06-03 23:14:49 +0200633 (void *)(offset + head),
634 (void *)(long)(event->header.size),
635 event->header.misc,
Arnaldo Carvalho de Melo94a24752009-08-11 16:21:38 -0300636 event->ip.pid, event->ip.tid,
Peter Zijlstra4502d772009-06-10 15:03:06 +0200637 (void *)(long)ip,
Peter Zijlstraea1900e2009-06-10 21:45:22 +0200638 (long long)period);
Ingo Molnar75051722009-06-03 23:14:49 +0200639
Peter Zijlstrae6e18ec2009-06-25 11:27:12 +0200640 if (sample_type & PERF_SAMPLE_CALLCHAIN) {
Ingo Molnarf37a2912009-07-01 12:37:06 +0200641 unsigned int i;
Ingo Molnar3efa1cc92009-06-14 15:04:15 +0200642
643 chain = (void *)more_data;
644
Frederic Weisbecker2cec19d2009-08-16 19:24:21 +0200645 dump_printf("... chain: nr:%Lu\n", chain->nr);
Ingo Molnar3efa1cc92009-06-14 15:04:15 +0200646
Ingo Molnar75220602009-06-18 08:00:17 +0200647 if (validate_chain(chain, event) < 0) {
648 eprintf("call-chain problem with event, skipping it.\n");
649 return 0;
650 }
651
652 if (dump_trace) {
Ingo Molnar3efa1cc92009-06-14 15:04:15 +0200653 for (i = 0; i < chain->nr; i++)
Frederic Weisbecker2cec19d2009-08-16 19:24:21 +0200654 dump_printf("..... %2d: %016Lx\n", i, chain->ips[i]);
Ingo Molnar3efa1cc92009-06-14 15:04:15 +0200655 }
656 }
657
Ingo Molnar75051722009-06-03 23:14:49 +0200658 if (thread == NULL) {
Ingo Molnar75220602009-06-18 08:00:17 +0200659 eprintf("problem processing %d event, skipping it.\n",
Ingo Molnar75051722009-06-03 23:14:49 +0200660 event->header.type);
661 return -1;
662 }
663
Julia Lawallf39cdf22009-10-17 08:43:17 +0200664 dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid);
665
Arnaldo Carvalho de Melocc8b88b2009-06-30 19:01:21 -0300666 if (comm_list && !strlist__has_entry(comm_list, thread->comm))
667 return 0;
668
Ingo Molnarcdd6c482009-09-21 12:02:48 +0200669 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
Anton Blanchardd8db1b52009-07-01 09:00:48 +1000670
Ingo Molnarcdd6c482009-09-21 12:02:48 +0200671 if (cpumode == PERF_RECORD_MISC_KERNEL) {
Ingo Molnar75051722009-06-03 23:14:49 +0200672 level = 'k';
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -0300673 sym = kernel_maps__find_symbol(ip, &map);
674 dump_printf(" ...... dso: %s\n",
675 map ? map->dso->long_name : "<not found>");
Ingo Molnarcdd6c482009-09-21 12:02:48 +0200676 } else if (cpumode == PERF_RECORD_MISC_USER) {
Ingo Molnar75051722009-06-03 23:14:49 +0200677 level = '.';
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -0300678 sym = resolve_symbol(thread, &map, &ip);
Ingo Molnar75051722009-06-03 23:14:49 +0200679
Ingo Molnar75051722009-06-03 23:14:49 +0200680 } else {
Ingo Molnar75051722009-06-03 23:14:49 +0200681 level = 'H';
Frederic Weisbecker2cec19d2009-08-16 19:24:21 +0200682 dump_printf(" ...... dso: [hypervisor]\n");
Ingo Molnar75051722009-06-03 23:14:49 +0200683 }
684
Arnaldo Carvalho de Meloec218fc2009-10-03 20:30:48 -0300685 if (dso_list &&
686 (!map || !map->dso ||
687 !(strlist__has_entry(dso_list, map->dso->short_name) ||
688 (map->dso->short_name != map->dso->long_name &&
689 strlist__has_entry(dso_list, map->dso->long_name)))))
690 return 0;
Arnaldo Carvalho de Melo25903402009-06-30 19:01:20 -0300691
Arnaldo Carvalho de Meloec218fc2009-10-03 20:30:48 -0300692 if (sym_list && sym && !strlist__has_entry(sym_list, sym->name))
693 return 0;
Arnaldo Carvalho de Melo7bec7a92009-06-30 19:01:22 -0300694
Arnaldo Carvalho de Meloec218fc2009-10-03 20:30:48 -0300695 if (hist_entry__add(thread, map, sym, ip,
696 chain, level, period)) {
697 eprintf("problem incrementing symbol count, skipping event\n");
698 return -1;
Ingo Molnar75051722009-06-03 23:14:49 +0200699 }
Arnaldo Carvalho de Meloec218fc2009-10-03 20:30:48 -0300700
Peter Zijlstraea1900e2009-06-10 21:45:22 +0200701 total += period;
Ingo Molnar75051722009-06-03 23:14:49 +0200702
703 return 0;
704}
705
706static int
707process_mmap_event(event_t *event, unsigned long offset, unsigned long head)
708{
Arnaldo Carvalho de Meloe4204992009-10-20 14:25:40 -0200709 struct map *map = map__new(&event->mmap, cwd, cwdlen, 0, NULL, verbose);
Arnaldo Carvalho de Melod5b889f2009-10-13 11:16:29 -0300710 struct thread *thread = threads__findnew(event->mmap.pid);
Frederic Weisbecker6baa0a52009-08-14 12:21:53 +0200711
Ingo Molnarcdd6c482009-09-21 12:02:48 +0200712 dump_printf("%p [%p]: PERF_RECORD_MMAP %d/%d: [%p(%p) @ %p]: %s\n",
Ingo Molnar75051722009-06-03 23:14:49 +0200713 (void *)(offset + head),
714 (void *)(long)(event->header.size),
Peter Zijlstra62fc4452009-06-04 16:53:49 +0200715 event->mmap.pid,
Arnaldo Carvalho de Melo94a24752009-08-11 16:21:38 -0300716 event->mmap.tid,
Ingo Molnar75051722009-06-03 23:14:49 +0200717 (void *)(long)event->mmap.start,
718 (void *)(long)event->mmap.len,
719 (void *)(long)event->mmap.pgoff,
720 event->mmap.filename);
721
722 if (thread == NULL || map == NULL) {
Ingo Molnarcdd6c482009-09-21 12:02:48 +0200723 dump_printf("problem processing PERF_RECORD_MMAP, skipping event.\n");
Ingo Molnardf979922009-06-04 13:41:22 +0200724 return 0;
Ingo Molnar75051722009-06-03 23:14:49 +0200725 }
726
727 thread__insert_map(thread, map);
728 total_mmap++;
729
730 return 0;
731}
732
733static int
734process_comm_event(event_t *event, unsigned long offset, unsigned long head)
735{
Arnaldo Carvalho de Melod5b889f2009-10-13 11:16:29 -0300736 struct thread *thread = threads__findnew(event->comm.pid);
Ingo Molnar75051722009-06-03 23:14:49 +0200737
Ingo Molnarcdd6c482009-09-21 12:02:48 +0200738 dump_printf("%p [%p]: PERF_RECORD_COMM: %s:%d\n",
Ingo Molnar75051722009-06-03 23:14:49 +0200739 (void *)(offset + head),
740 (void *)(long)(event->header.size),
741 event->comm.comm, event->comm.pid);
742
743 if (thread == NULL ||
Frederic Weisbecker4273b002009-08-18 16:03:46 +0200744 thread__set_comm_adjust(thread, event->comm.comm)) {
Ingo Molnarcdd6c482009-09-21 12:02:48 +0200745 dump_printf("problem processing PERF_RECORD_COMM, skipping event.\n");
Ingo Molnar75051722009-06-03 23:14:49 +0200746 return -1;
747 }
748 total_comm++;
749
750 return 0;
751}
752
753static int
Peter Zijlstra27d028d2009-07-23 16:52:41 +0200754process_task_event(event_t *event, unsigned long offset, unsigned long head)
Peter Zijlstra62fc4452009-06-04 16:53:49 +0200755{
Arnaldo Carvalho de Melod5b889f2009-10-13 11:16:29 -0300756 struct thread *thread = threads__findnew(event->fork.pid);
757 struct thread *parent = threads__findnew(event->fork.ppid);
Peter Zijlstra62fc4452009-06-04 16:53:49 +0200758
Ingo Molnarcdd6c482009-09-21 12:02:48 +0200759 dump_printf("%p [%p]: PERF_RECORD_%s: (%d:%d):(%d:%d)\n",
Peter Zijlstra62fc4452009-06-04 16:53:49 +0200760 (void *)(offset + head),
761 (void *)(long)(event->header.size),
Ingo Molnarcdd6c482009-09-21 12:02:48 +0200762 event->header.type == PERF_RECORD_FORK ? "FORK" : "EXIT",
Peter Zijlstra27d028d2009-07-23 16:52:41 +0200763 event->fork.pid, event->fork.tid,
764 event->fork.ppid, event->fork.ptid);
765
766 /*
767 * A thread clone will have the same PID for both
768 * parent and child.
769 */
770 if (thread == parent)
771 return 0;
772
Ingo Molnarcdd6c482009-09-21 12:02:48 +0200773 if (event->header.type == PERF_RECORD_EXIT)
Peter Zijlstra27d028d2009-07-23 16:52:41 +0200774 return 0;
Peter Zijlstra62fc4452009-06-04 16:53:49 +0200775
776 if (!thread || !parent || thread__fork(thread, parent)) {
Ingo Molnarcdd6c482009-09-21 12:02:48 +0200777 dump_printf("problem processing PERF_RECORD_FORK, skipping event.\n");
Peter Zijlstra62fc4452009-06-04 16:53:49 +0200778 return -1;
779 }
780 total_fork++;
781
782 return 0;
783}
784
785static int
Peter Zijlstra9d91a6f2009-06-18 11:40:28 +0200786process_lost_event(event_t *event, unsigned long offset, unsigned long head)
787{
Ingo Molnarcdd6c482009-09-21 12:02:48 +0200788 dump_printf("%p [%p]: PERF_RECORD_LOST: id:%Ld: lost:%Ld\n",
Peter Zijlstra9d91a6f2009-06-18 11:40:28 +0200789 (void *)(offset + head),
790 (void *)(long)(event->header.size),
791 event->lost.id,
792 event->lost.lost);
793
794 total_lost += event->lost.lost;
795
796 return 0;
797}
798
Ingo Molnarb2fef072009-06-05 18:07:51 +0200799static int
Peter Zijlstrae9ea2fd2009-06-24 22:46:04 +0200800process_read_event(event_t *event, unsigned long offset, unsigned long head)
801{
Ingo Molnarcdd6c482009-09-21 12:02:48 +0200802 struct perf_event_attr *attr;
Frederic Weisbecker0d3a5c82009-08-16 20:56:37 +0200803
804 attr = perf_header__find_attr(event->read.id, header);
Peter Zijlstra8f18aec2009-08-06 19:40:28 +0200805
Brice Goglin8d513272009-08-07 13:55:24 +0200806 if (show_threads) {
Ingo Molnar83a09442009-08-15 12:26:57 +0200807 const char *name = attr ? __event_name(attr->type, attr->config)
Brice Goglin8d513272009-08-07 13:55:24 +0200808 : "unknown";
809 perf_read_values_add_value(&show_threads_values,
810 event->read.pid, event->read.tid,
811 event->read.id,
812 name,
813 event->read.value);
814 }
815
Ingo Molnarcdd6c482009-09-21 12:02:48 +0200816 dump_printf("%p [%p]: PERF_RECORD_READ: %d %d %s %Lu\n",
Peter Zijlstrae9ea2fd2009-06-24 22:46:04 +0200817 (void *)(offset + head),
818 (void *)(long)(event->header.size),
819 event->read.pid,
820 event->read.tid,
Peter Zijlstra8f18aec2009-08-06 19:40:28 +0200821 attr ? __event_name(attr->type, attr->config)
822 : "FAIL",
Peter Zijlstrae9ea2fd2009-06-24 22:46:04 +0200823 event->read.value);
824
825 return 0;
826}
827
Frederic Weisbecker016e92f2009-10-07 12:47:31 +0200828static int sample_type_check(u64 type)
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300829{
Frederic Weisbecker016e92f2009-10-07 12:47:31 +0200830 sample_type = type;
Ingo Molnar8465b052009-06-14 14:44:07 +0200831
Frederic Weisbecker016e92f2009-10-07 12:47:31 +0200832 if (!(sample_type & PERF_SAMPLE_CALLCHAIN)) {
833 if (sort__has_parent) {
834 fprintf(stderr, "selected --sort parent, but no"
835 " callchain data. Did you call"
836 " perf record without -g?\n");
837 return -1;
838 }
839 if (callchain) {
840 fprintf(stderr, "selected -g but no callchain data."
841 " Did you call perf record without"
842 " -g?\n");
843 return -1;
844 }
845 } else if (callchain_param.mode != CHAIN_NONE && !callchain) {
846 callchain = 1;
847 if (register_callchain_param(&callchain_param) < 0) {
848 fprintf(stderr, "Can't register callchain"
849 " params\n");
850 return -1;
851 }
Ingo Molnard80d3382009-06-03 23:14:49 +0200852 }
853
854 return 0;
855}
856
Frederic Weisbecker016e92f2009-10-07 12:47:31 +0200857static struct perf_file_handler file_handler = {
858 .process_sample_event = process_sample_event,
859 .process_mmap_event = process_mmap_event,
860 .process_comm_event = process_comm_event,
861 .process_exit_event = process_task_event,
862 .process_fork_event = process_task_event,
863 .process_lost_event = process_lost_event,
864 .process_read_event = process_read_event,
865 .sample_type_check = sample_type_check,
866};
867
868
Ingo Molnard80d3382009-06-03 23:14:49 +0200869static int __cmd_report(void)
870{
Frederic Weisbecker5b447a62009-08-31 06:45:18 +0200871 struct thread *idle;
Frederic Weisbecker016e92f2009-10-07 12:47:31 +0200872 int ret;
Ingo Molnard80d3382009-06-03 23:14:49 +0200873
Arnaldo Carvalho de Melod5b889f2009-10-13 11:16:29 -0300874 idle = register_idle_thread();
Frederic Weisbecker5b447a62009-08-31 06:45:18 +0200875 thread__comm_adjust(idle);
Ingo Molnard80d3382009-06-03 23:14:49 +0200876
Brice Goglin8d513272009-08-07 13:55:24 +0200877 if (show_threads)
878 perf_read_values_init(&show_threads_values);
879
Frederic Weisbecker016e92f2009-10-07 12:47:31 +0200880 register_perf_file_handler(&file_handler);
Ingo Molnard80d3382009-06-03 23:14:49 +0200881
Frederic Weisbecker016e92f2009-10-07 12:47:31 +0200882 ret = mmap_dispatch_perf_file(&header, input_name, force, full_paths,
883 &cwdlen, &cwd);
884 if (ret)
885 return ret;
Ingo Molnar97b07b62009-05-26 18:48:58 +0200886
Frederic Weisbecker2cec19d2009-08-16 19:24:21 +0200887 dump_printf(" IP events: %10ld\n", total);
888 dump_printf(" mmap events: %10ld\n", total_mmap);
889 dump_printf(" comm events: %10ld\n", total_comm);
890 dump_printf(" fork events: %10ld\n", total_fork);
891 dump_printf(" lost events: %10ld\n", total_lost);
Frederic Weisbecker016e92f2009-10-07 12:47:31 +0200892 dump_printf(" unknown events: %10ld\n", file_handler.total_unknown);
Ingo Molnar97b07b62009-05-26 18:48:58 +0200893
Ingo Molnar35029732009-06-03 09:38:58 +0200894 if (dump_trace)
Ingo Molnar97b07b62009-05-26 18:48:58 +0200895 return 0;
Ingo Molnar97b07b62009-05-26 18:48:58 +0200896
Arnaldo Carvalho de Meloda21d1b2009-10-07 10:49:00 -0300897 if (verbose > 3)
Arnaldo Carvalho de Melod5b889f2009-10-13 11:16:29 -0300898 threads__fprintf(stdout);
Arnaldo Carvalho de Melo9ac99542009-06-04 13:54:00 -0300899
Arnaldo Carvalho de Meloda21d1b2009-10-07 10:49:00 -0300900 if (verbose > 2)
Ingo Molnar16f762a2009-05-27 09:10:38 +0200901 dsos__fprintf(stdout);
Ingo Molnar16f762a2009-05-27 09:10:38 +0200902
Peter Zijlstra82292892009-06-03 12:37:36 +0200903 collapse__resort();
Frederic Weisbeckerc20ab372009-07-02 20:14:33 +0200904 output__resort(total);
Peter Zijlstrae7fb08b2009-05-27 20:20:24 +0200905 output__fprintf(stdout, total);
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300906
Brice Goglin8d513272009-08-07 13:55:24 +0200907 if (show_threads)
908 perf_read_values_destroy(&show_threads_values);
909
Frederic Weisbecker016e92f2009-10-07 12:47:31 +0200910 return ret;
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -0300911}
912
Frederic Weisbecker4eb3e472009-07-02 17:58:21 +0200913static int
914parse_callchain_opt(const struct option *opt __used, const char *arg,
915 int unset __used)
916{
Frederic Weisbeckerc20ab372009-07-02 20:14:33 +0200917 char *tok;
918 char *endptr;
919
Frederic Weisbecker4eb3e472009-07-02 17:58:21 +0200920 callchain = 1;
921
922 if (!arg)
923 return 0;
924
Frederic Weisbeckerc20ab372009-07-02 20:14:33 +0200925 tok = strtok((char *)arg, ",");
926 if (!tok)
927 return -1;
928
929 /* get the output mode */
930 if (!strncmp(tok, "graph", strlen(arg)))
Frederic Weisbecker805d1272009-07-05 07:39:21 +0200931 callchain_param.mode = CHAIN_GRAPH_ABS;
Frederic Weisbecker4eb3e472009-07-02 17:58:21 +0200932
Frederic Weisbeckerc20ab372009-07-02 20:14:33 +0200933 else if (!strncmp(tok, "flat", strlen(arg)))
Frederic Weisbecker805d1272009-07-05 07:39:21 +0200934 callchain_param.mode = CHAIN_FLAT;
935
936 else if (!strncmp(tok, "fractal", strlen(arg)))
937 callchain_param.mode = CHAIN_GRAPH_REL;
938
Frederic Weisbeckerb1a88342009-08-08 02:16:24 +0200939 else if (!strncmp(tok, "none", strlen(arg))) {
940 callchain_param.mode = CHAIN_NONE;
941 callchain = 0;
942
943 return 0;
944 }
945
Frederic Weisbecker4eb3e472009-07-02 17:58:21 +0200946 else
947 return -1;
948
Frederic Weisbeckerc20ab372009-07-02 20:14:33 +0200949 /* get the min percentage */
950 tok = strtok(NULL, ",");
951 if (!tok)
Frederic Weisbecker805d1272009-07-05 07:39:21 +0200952 goto setup;
Frederic Weisbeckerc20ab372009-07-02 20:14:33 +0200953
Frederic Weisbecker805d1272009-07-05 07:39:21 +0200954 callchain_param.min_percent = strtod(tok, &endptr);
Frederic Weisbeckerc20ab372009-07-02 20:14:33 +0200955 if (tok == endptr)
956 return -1;
957
Frederic Weisbecker805d1272009-07-05 07:39:21 +0200958setup:
959 if (register_callchain_param(&callchain_param) < 0) {
960 fprintf(stderr, "Can't register callchain params\n");
961 return -1;
962 }
Frederic Weisbecker4eb3e472009-07-02 17:58:21 +0200963 return 0;
964}
965
John Kacurdd68ada2009-09-24 18:02:49 +0200966//static const char * const report_usage[] = {
967const char * const report_usage[] = {
Ingo Molnar53cb8bc2009-05-26 09:17:18 +0200968 "perf report [<options>] <command>",
969 NULL
970};
971
972static const struct option options[] = {
973 OPT_STRING('i', "input", &input_name, "file",
974 "input file name"),
Arnaldo Carvalho de Melo815e7772009-05-26 19:46:14 -0300975 OPT_BOOLEAN('v', "verbose", &verbose,
976 "be more verbose (show symbol address, etc)"),
Ingo Molnar97b07b62009-05-26 18:48:58 +0200977 OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace,
978 "dump raw trace in ASCII"),
Ingo Molnar83a09442009-08-15 12:26:57 +0200979 OPT_STRING('k', "vmlinux", &vmlinux_name, "file", "vmlinux pathname"),
Peter Zijlstrafa6963b2009-08-19 11:18:26 +0200980 OPT_BOOLEAN('f', "force", &force, "don't complain, do it"),
Mike Galbraith42976482009-07-02 08:09:46 +0200981 OPT_BOOLEAN('m', "modules", &modules,
982 "load module symbols - WARNING: use only with -k and LIVE kernel"),
Arnaldo Carvalho de Meloe3d7e182009-07-11 12:18:37 -0300983 OPT_BOOLEAN('n', "show-nr-samples", &show_nr_samples,
984 "Show a column with the number of samples"),
Brice Goglin8d513272009-08-07 13:55:24 +0200985 OPT_BOOLEAN('T', "threads", &show_threads,
986 "Show per-thread event counters"),
Brice Goglin9f866692009-08-10 15:26:32 +0200987 OPT_STRING(0, "pretty", &pretty_printing_style, "key",
988 "pretty printing style key: normal raw"),
Ingo Molnar63299f02009-05-28 10:52:00 +0200989 OPT_STRING('s', "sort", &sort_order, "key[,key2...]",
Ingo Molnarb25bcf22009-06-18 07:01:03 +0200990 "sort by key(s): pid, comm, dso, symbol, parent"),
Arnaldo Carvalho de Melob78c07d2009-05-29 13:48:59 -0300991 OPT_BOOLEAN('P', "full-paths", &full_paths,
992 "Don't shorten the pathnames taking into account the cwd"),
Ingo Molnarb25bcf22009-06-18 07:01:03 +0200993 OPT_STRING('p', "parent", &parent_pattern, "regex",
994 "regex filter to identify parent, see: '--sort parent'"),
Ingo Molnarb8e6d822009-06-18 14:32:19 +0200995 OPT_BOOLEAN('x', "exclude-other", &exclude_other,
996 "Only display entries with parent-match"),
Anton Blanchard1483b19f2009-07-16 15:44:29 +0200997 OPT_CALLBACK_DEFAULT('g', "call-graph", NULL, "output_type,min_percent",
Frederic Weisbeckerc20ab372009-07-02 20:14:33 +0200998 "Display callchains using output_type and min percent threshold. "
Anton Blanchard1483b19f2009-07-16 15:44:29 +0200999 "Default: fractal,0.5", &parse_callchain_opt, callchain_default_opt),
Arnaldo Carvalho de Melo25903402009-06-30 19:01:20 -03001000 OPT_STRING('d', "dsos", &dso_list_str, "dso[,dso...]",
1001 "only consider symbols in these dsos"),
Arnaldo Carvalho de Melocc8b88b2009-06-30 19:01:21 -03001002 OPT_STRING('C', "comms", &comm_list_str, "comm[,comm...]",
1003 "only consider symbols in these comms"),
Arnaldo Carvalho de Melo7bec7a92009-06-30 19:01:22 -03001004 OPT_STRING('S', "symbols", &sym_list_str, "symbol[,symbol...]",
1005 "only consider these symbols"),
Arnaldo Carvalho de Melo52d422d2009-07-10 22:47:28 -03001006 OPT_STRING('w', "column-widths", &col_width_list_str,
1007 "width[,width...]",
1008 "don't try to adjust column width, use these fixed values"),
1009 OPT_STRING('t', "field-separator", &field_sep, "separator",
1010 "separator for columns, no spaces will be added between "
1011 "columns '.' is reserved."),
Ingo Molnar53cb8bc2009-05-26 09:17:18 +02001012 OPT_END()
1013};
1014
Ingo Molnar5352f352009-06-03 10:07:39 +02001015static void setup_sorting(void)
1016{
1017 char *tmp, *tok, *str = strdup(sort_order);
1018
1019 for (tok = strtok_r(str, ", ", &tmp);
1020 tok; tok = strtok_r(NULL, ", ", &tmp)) {
1021 if (sort_dimension__add(tok) < 0) {
1022 error("Unknown --sort key: `%s'", tok);
1023 usage_with_options(report_usage, options);
1024 }
1025 }
1026
1027 free(str);
1028}
1029
Arnaldo Carvalho de Melocc8b88b2009-06-30 19:01:21 -03001030static void setup_list(struct strlist **list, const char *list_str,
Arnaldo Carvalho de Melo021191b2009-07-11 12:18:35 -03001031 struct sort_entry *se, const char *list_name,
1032 FILE *fp)
Arnaldo Carvalho de Melocc8b88b2009-06-30 19:01:21 -03001033{
1034 if (list_str) {
1035 *list = strlist__new(true, list_str);
1036 if (!*list) {
1037 fprintf(stderr, "problems parsing %s list\n",
1038 list_name);
1039 exit(129);
1040 }
Arnaldo Carvalho de Melo021191b2009-07-11 12:18:35 -03001041 if (strlist__nr_entries(*list) == 1) {
1042 fprintf(fp, "# %s: %s\n", list_name,
1043 strlist__entry(*list, 0)->s);
1044 se->elide = true;
1045 }
Arnaldo Carvalho de Melocc8b88b2009-06-30 19:01:21 -03001046 }
1047}
1048
Ingo Molnarf37a2912009-07-01 12:37:06 +02001049int cmd_report(int argc, const char **argv, const char *prefix __used)
Ingo Molnar53cb8bc2009-05-26 09:17:18 +02001050{
Arnaldo Carvalho de Meloa2928c42009-05-28 14:55:04 -03001051 symbol__init();
Ingo Molnar53cb8bc2009-05-26 09:17:18 +02001052
Ingo Molnaredc52de2009-06-04 16:24:37 +02001053 argc = parse_options(argc, argv, options, report_usage, 0);
Ingo Molnar53cb8bc2009-05-26 09:17:18 +02001054
Peter Zijlstra1aa16732009-05-27 20:20:25 +02001055 setup_sorting();
1056
Arnaldo Carvalho de Melo021191b2009-07-11 12:18:35 -03001057 if (parent_pattern != default_parent_pattern) {
Ingo Molnarb8e6d822009-06-18 14:32:19 +02001058 sort_dimension__add("parent");
Arnaldo Carvalho de Melo021191b2009-07-11 12:18:35 -03001059 sort_parent.elide = 1;
1060 } else
Ingo Molnarb8e6d822009-06-18 14:32:19 +02001061 exclude_other = 0;
1062
Ingo Molnaredc52de2009-06-04 16:24:37 +02001063 /*
1064 * Any (unrecognized) arguments left?
1065 */
1066 if (argc)
1067 usage_with_options(report_usage, options);
1068
Ingo Molnara930d2c2009-05-27 09:50:13 +02001069 setup_pager();
1070
Arnaldo Carvalho de Melo021191b2009-07-11 12:18:35 -03001071 setup_list(&dso_list, dso_list_str, &sort_dso, "dso", stdout);
1072 setup_list(&comm_list, comm_list_str, &sort_comm, "comm", stdout);
1073 setup_list(&sym_list, sym_list_str, &sort_sym, "symbol", stdout);
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -03001074
Arnaldo Carvalho de Melo52d422d2009-07-10 22:47:28 -03001075 if (field_sep && *field_sep == '.') {
1076 fputs("'.' is the only non valid --field-separator argument\n",
1077 stderr);
1078 exit(129);
1079 }
1080
Arnaldo Carvalho de Melo8fa66bd2009-05-18 12:45:42 -03001081 return __cmd_report();
1082}