aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf/builtin-report.c
diff options
context:
space:
mode:
authorArnaldo Carvalho de Melo <acme@redhat.com>2009-12-16 09:27:09 -0500
committerIngo Molnar <mingo@elte.hu>2009-12-16 10:51:50 -0500
commit4ecf84d086fbeca5a622e971fff013b291dbde86 (patch)
treeea482bdd8006c0318d2236737c5868af859c2179 /tools/perf/builtin-report.c
parentd599db3fc5dd4f1e8432fdbc6d899584b25f4dff (diff)
perf tools: Move hist entries printing routines from perf report
Will be used in other tools such as 'perf diff'. Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com> Cc: Frédéric Weisbecker <fweisbec@gmail.com> Cc: Mike Galbraith <efault@gmx.de> Cc: Peter Zijlstra <a.p.zijlstra@chello.nl> Cc: Paul Mackerras <paulus@samba.org> LKML-Reference: <1260973631-28035-1-git-send-email-acme@infradead.org> Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'tools/perf/builtin-report.c')
-rw-r--r--tools/perf/builtin-report.c397
1 files changed, 0 insertions, 397 deletions
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
index 26f4de6d9a51..24d20e7d125a 100644
--- a/tools/perf/builtin-report.c
+++ b/tools/perf/builtin-report.c
@@ -43,316 +43,6 @@ static char *pretty_printing_style = default_pretty_printing_style;
43 43
44static char callchain_default_opt[] = "fractal,0.5"; 44static char callchain_default_opt[] = "fractal,0.5";
45 45
46static size_t
47callchain__fprintf_left_margin(FILE *fp, int left_margin)
48{
49 int i;
50 int ret;
51
52 ret = fprintf(fp, " ");
53
54 for (i = 0; i < left_margin; i++)
55 ret += fprintf(fp, " ");
56
57 return ret;
58}
59
60static size_t ipchain__fprintf_graph_line(FILE *fp, int depth, int depth_mask,
61 int left_margin)
62{
63 int i;
64 size_t ret = 0;
65
66 ret += callchain__fprintf_left_margin(fp, left_margin);
67
68 for (i = 0; i < depth; i++)
69 if (depth_mask & (1 << i))
70 ret += fprintf(fp, "| ");
71 else
72 ret += fprintf(fp, " ");
73
74 ret += fprintf(fp, "\n");
75
76 return ret;
77}
78static size_t
79ipchain__fprintf_graph(FILE *fp, struct callchain_list *chain, int depth,
80 int depth_mask, int count, u64 total_samples,
81 int hits, int left_margin)
82{
83 int i;
84 size_t ret = 0;
85
86 ret += callchain__fprintf_left_margin(fp, left_margin);
87 for (i = 0; i < depth; i++) {
88 if (depth_mask & (1 << i))
89 ret += fprintf(fp, "|");
90 else
91 ret += fprintf(fp, " ");
92 if (!count && i == depth - 1) {
93 double percent;
94
95 percent = hits * 100.0 / total_samples;
96 ret += percent_color_fprintf(fp, "--%2.2f%%-- ", percent);
97 } else
98 ret += fprintf(fp, "%s", " ");
99 }
100 if (chain->sym)
101 ret += fprintf(fp, "%s\n", chain->sym->name);
102 else
103 ret += fprintf(fp, "%p\n", (void *)(long)chain->ip);
104
105 return ret;
106}
107
108static struct symbol *rem_sq_bracket;
109static struct callchain_list rem_hits;
110
111static void init_rem_hits(void)
112{
113 rem_sq_bracket = malloc(sizeof(*rem_sq_bracket) + 6);
114 if (!rem_sq_bracket) {
115 fprintf(stderr, "Not enough memory to display remaining hits\n");
116 return;
117 }
118
119 strcpy(rem_sq_bracket->name, "[...]");
120 rem_hits.sym = rem_sq_bracket;
121}
122
123static size_t
124__callchain__fprintf_graph(FILE *fp, struct callchain_node *self,
125 u64 total_samples, int depth, int depth_mask,
126 int left_margin)
127{
128 struct rb_node *node, *next;
129 struct callchain_node *child;
130 struct callchain_list *chain;
131 int new_depth_mask = depth_mask;
132 u64 new_total;
133 u64 remaining;
134 size_t ret = 0;
135 int i;
136
137 if (callchain_param.mode == CHAIN_GRAPH_REL)
138 new_total = self->children_hit;
139 else
140 new_total = total_samples;
141
142 remaining = new_total;
143
144 node = rb_first(&self->rb_root);
145 while (node) {
146 u64 cumul;
147
148 child = rb_entry(node, struct callchain_node, rb_node);
149 cumul = cumul_hits(child);
150 remaining -= cumul;
151
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
155 * level for the last child of this depth.
156 * Except if we have remaining filtered hits. They will
157 * supersede the last child
158 */
159 next = rb_next(node);
160 if (!next && (callchain_param.mode != CHAIN_GRAPH_REL || !remaining))
161 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 left_margin);
169 i = 0;
170 list_for_each_entry(chain, &child->val, list) {
171 if (chain->ip >= PERF_CONTEXT_MAX)
172 continue;
173 ret += ipchain__fprintf_graph(fp, chain, depth,
174 new_depth_mask, i++,
175 new_total,
176 cumul,
177 left_margin);
178 }
179 ret += __callchain__fprintf_graph(fp, child, new_total,
180 depth + 1,
181 new_depth_mask | (1 << depth),
182 left_margin);
183 node = next;
184 }
185
186 if (callchain_param.mode == CHAIN_GRAPH_REL &&
187 remaining && remaining != new_total) {
188
189 if (!rem_sq_bracket)
190 return ret;
191
192 new_depth_mask &= ~(1 << (depth - 1));
193
194 ret += ipchain__fprintf_graph(fp, &rem_hits, depth,
195 new_depth_mask, 0, new_total,
196 remaining, left_margin);
197 }
198
199 return ret;
200}
201
202
203static size_t
204callchain__fprintf_graph(FILE *fp, struct callchain_node *self,
205 u64 total_samples, int left_margin)
206{
207 struct callchain_list *chain;
208 bool printed = false;
209 int i = 0;
210 int ret = 0;
211
212 list_for_each_entry(chain, &self->val, list) {
213 if (chain->ip >= PERF_CONTEXT_MAX)
214 continue;
215
216 if (!i++ && sort__first_dimension == SORT_SYM)
217 continue;
218
219 if (!printed) {
220 ret += callchain__fprintf_left_margin(fp, left_margin);
221 ret += fprintf(fp, "|\n");
222 ret += callchain__fprintf_left_margin(fp, left_margin);
223 ret += fprintf(fp, "---");
224
225 left_margin += 3;
226 printed = true;
227 } else
228 ret += callchain__fprintf_left_margin(fp, left_margin);
229
230 if (chain->sym)
231 ret += fprintf(fp, " %s\n", chain->sym->name);
232 else
233 ret += fprintf(fp, " %p\n", (void *)(long)chain->ip);
234 }
235
236 ret += __callchain__fprintf_graph(fp, self, total_samples, 1, 1, left_margin);
237
238 return ret;
239}
240
241static size_t
242callchain__fprintf_flat(FILE *fp, struct callchain_node *self,
243 u64 total_samples)
244{
245 struct callchain_list *chain;
246 size_t ret = 0;
247
248 if (!self)
249 return 0;
250
251 ret += callchain__fprintf_flat(fp, self->parent, total_samples);
252
253
254 list_for_each_entry(chain, &self->val, list) {
255 if (chain->ip >= PERF_CONTEXT_MAX)
256 continue;
257 if (chain->sym)
258 ret += fprintf(fp, " %s\n", chain->sym->name);
259 else
260 ret += fprintf(fp, " %p\n",
261 (void *)(long)chain->ip);
262 }
263
264 return ret;
265}
266
267static size_t
268hist_entry_callchain__fprintf(FILE *fp, struct hist_entry *self,
269 u64 total_samples, int left_margin)
270{
271 struct rb_node *rb_node;
272 struct callchain_node *chain;
273 size_t ret = 0;
274
275 rb_node = rb_first(&self->sorted_chain);
276 while (rb_node) {
277 double percent;
278
279 chain = rb_entry(rb_node, struct callchain_node, rb_node);
280 percent = chain->hit * 100.0 / total_samples;
281 switch (callchain_param.mode) {
282 case CHAIN_FLAT:
283 ret += percent_color_fprintf(fp, " %6.2f%%\n",
284 percent);
285 ret += callchain__fprintf_flat(fp, chain, total_samples);
286 break;
287 case CHAIN_GRAPH_ABS: /* Falldown */
288 case CHAIN_GRAPH_REL:
289 ret += callchain__fprintf_graph(fp, chain, total_samples,
290 left_margin);
291 case CHAIN_NONE:
292 default:
293 break;
294 }
295 ret += fprintf(fp, "\n");
296 rb_node = rb_next(rb_node);
297 }
298
299 return ret;
300}
301
302static size_t hist_entry__fprintf(FILE *fp, struct hist_entry *self,
303 struct perf_session *session)
304{
305 struct sort_entry *se;
306 size_t ret;
307
308 if (symbol_conf.exclude_other && !self->parent)
309 return 0;
310
311 if (session->events_stats.total)
312 ret = percent_color_fprintf(fp,
313 symbol_conf.field_sep ? "%.2f" : " %6.2f%%",
314 (self->count * 100.0) / session->events_stats.total);
315 else
316 ret = fprintf(fp, symbol_conf.field_sep ? "%lld" : "%12lld ", self->count);
317
318 if (symbol_conf.show_nr_samples) {
319 if (symbol_conf.field_sep)
320 fprintf(fp, "%c%lld", *symbol_conf.field_sep, self->count);
321 else
322 fprintf(fp, "%11lld", self->count);
323 }
324
325 list_for_each_entry(se, &hist_entry__sort_list, list) {
326 if (se->elide)
327 continue;
328
329 fprintf(fp, "%s", symbol_conf.field_sep ?: " ");
330 ret += se->print(fp, self, se->width ? *se->width : 0);
331 }
332
333 ret += fprintf(fp, "\n");
334
335 if (symbol_conf.use_callchain) {
336 int left_margin = 0;
337
338 if (sort__first_dimension == SORT_COMM) {
339 se = list_first_entry(&hist_entry__sort_list, typeof(*se),
340 list);
341 left_margin = se->width ? *se->width : 0;
342 left_margin -= thread__comm_len(self->thread);
343 }
344
345 hist_entry_callchain__fprintf(fp, self, session->events_stats.total,
346 left_margin);
347 }
348
349 return ret;
350}
351
352/*
353 * collect histogram counts
354 */
355
356static int perf_session__add_hist_entry(struct perf_session *self, 46static int perf_session__add_hist_entry(struct perf_session *self,
357 struct addr_location *al, 47 struct addr_location *al,
358 struct ip_callchain *chain, u64 count) 48 struct ip_callchain *chain, u64 count)
@@ -381,93 +71,6 @@ static int perf_session__add_hist_entry(struct perf_session *self,
381 return 0; 71 return 0;
382} 72}
383 73
384static size_t perf_session__fprintf_hists(struct perf_session *self, FILE *fp)
385{
386 struct hist_entry *pos;
387 struct sort_entry *se;
388 struct rb_node *nd;
389 size_t ret = 0;
390 unsigned int width;
391 char *col_width = symbol_conf.col_width_list_str;
392
393 init_rem_hits();
394
395 fprintf(fp, "# Samples: %ld\n", self->events_stats.total);
396 fprintf(fp, "#\n");
397
398 fprintf(fp, "# Overhead");
399 if (symbol_conf.show_nr_samples) {
400 if (symbol_conf.field_sep)
401 fprintf(fp, "%cSamples", *symbol_conf.field_sep);
402 else
403 fputs(" Samples ", fp);
404 }
405 list_for_each_entry(se, &hist_entry__sort_list, list) {
406 if (se->elide)
407 continue;
408 if (symbol_conf.field_sep) {
409 fprintf(fp, "%c%s", *symbol_conf.field_sep, se->header);
410 continue;
411 }
412 width = strlen(se->header);
413 if (se->width) {
414 if (symbol_conf.col_width_list_str) {
415 if (col_width) {
416 *se->width = atoi(col_width);
417 col_width = strchr(col_width, ',');
418 if (col_width)
419 ++col_width;
420 }
421 }
422 width = *se->width = max(*se->width, width);
423 }
424 fprintf(fp, " %*s", width, se->header);
425 }
426 fprintf(fp, "\n");
427
428 if (symbol_conf.field_sep)
429 goto print_entries;
430
431 fprintf(fp, "# ........");
432 if (symbol_conf.show_nr_samples)
433 fprintf(fp, " ..........");
434 list_for_each_entry(se, &hist_entry__sort_list, list) {
435 unsigned int i;
436
437 if (se->elide)
438 continue;
439
440 fprintf(fp, " ");
441 if (se->width)
442 width = *se->width;
443 else
444 width = strlen(se->header);
445 for (i = 0; i < width; i++)
446 fprintf(fp, ".");
447 }
448 fprintf(fp, "\n");
449
450 fprintf(fp, "#\n");
451
452print_entries:
453 for (nd = rb_first(&self->hists); nd; nd = rb_next(nd)) {
454 pos = rb_entry(nd, struct hist_entry, rb_node);
455 ret += hist_entry__fprintf(fp, pos, self);
456 }
457
458 if (sort_order == default_sort_order &&
459 parent_pattern == default_parent_pattern) {
460 fprintf(fp, "#\n");
461 fprintf(fp, "# (For a higher level overview, try: perf report --sort comm,dso)\n");
462 fprintf(fp, "#\n");
463 }
464 fprintf(fp, "\n");
465
466 free(rem_sq_bracket);
467
468 return ret;
469}
470
471static int validate_chain(struct ip_callchain *chain, event_t *event) 74static int validate_chain(struct ip_callchain *chain, event_t *event)
472{ 75{
473 unsigned int chain_size; 76 unsigned int chain_size;