]> asedeno.scripts.mit.edu Git - linux.git/blob - tools/perf/ui/stdio/hist.c
Merge tag 'livepatching-for-5.5' of git://git.kernel.org/pub/scm/linux/kernel/git...
[linux.git] / tools / perf / ui / stdio / hist.c
1 // SPDX-License-Identifier: GPL-2.0
2 #include <stdio.h>
3 #include <stdlib.h>
4 #include <linux/string.h>
5
6 #include "../../util/callchain.h"
7 #include "../../util/debug.h"
8 #include "../../util/event.h"
9 #include "../../util/hist.h"
10 #include "../../util/map.h"
11 #include "../../util/map_groups.h"
12 #include "../../util/symbol.h"
13 #include "../../util/sort.h"
14 #include "../../util/evsel.h"
15 #include "../../util/srcline.h"
16 #include "../../util/string2.h"
17 #include "../../util/thread.h"
18 #include <linux/ctype.h>
19 #include <linux/zalloc.h>
20
21 static size_t callchain__fprintf_left_margin(FILE *fp, int left_margin)
22 {
23         int i;
24         int ret = fprintf(fp, "            ");
25
26         for (i = 0; i < left_margin; i++)
27                 ret += fprintf(fp, " ");
28
29         return ret;
30 }
31
32 static size_t ipchain__fprintf_graph_line(FILE *fp, int depth, int depth_mask,
33                                           int left_margin)
34 {
35         int i;
36         size_t ret = callchain__fprintf_left_margin(fp, left_margin);
37
38         for (i = 0; i < depth; i++)
39                 if (depth_mask & (1 << i))
40                         ret += fprintf(fp, "|          ");
41                 else
42                         ret += fprintf(fp, "           ");
43
44         ret += fprintf(fp, "\n");
45
46         return ret;
47 }
48
49 static size_t ipchain__fprintf_graph(FILE *fp, struct callchain_node *node,
50                                      struct callchain_list *chain,
51                                      int depth, int depth_mask, int period,
52                                      u64 total_samples, int left_margin)
53 {
54         int i;
55         size_t ret = 0;
56         char bf[1024], *alloc_str = NULL;
57         char buf[64];
58         const char *str;
59
60         ret += callchain__fprintf_left_margin(fp, left_margin);
61         for (i = 0; i < depth; i++) {
62                 if (depth_mask & (1 << i))
63                         ret += fprintf(fp, "|");
64                 else
65                         ret += fprintf(fp, " ");
66                 if (!period && i == depth - 1) {
67                         ret += fprintf(fp, "--");
68                         ret += callchain_node__fprintf_value(node, fp, total_samples);
69                         ret += fprintf(fp, "--");
70                 } else
71                         ret += fprintf(fp, "%s", "          ");
72         }
73
74         str = callchain_list__sym_name(chain, bf, sizeof(bf), false);
75
76         if (symbol_conf.show_branchflag_count) {
77                 callchain_list_counts__printf_value(chain, NULL,
78                                                     buf, sizeof(buf));
79
80                 if (asprintf(&alloc_str, "%s%s", str, buf) < 0)
81                         str = "Not enough memory!";
82                 else
83                         str = alloc_str;
84         }
85
86         fputs(str, fp);
87         fputc('\n', fp);
88         free(alloc_str);
89
90         return ret;
91 }
92
93 static struct symbol *rem_sq_bracket;
94 static struct callchain_list rem_hits;
95
96 static void init_rem_hits(void)
97 {
98         rem_sq_bracket = malloc(sizeof(*rem_sq_bracket) + 6);
99         if (!rem_sq_bracket) {
100                 fprintf(stderr, "Not enough memory to display remaining hits\n");
101                 return;
102         }
103
104         strcpy(rem_sq_bracket->name, "[...]");
105         rem_hits.ms.sym = rem_sq_bracket;
106 }
107
108 static size_t __callchain__fprintf_graph(FILE *fp, struct rb_root *root,
109                                          u64 total_samples, int depth,
110                                          int depth_mask, int left_margin)
111 {
112         struct rb_node *node, *next;
113         struct callchain_node *child = NULL;
114         struct callchain_list *chain;
115         int new_depth_mask = depth_mask;
116         u64 remaining;
117         size_t ret = 0;
118         int i;
119         uint entries_printed = 0;
120         int cumul_count = 0;
121
122         remaining = total_samples;
123
124         node = rb_first(root);
125         while (node) {
126                 u64 new_total;
127                 u64 cumul;
128
129                 child = rb_entry(node, struct callchain_node, rb_node);
130                 cumul = callchain_cumul_hits(child);
131                 remaining -= cumul;
132                 cumul_count += callchain_cumul_counts(child);
133
134                 /*
135                  * The depth mask manages the output of pipes that show
136                  * the depth. We don't want to keep the pipes of the current
137                  * level for the last child of this depth.
138                  * Except if we have remaining filtered hits. They will
139                  * supersede the last child
140                  */
141                 next = rb_next(node);
142                 if (!next && (callchain_param.mode != CHAIN_GRAPH_REL || !remaining))
143                         new_depth_mask &= ~(1 << (depth - 1));
144
145                 /*
146                  * But we keep the older depth mask for the line separator
147                  * to keep the level link until we reach the last child
148                  */
149                 ret += ipchain__fprintf_graph_line(fp, depth, depth_mask,
150                                                    left_margin);
151                 i = 0;
152                 list_for_each_entry(chain, &child->val, list) {
153                         ret += ipchain__fprintf_graph(fp, child, chain, depth,
154                                                       new_depth_mask, i++,
155                                                       total_samples,
156                                                       left_margin);
157                 }
158
159                 if (callchain_param.mode == CHAIN_GRAPH_REL)
160                         new_total = child->children_hit;
161                 else
162                         new_total = total_samples;
163
164                 ret += __callchain__fprintf_graph(fp, &child->rb_root, new_total,
165                                                   depth + 1,
166                                                   new_depth_mask | (1 << depth),
167                                                   left_margin);
168                 node = next;
169                 if (++entries_printed == callchain_param.print_limit)
170                         break;
171         }
172
173         if (callchain_param.mode == CHAIN_GRAPH_REL &&
174                 remaining && remaining != total_samples) {
175                 struct callchain_node rem_node = {
176                         .hit = remaining,
177                 };
178
179                 if (!rem_sq_bracket)
180                         return ret;
181
182                 if (callchain_param.value == CCVAL_COUNT && child && child->parent) {
183                         rem_node.count = child->parent->children_count - cumul_count;
184                         if (rem_node.count <= 0)
185                                 return ret;
186                 }
187
188                 new_depth_mask &= ~(1 << (depth - 1));
189                 ret += ipchain__fprintf_graph(fp, &rem_node, &rem_hits, depth,
190                                               new_depth_mask, 0, total_samples,
191                                               left_margin);
192         }
193
194         return ret;
195 }
196
197 /*
198  * If have one single callchain root, don't bother printing
199  * its percentage (100 % in fractal mode and the same percentage
200  * than the hist in graph mode). This also avoid one level of column.
201  *
202  * However when percent-limit applied, it's possible that single callchain
203  * node have different (non-100% in fractal mode) percentage.
204  */
205 static bool need_percent_display(struct rb_node *node, u64 parent_samples)
206 {
207         struct callchain_node *cnode;
208
209         if (rb_next(node))
210                 return true;
211
212         cnode = rb_entry(node, struct callchain_node, rb_node);
213         return callchain_cumul_hits(cnode) != parent_samples;
214 }
215
216 static size_t callchain__fprintf_graph(FILE *fp, struct rb_root *root,
217                                        u64 total_samples, u64 parent_samples,
218                                        int left_margin)
219 {
220         struct callchain_node *cnode;
221         struct callchain_list *chain;
222         u32 entries_printed = 0;
223         bool printed = false;
224         struct rb_node *node;
225         int i = 0;
226         int ret = 0;
227         char bf[1024];
228
229         node = rb_first(root);
230         if (node && !need_percent_display(node, parent_samples)) {
231                 cnode = rb_entry(node, struct callchain_node, rb_node);
232                 list_for_each_entry(chain, &cnode->val, list) {
233                         /*
234                          * If we sort by symbol, the first entry is the same than
235                          * the symbol. No need to print it otherwise it appears as
236                          * displayed twice.
237                          */
238                         if (!i++ && field_order == NULL &&
239                             sort_order && strstarts(sort_order, "sym"))
240                                 continue;
241
242                         if (!printed) {
243                                 ret += callchain__fprintf_left_margin(fp, left_margin);
244                                 ret += fprintf(fp, "|\n");
245                                 ret += callchain__fprintf_left_margin(fp, left_margin);
246                                 ret += fprintf(fp, "---");
247                                 left_margin += 3;
248                                 printed = true;
249                         } else
250                                 ret += callchain__fprintf_left_margin(fp, left_margin);
251
252                         ret += fprintf(fp, "%s",
253                                        callchain_list__sym_name(chain, bf,
254                                                                 sizeof(bf),
255                                                                 false));
256
257                         if (symbol_conf.show_branchflag_count)
258                                 ret += callchain_list_counts__printf_value(
259                                                 chain, fp, NULL, 0);
260                         ret += fprintf(fp, "\n");
261
262                         if (++entries_printed == callchain_param.print_limit)
263                                 break;
264                 }
265                 root = &cnode->rb_root;
266         }
267
268         if (callchain_param.mode == CHAIN_GRAPH_REL)
269                 total_samples = parent_samples;
270
271         ret += __callchain__fprintf_graph(fp, root, total_samples,
272                                           1, 1, left_margin);
273         if (ret) {
274                 /* do not add a blank line if it printed nothing */
275                 ret += fprintf(fp, "\n");
276         }
277
278         return ret;
279 }
280
281 static size_t __callchain__fprintf_flat(FILE *fp, struct callchain_node *node,
282                                         u64 total_samples)
283 {
284         struct callchain_list *chain;
285         size_t ret = 0;
286         char bf[1024];
287
288         if (!node)
289                 return 0;
290
291         ret += __callchain__fprintf_flat(fp, node->parent, total_samples);
292
293
294         list_for_each_entry(chain, &node->val, list) {
295                 if (chain->ip >= PERF_CONTEXT_MAX)
296                         continue;
297                 ret += fprintf(fp, "                %s\n", callchain_list__sym_name(chain,
298                                         bf, sizeof(bf), false));
299         }
300
301         return ret;
302 }
303
304 static size_t callchain__fprintf_flat(FILE *fp, struct rb_root *tree,
305                                       u64 total_samples)
306 {
307         size_t ret = 0;
308         u32 entries_printed = 0;
309         struct callchain_node *chain;
310         struct rb_node *rb_node = rb_first(tree);
311
312         while (rb_node) {
313                 chain = rb_entry(rb_node, struct callchain_node, rb_node);
314
315                 ret += fprintf(fp, "           ");
316                 ret += callchain_node__fprintf_value(chain, fp, total_samples);
317                 ret += fprintf(fp, "\n");
318                 ret += __callchain__fprintf_flat(fp, chain, total_samples);
319                 ret += fprintf(fp, "\n");
320                 if (++entries_printed == callchain_param.print_limit)
321                         break;
322
323                 rb_node = rb_next(rb_node);
324         }
325
326         return ret;
327 }
328
329 static size_t __callchain__fprintf_folded(FILE *fp, struct callchain_node *node)
330 {
331         const char *sep = symbol_conf.field_sep ?: ";";
332         struct callchain_list *chain;
333         size_t ret = 0;
334         char bf[1024];
335         bool first;
336
337         if (!node)
338                 return 0;
339
340         ret += __callchain__fprintf_folded(fp, node->parent);
341
342         first = (ret == 0);
343         list_for_each_entry(chain, &node->val, list) {
344                 if (chain->ip >= PERF_CONTEXT_MAX)
345                         continue;
346                 ret += fprintf(fp, "%s%s", first ? "" : sep,
347                                callchain_list__sym_name(chain,
348                                                 bf, sizeof(bf), false));
349                 first = false;
350         }
351
352         return ret;
353 }
354
355 static size_t callchain__fprintf_folded(FILE *fp, struct rb_root *tree,
356                                         u64 total_samples)
357 {
358         size_t ret = 0;
359         u32 entries_printed = 0;
360         struct callchain_node *chain;
361         struct rb_node *rb_node = rb_first(tree);
362
363         while (rb_node) {
364
365                 chain = rb_entry(rb_node, struct callchain_node, rb_node);
366
367                 ret += callchain_node__fprintf_value(chain, fp, total_samples);
368                 ret += fprintf(fp, " ");
369                 ret += __callchain__fprintf_folded(fp, chain);
370                 ret += fprintf(fp, "\n");
371                 if (++entries_printed == callchain_param.print_limit)
372                         break;
373
374                 rb_node = rb_next(rb_node);
375         }
376
377         return ret;
378 }
379
380 static size_t hist_entry_callchain__fprintf(struct hist_entry *he,
381                                             u64 total_samples, int left_margin,
382                                             FILE *fp)
383 {
384         u64 parent_samples = he->stat.period;
385
386         if (symbol_conf.cumulate_callchain)
387                 parent_samples = he->stat_acc->period;
388
389         switch (callchain_param.mode) {
390         case CHAIN_GRAPH_REL:
391                 return callchain__fprintf_graph(fp, &he->sorted_chain, total_samples,
392                                                 parent_samples, left_margin);
393                 break;
394         case CHAIN_GRAPH_ABS:
395                 return callchain__fprintf_graph(fp, &he->sorted_chain, total_samples,
396                                                 parent_samples, left_margin);
397                 break;
398         case CHAIN_FLAT:
399                 return callchain__fprintf_flat(fp, &he->sorted_chain, total_samples);
400                 break;
401         case CHAIN_FOLDED:
402                 return callchain__fprintf_folded(fp, &he->sorted_chain, total_samples);
403                 break;
404         case CHAIN_NONE:
405                 break;
406         default:
407                 pr_err("Bad callchain mode\n");
408         }
409
410         return 0;
411 }
412
413 int __hist_entry__snprintf(struct hist_entry *he, struct perf_hpp *hpp,
414                            struct perf_hpp_list *hpp_list)
415 {
416         const char *sep = symbol_conf.field_sep;
417         struct perf_hpp_fmt *fmt;
418         char *start = hpp->buf;
419         int ret;
420         bool first = true;
421
422         if (symbol_conf.exclude_other && !he->parent)
423                 return 0;
424
425         perf_hpp_list__for_each_format(hpp_list, fmt) {
426                 if (perf_hpp__should_skip(fmt, he->hists))
427                         continue;
428
429                 /*
430                  * If there's no field_sep, we still need
431                  * to display initial '  '.
432                  */
433                 if (!sep || !first) {
434                         ret = scnprintf(hpp->buf, hpp->size, "%s", sep ?: "  ");
435                         advance_hpp(hpp, ret);
436                 } else
437                         first = false;
438
439                 if (perf_hpp__use_color() && fmt->color)
440                         ret = fmt->color(fmt, hpp, he);
441                 else
442                         ret = fmt->entry(fmt, hpp, he);
443
444                 ret = hist_entry__snprintf_alignment(he, hpp, fmt, ret);
445                 advance_hpp(hpp, ret);
446         }
447
448         return hpp->buf - start;
449 }
450
451 static int hist_entry__snprintf(struct hist_entry *he, struct perf_hpp *hpp)
452 {
453         return __hist_entry__snprintf(he, hpp, he->hists->hpp_list);
454 }
455
456 static int hist_entry__hierarchy_fprintf(struct hist_entry *he,
457                                          struct perf_hpp *hpp,
458                                          struct hists *hists,
459                                          FILE *fp)
460 {
461         const char *sep = symbol_conf.field_sep;
462         struct perf_hpp_fmt *fmt;
463         struct perf_hpp_list_node *fmt_node;
464         char *buf = hpp->buf;
465         size_t size = hpp->size;
466         int ret, printed = 0;
467         bool first = true;
468
469         if (symbol_conf.exclude_other && !he->parent)
470                 return 0;
471
472         ret = scnprintf(hpp->buf, hpp->size, "%*s", he->depth * HIERARCHY_INDENT, "");
473         advance_hpp(hpp, ret);
474
475         /* the first hpp_list_node is for overhead columns */
476         fmt_node = list_first_entry(&hists->hpp_formats,
477                                     struct perf_hpp_list_node, list);
478         perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) {
479                 /*
480                  * If there's no field_sep, we still need
481                  * to display initial '  '.
482                  */
483                 if (!sep || !first) {
484                         ret = scnprintf(hpp->buf, hpp->size, "%s", sep ?: "  ");
485                         advance_hpp(hpp, ret);
486                 } else
487                         first = false;
488
489                 if (perf_hpp__use_color() && fmt->color)
490                         ret = fmt->color(fmt, hpp, he);
491                 else
492                         ret = fmt->entry(fmt, hpp, he);
493
494                 ret = hist_entry__snprintf_alignment(he, hpp, fmt, ret);
495                 advance_hpp(hpp, ret);
496         }
497
498         if (!sep)
499                 ret = scnprintf(hpp->buf, hpp->size, "%*s",
500                                 (hists->nr_hpp_node - 2) * HIERARCHY_INDENT, "");
501         advance_hpp(hpp, ret);
502
503         printed += fprintf(fp, "%s", buf);
504
505         perf_hpp_list__for_each_format(he->hpp_list, fmt) {
506                 hpp->buf  = buf;
507                 hpp->size = size;
508
509                 /*
510                  * No need to call hist_entry__snprintf_alignment() since this
511                  * fmt is always the last column in the hierarchy mode.
512                  */
513                 if (perf_hpp__use_color() && fmt->color)
514                         fmt->color(fmt, hpp, he);
515                 else
516                         fmt->entry(fmt, hpp, he);
517
518                 /*
519                  * dynamic entries are right-aligned but we want left-aligned
520                  * in the hierarchy mode
521                  */
522                 printed += fprintf(fp, "%s%s", sep ?: "  ", skip_spaces(buf));
523         }
524         printed += putc('\n', fp);
525
526         if (he->leaf && hist_entry__has_callchains(he) && symbol_conf.use_callchain) {
527                 u64 total = hists__total_period(hists);
528
529                 printed += hist_entry_callchain__fprintf(he, total, 0, fp);
530                 goto out;
531         }
532
533 out:
534         return printed;
535 }
536
537 static int hist_entry__block_fprintf(struct hist_entry *he,
538                                      char *bf, size_t size,
539                                      FILE *fp)
540 {
541         struct block_hist *bh = container_of(he, struct block_hist, he);
542         int ret = 0;
543
544         for (unsigned int i = 0; i < bh->block_hists.nr_entries; i++) {
545                 struct perf_hpp hpp = {
546                         .buf            = bf,
547                         .size           = size,
548                         .skip           = false,
549                 };
550
551                 bh->block_idx = i;
552                 hist_entry__snprintf(he, &hpp);
553
554                 if (!hpp.skip)
555                         ret += fprintf(fp, "%s\n", bf);
556         }
557
558         return ret;
559 }
560
561 static int hist_entry__fprintf(struct hist_entry *he, size_t size,
562                                char *bf, size_t bfsz, FILE *fp,
563                                bool ignore_callchains)
564 {
565         int ret;
566         int callchain_ret = 0;
567         struct perf_hpp hpp = {
568                 .buf            = bf,
569                 .size           = size,
570         };
571         struct hists *hists = he->hists;
572         u64 total_period = hists->stats.total_period;
573
574         if (size == 0 || size > bfsz)
575                 size = hpp.size = bfsz;
576
577         if (symbol_conf.report_hierarchy)
578                 return hist_entry__hierarchy_fprintf(he, &hpp, hists, fp);
579
580         if (symbol_conf.report_block)
581                 return hist_entry__block_fprintf(he, bf, size, fp);
582
583         hist_entry__snprintf(he, &hpp);
584
585         ret = fprintf(fp, "%s\n", bf);
586
587         if (hist_entry__has_callchains(he) && !ignore_callchains)
588                 callchain_ret = hist_entry_callchain__fprintf(he, total_period,
589                                                               0, fp);
590
591         ret += callchain_ret;
592
593         return ret;
594 }
595
596 static int print_hierarchy_indent(const char *sep, int indent,
597                                   const char *line, FILE *fp)
598 {
599         int width;
600
601         if (sep != NULL || indent < 2)
602                 return 0;
603
604         width = (indent - 2) * HIERARCHY_INDENT;
605
606         return fprintf(fp, "%-*.*s", width, width, line);
607 }
608
609 static int hists__fprintf_hierarchy_headers(struct hists *hists,
610                                             struct perf_hpp *hpp, FILE *fp)
611 {
612         bool first_node, first_col;
613         int indent;
614         int depth;
615         unsigned width = 0;
616         unsigned header_width = 0;
617         struct perf_hpp_fmt *fmt;
618         struct perf_hpp_list_node *fmt_node;
619         const char *sep = symbol_conf.field_sep;
620
621         indent = hists->nr_hpp_node;
622
623         /* preserve max indent depth for column headers */
624         print_hierarchy_indent(sep, indent, " ", fp);
625
626         /* the first hpp_list_node is for overhead columns */
627         fmt_node = list_first_entry(&hists->hpp_formats,
628                                     struct perf_hpp_list_node, list);
629
630         perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) {
631                 fmt->header(fmt, hpp, hists, 0, NULL);
632                 fprintf(fp, "%s%s", hpp->buf, sep ?: "  ");
633         }
634
635         /* combine sort headers with ' / ' */
636         first_node = true;
637         list_for_each_entry_continue(fmt_node, &hists->hpp_formats, list) {
638                 if (!first_node)
639                         header_width += fprintf(fp, " / ");
640                 first_node = false;
641
642                 first_col = true;
643                 perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) {
644                         if (perf_hpp__should_skip(fmt, hists))
645                                 continue;
646
647                         if (!first_col)
648                                 header_width += fprintf(fp, "+");
649                         first_col = false;
650
651                         fmt->header(fmt, hpp, hists, 0, NULL);
652
653                         header_width += fprintf(fp, "%s", strim(hpp->buf));
654                 }
655         }
656
657         fprintf(fp, "\n# ");
658
659         /* preserve max indent depth for initial dots */
660         print_hierarchy_indent(sep, indent, dots, fp);
661
662         /* the first hpp_list_node is for overhead columns */
663         fmt_node = list_first_entry(&hists->hpp_formats,
664                                     struct perf_hpp_list_node, list);
665
666         first_col = true;
667         perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) {
668                 if (!first_col)
669                         fprintf(fp, "%s", sep ?: "..");
670                 first_col = false;
671
672                 width = fmt->width(fmt, hpp, hists);
673                 fprintf(fp, "%.*s", width, dots);
674         }
675
676         depth = 0;
677         list_for_each_entry_continue(fmt_node, &hists->hpp_formats, list) {
678                 first_col = true;
679                 width = depth * HIERARCHY_INDENT;
680
681                 perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) {
682                         if (perf_hpp__should_skip(fmt, hists))
683                                 continue;
684
685                         if (!first_col)
686                                 width++;  /* for '+' sign between column header */
687                         first_col = false;
688
689                         width += fmt->width(fmt, hpp, hists);
690                 }
691
692                 if (width > header_width)
693                         header_width = width;
694
695                 depth++;
696         }
697
698         fprintf(fp, "%s%-.*s", sep ?: "  ", header_width, dots);
699
700         fprintf(fp, "\n#\n");
701
702         return 2;
703 }
704
705 static void fprintf_line(struct hists *hists, struct perf_hpp *hpp,
706                          int line, FILE *fp)
707 {
708         struct perf_hpp_fmt *fmt;
709         const char *sep = symbol_conf.field_sep;
710         bool first = true;
711         int span = 0;
712
713         hists__for_each_format(hists, fmt) {
714                 if (perf_hpp__should_skip(fmt, hists))
715                         continue;
716
717                 if (!first && !span)
718                         fprintf(fp, "%s", sep ?: "  ");
719                 else
720                         first = false;
721
722                 fmt->header(fmt, hpp, hists, line, &span);
723
724                 if (!span)
725                         fprintf(fp, "%s", hpp->buf);
726         }
727 }
728
729 static int
730 hists__fprintf_standard_headers(struct hists *hists,
731                                 struct perf_hpp *hpp,
732                                 FILE *fp)
733 {
734         struct perf_hpp_list *hpp_list = hists->hpp_list;
735         struct perf_hpp_fmt *fmt;
736         unsigned int width;
737         const char *sep = symbol_conf.field_sep;
738         bool first = true;
739         int line;
740
741         for (line = 0; line < hpp_list->nr_header_lines; line++) {
742                 /* first # is displayed one level up */
743                 if (line)
744                         fprintf(fp, "# ");
745                 fprintf_line(hists, hpp, line, fp);
746                 fprintf(fp, "\n");
747         }
748
749         if (sep)
750                 return hpp_list->nr_header_lines;
751
752         first = true;
753
754         fprintf(fp, "# ");
755
756         hists__for_each_format(hists, fmt) {
757                 unsigned int i;
758
759                 if (perf_hpp__should_skip(fmt, hists))
760                         continue;
761
762                 if (!first)
763                         fprintf(fp, "%s", sep ?: "  ");
764                 else
765                         first = false;
766
767                 width = fmt->width(fmt, hpp, hists);
768                 for (i = 0; i < width; i++)
769                         fprintf(fp, ".");
770         }
771
772         fprintf(fp, "\n");
773         fprintf(fp, "#\n");
774         return hpp_list->nr_header_lines + 2;
775 }
776
777 int hists__fprintf_headers(struct hists *hists, FILE *fp)
778 {
779         char bf[1024];
780         struct perf_hpp dummy_hpp = {
781                 .buf    = bf,
782                 .size   = sizeof(bf),
783         };
784
785         fprintf(fp, "# ");
786
787         if (symbol_conf.report_hierarchy)
788                 return hists__fprintf_hierarchy_headers(hists, &dummy_hpp, fp);
789         else
790                 return hists__fprintf_standard_headers(hists, &dummy_hpp, fp);
791
792 }
793
794 size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows,
795                       int max_cols, float min_pcnt, FILE *fp,
796                       bool ignore_callchains)
797 {
798         struct rb_node *nd;
799         size_t ret = 0;
800         const char *sep = symbol_conf.field_sep;
801         int nr_rows = 0;
802         size_t linesz;
803         char *line = NULL;
804         unsigned indent;
805
806         init_rem_hits();
807
808         hists__reset_column_width(hists);
809
810         if (symbol_conf.col_width_list_str)
811                 perf_hpp__set_user_width(symbol_conf.col_width_list_str);
812
813         if (show_header)
814                 nr_rows += hists__fprintf_headers(hists, fp);
815
816         if (max_rows && nr_rows >= max_rows)
817                 goto out;
818
819         linesz = hists__sort_list_width(hists) + 3 + 1;
820         linesz += perf_hpp__color_overhead();
821         line = malloc(linesz);
822         if (line == NULL) {
823                 ret = -1;
824                 goto out;
825         }
826
827         indent = hists__overhead_width(hists) + 4;
828
829         for (nd = rb_first_cached(&hists->entries); nd;
830              nd = __rb_hierarchy_next(nd, HMD_FORCE_CHILD)) {
831                 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
832                 float percent;
833
834                 if (h->filtered)
835                         continue;
836
837                 percent = hist_entry__get_percent_limit(h);
838                 if (percent < min_pcnt)
839                         continue;
840
841                 ret += hist_entry__fprintf(h, max_cols, line, linesz, fp, ignore_callchains);
842
843                 if (max_rows && ++nr_rows >= max_rows)
844                         break;
845
846                 /*
847                  * If all children are filtered out or percent-limited,
848                  * display "no entry >= x.xx%" message.
849                  */
850                 if (!h->leaf && !hist_entry__has_hierarchy_children(h, min_pcnt)) {
851                         int depth = hists->nr_hpp_node + h->depth + 1;
852
853                         print_hierarchy_indent(sep, depth, " ", fp);
854                         fprintf(fp, "%*sno entry >= %.2f%%\n", indent, "", min_pcnt);
855
856                         if (max_rows && ++nr_rows >= max_rows)
857                                 break;
858                 }
859
860                 if (h->ms.map == NULL && verbose > 1) {
861                         map_groups__fprintf(h->thread->mg, fp);
862                         fprintf(fp, "%.10s end\n", graph_dotted_line);
863                 }
864         }
865
866         free(line);
867 out:
868         zfree(&rem_sq_bracket);
869
870         return ret;
871 }
872
873 size_t events_stats__fprintf(struct events_stats *stats, FILE *fp)
874 {
875         int i;
876         size_t ret = 0;
877
878         for (i = 0; i < PERF_RECORD_HEADER_MAX; ++i) {
879                 const char *name;
880
881                 name = perf_event__name(i);
882                 if (!strcmp(name, "UNKNOWN"))
883                         continue;
884
885                 ret += fprintf(fp, "%16s events: %10d\n", name, stats->nr_events[i]);
886         }
887
888         return ret;
889 }