17ccf4f90SNamhyung Kim #include <stdio.h> 27ccf4f90SNamhyung Kim 37ccf4f90SNamhyung Kim #include "../../util/util.h" 47ccf4f90SNamhyung Kim #include "../../util/hist.h" 57ccf4f90SNamhyung Kim #include "../../util/sort.h" 65b9e2146SNamhyung Kim #include "../../util/evsel.h" 77ccf4f90SNamhyung Kim 87ccf4f90SNamhyung Kim 97ccf4f90SNamhyung Kim static size_t callchain__fprintf_left_margin(FILE *fp, int left_margin) 107ccf4f90SNamhyung Kim { 117ccf4f90SNamhyung Kim int i; 127ccf4f90SNamhyung Kim int ret = fprintf(fp, " "); 137ccf4f90SNamhyung Kim 147ccf4f90SNamhyung Kim for (i = 0; i < left_margin; i++) 157ccf4f90SNamhyung Kim ret += fprintf(fp, " "); 167ccf4f90SNamhyung Kim 177ccf4f90SNamhyung Kim return ret; 187ccf4f90SNamhyung Kim } 197ccf4f90SNamhyung Kim 207ccf4f90SNamhyung Kim static size_t ipchain__fprintf_graph_line(FILE *fp, int depth, int depth_mask, 217ccf4f90SNamhyung Kim int left_margin) 227ccf4f90SNamhyung Kim { 237ccf4f90SNamhyung Kim int i; 247ccf4f90SNamhyung Kim size_t ret = callchain__fprintf_left_margin(fp, left_margin); 257ccf4f90SNamhyung Kim 267ccf4f90SNamhyung Kim for (i = 0; i < depth; i++) 277ccf4f90SNamhyung Kim if (depth_mask & (1 << i)) 287ccf4f90SNamhyung Kim ret += fprintf(fp, "| "); 297ccf4f90SNamhyung Kim else 307ccf4f90SNamhyung Kim ret += fprintf(fp, " "); 317ccf4f90SNamhyung Kim 327ccf4f90SNamhyung Kim ret += fprintf(fp, "\n"); 337ccf4f90SNamhyung Kim 347ccf4f90SNamhyung Kim return ret; 357ccf4f90SNamhyung Kim } 367ccf4f90SNamhyung Kim 375ab250caSNamhyung Kim static size_t ipchain__fprintf_graph(FILE *fp, struct callchain_node *node, 385ab250caSNamhyung Kim struct callchain_list *chain, 397ccf4f90SNamhyung Kim int depth, int depth_mask, int period, 405ab250caSNamhyung Kim u64 total_samples, int left_margin) 417ccf4f90SNamhyung Kim { 427ccf4f90SNamhyung Kim int i; 437ccf4f90SNamhyung Kim size_t ret = 0; 442989ccaaSAndi Kleen char bf[1024]; 457ccf4f90SNamhyung Kim 467ccf4f90SNamhyung Kim ret += callchain__fprintf_left_margin(fp, left_margin); 477ccf4f90SNamhyung Kim for (i = 0; i < depth; i++) { 487ccf4f90SNamhyung Kim if (depth_mask & (1 << i)) 497ccf4f90SNamhyung Kim ret += fprintf(fp, "|"); 507ccf4f90SNamhyung Kim else 517ccf4f90SNamhyung Kim ret += fprintf(fp, " "); 527ccf4f90SNamhyung Kim if (!period && i == depth - 1) { 535ab250caSNamhyung Kim ret += fprintf(fp, "--"); 545ab250caSNamhyung Kim ret += callchain_node__fprintf_value(node, fp, total_samples); 555ab250caSNamhyung Kim ret += fprintf(fp, "--"); 567ccf4f90SNamhyung Kim } else 577ccf4f90SNamhyung Kim ret += fprintf(fp, "%s", " "); 587ccf4f90SNamhyung Kim } 592989ccaaSAndi Kleen fputs(callchain_list__sym_name(chain, bf, sizeof(bf), false), fp); 602989ccaaSAndi Kleen fputc('\n', fp); 617ccf4f90SNamhyung Kim return ret; 627ccf4f90SNamhyung Kim } 637ccf4f90SNamhyung Kim 647ccf4f90SNamhyung Kim static struct symbol *rem_sq_bracket; 657ccf4f90SNamhyung Kim static struct callchain_list rem_hits; 667ccf4f90SNamhyung Kim 677ccf4f90SNamhyung Kim static void init_rem_hits(void) 687ccf4f90SNamhyung Kim { 697ccf4f90SNamhyung Kim rem_sq_bracket = malloc(sizeof(*rem_sq_bracket) + 6); 707ccf4f90SNamhyung Kim if (!rem_sq_bracket) { 717ccf4f90SNamhyung Kim fprintf(stderr, "Not enough memory to display remaining hits\n"); 727ccf4f90SNamhyung Kim return; 737ccf4f90SNamhyung Kim } 747ccf4f90SNamhyung Kim 757ccf4f90SNamhyung Kim strcpy(rem_sq_bracket->name, "[...]"); 767ccf4f90SNamhyung Kim rem_hits.ms.sym = rem_sq_bracket; 777ccf4f90SNamhyung Kim } 787ccf4f90SNamhyung Kim 797ccf4f90SNamhyung Kim static size_t __callchain__fprintf_graph(FILE *fp, struct rb_root *root, 807ccf4f90SNamhyung Kim u64 total_samples, int depth, 817ccf4f90SNamhyung Kim int depth_mask, int left_margin) 827ccf4f90SNamhyung Kim { 837ccf4f90SNamhyung Kim struct rb_node *node, *next; 84f2af0086SNamhyung Kim struct callchain_node *child = NULL; 857ccf4f90SNamhyung Kim struct callchain_list *chain; 867ccf4f90SNamhyung Kim int new_depth_mask = depth_mask; 877ccf4f90SNamhyung Kim u64 remaining; 887ccf4f90SNamhyung Kim size_t ret = 0; 897ccf4f90SNamhyung Kim int i; 907ccf4f90SNamhyung Kim uint entries_printed = 0; 91f2af0086SNamhyung Kim int cumul_count = 0; 927ccf4f90SNamhyung Kim 937ccf4f90SNamhyung Kim remaining = total_samples; 947ccf4f90SNamhyung Kim 957ccf4f90SNamhyung Kim node = rb_first(root); 967ccf4f90SNamhyung Kim while (node) { 977ccf4f90SNamhyung Kim u64 new_total; 987ccf4f90SNamhyung Kim u64 cumul; 997ccf4f90SNamhyung Kim 1007ccf4f90SNamhyung Kim child = rb_entry(node, struct callchain_node, rb_node); 1017ccf4f90SNamhyung Kim cumul = callchain_cumul_hits(child); 1027ccf4f90SNamhyung Kim remaining -= cumul; 103f2af0086SNamhyung Kim cumul_count += callchain_cumul_counts(child); 1047ccf4f90SNamhyung Kim 1057ccf4f90SNamhyung Kim /* 1067ccf4f90SNamhyung Kim * The depth mask manages the output of pipes that show 1077ccf4f90SNamhyung Kim * the depth. We don't want to keep the pipes of the current 1087ccf4f90SNamhyung Kim * level for the last child of this depth. 1097ccf4f90SNamhyung Kim * Except if we have remaining filtered hits. They will 1107ccf4f90SNamhyung Kim * supersede the last child 1117ccf4f90SNamhyung Kim */ 1127ccf4f90SNamhyung Kim next = rb_next(node); 1137ccf4f90SNamhyung Kim if (!next && (callchain_param.mode != CHAIN_GRAPH_REL || !remaining)) 1147ccf4f90SNamhyung Kim new_depth_mask &= ~(1 << (depth - 1)); 1157ccf4f90SNamhyung Kim 1167ccf4f90SNamhyung Kim /* 1177ccf4f90SNamhyung Kim * But we keep the older depth mask for the line separator 1187ccf4f90SNamhyung Kim * to keep the level link until we reach the last child 1197ccf4f90SNamhyung Kim */ 1207ccf4f90SNamhyung Kim ret += ipchain__fprintf_graph_line(fp, depth, depth_mask, 1217ccf4f90SNamhyung Kim left_margin); 1227ccf4f90SNamhyung Kim i = 0; 1237ccf4f90SNamhyung Kim list_for_each_entry(chain, &child->val, list) { 1245ab250caSNamhyung Kim ret += ipchain__fprintf_graph(fp, child, chain, depth, 1257ccf4f90SNamhyung Kim new_depth_mask, i++, 1267ccf4f90SNamhyung Kim total_samples, 1277ccf4f90SNamhyung Kim left_margin); 1287ccf4f90SNamhyung Kim } 1297ccf4f90SNamhyung Kim 1307ccf4f90SNamhyung Kim if (callchain_param.mode == CHAIN_GRAPH_REL) 1317ccf4f90SNamhyung Kim new_total = child->children_hit; 1327ccf4f90SNamhyung Kim else 1337ccf4f90SNamhyung Kim new_total = total_samples; 1347ccf4f90SNamhyung Kim 1357ccf4f90SNamhyung Kim ret += __callchain__fprintf_graph(fp, &child->rb_root, new_total, 1367ccf4f90SNamhyung Kim depth + 1, 1377ccf4f90SNamhyung Kim new_depth_mask | (1 << depth), 1387ccf4f90SNamhyung Kim left_margin); 1397ccf4f90SNamhyung Kim node = next; 1407ccf4f90SNamhyung Kim if (++entries_printed == callchain_param.print_limit) 1417ccf4f90SNamhyung Kim break; 1427ccf4f90SNamhyung Kim } 1437ccf4f90SNamhyung Kim 1447ccf4f90SNamhyung Kim if (callchain_param.mode == CHAIN_GRAPH_REL && 1457ccf4f90SNamhyung Kim remaining && remaining != total_samples) { 1465ab250caSNamhyung Kim struct callchain_node rem_node = { 1475ab250caSNamhyung Kim .hit = remaining, 1485ab250caSNamhyung Kim }; 1497ccf4f90SNamhyung Kim 1507ccf4f90SNamhyung Kim if (!rem_sq_bracket) 1517ccf4f90SNamhyung Kim return ret; 1527ccf4f90SNamhyung Kim 153f2af0086SNamhyung Kim if (callchain_param.value == CCVAL_COUNT && child && child->parent) { 154f2af0086SNamhyung Kim rem_node.count = child->parent->children_count - cumul_count; 155f2af0086SNamhyung Kim if (rem_node.count <= 0) 156f2af0086SNamhyung Kim return ret; 157f2af0086SNamhyung Kim } 158f2af0086SNamhyung Kim 1597ccf4f90SNamhyung Kim new_depth_mask &= ~(1 << (depth - 1)); 1605ab250caSNamhyung Kim ret += ipchain__fprintf_graph(fp, &rem_node, &rem_hits, depth, 1617ccf4f90SNamhyung Kim new_depth_mask, 0, total_samples, 1625ab250caSNamhyung Kim left_margin); 1637ccf4f90SNamhyung Kim } 1647ccf4f90SNamhyung Kim 1657ccf4f90SNamhyung Kim return ret; 1667ccf4f90SNamhyung Kim } 1677ccf4f90SNamhyung Kim 1687ccf4f90SNamhyung Kim static size_t callchain__fprintf_graph(FILE *fp, struct rb_root *root, 169*54d27b31SNamhyung Kim u64 total_samples, u64 parent_samples, 170*54d27b31SNamhyung Kim int left_margin) 1717ccf4f90SNamhyung Kim { 1727ccf4f90SNamhyung Kim struct callchain_node *cnode; 1737ccf4f90SNamhyung Kim struct callchain_list *chain; 1747ccf4f90SNamhyung Kim u32 entries_printed = 0; 1757ccf4f90SNamhyung Kim bool printed = false; 1767ccf4f90SNamhyung Kim struct rb_node *node; 1777ccf4f90SNamhyung Kim int i = 0; 1787ccf4f90SNamhyung Kim int ret = 0; 1792989ccaaSAndi Kleen char bf[1024]; 1807ccf4f90SNamhyung Kim 1817ccf4f90SNamhyung Kim /* 1827ccf4f90SNamhyung Kim * If have one single callchain root, don't bother printing 1837ccf4f90SNamhyung Kim * its percentage (100 % in fractal mode and the same percentage 1847ccf4f90SNamhyung Kim * than the hist in graph mode). This also avoid one level of column. 1857ccf4f90SNamhyung Kim */ 1867ccf4f90SNamhyung Kim node = rb_first(root); 1877ccf4f90SNamhyung Kim if (node && !rb_next(node)) { 1887ccf4f90SNamhyung Kim cnode = rb_entry(node, struct callchain_node, rb_node); 1897ccf4f90SNamhyung Kim list_for_each_entry(chain, &cnode->val, list) { 1907ccf4f90SNamhyung Kim /* 1917ccf4f90SNamhyung Kim * If we sort by symbol, the first entry is the same than 1927ccf4f90SNamhyung Kim * the symbol. No need to print it otherwise it appears as 1937ccf4f90SNamhyung Kim * displayed twice. 1947ccf4f90SNamhyung Kim */ 195cfaa154bSNamhyung Kim if (!i++ && field_order == NULL && 196cfaa154bSNamhyung Kim sort_order && !prefixcmp(sort_order, "sym")) 1977ccf4f90SNamhyung Kim continue; 1987ccf4f90SNamhyung Kim if (!printed) { 1997ccf4f90SNamhyung Kim ret += callchain__fprintf_left_margin(fp, left_margin); 2007ccf4f90SNamhyung Kim ret += fprintf(fp, "|\n"); 2017ccf4f90SNamhyung Kim ret += callchain__fprintf_left_margin(fp, left_margin); 2027ccf4f90SNamhyung Kim ret += fprintf(fp, "---"); 2037ccf4f90SNamhyung Kim left_margin += 3; 2047ccf4f90SNamhyung Kim printed = true; 2057ccf4f90SNamhyung Kim } else 2067ccf4f90SNamhyung Kim ret += callchain__fprintf_left_margin(fp, left_margin); 2077ccf4f90SNamhyung Kim 2082989ccaaSAndi Kleen ret += fprintf(fp, "%s\n", callchain_list__sym_name(chain, bf, sizeof(bf), 2092989ccaaSAndi Kleen false)); 2107ccf4f90SNamhyung Kim 2117ccf4f90SNamhyung Kim if (++entries_printed == callchain_param.print_limit) 2127ccf4f90SNamhyung Kim break; 2137ccf4f90SNamhyung Kim } 2147ccf4f90SNamhyung Kim root = &cnode->rb_root; 2157ccf4f90SNamhyung Kim } 2167ccf4f90SNamhyung Kim 217*54d27b31SNamhyung Kim if (callchain_param.mode == CHAIN_GRAPH_REL) 218*54d27b31SNamhyung Kim total_samples = parent_samples; 219*54d27b31SNamhyung Kim 2207ccf4f90SNamhyung Kim ret += __callchain__fprintf_graph(fp, root, total_samples, 2217ccf4f90SNamhyung Kim 1, 1, left_margin); 2227ccf4f90SNamhyung Kim ret += fprintf(fp, "\n"); 2237ccf4f90SNamhyung Kim 2247ccf4f90SNamhyung Kim return ret; 2257ccf4f90SNamhyung Kim } 2267ccf4f90SNamhyung Kim 227316c7136SArnaldo Carvalho de Melo static size_t __callchain__fprintf_flat(FILE *fp, struct callchain_node *node, 2287ccf4f90SNamhyung Kim u64 total_samples) 2297ccf4f90SNamhyung Kim { 2307ccf4f90SNamhyung Kim struct callchain_list *chain; 2317ccf4f90SNamhyung Kim size_t ret = 0; 2322989ccaaSAndi Kleen char bf[1024]; 2337ccf4f90SNamhyung Kim 234316c7136SArnaldo Carvalho de Melo if (!node) 2357ccf4f90SNamhyung Kim return 0; 2367ccf4f90SNamhyung Kim 237316c7136SArnaldo Carvalho de Melo ret += __callchain__fprintf_flat(fp, node->parent, total_samples); 2387ccf4f90SNamhyung Kim 2397ccf4f90SNamhyung Kim 240316c7136SArnaldo Carvalho de Melo list_for_each_entry(chain, &node->val, list) { 2417ccf4f90SNamhyung Kim if (chain->ip >= PERF_CONTEXT_MAX) 2427ccf4f90SNamhyung Kim continue; 2432989ccaaSAndi Kleen ret += fprintf(fp, " %s\n", callchain_list__sym_name(chain, 2442989ccaaSAndi Kleen bf, sizeof(bf), false)); 2457ccf4f90SNamhyung Kim } 2467ccf4f90SNamhyung Kim 2477ccf4f90SNamhyung Kim return ret; 2487ccf4f90SNamhyung Kim } 2497ccf4f90SNamhyung Kim 250316c7136SArnaldo Carvalho de Melo static size_t callchain__fprintf_flat(FILE *fp, struct rb_root *tree, 2517ccf4f90SNamhyung Kim u64 total_samples) 2527ccf4f90SNamhyung Kim { 2537ccf4f90SNamhyung Kim size_t ret = 0; 2547ccf4f90SNamhyung Kim u32 entries_printed = 0; 2557ccf4f90SNamhyung Kim struct callchain_node *chain; 256316c7136SArnaldo Carvalho de Melo struct rb_node *rb_node = rb_first(tree); 2577ccf4f90SNamhyung Kim 2587ccf4f90SNamhyung Kim while (rb_node) { 2597ccf4f90SNamhyung Kim chain = rb_entry(rb_node, struct callchain_node, rb_node); 2607ccf4f90SNamhyung Kim 2615ab250caSNamhyung Kim ret += fprintf(fp, " "); 2625ab250caSNamhyung Kim ret += callchain_node__fprintf_value(chain, fp, total_samples); 2635ab250caSNamhyung Kim ret += fprintf(fp, "\n"); 2647ccf4f90SNamhyung Kim ret += __callchain__fprintf_flat(fp, chain, total_samples); 2657ccf4f90SNamhyung Kim ret += fprintf(fp, "\n"); 2667ccf4f90SNamhyung Kim if (++entries_printed == callchain_param.print_limit) 2677ccf4f90SNamhyung Kim break; 2687ccf4f90SNamhyung Kim 2697ccf4f90SNamhyung Kim rb_node = rb_next(rb_node); 2707ccf4f90SNamhyung Kim } 2717ccf4f90SNamhyung Kim 2727ccf4f90SNamhyung Kim return ret; 2737ccf4f90SNamhyung Kim } 2747ccf4f90SNamhyung Kim 27526e77924SNamhyung Kim static size_t __callchain__fprintf_folded(FILE *fp, struct callchain_node *node) 27626e77924SNamhyung Kim { 27726e77924SNamhyung Kim const char *sep = symbol_conf.field_sep ?: ";"; 27826e77924SNamhyung Kim struct callchain_list *chain; 27926e77924SNamhyung Kim size_t ret = 0; 28026e77924SNamhyung Kim char bf[1024]; 28126e77924SNamhyung Kim bool first; 28226e77924SNamhyung Kim 28326e77924SNamhyung Kim if (!node) 28426e77924SNamhyung Kim return 0; 28526e77924SNamhyung Kim 28626e77924SNamhyung Kim ret += __callchain__fprintf_folded(fp, node->parent); 28726e77924SNamhyung Kim 28826e77924SNamhyung Kim first = (ret == 0); 28926e77924SNamhyung Kim list_for_each_entry(chain, &node->val, list) { 29026e77924SNamhyung Kim if (chain->ip >= PERF_CONTEXT_MAX) 29126e77924SNamhyung Kim continue; 29226e77924SNamhyung Kim ret += fprintf(fp, "%s%s", first ? "" : sep, 29326e77924SNamhyung Kim callchain_list__sym_name(chain, 29426e77924SNamhyung Kim bf, sizeof(bf), false)); 29526e77924SNamhyung Kim first = false; 29626e77924SNamhyung Kim } 29726e77924SNamhyung Kim 29826e77924SNamhyung Kim return ret; 29926e77924SNamhyung Kim } 30026e77924SNamhyung Kim 30126e77924SNamhyung Kim static size_t callchain__fprintf_folded(FILE *fp, struct rb_root *tree, 30226e77924SNamhyung Kim u64 total_samples) 30326e77924SNamhyung Kim { 30426e77924SNamhyung Kim size_t ret = 0; 30526e77924SNamhyung Kim u32 entries_printed = 0; 30626e77924SNamhyung Kim struct callchain_node *chain; 30726e77924SNamhyung Kim struct rb_node *rb_node = rb_first(tree); 30826e77924SNamhyung Kim 30926e77924SNamhyung Kim while (rb_node) { 31026e77924SNamhyung Kim 31126e77924SNamhyung Kim chain = rb_entry(rb_node, struct callchain_node, rb_node); 31226e77924SNamhyung Kim 3135ab250caSNamhyung Kim ret += callchain_node__fprintf_value(chain, fp, total_samples); 3145ab250caSNamhyung Kim ret += fprintf(fp, " "); 31526e77924SNamhyung Kim ret += __callchain__fprintf_folded(fp, chain); 31626e77924SNamhyung Kim ret += fprintf(fp, "\n"); 31726e77924SNamhyung Kim if (++entries_printed == callchain_param.print_limit) 31826e77924SNamhyung Kim break; 31926e77924SNamhyung Kim 32026e77924SNamhyung Kim rb_node = rb_next(rb_node); 32126e77924SNamhyung Kim } 32226e77924SNamhyung Kim 32326e77924SNamhyung Kim return ret; 32426e77924SNamhyung Kim } 32526e77924SNamhyung Kim 3267ccf4f90SNamhyung Kim static size_t hist_entry_callchain__fprintf(struct hist_entry *he, 3277ccf4f90SNamhyung Kim u64 total_samples, int left_margin, 3287ccf4f90SNamhyung Kim FILE *fp) 3297ccf4f90SNamhyung Kim { 330*54d27b31SNamhyung Kim u64 parent_samples = he->stat.period; 331*54d27b31SNamhyung Kim 332*54d27b31SNamhyung Kim if (symbol_conf.cumulate_callchain) 333*54d27b31SNamhyung Kim parent_samples = he->stat_acc->period; 334*54d27b31SNamhyung Kim 3357ccf4f90SNamhyung Kim switch (callchain_param.mode) { 3367ccf4f90SNamhyung Kim case CHAIN_GRAPH_REL: 337*54d27b31SNamhyung Kim return callchain__fprintf_graph(fp, &he->sorted_chain, total_samples, 338*54d27b31SNamhyung Kim parent_samples, left_margin); 3397ccf4f90SNamhyung Kim break; 3407ccf4f90SNamhyung Kim case CHAIN_GRAPH_ABS: 3417ccf4f90SNamhyung Kim return callchain__fprintf_graph(fp, &he->sorted_chain, total_samples, 342*54d27b31SNamhyung Kim parent_samples, left_margin); 3437ccf4f90SNamhyung Kim break; 3447ccf4f90SNamhyung Kim case CHAIN_FLAT: 3457ccf4f90SNamhyung Kim return callchain__fprintf_flat(fp, &he->sorted_chain, total_samples); 3467ccf4f90SNamhyung Kim break; 34726e77924SNamhyung Kim case CHAIN_FOLDED: 34826e77924SNamhyung Kim return callchain__fprintf_folded(fp, &he->sorted_chain, total_samples); 34926e77924SNamhyung Kim break; 3507ccf4f90SNamhyung Kim case CHAIN_NONE: 3517ccf4f90SNamhyung Kim break; 3527ccf4f90SNamhyung Kim default: 3537ccf4f90SNamhyung Kim pr_err("Bad callchain mode\n"); 3547ccf4f90SNamhyung Kim } 3557ccf4f90SNamhyung Kim 3567ccf4f90SNamhyung Kim return 0; 3577ccf4f90SNamhyung Kim } 3587ccf4f90SNamhyung Kim 35926d8b338SNamhyung Kim static int hist_entry__snprintf(struct hist_entry *he, struct perf_hpp *hpp) 360be0e6d10SJiri Olsa { 361be0e6d10SJiri Olsa const char *sep = symbol_conf.field_sep; 362be0e6d10SJiri Olsa struct perf_hpp_fmt *fmt; 363be0e6d10SJiri Olsa char *start = hpp->buf; 364be0e6d10SJiri Olsa int ret; 365be0e6d10SJiri Olsa bool first = true; 366be0e6d10SJiri Olsa 367be0e6d10SJiri Olsa if (symbol_conf.exclude_other && !he->parent) 368be0e6d10SJiri Olsa return 0; 369be0e6d10SJiri Olsa 370be0e6d10SJiri Olsa perf_hpp__for_each_format(fmt) { 371361459f1SNamhyung Kim if (perf_hpp__should_skip(fmt, he->hists)) 372e67d49a7SNamhyung Kim continue; 373e67d49a7SNamhyung Kim 374be0e6d10SJiri Olsa /* 375be0e6d10SJiri Olsa * If there's no field_sep, we still need 376be0e6d10SJiri Olsa * to display initial ' '. 377be0e6d10SJiri Olsa */ 378be0e6d10SJiri Olsa if (!sep || !first) { 379be0e6d10SJiri Olsa ret = scnprintf(hpp->buf, hpp->size, "%s", sep ?: " "); 380be0e6d10SJiri Olsa advance_hpp(hpp, ret); 381be0e6d10SJiri Olsa } else 382be0e6d10SJiri Olsa first = false; 383be0e6d10SJiri Olsa 3849754c4f9SJiri Olsa if (perf_hpp__use_color() && fmt->color) 385be0e6d10SJiri Olsa ret = fmt->color(fmt, hpp, he); 386be0e6d10SJiri Olsa else 387be0e6d10SJiri Olsa ret = fmt->entry(fmt, hpp, he); 388be0e6d10SJiri Olsa 389be0e6d10SJiri Olsa advance_hpp(hpp, ret); 390be0e6d10SJiri Olsa } 391be0e6d10SJiri Olsa 392be0e6d10SJiri Olsa return hpp->buf - start; 393be0e6d10SJiri Olsa } 394be0e6d10SJiri Olsa 395000078bcSNamhyung Kim static int hist_entry__fprintf(struct hist_entry *he, size_t size, 39699cf666cSArnaldo Carvalho de Melo struct hists *hists, 39799cf666cSArnaldo Carvalho de Melo char *bf, size_t bfsz, FILE *fp) 398000078bcSNamhyung Kim { 399000078bcSNamhyung Kim int ret; 400ea251d51SNamhyung Kim struct perf_hpp hpp = { 401ea251d51SNamhyung Kim .buf = bf, 402ea251d51SNamhyung Kim .size = size, 403ea251d51SNamhyung Kim }; 4047e597d32SNamhyung Kim u64 total_period = hists->stats.total_period; 405000078bcSNamhyung Kim 40699cf666cSArnaldo Carvalho de Melo if (size == 0 || size > bfsz) 40799cf666cSArnaldo Carvalho de Melo size = hpp.size = bfsz; 408000078bcSNamhyung Kim 40926d8b338SNamhyung Kim hist_entry__snprintf(he, &hpp); 410000078bcSNamhyung Kim 411000078bcSNamhyung Kim ret = fprintf(fp, "%s\n", bf); 412000078bcSNamhyung Kim 413000078bcSNamhyung Kim if (symbol_conf.use_callchain) 4147e597d32SNamhyung Kim ret += hist_entry_callchain__fprintf(he, total_period, 0, fp); 415000078bcSNamhyung Kim 416000078bcSNamhyung Kim return ret; 417000078bcSNamhyung Kim } 418000078bcSNamhyung Kim 41941724e4cSJiri Olsa size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows, 420064f1981SNamhyung Kim int max_cols, float min_pcnt, FILE *fp) 4217ccf4f90SNamhyung Kim { 4221240005eSJiri Olsa struct perf_hpp_fmt *fmt; 4237ccf4f90SNamhyung Kim struct rb_node *nd; 4247ccf4f90SNamhyung Kim size_t ret = 0; 4257ccf4f90SNamhyung Kim unsigned int width; 4267ccf4f90SNamhyung Kim const char *sep = symbol_conf.field_sep; 4271240005eSJiri Olsa int nr_rows = 0; 428ed279da2SJiri Olsa char bf[96]; 429ea251d51SNamhyung Kim struct perf_hpp dummy_hpp = { 430ea251d51SNamhyung Kim .buf = bf, 431ea251d51SNamhyung Kim .size = sizeof(bf), 432ea251d51SNamhyung Kim }; 4335395a048SJiri Olsa bool first = true; 43499cf666cSArnaldo Carvalho de Melo size_t linesz; 43599cf666cSArnaldo Carvalho de Melo char *line = NULL; 4367ccf4f90SNamhyung Kim 4377ccf4f90SNamhyung Kim init_rem_hits(); 4387ccf4f90SNamhyung Kim 439678a500dSNamhyung Kim perf_hpp__for_each_format(fmt) 440678a500dSNamhyung Kim perf_hpp__reset_width(fmt, hists); 44126d8b338SNamhyung Kim 4425b591669SNamhyung Kim if (symbol_conf.col_width_list_str) 4435b591669SNamhyung Kim perf_hpp__set_user_width(symbol_conf.col_width_list_str); 4445b591669SNamhyung Kim 4457ccf4f90SNamhyung Kim if (!show_header) 4467ccf4f90SNamhyung Kim goto print_entries; 4477ccf4f90SNamhyung Kim 448ea251d51SNamhyung Kim fprintf(fp, "# "); 4497ccf4f90SNamhyung Kim 4501240005eSJiri Olsa perf_hpp__for_each_format(fmt) { 451361459f1SNamhyung Kim if (perf_hpp__should_skip(fmt, hists)) 452e67d49a7SNamhyung Kim continue; 453e67d49a7SNamhyung Kim 4545395a048SJiri Olsa if (!first) 455ea251d51SNamhyung Kim fprintf(fp, "%s", sep ?: " "); 4565395a048SJiri Olsa else 4575395a048SJiri Olsa first = false; 4587ccf4f90SNamhyung Kim 45994a0793dSNamhyung Kim fmt->header(fmt, &dummy_hpp, hists_to_evsel(hists)); 460ea251d51SNamhyung Kim fprintf(fp, "%s", bf); 4617ccf4f90SNamhyung Kim } 4627ccf4f90SNamhyung Kim 4637ccf4f90SNamhyung Kim fprintf(fp, "\n"); 4647ccf4f90SNamhyung Kim if (max_rows && ++nr_rows >= max_rows) 4657ccf4f90SNamhyung Kim goto out; 4667ccf4f90SNamhyung Kim 4677ccf4f90SNamhyung Kim if (sep) 4687ccf4f90SNamhyung Kim goto print_entries; 4697ccf4f90SNamhyung Kim 4705395a048SJiri Olsa first = true; 4715395a048SJiri Olsa 472ea251d51SNamhyung Kim fprintf(fp, "# "); 473ea251d51SNamhyung Kim 4741240005eSJiri Olsa perf_hpp__for_each_format(fmt) { 4751240005eSJiri Olsa unsigned int i; 476ea251d51SNamhyung Kim 477361459f1SNamhyung Kim if (perf_hpp__should_skip(fmt, hists)) 478e67d49a7SNamhyung Kim continue; 479e67d49a7SNamhyung Kim 4805395a048SJiri Olsa if (!first) 481ea251d51SNamhyung Kim fprintf(fp, "%s", sep ?: " "); 4825395a048SJiri Olsa else 4835395a048SJiri Olsa first = false; 484ea251d51SNamhyung Kim 48594a0793dSNamhyung Kim width = fmt->width(fmt, &dummy_hpp, hists_to_evsel(hists)); 486ea251d51SNamhyung Kim for (i = 0; i < width; i++) 487ea251d51SNamhyung Kim fprintf(fp, "."); 4887ccf4f90SNamhyung Kim } 489ea251d51SNamhyung Kim 4907ccf4f90SNamhyung Kim fprintf(fp, "\n"); 4917ccf4f90SNamhyung Kim if (max_rows && ++nr_rows >= max_rows) 4927ccf4f90SNamhyung Kim goto out; 4937ccf4f90SNamhyung Kim 4947ccf4f90SNamhyung Kim fprintf(fp, "#\n"); 4957ccf4f90SNamhyung Kim if (max_rows && ++nr_rows >= max_rows) 4967ccf4f90SNamhyung Kim goto out; 4977ccf4f90SNamhyung Kim 4987ccf4f90SNamhyung Kim print_entries: 49999cf666cSArnaldo Carvalho de Melo linesz = hists__sort_list_width(hists) + 3 + 1; 5009754c4f9SJiri Olsa linesz += perf_hpp__color_overhead(); 50199cf666cSArnaldo Carvalho de Melo line = malloc(linesz); 50299cf666cSArnaldo Carvalho de Melo if (line == NULL) { 50399cf666cSArnaldo Carvalho de Melo ret = -1; 50499cf666cSArnaldo Carvalho de Melo goto out; 50599cf666cSArnaldo Carvalho de Melo } 50699cf666cSArnaldo Carvalho de Melo 5077ccf4f90SNamhyung Kim for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) { 5087ccf4f90SNamhyung Kim struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); 50914135663SNamhyung Kim float percent; 5107ccf4f90SNamhyung Kim 5117ccf4f90SNamhyung Kim if (h->filtered) 5127ccf4f90SNamhyung Kim continue; 5137ccf4f90SNamhyung Kim 51414135663SNamhyung Kim percent = hist_entry__get_percent_limit(h); 515064f1981SNamhyung Kim if (percent < min_pcnt) 516064f1981SNamhyung Kim continue; 517064f1981SNamhyung Kim 51899cf666cSArnaldo Carvalho de Melo ret += hist_entry__fprintf(h, max_cols, hists, line, linesz, fp); 5197ccf4f90SNamhyung Kim 5207ccf4f90SNamhyung Kim if (max_rows && ++nr_rows >= max_rows) 52199cf666cSArnaldo Carvalho de Melo break; 5227ccf4f90SNamhyung Kim 5237ccf4f90SNamhyung Kim if (h->ms.map == NULL && verbose > 1) { 52493d5731dSArnaldo Carvalho de Melo __map_groups__fprintf_maps(h->thread->mg, 525acebd408SJiri Olsa MAP__FUNCTION, fp); 5267ccf4f90SNamhyung Kim fprintf(fp, "%.10s end\n", graph_dotted_line); 5277ccf4f90SNamhyung Kim } 5287ccf4f90SNamhyung Kim } 52999cf666cSArnaldo Carvalho de Melo 53099cf666cSArnaldo Carvalho de Melo free(line); 5317ccf4f90SNamhyung Kim out: 53274cf249dSArnaldo Carvalho de Melo zfree(&rem_sq_bracket); 5337ccf4f90SNamhyung Kim 5347ccf4f90SNamhyung Kim return ret; 5357ccf4f90SNamhyung Kim } 5367ccf4f90SNamhyung Kim 53752168eeaSArnaldo Carvalho de Melo size_t events_stats__fprintf(struct events_stats *stats, FILE *fp) 5387ccf4f90SNamhyung Kim { 5397ccf4f90SNamhyung Kim int i; 5407ccf4f90SNamhyung Kim size_t ret = 0; 5417ccf4f90SNamhyung Kim 5427ccf4f90SNamhyung Kim for (i = 0; i < PERF_RECORD_HEADER_MAX; ++i) { 5437ccf4f90SNamhyung Kim const char *name; 5447ccf4f90SNamhyung Kim 54552168eeaSArnaldo Carvalho de Melo if (stats->nr_events[i] == 0) 5467ccf4f90SNamhyung Kim continue; 5477ccf4f90SNamhyung Kim 5487ccf4f90SNamhyung Kim name = perf_event__name(i); 5497ccf4f90SNamhyung Kim if (!strcmp(name, "UNKNOWN")) 5507ccf4f90SNamhyung Kim continue; 5517ccf4f90SNamhyung Kim 5527ccf4f90SNamhyung Kim ret += fprintf(fp, "%16s events: %10d\n", name, 55352168eeaSArnaldo Carvalho de Melo stats->nr_events[i]); 5547ccf4f90SNamhyung Kim } 5557ccf4f90SNamhyung Kim 5567ccf4f90SNamhyung Kim return ret; 5577ccf4f90SNamhyung Kim } 558