blob: ad6b22dde27f2f9ea33f5d40eafd565a2aa8a0f6 [file] [log] [blame]
John Kacur3d1d07e2009-09-28 15:32:55 +02001#include "hist.h"
Arnaldo Carvalho de Melo4e4f06e2009-12-14 13:10:39 -02002#include "session.h"
3#include "sort.h"
Arnaldo Carvalho de Melo9b338272009-12-16 14:31:49 -02004#include <math.h>
John Kacur3d1d07e2009-09-28 15:32:55 +02005
6struct callchain_param callchain_param = {
7 .mode = CHAIN_GRAPH_REL,
8 .min_percent = 0.5
9};
10
Zhang, Yanmina1645ce2010-04-19 13:32:50 +080011void __perf_session__add_count(struct hist_entry *he,
12 struct addr_location *al,
13 u64 count)
14{
15 he->count += count;
16
17 switch (al->cpumode) {
18 case PERF_RECORD_MISC_KERNEL:
19 he->count_sys += count;
20 break;
21 case PERF_RECORD_MISC_USER:
22 he->count_us += count;
23 break;
24 case PERF_RECORD_MISC_GUEST_KERNEL:
25 he->count_guest_sys += count;
26 break;
27 case PERF_RECORD_MISC_GUEST_USER:
28 he->count_guest_us += count;
29 break;
30 default:
31 break;
32 }
33}
34
John Kacur3d1d07e2009-09-28 15:32:55 +020035/*
36 * histogram, sorted on item, collects counts
37 */
38
Eric B Munsond403d0a2010-03-05 12:51:06 -030039struct hist_entry *__perf_session__add_hist_entry(struct rb_root *hists,
Arnaldo Carvalho de Melo4e4f06e2009-12-14 13:10:39 -020040 struct addr_location *al,
41 struct symbol *sym_parent,
42 u64 count, bool *hit)
Arnaldo Carvalho de Melo9735abf2009-10-03 10:42:45 -030043{
Eric B Munsond403d0a2010-03-05 12:51:06 -030044 struct rb_node **p = &hists->rb_node;
Arnaldo Carvalho de Melo9735abf2009-10-03 10:42:45 -030045 struct rb_node *parent = NULL;
46 struct hist_entry *he;
47 struct hist_entry entry = {
Arnaldo Carvalho de Melo1ed091c2009-11-27 16:29:23 -020048 .thread = al->thread,
Arnaldo Carvalho de Melo59fd5302010-03-24 16:40:17 -030049 .ms = {
50 .map = al->map,
51 .sym = al->sym,
52 },
Arnaldo Carvalho de Melo1ed091c2009-11-27 16:29:23 -020053 .ip = al->addr,
54 .level = al->level,
Arnaldo Carvalho de Melo9735abf2009-10-03 10:42:45 -030055 .count = count,
56 .parent = sym_parent,
57 };
58 int cmp;
59
60 while (*p != NULL) {
61 parent = *p;
62 he = rb_entry(parent, struct hist_entry, rb_node);
63
64 cmp = hist_entry__cmp(&entry, he);
65
66 if (!cmp) {
67 *hit = true;
68 return he;
69 }
70
71 if (cmp < 0)
72 p = &(*p)->rb_left;
73 else
74 p = &(*p)->rb_right;
75 }
76
Arnaldo Carvalho de Melob9fb9302010-04-02 09:50:42 -030077 he = malloc(sizeof(*he) + (symbol_conf.use_callchain ?
78 sizeof(struct callchain_node) : 0));
Arnaldo Carvalho de Melo9735abf2009-10-03 10:42:45 -030079 if (!he)
80 return NULL;
81 *he = entry;
82 rb_link_node(&he->rb_node, parent, p);
Eric B Munsond403d0a2010-03-05 12:51:06 -030083 rb_insert_color(&he->rb_node, hists);
Arnaldo Carvalho de Melo9735abf2009-10-03 10:42:45 -030084 *hit = false;
85 return he;
86}
87
John Kacur3d1d07e2009-09-28 15:32:55 +020088int64_t
89hist_entry__cmp(struct hist_entry *left, struct hist_entry *right)
90{
91 struct sort_entry *se;
92 int64_t cmp = 0;
93
94 list_for_each_entry(se, &hist_entry__sort_list, list) {
Frederic Weisbeckerfcd14982010-04-14 19:11:29 +020095 cmp = se->se_cmp(left, right);
John Kacur3d1d07e2009-09-28 15:32:55 +020096 if (cmp)
97 break;
98 }
99
100 return cmp;
101}
102
103int64_t
104hist_entry__collapse(struct hist_entry *left, struct hist_entry *right)
105{
106 struct sort_entry *se;
107 int64_t cmp = 0;
108
109 list_for_each_entry(se, &hist_entry__sort_list, list) {
110 int64_t (*f)(struct hist_entry *, struct hist_entry *);
111
Frederic Weisbeckerfcd14982010-04-14 19:11:29 +0200112 f = se->se_collapse ?: se->se_cmp;
John Kacur3d1d07e2009-09-28 15:32:55 +0200113
114 cmp = f(left, right);
115 if (cmp)
116 break;
117 }
118
119 return cmp;
120}
121
122void hist_entry__free(struct hist_entry *he)
123{
124 free(he);
125}
126
127/*
128 * collapse the histogram
129 */
130
Arnaldo Carvalho de Melob9bf0892009-12-14 11:37:11 -0200131static void collapse__insert_entry(struct rb_root *root, struct hist_entry *he)
John Kacur3d1d07e2009-09-28 15:32:55 +0200132{
Arnaldo Carvalho de Melob9bf0892009-12-14 11:37:11 -0200133 struct rb_node **p = &root->rb_node;
John Kacur3d1d07e2009-09-28 15:32:55 +0200134 struct rb_node *parent = NULL;
135 struct hist_entry *iter;
136 int64_t cmp;
137
138 while (*p != NULL) {
139 parent = *p;
140 iter = rb_entry(parent, struct hist_entry, rb_node);
141
142 cmp = hist_entry__collapse(iter, he);
143
144 if (!cmp) {
145 iter->count += he->count;
146 hist_entry__free(he);
147 return;
148 }
149
150 if (cmp < 0)
151 p = &(*p)->rb_left;
152 else
153 p = &(*p)->rb_right;
154 }
155
156 rb_link_node(&he->rb_node, parent, p);
Arnaldo Carvalho de Melob9bf0892009-12-14 11:37:11 -0200157 rb_insert_color(&he->rb_node, root);
John Kacur3d1d07e2009-09-28 15:32:55 +0200158}
159
Eric B Munsoneefc4652010-03-05 12:51:08 -0300160void perf_session__collapse_resort(struct rb_root *hists)
John Kacur3d1d07e2009-09-28 15:32:55 +0200161{
Arnaldo Carvalho de Melob9bf0892009-12-14 11:37:11 -0200162 struct rb_root tmp;
John Kacur3d1d07e2009-09-28 15:32:55 +0200163 struct rb_node *next;
164 struct hist_entry *n;
165
166 if (!sort__need_collapse)
167 return;
168
Arnaldo Carvalho de Melob9bf0892009-12-14 11:37:11 -0200169 tmp = RB_ROOT;
Eric B Munsoneefc4652010-03-05 12:51:08 -0300170 next = rb_first(hists);
Arnaldo Carvalho de Melob9bf0892009-12-14 11:37:11 -0200171
John Kacur3d1d07e2009-09-28 15:32:55 +0200172 while (next) {
173 n = rb_entry(next, struct hist_entry, rb_node);
174 next = rb_next(&n->rb_node);
175
Eric B Munsoneefc4652010-03-05 12:51:08 -0300176 rb_erase(&n->rb_node, hists);
Arnaldo Carvalho de Melob9bf0892009-12-14 11:37:11 -0200177 collapse__insert_entry(&tmp, n);
John Kacur3d1d07e2009-09-28 15:32:55 +0200178 }
Arnaldo Carvalho de Melob9bf0892009-12-14 11:37:11 -0200179
Eric B Munsoneefc4652010-03-05 12:51:08 -0300180 *hists = tmp;
John Kacur3d1d07e2009-09-28 15:32:55 +0200181}
182
183/*
184 * reverse the map, sort on count.
185 */
186
Arnaldo Carvalho de Melod599db32009-12-15 20:04:42 -0200187static void perf_session__insert_output_hist_entry(struct rb_root *root,
Arnaldo Carvalho de Melo4e4f06e2009-12-14 13:10:39 -0200188 struct hist_entry *he,
189 u64 min_callchain_hits)
John Kacur3d1d07e2009-09-28 15:32:55 +0200190{
Arnaldo Carvalho de Melob9bf0892009-12-14 11:37:11 -0200191 struct rb_node **p = &root->rb_node;
John Kacur3d1d07e2009-09-28 15:32:55 +0200192 struct rb_node *parent = NULL;
193 struct hist_entry *iter;
194
Arnaldo Carvalho de Melod599db32009-12-15 20:04:42 -0200195 if (symbol_conf.use_callchain)
Arnaldo Carvalho de Melob9fb9302010-04-02 09:50:42 -0300196 callchain_param.sort(&he->sorted_chain, he->callchain,
John Kacur3d1d07e2009-09-28 15:32:55 +0200197 min_callchain_hits, &callchain_param);
198
199 while (*p != NULL) {
200 parent = *p;
201 iter = rb_entry(parent, struct hist_entry, rb_node);
202
203 if (he->count > iter->count)
204 p = &(*p)->rb_left;
205 else
206 p = &(*p)->rb_right;
207 }
208
209 rb_link_node(&he->rb_node, parent, p);
Arnaldo Carvalho de Melob9bf0892009-12-14 11:37:11 -0200210 rb_insert_color(&he->rb_node, root);
John Kacur3d1d07e2009-09-28 15:32:55 +0200211}
212
Arnaldo Carvalho de Melo5f4d3f82010-03-26 21:16:22 -0300213u64 perf_session__output_resort(struct rb_root *hists, u64 total_samples)
John Kacur3d1d07e2009-09-28 15:32:55 +0200214{
Arnaldo Carvalho de Melob9bf0892009-12-14 11:37:11 -0200215 struct rb_root tmp;
John Kacur3d1d07e2009-09-28 15:32:55 +0200216 struct rb_node *next;
217 struct hist_entry *n;
John Kacur3d1d07e2009-09-28 15:32:55 +0200218 u64 min_callchain_hits;
Arnaldo Carvalho de Melo5f4d3f82010-03-26 21:16:22 -0300219 u64 nr_hists = 0;
John Kacur3d1d07e2009-09-28 15:32:55 +0200220
221 min_callchain_hits =
222 total_samples * (callchain_param.min_percent / 100);
223
Arnaldo Carvalho de Melob9bf0892009-12-14 11:37:11 -0200224 tmp = RB_ROOT;
Eric B Munsoneefc4652010-03-05 12:51:08 -0300225 next = rb_first(hists);
John Kacur3d1d07e2009-09-28 15:32:55 +0200226
227 while (next) {
228 n = rb_entry(next, struct hist_entry, rb_node);
229 next = rb_next(&n->rb_node);
230
Eric B Munsoneefc4652010-03-05 12:51:08 -0300231 rb_erase(&n->rb_node, hists);
Arnaldo Carvalho de Melod599db32009-12-15 20:04:42 -0200232 perf_session__insert_output_hist_entry(&tmp, n,
Arnaldo Carvalho de Melo4e4f06e2009-12-14 13:10:39 -0200233 min_callchain_hits);
Arnaldo Carvalho de Melo5f4d3f82010-03-26 21:16:22 -0300234 ++nr_hists;
John Kacur3d1d07e2009-09-28 15:32:55 +0200235 }
Arnaldo Carvalho de Melob9bf0892009-12-14 11:37:11 -0200236
Eric B Munsoneefc4652010-03-05 12:51:08 -0300237 *hists = tmp;
Arnaldo Carvalho de Melo5f4d3f82010-03-26 21:16:22 -0300238 return nr_hists;
John Kacur3d1d07e2009-09-28 15:32:55 +0200239}
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200240
241static size_t callchain__fprintf_left_margin(FILE *fp, int left_margin)
242{
243 int i;
244 int ret = fprintf(fp, " ");
245
246 for (i = 0; i < left_margin; i++)
247 ret += fprintf(fp, " ");
248
249 return ret;
250}
251
252static size_t ipchain__fprintf_graph_line(FILE *fp, int depth, int depth_mask,
253 int left_margin)
254{
255 int i;
256 size_t ret = callchain__fprintf_left_margin(fp, left_margin);
257
258 for (i = 0; i < depth; i++)
259 if (depth_mask & (1 << i))
260 ret += fprintf(fp, "| ");
261 else
262 ret += fprintf(fp, " ");
263
264 ret += fprintf(fp, "\n");
265
266 return ret;
267}
268
269static size_t ipchain__fprintf_graph(FILE *fp, struct callchain_list *chain,
270 int depth, int depth_mask, int count,
271 u64 total_samples, int hits,
272 int left_margin)
273{
274 int i;
275 size_t ret = 0;
276
277 ret += callchain__fprintf_left_margin(fp, left_margin);
278 for (i = 0; i < depth; i++) {
279 if (depth_mask & (1 << i))
280 ret += fprintf(fp, "|");
281 else
282 ret += fprintf(fp, " ");
283 if (!count && i == depth - 1) {
284 double percent;
285
286 percent = hits * 100.0 / total_samples;
287 ret += percent_color_fprintf(fp, "--%2.2f%%-- ", percent);
288 } else
289 ret += fprintf(fp, "%s", " ");
290 }
Arnaldo Carvalho de Melob3c9ac02010-03-24 16:40:18 -0300291 if (chain->ms.sym)
292 ret += fprintf(fp, "%s\n", chain->ms.sym->name);
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200293 else
294 ret += fprintf(fp, "%p\n", (void *)(long)chain->ip);
295
296 return ret;
297}
298
299static struct symbol *rem_sq_bracket;
300static struct callchain_list rem_hits;
301
302static void init_rem_hits(void)
303{
304 rem_sq_bracket = malloc(sizeof(*rem_sq_bracket) + 6);
305 if (!rem_sq_bracket) {
306 fprintf(stderr, "Not enough memory to display remaining hits\n");
307 return;
308 }
309
310 strcpy(rem_sq_bracket->name, "[...]");
Arnaldo Carvalho de Melob3c9ac02010-03-24 16:40:18 -0300311 rem_hits.ms.sym = rem_sq_bracket;
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200312}
313
314static size_t __callchain__fprintf_graph(FILE *fp, struct callchain_node *self,
315 u64 total_samples, int depth,
316 int depth_mask, int left_margin)
317{
318 struct rb_node *node, *next;
319 struct callchain_node *child;
320 struct callchain_list *chain;
321 int new_depth_mask = depth_mask;
322 u64 new_total;
323 u64 remaining;
324 size_t ret = 0;
325 int i;
326
327 if (callchain_param.mode == CHAIN_GRAPH_REL)
328 new_total = self->children_hit;
329 else
330 new_total = total_samples;
331
332 remaining = new_total;
333
334 node = rb_first(&self->rb_root);
335 while (node) {
336 u64 cumul;
337
338 child = rb_entry(node, struct callchain_node, rb_node);
339 cumul = cumul_hits(child);
340 remaining -= cumul;
341
342 /*
343 * The depth mask manages the output of pipes that show
344 * the depth. We don't want to keep the pipes of the current
345 * level for the last child of this depth.
346 * Except if we have remaining filtered hits. They will
347 * supersede the last child
348 */
349 next = rb_next(node);
350 if (!next && (callchain_param.mode != CHAIN_GRAPH_REL || !remaining))
351 new_depth_mask &= ~(1 << (depth - 1));
352
353 /*
Daniel Mack3ad2f3f2010-02-03 08:01:28 +0800354 * But we keep the older depth mask for the line separator
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200355 * to keep the level link until we reach the last child
356 */
357 ret += ipchain__fprintf_graph_line(fp, depth, depth_mask,
358 left_margin);
359 i = 0;
360 list_for_each_entry(chain, &child->val, list) {
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200361 ret += ipchain__fprintf_graph(fp, chain, depth,
362 new_depth_mask, i++,
363 new_total,
364 cumul,
365 left_margin);
366 }
367 ret += __callchain__fprintf_graph(fp, child, new_total,
368 depth + 1,
369 new_depth_mask | (1 << depth),
370 left_margin);
371 node = next;
372 }
373
374 if (callchain_param.mode == CHAIN_GRAPH_REL &&
375 remaining && remaining != new_total) {
376
377 if (!rem_sq_bracket)
378 return ret;
379
380 new_depth_mask &= ~(1 << (depth - 1));
381
382 ret += ipchain__fprintf_graph(fp, &rem_hits, depth,
383 new_depth_mask, 0, new_total,
384 remaining, left_margin);
385 }
386
387 return ret;
388}
389
390static size_t callchain__fprintf_graph(FILE *fp, struct callchain_node *self,
391 u64 total_samples, int left_margin)
392{
393 struct callchain_list *chain;
394 bool printed = false;
395 int i = 0;
396 int ret = 0;
397
398 list_for_each_entry(chain, &self->val, list) {
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200399 if (!i++ && sort__first_dimension == SORT_SYM)
400 continue;
401
402 if (!printed) {
403 ret += callchain__fprintf_left_margin(fp, left_margin);
404 ret += fprintf(fp, "|\n");
405 ret += callchain__fprintf_left_margin(fp, left_margin);
406 ret += fprintf(fp, "---");
407
408 left_margin += 3;
409 printed = true;
410 } else
411 ret += callchain__fprintf_left_margin(fp, left_margin);
412
Arnaldo Carvalho de Melob3c9ac02010-03-24 16:40:18 -0300413 if (chain->ms.sym)
414 ret += fprintf(fp, " %s\n", chain->ms.sym->name);
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200415 else
416 ret += fprintf(fp, " %p\n", (void *)(long)chain->ip);
417 }
418
419 ret += __callchain__fprintf_graph(fp, self, total_samples, 1, 1, left_margin);
420
421 return ret;
422}
423
424static size_t callchain__fprintf_flat(FILE *fp, struct callchain_node *self,
425 u64 total_samples)
426{
427 struct callchain_list *chain;
428 size_t ret = 0;
429
430 if (!self)
431 return 0;
432
433 ret += callchain__fprintf_flat(fp, self->parent, total_samples);
434
435
436 list_for_each_entry(chain, &self->val, list) {
437 if (chain->ip >= PERF_CONTEXT_MAX)
438 continue;
Arnaldo Carvalho de Melob3c9ac02010-03-24 16:40:18 -0300439 if (chain->ms.sym)
440 ret += fprintf(fp, " %s\n", chain->ms.sym->name);
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200441 else
442 ret += fprintf(fp, " %p\n",
443 (void *)(long)chain->ip);
444 }
445
446 return ret;
447}
448
449static size_t hist_entry_callchain__fprintf(FILE *fp, struct hist_entry *self,
450 u64 total_samples, int left_margin)
451{
452 struct rb_node *rb_node;
453 struct callchain_node *chain;
454 size_t ret = 0;
455
456 rb_node = rb_first(&self->sorted_chain);
457 while (rb_node) {
458 double percent;
459
460 chain = rb_entry(rb_node, struct callchain_node, rb_node);
461 percent = chain->hit * 100.0 / total_samples;
462 switch (callchain_param.mode) {
463 case CHAIN_FLAT:
464 ret += percent_color_fprintf(fp, " %6.2f%%\n",
465 percent);
466 ret += callchain__fprintf_flat(fp, chain, total_samples);
467 break;
468 case CHAIN_GRAPH_ABS: /* Falldown */
469 case CHAIN_GRAPH_REL:
470 ret += callchain__fprintf_graph(fp, chain, total_samples,
471 left_margin);
472 case CHAIN_NONE:
473 default:
474 break;
475 }
476 ret += fprintf(fp, "\n");
477 rb_node = rb_next(rb_node);
478 }
479
480 return ret;
481}
482
Arnaldo Carvalho de Meloa4e3b952010-03-31 11:33:40 -0300483int hist_entry__snprintf(struct hist_entry *self,
484 char *s, size_t size,
Arnaldo Carvalho de Melodd2ee782010-03-11 20:12:43 -0300485 struct perf_session *pair_session,
486 bool show_displacement,
Arnaldo Carvalho de Meloa4e3b952010-03-31 11:33:40 -0300487 long displacement, bool color,
Arnaldo Carvalho de Melodd2ee782010-03-11 20:12:43 -0300488 u64 session_total)
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200489{
490 struct sort_entry *se;
Zhang, Yanmina1645ce2010-04-19 13:32:50 +0800491 u64 count, total, count_sys, count_us, count_guest_sys, count_guest_us;
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -0200492 const char *sep = symbol_conf.field_sep;
Arnaldo Carvalho de Meloa4e3b952010-03-31 11:33:40 -0300493 int ret;
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200494
495 if (symbol_conf.exclude_other && !self->parent)
496 return 0;
497
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -0200498 if (pair_session) {
499 count = self->pair ? self->pair->count : 0;
500 total = pair_session->events_stats.total;
Zhang, Yanmina1645ce2010-04-19 13:32:50 +0800501 count_sys = self->pair ? self->pair->count_sys : 0;
502 count_us = self->pair ? self->pair->count_us : 0;
503 count_guest_sys = self->pair ? self->pair->count_guest_sys : 0;
504 count_guest_us = self->pair ? self->pair->count_guest_us : 0;
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -0200505 } else {
506 count = self->count;
Eric B Munsoneefc4652010-03-05 12:51:08 -0300507 total = session_total;
Zhang, Yanmina1645ce2010-04-19 13:32:50 +0800508 count_sys = self->count_sys;
509 count_us = self->count_us;
510 count_guest_sys = self->count_guest_sys;
511 count_guest_us = self->count_guest_us;
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -0200512 }
513
Arnaldo Carvalho de Meloa4e3b952010-03-31 11:33:40 -0300514 if (total) {
515 if (color)
516 ret = percent_color_snprintf(s, size,
517 sep ? "%.2f" : " %6.2f%%",
518 (count * 100.0) / total);
519 else
520 ret = snprintf(s, size, sep ? "%.2f" : " %6.2f%%",
521 (count * 100.0) / total);
Zhang, Yanmina1645ce2010-04-19 13:32:50 +0800522 if (symbol_conf.show_cpu_utilization) {
523 ret += percent_color_snprintf(s + ret, size - ret,
524 sep ? "%.2f" : " %6.2f%%",
525 (count_sys * 100.0) / total);
526 ret += percent_color_snprintf(s + ret, size - ret,
527 sep ? "%.2f" : " %6.2f%%",
528 (count_us * 100.0) / total);
529 if (perf_guest) {
530 ret += percent_color_snprintf(s + ret,
531 size - ret,
532 sep ? "%.2f" : " %6.2f%%",
533 (count_guest_sys * 100.0) /
534 total);
535 ret += percent_color_snprintf(s + ret,
536 size - ret,
537 sep ? "%.2f" : " %6.2f%%",
538 (count_guest_us * 100.0) /
539 total);
540 }
541 }
Arnaldo Carvalho de Meloa4e3b952010-03-31 11:33:40 -0300542 } else
543 ret = snprintf(s, size, sep ? "%lld" : "%12lld ", count);
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200544
545 if (symbol_conf.show_nr_samples) {
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -0200546 if (sep)
Arnaldo Carvalho de Meloa4e3b952010-03-31 11:33:40 -0300547 ret += snprintf(s + ret, size - ret, "%c%lld", *sep, count);
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200548 else
Arnaldo Carvalho de Meloa4e3b952010-03-31 11:33:40 -0300549 ret += snprintf(s + ret, size - ret, "%11lld", count);
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -0200550 }
551
552 if (pair_session) {
553 char bf[32];
554 double old_percent = 0, new_percent = 0, diff;
555
556 if (total > 0)
Arnaldo Carvalho de Melo9b338272009-12-16 14:31:49 -0200557 old_percent = (count * 100.0) / total;
Eric B Munsoneefc4652010-03-05 12:51:08 -0300558 if (session_total > 0)
559 new_percent = (self->count * 100.0) / session_total;
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -0200560
Arnaldo Carvalho de Melo9b338272009-12-16 14:31:49 -0200561 diff = new_percent - old_percent;
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -0200562
Arnaldo Carvalho de Melo9b338272009-12-16 14:31:49 -0200563 if (fabs(diff) >= 0.01)
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -0200564 snprintf(bf, sizeof(bf), "%+4.2F%%", diff);
565 else
566 snprintf(bf, sizeof(bf), " ");
567
568 if (sep)
Arnaldo Carvalho de Meloa4e3b952010-03-31 11:33:40 -0300569 ret += snprintf(s + ret, size - ret, "%c%s", *sep, bf);
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -0200570 else
Arnaldo Carvalho de Meloa4e3b952010-03-31 11:33:40 -0300571 ret += snprintf(s + ret, size - ret, "%11.11s", bf);
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -0200572
573 if (show_displacement) {
574 if (displacement)
575 snprintf(bf, sizeof(bf), "%+4ld", displacement);
576 else
577 snprintf(bf, sizeof(bf), " ");
578
579 if (sep)
Arnaldo Carvalho de Meloa4e3b952010-03-31 11:33:40 -0300580 ret += snprintf(s + ret, size - ret, "%c%s", *sep, bf);
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -0200581 else
Arnaldo Carvalho de Meloa4e3b952010-03-31 11:33:40 -0300582 ret += snprintf(s + ret, size - ret, "%6.6s", bf);
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -0200583 }
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200584 }
585
586 list_for_each_entry(se, &hist_entry__sort_list, list) {
587 if (se->elide)
588 continue;
589
Arnaldo Carvalho de Meloa4e3b952010-03-31 11:33:40 -0300590 ret += snprintf(s + ret, size - ret, "%s", sep ?: " ");
Frederic Weisbeckerfcd14982010-04-14 19:11:29 +0200591 ret += se->se_snprintf(self, s + ret, size - ret,
592 se->se_width ? *se->se_width : 0);
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200593 }
594
Arnaldo Carvalho de Meloa4e3b952010-03-31 11:33:40 -0300595 return ret;
596}
597
598int hist_entry__fprintf(struct hist_entry *self,
599 struct perf_session *pair_session,
600 bool show_displacement,
601 long displacement, FILE *fp,
602 u64 session_total)
603{
604 char bf[512];
605 hist_entry__snprintf(self, bf, sizeof(bf), pair_session,
606 show_displacement, displacement,
607 true, session_total);
608 return fprintf(fp, "%s\n", bf);
Arnaldo Carvalho de Melo3997d372010-03-12 12:46:48 -0300609}
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200610
Arnaldo Carvalho de Melo3997d372010-03-12 12:46:48 -0300611static size_t hist_entry__fprintf_callchain(struct hist_entry *self, FILE *fp,
612 u64 session_total)
613{
614 int left_margin = 0;
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200615
Arnaldo Carvalho de Melo3997d372010-03-12 12:46:48 -0300616 if (sort__first_dimension == SORT_COMM) {
617 struct sort_entry *se = list_first_entry(&hist_entry__sort_list,
618 typeof(*se), list);
Frederic Weisbeckerfcd14982010-04-14 19:11:29 +0200619 left_margin = se->se_width ? *se->se_width : 0;
Arnaldo Carvalho de Melo3997d372010-03-12 12:46:48 -0300620 left_margin -= thread__comm_len(self->thread);
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200621 }
622
Arnaldo Carvalho de Melo3997d372010-03-12 12:46:48 -0300623 return hist_entry_callchain__fprintf(fp, self, session_total,
624 left_margin);
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200625}
626
Eric B Munsoneefc4652010-03-05 12:51:08 -0300627size_t perf_session__fprintf_hists(struct rb_root *hists,
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -0200628 struct perf_session *pair,
Eric B Munsoneefc4652010-03-05 12:51:08 -0300629 bool show_displacement, FILE *fp,
630 u64 session_total)
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200631{
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200632 struct sort_entry *se;
633 struct rb_node *nd;
634 size_t ret = 0;
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -0200635 unsigned long position = 1;
636 long displacement = 0;
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200637 unsigned int width;
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -0200638 const char *sep = symbol_conf.field_sep;
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200639 char *col_width = symbol_conf.col_width_list_str;
640
641 init_rem_hits();
642
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -0200643 fprintf(fp, "# %s", pair ? "Baseline" : "Overhead");
644
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200645 if (symbol_conf.show_nr_samples) {
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -0200646 if (sep)
647 fprintf(fp, "%cSamples", *sep);
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200648 else
649 fputs(" Samples ", fp);
650 }
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -0200651
Zhang, Yanmina1645ce2010-04-19 13:32:50 +0800652 if (symbol_conf.show_cpu_utilization) {
653 if (sep) {
654 ret += fprintf(fp, "%csys", *sep);
655 ret += fprintf(fp, "%cus", *sep);
656 if (perf_guest) {
657 ret += fprintf(fp, "%cguest sys", *sep);
658 ret += fprintf(fp, "%cguest us", *sep);
659 }
660 } else {
661 ret += fprintf(fp, " sys ");
662 ret += fprintf(fp, " us ");
663 if (perf_guest) {
664 ret += fprintf(fp, " guest sys ");
665 ret += fprintf(fp, " guest us ");
666 }
667 }
668 }
669
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -0200670 if (pair) {
671 if (sep)
672 ret += fprintf(fp, "%cDelta", *sep);
673 else
674 ret += fprintf(fp, " Delta ");
675
676 if (show_displacement) {
677 if (sep)
678 ret += fprintf(fp, "%cDisplacement", *sep);
679 else
680 ret += fprintf(fp, " Displ");
681 }
682 }
683
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200684 list_for_each_entry(se, &hist_entry__sort_list, list) {
685 if (se->elide)
686 continue;
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -0200687 if (sep) {
Frederic Weisbeckerfcd14982010-04-14 19:11:29 +0200688 fprintf(fp, "%c%s", *sep, se->se_header);
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200689 continue;
690 }
Frederic Weisbeckerfcd14982010-04-14 19:11:29 +0200691 width = strlen(se->se_header);
692 if (se->se_width) {
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200693 if (symbol_conf.col_width_list_str) {
694 if (col_width) {
Frederic Weisbeckerfcd14982010-04-14 19:11:29 +0200695 *se->se_width = atoi(col_width);
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200696 col_width = strchr(col_width, ',');
697 if (col_width)
698 ++col_width;
699 }
700 }
Frederic Weisbeckerfcd14982010-04-14 19:11:29 +0200701 width = *se->se_width = max(*se->se_width, width);
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200702 }
Frederic Weisbeckerfcd14982010-04-14 19:11:29 +0200703 fprintf(fp, " %*s", width, se->se_header);
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200704 }
705 fprintf(fp, "\n");
706
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -0200707 if (sep)
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200708 goto print_entries;
709
710 fprintf(fp, "# ........");
711 if (symbol_conf.show_nr_samples)
712 fprintf(fp, " ..........");
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -0200713 if (pair) {
714 fprintf(fp, " ..........");
715 if (show_displacement)
716 fprintf(fp, " .....");
717 }
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200718 list_for_each_entry(se, &hist_entry__sort_list, list) {
719 unsigned int i;
720
721 if (se->elide)
722 continue;
723
724 fprintf(fp, " ");
Frederic Weisbeckerfcd14982010-04-14 19:11:29 +0200725 if (se->se_width)
726 width = *se->se_width;
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200727 else
Frederic Weisbeckerfcd14982010-04-14 19:11:29 +0200728 width = strlen(se->se_header);
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200729 for (i = 0; i < width; i++)
730 fprintf(fp, ".");
731 }
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200732
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -0200733 fprintf(fp, "\n#\n");
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200734
735print_entries:
Eric B Munsoneefc4652010-03-05 12:51:08 -0300736 for (nd = rb_first(hists); nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -0200737 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
738
739 if (show_displacement) {
740 if (h->pair != NULL)
741 displacement = ((long)h->pair->position -
742 (long)position);
743 else
744 displacement = 0;
745 ++position;
746 }
Eric B Munsoneefc4652010-03-05 12:51:08 -0300747 ret += hist_entry__fprintf(h, pair, show_displacement,
748 displacement, fp, session_total);
Arnaldo Carvalho de Melo3997d372010-03-12 12:46:48 -0300749
750 if (symbol_conf.use_callchain)
751 ret += hist_entry__fprintf_callchain(h, fp, session_total);
752
Arnaldo Carvalho de Melo59fd5302010-03-24 16:40:17 -0300753 if (h->ms.map == NULL && verbose > 1) {
Arnaldo Carvalho de Melo65f2ed22010-03-09 15:58:17 -0300754 __map_groups__fprintf_maps(&h->thread->mg,
Arnaldo Carvalho de Meloc6e718f2010-03-26 12:11:06 -0300755 MAP__FUNCTION, verbose, fp);
Arnaldo Carvalho de Melo65f2ed22010-03-09 15:58:17 -0300756 fprintf(fp, "%.10s end\n", graph_dotted_line);
757 }
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200758 }
759
Arnaldo Carvalho de Melo4ecf84d02009-12-16 12:27:09 -0200760 free(rem_sq_bracket);
761
762 return ret;
763}