perf report: Fix leak of resolved callchains array on error path
[GitHub/mt8127/android_kernel_alcatel_ttab.git] / tools / perf / util / hist.c
CommitLineData
3d1d07ec 1#include "hist.h"
4e4f06e4
ACM
2#include "session.h"
3#include "sort.h"
9b33827d 4#include <math.h>
3d1d07ec
JK
5
6struct callchain_param callchain_param = {
7 .mode = CHAIN_GRAPH_REL,
8 .min_percent = 0.5
9};
10
a1645ce1
ZY
11void __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
3d1d07ec
JK
35/*
36 * histogram, sorted on item, collects counts
37 */
38
d403d0ac 39struct hist_entry *__perf_session__add_hist_entry(struct rb_root *hists,
4e4f06e4
ACM
40 struct addr_location *al,
41 struct symbol *sym_parent,
42 u64 count, bool *hit)
9735abf1 43{
d403d0ac 44 struct rb_node **p = &hists->rb_node;
9735abf1
ACM
45 struct rb_node *parent = NULL;
46 struct hist_entry *he;
47 struct hist_entry entry = {
1ed091c4 48 .thread = al->thread,
59fd5306
ACM
49 .ms = {
50 .map = al->map,
51 .sym = al->sym,
52 },
1ed091c4
ACM
53 .ip = al->addr,
54 .level = al->level,
9735abf1
ACM
55 .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
b9fb9304
ACM
77 he = malloc(sizeof(*he) + (symbol_conf.use_callchain ?
78 sizeof(struct callchain_node) : 0));
9735abf1
ACM
79 if (!he)
80 return NULL;
81 *he = entry;
82 rb_link_node(&he->rb_node, parent, p);
d403d0ac 83 rb_insert_color(&he->rb_node, hists);
9735abf1
ACM
84 *hit = false;
85 return he;
86}
87
3d1d07ec
JK
88int64_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) {
fcd14984 95 cmp = se->se_cmp(left, right);
3d1d07ec
JK
96 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
fcd14984 112 f = se->se_collapse ?: se->se_cmp;
3d1d07ec
JK
113
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
b9bf0892 131static void collapse__insert_entry(struct rb_root *root, struct hist_entry *he)
3d1d07ec 132{
b9bf0892 133 struct rb_node **p = &root->rb_node;
3d1d07ec
JK
134 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);
b9bf0892 157 rb_insert_color(&he->rb_node, root);
3d1d07ec
JK
158}
159
eefc465c 160void perf_session__collapse_resort(struct rb_root *hists)
3d1d07ec 161{
b9bf0892 162 struct rb_root tmp;
3d1d07ec
JK
163 struct rb_node *next;
164 struct hist_entry *n;
165
166 if (!sort__need_collapse)
167 return;
168
b9bf0892 169 tmp = RB_ROOT;
eefc465c 170 next = rb_first(hists);
b9bf0892 171
3d1d07ec
JK
172 while (next) {
173 n = rb_entry(next, struct hist_entry, rb_node);
174 next = rb_next(&n->rb_node);
175
eefc465c 176 rb_erase(&n->rb_node, hists);
b9bf0892 177 collapse__insert_entry(&tmp, n);
3d1d07ec 178 }
b9bf0892 179
eefc465c 180 *hists = tmp;
3d1d07ec
JK
181}
182
183/*
184 * reverse the map, sort on count.
185 */
186
d599db3f 187static void perf_session__insert_output_hist_entry(struct rb_root *root,
4e4f06e4
ACM
188 struct hist_entry *he,
189 u64 min_callchain_hits)
3d1d07ec 190{
b9bf0892 191 struct rb_node **p = &root->rb_node;
3d1d07ec
JK
192 struct rb_node *parent = NULL;
193 struct hist_entry *iter;
194
d599db3f 195 if (symbol_conf.use_callchain)
b9fb9304 196 callchain_param.sort(&he->sorted_chain, he->callchain,
3d1d07ec
JK
197 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);
b9bf0892 210 rb_insert_color(&he->rb_node, root);
3d1d07ec
JK
211}
212
5f4d3f88 213u64 perf_session__output_resort(struct rb_root *hists, u64 total_samples)
3d1d07ec 214{
b9bf0892 215 struct rb_root tmp;
3d1d07ec
JK
216 struct rb_node *next;
217 struct hist_entry *n;
3d1d07ec 218 u64 min_callchain_hits;
5f4d3f88 219 u64 nr_hists = 0;
3d1d07ec
JK
220
221 min_callchain_hits =
222 total_samples * (callchain_param.min_percent / 100);
223
b9bf0892 224 tmp = RB_ROOT;
eefc465c 225 next = rb_first(hists);
3d1d07ec
JK
226
227 while (next) {
228 n = rb_entry(next, struct hist_entry, rb_node);
229 next = rb_next(&n->rb_node);
230
eefc465c 231 rb_erase(&n->rb_node, hists);
d599db3f 232 perf_session__insert_output_hist_entry(&tmp, n,
4e4f06e4 233 min_callchain_hits);
5f4d3f88 234 ++nr_hists;
3d1d07ec 235 }
b9bf0892 236
eefc465c 237 *hists = tmp;
5f4d3f88 238 return nr_hists;
3d1d07ec 239}
4ecf84d0
ACM
240
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 }
b3c9ac08
ACM
291 if (chain->ms.sym)
292 ret += fprintf(fp, "%s\n", chain->ms.sym->name);
4ecf84d0
ACM
293 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, "[...]");
b3c9ac08 311 rem_hits.ms.sym = rem_sq_bracket;
4ecf84d0
ACM
312}
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 /*
3ad2f3fb 354 * But we keep the older depth mask for the line separator
4ecf84d0
ACM
355 * 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) {
4ecf84d0
ACM
361 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) {
4ecf84d0
ACM
399 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
b3c9ac08
ACM
413 if (chain->ms.sym)
414 ret += fprintf(fp, " %s\n", chain->ms.sym->name);
4ecf84d0
ACM
415 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;
b3c9ac08
ACM
439 if (chain->ms.sym)
440 ret += fprintf(fp, " %s\n", chain->ms.sym->name);
4ecf84d0
ACM
441 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
a4e3b956
ACM
483int hist_entry__snprintf(struct hist_entry *self,
484 char *s, size_t size,
dd2ee78d
ACM
485 struct perf_session *pair_session,
486 bool show_displacement,
a4e3b956 487 long displacement, bool color,
dd2ee78d 488 u64 session_total)
4ecf84d0
ACM
489{
490 struct sort_entry *se;
a1645ce1 491 u64 count, total, count_sys, count_us, count_guest_sys, count_guest_us;
c351c281 492 const char *sep = symbol_conf.field_sep;
a4e3b956 493 int ret;
4ecf84d0
ACM
494
495 if (symbol_conf.exclude_other && !self->parent)
496 return 0;
497
c351c281
ACM
498 if (pair_session) {
499 count = self->pair ? self->pair->count : 0;
500 total = pair_session->events_stats.total;
a1645ce1
ZY
501 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;
c351c281
ACM
505 } else {
506 count = self->count;
eefc465c 507 total = session_total;
a1645ce1
ZY
508 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;
c351c281
ACM
512 }
513
a4e3b956
ACM
514 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);
a1645ce1
ZY
522 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 }
a4e3b956
ACM
542 } else
543 ret = snprintf(s, size, sep ? "%lld" : "%12lld ", count);
4ecf84d0
ACM
544
545 if (symbol_conf.show_nr_samples) {
c351c281 546 if (sep)
a4e3b956 547 ret += snprintf(s + ret, size - ret, "%c%lld", *sep, count);
4ecf84d0 548 else
a4e3b956 549 ret += snprintf(s + ret, size - ret, "%11lld", count);
c351c281
ACM
550 }
551
552 if (pair_session) {
553 char bf[32];
554 double old_percent = 0, new_percent = 0, diff;
555
556 if (total > 0)
9b33827d 557 old_percent = (count * 100.0) / total;
eefc465c
EM
558 if (session_total > 0)
559 new_percent = (self->count * 100.0) / session_total;
c351c281 560
9b33827d 561 diff = new_percent - old_percent;
c351c281 562
9b33827d 563 if (fabs(diff) >= 0.01)
c351c281
ACM
564 snprintf(bf, sizeof(bf), "%+4.2F%%", diff);
565 else
566 snprintf(bf, sizeof(bf), " ");
567
568 if (sep)
a4e3b956 569 ret += snprintf(s + ret, size - ret, "%c%s", *sep, bf);
c351c281 570 else
a4e3b956 571 ret += snprintf(s + ret, size - ret, "%11.11s", bf);
c351c281
ACM
572
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)
a4e3b956 580 ret += snprintf(s + ret, size - ret, "%c%s", *sep, bf);
c351c281 581 else
a4e3b956 582 ret += snprintf(s + ret, size - ret, "%6.6s", bf);
c351c281 583 }
4ecf84d0
ACM
584 }
585
586 list_for_each_entry(se, &hist_entry__sort_list, list) {
587 if (se->elide)
588 continue;
589
a4e3b956 590 ret += snprintf(s + ret, size - ret, "%s", sep ?: " ");
fcd14984
FW
591 ret += se->se_snprintf(self, s + ret, size - ret,
592 se->se_width ? *se->se_width : 0);
4ecf84d0
ACM
593 }
594
a4e3b956
ACM
595 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);
3997d377 609}
4ecf84d0 610
3997d377
ACM
611static size_t hist_entry__fprintf_callchain(struct hist_entry *self, FILE *fp,
612 u64 session_total)
613{
614 int left_margin = 0;
4ecf84d0 615
3997d377
ACM
616 if (sort__first_dimension == SORT_COMM) {
617 struct sort_entry *se = list_first_entry(&hist_entry__sort_list,
618 typeof(*se), list);
fcd14984 619 left_margin = se->se_width ? *se->se_width : 0;
3997d377 620 left_margin -= thread__comm_len(self->thread);
4ecf84d0
ACM
621 }
622
3997d377
ACM
623 return hist_entry_callchain__fprintf(fp, self, session_total,
624 left_margin);
4ecf84d0
ACM
625}
626
eefc465c 627size_t perf_session__fprintf_hists(struct rb_root *hists,
c351c281 628 struct perf_session *pair,
eefc465c
EM
629 bool show_displacement, FILE *fp,
630 u64 session_total)
4ecf84d0 631{
4ecf84d0
ACM
632 struct sort_entry *se;
633 struct rb_node *nd;
634 size_t ret = 0;
c351c281
ACM
635 unsigned long position = 1;
636 long displacement = 0;
4ecf84d0 637 unsigned int width;
c351c281 638 const char *sep = symbol_conf.field_sep;
4ecf84d0
ACM
639 char *col_width = symbol_conf.col_width_list_str;
640
641 init_rem_hits();
642
c351c281
ACM
643 fprintf(fp, "# %s", pair ? "Baseline" : "Overhead");
644
4ecf84d0 645 if (symbol_conf.show_nr_samples) {
c351c281
ACM
646 if (sep)
647 fprintf(fp, "%cSamples", *sep);
4ecf84d0
ACM
648 else
649 fputs(" Samples ", fp);
650 }
c351c281 651
a1645ce1
ZY
652 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
c351c281
ACM
670 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
4ecf84d0
ACM
684 list_for_each_entry(se, &hist_entry__sort_list, list) {
685 if (se->elide)
686 continue;
c351c281 687 if (sep) {
fcd14984 688 fprintf(fp, "%c%s", *sep, se->se_header);
4ecf84d0
ACM
689 continue;
690 }
fcd14984
FW
691 width = strlen(se->se_header);
692 if (se->se_width) {
4ecf84d0
ACM
693 if (symbol_conf.col_width_list_str) {
694 if (col_width) {
fcd14984 695 *se->se_width = atoi(col_width);
4ecf84d0
ACM
696 col_width = strchr(col_width, ',');
697 if (col_width)
698 ++col_width;
699 }
700 }
fcd14984 701 width = *se->se_width = max(*se->se_width, width);
4ecf84d0 702 }
fcd14984 703 fprintf(fp, " %*s", width, se->se_header);
4ecf84d0
ACM
704 }
705 fprintf(fp, "\n");
706
c351c281 707 if (sep)
4ecf84d0
ACM
708 goto print_entries;
709
710 fprintf(fp, "# ........");
711 if (symbol_conf.show_nr_samples)
712 fprintf(fp, " ..........");
c351c281
ACM
713 if (pair) {
714 fprintf(fp, " ..........");
715 if (show_displacement)
716 fprintf(fp, " .....");
717 }
4ecf84d0
ACM
718 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, " ");
fcd14984
FW
725 if (se->se_width)
726 width = *se->se_width;
4ecf84d0 727 else
fcd14984 728 width = strlen(se->se_header);
4ecf84d0
ACM
729 for (i = 0; i < width; i++)
730 fprintf(fp, ".");
731 }
4ecf84d0 732
c351c281 733 fprintf(fp, "\n#\n");
4ecf84d0
ACM
734
735print_entries:
eefc465c 736 for (nd = rb_first(hists); nd; nd = rb_next(nd)) {
c351c281
ACM
737 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 }
eefc465c
EM
747 ret += hist_entry__fprintf(h, pair, show_displacement,
748 displacement, fp, session_total);
3997d377
ACM
749
750 if (symbol_conf.use_callchain)
751 ret += hist_entry__fprintf_callchain(h, fp, session_total);
752
59fd5306 753 if (h->ms.map == NULL && verbose > 1) {
65f2ed2b 754 __map_groups__fprintf_maps(&h->thread->mg,
c6e718ff 755 MAP__FUNCTION, verbose, fp);
65f2ed2b
ACM
756 fprintf(fp, "%.10s end\n", graph_dotted_line);
757 }
4ecf84d0
ACM
758 }
759
4ecf84d0
ACM
760 free(rem_sq_bracket);
761
762 return ret;
763}