]>
git.proxmox.com Git - mirror_ubuntu-jammy-kernel.git/blob - tools/perf/ui/stdio/hist.c
1 // SPDX-License-Identifier: GPL-2.0
3 #include <linux/string.h>
5 #include "../../util/util.h"
6 #include "../../util/hist.h"
7 #include "../../util/sort.h"
8 #include "../../util/evsel.h"
9 #include "../../util/srcline.h"
10 #include "../../util/string2.h"
11 #include "../../util/thread.h"
12 #include "../../util/sane_ctype.h"
14 static size_t callchain__fprintf_left_margin(FILE *fp
, int left_margin
)
17 int ret
= fprintf(fp
, " ");
19 for (i
= 0; i
< left_margin
; i
++)
20 ret
+= fprintf(fp
, " ");
25 static size_t inline__fprintf(struct map
*map
, u64 ip
, int left_margin
,
26 int depth
, int depth_mask
, FILE *fp
)
29 struct inline_node
*node
;
30 struct inline_list
*ilist
;
40 node
= dso__parse_addr_inlines(dso
,
41 map__rip_2objdump(map
, ip
));
45 list_for_each_entry(ilist
, &node
->val
, list
) {
46 if ((ilist
->filename
!= NULL
) || (ilist
->funcname
!= NULL
)) {
47 ret
+= callchain__fprintf_left_margin(fp
, left_margin
);
49 for (i
= 0; i
< depth
; i
++) {
50 if (depth_mask
& (1 << i
))
51 ret
+= fprintf(fp
, "|");
53 ret
+= fprintf(fp
, " ");
54 ret
+= fprintf(fp
, " ");
57 if (callchain_param
.key
== CCKEY_ADDRESS
||
58 callchain_param
.key
== CCKEY_SRCLINE
) {
59 if (ilist
->filename
!= NULL
)
60 ret
+= fprintf(fp
, "%s:%d (inline)",
64 ret
+= fprintf(fp
, "??");
65 } else if (ilist
->funcname
!= NULL
)
66 ret
+= fprintf(fp
, "%s (inline)",
68 else if (ilist
->filename
!= NULL
)
69 ret
+= fprintf(fp
, "%s:%d (inline)",
73 ret
+= fprintf(fp
, "??");
75 ret
+= fprintf(fp
, "\n");
79 inline_node__delete(node
);
83 static size_t ipchain__fprintf_graph_line(FILE *fp
, int depth
, int depth_mask
,
87 size_t ret
= callchain__fprintf_left_margin(fp
, left_margin
);
89 for (i
= 0; i
< depth
; i
++)
90 if (depth_mask
& (1 << i
))
91 ret
+= fprintf(fp
, "| ");
93 ret
+= fprintf(fp
, " ");
95 ret
+= fprintf(fp
, "\n");
100 static size_t ipchain__fprintf_graph(FILE *fp
, struct callchain_node
*node
,
101 struct callchain_list
*chain
,
102 int depth
, int depth_mask
, int period
,
103 u64 total_samples
, int left_margin
)
107 char bf
[1024], *alloc_str
= NULL
;
111 ret
+= callchain__fprintf_left_margin(fp
, left_margin
);
112 for (i
= 0; i
< depth
; i
++) {
113 if (depth_mask
& (1 << i
))
114 ret
+= fprintf(fp
, "|");
116 ret
+= fprintf(fp
, " ");
117 if (!period
&& i
== depth
- 1) {
118 ret
+= fprintf(fp
, "--");
119 ret
+= callchain_node__fprintf_value(node
, fp
, total_samples
);
120 ret
+= fprintf(fp
, "--");
122 ret
+= fprintf(fp
, "%s", " ");
125 str
= callchain_list__sym_name(chain
, bf
, sizeof(bf
), false);
127 if (symbol_conf
.show_branchflag_count
) {
128 callchain_list_counts__printf_value(chain
, NULL
,
131 if (asprintf(&alloc_str
, "%s%s", str
, buf
) < 0)
132 str
= "Not enough memory!";
141 if (symbol_conf
.inline_name
)
142 ret
+= inline__fprintf(chain
->ms
.map
, chain
->ip
,
143 left_margin
, depth
, depth_mask
, fp
);
147 static struct symbol
*rem_sq_bracket
;
148 static struct callchain_list rem_hits
;
150 static void init_rem_hits(void)
152 rem_sq_bracket
= malloc(sizeof(*rem_sq_bracket
) + 6);
153 if (!rem_sq_bracket
) {
154 fprintf(stderr
, "Not enough memory to display remaining hits\n");
158 strcpy(rem_sq_bracket
->name
, "[...]");
159 rem_hits
.ms
.sym
= rem_sq_bracket
;
162 static size_t __callchain__fprintf_graph(FILE *fp
, struct rb_root
*root
,
163 u64 total_samples
, int depth
,
164 int depth_mask
, int left_margin
)
166 struct rb_node
*node
, *next
;
167 struct callchain_node
*child
= NULL
;
168 struct callchain_list
*chain
;
169 int new_depth_mask
= depth_mask
;
173 uint entries_printed
= 0;
176 remaining
= total_samples
;
178 node
= rb_first(root
);
183 child
= rb_entry(node
, struct callchain_node
, rb_node
);
184 cumul
= callchain_cumul_hits(child
);
186 cumul_count
+= callchain_cumul_counts(child
);
189 * The depth mask manages the output of pipes that show
190 * the depth. We don't want to keep the pipes of the current
191 * level for the last child of this depth.
192 * Except if we have remaining filtered hits. They will
193 * supersede the last child
195 next
= rb_next(node
);
196 if (!next
&& (callchain_param
.mode
!= CHAIN_GRAPH_REL
|| !remaining
))
197 new_depth_mask
&= ~(1 << (depth
- 1));
200 * But we keep the older depth mask for the line separator
201 * to keep the level link until we reach the last child
203 ret
+= ipchain__fprintf_graph_line(fp
, depth
, depth_mask
,
206 list_for_each_entry(chain
, &child
->val
, list
) {
207 ret
+= ipchain__fprintf_graph(fp
, child
, chain
, depth
,
213 if (callchain_param
.mode
== CHAIN_GRAPH_REL
)
214 new_total
= child
->children_hit
;
216 new_total
= total_samples
;
218 ret
+= __callchain__fprintf_graph(fp
, &child
->rb_root
, new_total
,
220 new_depth_mask
| (1 << depth
),
223 if (++entries_printed
== callchain_param
.print_limit
)
227 if (callchain_param
.mode
== CHAIN_GRAPH_REL
&&
228 remaining
&& remaining
!= total_samples
) {
229 struct callchain_node rem_node
= {
236 if (callchain_param
.value
== CCVAL_COUNT
&& child
&& child
->parent
) {
237 rem_node
.count
= child
->parent
->children_count
- cumul_count
;
238 if (rem_node
.count
<= 0)
242 new_depth_mask
&= ~(1 << (depth
- 1));
243 ret
+= ipchain__fprintf_graph(fp
, &rem_node
, &rem_hits
, depth
,
244 new_depth_mask
, 0, total_samples
,
252 * If have one single callchain root, don't bother printing
253 * its percentage (100 % in fractal mode and the same percentage
254 * than the hist in graph mode). This also avoid one level of column.
256 * However when percent-limit applied, it's possible that single callchain
257 * node have different (non-100% in fractal mode) percentage.
259 static bool need_percent_display(struct rb_node
*node
, u64 parent_samples
)
261 struct callchain_node
*cnode
;
266 cnode
= rb_entry(node
, struct callchain_node
, rb_node
);
267 return callchain_cumul_hits(cnode
) != parent_samples
;
270 static size_t callchain__fprintf_graph(FILE *fp
, struct rb_root
*root
,
271 u64 total_samples
, u64 parent_samples
,
274 struct callchain_node
*cnode
;
275 struct callchain_list
*chain
;
276 u32 entries_printed
= 0;
277 bool printed
= false;
278 struct rb_node
*node
;
283 node
= rb_first(root
);
284 if (node
&& !need_percent_display(node
, parent_samples
)) {
285 cnode
= rb_entry(node
, struct callchain_node
, rb_node
);
286 list_for_each_entry(chain
, &cnode
->val
, list
) {
288 * If we sort by symbol, the first entry is the same than
289 * the symbol. No need to print it otherwise it appears as
292 if (!i
++ && field_order
== NULL
&&
293 sort_order
&& strstarts(sort_order
, "sym"))
297 ret
+= callchain__fprintf_left_margin(fp
, left_margin
);
298 ret
+= fprintf(fp
, "|\n");
299 ret
+= callchain__fprintf_left_margin(fp
, left_margin
);
300 ret
+= fprintf(fp
, "---");
304 ret
+= callchain__fprintf_left_margin(fp
, left_margin
);
306 ret
+= fprintf(fp
, "%s",
307 callchain_list__sym_name(chain
, bf
,
311 if (symbol_conf
.show_branchflag_count
)
312 ret
+= callchain_list_counts__printf_value(
314 ret
+= fprintf(fp
, "\n");
316 if (++entries_printed
== callchain_param
.print_limit
)
319 if (symbol_conf
.inline_name
)
320 ret
+= inline__fprintf(chain
->ms
.map
,
326 root
= &cnode
->rb_root
;
329 if (callchain_param
.mode
== CHAIN_GRAPH_REL
)
330 total_samples
= parent_samples
;
332 ret
+= __callchain__fprintf_graph(fp
, root
, total_samples
,
335 /* do not add a blank line if it printed nothing */
336 ret
+= fprintf(fp
, "\n");
342 static size_t __callchain__fprintf_flat(FILE *fp
, struct callchain_node
*node
,
345 struct callchain_list
*chain
;
352 ret
+= __callchain__fprintf_flat(fp
, node
->parent
, total_samples
);
355 list_for_each_entry(chain
, &node
->val
, list
) {
356 if (chain
->ip
>= PERF_CONTEXT_MAX
)
358 ret
+= fprintf(fp
, " %s\n", callchain_list__sym_name(chain
,
359 bf
, sizeof(bf
), false));
365 static size_t callchain__fprintf_flat(FILE *fp
, struct rb_root
*tree
,
369 u32 entries_printed
= 0;
370 struct callchain_node
*chain
;
371 struct rb_node
*rb_node
= rb_first(tree
);
374 chain
= rb_entry(rb_node
, struct callchain_node
, rb_node
);
376 ret
+= fprintf(fp
, " ");
377 ret
+= callchain_node__fprintf_value(chain
, fp
, total_samples
);
378 ret
+= fprintf(fp
, "\n");
379 ret
+= __callchain__fprintf_flat(fp
, chain
, total_samples
);
380 ret
+= fprintf(fp
, "\n");
381 if (++entries_printed
== callchain_param
.print_limit
)
384 rb_node
= rb_next(rb_node
);
390 static size_t __callchain__fprintf_folded(FILE *fp
, struct callchain_node
*node
)
392 const char *sep
= symbol_conf
.field_sep
?: ";";
393 struct callchain_list
*chain
;
401 ret
+= __callchain__fprintf_folded(fp
, node
->parent
);
404 list_for_each_entry(chain
, &node
->val
, list
) {
405 if (chain
->ip
>= PERF_CONTEXT_MAX
)
407 ret
+= fprintf(fp
, "%s%s", first
? "" : sep
,
408 callchain_list__sym_name(chain
,
409 bf
, sizeof(bf
), false));
416 static size_t callchain__fprintf_folded(FILE *fp
, struct rb_root
*tree
,
420 u32 entries_printed
= 0;
421 struct callchain_node
*chain
;
422 struct rb_node
*rb_node
= rb_first(tree
);
426 chain
= rb_entry(rb_node
, struct callchain_node
, rb_node
);
428 ret
+= callchain_node__fprintf_value(chain
, fp
, total_samples
);
429 ret
+= fprintf(fp
, " ");
430 ret
+= __callchain__fprintf_folded(fp
, chain
);
431 ret
+= fprintf(fp
, "\n");
432 if (++entries_printed
== callchain_param
.print_limit
)
435 rb_node
= rb_next(rb_node
);
441 static size_t hist_entry_callchain__fprintf(struct hist_entry
*he
,
442 u64 total_samples
, int left_margin
,
445 u64 parent_samples
= he
->stat
.period
;
447 if (symbol_conf
.cumulate_callchain
)
448 parent_samples
= he
->stat_acc
->period
;
450 switch (callchain_param
.mode
) {
451 case CHAIN_GRAPH_REL
:
452 return callchain__fprintf_graph(fp
, &he
->sorted_chain
, total_samples
,
453 parent_samples
, left_margin
);
455 case CHAIN_GRAPH_ABS
:
456 return callchain__fprintf_graph(fp
, &he
->sorted_chain
, total_samples
,
457 parent_samples
, left_margin
);
460 return callchain__fprintf_flat(fp
, &he
->sorted_chain
, total_samples
);
463 return callchain__fprintf_folded(fp
, &he
->sorted_chain
, total_samples
);
468 pr_err("Bad callchain mode\n");
474 int __hist_entry__snprintf(struct hist_entry
*he
, struct perf_hpp
*hpp
,
475 struct perf_hpp_list
*hpp_list
)
477 const char *sep
= symbol_conf
.field_sep
;
478 struct perf_hpp_fmt
*fmt
;
479 char *start
= hpp
->buf
;
483 if (symbol_conf
.exclude_other
&& !he
->parent
)
486 perf_hpp_list__for_each_format(hpp_list
, fmt
) {
487 if (perf_hpp__should_skip(fmt
, he
->hists
))
491 * If there's no field_sep, we still need
492 * to display initial ' '.
494 if (!sep
|| !first
) {
495 ret
= scnprintf(hpp
->buf
, hpp
->size
, "%s", sep
?: " ");
496 advance_hpp(hpp
, ret
);
500 if (perf_hpp__use_color() && fmt
->color
)
501 ret
= fmt
->color(fmt
, hpp
, he
);
503 ret
= fmt
->entry(fmt
, hpp
, he
);
505 ret
= hist_entry__snprintf_alignment(he
, hpp
, fmt
, ret
);
506 advance_hpp(hpp
, ret
);
509 return hpp
->buf
- start
;
512 static int hist_entry__snprintf(struct hist_entry
*he
, struct perf_hpp
*hpp
)
514 return __hist_entry__snprintf(he
, hpp
, he
->hists
->hpp_list
);
517 static int hist_entry__hierarchy_fprintf(struct hist_entry
*he
,
518 struct perf_hpp
*hpp
,
522 const char *sep
= symbol_conf
.field_sep
;
523 struct perf_hpp_fmt
*fmt
;
524 struct perf_hpp_list_node
*fmt_node
;
525 char *buf
= hpp
->buf
;
526 size_t size
= hpp
->size
;
527 int ret
, printed
= 0;
530 if (symbol_conf
.exclude_other
&& !he
->parent
)
533 ret
= scnprintf(hpp
->buf
, hpp
->size
, "%*s", he
->depth
* HIERARCHY_INDENT
, "");
534 advance_hpp(hpp
, ret
);
536 /* the first hpp_list_node is for overhead columns */
537 fmt_node
= list_first_entry(&hists
->hpp_formats
,
538 struct perf_hpp_list_node
, list
);
539 perf_hpp_list__for_each_format(&fmt_node
->hpp
, fmt
) {
541 * If there's no field_sep, we still need
542 * to display initial ' '.
544 if (!sep
|| !first
) {
545 ret
= scnprintf(hpp
->buf
, hpp
->size
, "%s", sep
?: " ");
546 advance_hpp(hpp
, ret
);
550 if (perf_hpp__use_color() && fmt
->color
)
551 ret
= fmt
->color(fmt
, hpp
, he
);
553 ret
= fmt
->entry(fmt
, hpp
, he
);
555 ret
= hist_entry__snprintf_alignment(he
, hpp
, fmt
, ret
);
556 advance_hpp(hpp
, ret
);
560 ret
= scnprintf(hpp
->buf
, hpp
->size
, "%*s",
561 (hists
->nr_hpp_node
- 2) * HIERARCHY_INDENT
, "");
562 advance_hpp(hpp
, ret
);
564 printed
+= fprintf(fp
, "%s", buf
);
566 perf_hpp_list__for_each_format(he
->hpp_list
, fmt
) {
571 * No need to call hist_entry__snprintf_alignment() since this
572 * fmt is always the last column in the hierarchy mode.
574 if (perf_hpp__use_color() && fmt
->color
)
575 fmt
->color(fmt
, hpp
, he
);
577 fmt
->entry(fmt
, hpp
, he
);
580 * dynamic entries are right-aligned but we want left-aligned
581 * in the hierarchy mode
583 printed
+= fprintf(fp
, "%s%s", sep
?: " ", ltrim(buf
));
585 printed
+= putc('\n', fp
);
587 if (symbol_conf
.use_callchain
&& he
->leaf
) {
588 u64 total
= hists__total_period(hists
);
590 printed
+= hist_entry_callchain__fprintf(he
, total
, 0, fp
);
598 static int hist_entry__fprintf(struct hist_entry
*he
, size_t size
,
599 char *bf
, size_t bfsz
, FILE *fp
,
603 int callchain_ret
= 0;
605 struct perf_hpp hpp
= {
609 struct hists
*hists
= he
->hists
;
610 u64 total_period
= hists
->stats
.total_period
;
612 if (size
== 0 || size
> bfsz
)
613 size
= hpp
.size
= bfsz
;
615 if (symbol_conf
.report_hierarchy
)
616 return hist_entry__hierarchy_fprintf(he
, &hpp
, hists
, fp
);
618 hist_entry__snprintf(he
, &hpp
);
620 ret
= fprintf(fp
, "%s\n", bf
);
623 callchain_ret
= hist_entry_callchain__fprintf(he
, total_period
,
626 if (callchain_ret
== 0 && symbol_conf
.inline_name
) {
627 inline_ret
= inline__fprintf(he
->ms
.map
, he
->ip
, 0, 0, 0, fp
);
630 ret
+= fprintf(fp
, "\n");
632 ret
+= callchain_ret
;
637 static int print_hierarchy_indent(const char *sep
, int indent
,
638 const char *line
, FILE *fp
)
640 if (sep
!= NULL
|| indent
< 2)
643 return fprintf(fp
, "%-.*s", (indent
- 2) * HIERARCHY_INDENT
, line
);
646 static int hists__fprintf_hierarchy_headers(struct hists
*hists
,
647 struct perf_hpp
*hpp
, FILE *fp
)
649 bool first_node
, first_col
;
653 unsigned header_width
= 0;
654 struct perf_hpp_fmt
*fmt
;
655 struct perf_hpp_list_node
*fmt_node
;
656 const char *sep
= symbol_conf
.field_sep
;
658 indent
= hists
->nr_hpp_node
;
660 /* preserve max indent depth for column headers */
661 print_hierarchy_indent(sep
, indent
, spaces
, fp
);
663 /* the first hpp_list_node is for overhead columns */
664 fmt_node
= list_first_entry(&hists
->hpp_formats
,
665 struct perf_hpp_list_node
, list
);
667 perf_hpp_list__for_each_format(&fmt_node
->hpp
, fmt
) {
668 fmt
->header(fmt
, hpp
, hists
, 0, NULL
);
669 fprintf(fp
, "%s%s", hpp
->buf
, sep
?: " ");
672 /* combine sort headers with ' / ' */
674 list_for_each_entry_continue(fmt_node
, &hists
->hpp_formats
, list
) {
676 header_width
+= fprintf(fp
, " / ");
680 perf_hpp_list__for_each_format(&fmt_node
->hpp
, fmt
) {
681 if (perf_hpp__should_skip(fmt
, hists
))
685 header_width
+= fprintf(fp
, "+");
688 fmt
->header(fmt
, hpp
, hists
, 0, NULL
);
690 header_width
+= fprintf(fp
, "%s", trim(hpp
->buf
));
696 /* preserve max indent depth for initial dots */
697 print_hierarchy_indent(sep
, indent
, dots
, fp
);
699 /* the first hpp_list_node is for overhead columns */
700 fmt_node
= list_first_entry(&hists
->hpp_formats
,
701 struct perf_hpp_list_node
, list
);
704 perf_hpp_list__for_each_format(&fmt_node
->hpp
, fmt
) {
706 fprintf(fp
, "%s", sep
?: "..");
709 width
= fmt
->width(fmt
, hpp
, hists
);
710 fprintf(fp
, "%.*s", width
, dots
);
714 list_for_each_entry_continue(fmt_node
, &hists
->hpp_formats
, list
) {
716 width
= depth
* HIERARCHY_INDENT
;
718 perf_hpp_list__for_each_format(&fmt_node
->hpp
, fmt
) {
719 if (perf_hpp__should_skip(fmt
, hists
))
723 width
++; /* for '+' sign between column header */
726 width
+= fmt
->width(fmt
, hpp
, hists
);
729 if (width
> header_width
)
730 header_width
= width
;
735 fprintf(fp
, "%s%-.*s", sep
?: " ", header_width
, dots
);
737 fprintf(fp
, "\n#\n");
742 static void fprintf_line(struct hists
*hists
, struct perf_hpp
*hpp
,
745 struct perf_hpp_fmt
*fmt
;
746 const char *sep
= symbol_conf
.field_sep
;
750 hists__for_each_format(hists
, fmt
) {
751 if (perf_hpp__should_skip(fmt
, hists
))
755 fprintf(fp
, "%s", sep
?: " ");
759 fmt
->header(fmt
, hpp
, hists
, line
, &span
);
762 fprintf(fp
, "%s", hpp
->buf
);
767 hists__fprintf_standard_headers(struct hists
*hists
,
768 struct perf_hpp
*hpp
,
771 struct perf_hpp_list
*hpp_list
= hists
->hpp_list
;
772 struct perf_hpp_fmt
*fmt
;
774 const char *sep
= symbol_conf
.field_sep
;
778 for (line
= 0; line
< hpp_list
->nr_header_lines
; line
++) {
779 /* first # is displayed one level up */
782 fprintf_line(hists
, hpp
, line
, fp
);
787 return hpp_list
->nr_header_lines
;
793 hists__for_each_format(hists
, fmt
) {
796 if (perf_hpp__should_skip(fmt
, hists
))
800 fprintf(fp
, "%s", sep
?: " ");
804 width
= fmt
->width(fmt
, hpp
, hists
);
805 for (i
= 0; i
< width
; i
++)
811 return hpp_list
->nr_header_lines
+ 2;
814 int hists__fprintf_headers(struct hists
*hists
, FILE *fp
)
817 struct perf_hpp dummy_hpp
= {
824 if (symbol_conf
.report_hierarchy
)
825 return hists__fprintf_hierarchy_headers(hists
, &dummy_hpp
, fp
);
827 return hists__fprintf_standard_headers(hists
, &dummy_hpp
, fp
);
831 size_t hists__fprintf(struct hists
*hists
, bool show_header
, int max_rows
,
832 int max_cols
, float min_pcnt
, FILE *fp
,
837 const char *sep
= symbol_conf
.field_sep
;
845 hists__reset_column_width(hists
);
847 if (symbol_conf
.col_width_list_str
)
848 perf_hpp__set_user_width(symbol_conf
.col_width_list_str
);
851 nr_rows
+= hists__fprintf_headers(hists
, fp
);
853 if (max_rows
&& nr_rows
>= max_rows
)
856 linesz
= hists__sort_list_width(hists
) + 3 + 1;
857 linesz
+= perf_hpp__color_overhead();
858 line
= malloc(linesz
);
864 indent
= hists__overhead_width(hists
) + 4;
866 for (nd
= rb_first(&hists
->entries
); nd
; nd
= __rb_hierarchy_next(nd
, HMD_FORCE_CHILD
)) {
867 struct hist_entry
*h
= rb_entry(nd
, struct hist_entry
, rb_node
);
873 percent
= hist_entry__get_percent_limit(h
);
874 if (percent
< min_pcnt
)
877 ret
+= hist_entry__fprintf(h
, max_cols
, line
, linesz
, fp
, use_callchain
);
879 if (max_rows
&& ++nr_rows
>= max_rows
)
883 * If all children are filtered out or percent-limited,
884 * display "no entry >= x.xx%" message.
886 if (!h
->leaf
&& !hist_entry__has_hierarchy_children(h
, min_pcnt
)) {
887 int depth
= hists
->nr_hpp_node
+ h
->depth
+ 1;
889 print_hierarchy_indent(sep
, depth
, spaces
, fp
);
890 fprintf(fp
, "%*sno entry >= %.2f%%\n", indent
, "", min_pcnt
);
892 if (max_rows
&& ++nr_rows
>= max_rows
)
896 if (h
->ms
.map
== NULL
&& verbose
> 1) {
897 __map_groups__fprintf_maps(h
->thread
->mg
,
899 fprintf(fp
, "%.10s end\n", graph_dotted_line
);
905 zfree(&rem_sq_bracket
);
910 size_t events_stats__fprintf(struct events_stats
*stats
, FILE *fp
)
915 for (i
= 0; i
< PERF_RECORD_HEADER_MAX
; ++i
) {
918 if (stats
->nr_events
[i
] == 0)
921 name
= perf_event__name(i
);
922 if (!strcmp(name
, "UNKNOWN"))
925 ret
+= fprintf(fp
, "%16s events: %10d\n", name
,
926 stats
->nr_events
[i
]);