14 struct callchain_param callchain_param = {
15 .mode = CHAIN_GRAPH_REL,
19 static void hist_entry__add_cpumode_period(struct hist_entry *self,
20 unsigned int cpumode, u64 period)
23 case PERF_RECORD_MISC_KERNEL:
24 self->period_sys += period;
26 case PERF_RECORD_MISC_USER:
27 self->period_us += period;
29 case PERF_RECORD_MISC_GUEST_KERNEL:
30 self->period_guest_sys += period;
32 case PERF_RECORD_MISC_GUEST_USER:
33 self->period_guest_us += period;
41 * histogram, sorted on item, collects periods
44 static struct hist_entry *hist_entry__new(struct hist_entry *template)
46 size_t callchain_size = symbol_conf.use_callchain ? sizeof(struct callchain_node) : 0;
47 struct hist_entry *self = malloc(sizeof(*self) + callchain_size);
52 if (symbol_conf.use_callchain)
53 callchain_init(self->callchain);
59 static void hists__inc_nr_entries(struct hists *self, struct hist_entry *entry)
63 if (entry->ms.sym && self->max_sym_namelen < entry->ms.sym->namelen)
64 self->max_sym_namelen = entry->ms.sym->namelen;
68 static u8 symbol__parent_filter(const struct symbol *parent)
70 if (symbol_conf.exclude_other && parent == NULL)
71 return 1 << HIST_FILTER__PARENT;
75 struct hist_entry *__hists__add_entry(struct hists *self,
76 struct addr_location *al,
77 struct symbol *sym_parent, u64 period)
79 struct rb_node **p = &self->entries.rb_node;
80 struct rb_node *parent = NULL;
81 struct hist_entry *he;
82 struct hist_entry entry = {
93 .filtered = symbol__parent_filter(sym_parent),
99 he = rb_entry(parent, struct hist_entry, rb_node);
101 cmp = hist_entry__cmp(&entry, he);
104 he->period += period;
115 he = hist_entry__new(&entry);
118 rb_link_node(&he->rb_node, parent, p);
119 rb_insert_color(&he->rb_node, &self->entries);
120 hists__inc_nr_entries(self, he);
122 hist_entry__add_cpumode_period(he, al->cpumode, period);
127 hist_entry__cmp(struct hist_entry *left, struct hist_entry *right)
129 struct sort_entry *se;
132 list_for_each_entry(se, &hist_entry__sort_list, list) {
133 cmp = se->se_cmp(left, right);
142 hist_entry__collapse(struct hist_entry *left, struct hist_entry *right)
144 struct sort_entry *se;
147 list_for_each_entry(se, &hist_entry__sort_list, list) {
148 int64_t (*f)(struct hist_entry *, struct hist_entry *);
150 f = se->se_collapse ?: se->se_cmp;
152 cmp = f(left, right);
160 void hist_entry__free(struct hist_entry *he)
166 * collapse the histogram
169 static bool collapse__insert_entry(struct rb_root *root, struct hist_entry *he)
171 struct rb_node **p = &root->rb_node;
172 struct rb_node *parent = NULL;
173 struct hist_entry *iter;
178 iter = rb_entry(parent, struct hist_entry, rb_node);
180 cmp = hist_entry__collapse(iter, he);
183 iter->period += he->period;
184 hist_entry__free(he);
194 rb_link_node(&he->rb_node, parent, p);
195 rb_insert_color(&he->rb_node, root);
199 void hists__collapse_resort(struct hists *self)
202 struct rb_node *next;
203 struct hist_entry *n;
205 if (!sort__need_collapse)
209 next = rb_first(&self->entries);
210 self->nr_entries = 0;
211 self->max_sym_namelen = 0;
214 n = rb_entry(next, struct hist_entry, rb_node);
215 next = rb_next(&n->rb_node);
217 rb_erase(&n->rb_node, &self->entries);
218 if (collapse__insert_entry(&tmp, n))
219 hists__inc_nr_entries(self, n);
226 * reverse the map, sort on period.
229 static void __hists__insert_output_entry(struct rb_root *entries,
230 struct hist_entry *he,
231 u64 min_callchain_hits)
233 struct rb_node **p = &entries->rb_node;
234 struct rb_node *parent = NULL;
235 struct hist_entry *iter;
237 if (symbol_conf.use_callchain)
238 callchain_param.sort(&he->sorted_chain, he->callchain,
239 min_callchain_hits, &callchain_param);
243 iter = rb_entry(parent, struct hist_entry, rb_node);
245 if (he->period > iter->period)
251 rb_link_node(&he->rb_node, parent, p);
252 rb_insert_color(&he->rb_node, entries);
255 void hists__output_resort(struct hists *self)
258 struct rb_node *next;
259 struct hist_entry *n;
260 u64 min_callchain_hits;
262 min_callchain_hits = self->stats.total_period * (callchain_param.min_percent / 100);
265 next = rb_first(&self->entries);
267 self->nr_entries = 0;
268 self->max_sym_namelen = 0;
271 n = rb_entry(next, struct hist_entry, rb_node);
272 next = rb_next(&n->rb_node);
274 rb_erase(&n->rb_node, &self->entries);
275 __hists__insert_output_entry(&tmp, n, min_callchain_hits);
276 hists__inc_nr_entries(self, n);
282 static size_t callchain__fprintf_left_margin(FILE *fp, int left_margin)
285 int ret = fprintf(fp, " ");
287 for (i = 0; i < left_margin; i++)
288 ret += fprintf(fp, " ");
293 static size_t ipchain__fprintf_graph_line(FILE *fp, int depth, int depth_mask,
297 size_t ret = callchain__fprintf_left_margin(fp, left_margin);
299 for (i = 0; i < depth; i++)
300 if (depth_mask & (1 << i))
301 ret += fprintf(fp, "| ");
303 ret += fprintf(fp, " ");
305 ret += fprintf(fp, "\n");
310 static size_t ipchain__fprintf_graph(FILE *fp, struct callchain_list *chain,
311 int depth, int depth_mask, int period,
312 u64 total_samples, int hits,
318 ret += callchain__fprintf_left_margin(fp, left_margin);
319 for (i = 0; i < depth; i++) {
320 if (depth_mask & (1 << i))
321 ret += fprintf(fp, "|");
323 ret += fprintf(fp, " ");
324 if (!period && i == depth - 1) {
327 percent = hits * 100.0 / total_samples;
328 ret += percent_color_fprintf(fp, "--%2.2f%%-- ", percent);
330 ret += fprintf(fp, "%s", " ");
333 ret += fprintf(fp, "%s\n", chain->ms.sym->name);
335 ret += fprintf(fp, "%p\n", (void *)(long)chain->ip);
340 static struct symbol *rem_sq_bracket;
341 static struct callchain_list rem_hits;
343 static void init_rem_hits(void)
345 rem_sq_bracket = malloc(sizeof(*rem_sq_bracket) + 6);
346 if (!rem_sq_bracket) {
347 fprintf(stderr, "Not enough memory to display remaining hits\n");
351 strcpy(rem_sq_bracket->name, "[...]");
352 rem_hits.ms.sym = rem_sq_bracket;
355 static size_t __callchain__fprintf_graph(FILE *fp, struct callchain_node *self,
356 u64 total_samples, int depth,
357 int depth_mask, int left_margin)
359 struct rb_node *node, *next;
360 struct callchain_node *child;
361 struct callchain_list *chain;
362 int new_depth_mask = depth_mask;
367 uint entries_printed = 0;
369 if (callchain_param.mode == CHAIN_GRAPH_REL)
370 new_total = self->children_hit;
372 new_total = total_samples;
374 remaining = new_total;
376 node = rb_first(&self->rb_root);
380 child = rb_entry(node, struct callchain_node, rb_node);
381 cumul = cumul_hits(child);
385 * The depth mask manages the output of pipes that show
386 * the depth. We don't want to keep the pipes of the current
387 * level for the last child of this depth.
388 * Except if we have remaining filtered hits. They will
389 * supersede the last child
391 next = rb_next(node);
392 if (!next && (callchain_param.mode != CHAIN_GRAPH_REL || !remaining))
393 new_depth_mask &= ~(1 << (depth - 1));
396 * But we keep the older depth mask for the line separator
397 * to keep the level link until we reach the last child
399 ret += ipchain__fprintf_graph_line(fp, depth, depth_mask,
402 list_for_each_entry(chain, &child->val, list) {
403 ret += ipchain__fprintf_graph(fp, chain, depth,
409 ret += __callchain__fprintf_graph(fp, child, new_total,
411 new_depth_mask | (1 << depth),
414 if (++entries_printed == callchain_param.print_limit)
418 if (callchain_param.mode == CHAIN_GRAPH_REL &&
419 remaining && remaining != new_total) {
424 new_depth_mask &= ~(1 << (depth - 1));
426 ret += ipchain__fprintf_graph(fp, &rem_hits, depth,
427 new_depth_mask, 0, new_total,
428 remaining, left_margin);
434 static size_t callchain__fprintf_graph(FILE *fp, struct callchain_node *self,
435 u64 total_samples, int left_margin)
437 struct callchain_list *chain;
438 bool printed = false;
441 u32 entries_printed = 0;
443 list_for_each_entry(chain, &self->val, list) {
444 if (!i++ && sort__first_dimension == SORT_SYM)
448 ret += callchain__fprintf_left_margin(fp, left_margin);
449 ret += fprintf(fp, "|\n");
450 ret += callchain__fprintf_left_margin(fp, left_margin);
451 ret += fprintf(fp, "---");
456 ret += callchain__fprintf_left_margin(fp, left_margin);
459 ret += fprintf(fp, " %s\n", chain->ms.sym->name);
461 ret += fprintf(fp, " %p\n", (void *)(long)chain->ip);
463 if (++entries_printed == callchain_param.print_limit)
467 ret += __callchain__fprintf_graph(fp, self, total_samples, 1, 1, left_margin);
472 static size_t callchain__fprintf_flat(FILE *fp, struct callchain_node *self,
475 struct callchain_list *chain;
481 ret += callchain__fprintf_flat(fp, self->parent, total_samples);
484 list_for_each_entry(chain, &self->val, list) {
485 if (chain->ip >= PERF_CONTEXT_MAX)
488 ret += fprintf(fp, " %s\n", chain->ms.sym->name);
490 ret += fprintf(fp, " %p\n",
491 (void *)(long)chain->ip);
497 static size_t hist_entry_callchain__fprintf(FILE *fp, struct hist_entry *self,
498 u64 total_samples, int left_margin)
500 struct rb_node *rb_node;
501 struct callchain_node *chain;
503 u32 entries_printed = 0;
505 rb_node = rb_first(&self->sorted_chain);
509 chain = rb_entry(rb_node, struct callchain_node, rb_node);
510 percent = chain->hit * 100.0 / total_samples;
511 switch (callchain_param.mode) {
513 ret += percent_color_fprintf(fp, " %6.2f%%\n",
515 ret += callchain__fprintf_flat(fp, chain, total_samples);
517 case CHAIN_GRAPH_ABS: /* Falldown */
518 case CHAIN_GRAPH_REL:
519 ret += callchain__fprintf_graph(fp, chain, total_samples,
525 ret += fprintf(fp, "\n");
526 if (++entries_printed == callchain_param.print_limit)
528 rb_node = rb_next(rb_node);
534 int hist_entry__snprintf(struct hist_entry *self, char *s, size_t size,
535 struct hists *pair_hists, bool show_displacement,
536 long displacement, bool color, u64 session_total)
538 struct sort_entry *se;
539 u64 period, total, period_sys, period_us, period_guest_sys, period_guest_us;
540 const char *sep = symbol_conf.field_sep;
543 if (symbol_conf.exclude_other && !self->parent)
547 period = self->pair ? self->pair->period : 0;
548 total = pair_hists->stats.total_period;
549 period_sys = self->pair ? self->pair->period_sys : 0;
550 period_us = self->pair ? self->pair->period_us : 0;
551 period_guest_sys = self->pair ? self->pair->period_guest_sys : 0;
552 period_guest_us = self->pair ? self->pair->period_guest_us : 0;
554 period = self->period;
555 total = session_total;
556 period_sys = self->period_sys;
557 period_us = self->period_us;
558 period_guest_sys = self->period_guest_sys;
559 period_guest_us = self->period_guest_us;
564 ret = percent_color_snprintf(s, size,
565 sep ? "%.2f" : " %6.2f%%",
566 (period * 100.0) / total);
568 ret = snprintf(s, size, sep ? "%.2f" : " %6.2f%%",
569 (period * 100.0) / total);
570 if (symbol_conf.show_cpu_utilization) {
571 ret += percent_color_snprintf(s + ret, size - ret,
572 sep ? "%.2f" : " %6.2f%%",
573 (period_sys * 100.0) / total);
574 ret += percent_color_snprintf(s + ret, size - ret,
575 sep ? "%.2f" : " %6.2f%%",
576 (period_us * 100.0) / total);
578 ret += percent_color_snprintf(s + ret,
580 sep ? "%.2f" : " %6.2f%%",
581 (period_guest_sys * 100.0) /
583 ret += percent_color_snprintf(s + ret,
585 sep ? "%.2f" : " %6.2f%%",
586 (period_guest_us * 100.0) /
591 ret = snprintf(s, size, sep ? "%lld" : "%12lld ", period);
593 if (symbol_conf.show_nr_samples) {
595 ret += snprintf(s + ret, size - ret, "%c%lld", *sep, period);
597 ret += snprintf(s + ret, size - ret, "%11lld", period);
602 double old_percent = 0, new_percent = 0, diff;
605 old_percent = (period * 100.0) / total;
606 if (session_total > 0)
607 new_percent = (self->period * 100.0) / session_total;
609 diff = new_percent - old_percent;
611 if (fabs(diff) >= 0.01)
612 snprintf(bf, sizeof(bf), "%+4.2F%%", diff);
614 snprintf(bf, sizeof(bf), " ");
617 ret += snprintf(s + ret, size - ret, "%c%s", *sep, bf);
619 ret += snprintf(s + ret, size - ret, "%11.11s", bf);
621 if (show_displacement) {
623 snprintf(bf, sizeof(bf), "%+4ld", displacement);
625 snprintf(bf, sizeof(bf), " ");
628 ret += snprintf(s + ret, size - ret, "%c%s", *sep, bf);
630 ret += snprintf(s + ret, size - ret, "%6.6s", bf);
634 list_for_each_entry(se, &hist_entry__sort_list, list) {
638 ret += snprintf(s + ret, size - ret, "%s", sep ?: " ");
639 ret += se->se_snprintf(self, s + ret, size - ret,
640 se->se_width ? *se->se_width : 0);
646 int hist_entry__fprintf(struct hist_entry *self, struct hists *pair_hists,
647 bool show_displacement, long displacement, FILE *fp,
651 hist_entry__snprintf(self, bf, sizeof(bf), pair_hists,
652 show_displacement, displacement,
653 true, session_total);
654 return fprintf(fp, "%s\n", bf);
657 static size_t hist_entry__fprintf_callchain(struct hist_entry *self, FILE *fp,
662 if (sort__first_dimension == SORT_COMM) {
663 struct sort_entry *se = list_first_entry(&hist_entry__sort_list,
665 left_margin = se->se_width ? *se->se_width : 0;
666 left_margin -= thread__comm_len(self->thread);
669 return hist_entry_callchain__fprintf(fp, self, session_total,
673 size_t hists__fprintf(struct hists *self, struct hists *pair,
674 bool show_displacement, FILE *fp)
676 struct sort_entry *se;
679 unsigned long position = 1;
680 long displacement = 0;
682 const char *sep = symbol_conf.field_sep;
683 const char *col_width = symbol_conf.col_width_list_str;
687 fprintf(fp, "# %s", pair ? "Baseline" : "Overhead");
689 if (symbol_conf.show_nr_samples) {
691 fprintf(fp, "%cSamples", *sep);
693 fputs(" Samples ", fp);
696 if (symbol_conf.show_cpu_utilization) {
698 ret += fprintf(fp, "%csys", *sep);
699 ret += fprintf(fp, "%cus", *sep);
701 ret += fprintf(fp, "%cguest sys", *sep);
702 ret += fprintf(fp, "%cguest us", *sep);
705 ret += fprintf(fp, " sys ");
706 ret += fprintf(fp, " us ");
708 ret += fprintf(fp, " guest sys ");
709 ret += fprintf(fp, " guest us ");
716 ret += fprintf(fp, "%cDelta", *sep);
718 ret += fprintf(fp, " Delta ");
720 if (show_displacement) {
722 ret += fprintf(fp, "%cDisplacement", *sep);
724 ret += fprintf(fp, " Displ");
728 list_for_each_entry(se, &hist_entry__sort_list, list) {
732 fprintf(fp, "%c%s", *sep, se->se_header);
735 width = strlen(se->se_header);
737 if (symbol_conf.col_width_list_str) {
739 *se->se_width = atoi(col_width);
740 col_width = strchr(col_width, ',');
745 width = *se->se_width = max(*se->se_width, width);
747 fprintf(fp, " %*s", width, se->se_header);
754 fprintf(fp, "# ........");
755 if (symbol_conf.show_nr_samples)
756 fprintf(fp, " ..........");
758 fprintf(fp, " ..........");
759 if (show_displacement)
760 fprintf(fp, " .....");
762 list_for_each_entry(se, &hist_entry__sort_list, list) {
770 width = *se->se_width;
772 width = strlen(se->se_header);
773 for (i = 0; i < width; i++)
777 fprintf(fp, "\n#\n");
780 for (nd = rb_first(&self->entries); nd; nd = rb_next(nd)) {
781 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
783 if (show_displacement) {
785 displacement = ((long)h->pair->position -
791 ret += hist_entry__fprintf(h, pair, show_displacement,
792 displacement, fp, self->stats.total_period);
794 if (symbol_conf.use_callchain)
795 ret += hist_entry__fprintf_callchain(h, fp, self->stats.total_period);
797 if (h->ms.map == NULL && verbose > 1) {
798 __map_groups__fprintf_maps(&h->thread->mg,
799 MAP__FUNCTION, verbose, fp);
800 fprintf(fp, "%.10s end\n", graph_dotted_line);
804 free(rem_sq_bracket);
809 static void hists__remove_entry_filter(struct hists *self, struct hist_entry *h,
810 enum hist_filter filter)
812 h->filtered &= ~(1 << filter);
817 self->stats.total_period += h->period;
818 self->stats.nr_events[PERF_RECORD_SAMPLE] += h->nr_events;
820 if (h->ms.sym && self->max_sym_namelen < h->ms.sym->namelen)
821 self->max_sym_namelen = h->ms.sym->namelen;
824 void hists__filter_by_dso(struct hists *self, const struct dso *dso)
828 self->nr_entries = self->stats.total_period = 0;
829 self->stats.nr_events[PERF_RECORD_SAMPLE] = 0;
830 self->max_sym_namelen = 0;
832 for (nd = rb_first(&self->entries); nd; nd = rb_next(nd)) {
833 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
835 if (symbol_conf.exclude_other && !h->parent)
838 if (dso != NULL && (h->ms.map == NULL || h->ms.map->dso != dso)) {
839 h->filtered |= (1 << HIST_FILTER__DSO);
843 hists__remove_entry_filter(self, h, HIST_FILTER__DSO);
847 void hists__filter_by_thread(struct hists *self, const struct thread *thread)
851 self->nr_entries = self->stats.total_period = 0;
852 self->stats.nr_events[PERF_RECORD_SAMPLE] = 0;
853 self->max_sym_namelen = 0;
855 for (nd = rb_first(&self->entries); nd; nd = rb_next(nd)) {
856 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
858 if (thread != NULL && h->thread != thread) {
859 h->filtered |= (1 << HIST_FILTER__THREAD);
863 hists__remove_entry_filter(self, h, HIST_FILTER__THREAD);
867 static int symbol__alloc_hist(struct symbol *self)
869 struct sym_priv *priv = symbol__priv(self);
870 const int size = (sizeof(*priv->hist) +
871 (self->end - self->start) * sizeof(u64));
873 priv->hist = zalloc(size);
874 return priv->hist == NULL ? -1 : 0;
877 int hist_entry__inc_addr_samples(struct hist_entry *self, u64 ip)
879 unsigned int sym_size, offset;
880 struct symbol *sym = self->ms.sym;
881 struct sym_priv *priv;
884 if (!sym || !self->ms.map)
887 priv = symbol__priv(sym);
888 if (priv->hist == NULL && symbol__alloc_hist(sym) < 0)
891 sym_size = sym->end - sym->start;
892 offset = ip - sym->start;
894 pr_debug3("%s: ip=%#Lx\n", __func__, self->ms.map->unmap_ip(self->ms.map, ip));
896 if (offset >= sym_size)
903 pr_debug3("%#Lx %s: period++ [ip: %#Lx, %#Lx] => %Ld\n", self->ms.sym->start,
904 self->ms.sym->name, ip, ip - self->ms.sym->start, h->ip[offset]);
908 static struct objdump_line *objdump_line__new(s64 offset, char *line)
910 struct objdump_line *self = malloc(sizeof(*self));
913 self->offset = offset;
920 void objdump_line__free(struct objdump_line *self)
926 static void objdump__add_line(struct list_head *head, struct objdump_line *line)
928 list_add_tail(&line->node, head);
931 struct objdump_line *objdump__get_next_ip_line(struct list_head *head,
932 struct objdump_line *pos)
934 list_for_each_entry_continue(pos, head, node)
935 if (pos->offset >= 0)
941 static int hist_entry__parse_objdump_line(struct hist_entry *self, FILE *file,
942 struct list_head *head)
944 struct symbol *sym = self->ms.sym;
945 struct objdump_line *objdump_line;
946 char *line = NULL, *tmp, *tmp2, *c;
948 s64 line_ip, offset = -1;
950 if (getline(&line, &line_len, file) < 0)
956 while (line_len != 0 && isspace(line[line_len - 1]))
957 line[--line_len] = '\0';
959 c = strchr(line, '\n');
966 * Strip leading spaces:
977 * Parse hexa addresses followed by ':'
979 line_ip = strtoull(tmp, &tmp2, 16);
980 if (*tmp2 != ':' || tmp == tmp2)
985 u64 start = map__rip_2objdump(self->ms.map, sym->start);
986 offset = line_ip - start;
989 objdump_line = objdump_line__new(offset, line);
990 if (objdump_line == NULL) {
994 objdump__add_line(head, objdump_line);
999 int hist_entry__annotate(struct hist_entry *self, struct list_head *head)
1001 struct symbol *sym = self->ms.sym;
1002 struct map *map = self->ms.map;
1003 struct dso *dso = map->dso;
1004 char *filename = dso__build_id_filename(dso, NULL, 0);
1005 bool free_filename = true;
1006 char command[PATH_MAX * 2];
1011 if (filename == NULL) {
1012 if (dso->has_build_id) {
1013 pr_err("Can't annotate %s: not enough memory\n",
1018 } else if (readlink(filename, command, sizeof(command)) < 0 ||
1019 strstr(command, "[kernel.kallsyms]") ||
1020 access(filename, R_OK)) {
1024 * If we don't have build-ids or the build-id file isn't in the
1025 * cache, or is just a kallsyms file, well, lets hope that this
1026 * DSO is the same as when 'perf record' ran.
1028 filename = dso->long_name;
1029 free_filename = false;
1032 if (dso->origin == DSO__ORIG_KERNEL) {
1033 if (dso->annotate_warned)
1034 goto out_free_filename;
1036 dso->annotate_warned = 1;
1037 pr_err("Can't annotate %s: No vmlinux file was found in the "
1038 "path\n", sym->name);
1039 goto out_free_filename;
1042 pr_debug("%s: filename=%s, sym=%s, start=%#Lx, end=%#Lx\n", __func__,
1043 filename, sym->name, map->unmap_ip(map, sym->start),
1044 map->unmap_ip(map, sym->end));
1046 len = sym->end - sym->start;
1048 pr_debug("annotating [%p] %30s : [%p] %30s\n",
1049 dso, dso->long_name, sym, sym->name);
1051 snprintf(command, sizeof(command),
1052 "objdump --start-address=0x%016Lx --stop-address=0x%016Lx -dS -C %s|grep -v %s|expand",
1053 map__rip_2objdump(map, sym->start),
1054 map__rip_2objdump(map, sym->end),
1055 filename, filename);
1057 pr_debug("Executing: %s\n", command);
1059 file = popen(command, "r");
1061 goto out_free_filename;
1064 if (hist_entry__parse_objdump_line(self, file, head) < 0)
1074 void hists__inc_nr_events(struct hists *self, u32 type)
1076 ++self->stats.nr_events[0];
1077 ++self->stats.nr_events[type];
1080 size_t hists__fprintf_nr_events(struct hists *self, FILE *fp)
1085 for (i = 0; i < PERF_RECORD_HEADER_MAX; ++i) {
1086 if (!event__name[i])
1088 ret += fprintf(fp, "%10s events: %10d\n",
1089 event__name[i], self->stats.nr_events[i]);