0001
0002 #include <stdio.h>
0003 #include <stdlib.h>
0004 #include <linux/string.h>
0005
0006 #include "../../util/callchain.h"
0007 #include "../../util/debug.h"
0008 #include "../../util/event.h"
0009 #include "../../util/hist.h"
0010 #include "../../util/map.h"
0011 #include "../../util/maps.h"
0012 #include "../../util/symbol.h"
0013 #include "../../util/sort.h"
0014 #include "../../util/evsel.h"
0015 #include "../../util/srcline.h"
0016 #include "../../util/string2.h"
0017 #include "../../util/thread.h"
0018 #include "../../util/block-info.h"
0019 #include <linux/ctype.h>
0020 #include <linux/zalloc.h>
0021
0022 static size_t callchain__fprintf_left_margin(FILE *fp, int left_margin)
0023 {
0024 int i;
0025 int ret = fprintf(fp, " ");
0026
0027 for (i = 0; i < left_margin; i++)
0028 ret += fprintf(fp, " ");
0029
0030 return ret;
0031 }
0032
0033 static size_t ipchain__fprintf_graph_line(FILE *fp, int depth, int depth_mask,
0034 int left_margin)
0035 {
0036 int i;
0037 size_t ret = callchain__fprintf_left_margin(fp, left_margin);
0038
0039 for (i = 0; i < depth; i++)
0040 if (depth_mask & (1 << i))
0041 ret += fprintf(fp, "| ");
0042 else
0043 ret += fprintf(fp, " ");
0044
0045 ret += fprintf(fp, "\n");
0046
0047 return ret;
0048 }
0049
0050 static size_t ipchain__fprintf_graph(FILE *fp, struct callchain_node *node,
0051 struct callchain_list *chain,
0052 int depth, int depth_mask, int period,
0053 u64 total_samples, int left_margin)
0054 {
0055 int i;
0056 size_t ret = 0;
0057 char bf[1024], *alloc_str = NULL;
0058 char buf[64];
0059 const char *str;
0060
0061 ret += callchain__fprintf_left_margin(fp, left_margin);
0062 for (i = 0; i < depth; i++) {
0063 if (depth_mask & (1 << i))
0064 ret += fprintf(fp, "|");
0065 else
0066 ret += fprintf(fp, " ");
0067 if (!period && i == depth - 1) {
0068 ret += fprintf(fp, "--");
0069 ret += callchain_node__fprintf_value(node, fp, total_samples);
0070 ret += fprintf(fp, "--");
0071 } else
0072 ret += fprintf(fp, "%s", " ");
0073 }
0074
0075 str = callchain_list__sym_name(chain, bf, sizeof(bf), false);
0076
0077 if (symbol_conf.show_branchflag_count) {
0078 callchain_list_counts__printf_value(chain, NULL,
0079 buf, sizeof(buf));
0080
0081 if (asprintf(&alloc_str, "%s%s", str, buf) < 0)
0082 str = "Not enough memory!";
0083 else
0084 str = alloc_str;
0085 }
0086
0087 fputs(str, fp);
0088 fputc('\n', fp);
0089 free(alloc_str);
0090
0091 return ret;
0092 }
0093
0094 static struct symbol *rem_sq_bracket;
0095 static struct callchain_list rem_hits;
0096
0097 static void init_rem_hits(void)
0098 {
0099 rem_sq_bracket = malloc(sizeof(*rem_sq_bracket) + 6);
0100 if (!rem_sq_bracket) {
0101 fprintf(stderr, "Not enough memory to display remaining hits\n");
0102 return;
0103 }
0104
0105 strcpy(rem_sq_bracket->name, "[...]");
0106 rem_hits.ms.sym = rem_sq_bracket;
0107 }
0108
0109 static size_t __callchain__fprintf_graph(FILE *fp, struct rb_root *root,
0110 u64 total_samples, int depth,
0111 int depth_mask, int left_margin)
0112 {
0113 struct rb_node *node, *next;
0114 struct callchain_node *child = NULL;
0115 struct callchain_list *chain;
0116 int new_depth_mask = depth_mask;
0117 u64 remaining;
0118 size_t ret = 0;
0119 int i;
0120 uint entries_printed = 0;
0121 int cumul_count = 0;
0122
0123 remaining = total_samples;
0124
0125 node = rb_first(root);
0126 while (node) {
0127 u64 new_total;
0128 u64 cumul;
0129
0130 child = rb_entry(node, struct callchain_node, rb_node);
0131 cumul = callchain_cumul_hits(child);
0132 remaining -= cumul;
0133 cumul_count += callchain_cumul_counts(child);
0134
0135
0136
0137
0138
0139
0140
0141
0142 next = rb_next(node);
0143 if (!next && (callchain_param.mode != CHAIN_GRAPH_REL || !remaining))
0144 new_depth_mask &= ~(1 << (depth - 1));
0145
0146
0147
0148
0149
0150 ret += ipchain__fprintf_graph_line(fp, depth, depth_mask,
0151 left_margin);
0152 i = 0;
0153 list_for_each_entry(chain, &child->val, list) {
0154 ret += ipchain__fprintf_graph(fp, child, chain, depth,
0155 new_depth_mask, i++,
0156 total_samples,
0157 left_margin);
0158 }
0159
0160 if (callchain_param.mode == CHAIN_GRAPH_REL)
0161 new_total = child->children_hit;
0162 else
0163 new_total = total_samples;
0164
0165 ret += __callchain__fprintf_graph(fp, &child->rb_root, new_total,
0166 depth + 1,
0167 new_depth_mask | (1 << depth),
0168 left_margin);
0169 node = next;
0170 if (++entries_printed == callchain_param.print_limit)
0171 break;
0172 }
0173
0174 if (callchain_param.mode == CHAIN_GRAPH_REL &&
0175 remaining && remaining != total_samples) {
0176 struct callchain_node rem_node = {
0177 .hit = remaining,
0178 };
0179
0180 if (!rem_sq_bracket)
0181 return ret;
0182
0183 if (callchain_param.value == CCVAL_COUNT && child && child->parent) {
0184 rem_node.count = child->parent->children_count - cumul_count;
0185 if (rem_node.count <= 0)
0186 return ret;
0187 }
0188
0189 new_depth_mask &= ~(1 << (depth - 1));
0190 ret += ipchain__fprintf_graph(fp, &rem_node, &rem_hits, depth,
0191 new_depth_mask, 0, total_samples,
0192 left_margin);
0193 }
0194
0195 return ret;
0196 }
0197
0198
0199
0200
0201
0202
0203
0204
0205
0206 static bool need_percent_display(struct rb_node *node, u64 parent_samples)
0207 {
0208 struct callchain_node *cnode;
0209
0210 if (rb_next(node))
0211 return true;
0212
0213 cnode = rb_entry(node, struct callchain_node, rb_node);
0214 return callchain_cumul_hits(cnode) != parent_samples;
0215 }
0216
0217 static size_t callchain__fprintf_graph(FILE *fp, struct rb_root *root,
0218 u64 total_samples, u64 parent_samples,
0219 int left_margin)
0220 {
0221 struct callchain_node *cnode;
0222 struct callchain_list *chain;
0223 u32 entries_printed = 0;
0224 bool printed = false;
0225 struct rb_node *node;
0226 int i = 0;
0227 int ret = 0;
0228 char bf[1024];
0229
0230 node = rb_first(root);
0231 if (node && !need_percent_display(node, parent_samples)) {
0232 cnode = rb_entry(node, struct callchain_node, rb_node);
0233 list_for_each_entry(chain, &cnode->val, list) {
0234
0235
0236
0237
0238
0239 if (!i++ && field_order == NULL &&
0240 sort_order && strstarts(sort_order, "sym"))
0241 continue;
0242
0243 if (!printed) {
0244 ret += callchain__fprintf_left_margin(fp, left_margin);
0245 ret += fprintf(fp, "|\n");
0246 ret += callchain__fprintf_left_margin(fp, left_margin);
0247 ret += fprintf(fp, "---");
0248 left_margin += 3;
0249 printed = true;
0250 } else
0251 ret += callchain__fprintf_left_margin(fp, left_margin);
0252
0253 ret += fprintf(fp, "%s",
0254 callchain_list__sym_name(chain, bf,
0255 sizeof(bf),
0256 false));
0257
0258 if (symbol_conf.show_branchflag_count)
0259 ret += callchain_list_counts__printf_value(
0260 chain, fp, NULL, 0);
0261 ret += fprintf(fp, "\n");
0262
0263 if (++entries_printed == callchain_param.print_limit)
0264 break;
0265 }
0266 root = &cnode->rb_root;
0267 }
0268
0269 if (callchain_param.mode == CHAIN_GRAPH_REL)
0270 total_samples = parent_samples;
0271
0272 ret += __callchain__fprintf_graph(fp, root, total_samples,
0273 1, 1, left_margin);
0274 if (ret) {
0275
0276 ret += fprintf(fp, "\n");
0277 }
0278
0279 return ret;
0280 }
0281
0282 static size_t __callchain__fprintf_flat(FILE *fp, struct callchain_node *node,
0283 u64 total_samples)
0284 {
0285 struct callchain_list *chain;
0286 size_t ret = 0;
0287 char bf[1024];
0288
0289 if (!node)
0290 return 0;
0291
0292 ret += __callchain__fprintf_flat(fp, node->parent, total_samples);
0293
0294
0295 list_for_each_entry(chain, &node->val, list) {
0296 if (chain->ip >= PERF_CONTEXT_MAX)
0297 continue;
0298 ret += fprintf(fp, " %s\n", callchain_list__sym_name(chain,
0299 bf, sizeof(bf), false));
0300 }
0301
0302 return ret;
0303 }
0304
0305 static size_t callchain__fprintf_flat(FILE *fp, struct rb_root *tree,
0306 u64 total_samples)
0307 {
0308 size_t ret = 0;
0309 u32 entries_printed = 0;
0310 struct callchain_node *chain;
0311 struct rb_node *rb_node = rb_first(tree);
0312
0313 while (rb_node) {
0314 chain = rb_entry(rb_node, struct callchain_node, rb_node);
0315
0316 ret += fprintf(fp, " ");
0317 ret += callchain_node__fprintf_value(chain, fp, total_samples);
0318 ret += fprintf(fp, "\n");
0319 ret += __callchain__fprintf_flat(fp, chain, total_samples);
0320 ret += fprintf(fp, "\n");
0321 if (++entries_printed == callchain_param.print_limit)
0322 break;
0323
0324 rb_node = rb_next(rb_node);
0325 }
0326
0327 return ret;
0328 }
0329
0330 static size_t __callchain__fprintf_folded(FILE *fp, struct callchain_node *node)
0331 {
0332 const char *sep = symbol_conf.field_sep ?: ";";
0333 struct callchain_list *chain;
0334 size_t ret = 0;
0335 char bf[1024];
0336 bool first;
0337
0338 if (!node)
0339 return 0;
0340
0341 ret += __callchain__fprintf_folded(fp, node->parent);
0342
0343 first = (ret == 0);
0344 list_for_each_entry(chain, &node->val, list) {
0345 if (chain->ip >= PERF_CONTEXT_MAX)
0346 continue;
0347 ret += fprintf(fp, "%s%s", first ? "" : sep,
0348 callchain_list__sym_name(chain,
0349 bf, sizeof(bf), false));
0350 first = false;
0351 }
0352
0353 return ret;
0354 }
0355
0356 static size_t callchain__fprintf_folded(FILE *fp, struct rb_root *tree,
0357 u64 total_samples)
0358 {
0359 size_t ret = 0;
0360 u32 entries_printed = 0;
0361 struct callchain_node *chain;
0362 struct rb_node *rb_node = rb_first(tree);
0363
0364 while (rb_node) {
0365
0366 chain = rb_entry(rb_node, struct callchain_node, rb_node);
0367
0368 ret += callchain_node__fprintf_value(chain, fp, total_samples);
0369 ret += fprintf(fp, " ");
0370 ret += __callchain__fprintf_folded(fp, chain);
0371 ret += fprintf(fp, "\n");
0372 if (++entries_printed == callchain_param.print_limit)
0373 break;
0374
0375 rb_node = rb_next(rb_node);
0376 }
0377
0378 return ret;
0379 }
0380
0381 static size_t hist_entry_callchain__fprintf(struct hist_entry *he,
0382 u64 total_samples, int left_margin,
0383 FILE *fp)
0384 {
0385 u64 parent_samples = he->stat.period;
0386
0387 if (symbol_conf.cumulate_callchain)
0388 parent_samples = he->stat_acc->period;
0389
0390 switch (callchain_param.mode) {
0391 case CHAIN_GRAPH_REL:
0392 return callchain__fprintf_graph(fp, &he->sorted_chain, total_samples,
0393 parent_samples, left_margin);
0394 break;
0395 case CHAIN_GRAPH_ABS:
0396 return callchain__fprintf_graph(fp, &he->sorted_chain, total_samples,
0397 parent_samples, left_margin);
0398 break;
0399 case CHAIN_FLAT:
0400 return callchain__fprintf_flat(fp, &he->sorted_chain, total_samples);
0401 break;
0402 case CHAIN_FOLDED:
0403 return callchain__fprintf_folded(fp, &he->sorted_chain, total_samples);
0404 break;
0405 case CHAIN_NONE:
0406 break;
0407 default:
0408 pr_err("Bad callchain mode\n");
0409 }
0410
0411 return 0;
0412 }
0413
0414 int __hist_entry__snprintf(struct hist_entry *he, struct perf_hpp *hpp,
0415 struct perf_hpp_list *hpp_list)
0416 {
0417 const char *sep = symbol_conf.field_sep;
0418 struct perf_hpp_fmt *fmt;
0419 char *start = hpp->buf;
0420 int ret;
0421 bool first = true;
0422
0423 if (symbol_conf.exclude_other && !he->parent)
0424 return 0;
0425
0426 perf_hpp_list__for_each_format(hpp_list, fmt) {
0427 if (perf_hpp__should_skip(fmt, he->hists))
0428 continue;
0429
0430
0431
0432
0433
0434 if (!sep || !first) {
0435 ret = scnprintf(hpp->buf, hpp->size, "%s", sep ?: " ");
0436 advance_hpp(hpp, ret);
0437 } else
0438 first = false;
0439
0440 if (perf_hpp__use_color() && fmt->color)
0441 ret = fmt->color(fmt, hpp, he);
0442 else
0443 ret = fmt->entry(fmt, hpp, he);
0444
0445 ret = hist_entry__snprintf_alignment(he, hpp, fmt, ret);
0446 advance_hpp(hpp, ret);
0447 }
0448
0449 return hpp->buf - start;
0450 }
0451
0452 static int hist_entry__snprintf(struct hist_entry *he, struct perf_hpp *hpp)
0453 {
0454 return __hist_entry__snprintf(he, hpp, he->hists->hpp_list);
0455 }
0456
0457 static int hist_entry__hierarchy_fprintf(struct hist_entry *he,
0458 struct perf_hpp *hpp,
0459 struct hists *hists,
0460 FILE *fp)
0461 {
0462 const char *sep = symbol_conf.field_sep;
0463 struct perf_hpp_fmt *fmt;
0464 struct perf_hpp_list_node *fmt_node;
0465 char *buf = hpp->buf;
0466 size_t size = hpp->size;
0467 int ret, printed = 0;
0468 bool first = true;
0469
0470 if (symbol_conf.exclude_other && !he->parent)
0471 return 0;
0472
0473 ret = scnprintf(hpp->buf, hpp->size, "%*s", he->depth * HIERARCHY_INDENT, "");
0474 advance_hpp(hpp, ret);
0475
0476
0477 fmt_node = list_first_entry(&hists->hpp_formats,
0478 struct perf_hpp_list_node, list);
0479 perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) {
0480
0481
0482
0483
0484 if (!sep || !first) {
0485 ret = scnprintf(hpp->buf, hpp->size, "%s", sep ?: " ");
0486 advance_hpp(hpp, ret);
0487 } else
0488 first = false;
0489
0490 if (perf_hpp__use_color() && fmt->color)
0491 ret = fmt->color(fmt, hpp, he);
0492 else
0493 ret = fmt->entry(fmt, hpp, he);
0494
0495 ret = hist_entry__snprintf_alignment(he, hpp, fmt, ret);
0496 advance_hpp(hpp, ret);
0497 }
0498
0499 if (!sep)
0500 ret = scnprintf(hpp->buf, hpp->size, "%*s",
0501 (hists->nr_hpp_node - 2) * HIERARCHY_INDENT, "");
0502 advance_hpp(hpp, ret);
0503
0504 printed += fprintf(fp, "%s", buf);
0505
0506 perf_hpp_list__for_each_format(he->hpp_list, fmt) {
0507 hpp->buf = buf;
0508 hpp->size = size;
0509
0510
0511
0512
0513
0514 if (perf_hpp__use_color() && fmt->color)
0515 fmt->color(fmt, hpp, he);
0516 else
0517 fmt->entry(fmt, hpp, he);
0518
0519
0520
0521
0522
0523 printed += fprintf(fp, "%s%s", sep ?: " ", skip_spaces(buf));
0524 }
0525 printed += putc('\n', fp);
0526
0527 if (he->leaf && hist_entry__has_callchains(he) && symbol_conf.use_callchain) {
0528 u64 total = hists__total_period(hists);
0529
0530 printed += hist_entry_callchain__fprintf(he, total, 0, fp);
0531 goto out;
0532 }
0533
0534 out:
0535 return printed;
0536 }
0537
0538 static int hist_entry__block_fprintf(struct hist_entry *he,
0539 char *bf, size_t size,
0540 FILE *fp)
0541 {
0542 struct block_hist *bh = container_of(he, struct block_hist, he);
0543 int ret = 0;
0544
0545 for (unsigned int i = 0; i < bh->block_hists.nr_entries; i++) {
0546 struct perf_hpp hpp = {
0547 .buf = bf,
0548 .size = size,
0549 .skip = false,
0550 };
0551
0552 bh->block_idx = i;
0553 hist_entry__snprintf(he, &hpp);
0554
0555 if (!hpp.skip)
0556 ret += fprintf(fp, "%s\n", bf);
0557 }
0558
0559 return ret;
0560 }
0561
0562 static int hist_entry__individual_block_fprintf(struct hist_entry *he,
0563 char *bf, size_t size,
0564 FILE *fp)
0565 {
0566 int ret = 0;
0567
0568 struct perf_hpp hpp = {
0569 .buf = bf,
0570 .size = size,
0571 .skip = false,
0572 };
0573
0574 hist_entry__snprintf(he, &hpp);
0575 if (!hpp.skip)
0576 ret += fprintf(fp, "%s\n", bf);
0577
0578 return ret;
0579 }
0580
0581 static int hist_entry__fprintf(struct hist_entry *he, size_t size,
0582 char *bf, size_t bfsz, FILE *fp,
0583 bool ignore_callchains)
0584 {
0585 int ret;
0586 int callchain_ret = 0;
0587 struct perf_hpp hpp = {
0588 .buf = bf,
0589 .size = size,
0590 };
0591 struct hists *hists = he->hists;
0592 u64 total_period = hists->stats.total_period;
0593
0594 if (size == 0 || size > bfsz)
0595 size = hpp.size = bfsz;
0596
0597 if (symbol_conf.report_hierarchy)
0598 return hist_entry__hierarchy_fprintf(he, &hpp, hists, fp);
0599
0600 if (symbol_conf.report_block)
0601 return hist_entry__block_fprintf(he, bf, size, fp);
0602
0603 if (symbol_conf.report_individual_block)
0604 return hist_entry__individual_block_fprintf(he, bf, size, fp);
0605
0606 hist_entry__snprintf(he, &hpp);
0607
0608 ret = fprintf(fp, "%s\n", bf);
0609
0610 if (hist_entry__has_callchains(he) && !ignore_callchains)
0611 callchain_ret = hist_entry_callchain__fprintf(he, total_period,
0612 0, fp);
0613
0614 ret += callchain_ret;
0615
0616 return ret;
0617 }
0618
0619 static int print_hierarchy_indent(const char *sep, int indent,
0620 const char *line, FILE *fp)
0621 {
0622 int width;
0623
0624 if (sep != NULL || indent < 2)
0625 return 0;
0626
0627 width = (indent - 2) * HIERARCHY_INDENT;
0628
0629 return fprintf(fp, "%-*.*s", width, width, line);
0630 }
0631
0632 static int hists__fprintf_hierarchy_headers(struct hists *hists,
0633 struct perf_hpp *hpp, FILE *fp)
0634 {
0635 bool first_node, first_col;
0636 int indent;
0637 int depth;
0638 unsigned width = 0;
0639 unsigned header_width = 0;
0640 struct perf_hpp_fmt *fmt;
0641 struct perf_hpp_list_node *fmt_node;
0642 const char *sep = symbol_conf.field_sep;
0643
0644 indent = hists->nr_hpp_node;
0645
0646
0647 print_hierarchy_indent(sep, indent, " ", fp);
0648
0649
0650 fmt_node = list_first_entry(&hists->hpp_formats,
0651 struct perf_hpp_list_node, list);
0652
0653 perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) {
0654 fmt->header(fmt, hpp, hists, 0, NULL);
0655 fprintf(fp, "%s%s", hpp->buf, sep ?: " ");
0656 }
0657
0658
0659 first_node = true;
0660 list_for_each_entry_continue(fmt_node, &hists->hpp_formats, list) {
0661 if (!first_node)
0662 header_width += fprintf(fp, " / ");
0663 first_node = false;
0664
0665 first_col = true;
0666 perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) {
0667 if (perf_hpp__should_skip(fmt, hists))
0668 continue;
0669
0670 if (!first_col)
0671 header_width += fprintf(fp, "+");
0672 first_col = false;
0673
0674 fmt->header(fmt, hpp, hists, 0, NULL);
0675
0676 header_width += fprintf(fp, "%s", strim(hpp->buf));
0677 }
0678 }
0679
0680 fprintf(fp, "\n# ");
0681
0682
0683 print_hierarchy_indent(sep, indent, dots, fp);
0684
0685
0686 fmt_node = list_first_entry(&hists->hpp_formats,
0687 struct perf_hpp_list_node, list);
0688
0689 first_col = true;
0690 perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) {
0691 if (!first_col)
0692 fprintf(fp, "%s", sep ?: "..");
0693 first_col = false;
0694
0695 width = fmt->width(fmt, hpp, hists);
0696 fprintf(fp, "%.*s", width, dots);
0697 }
0698
0699 depth = 0;
0700 list_for_each_entry_continue(fmt_node, &hists->hpp_formats, list) {
0701 first_col = true;
0702 width = depth * HIERARCHY_INDENT;
0703
0704 perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) {
0705 if (perf_hpp__should_skip(fmt, hists))
0706 continue;
0707
0708 if (!first_col)
0709 width++;
0710 first_col = false;
0711
0712 width += fmt->width(fmt, hpp, hists);
0713 }
0714
0715 if (width > header_width)
0716 header_width = width;
0717
0718 depth++;
0719 }
0720
0721 fprintf(fp, "%s%-.*s", sep ?: " ", header_width, dots);
0722
0723 fprintf(fp, "\n#\n");
0724
0725 return 2;
0726 }
0727
0728 static void fprintf_line(struct hists *hists, struct perf_hpp *hpp,
0729 int line, FILE *fp)
0730 {
0731 struct perf_hpp_fmt *fmt;
0732 const char *sep = symbol_conf.field_sep;
0733 bool first = true;
0734 int span = 0;
0735
0736 hists__for_each_format(hists, fmt) {
0737 if (perf_hpp__should_skip(fmt, hists))
0738 continue;
0739
0740 if (!first && !span)
0741 fprintf(fp, "%s", sep ?: " ");
0742 else
0743 first = false;
0744
0745 fmt->header(fmt, hpp, hists, line, &span);
0746
0747 if (!span)
0748 fprintf(fp, "%s", hpp->buf);
0749 }
0750 }
0751
0752 static int
0753 hists__fprintf_standard_headers(struct hists *hists,
0754 struct perf_hpp *hpp,
0755 FILE *fp)
0756 {
0757 struct perf_hpp_list *hpp_list = hists->hpp_list;
0758 struct perf_hpp_fmt *fmt;
0759 unsigned int width;
0760 const char *sep = symbol_conf.field_sep;
0761 bool first = true;
0762 int line;
0763
0764 for (line = 0; line < hpp_list->nr_header_lines; line++) {
0765
0766 if (line)
0767 fprintf(fp, "# ");
0768 fprintf_line(hists, hpp, line, fp);
0769 fprintf(fp, "\n");
0770 }
0771
0772 if (sep)
0773 return hpp_list->nr_header_lines;
0774
0775 first = true;
0776
0777 fprintf(fp, "# ");
0778
0779 hists__for_each_format(hists, fmt) {
0780 unsigned int i;
0781
0782 if (perf_hpp__should_skip(fmt, hists))
0783 continue;
0784
0785 if (!first)
0786 fprintf(fp, "%s", sep ?: " ");
0787 else
0788 first = false;
0789
0790 width = fmt->width(fmt, hpp, hists);
0791 for (i = 0; i < width; i++)
0792 fprintf(fp, ".");
0793 }
0794
0795 fprintf(fp, "\n");
0796 fprintf(fp, "#\n");
0797 return hpp_list->nr_header_lines + 2;
0798 }
0799
0800 int hists__fprintf_headers(struct hists *hists, FILE *fp)
0801 {
0802 char bf[1024];
0803 struct perf_hpp dummy_hpp = {
0804 .buf = bf,
0805 .size = sizeof(bf),
0806 };
0807
0808 fprintf(fp, "# ");
0809
0810 if (symbol_conf.report_hierarchy)
0811 return hists__fprintf_hierarchy_headers(hists, &dummy_hpp, fp);
0812 else
0813 return hists__fprintf_standard_headers(hists, &dummy_hpp, fp);
0814
0815 }
0816
0817 size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows,
0818 int max_cols, float min_pcnt, FILE *fp,
0819 bool ignore_callchains)
0820 {
0821 struct rb_node *nd;
0822 size_t ret = 0;
0823 const char *sep = symbol_conf.field_sep;
0824 int nr_rows = 0;
0825 size_t linesz;
0826 char *line = NULL;
0827 unsigned indent;
0828
0829 init_rem_hits();
0830
0831 hists__reset_column_width(hists);
0832
0833 if (symbol_conf.col_width_list_str)
0834 perf_hpp__set_user_width(symbol_conf.col_width_list_str);
0835
0836 if (show_header)
0837 nr_rows += hists__fprintf_headers(hists, fp);
0838
0839 if (max_rows && nr_rows >= max_rows)
0840 goto out;
0841
0842 linesz = hists__sort_list_width(hists) + 3 + 1;
0843 linesz += perf_hpp__color_overhead();
0844 line = malloc(linesz);
0845 if (line == NULL) {
0846 ret = -1;
0847 goto out;
0848 }
0849
0850 indent = hists__overhead_width(hists) + 4;
0851
0852 for (nd = rb_first_cached(&hists->entries); nd;
0853 nd = __rb_hierarchy_next(nd, HMD_FORCE_CHILD)) {
0854 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
0855 float percent;
0856
0857 if (h->filtered)
0858 continue;
0859
0860 if (symbol_conf.report_individual_block)
0861 percent = block_info__total_cycles_percent(h);
0862 else
0863 percent = hist_entry__get_percent_limit(h);
0864
0865 if (percent < min_pcnt)
0866 continue;
0867
0868 ret += hist_entry__fprintf(h, max_cols, line, linesz, fp, ignore_callchains);
0869
0870 if (max_rows && ++nr_rows >= max_rows)
0871 break;
0872
0873
0874
0875
0876
0877 if (!h->leaf && !hist_entry__has_hierarchy_children(h, min_pcnt)) {
0878 int depth = hists->nr_hpp_node + h->depth + 1;
0879
0880 print_hierarchy_indent(sep, depth, " ", fp);
0881 fprintf(fp, "%*sno entry >= %.2f%%\n", indent, "", min_pcnt);
0882
0883 if (max_rows && ++nr_rows >= max_rows)
0884 break;
0885 }
0886
0887 if (h->ms.map == NULL && verbose > 1) {
0888 maps__fprintf(h->thread->maps, fp);
0889 fprintf(fp, "%.10s end\n", graph_dotted_line);
0890 }
0891 }
0892
0893 free(line);
0894 out:
0895 zfree(&rem_sq_bracket);
0896
0897 return ret;
0898 }
0899
0900 size_t events_stats__fprintf(struct events_stats *stats, FILE *fp,
0901 bool skip_empty)
0902 {
0903 int i;
0904 size_t ret = 0;
0905 u32 total = stats->nr_events[0];
0906
0907 for (i = 0; i < PERF_RECORD_HEADER_MAX; ++i) {
0908 const char *name;
0909
0910 name = perf_event__name(i);
0911 if (!strcmp(name, "UNKNOWN"))
0912 continue;
0913 if (skip_empty && !stats->nr_events[i])
0914 continue;
0915
0916 if (i && total) {
0917 ret += fprintf(fp, "%16s events: %10d (%4.1f%%)\n",
0918 name, stats->nr_events[i],
0919 100.0 * stats->nr_events[i] / total);
0920 } else {
0921 ret += fprintf(fp, "%16s events: %10d\n",
0922 name, stats->nr_events[i]);
0923 }
0924 }
0925
0926 return ret;
0927 }